summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrdivacky <rdivacky@FreeBSD.org>2009-10-14 18:03:49 +0000
committerrdivacky <rdivacky@FreeBSD.org>2009-10-14 18:03:49 +0000
commit9092c3e0fa01f3139b016d05d267a89e3b07747a (patch)
tree137ebebcae16fb0ce7ab4af456992bbd8d22fced
parent4981926bf654fe5a2c3893f24ca44106b217e71e (diff)
downloadFreeBSD-src-9092c3e0fa01f3139b016d05d267a89e3b07747a.zip
FreeBSD-src-9092c3e0fa01f3139b016d05d267a89e3b07747a.tar.gz
Update clang to r84119.
-rw-r--r--CMakeLists.txt47
-rw-r--r--INPUTS/all-std-headers.cpp51
-rw-r--r--INSTALL.txt49
-rw-r--r--LICENSE.TXT2
-rw-r--r--Makefile29
-rw-r--r--NOTES.txt4
-rw-r--r--README.txt186
-rw-r--r--VER1
-rw-r--r--clang.xcodeproj/project.pbxproj268
-rw-r--r--docs/DriverInternals.html18
-rw-r--r--docs/InternalsManual.html7
-rw-r--r--docs/LanguageExtensions.html44
-rw-r--r--docs/UsersManual.html109
-rw-r--r--docs/libIndex.html267
-rw-r--r--docs/tools/Makefile5
-rw-r--r--docs/tools/clang.pod48
-rw-r--r--include/clang-c/Index.h220
-rw-r--r--include/clang/AST/APValue.h97
-rw-r--r--include/clang/AST/ASTConsumer.h12
-rw-r--r--include/clang/AST/ASTContext.h575
-rw-r--r--include/clang/AST/ASTDiagnostic.h2
-rw-r--r--include/clang/AST/Attr.h130
-rw-r--r--include/clang/AST/CXXInheritance.h212
-rw-r--r--include/clang/AST/CanonicalType.h721
-rw-r--r--include/clang/AST/Decl.h765
-rw-r--r--include/clang/AST/DeclBase.h272
-rw-r--r--include/clang/AST/DeclCXX.h1089
-rw-r--r--include/clang/AST/DeclContextInternals.h30
-rw-r--r--include/clang/AST/DeclGroup.h38
-rw-r--r--include/clang/AST/DeclNodes.def43
-rw-r--r--include/clang/AST/DeclObjC.h570
-rw-r--r--include/clang/AST/DeclTemplate.h724
-rw-r--r--include/clang/AST/DeclarationName.h58
-rw-r--r--include/clang/AST/Expr.h1021
-rw-r--r--include/clang/AST/ExprCXX.h625
-rw-r--r--include/clang/AST/ExprObjC.h286
-rw-r--r--include/clang/AST/ExternalASTSource.h8
-rw-r--r--include/clang/AST/NestedNameSpecifier.h46
-rw-r--r--include/clang/AST/ParentMap.h10
-rw-r--r--include/clang/AST/PrettyPrinter.h26
-rw-r--r--include/clang/AST/RecordLayout.h180
-rw-r--r--include/clang/AST/Redeclarable.h162
-rw-r--r--include/clang/AST/Stmt.h484
-rw-r--r--include/clang/AST/StmtCXX.h5
-rw-r--r--include/clang/AST/StmtGraphTraits.h28
-rw-r--r--include/clang/AST/StmtIterator.h64
-rw-r--r--include/clang/AST/StmtNodes.def14
-rw-r--r--include/clang/AST/StmtObjC.h190
-rw-r--r--include/clang/AST/StmtVisitor.h20
-rw-r--r--include/clang/AST/TemplateName.h70
-rw-r--r--include/clang/AST/Type.h1871
-rw-r--r--include/clang/AST/TypeLoc.h538
-rw-r--r--include/clang/AST/TypeLocNodes.def55
-rw-r--r--include/clang/AST/TypeLocVisitor.h58
-rw-r--r--include/clang/AST/TypeNodes.def23
-rw-r--r--include/clang/AST/TypeOrdering.h6
-rw-r--r--include/clang/AST/TypeVisitor.h12
-rw-r--r--include/clang/Analysis/Analyses/LiveVariables.h42
-rw-r--r--include/clang/Analysis/Analyses/UninitializedValues.h24
-rw-r--r--include/clang/Analysis/AnalysisDiagnostic.h2
-rw-r--r--include/clang/Analysis/CFG.h451
-rw-r--r--include/clang/Analysis/CallGraph.h147
-rw-r--r--include/clang/Analysis/FlowSensitive/DataflowSolver.h129
-rw-r--r--include/clang/Analysis/FlowSensitive/DataflowValues.h58
-rw-r--r--include/clang/Analysis/LocalCheckers.h32
-rw-r--r--include/clang/Analysis/PathDiagnostic.h232
-rw-r--r--include/clang/Analysis/PathSensitive/AnalysisContext.h167
-rw-r--r--include/clang/Analysis/PathSensitive/AnalysisManager.h140
-rw-r--r--include/clang/Analysis/PathSensitive/BasicValueFactory.h91
-rw-r--r--include/clang/Analysis/PathSensitive/BugReporter.h287
-rw-r--r--include/clang/Analysis/PathSensitive/Checker.h122
-rw-r--r--include/clang/Analysis/PathSensitive/CheckerVisitor.def18
-rw-r--r--include/clang/Analysis/PathSensitive/CheckerVisitor.h59
-rw-r--r--include/clang/Analysis/PathSensitive/ConstraintManager.h18
-rw-r--r--include/clang/Analysis/PathSensitive/Environment.h111
-rw-r--r--include/clang/Analysis/PathSensitive/ExplodedGraph.h594
-rw-r--r--include/clang/Analysis/PathSensitive/GRAuditor.h20
-rw-r--r--include/clang/Analysis/PathSensitive/GRBlockCounter.h16
-rw-r--r--include/clang/Analysis/PathSensitive/GRCoreEngine.h770
-rw-r--r--include/clang/Analysis/PathSensitive/GRExprEngine.h567
-rw-r--r--include/clang/Analysis/PathSensitive/GRExprEngineBuilders.h55
-rw-r--r--include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h10
-rw-r--r--include/clang/Analysis/PathSensitive/GRState.h450
-rw-r--r--include/clang/Analysis/PathSensitive/GRStateTrait.h82
-rw-r--r--include/clang/Analysis/PathSensitive/GRSubEngine.h68
-rw-r--r--include/clang/Analysis/PathSensitive/GRTransferFuncs.h60
-rw-r--r--include/clang/Analysis/PathSensitive/GRWorkList.h36
-rw-r--r--include/clang/Analysis/PathSensitive/MemRegion.h496
-rw-r--r--include/clang/Analysis/PathSensitive/SVals.h259
-rw-r--r--include/clang/Analysis/PathSensitive/SValuator.h54
-rw-r--r--include/clang/Analysis/PathSensitive/Store.h122
-rw-r--r--include/clang/Analysis/PathSensitive/SymbolManager.h179
-rw-r--r--include/clang/Analysis/PathSensitive/ValueManager.h108
-rw-r--r--include/clang/Analysis/ProgramPoint.h321
-rw-r--r--include/clang/Analysis/Support/BlkExprDeclBitVector.h128
-rw-r--r--include/clang/Analysis/Support/BumpVector.h215
-rw-r--r--include/clang/Analysis/Support/Optional.h55
-rw-r--r--include/clang/Analysis/Support/SaveAndRestore.h44
-rw-r--r--include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h14
-rw-r--r--include/clang/Analysis/Visitors/CFGRecStmtVisitor.h4
-rw-r--r--include/clang/Analysis/Visitors/CFGStmtVisitor.h62
-rw-r--r--include/clang/Analysis/Visitors/CFGVarDeclVisitor.h21
-rw-r--r--include/clang/Basic/Builtins.def173
-rw-r--r--include/clang/Basic/Builtins.h23
-rw-r--r--include/clang/Basic/ConvertUTF.h82
-rw-r--r--include/clang/Basic/Diagnostic.h194
-rw-r--r--include/clang/Basic/DiagnosticCommonKinds.td3
-rw-r--r--include/clang/Basic/DiagnosticDriverKinds.td10
-rw-r--r--include/clang/Basic/DiagnosticFrontendKinds.td22
-rw-r--r--include/clang/Basic/DiagnosticGroups.td21
-rw-r--r--include/clang/Basic/DiagnosticLexKinds.td12
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td17
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td483
-rw-r--r--include/clang/Basic/FileManager.h46
-rw-r--r--include/clang/Basic/IdentifierTable.h127
-rw-r--r--include/clang/Basic/LangOptions.h46
-rw-r--r--include/clang/Basic/Makefile4
-rw-r--r--include/clang/Basic/OnDiskHashTable.h88
-rw-r--r--include/clang/Basic/PartialDiagnostic.h155
-rw-r--r--include/clang/Basic/SourceLocation.h90
-rw-r--r--include/clang/Basic/SourceManager.h242
-rw-r--r--include/clang/Basic/SourceManagerInternals.h24
-rw-r--r--include/clang/Basic/TargetInfo.h176
-rw-r--r--include/clang/Basic/TokenKinds.def1
-rw-r--r--include/clang/Basic/TokenKinds.h2
-rw-r--r--include/clang/Basic/Version.h30
-rw-r--r--include/clang/CodeGen/ModuleBuilder.h6
-rw-r--r--include/clang/Driver/Action.h38
-rw-r--r--include/clang/Driver/Arg.h46
-rw-r--r--include/clang/Driver/ArgList.h55
-rw-r--r--include/clang/Driver/Compilation.h18
-rw-r--r--include/clang/Driver/Driver.h37
-rw-r--r--include/clang/Driver/DriverDiagnostic.h2
-rw-r--r--include/clang/Driver/HostInfo.h55
-rw-r--r--include/clang/Driver/Job.h22
-rw-r--r--include/clang/Driver/Option.h88
-rw-r--r--include/clang/Driver/Options.def23
-rw-r--r--include/clang/Driver/Options.h4
-rw-r--r--include/clang/Driver/Tool.h8
-rw-r--r--include/clang/Driver/ToolChain.h15
-rw-r--r--include/clang/Driver/Types.def5
-rw-r--r--include/clang/Frontend/ASTConsumers.h24
-rw-r--r--include/clang/Frontend/ASTUnit.h39
-rw-r--r--include/clang/Frontend/Analyses.def9
-rw-r--r--include/clang/Frontend/CommandLineSourceLoc.h29
-rw-r--r--include/clang/Frontend/CompileOptions.h2
-rw-r--r--include/clang/Frontend/DeclXML.def8
-rw-r--r--include/clang/Frontend/DocumentXML.h60
-rw-r--r--include/clang/Frontend/FixItRewriter.h4
-rw-r--r--include/clang/Frontend/FrontendDiagnostic.h2
-rw-r--r--include/clang/Frontend/InitHeaderSearch.h22
-rw-r--r--include/clang/Frontend/ManagerRegistry.h2
-rw-r--r--include/clang/Frontend/PCHBitCodes.h93
-rw-r--r--include/clang/Frontend/PCHReader.h155
-rw-r--r--include/clang/Frontend/PCHWriter.h69
-rw-r--r--include/clang/Frontend/PathDiagnosticClients.h36
-rw-r--r--include/clang/Frontend/StmtXML.def3
-rw-r--r--include/clang/Frontend/TextDiagnosticPrinter.h8
-rw-r--r--include/clang/Frontend/TypeXML.def21
-rw-r--r--include/clang/Frontend/Utils.h31
-rw-r--r--include/clang/Index/ASTLocation.h174
-rw-r--r--include/clang/Index/Analyzer.h56
-rw-r--r--include/clang/Index/DeclReferenceMap.h50
-rw-r--r--include/clang/Index/Entity.h143
-rw-r--r--include/clang/Index/GlobalSelector.h99
-rw-r--r--include/clang/Index/Handlers.h81
-rw-r--r--include/clang/Index/IndexProvider.h38
-rw-r--r--include/clang/Index/Indexer.h75
-rw-r--r--include/clang/Index/Program.h45
-rw-r--r--include/clang/Index/STLExtras.h63
-rw-r--r--include/clang/Index/SelectorMap.h57
-rw-r--r--include/clang/Index/TranslationUnit.h37
-rw-r--r--include/clang/Index/Utils.h35
-rw-r--r--include/clang/Lex/DirectoryLookup.h40
-rw-r--r--include/clang/Lex/HeaderMap.h14
-rw-r--r--include/clang/Lex/HeaderSearch.h50
-rw-r--r--include/clang/Lex/LexDiagnostic.h2
-rw-r--r--include/clang/Lex/Lexer.h100
-rw-r--r--include/clang/Lex/LiteralSupport.h46
-rw-r--r--include/clang/Lex/MacroInfo.h54
-rw-r--r--include/clang/Lex/MultipleIncludeOpt.h22
-rw-r--r--include/clang/Lex/PPCallbacks.h28
-rw-r--r--include/clang/Lex/PTHLexer.h32
-rw-r--r--include/clang/Lex/PTHManager.h44
-rw-r--r--include/clang/Lex/Pragma.h14
-rw-r--r--include/clang/Lex/Preprocessor.h201
-rw-r--r--include/clang/Lex/PreprocessorLexer.h58
-rw-r--r--include/clang/Lex/ScratchBuffer.h4
-rw-r--r--include/clang/Lex/Token.h70
-rw-r--r--include/clang/Lex/TokenConcatenation.h16
-rw-r--r--include/clang/Lex/TokenLexer.h40
-rw-r--r--include/clang/Parse/Action.h909
-rw-r--r--include/clang/Parse/AttributeList.h55
-rw-r--r--include/clang/Parse/DeclSpec.h338
-rw-r--r--include/clang/Parse/Designator.h44
-rw-r--r--include/clang/Parse/Ownership.h68
-rw-r--r--include/clang/Parse/ParseDiagnostic.h2
-rw-r--r--include/clang/Parse/Parser.h290
-rw-r--r--include/clang/Parse/Scope.h46
-rw-r--r--include/clang/Rewrite/DeltaTree.h8
-rw-r--r--include/clang/Rewrite/HTMLRewrite.h20
-rw-r--r--include/clang/Rewrite/RewriteRope.h62
-rw-r--r--include/clang/Rewrite/Rewriter.h111
-rw-r--r--include/clang/Rewrite/TokenRewriter.h24
-rw-r--r--include/clang/Sema/CodeCompleteConsumer.h332
-rw-r--r--include/clang/Sema/ExternalSemaSource.h8
-rw-r--r--include/clang/Sema/ParseAST.h10
-rw-r--r--include/clang/Sema/SemaConsumer.h4
-rw-r--r--include/clang/Sema/SemaDiagnostic.h2
-rw-r--r--lib/AST/APValue.cpp16
-rw-r--r--lib/AST/ASTContext.cpp2766
-rw-r--r--lib/AST/CMakeLists.txt11
-rw-r--r--lib/AST/CXXInheritance.cpp244
-rw-r--r--lib/AST/Decl.cpp509
-rw-r--r--lib/AST/DeclBase.cpp164
-rw-r--r--lib/AST/DeclCXX.cpp610
-rw-r--r--lib/AST/DeclObjC.cpp440
-rw-r--r--lib/AST/DeclPrinter.cpp244
-rw-r--r--lib/AST/DeclTemplate.cpp206
-rw-r--r--lib/AST/DeclarationName.cpp44
-rw-r--r--lib/AST/Expr.cpp797
-rw-r--r--lib/AST/ExprCXX.cpp274
-rw-r--r--lib/AST/ExprConstant.cpp284
-rw-r--r--lib/AST/InheritViz.cpp10
-rw-r--r--lib/AST/NestedNameSpecifier.cpp61
-rw-r--r--lib/AST/ParentMap.cpp10
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp674
-rw-r--r--lib/AST/RecordLayoutBuilder.h146
-rw-r--r--lib/AST/Stmt.cpp80
-rw-r--r--lib/AST/StmtDumper.cpp143
-rw-r--r--lib/AST/StmtIterator.cpp40
-rw-r--r--lib/AST/StmtPrinter.cpp191
-rw-r--r--lib/AST/StmtProfile.cpp720
-rw-r--r--lib/AST/StmtViz.cpp17
-rw-r--r--lib/AST/TemplateName.cpp42
-rw-r--r--lib/AST/Type.cpp987
-rw-r--r--lib/AST/TypeLoc.cpp370
-rw-r--r--lib/Analysis/AnalysisContext.cpp138
-rw-r--r--lib/Analysis/AnalysisManager.cpp35
-rw-r--r--lib/Analysis/BasicConstraintManager.cpp62
-rw-r--r--lib/Analysis/BasicObjCFoundationChecks.cpp329
-rw-r--r--lib/Analysis/BasicObjCFoundationChecks.h21
-rw-r--r--lib/Analysis/BasicStore.cpp380
-rw-r--r--lib/Analysis/BasicValueFactory.cpp138
-rw-r--r--lib/Analysis/BugReporter.cpp994
-rw-r--r--lib/Analysis/BugReporterVisitors.cpp349
-rw-r--r--lib/Analysis/CFG.cpp2084
-rw-r--r--lib/Analysis/CFRefCount.cpp1882
-rw-r--r--lib/Analysis/CMakeLists.txt10
-rw-r--r--lib/Analysis/CallGraph.cpp150
-rw-r--r--lib/Analysis/CallInliner.cpp75
-rw-r--r--lib/Analysis/CheckDeadStores.cpp99
-rw-r--r--lib/Analysis/CheckNSError.cpp166
-rw-r--r--lib/Analysis/CheckObjCDealloc.cpp134
-rw-r--r--lib/Analysis/CheckObjCInstMethSignature.cpp47
-rw-r--r--lib/Analysis/CheckObjCUnusedIVars.cpp64
-rw-r--r--lib/Analysis/CheckSecuritySyntaxOnly.cpp409
-rw-r--r--lib/Analysis/Environment.cpp141
-rw-r--r--lib/Analysis/ExplodedGraph.cpp200
-rw-r--r--lib/Analysis/GRBlockCounter.cpp2
-rw-r--r--lib/Analysis/GRCoreEngine.cpp439
-rw-r--r--lib/Analysis/GRExprEngine.cpp2541
-rw-r--r--lib/Analysis/GRExprEngineInternalChecks.cpp844
-rw-r--r--lib/Analysis/GRState.cpp158
-rw-r--r--lib/Analysis/LiveVariables.cpp122
-rw-r--r--lib/Analysis/MemRegion.cpp212
-rw-r--r--lib/Analysis/PathDiagnostic.cpp96
-rw-r--r--lib/Analysis/RangeConstraintManager.cpp60
-rw-r--r--lib/Analysis/RegionStore.cpp1809
-rw-r--r--lib/Analysis/SVals.cpp163
-rw-r--r--lib/Analysis/SValuator.cpp160
-rw-r--r--lib/Analysis/SimpleConstraintManager.cpp64
-rw-r--r--lib/Analysis/SimpleConstraintManager.h24
-rw-r--r--lib/Analysis/SimpleSValuator.cpp158
-rw-r--r--lib/Analysis/Store.cpp246
-rw-r--r--lib/Analysis/SymbolManager.cpp139
-rw-r--r--lib/Analysis/UninitializedValues.cpp84
-rw-r--r--lib/Analysis/ValueManager.cpp114
-rw-r--r--lib/Basic/Builtins.cpp18
-rw-r--r--lib/Basic/CMakeLists.txt11
-rw-r--r--lib/Basic/ConvertUTF.c606
-rw-r--r--lib/Basic/Diagnostic.cpp121
-rw-r--r--lib/Basic/FileManager.cpp88
-rw-r--r--lib/Basic/IdentifierTable.cpp58
-rw-r--r--lib/Basic/Makefile11
-rw-r--r--lib/Basic/SourceLocation.cpp4
-rw-r--r--lib/Basic/SourceManager.cpp302
-rw-r--r--lib/Basic/TargetInfo.cpp57
-rw-r--r--lib/Basic/Targets.cpp1092
-rw-r--r--lib/Basic/Version.cpp49
-rw-r--r--lib/CMakeLists.txt1
-rw-r--r--lib/CodeGen/ABIInfo.h22
-rw-r--r--lib/CodeGen/CGBlocks.cpp196
-rw-r--r--lib/CodeGen/CGBlocks.h40
-rw-r--r--lib/CodeGen/CGBuiltin.cpp255
-rw-r--r--lib/CodeGen/CGCXX.cpp1639
-rw-r--r--lib/CodeGen/CGCXX.h2
-rw-r--r--lib/CodeGen/CGCXXClass.cpp176
-rw-r--r--lib/CodeGen/CGCXXExpr.cpp304
-rw-r--r--lib/CodeGen/CGCXXTemp.cpp102
-rw-r--r--lib/CodeGen/CGCall.cpp268
-rw-r--r--lib/CodeGen/CGCall.h33
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp686
-rw-r--r--lib/CodeGen/CGDebugInfo.h56
-rw-r--r--lib/CodeGen/CGDecl.cpp291
-rw-r--r--lib/CodeGen/CGExpr.cpp889
-rw-r--r--lib/CodeGen/CGExprAgg.cpp251
-rw-r--r--lib/CodeGen/CGExprComplex.cpp177
-rw-r--r--lib/CodeGen/CGExprConstant.cpp868
-rw-r--r--lib/CodeGen/CGExprScalar.cpp684
-rw-r--r--lib/CodeGen/CGObjC.cpp259
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp999
-rw-r--r--lib/CodeGen/CGObjCMac.cpp2817
-rw-r--r--lib/CodeGen/CGObjCRuntime.h49
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.cpp386
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.h134
-rw-r--r--lib/CodeGen/CGRtti.cpp47
-rw-r--r--lib/CodeGen/CGStmt.cpp330
-rw-r--r--lib/CodeGen/CGValue.h124
-rw-r--r--lib/CodeGen/CGVtable.cpp557
-rw-r--r--lib/CodeGen/CGVtable.h61
-rw-r--r--lib/CodeGen/CMakeLists.txt11
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp437
-rw-r--r--lib/CodeGen/CodeGenFunction.h291
-rw-r--r--lib/CodeGen/CodeGenModule.cpp846
-rw-r--r--lib/CodeGen/CodeGenModule.h132
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp376
-rw-r--r--lib/CodeGen/CodeGenTypes.h124
-rw-r--r--lib/CodeGen/Makefile3
-rw-r--r--lib/CodeGen/Mangle.cpp1098
-rw-r--r--lib/CodeGen/Mangle.h48
-rw-r--r--lib/CodeGen/ModuleBuilder.cpp16
-rw-r--r--lib/CodeGen/README.txt18
-rw-r--r--lib/CodeGen/TargetABIInfo.cpp647
-rw-r--r--lib/Driver/Action.cpp12
-rw-r--r--lib/Driver/Arg.cpp23
-rw-r--r--lib/Driver/ArgList.cpp54
-rw-r--r--lib/Driver/Compilation.cpp46
-rw-r--r--lib/Driver/Driver.cpp580
-rw-r--r--lib/Driver/HostInfo.cpp257
-rw-r--r--lib/Driver/Job.cpp6
-rw-r--r--lib/Driver/Makefile16
-rw-r--r--lib/Driver/OptTable.cpp18
-rw-r--r--lib/Driver/Option.cpp57
-rw-r--r--lib/Driver/Tool.cpp2
-rw-r--r--lib/Driver/ToolChain.cpp12
-rw-r--r--lib/Driver/ToolChains.cpp392
-rw-r--r--lib/Driver/ToolChains.h138
-rw-r--r--lib/Driver/Tools.cpp1082
-rw-r--r--lib/Driver/Tools.h174
-rw-r--r--lib/Driver/Types.cpp48
-rw-r--r--lib/Frontend/ASTConsumers.cpp209
-rw-r--r--lib/Frontend/ASTUnit.cpp63
-rw-r--r--lib/Frontend/AnalysisConsumer.cpp536
-rw-r--r--lib/Frontend/Backend.cpp85
-rw-r--r--lib/Frontend/CMakeLists.txt11
-rw-r--r--lib/Frontend/CacheTokens.cpp189
-rw-r--r--lib/Frontend/DeclXML.cpp74
-rw-r--r--lib/Frontend/DependencyFile.cpp16
-rw-r--r--lib/Frontend/DiagChecker.cpp32
-rw-r--r--lib/Frontend/DocumentXML.cpp157
-rw-r--r--lib/Frontend/FixItRewriter.cpp44
-rw-r--r--lib/Frontend/GeneratePCH.cpp21
-rw-r--r--lib/Frontend/HTMLDiagnostics.cpp371
-rw-r--r--lib/Frontend/HTMLPrint.cpp10
-rw-r--r--lib/Frontend/InitHeaderSearch.cpp459
-rw-r--r--lib/Frontend/InitPreprocessor.cpp111
-rw-r--r--lib/Frontend/PCHReader.cpp612
-rw-r--r--lib/Frontend/PCHReaderDecl.cpp174
-rw-r--r--lib/Frontend/PCHReaderStmt.cpp127
-rw-r--r--lib/Frontend/PCHWriter.cpp547
-rw-r--r--lib/Frontend/PCHWriterDecl.cpp221
-rw-r--r--lib/Frontend/PCHWriterStmt.cpp101
-rw-r--r--lib/Frontend/PlistDiagnostics.cpp148
-rw-r--r--lib/Frontend/PrintParserCallbacks.cpp85
-rw-r--r--lib/Frontend/PrintPreprocessedOutput.cpp96
-rw-r--r--lib/Frontend/RewriteBlocks.cpp311
-rw-r--r--lib/Frontend/RewriteMacros.cpp49
-rw-r--r--lib/Frontend/RewriteObjC.cpp1306
-rw-r--r--lib/Frontend/RewriteTest.cpp4
-rw-r--r--lib/Frontend/StmtXML.cpp78
-rw-r--r--lib/Frontend/TextDiagnosticBuffer.cpp2
-rw-r--r--lib/Frontend/TextDiagnosticPrinter.cpp138
-rw-r--r--lib/Frontend/TypeXML.cpp72
-rw-r--r--lib/Frontend/Warnings.cpp16
-rw-r--r--lib/Headers/CMakeLists.txt7
-rw-r--r--lib/Headers/Makefile8
-rw-r--r--lib/Headers/emmintrin.h34
-rw-r--r--lib/Headers/mmintrin.h12
-rw-r--r--lib/Headers/stdarg.h2
-rw-r--r--lib/Index/ASTLocation.cpp117
-rw-r--r--lib/Index/ASTVisitor.h144
-rw-r--r--lib/Index/Analyzer.cpp438
-rw-r--r--lib/Index/CMakeLists.txt15
-rw-r--r--lib/Index/DeclReferenceMap.cpp91
-rw-r--r--lib/Index/Entity.cpp225
-rw-r--r--lib/Index/EntityImpl.h70
-rw-r--r--lib/Index/GlobalSelector.cpp73
-rw-r--r--lib/Index/Handlers.cpp22
-rw-r--r--lib/Index/IndexProvider.cpp20
-rw-r--r--lib/Index/Indexer.cpp104
-rw-r--r--lib/Index/Makefile28
-rw-r--r--lib/Index/Program.cpp50
-rw-r--r--lib/Index/ProgramImpl.h56
-rw-r--r--lib/Index/ResolveLocation.cpp505
-rw-r--r--lib/Index/SelectorMap.cpp85
-rw-r--r--lib/Lex/CMakeLists.txt4
-rw-r--r--lib/Lex/HeaderMap.cpp44
-rw-r--r--lib/Lex/HeaderSearch.cpp112
-rw-r--r--lib/Lex/Lexer.cpp436
-rw-r--r--lib/Lex/LiteralSupport.cpp267
-rw-r--r--lib/Lex/MacroArgs.cpp34
-rw-r--r--lib/Lex/MacroArgs.h26
-rw-r--r--lib/Lex/MacroInfo.cpp12
-rw-r--r--lib/Lex/PPCaching.cpp5
-rw-r--r--lib/Lex/PPDirectives.cpp352
-rw-r--r--lib/Lex/PPExpressions.cpp100
-rw-r--r--lib/Lex/PPLexerChange.cpp68
-rw-r--r--lib/Lex/PPMacroExpansion.cpp169
-rw-r--r--lib/Lex/PTHLexer.cpp220
-rw-r--r--lib/Lex/Pragma.cpp170
-rw-r--r--lib/Lex/Preprocessor.cpp134
-rw-r--r--lib/Lex/PreprocessorLexer.cpp4
-rw-r--r--lib/Lex/ScratchBuffer.cpp10
-rw-r--r--lib/Lex/TokenConcatenation.cpp42
-rw-r--r--lib/Lex/TokenLexer.cpp120
-rwxr-xr-xlib/Makefile2
-rw-r--r--lib/Parse/AttributeList.cpp20
-rw-r--r--lib/Parse/CMakeLists.txt4
-rw-r--r--lib/Parse/DeclSpec.cpp186
-rw-r--r--lib/Parse/ExtensionRAIIObject.h2
-rw-r--r--lib/Parse/MinimalAction.cpp70
-rw-r--r--lib/Parse/ParseCXXInlineMethods.cpp44
-rw-r--r--lib/Parse/ParseDecl.cpp858
-rw-r--r--lib/Parse/ParseDeclCXX.cpp533
-rw-r--r--lib/Parse/ParseExpr.cpp255
-rw-r--r--lib/Parse/ParseExprCXX.cpp220
-rw-r--r--lib/Parse/ParseInit.cpp40
-rw-r--r--lib/Parse/ParseObjc.cpp301
-rw-r--r--lib/Parse/ParsePragma.cpp65
-rw-r--r--lib/Parse/ParsePragma.h18
-rw-r--r--lib/Parse/ParseStmt.cpp109
-rw-r--r--lib/Parse/ParseTemplate.cpp221
-rw-r--r--lib/Parse/ParseTentative.cpp24
-rw-r--r--lib/Parse/Parser.cpp137
-rw-r--r--lib/Rewrite/CMakeLists.txt2
-rw-r--r--lib/Rewrite/DeltaTree.cpp106
-rw-r--r--lib/Rewrite/HTMLRewrite.cpp227
-rw-r--r--lib/Rewrite/RewriteRope.cpp184
-rw-r--r--lib/Rewrite/Rewriter.cpp74
-rw-r--r--lib/Rewrite/TokenRewriter.cpp20
-rw-r--r--lib/Sema/CMakeLists.txt12
-rw-r--r--lib/Sema/CodeCompleteConsumer.cpp184
-rw-r--r--lib/Sema/IdentifierResolver.cpp18
-rw-r--r--lib/Sema/IdentifierResolver.h10
-rw-r--r--lib/Sema/JumpDiagnostics.cpp62
-rw-r--r--lib/Sema/ParseAST.cpp37
-rw-r--r--lib/Sema/Sema.cpp329
-rw-r--r--lib/Sema/Sema.h1874
-rw-r--r--lib/Sema/SemaAccess.cpp89
-rw-r--r--lib/Sema/SemaAttr.cpp84
-rw-r--r--lib/Sema/SemaCXXCast.cpp1128
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp381
-rw-r--r--lib/Sema/SemaChecking.cpp530
-rw-r--r--lib/Sema/SemaCodeComplete.cpp1432
-rw-r--r--lib/Sema/SemaDecl.cpp2571
-rw-r--r--lib/Sema/SemaDeclAttr.cpp544
-rw-r--r--lib/Sema/SemaDeclCXX.cpp2665
-rw-r--r--lib/Sema/SemaDeclObjC.cpp832
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp320
-rw-r--r--lib/Sema/SemaExpr.cpp2800
-rw-r--r--lib/Sema/SemaExprCXX.cpp1129
-rw-r--r--lib/Sema/SemaExprObjC.cpp446
-rw-r--r--lib/Sema/SemaInit.cpp462
-rw-r--r--lib/Sema/SemaLookup.cpp1482
-rw-r--r--lib/Sema/SemaOverload.cpp2271
-rw-r--r--lib/Sema/SemaOverload.h37
-rw-r--r--lib/Sema/SemaStmt.cpp405
-rw-r--r--lib/Sema/SemaTemplate.cpp2545
-rw-r--r--lib/Sema/SemaTemplate.h104
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp1857
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp1238
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp1342
-rw-r--r--lib/Sema/SemaType.cpp797
-rw-r--r--lib/Sema/TreeTransform.h4829
-rw-r--r--test/Analysis/CFDateGC.m8
-rw-r--r--test/Analysis/CheckNSError.m4
-rw-r--r--test/Analysis/NSPanel.m2
-rw-r--r--test/Analysis/NSString.m15
-rw-r--r--test/Analysis/PR2978.m1
-rw-r--r--test/Analysis/PR3991.m1
-rw-r--r--test/Analysis/array-struct.c6
-rw-r--r--test/Analysis/casts.c19
-rw-r--r--test/Analysis/cfref_rdar6080742.c18
-rw-r--r--test/Analysis/complex.c2
-rw-r--r--test/Analysis/dead-stores.c171
-rw-r--r--test/Analysis/dead-stores.cpp19
-rw-r--r--test/Analysis/exercise-ps.c2
-rw-r--r--test/Analysis/misc-ps-basic-store.m14
-rw-r--r--test/Analysis/misc-ps-region-store-i386.m14
-rw-r--r--test/Analysis/misc-ps-region-store-x86_64.m14
-rw-r--r--test/Analysis/misc-ps-region-store.m243
-rw-r--r--test/Analysis/misc-ps.m410
-rw-r--r--test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m3
-rw-r--r--test/Analysis/no-outofbounds.c12
-rw-r--r--test/Analysis/null-deref-ps.c39
-rw-r--r--test/Analysis/outofbound.c1
-rw-r--r--test/Analysis/pr4209.m3
-rw-r--r--test/Analysis/rdar-6442306-1.m1
-rw-r--r--test/Analysis/rdar-6540084.m1
-rw-r--r--test/Analysis/rdar-6541136-region.c7
-rw-r--r--test/Analysis/rdar-6562655.m6
-rw-r--r--test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m3
-rw-r--r--test/Analysis/rdar-7168531.m19
-rw-r--r--test/Analysis/region-1.m1
-rw-r--r--test/Analysis/region-only-test.c2
-rw-r--r--test/Analysis/retain-release-gc-only.m186
-rw-r--r--test/Analysis/retain-release-region-store.m24
-rw-r--r--test/Analysis/retain-release.m439
-rw-r--r--test/Analysis/security-syntax-checks.m91
-rw-r--r--test/Analysis/uninit-vals-ps-region.c18
-rw-r--r--test/Analysis/uninit-vals-ps.c50
-rw-r--r--test/Analysis/uninit-vals.c2
-rw-r--r--test/Analysis/unions-region.m41
-rw-r--r--test/Analysis/unused-ivars.m45
-rw-r--r--test/CMakeLists.txt73
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-template-id.cpp27
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp73
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp42
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.elab/templateid.cpp18
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p2.cpp65
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p3.cpp41
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p4.cpp25
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p5.cpp35
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.unqual/p3.cpp4
-rw-r--r--test/CXX/basic/basic.start/basic.start.main/p2a.cpp8
-rw-r--r--test/CXX/basic/basic.start/basic.start.main/p2b.cpp8
-rw-r--r--test/CXX/basic/basic.start/basic.start.main/p2c.cpp4
-rw-r--r--test/CXX/basic/basic.start/basic.start.main/p2d.cpp4
-rw-r--r--test/CXX/basic/basic.start/basic.start.main/p2e.cpp4
-rw-r--r--test/CXX/basic/basic.start/basic.start.main/p2f.cpp7
-rw-r--r--test/CXX/basic/basic.start/basic.start.main/p2g.cpp4
-rw-r--r--test/CXX/basic/basic.stc/basic.stc.dynamic/p2-nodef.cpp7
-rw-r--r--test/CXX/basic/basic.stc/basic.stc.dynamic/p2.cpp25
-rw-r--r--test/CXX/class.derived/class.virtual/p12.cpp19
-rw-r--r--test/CXX/class/class.friend/p1-ambiguous.cpp37
-rw-r--r--test/CXX/class/class.friend/p1.cpp76
-rw-r--r--test/CXX/class/class.friend/p2.cpp10
-rw-r--r--test/CXX/class/class.friend/p6.cpp10
-rw-r--r--test/CXX/class/class.local/p3.cpp2
-rw-r--r--test/CXX/class/class.local/p4.cpp2
-rw-r--r--test/CXX/class/class.nest/p1.cpp14
-rw-r--r--test/CXX/class/class.nested.type/p1.cpp4
-rw-r--r--test/CXX/class/class.union/p1.cpp105
-rw-r--r--test/CXX/dcl.dcl/basic.namespace/namespace.def/namespace.memdef/p3.cpp15
-rw-r--r--test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3-cxx0x.cpp20
-rw-r--r--test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p5-cxx0x.cpp12
-rw-r--r--test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p6-cxx0x.cpp8
-rw-r--r--test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8-cxx0x.cpp15
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.stc/p9.cpp4
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp10
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp13
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp60
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p10.cpp16
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p2.cpp9
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp13
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp55
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p5.cpp18
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p6.cpp32
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p7.cpp7
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p8.cpp4
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct/p3.cpp3
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.mptr/p3.cpp26
-rw-r--r--test/CXX/expr/p3.cpp15
-rw-r--r--test/CXX/expr/p8.cpp18
-rw-r--r--test/CXX/expr/p9.cpp50
-rw-r--r--test/CXX/lex/lex.trigraph/p1.cpp19
-rw-r--r--test/CXX/lex/lex.trigraph/p2.cpp3
-rw-r--r--test/CXX/lex/lex.trigraph/p3.cpp8
-rw-r--r--test/CXX/over/over.match/over.match.best/p1.cpp16
-rw-r--r--test/CXX/over/over.over/p1.cpp94
-rw-r--r--test/CXX/over/over.over/p2.cpp10
-rw-r--r--test/CXX/over/over.over/p4.cpp23
-rw-r--r--test/CXX/temp/temp.decls/temp.class.spec/p6.cpp20
-rw-r--r--test/CXX/temp/temp.decls/temp.class.spec/temp.class.order/p2.cpp16
-rw-r--r--test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1-neg.cpp25
-rw-r--r--test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1.cpp26
-rw-r--r--test/CXX/temp/temp.decls/temp.class/temp.mem.class/p1.cpp27
-rw-r--r--test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1-retmem.cpp28
-rw-r--r--test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1.cpp68
-rw-r--r--test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1inst.cpp17
-rw-r--r--test/CXX/temp/temp.decls/temp.class/temp.mem.func/pr5056.cpp17
-rw-r--r--test/CXX/temp/temp.decls/temp.class/temp.static/p1-inst.cpp28
-rw-r--r--test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp26
-rw-r--r--test/CXX/temp/temp.decls/temp.fct/temp.func.order/p4.cpp23
-rw-r--r--test/CXX/temp/temp.decls/temp.fct/temp.func.order/p5.cpp12
-rw-r--r--test/CXX/temp/temp.decls/temp.fct/temp.over.link/p4-neg.cpp6
-rw-r--r--test/CXX/temp/temp.decls/temp.fct/temp.over.link/p6.cpp16
-rw-r--r--test/CXX/temp/temp.decls/temp.friend/p1.cpp56
-rw-r--r--test/CXX/temp/temp.decls/temp.friend/p3.cpp13
-rw-r--r--test/CXX/temp/temp.decls/temp.friend/p5.cpp11
-rw-r--r--test/CXX/temp/temp.decls/temp.mem/p1.cpp16
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3.cpp2
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp32
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p2.cpp36
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p3.cpp30
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p4.cpp44
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.funcaddr/p1.cpp22
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.partial/p11.cpp22
-rw-r--r--test/CXX/temp/temp.param/p1.cpp3
-rw-r--r--test/CXX/temp/temp.res/temp.dep/p3.cpp43
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p1.cpp99
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p10.cpp7
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p11.cpp8
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p13.cpp6
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p14.cpp42
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p15.cpp22
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p16.cpp26
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p17.cpp12
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p18.cpp20
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p19.cpp30
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp239
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p20.cpp14
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p21.cpp30
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p3.cpp14
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p4.cpp59
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p5.cpp61
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p6.cpp56
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p9.cpp14
-rw-r--r--test/CodeCompletion/call.cpp28
-rw-r--r--test/CodeCompletion/enum-switch-case-qualified.cpp33
-rw-r--r--test/CodeCompletion/enum-switch-case.c29
-rw-r--r--test/CodeCompletion/enum-switch-case.cpp29
-rw-r--r--test/CodeCompletion/function-templates.cpp15
-rw-r--r--test/CodeCompletion/functions.cpp9
-rw-r--r--test/CodeCompletion/member-access.c13
-rw-r--r--test/CodeCompletion/member-access.cpp43
-rw-r--r--test/CodeCompletion/namespace-alias.cpp21
-rw-r--r--test/CodeCompletion/namespace.cpp15
-rw-r--r--test/CodeCompletion/nested-name-specifier.cpp18
-rw-r--r--test/CodeCompletion/operator.cpp18
-rw-r--r--test/CodeCompletion/ordinary-name.c12
-rw-r--r--test/CodeCompletion/property.m29
-rw-r--r--test/CodeCompletion/tag.c13
-rw-r--r--test/CodeCompletion/tag.cpp26
-rw-r--r--test/CodeCompletion/templates.cpp17
-rw-r--r--test/CodeCompletion/truncation.c12
-rw-r--r--test/CodeCompletion/truncation.c.h5
-rw-r--r--test/CodeCompletion/using-namespace.cpp21
-rw-r--r--test/CodeCompletion/using.cpp25
-rw-r--r--test/CodeGen/2008-07-17-no-emit-on-error.c4
-rw-r--r--test/CodeGen/2008-07-22-bitfield-init-after-zero-len-array.c5
-rw-r--r--test/CodeGen/2008-07-29-override-alias-decl.c2
-rw-r--r--test/CodeGen/2009-01-21-invalid-debug-info.m2
-rw-r--r--test/CodeGen/2009-04-23-dbg.c2
-rw-r--r--test/CodeGen/2009-06-01-addrofknr.c12
-rw-r--r--test/CodeGen/2009-07-31-DbgDeclare.c5
-rw-r--r--test/CodeGen/2009-08-14-vararray-crash.c11
-rw-r--r--test/CodeGen/PR3613-static-decl.c2
-rw-r--r--test/CodeGen/PR4611-bitfield-layout.c6
-rw-r--r--test/CodeGen/PR5060-align.c13
-rw-r--r--test/CodeGen/address-space-compound-literal.c5
-rw-r--r--test/CodeGen/address-space-field1.c39
-rw-r--r--test/CodeGen/address-space-field2.c50
-rw-r--r--test/CodeGen/address-space-field3.c46
-rw-r--r--test/CodeGen/address-space-field4.c61
-rw-r--r--test/CodeGen/arm-arguments.c94
-rw-r--r--test/CodeGen/arm_asm_clobber.c21
-rw-r--r--test/CodeGen/array.c4
-rw-r--r--test/CodeGen/asm-inout.c18
-rw-r--r--test/CodeGen/asm.c13
-rw-r--r--test/CodeGen/attr-cleanup.c2
-rw-r--r--test/CodeGen/attributes.c100
-rw-r--r--test/CodeGen/blocks-2.c3
-rw-r--r--test/CodeGen/blocks-aligned-byref-variable.c19
-rw-r--r--test/CodeGen/blocks-seq.c20
-rw-r--r--test/CodeGen/boolassign.c5
-rw-r--r--test/CodeGen/builtin-attributes.c12
-rw-r--r--test/CodeGen/builtins-ffs_parity_popcount.c4
-rw-r--r--test/CodeGen/builtins-powi.c4
-rw-r--r--test/CodeGen/builtins.c2
-rw-r--r--test/CodeGen/cast-to-union.c8
-rw-r--r--test/CodeGen/conditional.c21
-rw-r--r--test/CodeGen/const-init.c61
-rw-r--r--test/CodeGen/darwin-string-literals.c16
-rw-r--r--test/CodeGen/debug-info.c6
-rw-r--r--test/CodeGen/designated-initializers.c5
-rw-r--r--test/CodeGen/exprs.c8
-rw-r--r--test/CodeGen/ext-vector-shuffle.c4
-rw-r--r--test/CodeGen/ext-vector.c19
-rw-r--r--test/CodeGen/function-attributes.c2
-rw-r--r--test/CodeGen/functions.c5
-rw-r--r--test/CodeGen/global-decls.c2
-rw-r--r--test/CodeGen/global-init.c25
-rw-r--r--test/CodeGen/global-with-initialiser.c6
-rw-r--r--test/CodeGen/globalinit.c2
-rw-r--r--test/CodeGen/init-with-member-expr.c2
-rw-r--r--test/CodeGen/inline.c16
-rw-r--r--test/CodeGen/inline2.c62
-rw-r--r--test/CodeGen/packed-union.c16
-rw-r--r--test/CodeGen/parameter-passing.c2
-rw-r--r--test/CodeGen/pragma-pack-1.c7
-rw-r--r--test/CodeGen/pragma-pack-2.c23
-rw-r--r--test/CodeGen/pragma-pack-3.c19
-rw-r--r--test/CodeGen/pragma-weak.c165
-rw-r--r--test/CodeGen/predefined-expr.c45
-rw-r--r--test/CodeGen/regparm.c5
-rw-r--r--test/CodeGen/stack-protector.c3
-rw-r--r--test/CodeGen/statements.c22
-rw-r--r--test/CodeGen/staticinit.c6
-rw-r--r--test/CodeGen/stdcall-fastcall.c2
-rw-r--r--test/CodeGen/string-init.c2
-rw-r--r--test/CodeGen/struct-init.c4
-rw-r--r--test/CodeGen/struct-x86-darwin.c20
-rw-r--r--test/CodeGen/struct.c43
-rw-r--r--test/CodeGen/union-init.c28
-rw-r--r--test/CodeGen/union-init2.c4
-rw-r--r--test/CodeGen/unreachable.c37
-rw-r--r--test/CodeGen/unwind-attr.c1
-rw-r--r--test/CodeGen/vector.c10
-rw-r--r--test/CodeGen/visibility.c2
-rw-r--r--test/CodeGen/volatile.c2
-rw-r--r--test/CodeGen/x86.c2
-rw-r--r--test/CodeGen/x86_32-arguments.c127
-rw-r--r--test/CodeGen/x86_64-arguments.c28
-rw-r--r--test/CodeGenCXX/PR4827-cast.cpp5
-rw-r--r--test/CodeGenCXX/PR4890-debug-info-dtor.cpp6
-rw-r--r--test/CodeGenCXX/PR4983-constructor-conversion.cpp16
-rw-r--r--test/CodeGenCXX/PR5050-constructor-conversion.cpp19
-rw-r--r--test/CodeGenCXX/PR5093-static-member-function.cpp9
-rw-r--r--test/CodeGenCXX/anonymous-namespaces.cpp22
-rw-r--r--test/CodeGenCXX/anonymous-union-member-initializer.cpp12
-rw-r--r--test/CodeGenCXX/array-pointer-decay.cpp7
-rw-r--r--test/CodeGenCXX/attr.cpp36
-rw-r--r--test/CodeGenCXX/cast-conversion.cpp33
-rw-r--r--test/CodeGenCXX/class-layout.cpp5
-rw-r--r--test/CodeGenCXX/conditional-expr-lvalue.cpp7
-rw-r--r--test/CodeGenCXX/constructor-conversion.cpp55
-rw-r--r--test/CodeGenCXX/constructor-default-arg.cpp40
-rw-r--r--test/CodeGenCXX/constructor-for-array-members.cpp44
-rw-r--r--test/CodeGenCXX/constructor-init-reference.cpp9
-rw-r--r--test/CodeGenCXX/constructor-init.cpp61
-rw-r--r--test/CodeGenCXX/constructor-template.cpp56
-rw-r--r--test/CodeGenCXX/conversion-function.cpp115
-rw-r--r--test/CodeGenCXX/convert-to-fptr.cpp47
-rw-r--r--test/CodeGenCXX/copy-assign-synthesis-1.cpp109
-rw-r--r--test/CodeGenCXX/copy-assign-synthesis.cpp79
-rw-r--r--test/CodeGenCXX/copy-constructor-elim.cpp43
-rw-r--r--test/CodeGenCXX/copy-constructor-synthesis.cpp110
-rw-r--r--test/CodeGenCXX/decl-ref-init.cpp31
-rw-r--r--test/CodeGenCXX/default-arg-temps.cpp14
-rw-r--r--test/CodeGenCXX/default-constructor-for-members.cpp24
-rw-r--r--test/CodeGenCXX/default-destructor-synthesis.cpp60
-rw-r--r--test/CodeGenCXX/delete.cpp37
-rw-r--r--test/CodeGenCXX/derived-to-base.cpp16
-rw-r--r--test/CodeGenCXX/destructor-calls.cpp41
-rw-r--r--test/CodeGenCXX/destructors.cpp30
-rw-r--r--test/CodeGenCXX/devirtualize-virtual-function-calls.cpp47
-rw-r--r--test/CodeGenCXX/explicit-instantiation.cpp13
-rw-r--r--test/CodeGenCXX/function-template-specialization.cpp15
-rw-r--r--test/CodeGenCXX/global-init.cpp16
-rw-r--r--test/CodeGenCXX/mangle-extreme.cpp47
-rw-r--r--test/CodeGenCXX/mangle-subst-std.cpp39
-rw-r--r--test/CodeGenCXX/mangle-subst.cpp56
-rw-r--r--test/CodeGenCXX/mangle.cpp190
-rw-r--r--test/CodeGenCXX/member-function-pointers.cpp73
-rw-r--r--test/CodeGenCXX/member-functions.cpp2
-rw-r--r--test/CodeGenCXX/member-pointers-zero-init.cpp34
-rw-r--r--test/CodeGenCXX/namespace-aliases.cpp3
-rw-r--r--test/CodeGenCXX/nested-base-member-access.cpp52
-rw-r--r--test/CodeGenCXX/new.cpp23
-rw-r--r--test/CodeGenCXX/nullptr.cpp7
-rw-r--r--test/CodeGenCXX/overload-binop-implicitconvert.cpp22
-rw-r--r--test/CodeGenCXX/predefined-expr-sizeof.cpp30
-rw-r--r--test/CodeGenCXX/predefined-expr.cpp226
-rw-r--r--test/CodeGenCXX/references.cpp13
-rw-r--r--test/CodeGenCXX/reinterpret-cast.cpp12
-rw-r--r--test/CodeGenCXX/static-data-member.cpp8
-rw-r--r--test/CodeGenCXX/static-init.cpp13
-rw-r--r--test/CodeGenCXX/temp-1.cpp83
-rw-r--r--test/CodeGenCXX/template-anonymous-union-member-initializer.cpp10
-rw-r--r--test/CodeGenCXX/trivial-constructor-init.cpp21
-rw-r--r--test/CodeGenCXX/virt.cpp1024
-rw-r--r--test/CodeGenCXX/virtual-base-cast.cpp9
-rw-r--r--test/CodeGenCXX/virtual-function-calls.cpp11
-rw-r--r--test/CodeGenCXX/vtable-cast-crash.cpp21
-rw-r--r--test/CodeGenCXX/x86_64-arguments.cpp10
-rw-r--r--test/CodeGenObjC/PR4541.m19
-rw-r--r--test/CodeGenObjC/PR4894-recursive-debug-crash.m40
-rw-r--r--test/CodeGenObjC/constant-strings.m4
-rw-r--r--test/CodeGenObjC/debug-info-linkagename.m17
-rw-r--r--test/CodeGenObjC/for-in.m44
-rw-r--r--test/CodeGenObjC/ivar-layout-64-bitfields.m40
-rw-r--r--test/CodeGenObjC/ivar-layout-no-optimize.m18
-rw-r--r--test/CodeGenObjC/messages.m4
-rw-r--r--test/CodeGenObjC/objc-assign-ivar.m53
-rw-r--r--test/CodeGenObjC/objc-gc-aggr-assign.m46
-rw-r--r--test/CodeGenObjC/objc-read-weak-byref.m26
-rw-r--r--test/CodeGenObjC/objc2-assign-global.m83
-rw-r--r--test/CodeGenObjC/objc2-ivar-assign.m41
-rw-r--r--test/CodeGenObjC/objc2-new-gc-api-strongcast.m26
-rw-r--r--test/CodeGenObjC/objc2-weak-assign.m4
-rw-r--r--test/CodeGenObjC/objc2-weak-ivar-debug.m15
-rw-r--r--test/CodeGenObjC/objc2-write-barrier-2.m80
-rw-r--r--test/CodeGenObjC/objc2-write-barrier-3.m47
-rw-r--r--test/CodeGenObjC/objc2-write-barrier-4.m28
-rw-r--r--test/CodeGenObjC/objc2-write-barrier-5.m27
-rw-r--r--test/CodeGenObjC/objc2-write-barrier.m114
-rw-r--r--test/CodeGenObjC/object-incr-decr-1.m19
-rw-r--r--test/CodeGenObjC/overloadable.m4
-rw-r--r--test/CodeGenObjC/predefined-expr.m90
-rw-r--r--test/CodeGenObjC/property-agrr-getter.m23
-rw-r--r--test/CodeGenObjC/property-setter-attr.m2
-rw-r--r--test/CodeGenObjC/protocol-in-extended-class.m29
-rw-r--r--test/CodeGenObjC/protocols-lazy.m4
-rw-r--r--test/CodeGenObjC/protocols.m50
-rw-r--r--test/CodeGenObjC/variadic-sends.m41
-rw-r--r--test/Coverage/targets.c27
-rw-r--r--test/Driver/arm-darwin-builtin.c14
-rw-r--r--test/Driver/ast.c26
-rw-r--r--test/Driver/bindings.c6
-rw-r--r--test/Driver/clang-translation.c8
-rw-r--r--test/Driver/darwin-arm.c4
-rw-r--r--test/Driver/darwin-as.c10
-rw-r--r--test/Driver/darwin-cc.c1
-rw-r--r--test/Driver/darwin-ld.c7
-rw-r--r--test/Driver/default-toolchain.c6
-rw-r--r--test/Driver/dragonfly.c10
-rw-r--r--test/Driver/freebsd.c10
-rw-r--r--test/Driver/openbsd.c8
-rw-r--r--test/Driver/pth.c8
-rw-r--r--test/Driver/qa_override.c3
-rw-r--r--test/Driver/redzone.c6
-rw-r--r--test/Frontend/ast-codegen.c12
-rw-r--r--test/Frontend/ast-main.c8
-rw-r--r--test/Frontend/dependency-gen.c2
-rw-r--r--test/Frontend/stdin.c2
-rw-r--r--test/Index/c-index-api-test.m224
-rw-r--r--test/Index/comments.c30
-rw-r--r--test/Index/cxx-operator-overload.cpp28
-rw-r--r--test/Index/find-decls.c25
-rw-r--r--test/Index/find-defs.c18
-rw-r--r--test/Index/find-refs.c47
-rw-r--r--test/Index/foo.h8
-rw-r--r--test/Index/multiple-redecls.c12
-rw-r--r--test/Index/objc-decls.m16
-rw-r--r--test/Index/objc-message.m38
-rw-r--r--test/Index/objc.h11
-rw-r--r--test/Index/resolve-loc.c39
-rw-r--r--test/Index/t1.c31
-rw-r--r--test/Index/t1.m23
-rw-r--r--test/Index/t2.c14
-rw-r--r--test/Index/t2.m16
-rw-r--r--test/Lexer/11-27-2007-FloatLiterals.c8
-rw-r--r--test/Lexer/comment-escape.c2
-rw-r--r--test/Lexer/dollar-idents.c2
-rw-r--r--test/Makefile32
-rw-r--r--test/Misc/diag-mapping2.c5
-rw-r--r--test/PCH/cxx-method.cpp7
-rw-r--r--test/PCH/libroot/usr/include/reloc.h15
-rw-r--r--test/PCH/libroot/usr/include/reloc2.h15
-rw-r--r--test/PCH/method_pool.h3
-rw-r--r--test/PCH/objc_exprs.m5
-rw-r--r--test/PCH/pr4489.c22
-rw-r--r--test/PCH/reloc.c14
-rw-r--r--test/Parser/CompoundStmtScope.c2
-rw-r--r--test/Parser/MicrosoftExtensions.c18
-rw-r--r--test/Parser/argument_redef.c2
-rw-r--r--test/Parser/bad-control.c4
-rw-r--r--test/Parser/cxx-ambig-paren-expr.cpp6
-rw-r--r--test/Parser/cxx-friend.cpp21
-rw-r--r--test/Parser/cxx-member-initializers.cpp10
-rw-r--r--test/Parser/cxx-template-decl.cpp21
-rw-r--r--test/Parser/cxx-using-declaration.cpp92
-rw-r--r--test/Parser/declarators.c10
-rw-r--r--test/Parser/implicit-casts.c1
-rw-r--r--test/Parser/objc-messaging-neg-1.m9
-rw-r--r--test/Parser/pointer_promotion.c3
-rw-r--r--test/Parser/pragma-weak.c2
-rw-r--r--test/Parser/recovery.c12
-rw-r--r--test/Parser/statements.c14
-rw-r--r--test/Parser/top-level-semi-cxx0x.cpp15
-rw-r--r--test/Preprocessor/assembler-with-cpp.c2
-rw-r--r--test/Preprocessor/macro-multiline.c2
-rw-r--r--test/Preprocessor/macro_fn_comma_swallow.c2
-rw-r--r--test/Preprocessor/macro_paste_mscomment.c4
-rw-r--r--test/Preprocessor/non_fragile_feature.m8
-rw-r--r--test/Preprocessor/non_fragile_feature1.m8
-rw-r--r--test/Preprocessor/pushable-diagnostics.c17
-rw-r--r--test/Rewriter/id-test-3.m2
-rw-r--r--test/Rewriter/method-encoding-1.m4
-rw-r--r--test/Rewriter/rewrite-foreach-4.m2
-rw-r--r--test/Rewriter/rewrite-foreach-5.m2
-rw-r--r--test/Sema/address_spaces.c16
-rw-r--r--test/Sema/align-arm-apcs.c4
-rw-r--r--test/Sema/altivec-init.c16
-rw-r--r--test/Sema/arg-scope-c99.c2
-rw-r--r--test/Sema/arg-scope.c2
-rw-r--r--test/Sema/array-constraint.c2
-rw-r--r--test/Sema/array-init.c23
-rw-r--r--test/Sema/attr-decl-after-definition.c19
-rw-r--r--test/Sema/attr-deprecated.c2
-rw-r--r--test/Sema/attr-format_arg.c2
-rw-r--r--test/Sema/attr-malloc.c25
-rw-r--r--test/Sema/attr-noreturn.c10
-rw-r--r--test/Sema/attr-section.c10
-rw-r--r--test/Sema/attr-weak.c4
-rw-r--r--test/Sema/bitfield-promote-int-16bit.c25
-rw-r--r--test/Sema/bitfield-promote.c34
-rw-r--r--test/Sema/bitfield.c2
-rw-r--r--test/Sema/block-args.c2
-rw-r--r--test/Sema/block-call.c52
-rw-r--r--test/Sema/block-literal.c82
-rw-r--r--test/Sema/block-misc.c39
-rw-r--r--test/Sema/block-printf-attribute-1.c17
-rw-r--r--test/Sema/block-return-1.c6
-rw-r--r--test/Sema/block-return-2.c5
-rw-r--r--test/Sema/block-return-3.c5
-rw-r--r--test/Sema/block-return.c6
-rw-r--r--test/Sema/block-sentinel-attribute.c25
-rw-r--r--test/Sema/builtin-prefetch.c2
-rw-r--r--test/Sema/builtin-unary-fp.c12
-rw-r--r--test/Sema/builtins.c32
-rw-r--r--test/Sema/c89-2.c6
-rw-r--r--test/Sema/c89.c4
-rw-r--r--test/Sema/compare.c23
-rw-r--r--test/Sema/complex-int.c5
-rw-r--r--test/Sema/conditional.c10
-rw-r--r--test/Sema/darwin-align-cast.c5
-rw-r--r--test/Sema/decl-type-merging.c10
-rw-r--r--test/Sema/enum.c2
-rw-r--r--test/Sema/exprs.c11
-rw-r--r--test/Sema/floating-point-compare.c4
-rw-r--r--test/Sema/format-attr-pr4470.c1
-rw-r--r--test/Sema/format-attribute-printf0.c26
-rw-r--r--test/Sema/freemain.c9
-rw-r--r--test/Sema/function-pointer-sentinel-attribute.c23
-rw-r--r--test/Sema/function-sentinel-attr.c2
-rw-r--r--test/Sema/function.c2
-rw-r--r--test/Sema/heinous-extensions-on.c13
-rw-r--r--test/Sema/implicit-builtin-redecl.c12
-rw-r--r--test/Sema/implicit-int.c9
-rw-r--r--test/Sema/incomplete-call.c4
-rw-r--r--test/Sema/incomplete-decl.c5
-rw-r--r--test/Sema/pragma-pack-4.c19
-rw-r--r--test/Sema/pragma-unused.c9
-rw-r--r--test/Sema/predefined-function.c17
-rw-r--r--test/Sema/promote-int-16bit.c6
-rw-r--r--test/Sema/redefinition.c4
-rw-r--r--test/Sema/return-noreturn.c29
-rw-r--r--test/Sema/return.c210
-rw-r--r--test/Sema/shift.c38
-rw-r--r--test/Sema/static-init.c4
-rw-r--r--test/Sema/struct-decl.c20
-rw-r--r--test/Sema/tentative-decls.c2
-rw-r--r--test/Sema/transparent-union-pointer.c8
-rw-r--r--test/Sema/type-spec-struct-union.c2
-rw-r--r--test/Sema/unused-expr.c54
-rw-r--r--test/Sema/va_arg_x86_64.c9
-rw-r--r--test/Sema/vector-cast.c2
-rw-r--r--test/Sema/warn-char-subscripts.c64
-rw-r--r--test/Sema/warn-unused-variables.c19
-rw-r--r--test/Sema/x86-intrinsics-headers.c24
-rw-r--r--test/SemaCXX/PR5086-ambig-resolution-enum.cpp13
-rw-r--r--test/SemaCXX/abstract.cpp57
-rw-r--r--test/SemaCXX/access-control-check.cpp16
-rw-r--r--test/SemaCXX/addr-of-overloaded-function.cpp27
-rw-r--r--test/SemaCXX/ambig-user-defined-conversions.cpp52
-rw-r--r--test/SemaCXX/ambiguous-builtin-unary-operator.cpp18
-rw-r--r--test/SemaCXX/arrow-operator.cpp22
-rw-r--r--test/SemaCXX/attr-after-definition.cpp9
-rw-r--r--test/SemaCXX/attr-deprecated.cpp66
-rw-r--r--test/SemaCXX/attr-format.cpp8
-rw-r--r--test/SemaCXX/auto-cxx0x.cpp2
-rw-r--r--test/SemaCXX/builtin-ptrtomember-ambig.cpp24
-rw-r--r--test/SemaCXX/builtin-ptrtomember-overload-1.cpp46
-rw-r--r--test/SemaCXX/builtin-ptrtomember-overload.cpp18
-rw-r--r--test/SemaCXX/c99.cpp8
-rw-r--r--test/SemaCXX/cast-conversion.cpp21
-rw-r--r--test/SemaCXX/cast-explicit-ctor.cpp6
-rw-r--r--test/SemaCXX/class-base-member-init.cpp6
-rw-r--r--test/SemaCXX/class-layout.cpp49
-rw-r--r--test/SemaCXX/class-names.cpp4
-rw-r--r--test/SemaCXX/composite-pointer-type.cpp8
-rw-r--r--test/SemaCXX/conditional-expr.cpp6
-rw-r--r--test/SemaCXX/constructor-initializer.cpp41
-rw-r--r--test/SemaCXX/constructor.cpp26
-rw-r--r--test/SemaCXX/conversion-delete-expr.cpp109
-rw-r--r--test/SemaCXX/conversion-function.cpp29
-rw-r--r--test/SemaCXX/copy-assignment.cpp2
-rw-r--r--test/SemaCXX/copy-constructor-error.cpp13
-rw-r--r--test/SemaCXX/cstyle-cast.cpp231
-rw-r--r--test/SemaCXX/dcl_ambig_res.cpp9
-rw-r--r--test/SemaCXX/dcl_init_aggr.cpp6
-rw-r--r--test/SemaCXX/decl-expr-ambiguity.cpp4
-rw-r--r--test/SemaCXX/decl-init-ref.cpp26
-rw-r--r--test/SemaCXX/decltype-crash.cpp7
-rw-r--r--test/SemaCXX/decltype-this.cpp15
-rw-r--r--test/SemaCXX/default-argument-temporaries.cpp11
-rw-r--r--test/SemaCXX/default-assignment-operator.cpp28
-rw-r--r--test/SemaCXX/default-constructor-initializers.cpp18
-rw-r--r--test/SemaCXX/default2.cpp22
-rw-r--r--test/SemaCXX/deleted-function.cpp2
-rw-r--r--test/SemaCXX/destructor.cpp11
-rw-r--r--test/SemaCXX/direct-initializer.cpp14
-rw-r--r--test/SemaCXX/empty-class-layout.cpp68
-rw-r--r--test/SemaCXX/enum.cpp13
-rw-r--r--test/SemaCXX/exception-spec.cpp126
-rw-r--r--test/SemaCXX/friend-class-nodecl.cpp10
-rw-r--r--test/SemaCXX/function-overloaded-redecl.cpp10
-rw-r--r--test/SemaCXX/functional-cast.cpp294
-rw-r--r--test/SemaCXX/i-c-e-cxx.cpp10
-rw-r--r--test/SemaCXX/illegal-member-initialization.cpp22
-rw-r--r--test/SemaCXX/incomplete-call.cpp38
-rw-r--r--test/SemaCXX/inherit.cpp2
-rw-r--r--test/SemaCXX/invalid-member-expr.cpp21
-rw-r--r--test/SemaCXX/invalid-template-specifier.cpp12
-rw-r--r--test/SemaCXX/libstdcxx_is_pod_hack.cpp7
-rw-r--r--test/SemaCXX/linkage-spec.cpp8
-rw-r--r--test/SemaCXX/member-expr-static.cpp18
-rw-r--r--test/SemaCXX/member-name-lookup.cpp10
-rw-r--r--test/SemaCXX/member-operator-expr.cpp29
-rw-r--r--test/SemaCXX/member-pointer.cpp10
-rw-r--r--test/SemaCXX/missing-members.cpp36
-rw-r--r--test/SemaCXX/namespace.cpp5
-rw-r--r--test/SemaCXX/nested-name-spec.cpp23
-rw-r--r--test/SemaCXX/new-delete.cpp45
-rw-r--r--test/SemaCXX/overload-value-dep-arg.cpp13
-rw-r--r--test/SemaCXX/overloaded-builtin-operators.cpp36
-rw-r--r--test/SemaCXX/overloaded-operator.cpp37
-rw-r--r--test/SemaCXX/primary-base.cpp11
-rw-r--r--test/SemaCXX/pseudo-destructors.cpp40
-rw-r--r--test/SemaCXX/qual-id-test.cpp140
-rw-r--r--test/SemaCXX/ref-init-ambiguous.cpp28
-rw-r--r--test/SemaCXX/references.cpp15
-rw-r--r--test/SemaCXX/return.cpp18
-rw-r--r--test/SemaCXX/static-array-member.cpp18
-rw-r--r--test/SemaCXX/static-cast-complete-type.cpp13
-rw-r--r--test/SemaCXX/static-cast.cpp22
-rw-r--r--test/SemaCXX/static-initializers.cpp10
-rw-r--r--test/SemaCXX/type-traits-incomplete.cpp7
-rw-r--r--test/SemaCXX/type-traits.cpp149
-rw-r--r--test/SemaCXX/unknown-type-name.cpp29
-rw-r--r--test/SemaCXX/unreachable-catch-clauses.cpp14
-rw-r--r--test/SemaCXX/using-decl-1.cpp11
-rw-r--r--test/SemaCXX/using-decl-templates.cpp36
-rw-r--r--test/SemaCXX/value-dependent-exprs.cpp47
-rw-r--r--test/SemaCXX/vararg-non-pod.cpp14
-rw-r--r--test/SemaCXX/vector-casts.cpp40
-rw-r--r--test/SemaCXX/warn-assignment-condition.cpp65
-rw-r--r--test/SemaCXX/warn-char-subscripts.cpp21
-rw-r--r--test/SemaCXX/warn-for-var-in-else.cpp1
-rw-r--r--test/SemaCXX/warn-reorder-ctor-initialization.cpp89
-rw-r--r--test/SemaCXX/warn-unused-variables.cpp6
-rw-r--r--test/SemaCXX/wchar_t.cpp4
-rw-r--r--test/SemaObjC/access-property-getter.m1
-rw-r--r--test/SemaObjC/attr-malloc.m16
-rw-r--r--test/SemaObjC/block-explicit-return-type.m77
-rw-r--r--test/SemaObjC/blocks.m11
-rw-r--r--test/SemaObjC/call-super-2.m4
-rw-r--r--test/SemaObjC/category-1.m19
-rw-r--r--test/SemaObjC/category-method-lookup-2.m1
-rw-r--r--test/SemaObjC/class-bitfield.m6
-rw-r--r--test/SemaObjC/class-getter-using-dotsyntax.m39
-rw-r--r--test/SemaObjC/class-impl-1.m2
-rw-r--r--test/SemaObjC/compatible-protocol-qualified-types.m1
-rw-r--r--test/SemaObjC/comptypes-1.m4
-rw-r--r--test/SemaObjC/comptypes-3.m12
-rw-r--r--test/SemaObjC/comptypes-5.m4
-rw-r--r--test/SemaObjC/comptypes-7.m4
-rw-r--r--test/SemaObjC/comptypes-a.m1
-rw-r--r--test/SemaObjC/conditional-expr-3.m6
-rw-r--r--test/SemaObjC/conditional-expr-4.m20
-rw-r--r--test/SemaObjC/conditional-expr-5.m27
-rw-r--r--test/SemaObjC/conditional-expr.m83
-rw-r--r--test/SemaObjC/crash-label.m9
-rw-r--r--test/SemaObjC/deref-interface.m12
-rw-r--r--test/SemaObjC/format-arg-attribute.m3
-rw-r--r--test/SemaObjC/id-isa-ref.m37
-rw-r--r--test/SemaObjC/id.m2
-rw-r--r--test/SemaObjC/interface-scope-2.m2
-rw-r--r--test/SemaObjC/invalid-objc-decls-1.m8
-rw-r--r--test/SemaObjC/message.m2
-rw-r--r--test/SemaObjC/method-arg-decay.m1
-rw-r--r--test/SemaObjC/method-conflict.m4
-rw-r--r--test/SemaObjC/method-encoding-2.m4
-rw-r--r--test/SemaObjC/method-lookup-2.m5
-rw-r--r--test/SemaObjC/method-lookup.m1
-rw-r--r--test/SemaObjC/method-typecheck-1.m11
-rw-r--r--test/SemaObjC/no-warn-unimpl-method.m2
-rw-r--r--test/SemaObjC/nonnull.m42
-rw-r--r--test/SemaObjC/nsobject-attribute.m2
-rw-r--r--test/SemaObjC/objc2-merge-gc-attribue-decl.m5
-rw-r--r--test/SemaObjC/property-11.m1
-rw-r--r--test/SemaObjC/property-9-impl-method.m3
-rw-r--r--test/SemaObjC/property-error-readonly-assign.m23
-rw-r--r--test/SemaObjC/property-expression-error.m18
-rw-r--r--test/SemaObjC/property-method-lookup-impl.m4
-rw-r--r--test/SemaObjC/property-missing.m2
-rw-r--r--test/SemaObjC/protocol-archane.m3
-rw-r--r--test/SemaObjC/protocol-attribute.m4
-rw-r--r--test/SemaObjC/protocol-implementation-inherited.m2
-rw-r--r--test/SemaObjC/protocol-lookup.m1
-rw-r--r--test/SemaObjC/protocol-qualified-class-unsupported.m2
-rw-r--r--test/SemaObjC/rdr-6211479-array-property.m3
-rw-r--r--test/SemaObjC/return.m6
-rw-r--r--test/SemaObjC/selector-1.m13
-rw-r--r--test/SemaObjC/sizeof-interface.m11
-rw-r--r--test/SemaObjC/static-ivar-ref-1.m3
-rw-r--r--test/SemaObjC/super-cat-prot.m4
-rw-r--r--test/SemaObjC/super.m1
-rw-r--r--test/SemaObjC/synchronized.m2
-rw-r--r--test/SemaObjC/undef-superclass-1.m7
-rw-r--r--test/SemaObjC/unused.m33
-rw-r--r--test/SemaObjC/warn-assign-property-nscopying.m15
-rw-r--r--test/SemaObjC/warn-superclass-method-mismatch.m50
-rw-r--r--test/SemaObjC/weak-attr-ivar.m5
-rw-r--r--test/SemaObjCXX/overload.mm1
-rw-r--r--test/SemaObjCXX/protocol-lookup.mm1
-rw-r--r--test/SemaObjCXX/references.mm4
-rw-r--r--test/SemaTemplate/ackermann.cpp7
-rw-r--r--test/SemaTemplate/ambiguous-ovl-print.cpp9
-rw-r--r--test/SemaTemplate/canonical-expr-type-0x.cpp16
-rw-r--r--test/SemaTemplate/canonical-expr-type.cpp53
-rw-r--r--test/SemaTemplate/class-template-spec.cpp34
-rw-r--r--test/SemaTemplate/constructor-template.cpp53
-rw-r--r--test/SemaTemplate/copy-ctor-assign.cpp36
-rw-r--r--test/SemaTemplate/current-instantiation.cpp73
-rw-r--r--test/SemaTemplate/default-arguments.cpp20
-rw-r--r--test/SemaTemplate/default-expr-arguments.cpp86
-rw-r--r--test/SemaTemplate/dependent-base-member-init.cpp36
-rw-r--r--test/SemaTemplate/dependent-type-identity.cpp2
-rw-r--r--test/SemaTemplate/destructor-template.cpp12
-rw-r--r--test/SemaTemplate/example-dynarray.cpp63
-rw-r--r--test/SemaTemplate/explicit-instantiation.cpp75
-rw-r--r--test/SemaTemplate/explicit-specialization-member.cpp11
-rw-r--r--test/SemaTemplate/ext-vector-type.cpp2
-rw-r--r--test/SemaTemplate/extern-templates.cpp66
-rw-r--r--test/SemaTemplate/friend-template.cpp64
-rw-r--r--test/SemaTemplate/friend.cpp14
-rw-r--r--test/SemaTemplate/fun-template-def.cpp7
-rw-r--r--test/SemaTemplate/function-template-specialization.cpp35
-rw-r--r--test/SemaTemplate/implicit-instantiation-1.cpp2
-rw-r--r--test/SemaTemplate/injected-class-name.cpp10
-rw-r--r--test/SemaTemplate/instantiate-anonymous-union.cpp31
-rw-r--r--test/SemaTemplate/instantiate-cast.cpp8
-rw-r--r--test/SemaTemplate/instantiate-deeply.cpp22
-rw-r--r--test/SemaTemplate/instantiate-expr-2.cpp48
-rw-r--r--test/SemaTemplate/instantiate-expr-5.cpp4
-rw-r--r--test/SemaTemplate/instantiate-friend-class.cpp9
-rw-r--r--test/SemaTemplate/instantiate-function-1.cpp2
-rw-r--r--test/SemaTemplate/instantiate-function-1.mm3
-rw-r--r--test/SemaTemplate/instantiate-init.cpp28
-rw-r--r--test/SemaTemplate/instantiate-member-initializers.cpp26
-rw-r--r--test/SemaTemplate/instantiate-member-template.cpp105
-rw-r--r--test/SemaTemplate/instantiate-method.cpp9
-rw-r--r--test/SemaTemplate/instantiate-static-var.cpp22
-rw-r--r--test/SemaTemplate/instantiate-typedef.cpp2
-rw-r--r--test/SemaTemplate/instantiate-using-decl.cpp17
-rw-r--r--test/SemaTemplate/member-access-expr.cpp77
-rw-r--r--test/SemaTemplate/member-function-template.cpp51
-rw-r--r--test/SemaTemplate/member-initializers.cpp13
-rw-r--r--test/SemaTemplate/member-template-access-expr.cpp30
-rw-r--r--test/SemaTemplate/metafun-apply.cpp3
-rw-r--r--test/SemaTemplate/nested-linkage.cpp3
-rw-r--r--test/SemaTemplate/nested-template.cpp89
-rw-r--r--test/SemaTemplate/partial-spec-instantiate.cpp20
-rw-r--r--test/SemaTemplate/qualified-id.cpp9
-rw-r--r--test/SemaTemplate/qualified-names-diag.cpp2
-rw-r--r--test/SemaTemplate/temp_class_order.cpp42
-rw-r--r--test/SemaTemplate/temp_class_spec.cpp75
-rw-r--r--test/SemaTemplate/temp_class_spec_neg.cpp4
-rw-r--r--test/SemaTemplate/temp_func_order.cpp95
-rw-r--r--test/SemaTemplate/typename-specifier-4.cpp70
-rw-r--r--test/SemaTemplate/typename-specifier.cpp15
-rw-r--r--test/SemaTemplate/value-dependent-null-pointer-constant.cpp29
-rwxr-xr-xtest/TestRunner.sh137
-rw-r--r--test/lit.cfg152
-rw-r--r--test/lit.site.cfg.in10
-rw-r--r--tools/CIndex/CIndex.cpp745
-rw-r--r--tools/CIndex/CIndex.exports29
-rw-r--r--tools/CIndex/CMakeLists.txt27
-rw-r--r--tools/CIndex/Makefile54
-rw-r--r--tools/CMakeLists.txt9
-rw-r--r--tools/Makefile2
-rw-r--r--tools/c-index-test/CMakeLists.txt25
-rw-r--r--tools/c-index-test/Makefile24
-rw-r--r--tools/c-index-test/c-index-test.c106
-rw-r--r--tools/clang-cc/CMakeLists.txt3
-rw-r--r--tools/clang-cc/clang-cc.cpp907
-rw-r--r--tools/driver/CMakeLists.txt2
-rw-r--r--tools/driver/Makefile6
-rw-r--r--tools/driver/driver.cpp126
-rw-r--r--tools/index-test/CMakeLists.txt2
-rw-r--r--tools/index-test/Makefile5
-rw-r--r--tools/index-test/index-test.cpp271
-rw-r--r--tools/wpa/CMakeLists.txt20
-rw-r--r--tools/wpa/Makefile16
-rw-r--r--tools/wpa/clang-wpa.cpp62
-rwxr-xr-xutils/ABITest/ABITestGen.py2
-rw-r--r--utils/C++Tests/LLVM-Syntax/lit.local.cfg22
-rw-r--r--utils/C++Tests/lit.cfg18
-rw-r--r--utils/C++Tests/stdc++-Syntax/lit.local.cfg17
-rwxr-xr-xutils/CaptureCmd2
-rwxr-xr-xutils/CmpDriver92
-rwxr-xr-xutils/FindSpecRefs2
-rwxr-xr-xutils/SummarizeErrors2
-rwxr-xr-xutils/analyzer/CmpRuns230
-rwxr-xr-xutils/ccc-analyzer139
-rw-r--r--utils/clang-completion-mode.el257
-rwxr-xr-xutils/scan-build67
-rw-r--r--utils/valgrind/x86_64-pc-linux-gnu_gcc-4.3.3.supp23
-rw-r--r--www/OpenProjects.html10
-rw-r--r--www/analyzer/annotations.html12
-rw-r--r--www/analyzer/content.css2
-rw-r--r--www/analyzer/latest_checker.html.incl2
-rw-r--r--www/analyzer/menu.css4
-rw-r--r--www/analyzer/menu.html.incl7
-rw-r--r--www/comparison.html3
-rw-r--r--www/content.css2
-rw-r--r--www/cxx_status.html587
-rw-r--r--www/diagnostics.html71
-rw-r--r--www/features.html1
-rw-r--r--www/get_started.html107
-rw-r--r--www/hacking.html104
-rw-r--r--www/menu.html.incl20
1226 files changed, 105925 insertions, 41032 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index bb128d6..0cd52d0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,3 +1,26 @@
+# Clang version information
+
+# Make sure that CMake reconfigures when the version changes.
+configure_file(
+ ${CMAKE_CURRENT_SOURCE_DIR}/VER
+ ${CMAKE_CURRENT_BINARY_DIR}/VER)
+
+set(CLANG_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
+set(CLANG_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
+
+# Compute the Clang version from the contents of VER
+file(READ ${CMAKE_CURRENT_SOURCE_DIR}/VER CLANG_VERSION_DATA)
+string(REGEX MATCH "[0-9]+\\.[0-9]+(\\.[0-9]+)?" CLANG_VERSION
+ ${CLANG_VERSION_DATA})
+message(STATUS "Clang version: ${CLANG_VERSION}")
+
+# Add appropriate flags for GCC
+if (CMAKE_COMPILER_IS_GNUCXX)
+ # FIXME: Turn off exceptions, RTTI:
+ # -fno-exceptions -fno-rtti
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-common -Woverloaded-virtual -pedantic -Wno-long-long -Wall -W -Wno-unused-parameter -Wwrite-strings")
+endif ()
+
macro(add_clang_library name)
set(srcs ${ARGN})
if(MSVC_IDE OR XCODE)
@@ -11,10 +34,27 @@ macro(add_clang_library name)
../../include/clang${dir}/*.def)
set(srcs ${srcs} ${headers})
endif(MSVC_IDE OR XCODE)
- add_library( ${name} ${srcs} )
+ if (SHARED_LIBRARY)
+ set(libkind SHARED)
+ else()
+ set(libkind)
+ endif()
+ add_library( ${name} ${libkind} ${srcs} )
if( LLVM_COMMON_DEPENDS )
add_dependencies( ${name} ${LLVM_COMMON_DEPENDS} )
endif( LLVM_COMMON_DEPENDS )
+ if( LLVM_USED_LIBS )
+ foreach(lib ${LLVM_USED_LIBS})
+ target_link_libraries( ${name} ${lib} )
+ endforeach(lib)
+ endif( LLVM_USED_LIBS )
+ if( LLVM_LINK_COMPONENTS )
+ llvm_config(${name} ${LLVM_LINK_COMPONENTS})
+ endif( LLVM_LINK_COMPONENTS )
+ get_system_libs(llvm_system_libs)
+ if( llvm_system_libs )
+ target_link_libraries(${name} ${llvm_system_libs})
+ endif( llvm_system_libs )
add_dependencies(${name} ClangDiagnosticCommon)
if(MSVC)
get_target_property(cflag ${name} COMPILE_FLAGS)
@@ -36,8 +76,6 @@ macro(add_clang_executable name)
set(srcs ${srcs} ${headers})
endif(MSVC_IDE)
add_llvm_executable( ${name} ${srcs} )
- install(TARGETS ${name}
- RUNTIME DESTINATION bin)
endmacro(add_clang_executable)
include_directories(
@@ -57,4 +95,5 @@ add_subdirectory(lib)
add_subdirectory(tools)
# TODO: docs.
-add_subdirectory(test) \ No newline at end of file
+add_subdirectory(test)
+
diff --git a/INPUTS/all-std-headers.cpp b/INPUTS/all-std-headers.cpp
new file mode 100644
index 0000000..bddf4ec
--- /dev/null
+++ b/INPUTS/all-std-headers.cpp
@@ -0,0 +1,51 @@
+#include <algorithm>
+#include <bitset>
+#include <cassert>
+#include <cctype>
+#include <cerrno>
+#include <cfloat>
+#include <ciso646>
+#include <climits>
+#include <clocale>
+#include <cmath>
+#include <complex>
+#include <csetjmp>
+#include <csignal>
+#include <cstdarg>
+#include <cstddef>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <ctime>
+#include <cwchar>
+#include <cwctype>
+#include <deque>
+#include <exception>
+#include <fstream>
+#include <functional>
+#include <iomanip>
+#include <ios>
+#include <iosfwd>
+#include <iostream>
+#include <istream>
+#include <iterator>
+#include <limits>
+#include <list>
+#include <locale>
+#include <map>
+#include <memory>
+#include <new>
+#include <numeric>
+#include <ostream>
+#include <queue>
+#include <set>
+#include <sstream>
+#include <stack>
+#include <stdexcept>
+#include <streambuf>
+#include <string>
+#include <strstream>
+#include <typeinfo>
+#include <utility>
+#include <valarray>
+#include <vector>
diff --git a/INSTALL.txt b/INSTALL.txt
new file mode 100644
index 0000000..e8e3209
--- /dev/null
+++ b/INSTALL.txt
@@ -0,0 +1,49 @@
+//===----------------------------------------------------------------------===//
+// Clang Installation Instructions
+//===----------------------------------------------------------------------===//
+
+These instructions describe how to build and install Clang.
+
+//===----------------------------------------------------------------------===//
+// Step 1: Organization
+//===----------------------------------------------------------------------===//
+
+Clang is designed to be built as part of an LLVM build. Assuming that the LLVM
+source code is located at $LLVM_SRC_ROOT, then the clang source code should be
+installed as:
+
+ $LLVM_SRC_ROOT/tools/clang
+
+The directory is not required to be called clang, but doing so will allow the
+LLVM build system to automatically recognize it and build it along with LLVM.
+
+//===----------------------------------------------------------------------===//
+// Step 2: Configure and Build LLVM
+//===----------------------------------------------------------------------===//
+
+Configure and build your copy of LLVM (see $LLVM_SRC_ROOT/GettingStarted.html
+for more information).
+
+Assuming you installed clang at $LLVM_SRC_ROOT/tools/clang then Clang will
+automatically be built with LLVM. Otherwise, run 'make' in the Clang source
+directory to build Clang.
+
+//===----------------------------------------------------------------------===//
+// Step 3: (Optional) Verify Your Build
+//===----------------------------------------------------------------------===//
+
+It is a good idea to run the Clang tests to make sure your build works
+correctly. From inside the Clang build directory, run 'make test' to run the
+tests.
+
+//===----------------------------------------------------------------------===//
+// Step 4: Install Clang
+//===----------------------------------------------------------------------===//
+
+From inside the Clang build directory, run 'make install' to install the Clang
+compiler and header files into the prefix directory selected when LLVM was
+configured.
+
+The Clang compiler is available as 'clang' and supports a gcc like command line
+interface. See the man page for clang (installed into $prefix/share/man/man1)
+for more information.
diff --git a/LICENSE.TXT b/LICENSE.TXT
index 21cb5c7..72faf41 100644
--- a/LICENSE.TXT
+++ b/LICENSE.TXT
@@ -4,7 +4,7 @@ LLVM Release License
University of Illinois/NCSA
Open Source License
-Copyright (c) 2007 University of Illinois at Urbana-Champaign.
+Copyright (c) 2007-2009 University of Illinois at Urbana-Champaign.
All rights reserved.
Developed by:
diff --git a/Makefile b/Makefile
index 00e38d2..22fe214 100644
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@ DIRS := include lib tools docs
include $(LEVEL)/Makefile.common
ifneq ($(PROJ_SRC_ROOT),$(PROJ_OBJ_ROOT))
-test::
+all::
$(Verb) if [ ! -f test/Makefile ]; then \
$(MKDIR) test; \
$(CP) $(PROJ_SRC_DIR)/test/Makefile test/Makefile; \
@@ -30,3 +30,30 @@ cscope.files:
-or -name '*.h' > cscope.files
.PHONY: test report clean cscope.files
+
+install-local::
+ $(Echo) Installing include files
+ $(Verb) $(MKDIR) $(PROJ_includedir)
+ $(Verb) if test -d "$(PROJ_SRC_ROOT)/tools/clang/include" ; then \
+ cd $(PROJ_SRC_ROOT)/tools/clang/include && \
+ for hdr in `find . -type f '!' '(' -name '*~' \
+ -o -name '.#*' -o -name '*.in' -o -name '*.txt' \
+ -o -name 'Makefile' -o -name '*.td' ')' -print \
+ | grep -v CVS | grep -v .svn` ; do \
+ instdir=`dirname "$(PROJ_includedir)/$$hdr"` ; \
+ if test \! -d "$$instdir" ; then \
+ $(EchoCmd) Making install directory $$instdir ; \
+ $(MKDIR) $$instdir ;\
+ fi ; \
+ $(DataInstall) $$hdr $(PROJ_includedir)/$$hdr ; \
+ done ; \
+ fi
+ifneq ($(PROJ_SRC_ROOT),$(PROJ_OBJ_ROOT))
+ $(Verb) if test -d "$(PROJ_OBJ_ROOT)/tools/clang/include" ; then \
+ cd $(PROJ_OBJ_ROOT)/tools/clang/include && \
+ for hdr in `find . -type f '!' '(' -name 'Makefile' ')' -print \
+ | grep -v CVS | grep -v .tmp` ; do \
+ $(DataInstall) $$hdr $(PROJ_includedir)/$$hdr ; \
+ done ; \
+ fi
+endif
diff --git a/NOTES.txt b/NOTES.txt
index 3b5ad16..c658fe9 100644
--- a/NOTES.txt
+++ b/NOTES.txt
@@ -16,8 +16,8 @@ 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
+$ clang -ccc-pch-is-pth -x objective-c-header INPUTS/Cocoa_h.m -o /tmp/tokencache
+$ clang-cc -token-cache /tmp/tokencache INPUTS/Cocoa_h.m
//===---------------------------------------------------------------------===//
diff --git a/README.txt b/README.txt
index 611dc9d..924ecc4 100644
--- a/README.txt
+++ b/README.txt
@@ -1,178 +1,26 @@
//===----------------------------------------------------------------------===//
// 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.
+Welcome to Clang. This is a compiler front-end for the C family of languages
+(C, C++, Objective-C, and Objective-C++) which is built as part of the LLVM
+compiler intrastructure project.
- 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? :)
+Unlike many other compiler frontends, Clang is useful for a number of things
+beyond just compiling code: we intend for Clang to be host to a number of
+different source level tools. One example of this is the Clang Static Analyzer.
- 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.
+If you're interested in more (including how to build Clang) it is best to read
+the relevant web sites. Here are some pointers:
- 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.
+Information on Clang: http://clang.llvm.org/
+Building and using Clang: http://clang.llvm.org/get_started.html
+Clang Static Analyzer: http://clang-analyzer.llvm.org/
+Information on the LLVM project: http://llvm.org/
- 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. :)
+If you have questions or comments about Clang, a great place to discuss them is
+on the Clang development mailing list:
+ http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
+If you find a bug in Clang, please file it in the LLVM bug tracker:
+ http://llvm.org/bugs/
diff --git a/VER b/VER
new file mode 100644
index 0000000..9459d4b
--- /dev/null
+++ b/VER
@@ -0,0 +1 @@
+1.1
diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj
index 26be7bb..24e1ac3 100644
--- a/clang.xcodeproj/project.pbxproj
+++ b/clang.xcodeproj/project.pbxproj
@@ -30,18 +30,27 @@
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 */; };
+ 1A4C41BF105B4C0B0047B5E7 /* CGCXXClass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A4C41BE105B4C0B0047B5E7 /* CGCXXClass.cpp */; };
+ 1A535ED9107BC45E000C3AE7 /* CXXInheritance.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A535ED8107BC45E000C3AE7 /* CXXInheritance.cpp */; };
1A5D5E580E5E81010023C059 /* CGCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A5D5E570E5E81010023C059 /* CGCXX.cpp */; };
+ 1A6B6CD410693FC900BB4A8F /* CodeCompleteConsumer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6B6CD110693FC900BB4A8F /* CodeCompleteConsumer.cpp */; };
+ 1A6B6CD510693FC900BB4A8F /* SemaCodeComplete.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6B6CD210693FC900BB4A8F /* SemaCodeComplete.cpp */; };
+ 1A6B6E9A1069833600BB4A8F /* CGCXXExpr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6B6E991069833600BB4A8F /* CGCXXExpr.cpp */; };
+ 1A6C01F7108128710072DEE4 /* CGRtti.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6C01F6108128710072DEE4 /* CGRtti.cpp */; };
1A6FE7090FD6F85800E00CA9 /* CGCXXTemp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6FE7080FD6F85800E00CA9 /* CGCXXTemp.cpp */; };
1A701B640F7C8FE400FEC4D1 /* SemaAccess.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A701B630F7C8FE400FEC4D1 /* SemaAccess.cpp */; };
1A7342480C7B57D500122F56 /* CGObjC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A7342470C7B57D500122F56 /* CGObjC.cpp */; };
+ 1A81AA19108144F40094E50B /* CGVtable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A81AA18108144F40094E50B /* CGVtable.cpp */; };
1A869A700BA2164C008DA07A /* LiteralSupport.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 1A869A6E0BA2164C008DA07A /* LiteralSupport.h */; };
1A869AA80BA21ABA008DA07A /* LiteralSupport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A869AA70BA21ABA008DA07A /* LiteralSupport.cpp */; };
+ 1AA1D91810125DE30078DEBC /* RecordLayoutBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AA1D91610125DE30078DEBC /* RecordLayoutBuilder.cpp */; };
1ABC36940C7A4BDC006DB0AB /* CGBuiltin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABC36930C7A4BDC006DB0AB /* CGBuiltin.cpp */; };
1ADF47AF0F782C3200E48A8A /* SemaTemplateInstantiateDecl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ADF47AE0F782C3200E48A8A /* SemaTemplateInstantiateDecl.cpp */; };
+ 1AE4EE3E103B89ED00888A23 /* StmtProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AE4EE3D103B89ED00888A23 /* StmtProfile.cpp */; };
+ 1AE4EE40103B8A0A00888A23 /* TargetABIInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AE4EE3F103B8A0A00888A23 /* TargetABIInfo.cpp */; };
1AFEF4070F8A6B2300476F2B /* clang-cc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AFEF4050F8A6B2300476F2B /* clang-cc.cpp */; };
+ 1AFF8AE31012BFC900D248DA /* CGRecordLayoutBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AFF8AE11012BFC900D248DA /* CGRecordLayoutBuilder.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 */; };
@@ -66,7 +75,6 @@
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 */; };
@@ -92,7 +100,7 @@
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 */; };
+ 35E1946A0ECB82FB00F21733 /* SemaCXXCast.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35E194680ECB82FB00F21733 /* SemaCXXCast.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 */; };
@@ -105,7 +113,22 @@
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 */; };
+ 9012911D1048068D0083456D /* ASTUnit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9012911C1048068D0083456D /* ASTUnit.cpp */; };
+ 90129121104812F90083456D /* CIndex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9012911F104812F90083456D /* CIndex.cpp */; };
906BF4B00F83BA2E001071FA /* ConvertUTF.c in Sources */ = {isa = PBXBuildFile; fileRef = 906BF4AF0F83BA2E001071FA /* ConvertUTF.c */; };
+ 90F9EFAA104ABDED00D09A15 /* c-index-test.c in Sources */ = {isa = PBXBuildFile; fileRef = 90F9EFA9104ABDED00D09A15 /* c-index-test.c */; };
+ 90FD6D7B103C3D49005F5B73 /* Analyzer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90FD6D6D103C3D49005F5B73 /* Analyzer.cpp */; };
+ 90FD6D7C103C3D49005F5B73 /* ASTLocation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90FD6D6E103C3D49005F5B73 /* ASTLocation.cpp */; };
+ 90FD6D7D103C3D49005F5B73 /* DeclReferenceMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90FD6D70103C3D49005F5B73 /* DeclReferenceMap.cpp */; };
+ 90FD6D7E103C3D49005F5B73 /* Entity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90FD6D71103C3D49005F5B73 /* Entity.cpp */; };
+ 90FD6D7F103C3D49005F5B73 /* GlobalSelector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90FD6D73103C3D49005F5B73 /* GlobalSelector.cpp */; };
+ 90FD6D80103C3D49005F5B73 /* Handlers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90FD6D74103C3D49005F5B73 /* Handlers.cpp */; };
+ 90FD6D81103C3D49005F5B73 /* Indexer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90FD6D75103C3D49005F5B73 /* Indexer.cpp */; };
+ 90FD6D82103C3D49005F5B73 /* IndexProvider.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90FD6D76103C3D49005F5B73 /* IndexProvider.cpp */; };
+ 90FD6D83103C3D49005F5B73 /* Program.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90FD6D77103C3D49005F5B73 /* Program.cpp */; };
+ 90FD6D84103C3D49005F5B73 /* ResolveLocation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90FD6D79103C3D49005F5B73 /* ResolveLocation.cpp */; };
+ 90FD6D85103C3D49005F5B73 /* SelectorMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90FD6D7A103C3D49005F5B73 /* SelectorMap.cpp */; };
+ 90FD6DB6103D977E005F5B73 /* index-test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90FD6DB5103D977E005F5B73 /* index-test.cpp */; };
BDF87CF70FD746F300BBF872 /* SemaTemplateDeduction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BDF87CF60FD746F300BBF872 /* SemaTemplateDeduction.cpp */; };
DE01DA490B12ADA300AC22CE /* PPCallbacks.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE01DA480B12ADA300AC22CE /* PPCallbacks.h */; };
DE06756C0C051CFE00EBBFD8 /* ParseExprCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE06756B0C051CFE00EBBFD8 /* ParseExprCXX.cpp */; };
@@ -188,8 +211,6 @@
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 */; };
@@ -307,7 +328,6 @@
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 */,
@@ -324,7 +344,7 @@
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>"; };
+ 1A2A54A50FD1DD1C00F4CE45 /* ASTConsumers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ASTConsumers.cpp; path = lib/Frontend/ASTConsumers.cpp; sourceTree = "<group>"; tabWidth = 2; };
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>"; };
@@ -336,19 +356,25 @@
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>"; };
+ 1A2A54B10FD1DD1C00F4CE45 /* RewriteObjC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = RewriteObjC.cpp; path = lib/Frontend/RewriteObjC.cpp; sourceTree = "<group>"; tabWidth = 2; };
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; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaTemplateInstantiateStmt.cpp; path = lib/Sema/SemaTemplateInstantiateStmt.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1A4C41BE105B4C0B0047B5E7 /* CGCXXClass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGCXXClass.cpp; path = lib/CodeGen/CGCXXClass.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1A535ED8107BC45E000C3AE7 /* CXXInheritance.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CXXInheritance.cpp; path = lib/AST/CXXInheritance.cpp; sourceTree = "<group>"; };
+ 1A535EDB107BC47B000C3AE7 /* CanonicalType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CanonicalType.h; path = clang/AST/CanonicalType.h; 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>"; };
+ 1A649E1E0F9599DA005B965E /* CGCXX.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CGCXX.h; path = lib/CodeGen/CGCXX.h; sourceTree = "<group>"; tabWidth = 2; };
+ 1A6B6CD110693FC900BB4A8F /* CodeCompleteConsumer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CodeCompleteConsumer.cpp; path = lib/Sema/CodeCompleteConsumer.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1A6B6CD210693FC900BB4A8F /* SemaCodeComplete.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaCodeComplete.cpp; path = lib/Sema/SemaCodeComplete.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1A6B6CD310693FC900BB4A8F /* SemaTemplate.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = SemaTemplate.h; path = lib/Sema/SemaTemplate.h; sourceTree = "<group>"; tabWidth = 2; };
+ 1A6B6E991069833600BB4A8F /* CGCXXExpr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGCXXExpr.cpp; path = lib/CodeGen/CGCXXExpr.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1A6C01F6108128710072DEE4 /* CGRtti.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGRtti.cpp; path = lib/CodeGen/CGRtti.cpp; sourceTree = "<group>"; tabWidth = 2; };
1A6FE7080FD6F85800E00CA9 /* CGCXXTemp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGCXXTemp.cpp; path = lib/CodeGen/CGCXXTemp.cpp; sourceTree = "<group>"; tabWidth = 2; };
1A7019E90F79BC1100FEC4D1 /* DiagnosticAnalysisKinds.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DiagnosticAnalysisKinds.td; sourceTree = "<group>"; };
1A7019EA0F79BC1100FEC4D1 /* DiagnosticASTKinds.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DiagnosticASTKinds.td; sourceTree = "<group>"; };
@@ -361,11 +387,21 @@
1A701B630F7C8FE400FEC4D1 /* SemaAccess.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaAccess.cpp; path = lib/Sema/SemaAccess.cpp; sourceTree = "<group>"; tabWidth = 2; };
1A72BEAC0D641E9400B085E9 /* Attr.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Attr.h; path = clang/AST/Attr.h; sourceTree = "<group>"; tabWidth = 2; };
1A7342470C7B57D500122F56 /* CGObjC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGObjC.cpp; path = lib/CodeGen/CGObjC.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1A81AA18108144F40094E50B /* CGVtable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGVtable.cpp; path = lib/CodeGen/CGVtable.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1A81AA5D108278A20094E50B /* CGVtable.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CGVtable.h; path = lib/CodeGen/CGVtable.h; sourceTree = "<group>"; tabWidth = 2; };
1A869A6E0BA2164C008DA07A /* LiteralSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LiteralSupport.h; sourceTree = "<group>"; };
1A869AA70BA21ABA008DA07A /* LiteralSupport.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = LiteralSupport.cpp; sourceTree = "<group>"; };
+ 1AA1D91610125DE30078DEBC /* RecordLayoutBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = RecordLayoutBuilder.cpp; path = lib/AST/RecordLayoutBuilder.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1AA1D91710125DE30078DEBC /* RecordLayoutBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = RecordLayoutBuilder.h; path = lib/AST/RecordLayoutBuilder.h; sourceTree = "<group>"; tabWidth = 2; };
+ 1AB290021045858B00FE33D8 /* PartialDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = PartialDiagnostic.h; sourceTree = "<group>"; tabWidth = 2; };
1ABC36930C7A4BDC006DB0AB /* CGBuiltin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGBuiltin.cpp; path = lib/CodeGen/CGBuiltin.cpp; sourceTree = "<group>"; tabWidth = 2; };
1ADF47AE0F782C3200E48A8A /* SemaTemplateInstantiateDecl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaTemplateInstantiateDecl.cpp; path = lib/Sema/SemaTemplateInstantiateDecl.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1AE4EE3B103B89CA00888A23 /* TreeTransform.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = TreeTransform.h; path = lib/Sema/TreeTransform.h; sourceTree = "<group>"; tabWidth = 2; };
+ 1AE4EE3D103B89ED00888A23 /* StmtProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = StmtProfile.cpp; path = lib/AST/StmtProfile.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1AE4EE3F103B8A0A00888A23 /* TargetABIInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = TargetABIInfo.cpp; path = lib/CodeGen/TargetABIInfo.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; };
+ 1AFF8AE11012BFC900D248DA /* CGRecordLayoutBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGRecordLayoutBuilder.cpp; path = lib/CodeGen/CGRecordLayoutBuilder.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1AFF8AE21012BFC900D248DA /* CGRecordLayoutBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CGRecordLayoutBuilder.h; path = lib/CodeGen/CGRecordLayoutBuilder.h; 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>"; };
@@ -406,7 +442,6 @@
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; };
@@ -453,7 +488,7 @@
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; };
+ 35E194680ECB82FB00F21733 /* SemaCXXCast.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaCXXCast.cpp; path = lib/Sema/SemaCXXCast.cpp; sourceTree = "<group>"; tabWidth = 2; };
35E1946C0ECB83C100F21733 /* PTHLexer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PTHLexer.cpp; sourceTree = "<group>"; };
35EE48AD0E0C4CB200715C54 /* DeclCXX.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclCXX.h; path = clang/AST/DeclCXX.h; sourceTree = "<group>"; tabWidth = 2; };
35EE48AE0E0C4CB200715C54 /* ParentMap.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ParentMap.h; path = clang/AST/ParentMap.h; sourceTree = "<group>"; tabWidth = 2; };
@@ -471,10 +506,15 @@
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>"; };
+ 7F270AFE107A90010031B377 /* CodeCompleteConsumer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CodeCompleteConsumer.h; path = clang/Sema/CodeCompleteConsumer.h; 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; };
+ 9012911510470FCE0083456D /* Index.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Index.h; path = "clang-c/Index.h"; sourceTree = "<group>"; };
+ 9012911C1048068D0083456D /* ASTUnit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ASTUnit.cpp; path = lib/Frontend/ASTUnit.cpp; sourceTree = "<group>"; };
+ 9012911F104812F90083456D /* CIndex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CIndex.cpp; path = tools/CIndex/CIndex.cpp; sourceTree = "<group>"; };
+ 90129120104812F90083456D /* CIndex.exports */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = CIndex.exports; path = tools/CIndex/CIndex.exports; sourceTree = "<group>"; };
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>"; };
@@ -482,9 +522,50 @@
9063F22A0F9E911F002F7251 /* TemplateKinds.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TemplateKinds.h; sourceTree = "<group>"; };
906BF4AE0F83BA16001071FA /* ConvertUTF.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConvertUTF.h; sourceTree = "<group>"; };
906BF4AF0F83BA2E001071FA /* ConvertUTF.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ConvertUTF.c; sourceTree = "<group>"; };
+ 90F9EFA9104ABDED00D09A15 /* c-index-test.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "c-index-test.c"; path = "tools/c-index-test/c-index-test.c"; sourceTree = "<group>"; };
90FB99DE0F98FB1D008F9415 /* DeclContextInternals.h */ = {isa = PBXFileReference; fileEncoding = 4; 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>"; };
+ 90FD6D5F103C3D21005F5B73 /* Analyzer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Analyzer.h; path = clang/Index/Analyzer.h; sourceTree = "<group>"; };
+ 90FD6D60103C3D21005F5B73 /* ASTLocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTLocation.h; path = clang/Index/ASTLocation.h; sourceTree = "<group>"; };
+ 90FD6D61103C3D21005F5B73 /* DeclReferenceMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DeclReferenceMap.h; path = clang/Index/DeclReferenceMap.h; sourceTree = "<group>"; };
+ 90FD6D62103C3D21005F5B73 /* Entity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Entity.h; path = clang/Index/Entity.h; sourceTree = "<group>"; };
+ 90FD6D63103C3D21005F5B73 /* GlobalSelector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GlobalSelector.h; path = clang/Index/GlobalSelector.h; sourceTree = "<group>"; };
+ 90FD6D64103C3D21005F5B73 /* Handlers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Handlers.h; path = clang/Index/Handlers.h; sourceTree = "<group>"; };
+ 90FD6D65103C3D21005F5B73 /* Indexer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Indexer.h; path = clang/Index/Indexer.h; sourceTree = "<group>"; };
+ 90FD6D66103C3D21005F5B73 /* IndexProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IndexProvider.h; path = clang/Index/IndexProvider.h; sourceTree = "<group>"; };
+ 90FD6D67103C3D21005F5B73 /* Program.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Program.h; path = clang/Index/Program.h; sourceTree = "<group>"; };
+ 90FD6D68103C3D21005F5B73 /* SelectorMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SelectorMap.h; path = clang/Index/SelectorMap.h; sourceTree = "<group>"; };
+ 90FD6D69103C3D21005F5B73 /* STLExtras.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = STLExtras.h; path = clang/Index/STLExtras.h; sourceTree = "<group>"; };
+ 90FD6D6A103C3D21005F5B73 /* TranslationUnit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TranslationUnit.h; path = clang/Index/TranslationUnit.h; sourceTree = "<group>"; };
+ 90FD6D6B103C3D21005F5B73 /* Utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Utils.h; path = clang/Index/Utils.h; sourceTree = "<group>"; };
+ 90FD6D6D103C3D49005F5B73 /* Analyzer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Analyzer.cpp; path = lib/Index/Analyzer.cpp; sourceTree = "<group>"; };
+ 90FD6D6E103C3D49005F5B73 /* ASTLocation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ASTLocation.cpp; path = lib/Index/ASTLocation.cpp; sourceTree = "<group>"; };
+ 90FD6D6F103C3D49005F5B73 /* ASTVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTVisitor.h; path = lib/Index/ASTVisitor.h; sourceTree = "<group>"; };
+ 90FD6D70103C3D49005F5B73 /* DeclReferenceMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DeclReferenceMap.cpp; path = lib/Index/DeclReferenceMap.cpp; sourceTree = "<group>"; };
+ 90FD6D71103C3D49005F5B73 /* Entity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Entity.cpp; path = lib/Index/Entity.cpp; sourceTree = "<group>"; };
+ 90FD6D72103C3D49005F5B73 /* EntityImpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EntityImpl.h; path = lib/Index/EntityImpl.h; sourceTree = "<group>"; };
+ 90FD6D73103C3D49005F5B73 /* GlobalSelector.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GlobalSelector.cpp; path = lib/Index/GlobalSelector.cpp; sourceTree = "<group>"; };
+ 90FD6D74103C3D49005F5B73 /* Handlers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Handlers.cpp; path = lib/Index/Handlers.cpp; sourceTree = "<group>"; };
+ 90FD6D75103C3D49005F5B73 /* Indexer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Indexer.cpp; path = lib/Index/Indexer.cpp; sourceTree = "<group>"; };
+ 90FD6D76103C3D49005F5B73 /* IndexProvider.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = IndexProvider.cpp; path = lib/Index/IndexProvider.cpp; sourceTree = "<group>"; };
+ 90FD6D77103C3D49005F5B73 /* Program.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Program.cpp; path = lib/Index/Program.cpp; sourceTree = "<group>"; };
+ 90FD6D78103C3D49005F5B73 /* ProgramImpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProgramImpl.h; path = lib/Index/ProgramImpl.h; sourceTree = "<group>"; };
+ 90FD6D79103C3D49005F5B73 /* ResolveLocation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ResolveLocation.cpp; path = lib/Index/ResolveLocation.cpp; sourceTree = "<group>"; };
+ 90FD6D7A103C3D49005F5B73 /* SelectorMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SelectorMap.cpp; path = lib/Index/SelectorMap.cpp; sourceTree = "<group>"; };
+ 90FD6D86103C3D80005F5B73 /* Analyses.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Analyses.def; path = clang/Frontend/Analyses.def; sourceTree = "<group>"; };
+ 90FD6D87103C3D80005F5B73 /* AnalysisConsumer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AnalysisConsumer.h; path = clang/Frontend/AnalysisConsumer.h; sourceTree = "<group>"; };
+ 90FD6D88103C3D80005F5B73 /* ASTConsumers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTConsumers.h; path = clang/Frontend/ASTConsumers.h; sourceTree = "<group>"; };
+ 90FD6D89103C3D80005F5B73 /* ASTUnit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTUnit.h; path = clang/Frontend/ASTUnit.h; sourceTree = "<group>"; };
+ 90FD6D8A103C3D80005F5B73 /* CommandLineSourceLoc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandLineSourceLoc.h; path = clang/Frontend/CommandLineSourceLoc.h; sourceTree = "<group>"; };
+ 90FD6D8B103C3D80005F5B73 /* DeclContextXML.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = DeclContextXML.def; path = clang/Frontend/DeclContextXML.def; sourceTree = "<group>"; };
+ 90FD6D8C103C3D80005F5B73 /* DeclXML.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = DeclXML.def; path = clang/Frontend/DeclXML.def; sourceTree = "<group>"; };
+ 90FD6D8D103C3D80005F5B73 /* DocumentXML.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = DocumentXML.def; path = clang/Frontend/DocumentXML.def; sourceTree = "<group>"; };
+ 90FD6D8E103C3D80005F5B73 /* DocumentXML.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DocumentXML.h; path = clang/Frontend/DocumentXML.h; sourceTree = "<group>"; };
+ 90FD6D8F103C3D80005F5B73 /* StmtXML.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = StmtXML.def; path = clang/Frontend/StmtXML.def; sourceTree = "<group>"; };
+ 90FD6D90103C3D80005F5B73 /* TypeXML.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = TypeXML.def; path = clang/Frontend/TypeXML.def; sourceTree = "<group>"; };
+ 90FD6D91103C3D80005F5B73 /* Utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Utils.h; path = clang/Frontend/Utils.h; sourceTree = "<group>"; };
+ 90FD6DB5103D977E005F5B73 /* index-test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "index-test.cpp"; path = "tools/index-test/index-test.cpp"; sourceTree = "<group>"; };
BDF87CF60FD746F300BBF872 /* SemaTemplateDeduction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaTemplateDeduction.cpp; path = lib/Sema/SemaTemplateDeduction.cpp; sourceTree = "<group>"; tabWidth = 2; };
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; };
@@ -530,7 +611,6 @@
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>"; };
@@ -603,8 +683,6 @@
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>"; };
@@ -741,6 +819,7 @@
08FB7795FE84155DC02AAC07 /* Libraries */ = {
isa = PBXGroup;
children = (
+ 90FD6D6C103C3D2D005F5B73 /* Index */,
DED7D7500A5242C7003AD0FB /* Basic */,
DED7D78C0A5242E6003AD0FB /* Lex */,
DE1F22600A7D8C9B00FBF588 /* Parse */,
@@ -817,6 +896,7 @@
352246E00F5C6BC000D0D279 /* Frontend */ = {
isa = PBXGroup;
children = (
+ 9012911C1048068D0083456D /* ASTUnit.cpp */,
1A2A54A40FD1DD1C00F4CE45 /* AnalysisConsumer.cpp */,
1A2A54A50FD1DD1C00F4CE45 /* ASTConsumers.cpp */,
1A2A54A60FD1DD1C00F4CE45 /* Backend.cpp */,
@@ -957,6 +1037,80 @@
name = Analyses;
sourceTree = "<group>";
};
+ 9012911210470FAF0083456D /* clang-c */ = {
+ isa = PBXGroup;
+ children = (
+ 9012911510470FCE0083456D /* Index.h */,
+ );
+ name = "clang-c";
+ sourceTree = "<group>";
+ };
+ 9012911E104812DA0083456D /* CIndex */ = {
+ isa = PBXGroup;
+ children = (
+ 9012911F104812F90083456D /* CIndex.cpp */,
+ 90129120104812F90083456D /* CIndex.exports */,
+ );
+ name = CIndex;
+ sourceTree = "<group>";
+ };
+ 90F9EFA8104ABDC400D09A15 /* c-index-test */ = {
+ isa = PBXGroup;
+ children = (
+ 90F9EFA9104ABDED00D09A15 /* c-index-test.c */,
+ );
+ name = "c-index-test";
+ sourceTree = "<group>";
+ };
+ 90FD6D5E103C3D03005F5B73 /* Index */ = {
+ isa = PBXGroup;
+ children = (
+ 90FD6D5F103C3D21005F5B73 /* Analyzer.h */,
+ 90FD6D60103C3D21005F5B73 /* ASTLocation.h */,
+ 90FD6D61103C3D21005F5B73 /* DeclReferenceMap.h */,
+ 90FD6D62103C3D21005F5B73 /* Entity.h */,
+ 90FD6D63103C3D21005F5B73 /* GlobalSelector.h */,
+ 90FD6D64103C3D21005F5B73 /* Handlers.h */,
+ 90FD6D65103C3D21005F5B73 /* Indexer.h */,
+ 90FD6D66103C3D21005F5B73 /* IndexProvider.h */,
+ 90FD6D67103C3D21005F5B73 /* Program.h */,
+ 90FD6D68103C3D21005F5B73 /* SelectorMap.h */,
+ 90FD6D69103C3D21005F5B73 /* STLExtras.h */,
+ 90FD6D6A103C3D21005F5B73 /* TranslationUnit.h */,
+ 90FD6D6B103C3D21005F5B73 /* Utils.h */,
+ );
+ name = Index;
+ sourceTree = "<group>";
+ };
+ 90FD6D6C103C3D2D005F5B73 /* Index */ = {
+ isa = PBXGroup;
+ children = (
+ 90FD6D6D103C3D49005F5B73 /* Analyzer.cpp */,
+ 90FD6D6E103C3D49005F5B73 /* ASTLocation.cpp */,
+ 90FD6D6F103C3D49005F5B73 /* ASTVisitor.h */,
+ 90FD6D70103C3D49005F5B73 /* DeclReferenceMap.cpp */,
+ 90FD6D71103C3D49005F5B73 /* Entity.cpp */,
+ 90FD6D72103C3D49005F5B73 /* EntityImpl.h */,
+ 90FD6D73103C3D49005F5B73 /* GlobalSelector.cpp */,
+ 90FD6D74103C3D49005F5B73 /* Handlers.cpp */,
+ 90FD6D75103C3D49005F5B73 /* Indexer.cpp */,
+ 90FD6D76103C3D49005F5B73 /* IndexProvider.cpp */,
+ 90FD6D77103C3D49005F5B73 /* Program.cpp */,
+ 90FD6D78103C3D49005F5B73 /* ProgramImpl.h */,
+ 90FD6D79103C3D49005F5B73 /* ResolveLocation.cpp */,
+ 90FD6D7A103C3D49005F5B73 /* SelectorMap.cpp */,
+ );
+ name = Index;
+ sourceTree = "<group>";
+ };
+ 90FD6DB4103D9763005F5B73 /* index-test */ = {
+ isa = PBXGroup;
+ children = (
+ 90FD6DB5103D977E005F5B73 /* index-test.cpp */,
+ );
+ name = "index-test";
+ sourceTree = "<group>";
+ };
C6859E8C029090F304C91782 /* Documentation */ = {
isa = PBXGroup;
children = (
@@ -1037,6 +1191,7 @@
isa = PBXGroup;
children = (
35585DBD0EAFBC4500D0A97A /* CXXFieldCollector.h */,
+ 1A6B6CD110693FC900BB4A8F /* CodeCompleteConsumer.cpp */,
3527124F0DAFE54700C76352 /* IdentifierResolver.h */,
352712500DAFE54700C76352 /* IdentifierResolver.cpp */,
DECB6D640F9AE26600F5FBC7 /* JumpDiagnostics.cpp */,
@@ -1052,23 +1207,22 @@
35EF676F0DAD1D2C00B19414 /* SemaDeclCXX.cpp */,
DE704B250D0FBEBE009C7762 /* SemaDeclObjC.cpp */,
DE67E7100C020ED400F66BC5 /* SemaExpr.cpp */,
- DE67E70E0C020ECF00F66BC5 /* SemaExprCXX.cpp */,
DE47999B0D2EBE1A00706D2D /* SemaExprObjC.cpp */,
- 3557D1EF0EB13BB700C59739 /* SemaInherit.cpp */,
- DE3B921C0EB1A81400D01046 /* SemaInherit.h */,
+ DE67E70E0C020ECF00F66BC5 /* SemaExprCXX.cpp */,
3599299A0DE2425300A8A33E /* SemaInit.cpp */,
357EA27C0F2526F300439B60 /* SemaLookup.cpp */,
- 35E194680ECB82FB00F21733 /* SemaNamedCast.cpp */,
+ 1A6B6CD210693FC900BB4A8F /* SemaCodeComplete.cpp */,
+ 35E194680ECB82FB00F21733 /* SemaCXXCast.cpp */,
35585DBE0EAFBC4500D0A97A /* SemaOverload.cpp */,
35585DBF0EAFBC4500D0A97A /* SemaOverload.h */,
DE67E70C0C020ECA00F66BC5 /* SemaStmt.cpp */,
3591853E0EFB1088000039AF /* SemaTemplate.cpp */,
+ 1A6B6CD310693FC900BB4A8F /* SemaTemplate.h */,
BDF87CF60FD746F300BBF872 /* SemaTemplateDeduction.cpp */,
35544B8B0F5C803200D92AA9 /* SemaTemplateInstantiate.cpp */,
1ADF47AE0F782C3200E48A8A /* SemaTemplateInstantiateDecl.cpp */,
- 1A410F840FBCE51100351440 /* SemaTemplateInstantiateExpr.cpp */,
- 1A5119C30FBDF71000A1FF22 /* SemaTemplateInstantiateStmt.cpp */,
DE67E70A0C020EC500F66BC5 /* SemaType.cpp */,
+ 1AE4EE3B103B89CA00888A23 /* TreeTransform.h */,
);
name = Sema;
sourceTree = "<group>";
@@ -1076,6 +1230,7 @@
DE67E7260C02108300F66BC5 /* Sema */ = {
isa = PBXGroup;
children = (
+ 7F270AFE107A90010031B377 /* CodeCompleteConsumer.h */,
9063F2210F9E8BDF002F7251 /* ExternalSemaSource.h */,
9063F2220F9E8BDF002F7251 /* SemaConsumer.h */,
DE67E7270C02109800F66BC5 /* ParseAST.h */,
@@ -1096,6 +1251,8 @@
35475B220E7997680000BFE4 /* CGCall.h */,
1A5D5E570E5E81010023C059 /* CGCXX.cpp */,
1A649E1E0F9599DA005B965E /* CGCXX.h */,
+ 1A4C41BE105B4C0B0047B5E7 /* CGCXXClass.cpp */,
+ 1A6B6E991069833600BB4A8F /* CGCXXExpr.cpp */,
1A6FE7080FD6F85800E00CA9 /* CGCXXTemp.cpp */,
35A3E7000DD3874400757F74 /* CGDebugInfo.cpp */,
35A3E7010DD3874400757F74 /* CGDebugInfo.h */,
@@ -1109,8 +1266,13 @@
DE38CD4E0D794CF900A273B6 /* CGObjCRuntime.h */,
DE38CD4F0D794D0100A273B6 /* CGObjCGNU.cpp */,
3552E7580E520DD7003A8CA5 /* CGObjCMac.cpp */,
+ 1AFF8AE11012BFC900D248DA /* CGRecordLayoutBuilder.cpp */,
+ 1AFF8AE21012BFC900D248DA /* CGRecordLayoutBuilder.h */,
+ 1A6C01F6108128710072DEE4 /* CGRtti.cpp */,
DE4772F90C10EAE5002239E8 /* CGStmt.cpp */,
35475B230E7997680000BFE4 /* CGValue.h */,
+ 1A81AA18108144F40094E50B /* CGVtable.cpp */,
+ 1A81AA5D108278A20094E50B /* CGVtable.h */,
DE928B800C0A615B00231DA4 /* CodeGenFunction.h */,
DE928B820C0A616000231DA4 /* CodeGenFunction.cpp */,
DE928B7C0C0A615100231DA4 /* CodeGenModule.h */,
@@ -1120,6 +1282,7 @@
1A2193CC0F45EEB700C0713D /* Mangle.cpp */,
1A2193CD0F45EEB700C0713D /* Mangle.h */,
DE928B120C05659200231DA4 /* ModuleBuilder.cpp */,
+ 1AE4EE3F103B8A0A00888A23 /* TargetABIInfo.cpp */,
);
name = CodeGen;
sourceTree = "<group>";
@@ -1142,10 +1305,10 @@
DE75ED280B044DC90020CF81 /* ASTContext.h */,
DEA09A6E0F31756F000C2258 /* ASTDiagnostic.h */,
1A72BEAC0D641E9400B085E9 /* Attr.h */,
+ 1A535EDB107BC47B000C3AE7 /* CanonicalType.h */,
90FB99DE0F98FB1D008F9415 /* DeclContextInternals.h */,
90FB99DF0F98FB1D008F9415 /* DeclVisitor.h */,
90FB99E00F98FB1D008F9415 /* ExternalASTSource.h */,
- DEC63B1B0C7B940600DBF169 /* CFG.h */,
DEC8D9900A9433CD00353FCA /* Decl.h */,
3538FDB60ED24A2C005EC283 /* DeclarationName.h */,
035611470DA6A45C00D2EF2A /* DeclBase.h */,
@@ -1182,7 +1345,7 @@
DE8823CA0ED0046600CBC30A /* APValue.cpp */,
35BB2D7E0D19954000944DB5 /* ASTConsumer.cpp */,
DE1732FF0B068B700080B521 /* ASTContext.cpp */,
- DEC63B190C7B940200DBF169 /* CFG.cpp */,
+ 1A535ED8107BC45E000C3AE7 /* CXXInheritance.cpp */,
35FE6BCE0DF6EE1F00739712 /* DeclBase.cpp */,
DED62ABA0AE2EDF1001E80A4 /* Decl.cpp */,
3538FDB70ED24A4E005EC283 /* DeclarationName.cpp */,
@@ -1197,10 +1360,13 @@
3557D1A80EB136B100C59739 /* InheritViz.cpp */,
DEDFE5CE0F7206E40035BD10 /* NestedNameSpecifier.cpp */,
35EE48B00E0C4CCA00715C54 /* ParentMap.cpp */,
+ 1AA1D91610125DE30078DEBC /* RecordLayoutBuilder.cpp */,
+ 1AA1D91710125DE30078DEBC /* RecordLayoutBuilder.h */,
DE3452400AEF1A2D00DBC861 /* Stmt.cpp */,
DEF2EDA60C6A4252000C4259 /* StmtDumper.cpp */,
- DE34621C0AFEB19B00DBC861 /* StmtPrinter.cpp */,
35847BE40CC7DBAF00C40FFF /* StmtIterator.cpp */,
+ DE34621C0AFEB19B00DBC861 /* StmtPrinter.cpp */,
+ 1AE4EE3D103B89ED00888A23 /* StmtProfile.cpp */,
35CFFDFF0CA1CBCB00E6F2BE /* StmtViz.cpp */,
DEDFF8870F848CF80035BD10 /* TemplateName.cpp */,
DE75EDF00B06880E0020CF81 /* Type.cpp */,
@@ -1218,9 +1384,11 @@
DE67E7260C02108300F66BC5 /* Sema */,
DE928B140C05659A00231DA4 /* CodeGen */,
356EF9AF0C8F7DA4006650F5 /* Analysis */,
+ 90FD6D5E103C3D03005F5B73 /* Index */,
DEF7D9F40C9C8B020001F598 /* Rewrite */,
DEF1615D0F65C7FC0098507F /* Frontend */,
DEF165020F8D46810098507F /* Driver */,
+ 9012911210470FAF0083456D /* clang-c */,
);
path = include;
sourceTree = "<group>";
@@ -1250,6 +1418,7 @@
9063F2280F9E911F002F7251 /* OnDiskHashTable.h */,
DE8824560ED1244600CBC30A /* OperatorKinds.def */,
DE8824530ED1243E00CBC30A /* OperatorKinds.h */,
+ 1AB290021045858B00FE33D8 /* PartialDiagnostic.h */,
DEAABDF70F5F477C0098928A /* PrettyStackTrace.h */,
DED7D7350A524295003AD0FB /* SourceLocation.h */,
DED7D7360A524295003AD0FB /* SourceManager.h */,
@@ -1339,6 +1508,9 @@
DEDFE61F0F7B3AE10035BD10 /* Tools */ = {
isa = PBXGroup;
children = (
+ 90F9EFA8104ABDC400D09A15 /* c-index-test */,
+ 9012911E104812DA0083456D /* CIndex */,
+ 90FD6DB4103D9763005F5B73 /* index-test */,
DEDFE6200F7B3AE90035BD10 /* clang-cc */,
DEDFE6210F7B3AF10035BD10 /* clang */,
);
@@ -1389,6 +1561,18 @@
DEF1615D0F65C7FC0098507F /* Frontend */ = {
isa = PBXGroup;
children = (
+ 90FD6D86103C3D80005F5B73 /* Analyses.def */,
+ 90FD6D87103C3D80005F5B73 /* AnalysisConsumer.h */,
+ 90FD6D88103C3D80005F5B73 /* ASTConsumers.h */,
+ 90FD6D89103C3D80005F5B73 /* ASTUnit.h */,
+ 90FD6D8A103C3D80005F5B73 /* CommandLineSourceLoc.h */,
+ 90FD6D8B103C3D80005F5B73 /* DeclContextXML.def */,
+ 90FD6D8C103C3D80005F5B73 /* DeclXML.def */,
+ 90FD6D8D103C3D80005F5B73 /* DocumentXML.def */,
+ 90FD6D8E103C3D80005F5B73 /* DocumentXML.h */,
+ 90FD6D8F103C3D80005F5B73 /* StmtXML.def */,
+ 90FD6D90103C3D80005F5B73 /* TypeXML.def */,
+ 90FD6D91103C3D80005F5B73 /* Utils.h */,
DEF161620F65C81C0098507F /* CompileOptions.h */,
DEF168620F9549250098507F /* FixItRewriter.h */,
DEF169220F9645960098507F /* FrontendDiagnostic.h */,
@@ -1545,7 +1729,6 @@
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 */,
@@ -1617,9 +1800,8 @@
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 */,
+ 35E1946A0ECB82FB00F21733 /* SemaCXXCast.cpp in Sources */,
35E1946D0ECB83C100F21733 /* PTHLexer.cpp in Sources */,
3537AA0E0ECD08A4008F7CDC /* PreprocessorLexer.cpp in Sources */,
DE8823CB0ED0046600CBC30A /* APValue.cpp in Sources */,
@@ -1672,8 +1854,6 @@
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 */,
@@ -1695,6 +1875,32 @@
BDF87CF70FD746F300BBF872 /* SemaTemplateDeduction.cpp in Sources */,
1A14D3A70FD78A3F00DA2835 /* DeclPrinter.cpp in Sources */,
DE37252E0FE481AD00CF2CC2 /* Builtins.cpp in Sources */,
+ 1AA1D91810125DE30078DEBC /* RecordLayoutBuilder.cpp in Sources */,
+ 1AFF8AE31012BFC900D248DA /* CGRecordLayoutBuilder.cpp in Sources */,
+ 1AE4EE3E103B89ED00888A23 /* StmtProfile.cpp in Sources */,
+ 1AE4EE40103B8A0A00888A23 /* TargetABIInfo.cpp in Sources */,
+ 90FD6D7B103C3D49005F5B73 /* Analyzer.cpp in Sources */,
+ 90FD6D7C103C3D49005F5B73 /* ASTLocation.cpp in Sources */,
+ 90FD6D7D103C3D49005F5B73 /* DeclReferenceMap.cpp in Sources */,
+ 90FD6D7E103C3D49005F5B73 /* Entity.cpp in Sources */,
+ 90FD6D7F103C3D49005F5B73 /* GlobalSelector.cpp in Sources */,
+ 90FD6D80103C3D49005F5B73 /* Handlers.cpp in Sources */,
+ 90FD6D81103C3D49005F5B73 /* Indexer.cpp in Sources */,
+ 90FD6D82103C3D49005F5B73 /* IndexProvider.cpp in Sources */,
+ 90FD6D83103C3D49005F5B73 /* Program.cpp in Sources */,
+ 90FD6D84103C3D49005F5B73 /* ResolveLocation.cpp in Sources */,
+ 90FD6D85103C3D49005F5B73 /* SelectorMap.cpp in Sources */,
+ 90FD6DB6103D977E005F5B73 /* index-test.cpp in Sources */,
+ 9012911D1048068D0083456D /* ASTUnit.cpp in Sources */,
+ 90129121104812F90083456D /* CIndex.cpp in Sources */,
+ 90F9EFAA104ABDED00D09A15 /* c-index-test.c in Sources */,
+ 1A4C41BF105B4C0B0047B5E7 /* CGCXXClass.cpp in Sources */,
+ 1A6B6CD410693FC900BB4A8F /* CodeCompleteConsumer.cpp in Sources */,
+ 1A6B6CD510693FC900BB4A8F /* SemaCodeComplete.cpp in Sources */,
+ 1A6B6E9A1069833600BB4A8F /* CGCXXExpr.cpp in Sources */,
+ 1A535ED9107BC45E000C3AE7 /* CXXInheritance.cpp in Sources */,
+ 1A6C01F7108128710072DEE4 /* CGRtti.cpp in Sources */,
+ 1A81AA19108144F40094E50B /* CGVtable.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/docs/DriverInternals.html b/docs/DriverInternals.html
index a99d72c..a7d2da3 100644
--- a/docs/DriverInternals.html
+++ b/docs/DriverInternals.html
@@ -240,7 +240,7 @@
<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
+ constructed. This involves determining the input files and
their types, what work is to be done on them (preprocess,
compile, assemble, link, etc.), and constructing a list of
Action instances for each task. The result is a list of
@@ -312,7 +312,7 @@
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
+ action; once selected the driver interacts with the tool
to see if it can match additional actions (for example, by
having an integrated preprocessor).
@@ -397,7 +397,7 @@
<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
+ invariant during construction of a Compilation; an IDE should be
able to construct a single long lived driver instance to use
for an entire build, for example.</p>
@@ -409,7 +409,7 @@
<h4 id="int_unified_parsing">Unified Parsing &amp; Pipelining</h4>
- <p>Parsing and pipeling both occur without reference to a
+ <p>Parsing and pipelining both occur without reference to a
Compilation instance. This is by design; the driver expects that
both of these phases are platform neutral, with a few very well
defined exceptions such as whether the platform uses a driver
@@ -425,11 +425,11 @@
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
+ <p>For example, on Darwin <tt>-gfull</tt> gets translated into two
+ separate arguments, <tt>-g</tt>
+ and <tt>-fno-eliminate-unused-debug-symbols</tt>. Trying to write Tool
+ logic to do something with <tt>-gfull</tt> will not work, because Tool
+ argument translation is done after the arguments have been
translated.</p>
<p>A long term goal is to remove this tool chain specific
diff --git a/docs/InternalsManual.html b/docs/InternalsManual.html
index a4d5a05..f39224f 100644
--- a/docs/InternalsManual.html
+++ b/docs/InternalsManual.html
@@ -67,6 +67,7 @@ td {
<li><a href="#Constants">Constant Folding in the Clang AST</a></li>
</ul>
</li>
+<li><a href="libIndex.html">The Index Library</a></li>
</ul>
@@ -528,12 +529,6 @@ 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
diff --git a/docs/LanguageExtensions.html b/docs/LanguageExtensions.html
index c855a50..9ac35e1 100644
--- a/docs/LanguageExtensions.html
+++ b/docs/LanguageExtensions.html
@@ -27,6 +27,7 @@ td {
<li><a href="#builtins">Builtin Functions</a>
<ul>
<li><a href="#__builtin_shufflevector">__builtin_shufflevector</a></li>
+ <li><a href="#__builtin_unreachable">__builtin_unreachable</a></li>
</ul>
</li>
<li><a href="#targetspecific">Target-Specific Extensions</a>
@@ -264,7 +265,7 @@ 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
+<p><tt>__builtin_shufflevector</tt> is used to express generic vector
permutation/shuffle/swizzle operations. This builtin is also very important for
the implementation of various target-specific header files like
<tt>&lt;xmmintrin.h&gt;</tt>.
@@ -310,6 +311,47 @@ with the same element type as vec1/vec2 but that has an element count equal to
the number of indices specified.
</p>
+<p>Query for this feature with __has_builtin(__builtin_shufflevector).</p>
+
+<!-- ======================================================================= -->
+<h3 id="__builtin_unreachable">__builtin_unreachable</h3>
+<!-- ======================================================================= -->
+
+<p><tt>__builtin_unreachable</tt> is used to indicate that a specific point in
+the program cannot be reached, even if the compiler might otherwise think it
+can. This is useful to improve optimization and eliminates certain warnings.
+For example, without the <tt>__builtin_unreachable</tt> in the example below,
+the compiler assumes that the inline asm can fall through and prints a "function
+declared 'noreturn' should not return" warning.
+</p>
+
+<p><b>Syntax:</b></p>
+
+<pre>
+__builtin_unreachable()
+</pre>
+
+<p><b>Example of Use:</b></p>
+
+<pre>
+void myabort(void) __attribute__((noreturn));
+void myabort(void) {
+ asm("int3");
+ __builtin_unreachable();
+}
+</pre>
+
+<p><b>Description:</b></p>
+
+<p>The __builtin_unreachable() builtin has completely undefined behavior. Since
+it has undefined behavior, it is a statement that it is never reached and the
+optimizer can take advantage of this to produce better code. This builtin takes
+no arguments and produces a void result.
+</p>
+
+<p>Query for this feature with __has_builtin(__builtin_unreachable).</p>
+
+
<!-- ======================================================================= -->
<h2 id="targetspecific">Target-Specific Extensions</h2>
<!-- ======================================================================= -->
diff --git a/docs/UsersManual.html b/docs/UsersManual.html
index 65415ee..20fdda7 100644
--- a/docs/UsersManual.html
+++ b/docs/UsersManual.html
@@ -33,6 +33,12 @@ td {
<li><a href="#general_features">Language and Target-Independent Features</a>
<ul>
<li><a href="#diagnostics">Controlling Errors and Warnings</a></li>
+ <ul>
+ <li><a href="#diagnostics_display">Controlling How Clang Displays Diagnostics</a></li>
+ <li><a href="#diagnostics_mappings">Diagnostic Mappings</a></li>
+ <li><a href="#diagnostics_commandline">Controlling Diagnostics via Command Line Flags</a></li>
+ <li><a href="#diagnostics_pragmas">Controlling Diagnostics via Pragmas</a></li>
+ </ul>
<li><a href="#precompiledheaders">Precompiled Headers</a></li>
</ul>
</li>
@@ -362,7 +368,7 @@ by commenting them out.</p>
<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>
+<h4 id="diagnostics_display">Controlling How Clang Displays Diagnostics</h4>
<p>When Clang emits a diagnostic, it includes rich information in the output,
and gives you fine-grain control over which information is printed. Clang has
@@ -394,18 +400,64 @@ it:</p>
<p>For more information please see <a href="#cl_diag_formatting">Formatting of
Diagnostics</a>.</p>
-<h4>Controlling Which Diagnostics Clang Generates</h4>
+<h4 id="diagnostics_mappings">Diagnostic Mappings</h4>
-<p>mappings: ignore, note, warning, error, fatal</p>
+<p>All diagnostics are mapped into one of these 5 classes:</p>
<p>
-The two major classes are control from the command line and control via pragmas
-in your code.</p>
+<ul>
+<li>Ignored</li>
+<li>Note</li>
+<li>Warning</li>
+<li>Error</li>
+<li>Fatal</li>
+</ul></p>
+<h4 id="diagnostics_commandline">Controlling Diagnostics via Command Line Flags</h4>
<p>-W flags, -pedantic, etc</p>
-<p>pragma GCC diagnostic</p>
+<h4 id="diagnostics_pragmas">Controlling Diagnostics via Pragmas</h4>
+
+<p>Clang can also control what diagnostics are enabled through the use of
+pragmas in the source code. This is useful for turning off specific warnings
+in a section of source code. Clang supports GCC's pragma for compatibility
+with existing source code, as well as several extensions. </p>
+
+<p>The pragma may control any warning that can be used from the command line.
+Warnings may be set to ignored, warning, error, or fatal. The following
+example code will tell Clang or GCC to ignore the -Wall warnings:</p>
+
+<pre>
+#pragma GCC diagnostic ignored "-Wall"
+</pre>
+
+<p>In addition to all of the functionality of provided by GCC's pragma, Clang
+also allows you to push and pop the current warning state. This is particularly
+useful when writing a header file that will be compiled by other people, because
+you don't know what warning flags they build with.</p>
+
+<p>In the below example
+-Wmultichar is ignored for only a single line of code, after which the
+diagnostics return to whatever state had previously existed.</p>
+
+<pre>
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wmultichar"
+
+char b = 'df'; // no warning.
+
+#pragma clang diagnostic pop
+</pre>
+
+<p>The push and pop pragmas will save and restore the full diagnostic state of
+the compiler, regardless of how it was set. That means that it is possible to
+use push and pop around GCC compatible diagnostics and Clang will push and pop
+them appropriately, while GCC will ignore the pushes and pops as unknown
+pragmas. It should be noted that while Clang supports the GCC pragma, Clang and
+GCC do not support the exact same set of warnings, so even when using GCC
+compatible #pragmas there is no guarantee that they will have identical behaviour
+on both compilers. </p>
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
<h3 id="precompiledheaders">Precompiled Headers</h3>
@@ -465,6 +517,50 @@ for headers that are directly included within a source file. For example:</p>
<tt>test.h</tt> since <tt>test.h</tt> was included directly in the source file
and not specified on the command line using <tt>-include</tt>.</p>
+<h4>Relocatable PCH Files</h4>
+<p>It is sometimes necessary to build a precompiled header from headers that
+are not yet in their final, installed locations. For example, one might build a
+precompiled header within the build tree that is then meant to be installed
+alongside the headers. Clang permits the creation of "relocatable" precompiled
+headers, which are built with a given path (into the build directory) and can
+later be used from an installed location.</p>
+
+<p>To build a relocatable precompiled header, place your headers into a
+subdirectory whose structure mimics the installed location. For example, if you
+want to build a precompiled header for the header <code>mylib.h</code> that
+will be installed into <code>/usr/include</code>, create a subdirectory
+<code>build/usr/include</code> and place the header <code>mylib.h</code> into
+that subdirectory. If <code>mylib.h</code> depends on other headers, then
+they can be stored within <code>build/usr/include</code> in a way that mimics
+the installed location.</p>
+
+<p>Building a relocatable precompiled header requires two additional arguments.
+First, pass the <code>--relocatable-pch</code> flag to indicate that the
+resulting PCH file should be relocatable. Second, pass
+<code>-isysroot /path/to/build</code>, which makes all includes for your
+library relative to the build directory. For example:</p>
+
+<pre>
+ # clang -x c-header --relocatable-pch -isysroot /path/to/build /path/to/build/mylib.h mylib.h.pch
+</pre>
+
+<p>When loading the relocatable PCH file, the various headers used in the PCH
+file are found from the system header root. For example, <code>mylib.h</code>
+can be found in <code>/usr/include/mylib.h</code>. If the headers are installed
+in some other system root, the <code>-isysroot</code> option can be used provide
+a different system root from which the headers will be based. For example,
+<code>-isysroot /Developer/SDKs/MacOSX10.4u.sdk</code> will look for
+<code>mylib.h</code> in
+<code>/Developer/SDKs/MacOSX10.4u.sdk/usr/include/mylib.h</code>.</p>
+
+<p>Relocatable precompiled headers are intended to be used in a limited number
+of cases where the compilation environment is tightly controlled and the
+precompiled header cannot be generated after headers have been installed.
+Relocatable precompiled headers also have some performance impact, because
+the difference in location between the header locations at PCH build time vs.
+at the time of PCH use requires one of the PCH optimizations,
+<code>stat()</code> caching, to be disabled. However, this change is only
+likely to affect PCH files that reference a large number of headers.</p>
<!-- ======================================================================= -->
<h2 id="c">C Language Features</h2>
@@ -500,7 +596,6 @@ 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>
diff --git a/docs/libIndex.html b/docs/libIndex.html
new file mode 100644
index 0000000..5693de8
--- /dev/null
+++ b/docs/libIndex.html
@@ -0,0 +1,267 @@
+<html>
+<head>
+ <title>The Index Library</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>The Index Library</h1>
+
+ <p><b>Table of Contents</b></p>
+ <ul>
+ <li><a href="#philosophy">Design Philosophy</a></li>
+ <li><a href="#classes">Classes</a>
+ <ul>
+ <li><a href="#entity">Entity</a></li>
+ <li><a href="#astlocation">ASTLocation</a></li>
+ <li><a href="#declreferencemap">DeclReferenceMap</a></li>
+ </ul>
+ </li>
+ <li><a href="#functions">Functions</a>
+ <ul>
+ <li><a href="#resolveloc">ResolveLocationInAST</a></li>
+ </ul>
+ </li>
+ <li><a href="#astfiles">AST Files</a></li>
+ <li><a href="#indextest">index-test tool</a>
+ <ul>
+ <li><a href="#indextestusage">Usage</a></li>
+ <li><a href="#indextestexamples">Examples</a></li>
+ </ul>
+ </li>
+</ul>
+
+<h2 id="philosophy">Design Philosophy</h2>
+
+<p> The Index library is meant to provide the basic infrastructure for
+ cross-translation-unit analysis and is primarily focused on indexing
+ related functionality. It provides an API for clients that need to
+ accurately map the AST nodes of the ASTContext to the locations in the source files.
+It also allows them to analyze information across multiple translation units.</p>
+
+<p>As a "general rule", ASTContexts are considered the primary source of
+information that a client wants about a translation unit. There will be no such class as an
+ "indexing database" that stores, for example, source locations of identifiers separately from ASTContext.
+All the information that a client needs from a translation unit will be extracted from the ASTContext.</p>
+
+<h2 id="classes">Classes</h2>
+
+<h3 id="entity">Entity</h3>
+
+<p>To be able to reason about semantically the same Decls that are contained in multiple ASTContexts, the 'Entity' class was introduced.
+An Entity is an ASTContext-independent "token" that can be created from a Decl (and a typename in the future) with
+the purpose to "resolve" it into a Decl belonging to another ASTContext. Some examples to make the concept of Entities more clear:</p>
+
+<p>
+t1.c:
+<pre class="code_example">
+void foo(void);
+void bar(void);
+</pre>
+</p>
+
+<p>
+t2.c:
+<pre class="code_example">
+void foo(void) {
+}
+</pre>
+</p>
+
+<p>
+Translation unit <code>t1.c</code> contains 2 Entities <code>foo</code> and <code>bar</code>, while <code>t2.c</code> contains 1 Entity <code>foo</code>.
+Entities are uniqued in such a way that the Entity* pointer for <code>t1.c/foo</code> is the same as the Entity* pointer for <code>t2.c/foo</code>.
+An Entity doesn't convey any information about the declaration, it is more like an opaque pointer used only to get the
+associated Decl out of an ASTContext so that the actual information for the declaration can be accessed.
+Another important aspect of Entities is that they can only be created/associated for declarations that are visible outside the
+translation unit. This means that for:
+</p>
+<p>
+t3.c:
+<pre class="code_example">
+static void foo(void);
+</pre>
+</p>
+<p>
+there can be no Entity (if you ask for the Entity* of the static function <code>foo</code> you'll get a null pointer).
+This is for 2 reasons:
+<ul>
+<li>To preserve the invariant that the same Entity* pointers refer to the same semantic Decls.
+ In the above example <code>t1.c/foo</code> and <code>t2.c/foo</code> are the same, while <code>t3.c/foo</code> is different.</li>
+<li>The purpose of Entity is to get the same semantic Decl from multiple ASTContexts. For a Decl that is not visible
+ outside of its own translation unit, you don't need an Entity since it won't appear in another ASTContext.</li>
+</ul>
+</p>
+
+<h3 id="astlocation">ASTLocation</h3>
+
+Encapsulates a "point" in the AST tree of the ASTContext.
+It represents either a Decl*, or a Stmt* along with its immediate Decl* parent.
+An example for its usage is that libIndex will provide the references of <code>foo</code> in the form of ASTLocations,
+"pointing" at the expressions that reference <code>foo</code>.
+
+<h3 id="declreferencemap">DeclReferenceMap</h3>
+
+Accepts an ASTContext and creates a mapping from NamedDecls to the ASTLocations that reference them (in the same ASTContext).
+
+<h2 id="functions">Functions</h2>
+
+<h3 id="resolveloc">ResolveLocationInAST</h3>
+
+A function that accepts an ASTContext and a SourceLocation which it resolves into an ASTLocation.
+
+<h2 id="astfiles">AST Files</h2>
+
+The precompiled headers implementation of clang (<a href="http://clang.llvm.org/docs/PCHInternals.html">PCH</a>) is ideal for storing an ASTContext in a compact form that
+will be loaded later for AST analysis. An "AST file" refers to a translation unit that was "compiled" into a precompiled header file.
+
+<h2 id="indextest">index-test tool</h2>
+
+<h3 id="indextestusage">Usage</h3>
+
+A command-line tool that exercises the libIndex API, useful for testing its features.
+As input it accepts multiple AST files (representing multiple translation units) and a few options:
+
+<p>
+<pre class="code_example">
+ -point-at [file:line:column]
+</pre>
+Resolves a [file:line:column] triplet into a ASTLocation from the first AST file. If no other option is specified, it prints the ASTLocation.
+It also prints a declaration's associated doxygen comment, if one is available.
+</p>
+
+<p>
+<pre class="code_example">
+ -print-refs
+</pre>
+Prints the ASTLocations that reference the declaration that was resolved out of the [file:line:column] triplet
+</p>
+
+<p>
+<pre class="code_example">
+ -print-defs
+</pre>
+Prints the ASTLocations that define the resolved declaration
+</p>
+
+<p>
+<pre class="code_example">
+ -print-decls
+</pre>
+Prints the ASTLocations that declare the resolved declaration
+</p>
+
+<h3 id="indextestexamples">Examples</h3>
+
+<p>
+Here's an example of using index-test:
+</p>
+
+<p>
+We have 3 files,
+</p>
+
+<p>
+foo.h:
+<pre class="code_example">
+extern int global_var;
+
+void foo_func(int param1);
+void bar_func(void);
+</pre>
+
+t1.c:
+<pre class="code_example">
+#include "foo.h"
+
+void foo_func(int param1) {
+ int local_var = global_var;
+ for (int for_var = 100; for_var < 500; ++for_var) {
+ local_var = param1 + for_var;
+ }
+ bar_func();
+}
+</pre>
+
+t2.c:
+<pre class="code_example">
+#include "foo.h"
+
+int global_var = 10;
+
+void bar_func(void) {
+ global_var += 100;
+ foo_func(global_var);
+}
+</pre>
+</p>
+
+<p>
+You first get AST files out of <code>t1.c</code> and <code>t2.c</code>:
+
+<pre class="code_example">
+$ clang-cc -emit-pch t1.c -o t1.ast
+$ clang-cc -emit-pch t2.c -o t2.ast
+</pre>
+</p>
+
+<p>
+Find the ASTLocation under this position of <code>t1.c</code>:
+<pre class="code_example">
+[...]
+void foo_func(int param1) {
+ int local_var = global_var;
+ ^
+[...]
+</pre>
+
+<pre class="code_example">
+$ index-test t1.ast -point-at t1.c:4:23
+> [Decl: Var local_var | Stmt: DeclRefExpr global_var] &lt;t1.c:4:19, t1.c:4:19>
+</pre>
+</p>
+
+<p>
+Find the declaration:
+
+<pre class="code_example">
+$ index-test t1.ast -point-at t1.c:4:23 -print-decls
+> [Decl: Var global_var] &lt;foo.h:1:12, foo.h:1:12>
+</pre>
+</p>
+
+<p>
+Find the references:
+
+<pre class="code_example">
+$ index-test t1.ast t2.ast -point-at t1.c:4:23 -print-refs
+> [Decl: Var local_var | Stmt: DeclRefExpr global_var] &lt;t1.c:4:19, t1.c:4:19>
+> [Decl: Function bar_func | Stmt: DeclRefExpr global_var] &lt;t2.c:6:3, t2.c:6:3>
+> [Decl: Function bar_func | Stmt: DeclRefExpr global_var] &lt;t2.c:7:12, t2.c:7:12>
+</pre>
+</p>
+
+<p>
+Find definitions:
+
+<pre class="code_example">
+$ index-test t1.ast t2.ast -point-at t1.c:4:23 -print-defs
+> [Decl: Var global_var] &lt;t2.c:3:5, t2.c:3:18>
+</pre>
+</p>
+
+</div>
+
+</body>
+</html>
diff --git a/docs/tools/Makefile b/docs/tools/Makefile
index 90eb776..12696ef 100644
--- a/docs/tools/Makefile
+++ b/docs/tools/Makefile
@@ -21,6 +21,7 @@ SRC_DOC_DIR=
DST_HTML_DIR=html/
DST_MAN_DIR=man/man1/
DST_PS_DIR=ps/
+CLANG_VERSION := trunk
# If we are in BUILD_FOR_WEBSITE mode, default to the all target.
all:: html man ps
@@ -39,6 +40,8 @@ else
LEVEL := ../../../..
include $(LEVEL)/Makefile.common
+CLANG_VERSION := $(shell cat $(PROJ_SRC_DIR)/../../VER)
+
SRC_DOC_DIR=$(PROJ_SRC_DIR)/
DST_HTML_DIR=$(PROJ_OBJ_DIR)/
DST_MAN_DIR=$(PROJ_OBJ_DIR)/
@@ -66,7 +69,7 @@ $(DST_HTML_DIR)%.html: %.pod $(DST_HTML_DIR)/.dir
--podpath=. --infile=$< --outfile=$@ --title=$*
$(DST_MAN_DIR)%.1: %.pod $(DST_MAN_DIR)/.dir
- pod2man --release "clang 1.0" --center="Clang Tools Documentation" $< $@
+ pod2man --release "clang $(CLANG_VERSION)" --center="Clang Tools Documentation" $< $@
$(DST_PS_DIR)%.ps: $(DST_MAN_DIR)%.1 $(DST_PS_DIR)/.dir
groff -Tps -man $< > $@
diff --git a/docs/tools/clang.pod b/docs/tools/clang.pod
index c520f93..daa7387 100644
--- a/docs/tools/clang.pod
+++ b/docs/tools/clang.pod
@@ -378,8 +378,7 @@ Show commands to run and use verbose output.
=over
-=item
-B<-fshow-column>
+=item B<-fshow-column>
B<-fshow-source-location>
B<-fcaret-diagnostics>
B<-fdiagnostics-fixit-info>
@@ -428,13 +427,14 @@ 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>
+#=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
@@ -445,21 +445,21 @@ Do not search the standard system directories for include files.
=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
+#=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
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
new file mode 100644
index 0000000..3178017
--- /dev/null
+++ b/include/clang-c/Index.h
@@ -0,0 +1,220 @@
+/*===-- clang-c/Index.h - Indexing Public C Interface -------------*- C -*-===*\
+|* *|
+|* The LLVM Compiler Infrastructure *|
+|* *|
+|* This file is distributed under the University of Illinois Open Source *|
+|* License. See LICENSE.TXT for details. *|
+|* *|
+|*===----------------------------------------------------------------------===*|
+|* *|
+|* This header provides a public inferface to a Clang library for extracting *|
+|* high-level symbol information from source files without exposing the full *|
+|* Clang C++ API. *|
+|* *|
+\*===----------------------------------------------------------------------===*/
+
+#ifndef CLANG_C_INDEX_H
+#define CLANG_C_INDEX_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ Clang indeX abstractions. The backing store for the following API's will be
+ clangs AST file (currently based on PCH). AST files are created as follows:
+
+ "clang -emit-ast <sourcefile.langsuffix> -o <sourcefile.ast>".
+
+ Naming Conventions: To avoid namespace pollution, data types are prefixed
+ with "CX" and functions are prefixed with "clang_".
+*/
+typedef void *CXIndex; /* An indexing instance. */
+
+typedef void *CXTranslationUnit; /* A translation unit instance. */
+
+typedef void *CXDecl; /* A specific declaration within a translation unit. */
+typedef void *CXStmt; /* A specific statement within a function/method */
+
+/* Cursors represent declarations, definitions, and references. */
+enum CXCursorKind {
+ /* Declarations */
+ CXCursor_FirstDecl = 1,
+ CXCursor_TypedefDecl = 2,
+ CXCursor_StructDecl = 3,
+ CXCursor_UnionDecl = 4,
+ CXCursor_ClassDecl = 5,
+ CXCursor_EnumDecl = 6,
+ CXCursor_FieldDecl = 7,
+ CXCursor_EnumConstantDecl = 8,
+ CXCursor_FunctionDecl = 9,
+ CXCursor_VarDecl = 10,
+ CXCursor_ParmDecl = 11,
+ CXCursor_ObjCInterfaceDecl = 12,
+ CXCursor_ObjCCategoryDecl = 13,
+ CXCursor_ObjCProtocolDecl = 14,
+ CXCursor_ObjCPropertyDecl = 15,
+ CXCursor_ObjCIvarDecl = 16,
+ CXCursor_ObjCInstanceMethodDecl = 17,
+ CXCursor_ObjCClassMethodDecl = 18,
+ CXCursor_LastDecl = 18,
+
+ /* Definitions */
+ CXCursor_FirstDefn = 32,
+ CXCursor_FunctionDefn = 32,
+ CXCursor_ObjCClassDefn = 33,
+ CXCursor_ObjCCategoryDefn = 34,
+ CXCursor_ObjCInstanceMethodDefn = 35,
+ CXCursor_ObjCClassMethodDefn = 36,
+ CXCursor_LastDefn = 36,
+
+ /* References */
+ CXCursor_FirstRef = 40, /* Decl references */
+ CXCursor_ObjCSuperClassRef = 40,
+ CXCursor_ObjCProtocolRef = 41,
+ CXCursor_ObjCClassRef = 42,
+
+ CXCursor_ObjCSelectorRef = 43, /* Expression references */
+ CXCursor_ObjCIvarRef = 44,
+ CXCursor_VarRef = 45,
+ CXCursor_FunctionRef = 46,
+ CXCursor_EnumConstantRef = 47,
+ CXCursor_MemberRef = 48,
+ CXCursor_LastRef = 48,
+
+ /* Error conditions */
+ CXCursor_FirstInvalid = 70,
+ CXCursor_InvalidFile = 70,
+ CXCursor_NoDeclFound = 71,
+ CXCursor_NotImplemented = 72,
+ CXCursor_LastInvalid = 72
+};
+
+/* A cursor into the CXTranslationUnit. */
+
+typedef struct {
+ enum CXCursorKind kind;
+ CXDecl decl;
+ CXStmt stmt; /* expression reference */
+} CXCursor;
+
+/* A unique token for looking up "visible" CXDecls from a CXTranslationUnit. */
+typedef void *CXEntity;
+
+CXIndex clang_createIndex();
+void clang_disposeIndex(CXIndex);
+
+const char *clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit);
+
+CXTranslationUnit clang_createTranslationUnit(
+ CXIndex, const char *ast_filename
+);
+void clang_disposeTranslationUnit(CXTranslationUnit);
+
+/*
+ Usage: clang_loadTranslationUnit(). Will load the toplevel declarations
+ within a translation unit, issuing a 'callback' for each one.
+
+ void printObjCInterfaceNames(CXTranslationUnit X, CXCursor C) {
+ if (clang_getCursorKind(C) == Cursor_Declaration) {
+ CXDecl D = clang_getCursorDecl(C);
+ if (clang_getDeclKind(D) == CXDecl_ObjC_interface)
+ printf("@interface %s in file %s on line %d column %d\n",
+ clang_getDeclSpelling(D), clang_getCursorSource(C),
+ clang_getCursorLine(C), clang_getCursorColumn(C));
+ }
+ }
+ static void usage {
+ clang_loadTranslationUnit(CXTranslationUnit, printObjCInterfaceNames);
+ }
+*/
+typedef void *CXClientData;
+typedef void (*CXTranslationUnitIterator)(CXTranslationUnit, CXCursor,
+ CXClientData);
+void clang_loadTranslationUnit(CXTranslationUnit, CXTranslationUnitIterator,
+ CXClientData);
+
+/*
+ Usage: clang_loadDeclaration(). Will load the declaration, issuing a
+ 'callback' for each declaration/reference within the respective declaration.
+
+ For interface declarations, this will index the super class, protocols,
+ ivars, methods, etc. For structure declarations, this will index the fields.
+ For functions, this will index the parameters (and body, for function
+ definitions), local declarations/references.
+
+ void getInterfaceDetails(CXDecl X, CXCursor C) {
+ switch (clang_getCursorKind(C)) {
+ case Cursor_ObjC_ClassRef:
+ CXDecl SuperClass = clang_getCursorDecl(C);
+ case Cursor_ObjC_ProtocolRef:
+ CXDecl AdoptsProtocol = clang_getCursorDecl(C);
+ case Cursor_Declaration:
+ CXDecl AnIvarOrMethod = clang_getCursorDecl(C);
+ }
+ }
+ static void usage() {
+ if (clang_getDeclKind(D) == CXDecl_ObjC_interface) {
+ clang_loadDeclaration(D, getInterfaceDetails);
+ }
+ }
+*/
+typedef void (*CXDeclIterator)(CXDecl, CXCursor, CXClientData);
+
+void clang_loadDeclaration(CXDecl, CXDeclIterator, CXClientData);
+
+/*
+ * CXEntity Operations.
+ */
+const char *clang_getDeclarationName(CXEntity);
+const char *clang_getURI(CXEntity);
+CXEntity clang_getEntity(const char *URI);
+/*
+ * CXDecl Operations.
+ */
+CXCursor clang_getCursorFromDecl(CXDecl);
+CXEntity clang_getEntityFromDecl(CXDecl);
+const char *clang_getDeclSpelling(CXDecl);
+unsigned clang_getDeclLine(CXDecl);
+unsigned clang_getDeclColumn(CXDecl);
+const char *clang_getDeclSource(CXDecl);
+
+/*
+ * CXCursor Operations.
+ */
+CXCursor clang_getCursor(CXTranslationUnit, const char *source_name,
+ unsigned line, unsigned column);
+
+enum CXCursorKind clang_getCursorKind(CXCursor);
+unsigned clang_isDeclaration(enum CXCursorKind);
+unsigned clang_isReference(enum CXCursorKind);
+unsigned clang_isDefinition(enum CXCursorKind);
+unsigned clang_isInvalid(enum CXCursorKind);
+
+unsigned clang_getCursorLine(CXCursor);
+unsigned clang_getCursorColumn(CXCursor);
+const char *clang_getCursorSource(CXCursor);
+const char *clang_getCursorSpelling(CXCursor);
+
+/* for debug/testing */
+const char *clang_getCursorKindSpelling(enum CXCursorKind Kind);
+void clang_getDefinitionSpellingAndExtent(CXCursor,
+ const char **startBuf,
+ const char **endBuf,
+ unsigned *startLine,
+ unsigned *startColumn,
+ unsigned *endLine,
+ unsigned *endColumn);
+
+/*
+ * If CXCursorKind == Cursor_Reference, then this will return the referenced
+ * declaration.
+ * If CXCursorKind == Cursor_Declaration, then this will return the declaration.
+ */
+CXDecl clang_getCursorDecl(CXCursor);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/include/clang/AST/APValue.h b/include/clang/AST/APValue.h
index 5d5abfe..94d258d 100644
--- a/include/clang/AST/APValue.h
+++ b/include/clang/AST/APValue.h
@@ -37,16 +37,16 @@ public:
};
private:
ValueKind Kind;
-
- struct ComplexAPSInt {
- APSInt Real, Imag;
+
+ 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;
@@ -57,16 +57,17 @@ private:
Vec() : Elts(0), NumElts(0) {}
~Vec() { delete[] Elts; }
};
-
+
enum {
- MaxSize = (sizeof(ComplexAPSInt) > sizeof(ComplexAPFloat) ?
+ 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*)];
-
+
+ union {
+ void *Aligner;
+ char Data[MaxSize];
+ };
+
public:
APValue() : Kind(Uninitialized) {}
explicit APValue(const APSInt &I) : Kind(Uninitialized) {
@@ -93,7 +94,7 @@ public:
~APValue() {
MakeUninit();
}
-
+
ValueKind getKind() const { return Kind; }
bool isUninit() const { return Kind == Uninitialized; }
bool isInt() const { return Kind == Int; }
@@ -102,54 +103,54 @@ public:
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;
+ return *(APSInt*)(char*)Data;
}
const APSInt &getInt() const {
return const_cast<APValue*>(this)->getInt();
}
-
+
APFloat &getFloat() {
assert(isFloat() && "Invalid accessor");
- return *(APFloat*)(void*)Data;
+ return *(APFloat*)(char*)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];
+ return ((Vec*)(char*)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;
+ return ((ComplexAPSInt*)(char*)Data)->Real;
}
const APSInt &getComplexIntReal() const {
return const_cast<APValue*>(this)->getComplexIntReal();
}
-
+
APSInt &getComplexIntImag() {
assert(isComplexInt() && "Invalid accessor");
- return ((ComplexAPSInt*)(void*)Data)->Imag;
+ return ((ComplexAPSInt*)(char*)Data)->Imag;
}
const APSInt &getComplexIntImag() const {
return const_cast<APValue*>(this)->getComplexIntImag();
}
-
+
APFloat &getComplexFloatReal() {
assert(isComplexFloat() && "Invalid accessor");
- return ((ComplexAPFloat*)(void*)Data)->Real;
+ return ((ComplexAPFloat*)(char*)Data)->Real;
}
const APFloat &getComplexFloatReal() const {
return const_cast<APValue*>(this)->getComplexFloatReal();
@@ -157,7 +158,7 @@ public:
APFloat &getComplexFloatImag() {
assert(isComplexFloat() && "Invalid accessor");
- return ((ComplexAPFloat*)(void*)Data)->Imag;
+ return ((ComplexAPFloat*)(char*)Data)->Imag;
}
const APFloat &getComplexFloatImag() const {
return const_cast<APValue*>(this)->getComplexFloatImag();
@@ -171,44 +172,44 @@ public:
assert(isLValue() && "Invalid accessor");
return ((const LV*)(const void*)Data)->Offset;
}
-
+
void setInt(const APSInt &I) {
assert(isInt() && "Invalid accessor");
- *(APSInt*)(void*)Data = I;
+ *(APSInt*)(char*)Data = I;
}
void setFloat(const APFloat &F) {
assert(isFloat() && "Invalid accessor");
- *(APFloat*)(void*)Data = F;
+ *(APFloat*)(char*)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;
+ ((Vec*)(char*)Data)->Elts = new APValue[N];
+ ((Vec*)(char*)Data)->NumElts = N;
for (unsigned i = 0; i != N; ++i)
- ((Vec*)(void*)Data)->Elts[i] = E[i];
+ ((Vec*)(char*)Data)->Elts[i] = E[i];
}
void setComplexInt(const APSInt &R, const APSInt &I) {
- assert(R.getBitWidth() == I.getBitWidth() &&
+ assert(R.getBitWidth() == I.getBitWidth() &&
"Invalid complex int (type mismatch).");
assert(isComplexInt() && "Invalid accessor");
- ((ComplexAPSInt*)(void*)Data)->Real = R;
- ((ComplexAPSInt*)(void*)Data)->Imag = I;
+ ((ComplexAPSInt*)(char*)Data)->Real = R;
+ ((ComplexAPSInt*)(char*)Data)->Imag = I;
}
void setComplexFloat(const APFloat &R, const APFloat &I) {
- assert(&R.getSemantics() == &I.getSemantics() &&
+ assert(&R.getSemantics() == &I.getSemantics() &&
"Invalid complex float (type mismatch).");
assert(isComplexFloat() && "Invalid accessor");
- ((ComplexAPFloat*)(void*)Data)->Real = R;
- ((ComplexAPFloat*)(void*)Data)->Imag = I;
+ ((ComplexAPFloat*)(char*)Data)->Real = R;
+ ((ComplexAPFloat*)(char*)Data)->Imag = I;
}
void setLValue(Expr *B, uint64_t O) {
assert(isLValue() && "Invalid accessor");
- ((LV*)(void*)Data)->Base = B;
- ((LV*)(void*)Data)->Offset = O;
+ ((LV*)(char*)Data)->Base = B;
+ ((LV*)(char*)Data)->Offset = O;
}
-
+
const APValue &operator=(const APValue &RHS);
-
+
private:
void MakeUninit();
void MakeInt() {
@@ -218,27 +219,27 @@ private:
}
void MakeFloat() {
assert(isUninit() && "Bad state change");
- new ((APFloat*)(void*)Data) APFloat(0.0);
+ new ((void*)(char*)Data) APFloat(0.0);
Kind = Float;
}
void MakeVector() {
assert(isUninit() && "Bad state change");
- new ((Vec*)(void*)Data) Vec();
+ new ((void*)(char*)Data) Vec();
Kind = Vector;
}
void MakeComplexInt() {
assert(isUninit() && "Bad state change");
- new ((ComplexAPSInt*)(void*)Data) ComplexAPSInt();
+ new ((void*)(char*)Data) ComplexAPSInt();
Kind = ComplexInt;
}
void MakeComplexFloat() {
assert(isUninit() && "Bad state change");
- new ((ComplexAPFloat*)(void*)Data) ComplexAPFloat();
+ new ((void*)(char*)Data) ComplexAPFloat();
Kind = ComplexFloat;
}
void MakeLValue() {
assert(isUninit() && "Bad state change");
- new ((LV*)(void*)Data) LV();
+ new ((void*)(char*)Data) LV();
Kind = LValue;
}
};
@@ -247,7 +248,7 @@ 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/ASTConsumer.h b/include/clang/AST/ASTConsumer.h
index 6dc7e13..af6bf30 100644
--- a/include/clang/AST/ASTConsumer.h
+++ b/include/clang/AST/ASTConsumer.h
@@ -36,27 +36,27 @@ 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) {}
-
+ 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.
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 041a0f3..63f9091 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -22,6 +22,7 @@
#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/TemplateName.h"
#include "clang/AST/Type.h"
+#include "clang/AST/CanonicalType.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/OwningPtr.h"
@@ -43,24 +44,26 @@ namespace clang {
class TargetInfo;
// Decls
class Decl;
+ class FieldDecl;
+ class ObjCIvarDecl;
+ class ObjCIvarRefExpr;
class ObjCPropertyDecl;
class RecordDecl;
class TagDecl;
+ class TemplateTypeParmDecl;
class TranslationUnitDecl;
class TypeDecl;
class TypedefDecl;
- class TemplateTypeParmDecl;
- class FieldDecl;
- class ObjCIvarRefExpr;
- class ObjCIvarDecl;
-
+ class UnresolvedUsingDecl;
+ class UsingDecl;
+
namespace Builtin { class Context; }
-
+
/// 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 {
+class ASTContext {
std::vector<Type*> Types;
- llvm::FoldingSet<ExtQualType> ExtQualTypes;
+ llvm::FoldingSet<ExtQuals> ExtQualNodes;
llvm::FoldingSet<ComplexType> ComplexTypes;
llvm::FoldingSet<PointerType> PointerTypes;
llvm::FoldingSet<BlockPointerType> BlockPointerTypes;
@@ -70,17 +73,21 @@ class ASTContext {
llvm::FoldingSet<ConstantArrayType> ConstantArrayTypes;
llvm::FoldingSet<IncompleteArrayType> IncompleteArrayTypes;
std::vector<VariableArrayType*> VariableArrayTypes;
- std::vector<DependentSizedArrayType*> DependentSizedArrayTypes;
- std::vector<DependentSizedExtVectorType*> DependentSizedExtVectorTypes;
+ llvm::FoldingSet<DependentSizedArrayType> DependentSizedArrayTypes;
+ llvm::FoldingSet<DependentSizedExtVectorType> DependentSizedExtVectorTypes;
llvm::FoldingSet<VectorType> VectorTypes;
llvm::FoldingSet<FunctionNoProtoType> FunctionNoProtoTypes;
llvm::FoldingSet<FunctionProtoType> FunctionProtoTypes;
+ llvm::FoldingSet<DependentTypeOfExprType> DependentTypeOfExprTypes;
+ llvm::FoldingSet<DependentDecltypeType> DependentDecltypeTypes;
llvm::FoldingSet<TemplateTypeParmType> TemplateTypeParmTypes;
llvm::FoldingSet<TemplateSpecializationType> TemplateSpecializationTypes;
llvm::FoldingSet<QualifiedNameType> QualifiedNameTypes;
llvm::FoldingSet<TypenameType> TypenameTypes;
- llvm::FoldingSet<ObjCQualifiedInterfaceType> ObjCQualifiedInterfaceTypes;
+ llvm::FoldingSet<ObjCInterfaceType> ObjCInterfaceTypes;
llvm::FoldingSet<ObjCObjectPointerType> ObjCObjectPointerTypes;
+ llvm::FoldingSet<ObjCProtocolListType> ObjCProtocolListTypes;
+ llvm::FoldingSet<ElaboratedType> ElaboratedTypes;
llvm::FoldingSet<QualifiedTemplateName> QualifiedTemplateNames;
llvm::FoldingSet<DependentTemplateName> DependentTemplateNames;
@@ -97,46 +104,109 @@ class ASTContext {
llvm::DenseMap<const RecordDecl*, const ASTRecordLayout*> ASTRecordLayouts;
llvm::DenseMap<const ObjCContainerDecl*, const ASTRecordLayout*> ObjCLayouts;
+ /// \brief Mapping from ObjCContainers to their ObjCImplementations.
+ llvm::DenseMap<ObjCContainerDecl*, ObjCImplDecl*> ObjCImpls;
+
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;
-
+ QualType ObjCIdTypedefType;
+
/// 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 ObjCClassTypedefType;
+
QualType ObjCConstantStringType;
RecordDecl *CFConstantStringTypeDecl;
RecordDecl *ObjCFastEnumerationStateTypeDecl;
-
- /// \brief Keeps track of all declaration attributes.
+
+ /// \brief The type for the C FILE type.
+ TypeDecl *FILEDecl;
+
+ /// \brief The type for the C jmp_buf type.
+ TypeDecl *jmp_bufDecl;
+
+ /// \brief The type for the C sigjmp_buf type.
+ TypeDecl *sigjmp_bufDecl;
+
+ /// \brief Keeps track of all declaration attributes.
///
/// Since so few decls have attrs, we keep them in a hash map instead of
/// wasting space in the Decl class.
llvm::DenseMap<const Decl*, Attr*> DeclAttrs;
-
+
+ /// \brief Keeps track of the static data member templates from which
+ /// static data members of class template specializations were instantiated.
+ ///
+ /// This data structure stores the mapping from instantiations of static
+ /// data members to the static data member representations within the
+ /// class template from which they were instantiated along with the kind
+ /// of instantiation or specialization (a TemplateSpecializationKind - 1).
+ ///
+ /// Given the following example:
+ ///
+ /// \code
+ /// template<typename T>
+ /// struct X {
+ /// static T value;
+ /// };
+ ///
+ /// template<typename T>
+ /// T X<T>::value = T(17);
+ ///
+ /// int *x = &X<int>::value;
+ /// \endcode
+ ///
+ /// This mapping will contain an entry that maps from the VarDecl for
+ /// X<int>::value to the corresponding VarDecl for X<T>::value (within the
+ /// class template X) and will be marked TSK_ImplicitInstantiation.
+ llvm::DenseMap<VarDecl *, MemberSpecializationInfo *>
+ InstantiatedFromStaticDataMember;
+
+ /// \brief Keeps track of the UnresolvedUsingDecls from which UsingDecls
+ /// where created during instantiation.
+ ///
+ /// For example:
+ /// \code
+ /// template<typename T>
+ /// struct A {
+ /// void f();
+ /// };
+ ///
+ /// template<typename T>
+ /// struct B : A<T> {
+ /// using A<T>::f;
+ /// };
+ ///
+ /// template struct B<int>;
+ /// \endcode
+ ///
+ /// This mapping will contain an entry that maps from the UsingDecl in
+ /// B<int> to the UnresolvedUsingDecl in B<T>.
+ llvm::DenseMap<UsingDecl *, UnresolvedUsingDecl *>
+ InstantiatedFromUnresolvedUsingDecl;
+
+ llvm::DenseMap<FieldDecl *, FieldDecl *> InstantiatedFromUnnamedFieldDecl;
+
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;
@@ -144,17 +214,17 @@ class ASTContext {
/// \brief Whether we have already loaded comment source ranges from an
/// external source.
bool LoadedExternalComments;
-
+
/// MallocAlloc/BumpAlloc - The allocator objects used to create AST objects.
bool FreeMemory;
llvm::MallocAllocator MallocAlloc;
llvm::BumpPtrAllocator BumpAlloc;
-
+
/// \brief Mapping from declarations to their comments, once we have
/// already looked up the comment associated with a given declaration.
llvm::DenseMap<const Decl *, std::string> DeclComments;
-
-public:
+
+public:
TargetInfo &Target;
IdentifierTable &Idents;
SelectorTable &Selectors;
@@ -163,41 +233,73 @@ public:
llvm::OwningPtr<ExternalASTSource> ExternalSource;
clang::PrintingPolicy PrintingPolicy;
+ // Typedefs which may be provided defining the structure of Objective-C
+ // pseudo-builtins
+ QualType ObjCIdRedefinitionType;
+ QualType ObjCClassRedefinitionType;
+
/// \brief Source ranges for all of the comments in the source file,
/// sorted in order of appearance in the translation unit.
std::vector<SourceRange> Comments;
-
+
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) {
+ void Deallocate(void *Ptr) {
if (FreeMemory)
- MallocAlloc.Deallocate(Ptr);
+ MallocAlloc.Deallocate(Ptr);
}
const LangOptions& getLangOptions() const { return LangOpts; }
-
- FullSourceLoc getFullLoc(SourceLocation Loc) const {
+
+ FullSourceLoc getFullLoc(SourceLocation Loc) const {
return FullSourceLoc(Loc,SourceMgr);
}
/// \brief Retrieve the attributes for the given declaration.
Attr*& getDeclAttrs(const Decl *D) { return DeclAttrs[D]; }
-
+
/// \brief Erase the attributes corresponding to the given declaration.
void eraseDeclAttrs(const Decl *D) { DeclAttrs.erase(D); }
-
+
+ /// \brief If this variable is an instantiated static data member of a
+ /// class template specialization, returns the templated static data member
+ /// from which it was instantiated.
+ MemberSpecializationInfo *getInstantiatedFromStaticDataMember(VarDecl *Var);
+
+ /// \brief Note that the static data member \p Inst is an instantiation of
+ /// the static data member template \p Tmpl of a class template.
+ void setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl,
+ TemplateSpecializationKind TSK);
+
+ /// \brief If this using decl is instantiated from an unresolved using decl,
+ /// return it.
+ UnresolvedUsingDecl *getInstantiatedFromUnresolvedUsingDecl(UsingDecl *UUD);
+
+ /// \brief Note that the using decl \p Inst is an instantiation of
+ /// the unresolved using decl \p Tmpl of a class template.
+ void setInstantiatedFromUnresolvedUsingDecl(UsingDecl *Inst,
+ UnresolvedUsingDecl *Tmpl);
+
+
+ FieldDecl *getInstantiatedFromUnnamedFieldDecl(FieldDecl *Field);
+
+ void setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst, FieldDecl *Tmpl);
+
TranslationUnitDecl *getTranslationUnitDecl() const { return TUDecl; }
+
const char *getCommentForDecl(const Decl *D);
-
+
// Builtin Types.
QualType VoidTy;
QualType BoolTy;
QualType CharTy;
- QualType WCharTy; // [C++ 3.9.1p5], integer type in C99.
+ QualType WCharTy; // [C++ 3.9.1p5], integer type in C99.
+ QualType Char16Ty; // [C++0x 3.9.1p5], integer type in C99.
+ QualType Char32Ty; // [C++0x 3.9.1p5], integer type in C99.
QualType SignedCharTy, ShortTy, IntTy, LongTy, LongLongTy, Int128Ty;
QualType UnsignedCharTy, UnsignedShortTy, UnsignedIntTy, UnsignedLongTy;
QualType UnsignedLongLongTy, UnsignedInt128Ty;
@@ -207,6 +309,7 @@ public:
QualType OverloadTy;
QualType DependentTy;
QualType UndeducedAutoTy;
+ QualType ObjCBuiltinIdTy, ObjCBuiltinClassTy;
ASTContext(const LangOptions& LOpts, SourceManager &SM, TargetInfo &t,
IdentifierTable &idents, SelectorTable &sels,
@@ -232,23 +335,52 @@ public:
//===--------------------------------------------------------------------===//
// 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
+
+private:
+ /// getExtQualType - Return a type with extended qualifiers.
+ QualType getExtQualType(const Type *Base, Qualifiers Quals);
+
+public:
+ /// 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);
-
+ QualType getObjCGCQualType(QualType T, Qualifiers::GC gcAttr);
+
+ /// getRestrictType - Returns the uniqued reference to the type for a
+ /// 'restrict' qualified type. The resulting type has a union of the
+ /// qualifiers from T and 'restrict'.
+ QualType getRestrictType(QualType T) {
+ return T.withFastQualifiers(Qualifiers::Restrict);
+ }
+
+ /// getVolatileType - Returns the uniqued reference to the type for a
+ /// 'volatile' qualified type. The resulting type has a union of the
+ /// qualifiers from T and 'volatile'.
+ QualType getVolatileType(QualType T);
+
+ /// getConstType - Returns the uniqued reference to the type for a
+ /// 'const' qualified type. The resulting type has a union of the
+ /// qualifiers from T and 'const'.
+ ///
+ /// It can be reasonably expected that this will always be
+ /// equivalent to calling T.withConst().
+ QualType getConstType(QualType T) { return T.withConst(); }
+
+ /// getNoReturnType - Add the noreturn attribute to the given type which must
+ /// be a FunctionType or a pointer to an allowable type or a BlockPointer.
+ QualType getNoReturnType(QualType T);
+
/// 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);
@@ -274,15 +406,17 @@ public:
/// variable array of the specified element type.
QualType getVariableArrayType(QualType EltTy, Expr *NumElts,
ArrayType::ArraySizeModifier ASM,
- unsigned EltTypeQuals);
-
+ unsigned EltTypeQuals,
+ SourceRange Brackets);
+
/// 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);
+ unsigned EltTypeQuals,
+ SourceRange Brackets);
/// getIncompleteArrayType - Returns a unique reference to the type for a
/// incomplete array of the specified element type.
@@ -295,7 +429,23 @@ public:
QualType getConstantArrayType(QualType EltTy, const llvm::APInt &ArySize,
ArrayType::ArraySizeModifier ASM,
unsigned EltTypeQuals);
-
+
+ /// getConstantArrayWithExprType - Return a reference to the type for a
+ /// constant array of the specified element type.
+ QualType getConstantArrayWithExprType(QualType EltTy,
+ const llvm::APInt &ArySize,
+ Expr *ArySizeExpr,
+ ArrayType::ArraySizeModifier ASM,
+ unsigned EltTypeQuals,
+ SourceRange Brackets);
+
+ /// getConstantArrayWithoutExprType - Return a reference to the type
+ /// for a constant array of the specified element type.
+ QualType getConstantArrayWithoutExprType(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);
@@ -309,13 +459,13 @@ public:
/// the type for a dependently-sized vector of the specified element
/// type. FIXME: We will need these to be uniqued, or at least
/// comparable, at some point.
- QualType getDependentSizedExtVectorType(QualType VectorType,
+ QualType getDependentSizedExtVectorType(QualType VectorType,
Expr *SizeExpr,
SourceLocation AttrLoc);
/// getFunctionNoProtoType - Return a K&R style C function type like 'int()'.
///
- QualType getFunctionNoProtoType(QualType ResultTy);
+ QualType getFunctionNoProtoType(QualType ResultTy, bool NoReturn = false);
/// getFunctionType - Return a normal function type with a typed argument
/// list. isVariadic indicates whether the argument list includes '...'.
@@ -323,7 +473,8 @@ public:
unsigned NumArgs, bool isVariadic,
unsigned TypeQuals, bool hasExceptionSpec = false,
bool hasAnyExceptionSpec = false,
- unsigned NumExs = 0, const QualType *ExArray = 0);
+ unsigned NumExs = 0, const QualType *ExArray = 0,
+ bool NoReturn = false);
/// getTypeDeclType - Return the unique reference to the type for
/// the specified type declaration.
@@ -332,9 +483,8 @@ public:
/// 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,
+ QualType getTemplateTypeParmType(unsigned Depth, unsigned Index,
bool ParameterPack,
IdentifierInfo *Name = 0);
@@ -345,37 +495,40 @@ public:
QualType getQualifiedNameType(NestedNameSpecifier *NNS,
QualType NamedType);
- QualType getTypenameType(NestedNameSpecifier *NNS,
+ QualType getTypenameType(NestedNameSpecifier *NNS,
const IdentifierInfo *Name,
QualType Canon = QualType());
- QualType getTypenameType(NestedNameSpecifier *NNS,
+ QualType getTypenameType(NestedNameSpecifier *NNS,
const TemplateSpecializationType *TemplateId,
QualType Canon = QualType());
+ QualType getElaboratedType(QualType UnderlyingType,
+ ElaboratedType::TagKind Tag);
+
+ QualType getObjCInterfaceType(const ObjCInterfaceDecl *Decl,
+ ObjCProtocolDecl **Protocols = 0,
+ unsigned NumProtocols = 0);
/// getObjCObjectPointerType - Return a ObjCObjectPointerType type for the
/// given interface decl and the conforming protocol list.
- QualType getObjCObjectPointerType(ObjCInterfaceDecl *Decl,
+ QualType getObjCObjectPointerType(QualType OIT,
ObjCProtocolDecl **ProtocolList = 0,
unsigned NumProtocols = 0);
-
- /// getObjCQualifiedInterfaceType - Return a
- /// ObjCQualifiedInterfaceType type for the given interface decl and
- /// the conforming protocol list.
- QualType getObjCQualifiedInterfaceType(ObjCInterfaceDecl *Decl,
- ObjCProtocolDecl **ProtocolList,
- unsigned NumProtocols);
-
+
+ QualType getObjCProtocolListType(QualType T,
+ ObjCProtocolDecl **Protocols,
+ unsigned NumProtocols);
+
/// getTypeOfType - GCC extension.
QualType getTypeOfExprType(Expr *e);
QualType getTypeOfType(QualType t);
-
+
/// getDecltypeType - C++0x decltype.
QualType getDecltypeType(Expr *e);
-
+
/// getTagDeclType - Return the unique reference to the type for the
/// specified TagDecl (struct/union/class/enum) decl.
- QualType getTagDeclType(TagDecl *Decl);
-
+ QualType getTagDeclType(const 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;
@@ -392,15 +545,15 @@ public:
/// 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();
-
+ QualType getCFConstantStringType();
+
/// Get the structure type used to representation CFStrings, or NULL
/// if it hasn't yet been built.
QualType getRawCFConstantStringType() {
@@ -412,13 +565,13 @@ public:
// This setter/getter represents the ObjC type for an NSConstantString.
void setObjCConstantStringInterface(ObjCInterfaceDecl *Decl);
- QualType getObjCConstantStringInterface() const {
- return ObjCConstantStringType;
+ 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() {
@@ -429,109 +582,166 @@ public:
void setObjCFastEnumerationStateType(QualType T);
+ /// \brief Set the type for the C FILE type.
+ void setFILEDecl(TypeDecl *FILEDecl) { this->FILEDecl = FILEDecl; }
+
+ /// \brief Retrieve the C FILE type.
+ QualType getFILEType() {
+ if (FILEDecl)
+ return getTypeDeclType(FILEDecl);
+ return QualType();
+ }
+
+ /// \brief Set the type for the C jmp_buf type.
+ void setjmp_bufDecl(TypeDecl *jmp_bufDecl) {
+ this->jmp_bufDecl = jmp_bufDecl;
+ }
+
+ /// \brief Retrieve the C jmp_buf type.
+ QualType getjmp_bufType() {
+ if (jmp_bufDecl)
+ return getTypeDeclType(jmp_bufDecl);
+ return QualType();
+ }
+
+ /// \brief Set the type for the C sigjmp_buf type.
+ void setsigjmp_bufDecl(TypeDecl *sigjmp_bufDecl) {
+ this->sigjmp_bufDecl = sigjmp_bufDecl;
+ }
+
+ /// \brief Retrieve the C sigjmp_buf type.
+ QualType getsigjmp_bufType() {
+ if (sigjmp_bufDecl)
+ return getTypeDeclType(sigjmp_bufDecl);
+ return QualType();
+ }
+
/// 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,
+ 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,
+ 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,
+ void getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD,
const Decl *Container,
std::string &S);
-
+
+ bool ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto,
+ ObjCProtocolDecl *rProto);
+
/// 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; }
+ QualType getObjCIdType() const { return ObjCIdTypedefType; }
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; }
+ QualType getObjCClassType() const { return ObjCClassTypedefType; }
void setObjCClassType(QualType T);
-
+
void setBuiltinVaListType(QualType T);
QualType getBuiltinVaListType() const { return BuiltinVaListType; }
QualType getFixedWidthIntType(unsigned Width, bool Signed);
- TemplateName getQualifiedTemplateName(NestedNameSpecifier *NNS,
+ /// getCVRQualifiedType - Returns a type with additional const,
+ /// volatile, or restrict qualifiers.
+ QualType getCVRQualifiedType(QualType T, unsigned CVR) {
+ return getQualifiedType(T, Qualifiers::fromCVRMask(CVR));
+ }
+
+ /// getQualifiedType - Returns a type with additional qualifiers.
+ QualType getQualifiedType(QualType T, Qualifiers Qs) {
+ if (!Qs.hasNonFastQualifiers())
+ return T.withFastQualifiers(Qs.getFastQualifiers());
+ QualifierCollector Qc(Qs);
+ const Type *Ptr = Qc.strip(T);
+ return getExtQualType(Ptr, Qc);
+ }
+
+ /// getQualifiedType - Returns a type with additional qualifiers.
+ QualType getQualifiedType(const Type *T, Qualifiers Qs) {
+ if (!Qs.hasNonFastQualifiers())
+ return QualType(T, Qs.getFastQualifiers());
+ return getExtQualType(T, Qs);
+ }
+
+ TemplateName getQualifiedTemplateName(NestedNameSpecifier *NNS,
bool TemplateKeyword,
TemplateDecl *Template);
+ TemplateName getQualifiedTemplateName(NestedNameSpecifier *NNS,
+ bool TemplateKeyword,
+ OverloadedFunctionDecl *Template);
- TemplateName getDependentTemplateName(NestedNameSpecifier *NNS,
+ TemplateName getDependentTemplateName(NestedNameSpecifier *NNS,
const IdentifierInfo *Name);
enum GetBuiltinTypeError {
- GE_None, //< No error
- GE_Missing_FILE //< Missing the FILE type from <stdio.h>
+ GE_None, //< No error
+ GE_Missing_stdio, //< Missing a type from <stdio.h>
+ GE_Missing_setjmp //< Missing a type from <setjmp.h>
};
-
+
/// GetBuiltinType - Return the type for the specified builtin.
QualType GetBuiltinType(unsigned ID, GetBuiltinTypeError &Error);
-
+
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;
+public:
/// getObjCGCAttr - Returns one of GCNone, Weak or Strong objc's
/// garbage collection attribute.
///
- QualType::GCAttrTypes getObjCGCAttrKind(const QualType &Ty) const;
-
+ Qualifiers::GC 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) {
@@ -540,7 +750,7 @@ public:
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) {
@@ -549,23 +759,23 @@ public:
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);
@@ -592,14 +802,14 @@ public:
//===--------------------------------------------------------------------===//
// Type Operators
//===--------------------------------------------------------------------===//
-
+
/// getCanonicalType - Return the canonical (structural) type corresponding to
/// the specified potentially non-canonical type. The non-canonical version
/// of a type may have many "decorated" versions of types. Decorators can
/// include typedefs, 'typeof' operators, etc. The returned type is guaranteed
/// to be free of any of these, allowing two canonical types to be compared
/// for exact equality with a simple pointer comparison.
- QualType getCanonicalType(QualType T);
+ CanQualType getCanonicalType(QualType T);
const Type *getCanonicalType(const Type *T) {
return T->getCanonicalTypeInternal().getTypePtr();
}
@@ -608,7 +818,7 @@ public:
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) {
@@ -617,20 +827,7 @@ public:
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" declaration of
/// \brief Retrieves the "canonical" nested name specifier for a
/// given nested name specifier.
@@ -678,6 +875,13 @@ public:
/// types, values, and templates.
TemplateName getCanonicalTemplateName(TemplateName Name);
+ /// \brief Retrieve the "canonical" template argument.
+ ///
+ /// The canonical template argument is the simplest template argument
+ /// (which may be a type, value, expression, or declaration) that
+ /// expresses the value of the argument.
+ TemplateArgument getCanonicalTemplateArgument(const TemplateArgument &Arg);
+
/// 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
@@ -693,10 +897,17 @@ public:
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);
-
+ /// getBaseElementType - Returns the innermost element type of an array type.
+ /// For example, will return "int" for int[m][n]
+ QualType getBaseElementType(const ArrayType *VAT);
+
+ /// getBaseElementType - Returns the innermost element type of a type
+ /// (which needn't actually be an array type).
+ QualType getBaseElementType(QualType QT);
+
+ /// getConstantArrayElementCount - Returns number of constant array elements.
+ uint64_t getConstantArrayElementCount(const ConstantArrayType *CA) const;
+
/// getArrayDecayedType - Return the properly qualified result of decaying the
/// specified array type to a pointer. This operation is non-trivial when
/// handling typedefs etc. The canonical type of "T" must be an array type,
@@ -704,23 +915,35 @@ public:
///
/// See C99 6.7.5.3p7 and C99 6.3.2.1p3.
QualType getArrayDecayedType(QualType T);
-
- /// getIntegerTypeOrder - Returns the highest ranked integer type:
+
+ /// getPromotedIntegerType - Returns the type that Promotable will
+ /// promote to: C99 6.3.1.1p2, assuming that Promotable is a promotable
+ /// integer type.
+ QualType getPromotedIntegerType(QualType PromotableType);
+
+ /// \brief Whether this is a promotable bitfield reference according
+ /// to C99 6.3.1.1p2, bullet 2 (and GCC extensions).
+ ///
+ /// \returns the type this bit-field will promote to, or NULL if no
+ /// promotion occurs.
+ QualType isPromotableBitField(Expr *E);
+
+ /// 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.
+ /// 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.
+ /// LHS < RHS, return -1.
int getFloatingTypeOrder(QualType LHS, QualType RHS);
- /// getFloatingTypeOfSizeWithinDomain - Returns a real floating
- /// point or a complex type (based on typeDomain/typeSize).
+ /// 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 getFloatingTypeOfSizeWithinDomain(QualType typeSize,
QualType typeDomain) const;
private:
@@ -732,33 +955,28 @@ public:
//===--------------------------------------------------------------------===//
// Type Compatibility Predicates
//===--------------------------------------------------------------------===//
-
+
/// Compatibility predicates used to check assignment expressions.
bool typesAreCompatible(QualType, QualType); // C99 6.2.7p1
-
+
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;
+ return T == ObjCIdTypedefType;
}
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;
+ return T == ObjCClassTypedefType;
}
bool isObjCSelType(QualType T) const {
assert(SelStructType && "isObjCSelType used before 'SEL' type is built");
return T->getAsStructureType() == SelStructType;
}
+ bool QualifiedIdConformsQualifiedId(QualType LHS, QualType RHS);
+ bool ObjCQualifiedIdTypesAreCompatible(QualType LHS, QualType RHS,
+ bool ForCompare);
// Check the safety of assignment from LHS to RHS
- bool canAssignObjCInterfaces(const ObjCInterfaceType *LHS,
+ bool canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT,
+ const ObjCObjectPointerType *RHSOPT);
+ bool canAssignObjCInterfaces(const ObjCInterfaceType *LHS,
const ObjCInterfaceType *RHS);
bool areComparableObjCPointerTypes(QualType LHS, QualType RHS);
@@ -766,6 +984,11 @@ public:
QualType mergeTypes(QualType, QualType);
QualType mergeFunctionTypes(QualType, QualType);
+ /// 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);
+
//===--------------------------------------------------------------------===//
// Integer Predicates
//===--------------------------------------------------------------------===//
@@ -782,15 +1005,15 @@ public:
//===--------------------------------------------------------------------===//
// 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(); }
-
+ const_type_iterator types_end() const { return Types.end(); }
+
//===--------------------------------------------------------------------===//
// Integer Values
//===--------------------------------------------------------------------===//
@@ -803,15 +1026,37 @@ public:
return Res;
}
+ /// \brief Get the implementation of ObjCInterfaceDecl,or NULL if none exists.
+ ObjCImplementationDecl *getObjCImplementation(ObjCInterfaceDecl *D);
+ /// \brief Get the implementation of ObjCCategoryDecl, or NULL if none exists.
+ ObjCCategoryImplDecl *getObjCImplementation(ObjCCategoryDecl *D);
+
+ /// \brief Set the implementation of ObjCInterfaceDecl.
+ void setObjCImplementation(ObjCInterfaceDecl *IFaceD,
+ ObjCImplementationDecl *ImplD);
+ /// \brief Set the implementation of ObjCCategoryDecl.
+ void setObjCImplementation(ObjCCategoryDecl *CatD,
+ ObjCCategoryImplDecl *ImplD);
+
+ /// \brief Allocate an uninitialized DeclaratorInfo.
+ ///
+ /// The caller should initialize the memory held by DeclaratorInfo using
+ /// the TypeLoc wrappers.
+ ///
+ /// \param T the type that will be the basis for type source info. This type
+ /// should refer to how the declarator was written in source code, not to
+ /// what type semantic analysis resolved the declarator to.
+ DeclaratorInfo *CreateDeclaratorInfo(QualType T);
+
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,
+ void getObjCEncodingForTypeImpl(QualType t, std::string &S,
bool ExpandPointedToStructures,
bool ExpandStructures,
const FieldDecl *Field,
@@ -819,7 +1064,7 @@ private:
bool EncodingProperty = false);
const ASTRecordLayout &getObjCLayout(const ObjCInterfaceDecl *D,
- const ObjCImplementationDecl *Impl);
+ const ObjCImplementationDecl *Impl);
};
} // end namespace clang
diff --git a/include/clang/AST/ASTDiagnostic.h b/include/clang/AST/ASTDiagnostic.h
index e9f1505..abd36f7 100644
--- a/include/clang/AST/ASTDiagnostic.h
+++ b/include/clang/AST/ASTDiagnostic.h
@@ -13,7 +13,7 @@
#include "clang/Basic/Diagnostic.h"
namespace clang {
- namespace diag {
+ namespace diag {
enum {
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE) ENUM,
#define ASTSTART
diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h
index 7d3009b..6a5e366 100644
--- a/include/clang/AST/Attr.h
+++ b/include/clang/AST/Attr.h
@@ -14,6 +14,9 @@
#ifndef LLVM_CLANG_AST_ATTR_H
#define LLVM_CLANG_AST_ATTR_H
+#include "llvm/Support/Casting.h"
+using llvm::dyn_cast;
+
#include <cassert>
#include <cstring>
#include <string>
@@ -54,22 +57,24 @@ public:
DLLImport,
Deprecated,
Destructor,
- FastCall,
+ FastCall,
Format,
FormatArg,
GNUInline,
IBOutletKind, // Clang-specific. Use "Kind" suffix to not conflict with
+ Malloc,
+ NoDebug,
+ NoInline,
+ NonNull,
NoReturn,
NoThrow,
- Nodebug,
- Noinline,
- NonNull,
ObjCException,
ObjCNSObject,
CFReturnsRetained, // Clang/Checker-specific.
NSReturnsRetained, // Clang/Checker-specific.
Overloadable, // Clang-specific
Packed,
+ PragmaPack,
Pure,
Regparm,
ReqdWorkGroupSize, // OpenCL-specific
@@ -78,14 +83,14 @@ public:
StdCall,
TransparentUnion,
Unavailable,
- Unused,
+ Unused,
Used,
Visibility,
WarnUnusedResult,
Weak,
WeakImport
};
-
+
private:
Attr *Next;
Kind AttrKind;
@@ -99,16 +104,16 @@ protected:
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; }
@@ -119,17 +124,24 @@ public:
const Attr *getNext() const { return Next; }
void setNext(Attr *next) { Next = next; }
+ template<typename T> const T *getNext() const {
+ for (const Attr *attr = getNext(); attr; attr = attr->getNext())
+ if (const T *V = dyn_cast<T>(attr))
+ return V;
+ return 0;
+ }
+
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;
@@ -146,36 +158,39 @@ public: \
static bool classof(const ATTR##Attr *A) { return true; } \
}
-class PackedAttr : public Attr {
+DEF_SIMPLE_ATTR(Packed);
+
+class PragmaPackAttr : public Attr {
unsigned Alignment;
public:
- PackedAttr(unsigned alignment) : Attr(Packed), Alignment(alignment) {}
+ PragmaPackAttr(unsigned alignment) : Attr(PragmaPack), Alignment(alignment) {}
/// getAlignment - The specified alignment in bits.
unsigned getAlignment() const { return Alignment; }
- virtual Attr* clone(ASTContext &C) const {
- return ::new (C) PackedAttr(Alignment);
+ virtual Attr* clone(ASTContext &C) const {
+ return ::new (C) PragmaPackAttr(Alignment);
}
// Implement isa/cast/dyncast/etc.
static bool classof(const Attr *A) {
- return A->getKind() == Packed;
+ return A->getKind() == PragmaPack;
}
- static bool classof(const PackedAttr *A) { return true; }
+ static bool classof(const PragmaPackAttr *A) { return true; }
};
-
+
class AlignedAttr : public Attr {
unsigned Alignment;
public:
AlignedAttr(unsigned alignment) : Attr(Aligned), Alignment(alignment) {}
+ // FIXME: Should use addressable units, not bits, to match llvm
/// 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;
@@ -187,11 +202,11 @@ 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;
@@ -203,11 +218,11 @@ 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;
@@ -237,28 +252,28 @@ 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 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 Attr *A) { return A->getKind() == Destructor; }
static bool classof(const DestructorAttr *A) { return true; }
-};
-
+};
+
class GNUInlineAttr : public Attr {
public:
GNUInlineAttr() : Attr(GNUInline) {}
@@ -285,15 +300,16 @@ public:
static bool classof(const IBOutletAttr *A) { return true; }
};
+DEF_SIMPLE_ATTR(Malloc);
DEF_SIMPLE_ATTR(NoReturn);
-DEF_SIMPLE_ATTR(AnalyzerNoReturn);
+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); }
@@ -307,8 +323,8 @@ public:
DEF_SIMPLE_ATTR(Unavailable);
DEF_SIMPLE_ATTR(Unused);
-DEF_SIMPLE_ATTR(Used);
-DEF_SIMPLE_ATTR(Weak);
+DEF_SIMPLE_ATTR(Used);
+DEF_SIMPLE_ATTR(Weak);
DEF_SIMPLE_ATTR(WeakImport);
DEF_SIMPLE_ATTR(NoThrow);
DEF_SIMPLE_ATTR(Const);
@@ -320,14 +336,14 @@ class NonNullAttr : public Attr {
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;
}
@@ -339,7 +355,7 @@ public:
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); }
@@ -359,8 +375,8 @@ public:
int getFormatIdx() const { return formatIdx; }
int getFirstArg() const { return firstArg; }
- virtual Attr *clone(ASTContext &C) const {
- return ::new (C) FormatAttr(Type, formatIdx, firstArg);
+ virtual Attr *clone(ASTContext &C) const {
+ return ::new (C) FormatAttr(Type, formatIdx, firstArg);
}
// Implement isa/cast/dyncast/etc.
@@ -437,8 +453,8 @@ public:
virtual bool isMerged() const { return false; }
- virtual Attr *clone(ASTContext &C) const {
- return ::new (C) OverloadableAttr;
+ virtual Attr *clone(ASTContext &C) const {
+ return ::new (C) OverloadableAttr;
}
static bool classof(const Attr *A) { return A->getKind() == Overloadable; }
@@ -465,15 +481,15 @@ public:
};
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.
@@ -481,9 +497,9 @@ public:
static bool classof(const CleanupAttr *A) { return true; }
};
-DEF_SIMPLE_ATTR(Nodebug);
-DEF_SIMPLE_ATTR(WarnUnusedResult);
-DEF_SIMPLE_ATTR(Noinline);
+DEF_SIMPLE_ATTR(NoDebug);
+DEF_SIMPLE_ATTR(WarnUnusedResult);
+DEF_SIMPLE_ATTR(NoInline);
class RegparmAttr : public Attr {
unsigned NumParams;
@@ -493,11 +509,11 @@ public:
unsigned getNumParams() const { return NumParams; }
- virtual Attr *clone(ASTContext &C) const {
- return ::new (C) RegparmAttr(NumParams);
+ virtual Attr *clone(ASTContext &C) const {
+ return ::new (C) RegparmAttr(NumParams);
}
- // Implement isa/cast/dyncast/etc.
+ // Implement isa/cast/dyncast/etc.
static bool classof(const Attr *A) { return A->getKind() == Regparm; }
static bool classof(const RegparmAttr *A) { return true; }
};
@@ -512,23 +528,23 @@ public:
unsigned getYDim() const { return Y; }
unsigned getZDim() const { return Z; }
- virtual Attr *clone(ASTContext &C) const {
- return ::new (C) ReqdWorkGroupSizeAttr(X, Y, Z);
+ virtual Attr *clone(ASTContext &C) const {
+ return ::new (C) ReqdWorkGroupSizeAttr(X, Y, Z);
}
-
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Attr *A) {
return A->getKind() == ReqdWorkGroupSize;
}
static bool classof(const ReqdWorkGroupSizeAttr *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/CXXInheritance.h b/include/clang/AST/CXXInheritance.h
new file mode 100644
index 0000000..a57bcc1
--- /dev/null
+++ b/include/clang/AST/CXXInheritance.h
@@ -0,0 +1,212 @@
+//===------ CXXInheritance.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 routines that help analyzing C++ inheritance hierarchies.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_CXXINHERITANCE_H
+#define LLVM_CLANG_AST_CXXINHERITANCE_H
+
+#include "clang/AST/DeclarationName.h"
+#include "clang/AST/DeclBase.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/TypeOrdering.h"
+#include "llvm/ADT/SmallVector.h"
+#include <list>
+#include <map>
+#include <cassert>
+
+namespace clang {
+
+class CXXBaseSpecifier;
+class CXXMethodDecl;
+class CXXRecordDecl;
+class NamedDecl;
+
+/// \brief Represents 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 CXXBasePathElement {
+ /// \brief 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;
+
+ /// \brief The record decl of the class that the base is a base of.
+ const CXXRecordDecl *Class;
+
+ /// \brief 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;
+};
+
+/// \brief 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.
+///
+/// Individual elements in the path are described by the \c CXXBasePathElement
+/// structure, which captures both the link from a derived class to one of its
+/// direct bases and identification describing which base class
+/// subobject is being used.
+struct CXXBasePath : public llvm::SmallVector<CXXBasePathElement, 4> {
+ /// \brief 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 CXXBasePaths {
+ /// \brief The type from which this search originated.
+ CXXRecordDecl *Origin;
+
+ /// Paths - The actual set of paths that can be taken from the
+ /// derived class to the same base class.
+ std::list<CXXBasePath> 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.
+ CXXBasePath 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 CXXRecordDecl;
+
+ void ComputeDeclsFound();
+
+public:
+ typedef std::list<CXXBasePath>::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 CXXBasePaths(bool FindAmbiguities = true,
+ bool RecordPaths = true,
+ bool DetectVirtual = true)
+ : FindAmbiguities(FindAmbiguities), RecordPaths(RecordPaths),
+ DetectVirtual(DetectVirtual), DetectedVirtual(0), DeclsFound(0),
+ NumDeclsFound(0) { }
+
+ ~CXXBasePaths() { delete [] DeclsFound; }
+
+ paths_iterator begin() const { return Paths.begin(); }
+ paths_iterator end() const { return Paths.end(); }
+
+ CXXBasePath& front() { return Paths.front(); }
+ const CXXBasePath& front() const { return Paths.front(); }
+
+ decl_iterator found_decls_begin();
+ decl_iterator found_decls_end();
+
+ /// \brief Determine whether the path from the most-derived type to the
+ /// given base type is ambiguous (i.e., it refers to multiple subobjects of
+ /// the same base type).
+ bool isAmbiguous(QualType BaseType);
+
+ /// \brief Whether we are finding multiple paths to detect ambiguities.
+ bool isFindingAmbiguities() const { return FindAmbiguities; }
+
+ /// \brief Whether we are recording paths.
+ bool isRecordingPaths() const { return RecordPaths; }
+
+ /// \brief Specify whether we should be recording paths or not.
+ void setRecordingPaths(bool RP) { RecordPaths = RP; }
+
+ /// \brief Whether we are detecting virtual bases.
+ bool isDetectingVirtual() const { return DetectVirtual; }
+
+ /// \brief The virtual base discovered on the path (if we are merely
+ /// detecting virtuals).
+ const RecordType* getDetectedVirtual() const {
+ return DetectedVirtual;
+ }
+
+ /// \brief Retrieve the type from which this base-paths search
+ /// began
+ CXXRecordDecl *getOrigin() const { return Origin; }
+ void setOrigin(CXXRecordDecl *Rec) { Origin = Rec; }
+
+ /// \brief Clear the base-paths results.
+ void clear();
+
+ /// \brief Swap this data structure's contents with another CXXBasePaths
+ /// object.
+ void swap(CXXBasePaths &Other);
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/AST/CanonicalType.h b/include/clang/AST/CanonicalType.h
new file mode 100644
index 0000000..d7ac76d
--- /dev/null
+++ b/include/clang/AST/CanonicalType.h
@@ -0,0 +1,721 @@
+//===-- CanonicalType.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 CanQual class template, which provides access to
+// canonical types.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_CANONICAL_TYPE_H
+#define LLVM_CLANG_AST_CANONICAL_TYPE_H
+
+#include "clang/AST/Type.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/type_traits.h"
+#include <iterator>
+
+namespace clang {
+
+template<typename T> class CanProxy;
+template<typename T> struct CanProxyAdaptor;
+
+//----------------------------------------------------------------------------//
+// Canonical, qualified type template
+//----------------------------------------------------------------------------//
+
+/// \brief Represents a canonical, potentially-qualified type.
+///
+/// The CanQual template is a lightweight smart pointer that provides access
+/// to the canonical representation of a type, where all typedefs and other
+/// syntactic sugar has been eliminated. A CanQualType may also have various
+/// qualifiers (const, volatile, restrict) attached to it.
+///
+/// The template type parameter @p T is one of the Type classes (PointerType,
+/// BuiltinType, etc.). The type stored within @c CanQual<T> will be of that
+/// type (or some subclass of that type). The typedef @c CanQualType is just
+/// a shorthand for @c CanQual<Type>.
+///
+/// An instance of @c CanQual<T> can be implicitly converted to a
+/// @c CanQual<U> when T is derived from U, which essentially provides an
+/// implicit upcast. For example, @c CanQual<LValueReferenceType> can be
+/// converted to @c CanQual<ReferenceType>. Note that any @c CanQual type can
+/// be implicitly converted to a QualType, but the reverse operation requires
+/// a call to ASTContext::getCanonicalType().
+///
+///
+template<typename T = Type>
+class CanQual {
+ /// \brief The actual, canonical type.
+ QualType Stored;
+
+public:
+ /// \brief Constructs a NULL canonical type.
+ CanQual() : Stored() { }
+
+ /// \brief Converting constructor that permits implicit upcasting of
+ /// canonical type pointers.
+ template<typename U>
+ CanQual(const CanQual<U>& Other,
+ typename llvm::enable_if<llvm::is_base_of<T, U>, int>::type = 0);
+
+ /// \brief Implicit conversion to the underlying pointer.
+ ///
+ /// Also provides the ability to use canonical types in a boolean context,
+ /// e.g.,
+ /// @code
+ /// if (CanQual<PointerType> Ptr = T->getAs<PointerType>()) { ... }
+ /// @endcode
+ operator const T*() const { return getTypePtr(); }
+
+ /// \brief Retrieve the underlying type pointer, which refers to a
+ /// canonical type.
+ T *getTypePtr() const { return cast_or_null<T>(Stored.getTypePtr()); }
+
+ /// \brief Implicit conversion to a qualified type.
+ operator QualType() const { return Stored; }
+
+ /// \brief Retrieve a canonical type pointer with a different static type,
+ /// upcasting or downcasting as needed.
+ ///
+ /// The getAs() function is typically used to try to downcast to a
+ /// more specific (canonical) type in the type system. For example:
+ ///
+ /// @code
+ /// void f(CanQual<Type> T) {
+ /// if (CanQual<PointerType> Ptr = T->getAs<PointerType>()) {
+ /// // look at Ptr's pointee type
+ /// }
+ /// }
+ /// @endcode
+ ///
+ /// \returns A proxy pointer to the same type, but with the specified
+ /// static type (@p U). If the dynamic type is not the specified static type
+ /// or a derived class thereof, a NULL canonical type.
+ template<typename U> CanProxy<U> getAs() const;
+
+ /// \brief Overloaded arrow operator that produces a canonical type
+ /// proxy.
+ CanProxy<T> operator->() const;
+
+ /// \brief Retrieve all qualifiers.
+ Qualifiers getQualifiers() const { return Stored.getQualifiers(); }
+
+ /// \brief Retrieve the const/volatile/restrict qualifiers.
+ unsigned getCVRQualifiers() const { return Stored.getCVRQualifiers(); }
+
+ /// \brief Determines whether this type has any qualifiers
+ bool hasQualifiers() const { return Stored.hasQualifiers(); }
+
+ bool isConstQualified() const {
+ return Stored.isConstQualified();
+ }
+ bool isVolatileQualified() const {
+ return Stored.isVolatileQualified();
+ }
+ bool isRestrictQualified() const {
+ return Stored.isRestrictQualified();
+ }
+
+ /// \brief Retrieve the unqualified form of this type.
+ CanQual<T> getUnqualifiedType() const;
+
+ CanQual<T> getQualifiedType(unsigned TQs) const {
+ return CanQual<T>::CreateUnsafe(QualType(getTypePtr(), TQs));
+ }
+
+ /// \brief Determines whether this canonical type is more qualified than
+ /// the @p Other canonical type.
+ bool isMoreQualifiedThan(CanQual<T> Other) const {
+ return Stored.isMoreQualifiedThan(Other.Stored);
+ }
+
+ /// \brief Determines whether this canonical type is at least as qualified as
+ /// the @p Other canonical type.
+ bool isAtLeastAsQualifiedAs(CanQual<T> Other) const {
+ return Stored.isAtLeastAsQualifiedAs(Other.Stored);
+ }
+
+ /// \brief If the canonical type is a reference type, returns the type that
+ /// it refers to; otherwise, returns the type itself.
+ CanQual<Type> getNonReferenceType() const;
+
+ /// \brief Retrieve the internal representation of this canonical type.
+ void *getAsOpaquePtr() const { return Stored.getAsOpaquePtr(); }
+
+ /// \brief Construct a canonical type from its internal representation.
+ static CanQual<T> getFromOpaquePtr(void *Ptr);
+
+ /// \brief Builds a canonical type from a QualType.
+ ///
+ /// This routine is inherently unsafe, because it requires the user to
+ /// ensure that the given type is a canonical type with the correct
+ // (dynamic) type.
+ static CanQual<T> CreateUnsafe(QualType Other);
+};
+
+template<typename T, typename U>
+inline bool operator==(CanQual<T> x, CanQual<U> y) {
+ return x.getAsOpaquePtr() == y.getAsOpaquePtr();
+}
+
+template<typename T, typename U>
+inline bool operator!=(CanQual<T> x, CanQual<U> y) {
+ return x.getAsOpaquePtr() != y.getAsOpaquePtr();
+}
+
+/// \brief Represents a canonical, potentially-qualified type.
+typedef CanQual<Type> CanQualType;
+
+//----------------------------------------------------------------------------//
+// Internal proxy classes used by canonical types
+//----------------------------------------------------------------------------//
+
+#define LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(Accessor) \
+CanQualType Accessor() const { \
+return CanQualType::CreateUnsafe(this->getTypePtr()->Accessor()); \
+}
+
+#define LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Type, Accessor) \
+Type Accessor() const { return this->getTypePtr()->Accessor(); }
+
+/// \brief Base class of all canonical proxy types, which is responsible for
+/// storing the underlying canonical type and providing basic conversions.
+template<typename T>
+class CanProxyBase {
+protected:
+ CanQual<T> Stored;
+
+public:
+ /// \brief Retrieve the pointer to the underlying Type
+ T* getTypePtr() const { return Stored.getTypePtr(); }
+
+ /// \brief Implicit conversion to the underlying pointer.
+ ///
+ /// Also provides the ability to use canonical type proxies in a Boolean
+ // context,e.g.,
+ /// @code
+ /// if (CanQual<PointerType> Ptr = T->getAs<PointerType>()) { ... }
+ /// @endcode
+ operator const T*() const { return this->Stored.getTypePtr(); }
+
+ /// \brief Try to convert the given canonical type to a specific structural
+ /// type.
+ template<typename U> CanProxy<U> getAs() const {
+ return this->Stored.template getAs<U>();
+ }
+
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Type::TypeClass, getTypeClass)
+
+ // Type predicates
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjectType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIncompleteType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIncompleteOrObjectType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isPODType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isVariablyModifiedType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIntegerType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isEnumeralType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBooleanType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isCharType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isWideCharType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIntegralType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isRealFloatingType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isComplexType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isAnyComplexType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isFloatingType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isRealType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isArithmeticType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isVoidType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isDerivedType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isScalarType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isAggregateType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isAnyPointerType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isVoidPointerType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isFunctionPointerType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isMemberFunctionPointerType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isClassType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isStructureType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isUnionType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isComplexIntegerType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isNullPtrType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isDependentType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isOverloadableType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasPointerRepresentation)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasObjCPointerRepresentation)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isPromotableIntegerType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isSignedIntegerType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isUnsignedIntegerType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isConstantSizeType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isSpecifierType)
+
+ /// \brief Retrieve the proxy-adaptor type.
+ ///
+ /// This arrow operator is used when CanProxyAdaptor has been specialized
+ /// for the given type T. In that case, we reference members of the
+ /// CanProxyAdaptor specialization. Otherwise, this operator will be hidden
+ /// by the arrow operator in the primary CanProxyAdaptor template.
+ const CanProxyAdaptor<T> *operator->() const {
+ return static_cast<const CanProxyAdaptor<T> *>(this);
+ }
+};
+
+/// \brief Replacable canonical proxy adaptor class that provides the link
+/// between a canonical type and the accessors of the type.
+///
+/// The CanProxyAdaptor is a replaceable class template that is instantiated
+/// as part of each canonical proxy type. The primary template merely provides
+/// redirection to the underlying type (T), e.g., @c PointerType. One can
+/// provide specializations of this class template for each underlying type
+/// that provide accessors returning canonical types (@c CanQualType) rather
+/// than the more typical @c QualType, to propagate the notion of "canonical"
+/// through the system.
+template<typename T>
+struct CanProxyAdaptor : CanProxyBase<T> { };
+
+/// \brief Canonical proxy type returned when retrieving the members of a
+/// canonical type or as the result of the @c CanQual<T>::getAs member
+/// function.
+///
+/// The CanProxy type mainly exists as a proxy through which operator-> will
+/// look to either map down to a raw T* (e.g., PointerType*) or to a proxy
+/// type that provides canonical-type access to the fields of the type.
+template<typename T>
+class CanProxy : public CanProxyAdaptor<T> {
+public:
+ /// \brief Build a NULL proxy.
+ CanProxy() { }
+
+ /// \brief Build a proxy to the given canonical type.
+ CanProxy(CanQual<T> Stored) { this->Stored = Stored; }
+
+ /// \brief Implicit conversion to the stored canonical type.
+ operator CanQual<T>() const { return this->Stored; }
+};
+
+} // end namespace clang
+
+namespace llvm {
+
+/// Implement simplify_type for CanQual<T>, so that we can dyn_cast from
+/// CanQual<T> to a specific Type class. We're prefer isa/dyn_cast/cast/etc.
+/// to return smart pointer (proxies?).
+template<typename T>
+struct simplify_type<const ::clang::CanQual<T> > {
+ typedef T* SimpleType;
+ static SimpleType getSimplifiedValue(const ::clang::CanQual<T> &Val) {
+ return Val.getTypePtr();
+ }
+};
+template<typename T>
+struct simplify_type< ::clang::CanQual<T> >
+: public simplify_type<const ::clang::CanQual<T> > {};
+
+// Teach SmallPtrSet that CanQual<T> is "basically a pointer".
+template<typename T>
+class PointerLikeTypeTraits<clang::CanQual<T> > {
+public:
+ static inline void *getAsVoidPointer(clang::CanQual<T> P) {
+ return P.getAsOpaquePtr();
+ }
+ static inline clang::CanQual<T> getFromVoidPointer(void *P) {
+ return clang::CanQual<T>::getFromOpaquePtr(P);
+ }
+ // qualifier information is encoded in the low bits.
+ enum { NumLowBitsAvailable = 0 };
+};
+
+} // end namespace llvm
+
+namespace clang {
+
+//----------------------------------------------------------------------------//
+// Canonical proxy adaptors for canonical type nodes.
+//----------------------------------------------------------------------------//
+
+/// \brief Iterator adaptor that turns an iterator over canonical QualTypes
+/// into an iterator over CanQualTypes.
+template<typename InputIterator>
+class CanTypeIterator {
+ InputIterator Iter;
+
+public:
+ typedef CanQualType value_type;
+ typedef value_type reference;
+ typedef CanProxy<Type> pointer;
+ typedef typename std::iterator_traits<InputIterator>::difference_type
+ difference_type;
+ typedef typename std::iterator_traits<InputIterator>::iterator_category
+ iterator_category;
+
+ CanTypeIterator() : Iter() { }
+ explicit CanTypeIterator(InputIterator Iter) : Iter(Iter) { }
+
+ // Input iterator
+ reference operator*() const {
+ return CanQualType::CreateUnsafe(*Iter);
+ }
+
+ pointer operator->() const;
+
+ CanTypeIterator &operator++() {
+ ++Iter;
+ return *this;
+ }
+
+ CanTypeIterator operator++(int) {
+ CanTypeIterator Tmp(*this);
+ ++Iter;
+ return Tmp;
+ }
+
+ friend bool operator==(const CanTypeIterator& X, const CanTypeIterator &Y) {
+ return X.Iter == Y.Iter;
+ }
+ friend bool operator!=(const CanTypeIterator& X, const CanTypeIterator &Y) {
+ return X.Iter != Y.Iter;
+ }
+
+ // Bidirectional iterator
+ CanTypeIterator &operator--() {
+ --Iter;
+ return *this;
+ }
+
+ CanTypeIterator operator--(int) {
+ CanTypeIterator Tmp(*this);
+ --Iter;
+ return Tmp;
+ }
+
+ // Random access iterator
+ reference operator[](difference_type n) const {
+ return CanQualType::CreateUnsafe(Iter[n]);
+ }
+
+ CanTypeIterator &operator+=(difference_type n) {
+ Iter += n;
+ return *this;
+ }
+
+ CanTypeIterator &operator-=(difference_type n) {
+ Iter -= n;
+ return *this;
+ }
+
+ friend CanTypeIterator operator+(CanTypeIterator X, difference_type n) {
+ X += n;
+ return X;
+ }
+
+ friend CanTypeIterator operator+(difference_type n, CanTypeIterator X) {
+ X += n;
+ return X;
+ }
+
+ friend CanTypeIterator operator-(CanTypeIterator X, difference_type n) {
+ X -= n;
+ return X;
+ }
+
+ friend difference_type operator-(const CanTypeIterator &X,
+ const CanTypeIterator &Y) {
+ return X - Y;
+ }
+};
+
+template<>
+struct CanProxyAdaptor<ComplexType> : public CanProxyBase<ComplexType> {
+ LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType)
+};
+
+template<>
+struct CanProxyAdaptor<PointerType> : public CanProxyBase<PointerType> {
+ LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType)
+};
+
+template<>
+struct CanProxyAdaptor<BlockPointerType>
+ : public CanProxyBase<BlockPointerType> {
+ LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType)
+};
+
+template<>
+struct CanProxyAdaptor<ReferenceType> : public CanProxyBase<ReferenceType> {
+ LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType)
+};
+
+template<>
+struct CanProxyAdaptor<LValueReferenceType>
+ : public CanProxyBase<LValueReferenceType> {
+ LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType)
+};
+
+template<>
+struct CanProxyAdaptor<RValueReferenceType>
+ : public CanProxyBase<RValueReferenceType> {
+ LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType)
+};
+
+template<>
+struct CanProxyAdaptor<MemberPointerType>
+ : public CanProxyBase<MemberPointerType> {
+ LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const Type *, getClass)
+};
+
+template<>
+struct CanProxyAdaptor<ArrayType> : public CanProxyBase<ArrayType> {
+ LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(ArrayType::ArraySizeModifier,
+ getSizeModifier)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Qualifiers, getIndexTypeQualifiers)
+};
+
+template<>
+struct CanProxyAdaptor<ConstantArrayType>
+ : public CanProxyBase<ConstantArrayType> {
+ LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(ArrayType::ArraySizeModifier,
+ getSizeModifier)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Qualifiers, getIndexTypeQualifiers)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const llvm::APInt &, getSize)
+};
+
+template<>
+struct CanProxyAdaptor<ConstantArrayWithExprType>
+ : public CanProxyBase<ConstantArrayWithExprType> {
+ LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(ArrayType::ArraySizeModifier,
+ getSizeModifier)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Qualifiers, getIndexTypeQualifiers)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const llvm::APInt &, getSize)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Expr *, getSizeExpr)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceRange, getBracketsRange)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getLBracketLoc)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getRBracketLoc)
+};
+
+template<>
+struct CanProxyAdaptor<ConstantArrayWithoutExprType>
+ : public CanProxyBase<ConstantArrayWithoutExprType> {
+ LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(ArrayType::ArraySizeModifier,
+ getSizeModifier)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Qualifiers, getIndexTypeQualifiers)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const llvm::APInt &, getSize)
+};
+
+template<>
+struct CanProxyAdaptor<IncompleteArrayType>
+ : public CanProxyBase<IncompleteArrayType> {
+ LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(ArrayType::ArraySizeModifier,
+ getSizeModifier)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Qualifiers, getIndexTypeQualifiers)
+};
+
+template<>
+struct CanProxyAdaptor<VariableArrayType>
+ : public CanProxyBase<VariableArrayType> {
+ LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(ArrayType::ArraySizeModifier,
+ getSizeModifier)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Qualifiers, getIndexTypeQualifiers)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Expr *, getSizeExpr)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceRange, getBracketsRange)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getLBracketLoc)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getRBracketLoc)
+};
+
+template<>
+struct CanProxyAdaptor<DependentSizedArrayType>
+ : public CanProxyBase<DependentSizedArrayType> {
+ LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Expr *, getSizeExpr)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceRange, getBracketsRange)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getLBracketLoc)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getRBracketLoc)
+};
+
+template<>
+struct CanProxyAdaptor<DependentSizedExtVectorType>
+ : public CanProxyBase<DependentSizedExtVectorType> {
+ LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const Expr *, getSizeExpr)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getAttributeLoc)
+};
+
+template<>
+struct CanProxyAdaptor<VectorType> : public CanProxyBase<VectorType> {
+ LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getNumElements)
+};
+
+template<>
+struct CanProxyAdaptor<ExtVectorType> : public CanProxyBase<ExtVectorType> {
+ LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getNumElements)
+};
+
+template<>
+struct CanProxyAdaptor<FunctionType> : public CanProxyBase<FunctionType> {
+ LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getResultType)
+};
+
+template<>
+struct CanProxyAdaptor<FunctionNoProtoType>
+ : public CanProxyBase<FunctionNoProtoType> {
+ LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getResultType)
+};
+
+template<>
+struct CanProxyAdaptor<FunctionProtoType>
+ : public CanProxyBase<FunctionProtoType> {
+ LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getResultType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getNumArgs);
+ CanQualType getArgType(unsigned i) const {
+ return CanQualType::CreateUnsafe(this->getTypePtr()->getArgType(i));
+ }
+
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isVariadic)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getTypeQuals)
+
+ typedef CanTypeIterator<FunctionProtoType::arg_type_iterator>
+ arg_type_iterator;
+
+ arg_type_iterator arg_type_begin() const {
+ return arg_type_iterator(this->getTypePtr()->arg_type_begin());
+ }
+
+ arg_type_iterator arg_type_end() const {
+ return arg_type_iterator(this->getTypePtr()->arg_type_end());
+ }
+
+ // Note: canonical function types never have exception specifications
+};
+
+template<>
+struct CanProxyAdaptor<TypeOfType> : public CanProxyBase<TypeOfType> {
+ LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getUnderlyingType)
+};
+
+template<>
+struct CanProxyAdaptor<DecltypeType> : public CanProxyBase<DecltypeType> {
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Expr *, getUnderlyingExpr)
+ LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getUnderlyingType)
+};
+
+template<>
+struct CanProxyAdaptor<TagType> : public CanProxyBase<TagType> {
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(TagDecl *, getDecl)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBeingDefined)
+};
+
+template<>
+struct CanProxyAdaptor<RecordType> : public CanProxyBase<RecordType> {
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(RecordDecl *, getDecl)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBeingDefined)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasConstFields)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getAddressSpace)
+};
+
+template<>
+struct CanProxyAdaptor<EnumType> : public CanProxyBase<EnumType> {
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(EnumDecl *, getDecl)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBeingDefined)
+};
+
+template<>
+struct CanProxyAdaptor<TemplateTypeParmType>
+ : public CanProxyBase<TemplateTypeParmType> {
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getDepth)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getIndex)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isParameterPack)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(IdentifierInfo *, getName)
+};
+
+template<>
+struct CanProxyAdaptor<ObjCObjectPointerType>
+ : public CanProxyBase<ObjCObjectPointerType> {
+ LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const ObjCInterfaceType *,
+ getInterfaceType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCIdType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCClassType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCQualifiedIdType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCQualifiedClassType)
+
+ typedef ObjCObjectPointerType::qual_iterator qual_iterator;
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(qual_iterator, qual_begin)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(qual_iterator, qual_end)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, qual_empty)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getNumProtocols)
+};
+
+//----------------------------------------------------------------------------//
+// Method and function definitions
+//----------------------------------------------------------------------------//
+template<typename T>
+inline CanQual<T> CanQual<T>::getUnqualifiedType() const {
+ return CanQual<T>::CreateUnsafe(Stored.getUnqualifiedType());
+}
+
+template<typename T>
+inline CanQual<Type> CanQual<T>::getNonReferenceType() const {
+ if (CanQual<ReferenceType> RefType = getAs<ReferenceType>())
+ return RefType->getPointeeType();
+ else
+ return *this;
+}
+
+template<typename T>
+CanQual<T> CanQual<T>::getFromOpaquePtr(void *Ptr) {
+ CanQual<T> Result;
+ Result.Stored.setFromOpaqueValue(Ptr);
+ assert((!Result || Result.Stored.isCanonical())
+ && "Type is not canonical!");
+ return Result;
+}
+
+template<typename T>
+CanQual<T> CanQual<T>::CreateUnsafe(QualType Other) {
+ assert((Other.isNull() || Other->isCanonical()) && "Type is not canonical!");
+ assert((Other.isNull() || isa<T>(Other.getTypePtr())) &&
+ "Dynamic type does not meet the static type's requires");
+ CanQual<T> Result;
+ Result.Stored = Other;
+ return Result;
+}
+
+template<typename T>
+template<typename U>
+CanProxy<U> CanQual<T>::getAs() const {
+ if (Stored.isNull())
+ return CanProxy<U>();
+
+ if (isa<U>(Stored.getTypePtr()))
+ return CanQual<U>::CreateUnsafe(Stored);
+
+ return CanProxy<U>();
+}
+
+template<typename T>
+CanProxy<T> CanQual<T>::operator->() const {
+ return CanProxy<T>(*this);
+}
+
+template<typename InputIterator>
+typename CanTypeIterator<InputIterator>::pointer
+CanTypeIterator<InputIterator>::operator->() const {
+ return CanProxy<Type>(*this);
+}
+
+}
+
+
+#endif // LLVM_CLANG_AST_CANONICAL_TYPE_H
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 69a5286..7c326de 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -16,6 +16,7 @@
#include "clang/AST/APValue.h"
#include "clang/AST/DeclBase.h"
+#include "clang/AST/Redeclarable.h"
#include "clang/AST/DeclarationName.h"
#include "clang/AST/ExternalASTSource.h"
@@ -26,23 +27,45 @@ class Stmt;
class CompoundStmt;
class StringLiteral;
class TemplateArgumentList;
+class MemberSpecializationInfo;
class FunctionTemplateSpecializationInfo;
-
+class TypeLoc;
+
+/// \brief A container of type source information.
+///
+/// A client can read the relevant info using TypeLoc wrappers, e.g:
+/// @code
+/// TypeLoc TL = DeclaratorInfo->getTypeLoc();
+/// if (PointerLoc *PL = dyn_cast<PointerLoc>(&TL))
+/// PL->getStarLoc().print(OS, SrcMgr);
+/// @endcode
+///
+class DeclaratorInfo {
+ QualType Ty;
+ // Contains a memory block after the class, used for type source information,
+ // allocated by ASTContext.
+ friend class ASTContext;
+ DeclaratorInfo(QualType ty) : Ty(ty) { }
+public:
+ /// \brief Return the TypeLoc wrapper for the type source info.
+ TypeLoc getTypeLoc() const;
+};
+
/// TranslationUnitDecl - The top declaration context.
class TranslationUnitDecl : public Decl, public DeclContext {
ASTContext &Ctx;
-
+
explicit TranslationUnitDecl(ASTContext &ctx)
: Decl(TranslationUnit, 0, SourceLocation()),
DeclContext(TranslationUnit),
Ctx(ctx) {}
public:
ASTContext &getASTContext() const { return Ctx; }
-
+
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 bool classof(const TranslationUnitDecl *D) { return true; }
static DeclContext *castToDeclContext(const TranslationUnitDecl *D) {
return static_cast<DeclContext *>(const_cast<TranslationUnitDecl*>(D));
}
@@ -91,7 +114,7 @@ public:
/// 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,
@@ -99,6 +122,25 @@ public:
/// Creating this name is expensive, so it should be called only when
/// performance doesn't matter.
std::string getQualifiedNameAsString() const;
+ std::string getQualifiedNameAsString(const PrintingPolicy &Policy) const;
+
+ /// getNameForDiagnostic - Appends a human-readable name for this
+ /// declaration into the given string.
+ ///
+ /// This is the method invoked by Sema when displaying a NamedDecl
+ /// in a diagnostic. It does not necessarily produce the same
+ /// result as getNameAsString(); for example, class template
+ /// specializations are printed with their template arguments.
+ ///
+ /// TODO: use an API that doesn't require so many temporary strings
+ virtual void getNameForDiagnostic(std::string &S,
+ const PrintingPolicy &Policy,
+ bool Qualified) const {
+ if (Qualified)
+ S += getQualifiedNameAsString(Policy);
+ else
+ S += getNameAsString();
+ }
/// declarationReplaces - Determine whether this declaration, if
/// known to be well-formed within its context, will replace the
@@ -118,7 +160,7 @@ public:
const NamedDecl *getUnderlyingDecl() const {
return const_cast<NamedDecl*>(this)->getUnderlyingDecl();
}
-
+
static bool classof(const Decl *D) {
return D->getKind() >= NamedFirst && D->getKind() <= NamedLast;
}
@@ -128,7 +170,7 @@ public:
/// NamespaceDecl - Represent a C++ namespace.
class NamespaceDecl : public NamedDecl, public DeclContext {
SourceLocation LBracLoc, RBracLoc;
-
+
// For extended namespace definitions:
//
// namespace A { int x; }
@@ -139,7 +181,7 @@ class NamespaceDecl : public NamedDecl, public DeclContext {
// 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;
@@ -148,9 +190,20 @@ class NamespaceDecl : public NamedDecl, public DeclContext {
public:
static NamespaceDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id);
-
+
virtual void Destroy(ASTContext& C);
+ // \brief Returns true if this is an anonymous namespace declaration.
+ //
+ // For example:
+ // namespace {
+ // ...
+ // };
+ // q.v. C++ [namespace.unnamed]
+ bool isAnonymousNamespace() const {
+ return !getIdentifier();
+ }
+
NamespaceDecl *getNextNamespace() { return NextNamespace; }
const NamespaceDecl *getNextNamespace() const { return NextNamespace; }
void setNextNamespace(NamespaceDecl *ND) { NextNamespace = ND; }
@@ -159,7 +212,9 @@ public:
return OrigNamespace;
}
void setOriginalNamespace(NamespaceDecl *ND) { OrigNamespace = ND; }
-
+
+ virtual NamespaceDecl *getCanonicalDecl() { return OrigNamespace; }
+
virtual SourceRange getSourceRange() const {
return SourceRange(getLocation(), RBracLoc);
}
@@ -168,7 +223,7 @@ public:
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; }
@@ -180,20 +235,20 @@ public:
}
};
-/// ValueDecl - Represent the declaration of a variable (in which case it is
+/// 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.
+/// an enum constant.
class ValueDecl : public NamedDecl {
QualType DeclType;
protected:
ValueDecl(Kind DK, DeclContext *DC, SourceLocation L,
- DeclarationName N, QualType T)
+ 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;
@@ -201,6 +256,29 @@ public:
static bool classof(const ValueDecl *D) { return true; }
};
+/// \brief Represents a ValueDecl that came out of a declarator.
+/// Contains type source information through DeclaratorInfo.
+class DeclaratorDecl : public ValueDecl {
+ DeclaratorInfo *DeclInfo;
+
+protected:
+ DeclaratorDecl(Kind DK, DeclContext *DC, SourceLocation L,
+ DeclarationName N, QualType T, DeclaratorInfo *DInfo)
+ : ValueDecl(DK, DC, L, N, T), DeclInfo(DInfo) {}
+
+public:
+ DeclaratorInfo *getDeclaratorInfo() const { return DeclInfo; }
+ void setDeclaratorInfo(DeclaratorInfo *DInfo) { DeclInfo = DInfo; }
+
+ SourceLocation getTypeSpecStartLoc() const;
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) {
+ return D->getKind() >= DeclaratorFirst && D->getKind() <= DeclaratorLast;
+ }
+ static bool classof(const DeclaratorDecl *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).
@@ -222,9 +300,32 @@ struct EvaluatedStmt {
APValue Evaluated;
};
+// \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 implicitly instantiated from a
+ /// template. (C++ [temp.inst]).
+ TSK_ImplicitInstantiation,
+ /// 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 instantiated from a template
+ /// due to an explicit instantiation declaration request
+ /// (C++0x [temp.explicit]).
+ TSK_ExplicitInstantiationDeclaration,
+ /// This template specialization was instantiated from a template
+ /// due to an explicit instantiation definition request
+ /// (C++ [temp.explicit]).
+ TSK_ExplicitInstantiationDefinition
+};
+
/// VarDecl - An instance of this class is created to represent a variable
/// declaration or definition.
-class VarDecl : public ValueDecl {
+class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
public:
enum StorageClass {
None, Auto, Register, Extern, Static, PrivateExtern
@@ -236,81 +337,108 @@ public:
/// It is illegal to call this function with SC == None.
static const char *getStorageClassSpecifierString(StorageClass SC);
+protected:
+ /// \brief Placeholder type used in Init to denote an unparsed C++ default
+ /// argument.
+ struct UnparsedDefaultArgument;
+
+ /// \brief Placeholder type used in Init to denote an uninstantiated C++
+ /// default argument.
+ struct UninstantiatedDefaultArgument;
+
+ typedef llvm::PointerUnion4<Stmt *, EvaluatedStmt *,
+ UnparsedDefaultArgument *,
+ UninstantiatedDefaultArgument *> InitType;
+
+ /// \brief The initializer for this variable or, for a ParmVarDecl, the
+ /// C++ default argument.
+ mutable InitType Init;
+
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;
+ 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(),
+ QualType T, DeclaratorInfo *DInfo, StorageClass SC)
+ : DeclaratorDecl(DK, DC, L, Id, T, DInfo), Init(),
ThreadSpecified(false), HasCXXDirectInit(false),
- DeclaredInCondition(false), PreviousDeclaration(0),
- TypeSpecStartLoc(TSSL) {
- SClass = SC;
+ DeclaredInCondition(false) {
+ SClass = SC;
}
+
+ typedef Redeclarable<VarDecl> redeclarable_base;
+ virtual VarDecl *getNextRedeclaration() { return RedeclLink.getNext(); }
+
public:
+ typedef redeclarable_base::redecl_iterator redecl_iterator;
+ redecl_iterator redecls_begin() const {
+ return redeclarable_base::redecls_begin();
+ }
+ redecl_iterator redecls_end() const {
+ return redeclarable_base::redecls_end();
+ }
+
static VarDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id,
- QualType T, StorageClass S,
- SourceLocation TypeSpecStartLoc = SourceLocation());
+ QualType T, DeclaratorInfo *DInfo, StorageClass S);
virtual ~VarDecl();
virtual void Destroy(ASTContext& C);
StorageClass getStorageClass() const { return (StorageClass)SClass; }
void setStorageClass(StorageClass SC) { SClass = SC; }
-
- virtual SourceRange getSourceRange() const;
- SourceLocation getTypeSpecStartLoc() const { return TypeSpecStartLoc; }
- void setTypeSpecStartLoc(SourceLocation SL) {
- TypeSpecStartLoc = SL;
- }
+ virtual SourceRange getSourceRange() const;
- const Expr *getInit() const {
+ 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;
+ if (!S) {
+ if (EvaluatedStmt *ES = Init.dyn_cast<EvaluatedStmt*>())
+ S = ES->Value;
+ }
+ return (const Expr*) S;
}
- Expr *getInit() {
+ Expr *getInit() {
if (Init.isNull())
return 0;
Stmt *S = Init.dyn_cast<Stmt *>();
- if (!S)
- S = Init.get<EvaluatedStmt *>()->Value;
+ if (!S) {
+ if (EvaluatedStmt *ES = Init.dyn_cast<EvaluatedStmt*>())
+ S = ES->Value;
+ }
- return (Expr*) S;
+ 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;
+ if (EvaluatedStmt *ES = Init.dyn_cast<EvaluatedStmt*>())
+ return &ES->Value;
+
+ // This union hack tip-toes around strict-aliasing rules.
+ union {
+ InitType *InitPtr;
+ Stmt **StmtPtr;
+ };
+
+ InitPtr = &Init;
+ return StmtPtr;
}
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 {
@@ -325,7 +453,7 @@ public:
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 {
@@ -350,7 +478,7 @@ public:
///
/// \pre isInitKnownICE()
bool isInitICE() const {
- assert(isInitKnownICE() &&
+ assert(isInitKnownICE() &&
"Check whether we already know that the initializer is an ICE");
return Init.get<EvaluatedStmt *>()->IsICE;
}
@@ -392,7 +520,7 @@ public:
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
@@ -401,27 +529,21 @@ public:
bool isDeclaredInCondition() const {
return DeclaredInCondition;
}
- void setDeclaredInCondition(bool InCondition) {
- DeclaredInCondition = InCondition;
+ 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;
- }
+ virtual VarDecl *getCanonicalDecl();
/// 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;
}
@@ -448,7 +570,7 @@ public:
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
@@ -462,6 +584,24 @@ public:
return getDeclContext()->isRecord();
}
+ /// \brief If this variable is an instantiated static data member of a
+ /// class template specialization, returns the templated static data member
+ /// from which it was instantiated.
+ VarDecl *getInstantiatedFromStaticDataMember();
+
+ /// \brief If this variable is a static data member, determine what kind of
+ /// template specialization or instantiation this is.
+ TemplateSpecializationKind getTemplateSpecializationKind();
+
+ /// \brief If this variable is an instantiation of a static data member of a
+ /// class template specialization, retrieves the member specialization
+ /// information.
+ MemberSpecializationInfo *getMemberSpecializationInfo();
+
+ /// \brief For a static data member that was instantiated from a static
+ /// data member of a class template, set the template specialiation kind.
+ void setTemplateSpecializationKind(TemplateSpecializationKind TSK);
+
/// isFileVarDecl - Returns true for file scoped variable declaration.
bool isFileVarDecl() const {
if (getKind() != Decl::Var)
@@ -471,16 +611,19 @@ public:
if (isa<TranslationUnitDecl>(Ctx) || isa<NamespaceDecl>(Ctx) )
return true;
}
+ if (isStaticDataMember())
+ 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;
+ bool isExternC() const;
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) {
@@ -492,12 +635,12 @@ public:
class ImplicitParamDecl : public VarDecl {
protected:
ImplicitParamDecl(Kind DK, DeclContext *DC, SourceLocation L,
- IdentifierInfo *Id, QualType Tw)
- : VarDecl(DK, DC, L, Id, Tw, VarDecl::None) {}
+ IdentifierInfo *Id, QualType Tw)
+ : VarDecl(DK, DC, L, Id, Tw, /*DInfo=*/0, VarDecl::None) {}
public:
static ImplicitParamDecl *Create(ASTContext &C, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id,
- QualType T);
+ 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; }
@@ -509,44 +652,72 @@ class ParmVarDecl : public VarDecl {
/// FIXME: Also can be paced into the bitfields in Decl.
/// in, inout, etc.
unsigned objcDeclQualifier : 6;
-
- /// Default argument, if any. [C++ Only]
- Expr *DefaultArg;
+
+ /// \brief Retrieves the fake "value" of an unparsed
+ static Expr *getUnparsedDefaultArgValue() {
+ uintptr_t Value = (uintptr_t)-1;
+ // Mask off the low bits
+ Value &= ~(uintptr_t)0x07;
+ return reinterpret_cast<Expr*> (Value);
+ }
+
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) {}
+ IdentifierInfo *Id, QualType T, DeclaratorInfo *DInfo,
+ StorageClass S, Expr *DefArg)
+ : VarDecl(DK, DC, L, Id, T, DInfo, S), objcDeclQualifier(OBJC_TQ_None) {
+ setDefaultArg(DefArg);
+ }
public:
static ParmVarDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L,IdentifierInfo *Id,
- QualType T, StorageClass S, Expr *DefArg);
-
+ QualType T, DeclaratorInfo *DInfo,
+ StorageClass S, Expr *DefArg);
+
ObjCDeclQualifier getObjCDeclQualifier() const {
return ObjCDeclQualifier(objcDeclQualifier);
}
void setObjCDeclQualifier(ObjCDeclQualifier QTVal) {
objcDeclQualifier = QTVal;
}
-
- const Expr *getDefaultArg() const {
+
+ const Expr *getDefaultArg() const {
assert(!hasUnparsedDefaultArg() && "Default argument is not yet parsed!");
- return DefaultArg;
+ assert(!hasUninstantiatedDefaultArg() &&
+ "Default argument is not yet instantiated!");
+ return getInit();
}
- Expr *getDefaultArg() {
+ Expr *getDefaultArg() {
assert(!hasUnparsedDefaultArg() && "Default argument is not yet parsed!");
- return DefaultArg;
+ assert(!hasUninstantiatedDefaultArg() &&
+ "Default argument is not yet instantiated!");
+ return getInit();
+ }
+ void setDefaultArg(Expr *defarg) {
+ Init = reinterpret_cast<Stmt *>(defarg);
+ }
+
+ /// \brief Retrieve the source range that covers the entire default
+ /// argument.
+ SourceRange getDefaultArgRange() const;
+ void setUninstantiatedDefaultArg(Expr *arg) {
+ Init = reinterpret_cast<UninstantiatedDefaultArgument *>(arg);
+ }
+ Expr *getUninstantiatedDefaultArg() {
+ return (Expr *)Init.get<UninstantiatedDefaultArgument *>();
+ }
+ const Expr *getUninstantiatedDefaultArg() const {
+ return (const Expr *)Init.get<UninstantiatedDefaultArgument *>();
}
- void setDefaultArg(Expr *defarg) { DefaultArg = defarg; }
/// hasDefaultArg - Determines whether this parameter has a default argument,
/// either parsed or not.
bool hasDefaultArg() const {
- return DefaultArg != 0;
+ return getInit() || hasUnparsedDefaultArg() ||
+ hasUninstantiatedDefaultArg();
}
-
+
/// 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
@@ -558,7 +729,11 @@ public:
/// }; // x has a regular default argument now
/// @endcode
bool hasUnparsedDefaultArg() const {
- return DefaultArg == reinterpret_cast<Expr *>(-1);
+ return Init.is<UnparsedDefaultArgument*>();
+ }
+
+ bool hasUninstantiatedDefaultArg() const {
+ return Init.is<UninstantiatedDefaultArgument*>();
}
/// setUnparsedDefaultArg - Specify that this parameter has an
@@ -566,10 +741,12 @@ public:
/// 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); }
+ void setUnparsedDefaultArg() {
+ Init = (UnparsedDefaultArgument *)0;
+ }
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
@@ -577,9 +754,9 @@ public:
void setOwningFunction(DeclContext *FD) { setDeclContext(FD); }
// Implement isa/cast/dyncast/etc.
- static bool classof(const Decl *D) {
+ static bool classof(const Decl *D) {
return (D->getKind() == ParmVar ||
- D->getKind() == OriginalParmVar);
+ D->getKind() == OriginalParmVar);
}
static bool classof(const ParmVarDecl *D) { return true; }
};
@@ -594,15 +771,17 @@ protected:
QualType OriginalType;
private:
OriginalParmVarDecl(DeclContext *DC, SourceLocation L,
- IdentifierInfo *Id, QualType T,
+ IdentifierInfo *Id, QualType T,
+ DeclaratorInfo *DInfo,
QualType OT, StorageClass S,
Expr *DefArg)
- : ParmVarDecl(OriginalParmVar, DC, L, Id, T, S, DefArg), OriginalType(OT) {}
+ : ParmVarDecl(OriginalParmVar, DC, L, Id, T, DInfo, S, DefArg),
+ OriginalType(OT) {}
public:
static OriginalParmVarDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L,IdentifierInfo *Id,
- QualType T, QualType OT,
- StorageClass S, Expr *DefArg);
+ QualType T, DeclaratorInfo *DInfo,
+ QualType OT, StorageClass S, Expr *DefArg);
void setOriginalType(QualType T) { OriginalType = T; }
@@ -610,9 +789,9 @@ public:
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.
+/// 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
@@ -621,46 +800,35 @@ public:
/// 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 {
+/// getPreviousDeclaration() chain.
+class FunctionDecl : public DeclaratorDecl, public DeclContext,
+ public Redeclarable<FunctionDecl> {
public:
enum StorageClass {
None, Extern, Static, PrivateExtern
};
-
-private:
+
+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.
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;
+ bool IsTrivial : 1; // sunk from CXXMethodDecl
+ bool IsCopyAssignment : 1; // sunk from CXXMethodDecl
+ bool HasImplicitReturnZero : 1;
- // Move to DeclGroup when it is implemented.
- SourceLocation TypeSpecStartLoc;
-
/// \brief End part of this FunctionDecl's source range.
///
/// We could compute the full range in getSourceRange(). However, when we're
@@ -672,42 +840,59 @@ private:
/// \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.
- /// For function template specializations, this will be a
+ /// of class template specializations, this will be a MemberSpecializationInfo
+ /// pointer containing information about the specialization.
+ /// For function template specializations, this will be a
/// FunctionTemplateSpecializationInfo, which contains information about
- /// the template being specialized and the template arguments involved in
+ /// the template being specialized and the template arguments involved in
/// that specialization.
- llvm::PointerUnion3<FunctionTemplateDecl*, FunctionDecl*,
- FunctionTemplateSpecializationInfo*>
+ llvm::PointerUnion3<FunctionTemplateDecl *,
+ MemberSpecializationInfo *,
+ FunctionTemplateSpecializationInfo *>
TemplateOrSpecialization;
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),
+ DeclarationName N, QualType T, DeclaratorInfo *DInfo,
+ StorageClass S, bool isInline)
+ : DeclaratorDecl(DK, DC, L, N, T, DInfo),
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),
+ ParamInfo(0), Body(),
+ SClass(S), IsInline(isInline),
+ IsVirtualAsWritten(false), IsPure(false), HasInheritedPrototype(false),
+ HasWrittenPrototype(true), IsDeleted(false), IsTrivial(false),
+ IsCopyAssignment(false),
+ HasImplicitReturnZero(false),
EndRangeLoc(L), TemplateOrSpecialization() {}
virtual ~FunctionDecl() {}
virtual void Destroy(ASTContext& C);
+ typedef Redeclarable<FunctionDecl> redeclarable_base;
+ virtual FunctionDecl *getNextRedeclaration() { return RedeclLink.getNext(); }
+
public:
+ typedef redeclarable_base::redecl_iterator redecl_iterator;
+ redecl_iterator redecls_begin() const {
+ return redeclarable_base::redecls_begin();
+ }
+ redecl_iterator redecls_end() const {
+ return redeclarable_base::redecls_end();
+ }
+
static FunctionDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L,
- DeclarationName N, QualType T,
+ DeclarationName N, QualType T,
+ DeclaratorInfo *DInfo,
StorageClass S = None, bool isInline = false,
- bool hasWrittenPrototype = true,
- SourceLocation TSStartLoc = SourceLocation());
+ bool hasWrittenPrototype = true);
+
+ virtual void getNameForDiagnostic(std::string &S,
+ const PrintingPolicy &Policy,
+ bool Qualified) const;
virtual SourceRange getSourceRange() const {
return SourceRange(getLocation(), EndRangeLoc);
@@ -715,9 +900,6 @@ public:
void setLocEnd(SourceLocation E) {
EndRangeLoc = E;
}
-
- 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
@@ -731,10 +913,6 @@ public:
return getBody(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
@@ -755,14 +933,30 @@ public:
bool isPure() const { return IsPure; }
void setPure(bool P = true) { IsPure = P; }
+ /// Whether this function is "trivial" in some specialized C++ senses.
+ /// Can only be true for default constructors, copy constructors,
+ /// copy assignment operators, and destructors. Not meaningful until
+ /// the class has been fully built by Sema.
+ bool isTrivial() const { return IsTrivial; }
+ void setTrivial(bool IT) { IsTrivial = IT; }
+
+ bool isCopyAssignment() const { return IsCopyAssignment; }
+ void setCopyAssignment(bool CA) { IsCopyAssignment = CA; }
+
+ /// Whether falling off this function implicitly returns null/zero.
+ /// If a more specific implicit return value is required, front-ends
+ /// should synthesize the appropriate return statements.
+ bool hasImplicitReturnZero() const { return HasImplicitReturnZero; }
+ void setHasImplicitReturnZero(bool IRZ) { HasImplicitReturnZero = IRZ; }
+
/// \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 hasPrototype() const {
+ return HasWrittenPrototype || HasInheritedPrototype;
}
-
+
bool hasWrittenPrototype() const { return HasWrittenPrototype; }
void setHasWrittenPrototype(bool P) { HasWrittenPrototype = P; }
@@ -798,39 +992,36 @@ public:
/// \brief Determines whether this function is a function with
/// external, C linkage.
- bool isExternC(ASTContext &Context) const;
+ bool isExternC() 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);
- unsigned getBuiltinID(ASTContext &Context) const;
+ virtual const FunctionDecl *getCanonicalDecl() const;
+ virtual FunctionDecl *getCanonicalDecl();
+
+ unsigned getBuiltinID() 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];
@@ -847,8 +1038,8 @@ public:
/// arguments (in C++).
unsigned getMinRequiredArguments() const;
- QualType getResultType() const {
- return getType()->getAsFunctionType()->getResultType();
+ QualType getResultType() const {
+ return getType()->getAs<FunctionType>()->getResultType();
}
StorageClass getStorageClass() const { return StorageClass(SClass); }
void setStorageClass(StorageClass SC) { SClass = SC; }
@@ -856,27 +1047,11 @@ public:
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(ASTContext &Context) const;
-
- /// \brief Determines whether this function is a GNU "extern
- /// inline", which is roughly the opposite of a C99 "extern inline"
- /// function.
- bool isExternGNUInline(ASTContext &Context) const;
-
+ bool isInlineDefinitionExternallyVisible() const;
+
/// isOverloadedOperator - Whether this function declaration
/// represents an C++ overloaded operator, e.g., "operator+".
- bool isOverloadedOperator() const {
+ bool isOverloadedOperator() const {
return getOverloadedOperator() != OO_None;
};
@@ -903,15 +1078,17 @@ public:
/// 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 TemplateOrSpecialization.dyn_cast<FunctionDecl*>();
- }
+ FunctionDecl *getInstantiatedFromMemberFunction() const;
+ /// \brief If this function is an instantiation of a member function of a
+ /// class template specialization, retrieves the member specialization
+ /// information.
+ MemberSpecializationInfo *getMemberSpecializationInfo() const;
+
/// \brief Specify that this record is an instantiation of the
- /// member function RD.
- void setInstantiationOfMemberFunction(FunctionDecl *RD) {
- TemplateOrSpecialization = RD;
- }
+ /// member function FD.
+ void setInstantiationOfMemberFunction(FunctionDecl *FD,
+ TemplateSpecializationKind TSK);
/// \brief Retrieves the function template that is described by this
/// function declaration.
@@ -933,20 +1110,34 @@ public:
TemplateOrSpecialization = Template;
}
+ /// \brief Determine whether this function is a function template
+ /// specialization.
+ bool isFunctionTemplateSpecialization() const {
+ return getPrimaryTemplate() != 0;
+ }
+
+ /// \brief If this function is actually a function template specialization,
+ /// retrieve information about this function template specialization.
+ /// Otherwise, returns NULL.
+ FunctionTemplateSpecializationInfo *getTemplateSpecializationInfo() const {
+ return TemplateOrSpecialization.
+ dyn_cast<FunctionTemplateSpecializationInfo*>();
+ }
+
/// \brief Retrieve the primary template that this function template
/// specialization either specializes or was instantiated from.
///
/// If this function declaration is not a function template specialization,
/// returns NULL.
FunctionTemplateDecl *getPrimaryTemplate() const;
-
+
/// \brief Retrieve the template arguments used to produce this function
/// template specialization from the primary template.
///
/// If this function declaration is not a function template specialization,
/// returns NULL.
- const TemplateArgumentList *getTemplateSpecializationArgs() const;
-
+ const TemplateArgumentList *getTemplateSpecializationArgs() const;
+
/// \brief Specify that this function declaration is actually a function
/// template specialization.
///
@@ -957,19 +1148,30 @@ public:
///
/// \param TemplateArgs the template arguments that produced this
/// function template specialization from the template.
+ ///
+ /// \param InsertPos If non-NULL, the position in the function template
+ /// specialization set where the function template specialization data will
+ /// be inserted.
+ ///
+ /// \param TSK the kind of template specialization this is.
void setFunctionTemplateSpecialization(ASTContext &Context,
FunctionTemplateDecl *Template,
const TemplateArgumentList *TemplateArgs,
- void *InsertPos);
+ void *InsertPos,
+ TemplateSpecializationKind TSK = TSK_ImplicitInstantiation);
- /// \brief Determine whether this is an explicit specialization of a
- /// function template or a member function of a class template.
- bool isExplicitSpecialization() const;
+ /// \brief Determine what kind of template instantiation this function
+ /// represents.
+ TemplateSpecializationKind getTemplateSpecializationKind() const;
- /// \brief Note that this is an explicit specialization of a function template
- /// or a member function of a class template.
- void setExplicitSpecialization(bool ES);
-
+ /// \brief Determine what kind of template instantiation this function
+ /// represents.
+ void setTemplateSpecializationKind(TemplateSpecializationKind TSK);
+
+ /// \brief Determine whether this is or was instantiated from an out-of-line
+ /// definition of a member function.
+ bool isOutOfLine() const;
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) {
return D->getKind() >= FunctionFirst && D->getKind() <= FunctionLast;
@@ -984,22 +1186,23 @@ public:
};
-/// FieldDecl - An instance of this class is created by Sema::ActOnField to
+/// FieldDecl - An instance of this class is created by Sema::ActOnField to
/// represent a member of a struct/union/class.
-class FieldDecl : public ValueDecl {
+class FieldDecl : public DeclaratorDecl {
// 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)
- { }
+ FieldDecl(Kind DK, DeclContext *DC, SourceLocation L,
+ IdentifierInfo *Id, QualType T, DeclaratorInfo *DInfo,
+ Expr *BW, bool Mutable)
+ : DeclaratorDecl(DK, DC, L, Id, T, DInfo), Mutable(Mutable), BitWidth(BW) {
+ }
public:
- static FieldDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L,
- IdentifierInfo *Id, QualType T, Expr *BW,
- bool Mutable);
+ static FieldDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L,
+ IdentifierInfo *Id, QualType T,
+ DeclaratorInfo *DInfo, Expr *BW, bool Mutable);
/// isMutable - Determines whether this field is mutable (C++ only).
bool isMutable() const { return Mutable; }
@@ -1049,7 +1252,7 @@ public:
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; }
@@ -1058,11 +1261,11 @@ public:
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;
};
@@ -1104,16 +1307,16 @@ 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)
+ 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; }
@@ -1123,16 +1326,17 @@ public:
};
class TypedefDecl;
-
+
/// TagDecl - Represents the declaration of a struct/union/class/enum.
-class TagDecl : public TypeDecl, public DeclContext {
+class TagDecl
+ : public TypeDecl, public DeclContext, public Redeclarable<TagDecl> {
public:
- enum TagKind {
- TK_struct,
- TK_union,
- TK_class,
- TK_enum
- };
+ // This is really ugly.
+ typedef ElaboratedType::TagKind TagKind;
+ static const TagKind TK_struct = ElaboratedType::TK_struct;
+ static const TagKind TK_union = ElaboratedType::TK_union;
+ static const TagKind TK_class = ElaboratedType::TK_class;
+ static const TagKind TK_enum = ElaboratedType::TK_enum;
private:
// FIXME: This can be packed into the bitfields in Decl.
@@ -1142,21 +1346,48 @@ private:
/// 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;
-
+
+ SourceLocation TagKeywordLoc;
+ SourceLocation RBraceLoc;
+
protected:
TagDecl(Kind DK, TagKind TK, DeclContext *DC, SourceLocation L,
- IdentifierInfo *Id)
- : TypeDecl(DK, DC, L, Id), DeclContext(DK), TypedefForAnonDecl(0) {
+ IdentifierInfo *Id, TagDecl *PrevDecl,
+ SourceLocation TKL = SourceLocation())
+ : TypeDecl(DK, DC, L, Id), DeclContext(DK), TypedefForAnonDecl(0),
+ TagKeywordLoc(TKL) {
assert((DK != Enum || TK == TK_enum) &&"EnumDecl not matched with TK_enum");
TagDeclKind = TK;
IsDefinition = false;
+ setPreviousDeclaration(PrevDecl);
}
+
+ typedef Redeclarable<TagDecl> redeclarable_base;
+ virtual TagDecl *getNextRedeclaration() { return RedeclLink.getNext(); }
+
public:
-
+ typedef redeclarable_base::redecl_iterator redecl_iterator;
+ redecl_iterator redecls_begin() const {
+ return redeclarable_base::redecls_begin();
+ }
+ redecl_iterator redecls_end() const {
+ return redeclarable_base::redecls_end();
+ }
+
+ SourceLocation getRBraceLoc() const { return RBraceLoc; }
+ void setRBraceLoc(SourceLocation L) { RBraceLoc = L; }
+
+ SourceLocation getTagKeywordLoc() const { return TagKeywordLoc; }
+ void setTagKeywordLoc(SourceLocation TKL) { TagKeywordLoc = TKL; }
+
+ virtual SourceRange getSourceRange() const;
+
+ virtual TagDecl* getCanonicalDecl();
+
/// isDefinition - Return true if this decl has its body specified.
bool isDefinition() const {
return IsDefinition;
@@ -1168,7 +1399,7 @@ public:
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.
@@ -1177,7 +1408,7 @@ public:
/// @brief Completes the definition of this tag declaration.
void completeDefinition();
- /// getDefinition - Returns the TagDecl that actually defines this
+ /// 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
@@ -1185,17 +1416,16 @@ public:
/// 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";
- }
+ return ElaboratedType::getNameForTagKind(getTagKind());
}
+ /// getTagKindForTypeSpec - Converts a type specifier (DeclSpec::TST)
+ /// into a tag kind. It is an error to provide a type specifier
+ /// which *isn't* a tag kind here.
+ static TagKind getTagKindForTypeSpec(unsigned TypeSpec);
+
TagKind getTagKind() const {
return TagKind(TagDeclKind);
}
@@ -1206,10 +1436,10 @@ public:
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;
@@ -1240,15 +1470,19 @@ class EnumDecl : public TagDecl {
EnumDecl *InstantiatedFrom;
EnumDecl(DeclContext *DC, SourceLocation L,
- IdentifierInfo *Id)
- : TagDecl(Enum, TK_enum, DC, L, Id), InstantiatedFrom(0) {
+ IdentifierInfo *Id, EnumDecl *PrevDecl, SourceLocation TKL)
+ : TagDecl(Enum, TK_enum, DC, L, Id, PrevDecl, TKL), InstantiatedFrom(0) {
IntegerType = QualType();
}
public:
+ EnumDecl *getCanonicalDecl() {
+ return cast<EnumDecl>(TagDecl::getCanonicalDecl());
+ }
+
static EnumDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id,
- EnumDecl *PrevDecl);
-
+ SourceLocation TKL, EnumDecl *PrevDecl);
+
virtual void Destroy(ASTContext& C);
/// completeDefinition - When created, the EnumDecl corresponds to a
@@ -1257,16 +1491,16 @@ public:
/// 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() const {
+ enumerator_iterator enumerator_begin() const {
return enumerator_iterator(this->decls_begin());
}
- enumerator_iterator enumerator_end() const {
+ enumerator_iterator enumerator_end() const {
return enumerator_iterator(this->decls_end());
}
@@ -1307,18 +1541,24 @@ class RecordDecl : public TagDecl {
/// anonymous struct or union.
bool AnonymousStructOrUnion : 1;
+ /// HasObjectMember - This is true if this struct has at least one
+ /// member containing an object
+ bool HasObjectMember : 1;
+
protected:
RecordDecl(Kind DK, TagKind TK, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id);
+ SourceLocation L, IdentifierInfo *Id,
+ RecordDecl *PrevDecl, SourceLocation TKL);
virtual ~RecordDecl();
public:
static RecordDecl *Create(ASTContext &C, TagKind TK, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id,
+ SourceLocation TKL = SourceLocation(),
RecordDecl* PrevDecl = 0);
virtual void Destroy(ASTContext& C);
-
+
bool hasFlexibleArrayMember() const { return HasFlexibleArrayMember; }
void setHasFlexibleArrayMember(bool V) { HasFlexibleArrayMember = V; }
@@ -1328,7 +1568,7 @@ public:
/// type declared, e.g.,
/// @code
/// union { int i; float f; };
- /// @endcode
+ /// @endcode
/// is an anonymous union but neither of the following are:
/// @code
/// union X { int i; float f; };
@@ -1339,6 +1579,9 @@ public:
AnonymousStructOrUnion = Anon;
}
+ bool hasObjectMember() const { return HasObjectMember; }
+ void setHasObjectMember (bool val) { HasObjectMember = val; }
+
/// \brief Determines whether this declaration represents the
/// injected class name.
///
@@ -1354,7 +1597,7 @@ public:
/// \endcode
bool isInjectedClassName() const;
- /// getDefinition - Returns the RecordDecl that actually defines this
+ /// 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
@@ -1364,7 +1607,7 @@ public:
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.
@@ -1379,7 +1622,7 @@ public:
// field_empty - Whether there are any fields (non-static data
// members) in this record.
- bool field_empty() const {
+ bool field_empty() const {
return field_begin() == field_end();
}
@@ -1408,7 +1651,7 @@ public:
static bool classof(const Decl *D) {
return D->getKind() == FileScopeAsm;
}
- static bool classof(const FileScopeAsmDecl *D) { return true; }
+ static bool classof(const FileScopeAsmDecl *D) { return true; }
};
/// BlockDecl - This represents a block literal declaration, which is like an
@@ -1423,12 +1666,12 @@ class BlockDecl : public Decl, public DeclContext {
/// no formals.
ParmVarDecl **ParamInfo;
unsigned NumParams;
-
+
Stmt *Body;
-
+
protected:
BlockDecl(DeclContext *DC, SourceLocation CaretLoc)
- : Decl(Block, DC, CaretLoc), DeclContext(Block),
+ : Decl(Block, DC, CaretLoc), DeclContext(Block),
isVariadic(false), ParamInfo(0), NumParams(0), Body(0) {}
virtual ~BlockDecl();
@@ -1441,7 +1684,7 @@ public:
bool IsVariadic() const { return isVariadic; }
void setIsVariadic(bool value) { isVariadic = value; }
-
+
CompoundStmt *getCompoundBody() const { return (CompoundStmt*) Body; }
Stmt *getBody() const { return (Stmt*) Body; }
void setBody(CompoundStmt *B) { Body = (Stmt*) B; }
@@ -1450,14 +1693,14 @@ public:
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 #");
@@ -1468,10 +1711,10 @@ public:
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 bool classof(const BlockDecl *D) { return true; }
static DeclContext *castToDeclContext(const BlockDecl *D) {
return static_cast<DeclContext *>(const_cast<BlockDecl*>(D));
}
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h
index 0bce2f8..9e88871 100644
--- a/include/clang/AST/DeclBase.h
+++ b/include/clang/AST/DeclBase.h
@@ -37,6 +37,7 @@ class ObjCCategoryDecl;
class ObjCProtocolDecl;
class ObjCImplementationDecl;
class ObjCCategoryImplDecl;
+class ObjCImplDecl;
class LinkageSpecDecl;
class BlockDecl;
class DeclarationName;
@@ -59,8 +60,8 @@ public:
namespace clang {
-/// Decl - This represents one declaration (or definition), e.g. a variable,
-/// typedef, function, struct, etc.
+/// Decl - This represents one declaration (or definition), e.g. a variable,
+/// typedef, function, struct, etc.
///
class Decl {
public:
@@ -68,7 +69,7 @@ public:
enum Kind {
#define DECL(Derived, Base) Derived,
#define DECL_RANGE(CommonBase, Start, End) \
- CommonBase##First = Start, CommonBase##Last = 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"
@@ -78,7 +79,9 @@ public:
/// 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.
+ /// use additional namespaces for Objective-C entities. We also
+ /// put C++ friend declarations (of previously-undeclared entities) in
+ /// shadow namespaces.
enum IdentifierNamespace {
IDNS_Label = 0x1,
IDNS_Tag = 0x2,
@@ -86,9 +89,11 @@ public:
IDNS_Ordinary = 0x8,
IDNS_ObjCProtocol = 0x10,
IDNS_ObjCImplementation = 0x20,
- IDNS_ObjCCategoryImpl = 0x40
+ IDNS_ObjCCategoryImpl = 0x40,
+ IDNS_OrdinaryFriend = 0x80,
+ IDNS_TagFriend = 0x100
};
-
+
/// 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).
@@ -101,7 +106,7 @@ public:
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
@@ -114,8 +119,8 @@ private:
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.
@@ -139,16 +144,16 @@ private:
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;
@@ -162,23 +167,23 @@ private:
protected:
/// IdentifierNamespace - This specifies what IDNS_* namespace this lives in.
- unsigned IdentifierNamespace : 8;
-
+ unsigned IdentifierNamespace : 16;
+
private:
#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),
+ Decl(Kind DK, DeclContext *DC, SourceLocation L)
+ : NextDeclInContext(0), DeclCtx(DC),
Loc(L), DeclKind(DK), InvalidDecl(0),
HasAttrs(false), Implicit(false), Used(false),
IdentifierNamespace(getIdentifierNamespaceForKind(DK)), Access(AS_none) {
@@ -201,7 +206,7 @@ public:
Kind getKind() const { return DeclKind; }
const char *getDeclKindName() const;
-
+
Decl *getNextDeclInContext() { return NextDeclInContext; }
const Decl *getNextDeclInContext() const { return NextDeclInContext; }
@@ -219,16 +224,18 @@ public:
return const_cast<Decl*>(this)->getTranslationUnitDecl();
}
+ bool isInAnonymousNamespace() const;
+
ASTContext &getASTContext() const;
-
+
void setAccess(AccessSpecifier AS) {
- Access = AS;
+ Access = AS;
CheckAccessDeclContext();
}
-
- AccessSpecifier getAccess() const {
+
+ AccessSpecifier getAccess() const {
CheckAccessDeclContext();
- return AccessSpecifier(Access);
+ return AccessSpecifier(Access);
}
bool hasAttrs() const { return HasAttrs; }
@@ -246,11 +253,11 @@ public:
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; }
@@ -261,12 +268,12 @@ public:
/// was written explicitly in the source code.
bool isImplicit() const { return Implicit; }
void setImplicit(bool I = true) { Implicit = I; }
-
+
/// \brief Whether this declaration was used, meaning that a definition
/// is required.
bool isUsed() const { return Used; }
void setUsed(bool U = true) { Used = U; }
-
+
unsigned getIdentifierNamespace() const {
return IdentifierNamespace;
}
@@ -275,7 +282,7 @@ public:
}
static unsigned getIdentifierNamespaceForKind(Kind DK);
-
+
/// getLexicalDeclContext - The declaration context where this Decl was
/// lexically declared (LexicalDC). May be different from
/// getDeclContext() (SemanticDC).
@@ -298,7 +305,7 @@ public:
bool isOutOfLine() const {
return getLexicalDeclContext() != getDeclContext();
}
-
+
/// setDeclContext - Set both the semantic and lexical DeclContext
/// to DC.
void setDeclContext(DeclContext *DC);
@@ -311,6 +318,72 @@ public:
// be defined inside or outside a function etc).
bool isDefinedOutsideFunctionOrMethod() const;
+ /// \brief Retrieves the "canonical" declaration of the given declaration.
+ virtual Decl *getCanonicalDecl() { return this; }
+ const Decl *getCanonicalDecl() const {
+ return const_cast<Decl*>(this)->getCanonicalDecl();
+ }
+
+ /// \brief Whether this particular Decl is a canonical one.
+ bool isCanonicalDecl() const { return getCanonicalDecl() == this; }
+
+protected:
+ /// \brief Returns the next redeclaration or itself if this is the only decl.
+ ///
+ /// Decl subclasses that can be redeclared should override this method so that
+ /// Decl::redecl_iterator can iterate over them.
+ virtual Decl *getNextRedeclaration() { return this; }
+
+public:
+ /// \brief Iterates through all the redeclarations of the same decl.
+ class redecl_iterator {
+ /// Current - The current declaration.
+ Decl *Current;
+ Decl *Starter;
+
+ public:
+ typedef Decl* value_type;
+ typedef Decl* reference;
+ typedef Decl* pointer;
+ typedef std::forward_iterator_tag iterator_category;
+ typedef std::ptrdiff_t difference_type;
+
+ redecl_iterator() : Current(0) { }
+ explicit redecl_iterator(Decl *C) : Current(C), Starter(C) { }
+
+ reference operator*() const { return Current; }
+ pointer operator->() const { return Current; }
+
+ redecl_iterator& operator++() {
+ assert(Current && "Advancing while iterator has reached end");
+ // Get either previous decl or latest decl.
+ Decl *Next = Current->getNextRedeclaration();
+ assert(Next && "Should return next redeclaration or itself, never null!");
+ Current = (Next != Starter ? Next : 0);
+ return *this;
+ }
+
+ redecl_iterator operator++(int) {
+ redecl_iterator tmp(*this);
+ ++(*this);
+ return tmp;
+ }
+
+ friend bool operator==(redecl_iterator x, redecl_iterator y) {
+ return x.Current == y.Current;
+ }
+ friend bool operator!=(redecl_iterator x, redecl_iterator y) {
+ return x.Current != y.Current;
+ }
+ };
+
+ /// \brief Returns iterator for all the redeclarations of the same decl.
+ /// It will iterate at least once (when this decl is the only one).
+ redecl_iterator redecls_begin() const {
+ return redecl_iterator(const_cast<Decl*>(this));
+ }
+ redecl_iterator redecls_end() const { return redecl_iterator(); }
+
/// 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.
@@ -327,33 +400,71 @@ public:
static void addDeclKind(Kind k);
static bool CollectingStats(bool Enable = false);
static void PrintStats();
-
+
/// isTemplateParameter - Determines whether this declaration is a
/// template parameter.
bool isTemplateParameter() const;
-
+
/// isTemplateParameter - Determines whether this declaration is a
/// template parameter pack.
bool isTemplateParameterPack() const;
/// \brief Whether this declaration is a function or function template.
bool isFunctionOrFunctionTemplate() const;
-
+
+ /// \brief Changes the namespace of this declaration to reflect that it's
+ /// the object of a friend declaration.
+ ///
+ /// These declarations appear in the lexical context of the friending
+ /// class, but in the semantic context of the actual entity. This property
+ /// applies only to a specific decl object; other redeclarations of the
+ /// same entity may not (and probably don't) share this property.
+ void setObjectOfFriendDecl(bool PreviouslyDeclared) {
+ unsigned OldNS = IdentifierNamespace;
+ assert((OldNS == IDNS_Tag || OldNS == IDNS_Ordinary ||
+ OldNS == (IDNS_Tag | IDNS_Ordinary))
+ && "unsupported namespace for undeclared friend");
+ if (!PreviouslyDeclared) IdentifierNamespace = 0;
+
+ if (OldNS == IDNS_Tag)
+ IdentifierNamespace |= IDNS_TagFriend;
+ else
+ IdentifierNamespace |= IDNS_OrdinaryFriend;
+ }
+
+ enum FriendObjectKind {
+ FOK_None, // not a friend object
+ FOK_Declared, // a friend of a previously-declared entity
+ FOK_Undeclared // a friend of a previously-undeclared entity
+ };
+
+ /// \brief Determines whether this declaration is the object of a
+ /// friend declaration and, if so, what kind.
+ ///
+ /// There is currently no direct way to find the associated FriendDecl.
+ FriendObjectKind getFriendObjectKind() const {
+ unsigned mask
+ = (IdentifierNamespace & (IDNS_TagFriend | IDNS_OrdinaryFriend));
+ if (!mask) return FOK_None;
+ return (IdentifierNamespace & (IDNS_Tag | IDNS_Ordinary) ?
+ FOK_Declared : FOK_Undeclared);
+ }
+
// 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, unsigned Indentation = 0);
+ void print(llvm::raw_ostream &Out, unsigned Indentation = 0) const;
void print(llvm::raw_ostream &Out, const PrintingPolicy &Policy,
- unsigned Indentation = 0);
+ unsigned Indentation = 0) const;
static void printGroup(Decl** Begin, unsigned NumDecls,
llvm::raw_ostream &Out, const PrintingPolicy &Policy,
unsigned Indentation = 0);
- void dump();
+ void dump() const;
private:
const Attr *getAttrsImpl() const;
@@ -371,10 +482,10 @@ 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
@@ -386,8 +497,6 @@ public:
/// TagDecl
/// ObjCMethodDecl
/// ObjCContainerDecl
-/// ObjCCategoryImplDecl
-/// ObjCImplementationDecl
/// LinkageSpecDecl
/// BlockDecl
///
@@ -421,9 +530,9 @@ class DeclContext {
mutable Decl *LastDecl;
protected:
- DeclContext(Decl::Kind K)
+ DeclContext(Decl::Kind K)
: DeclKind(K), ExternalLexicalStorage(false),
- ExternalVisibleStorage(false), LookupPtr(0), FirstDecl(0),
+ ExternalVisibleStorage(false), LookupPtr(0), FirstDecl(0),
LastDecl(0) { }
void DestroyDecls(ASTContext &C);
@@ -443,7 +552,7 @@ public:
const DeclContext *getParent() const {
return const_cast<DeclContext*>(this)->getParent();
}
-
+
/// getLexicalParent - Returns the containing lexical DeclContext. May be
/// different from getParent, e.g.:
///
@@ -458,8 +567,14 @@ public:
}
const DeclContext *getLexicalParent() const {
return const_cast<DeclContext*>(this)->getLexicalParent();
- }
+ }
+ DeclContext *getLookupParent();
+
+ const DeclContext *getLookupParent() const {
+ return const_cast<DeclContext*>(this)->getLookupParent();
+ }
+
ASTContext &getParentASTContext() const {
return cast<Decl>(this)->getASTContext();
}
@@ -499,10 +614,10 @@ public:
/// 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:
+ /// enumeration type:
/// @code
/// enum E {
- /// Val1
+ /// Val1
/// };
/// @endcode
/// Here, E is a transparent context, so its enumerator (Val1) will
@@ -512,13 +627,16 @@ public:
/// inline namespaces.
bool isTransparentContext() const;
- bool Encloses(DeclContext *DC) const {
- for (; DC; DC = DC->getParent())
- if (DC == this)
- return true;
- return false;
+ /// \brief Determine whether this declaration context is equivalent
+ /// to the declaration context DC.
+ bool Equals(DeclContext *DC) {
+ return this->getPrimaryContext() == DC->getPrimaryContext();
}
+ /// \brief Determine whether this declaration context encloses the
+ /// declaration context DC.
+ bool Encloses(DeclContext *DC);
+
/// getPrimaryContext - There may be many different
/// declarations of the same entity (including forward declarations
/// of classes, multiple definitions of namespaces, etc.), each with
@@ -535,7 +653,7 @@ public:
const DeclContext *getLookupContext() const {
return const_cast<DeclContext *>(this)->getLookupContext();
}
-
+
/// \brief Retrieve the nearest enclosing namespace context.
DeclContext *getEnclosingNamespaceContext();
const DeclContext *getEnclosingNamespaceContext() const {
@@ -591,16 +709,16 @@ public:
return tmp;
}
- friend bool operator==(decl_iterator x, decl_iterator y) {
+ friend bool operator==(decl_iterator x, decl_iterator y) {
return x.Current == y.Current;
}
- friend bool operator!=(decl_iterator x, decl_iterator y) {
+ 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.
+ /// this context.
decl_iterator decls_begin() const;
decl_iterator decls_end() const;
bool decls_empty() const;
@@ -616,7 +734,7 @@ public:
/// 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.
@@ -661,13 +779,13 @@ public:
++(*this);
return tmp;
}
-
+
friend bool
operator==(const specific_decl_iterator& x, const specific_decl_iterator& y) {
return x.Current == y.Current;
}
-
- friend bool
+
+ friend bool
operator!=(const specific_decl_iterator& x, const specific_decl_iterator& y) {
return x.Current != y.Current;
}
@@ -688,7 +806,7 @@ public:
/// 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.
@@ -735,13 +853,13 @@ public:
++(*this);
return tmp;
}
-
+
friend bool
operator==(const filtered_decl_iterator& x, const filtered_decl_iterator& y) {
return x.Current == y.Current;
}
-
- friend bool
+
+ friend bool
operator!=(const filtered_decl_iterator& x, const filtered_decl_iterator& y) {
return x.Current != y.Current;
}
@@ -761,6 +879,14 @@ public:
/// semantic context via makeDeclVisibleInContext.
void addDecl(Decl *D);
+ /// @brief Add the declaration D to this context without modifying
+ /// any lookup tables.
+ ///
+ /// This is useful for some operations in dependent contexts where
+ /// the semantic context might not be dependent; this basically
+ /// only happens with friends.
+ void addHiddenDecl(Decl *D);
+
/// lookup_iterator - An iterator that provides access to the results
/// of looking up a name within this context.
typedef NamedDecl **lookup_iterator;
@@ -795,12 +921,16 @@ public:
/// visible from this context, as determined by
/// NamedDecl::declarationReplaces, the previous declaration will be
/// replaced with D.
- void makeDeclVisibleInContext(NamedDecl *D);
+ ///
+ /// @param Recoverable true if it's okay to not add this decl to
+ /// the lookup tables because it can be easily recovered by walking
+ /// the declaration chains.
+ void makeDeclVisibleInContext(NamedDecl *D, bool Recoverable = true);
/// 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() const;
@@ -824,8 +954,8 @@ public:
/// \brief State whether this DeclContext has external storage for
/// declarations lexically in this context.
- void setHasExternalLexicalStorage(bool ES = true) {
- ExternalLexicalStorage = ES;
+ void setHasExternalLexicalStorage(bool ES = true) {
+ ExternalLexicalStorage = ES;
}
/// \brief Whether this DeclContext has external storage containing
@@ -834,8 +964,8 @@ public:
/// \brief State whether this DeclContext has external storage for
/// declarations visible in this context.
- void setHasExternalVisibleStorage(bool ES = true) {
- ExternalVisibleStorage = ES;
+ void setHasExternalVisibleStorage(bool ES = true) {
+ ExternalVisibleStorage = ES;
}
static bool classof(const Decl *D);
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index c523e96..c858c5c 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -14,46 +14,51 @@
#ifndef LLVM_CLANG_AST_DECLCXX_H
#define LLVM_CLANG_AST_DECLCXX_H
+#include "clang/AST/Expr.h"
#include "clang/AST/Decl.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/SmallPtrSet.h"
namespace clang {
class ClassTemplateDecl;
-class CXXRecordDecl;
+class ClassTemplateSpecializationDecl;
+class CXXBasePath;
+class CXXBasePaths;
class CXXConstructorDecl;
-class CXXDestructorDecl;
class CXXConversionDecl;
+class CXXDestructorDecl;
class CXXMethodDecl;
-class ClassTemplateSpecializationDecl;
-
-/// \brief Represents any kind of function declaration, whether it is a
+class CXXRecordDecl;
+class CXXMemberLookupCriteria;
+
+/// \brief Represents any kind of function declaration, whether it is a
/// concrete function or a function template.
class AnyFunctionDecl {
NamedDecl *Function;
-
+
AnyFunctionDecl(NamedDecl *ND) : Function(ND) { }
-
+
public:
AnyFunctionDecl(FunctionDecl *FD) : Function(FD) { }
AnyFunctionDecl(FunctionTemplateDecl *FTD);
-
- /// \brief Implicily converts any function or function template into a
+
+ /// \brief Implicily converts any function or function template into a
/// named declaration.
operator NamedDecl *() const { return Function; }
-
+
/// \brief Retrieve the underlying function or function template.
NamedDecl *get() const { return Function; }
-
- static AnyFunctionDecl getFromNamedDecl(NamedDecl *ND) {
+
+ static AnyFunctionDecl getFromNamedDecl(NamedDecl *ND) {
return AnyFunctionDecl(ND);
}
};
-
+
} // end namespace clang
namespace llvm {
- /// Implement simplify_type for AnyFunctionDecl, so that we can dyn_cast from
+ /// Implement simplify_type for AnyFunctionDecl, so that we can dyn_cast from
/// AnyFunctionDecl to any function or function template declaration.
template<> struct simplify_type<const ::clang::AnyFunctionDecl> {
typedef ::clang::NamedDecl* SimpleType;
@@ -63,26 +68,26 @@ namespace llvm {
};
template<> struct simplify_type< ::clang::AnyFunctionDecl>
: public simplify_type<const ::clang::AnyFunctionDecl> {};
-
+
// Provide PointerLikeTypeTraits for non-cvr pointers.
template<>
class PointerLikeTypeTraits< ::clang::AnyFunctionDecl> {
public:
static inline void *getAsVoidPointer(::clang::AnyFunctionDecl F) {
- return F.get();
+ return F.get();
}
static inline ::clang::AnyFunctionDecl getFromVoidPointer(void *P) {
return ::clang::AnyFunctionDecl::getFromNamedDecl(
static_cast< ::clang::NamedDecl*>(P));
}
-
+
enum { NumLowBitsAvailable = 2 };
};
-
+
} // end namespace llvm
namespace clang {
-
+
/// 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.
@@ -127,12 +132,64 @@ public:
unsigned size() const { return Functions.size(); }
// Implement isa/cast/dyncast/etc.
- static bool classof(const Decl *D) {
- return D->getKind() == OverloadedFunction;
+ static bool classof(const Decl *D) {
+ return D->getKind() == OverloadedFunction;
}
static bool classof(const OverloadedFunctionDecl *D) { return true; }
};
+/// \brief Provides uniform iteration syntax for an overload set, function,
+/// or function template.
+class OverloadIterator {
+ /// \brief An overloaded function set, function declaration, or
+ /// function template declaration.
+ NamedDecl *D;
+
+ /// \brief If the declaration is an overloaded function set, this is the
+ /// iterator pointing to the current position within that overloaded
+ /// function set.
+ OverloadedFunctionDecl::function_iterator Iter;
+
+public:
+ typedef AnyFunctionDecl value_type;
+ typedef value_type reference;
+ typedef NamedDecl *pointer;
+ typedef int difference_type;
+ typedef std::forward_iterator_tag iterator_category;
+
+ OverloadIterator() : D(0) { }
+
+ OverloadIterator(FunctionDecl *FD) : D(FD) { }
+ OverloadIterator(FunctionTemplateDecl *FTD)
+ : D(reinterpret_cast<NamedDecl*>(FTD)) { }
+ OverloadIterator(OverloadedFunctionDecl *Ovl)
+ : D(Ovl), Iter(Ovl->function_begin()) { }
+
+ OverloadIterator(NamedDecl *ND);
+
+ reference operator*() const;
+
+ pointer operator->() const { return (**this).get(); }
+
+ OverloadIterator &operator++();
+
+ OverloadIterator operator++(int) {
+ OverloadIterator Temp(*this);
+ ++(*this);
+ return Temp;
+ }
+
+ bool Equals(const OverloadIterator &Other) const;
+};
+
+inline bool operator==(const OverloadIterator &X, const OverloadIterator &Y) {
+ return X.Equals(Y);
+}
+
+inline bool operator!=(const OverloadIterator &X, const OverloadIterator &Y) {
+ return !(X == Y);
+}
+
/// CXXBaseSpecifier - A base class of a C++ class.
///
/// Each CXXBaseSpecifier represents a single, direct base class (or
@@ -162,7 +219,7 @@ class CXXBaseSpecifier {
/// 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;
+ 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
@@ -173,7 +230,7 @@ class CXXBaseSpecifier {
/// BaseType - The type of the base class. This will be a class or
/// struct (or a typedef of such).
QualType BaseType;
-
+
public:
CXXBaseSpecifier() { }
@@ -183,7 +240,7 @@ public:
/// 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; }
@@ -193,11 +250,11 @@ public:
/// 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 {
+ AccessSpecifier getAccessSpecifier() const {
if ((AccessSpecifier)Access == AS_none)
return BaseOfClass? AS_private : AS_public;
else
- return (AccessSpecifier)Access;
+ return (AccessSpecifier)Access;
}
/// getAccessSpecifierAsWritten - Retrieves the access specifier as
@@ -218,7 +275,7 @@ public:
/// to deal with C++-specific things.
class CXXRecordDecl : public RecordDecl {
/// UserDeclaredConstructor - True when this class has a
- /// user-declared constructor.
+ /// user-declared constructor.
bool UserDeclaredConstructor : 1;
/// UserDeclaredCopyConstructor - True when this class has a
@@ -239,6 +296,12 @@ class CXXRecordDecl : public RecordDecl {
/// PlainOldData - True when this class is a POD-type.
bool PlainOldData : 1;
+ /// Empty - true when this class is empty for traits purposes, i.e. has no
+ /// data members other than 0-width bit-fields, has no virtual function/base,
+ /// and doesn't inherit from a non-empty class. Doesn't take union-ness into
+ /// account.
+ bool Empty : 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;
@@ -246,12 +309,55 @@ class CXXRecordDecl : public RecordDecl {
/// 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
+
+ /// HasTrivialConstructor - True when this class has a trivial constructor.
+ ///
+ /// C++ [class.ctor]p5. A constructor is trivial if it is an
+ /// implicitly-declared default constructor and if:
+ /// * its class has no virtual functions and no virtual base classes, and
+ /// * all the direct base classes of its class have trivial constructors, and
+ /// * for all the nonstatic data members of its class that are of class type
+ /// (or array thereof), each such class has a trivial constructor.
bool HasTrivialConstructor : 1;
-
- /// HasTrivialDestructor - True when this class has a trivial destructor
+
+ /// HasTrivialCopyConstructor - True when this class has a trivial copy
+ /// constructor.
+ ///
+ /// C++ [class.copy]p6. A copy constructor for class X is trivial
+ /// if it is implicitly declared and if
+ /// * class X has no virtual functions and no virtual base classes, and
+ /// * each direct base class of X has a trivial copy constructor, and
+ /// * for all the nonstatic data members of X that are of class type (or
+ /// array thereof), each such class type has a trivial copy constructor;
+ /// otherwise the copy constructor is non-trivial.
+ bool HasTrivialCopyConstructor : 1;
+
+ /// HasTrivialCopyAssignment - True when this class has a trivial copy
+ /// assignment operator.
+ ///
+ /// C++ [class.copy]p11. A copy assignment operator for class X is
+ /// trivial if it is implicitly declared and if
+ /// * class X has no virtual functions and no virtual base classes, and
+ /// * each direct base class of X has a trivial copy assignment operator, and
+ /// * for all the nonstatic data members of X that are of class type (or
+ /// array thereof), each such class type has a trivial copy assignment
+ /// operator;
+ /// otherwise the copy assignment operator is non-trivial.
+ bool HasTrivialCopyAssignment : 1;
+
+ /// HasTrivialDestructor - True when this class has a trivial destructor.
+ ///
+ /// C++ [class.dtor]p3. A destructor is trivial if it is an
+ /// implicitly-declared destructor and if:
+ /// * all of the direct base classes of its class have trivial destructors
+ /// and
+ /// * for all of the non-static data members of its class that are of class
+ /// type (or array thereof), each such class has a trivial destructor.
bool HasTrivialDestructor : 1;
+
+ /// ComputedVisibleConversions - True when visible conversion functions are
+ /// already computed and are available.
+ bool ComputedVisibleConversions : 1;
/// Bases - Base classes of this class.
/// FIXME: This is wasted space for a union.
@@ -260,45 +366,85 @@ class CXXRecordDecl : public RecordDecl {
/// NumBases - The number of base class specifiers in Bases.
unsigned NumBases;
+ /// VBases - direct and indirect virtual base classes of this class.
+ CXXBaseSpecifier *VBases;
+
+ /// NumVBases - The number of virtual base class specifiers in VBases.
+ unsigned NumVBases;
+
/// 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.
+ /// CXXConversionDecl.
OverloadedFunctionDecl Conversions;
+ /// VisibleConversions - Overload set containing the conversion functions
+ /// of this C++ class and all those inherited conversion functions that
+ /// are visible in this class. Each of the entries in this overload set is
+ /// a CXXConversionDecl or a FunctionTemplateDecl.
+ OverloadedFunctionDecl VisibleConversions;
+
/// \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*>
+ /// MemberSpecializationInfo referring to the member class that was
+ /// instantiated or specialized.
+ llvm::PointerUnion<ClassTemplateDecl*, MemberSpecializationInfo*>
TemplateOrInstantiation;
-
+
+ void getNestedVisibleConversionFunctions(CXXRecordDecl *RD,
+ const llvm::SmallPtrSet<CanQualType, 8> &TopConversionsTypeSet,
+ const llvm::SmallPtrSet<CanQualType, 8> &HiddenConversionTypes);
+ void collectConversionFunctions(
+ llvm::SmallPtrSet<CanQualType, 8>& ConversionsTypeSet);
+
protected:
CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id);
+ SourceLocation L, IdentifierInfo *Id,
+ CXXRecordDecl *PrevDecl,
+ SourceLocation TKL = SourceLocation());
~CXXRecordDecl();
public:
/// base_class_iterator - Iterator that traverses the base classes
- /// of a clas.
+ /// of a class.
typedef CXXBaseSpecifier* base_class_iterator;
/// base_class_const_iterator - Iterator that traverses the base
- /// classes of a clas.
+ /// classes of a class.
typedef const CXXBaseSpecifier* base_class_const_iterator;
+ /// reverse_base_class_iterator = Iterator that traverses the base classes
+ /// of a class in reverse order.
+ typedef std::reverse_iterator<base_class_iterator>
+ reverse_base_class_iterator;
+
+ /// reverse_base_class_iterator = Iterator that traverses the base classes
+ /// of a class in reverse order.
+ typedef std::reverse_iterator<base_class_const_iterator>
+ reverse_base_class_const_iterator;
+
+ virtual CXXRecordDecl *getCanonicalDecl() {
+ return cast<CXXRecordDecl>(RecordDecl::getCanonicalDecl());
+ }
+
static CXXRecordDecl *Create(ASTContext &C, TagKind TK, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id,
+ SourceLocation TKL = SourceLocation(),
CXXRecordDecl* PrevDecl=0,
bool DelayTypeCreation = false);
-
+
virtual void Destroy(ASTContext& C);
-
+
+ bool isDynamicClass() const {
+ return Polymorphic || NumVBases != 0;
+ }
+
/// setBases - Sets the base classes of this struct or class.
void setBases(ASTContext &C,
CXXBaseSpecifier const * const *Bases, unsigned NumBases);
@@ -311,18 +457,78 @@ public:
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; }
+ reverse_base_class_iterator bases_rbegin() {
+ return reverse_base_class_iterator(bases_end());
+ }
+ reverse_base_class_const_iterator bases_rbegin() const {
+ return reverse_base_class_const_iterator(bases_end());
+ }
+ reverse_base_class_iterator bases_rend() {
+ return reverse_base_class_iterator(bases_begin());
+ }
+ reverse_base_class_const_iterator bases_rend() const {
+ return reverse_base_class_const_iterator(bases_begin());
+ }
+
+ /// getNumVBases - Retrieves the number of virtual base classes of this
+ /// class.
+ unsigned getNumVBases() const { return NumVBases; }
+
+ base_class_iterator vbases_begin() { return VBases; }
+ base_class_const_iterator vbases_begin() const { return VBases; }
+ base_class_iterator vbases_end() { return VBases + NumVBases; }
+ base_class_const_iterator vbases_end() const { return VBases + NumVBases; }
+ reverse_base_class_iterator vbases_rbegin() {
+ return reverse_base_class_iterator(vbases_end());
+ }
+ reverse_base_class_const_iterator vbases_rbegin() const {
+ return reverse_base_class_const_iterator(vbases_end());
+ }
+ reverse_base_class_iterator vbases_rend() {
+ return reverse_base_class_iterator(vbases_begin());
+ }
+ reverse_base_class_const_iterator vbases_rend() const {
+ return reverse_base_class_const_iterator(vbases_begin());
+ }
+
+ /// Iterator access to method members. The method iterator visits
+ /// all method members of the class, including non-instance methods,
+ /// special methods, etc.
+ typedef specific_decl_iterator<CXXMethodDecl> method_iterator;
+
+ /// method_begin - Method begin iterator. Iterates in the order the methods
+ /// were declared.
+ method_iterator method_begin() const {
+ return method_iterator(decls_begin());
+ }
+ /// method_end - Method end iterator.
+ method_iterator method_end() const {
+ return method_iterator(decls_end());
+ }
+
+ /// Iterator access to constructor members.
+ typedef specific_decl_iterator<CXXConstructorDecl> ctor_iterator;
+
+ ctor_iterator ctor_begin() const {
+ return ctor_iterator(decls_begin());
+ }
+ ctor_iterator ctor_end() const {
+ return ctor_iterator(decls_end());
+ }
/// hasConstCopyConstructor - Determines whether this class has a
/// copy constructor that accepts a const-qualified argument.
bool hasConstCopyConstructor(ASTContext &Context) const;
/// getCopyConstructor - Returns the copy constructor for this class
- CXXConstructorDecl *getCopyConstructor(ASTContext &Context,
+ CXXConstructorDecl *getCopyConstructor(ASTContext &Context,
unsigned TypeQuals) const;
/// hasConstCopyAssignment - Determines whether this class has a
/// copy assignment operator that accepts a const-qualified argument.
- bool hasConstCopyAssignment(ASTContext &Context) const;
+ /// It returns its decl in MD if found.
+ bool hasConstCopyAssignment(ASTContext &Context,
+ const CXXMethodDecl *&MD) const;
/// addedConstructor - Notify the class that another constructor has
/// been added. This routine helps maintain information about the
@@ -332,7 +538,12 @@ public:
/// hasUserDeclaredConstructor - Whether this class has any
/// user-declared constructors. When true, a default constructor
/// will not be implicitly declared.
- bool hasUserDeclaredConstructor() const { return UserDeclaredConstructor; }
+ bool hasUserDeclaredConstructor() const {
+ assert((isDefinition() ||
+ cast<RecordType>(getTypeForDecl())->isBeingDefined()) &&
+ "Incomplete record decl!");
+ return UserDeclaredConstructor;
+ }
/// hasUserDeclaredCopyConstructor - Whether this class has a
/// user-declared copy constructor. When false, a copy constructor
@@ -361,22 +572,43 @@ public:
/// 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;
+ void setUserDeclaredDestructor(bool UCD) {
+ UserDeclaredDestructor = UCD;
}
/// getConversions - Retrieve the overload set containing all of the
/// conversion functions in this class.
- OverloadedFunctionDecl *getConversionFunctions() {
- return &Conversions;
+ OverloadedFunctionDecl *getConversionFunctions() {
+ assert((this->isDefinition() ||
+ cast<RecordType>(getTypeForDecl())->isBeingDefined()) &&
+ "getConversionFunctions() called on incomplete type");
+ return &Conversions;
}
- const OverloadedFunctionDecl *getConversionFunctions() const {
- return &Conversions;
+ const OverloadedFunctionDecl *getConversionFunctions() const {
+ assert((this->isDefinition() ||
+ cast<RecordType>(getTypeForDecl())->isBeingDefined()) &&
+ "getConversionFunctions() called on incomplete type");
+ return &Conversions;
}
+ /// getVisibleConversionFunctions - get all conversion functions visible
+ /// in current class; including conversion function templates.
+ OverloadedFunctionDecl *getVisibleConversionFunctions();
+ /// addVisibleConversionFunction - Add a new conversion function to the
+ /// list of visible conversion functions.
+ void addVisibleConversionFunction(CXXConversionDecl *ConvDecl);
+
+ /// \brief Add a new conversion function template to the list of visible
+ /// conversion functions.
+ void addVisibleConversionFunction(FunctionTemplateDecl *ConvDecl);
+
/// addConversionFunction - Add a new conversion function to the
/// list of conversion functions.
- void addConversionFunction(ASTContext &Context, CXXConversionDecl *ConvDecl);
+ void addConversionFunction(CXXConversionDecl *ConvDecl);
+
+ /// \brief Add a new conversion function template to the list of conversion
+ /// functions.
+ void addConversionFunction(FunctionTemplateDecl *ConvDecl);
/// isAggregate - Whether this class is an aggregate (C++
/// [dcl.init.aggr]), which is a class with no user-declared
@@ -397,6 +629,15 @@ public:
/// setPOD - Set whether this class is a POD-type (C++ [class]p4).
void setPOD(bool POD) { PlainOldData = POD; }
+ /// isEmpty - Whether this class is empty (C++0x [meta.unary.prop]), which
+ /// means it has a virtual function, virtual base, data member (other than
+ /// 0-width bit-field) or inherits from a non-empty class. Does NOT include
+ /// a check for union-ness.
+ bool isEmpty() const { return Empty; }
+
+ /// Set whether this class is empty (C++0x [meta.unary.prop])
+ void setEmpty(bool Emp) { Empty = Emp; }
+
/// 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; }
@@ -408,26 +649,42 @@ public:
/// 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; }
-
+
+ // hasTrivialCopyConstructor - Whether this class has a trivial copy
+ // constructor (C++ [class.copy]p6)
+ bool hasTrivialCopyConstructor() const { return HasTrivialCopyConstructor; }
+
+ // setHasTrivialCopyConstructor - Set whether this class has a trivial
+ // copy constructor (C++ [class.copy]p6)
+ void setHasTrivialCopyConstructor(bool TC) { HasTrivialCopyConstructor = TC; }
+
+ // hasTrivialCopyAssignment - Whether this class has a trivial copy
+ // assignment operator (C++ [class.copy]p11)
+ bool hasTrivialCopyAssignment() const { return HasTrivialCopyAssignment; }
+
+ // setHasTrivialCopyAssignment - Set whether this class has a
+ // trivial copy assignment operator (C++ [class.copy]p11)
+ void setHasTrivialCopyAssignment(bool TC) { HasTrivialCopyAssignment = 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.
///
@@ -447,15 +704,17 @@ public:
/// 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*>();
- }
-
+ CXXRecordDecl *getInstantiatedFromMemberClass() const;
+
+ /// \brief If this class is an instantiation of a member class of a
+ /// class template specialization, retrieves the member specialization
+ /// information.
+ MemberSpecializationInfo *getMemberSpecializationInfo() const;
+
/// \brief Specify that this record is an instantiation of the
/// member class RD.
- void setInstantiationOfMemberClass(CXXRecordDecl *RD) {
- TemplateOrInstantiation = RD;
- }
+ void setInstantiationOfMemberClass(CXXRecordDecl *RD,
+ TemplateSpecializationKind TSK);
/// \brief Retrieves the class template that is described by this
/// class declaration.
@@ -476,34 +735,150 @@ public:
TemplateOrInstantiation = Template;
}
+ /// \brief Determine whether this particular class is a specialization or
+ /// instantiation of a class template or member class of a class template,
+ /// and how it was instantiated or specialized.
+ TemplateSpecializationKind getTemplateSpecializationKind();
+
+ /// \brief Set the kind of specialization or template instantiation this is.
+ void setTemplateSpecializationKind(TemplateSpecializationKind TSK);
+
/// getDefaultConstructor - Returns the default constructor for this class
CXXConstructorDecl *getDefaultConstructor(ASTContext &Context);
-
+
/// getDestructor - Returns the destructor decl for this class.
const CXXDestructorDecl *getDestructor(ASTContext &Context);
-
+
/// isLocalClass - If the class is a local class [class.local], returns
/// the enclosing function declaration.
const FunctionDecl *isLocalClass() const {
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(getDeclContext()))
return RD->isLocalClass();
-
+
return dyn_cast<FunctionDecl>(getDeclContext());
}
+
+ /// \brief Determine whether this class is derived from the class \p Base.
+ ///
+ /// This routine only determines whether this class is derived from \p Base,
+ /// but does not account for factors that may make a Derived -> Base class
+ /// ill-formed, such as private/protected inheritance or multiple, ambiguous
+ /// base class subobjects.
+ ///
+ /// \param Base the base class we are searching for.
+ ///
+ /// \returns true if this class is derived from Base, false otherwise.
+ bool isDerivedFrom(CXXRecordDecl *Base);
+
+ /// \brief Determine whether this class is derived from the type \p Base.
+ ///
+ /// This routine only determines whether this class is derived from \p Base,
+ /// but does not account for factors that may make a Derived -> Base class
+ /// ill-formed, such as private/protected inheritance or multiple, ambiguous
+ /// base class subobjects.
+ ///
+ /// \param Base the base class we are searching for.
+ ///
+ /// \param Paths will contain the paths taken from the current class to the
+ /// given \p Base class.
+ ///
+ /// \returns true if this class is derived from Base, false otherwise.
+ ///
+ /// \todo add a separate paramaeter to configure IsDerivedFrom, rather than
+ /// tangling input and output in \p Paths
+ bool isDerivedFrom(CXXRecordDecl *Base, CXXBasePaths &Paths);
+
+ /// \brief Function type used by lookupInBases() to determine whether a
+ /// specific base class subobject matches the lookup criteria.
+ ///
+ /// \param Specifier the base-class specifier that describes the inheritance
+ /// from the base class we are trying to match.
+ ///
+ /// \param Path the current path, from the most-derived class down to the
+ /// base named by the \p Specifier.
+ ///
+ /// \param UserData a single pointer to user-specified data, provided to
+ /// lookupInBases().
+ ///
+ /// \returns true if this base matched the search criteria, false otherwise.
+ typedef bool BaseMatchesCallback(CXXBaseSpecifier *Specifier,
+ CXXBasePath &Path,
+ void *UserData);
+
+ /// \brief Look for entities within the base classes of this C++ class,
+ /// transitively searching all base class subobjects.
+ ///
+ /// This routine uses the callback function \p BaseMatches to find base
+ /// classes meeting some search criteria, walking all base class subobjects
+ /// and populating the given \p Paths structure with the paths through the
+ /// inheritance hierarchy that resulted in a match. On a successful search,
+ /// the \p Paths structure can be queried to retrieve the matching paths and
+ /// to determine if there were any ambiguities.
+ ///
+ /// \param BaseMatches callback function used to determine whether a given
+ /// base matches the user-defined search criteria.
+ ///
+ /// \param UserData user data pointer that will be provided to \p BaseMatches.
+ ///
+ /// \param Paths used to record the paths from this class to its base class
+ /// subobjects that match the search criteria.
+ ///
+ /// \returns true if there exists any path from this class to a base class
+ /// subobject that matches the search criteria.
+ bool lookupInBases(BaseMatchesCallback *BaseMatches, void *UserData,
+ CXXBasePaths &Paths);
+
+ /// \brief Base-class lookup callback that determines whether the given
+ /// base class specifier refers to a specific class declaration.
+ ///
+ /// This callback can be used with \c lookupInBases() to determine whether
+ /// a given derived class has is a base class subobject of a particular type.
+ /// The user data pointer should refer to the canonical CXXRecordDecl of the
+ /// base class that we are searching for.
+ static bool FindBaseClass(CXXBaseSpecifier *Specifier, CXXBasePath &Path,
+ void *BaseRecord);
+
+ /// \brief Base-class lookup callback that determines whether there exists
+ /// a tag with the given name.
+ ///
+ /// This callback can be used with \c lookupInBases() to find tag members
+ /// of the given name within a C++ class hierarchy. The user data pointer
+ /// is an opaque \c DeclarationName pointer.
+ static bool FindTagMember(CXXBaseSpecifier *Specifier, CXXBasePath &Path,
+ void *Name);
+
+ /// \brief Base-class lookup callback that determines whether there exists
+ /// a member with the given name.
+ ///
+ /// This callback can be used with \c lookupInBases() to find members
+ /// of the given name within a C++ class hierarchy. The user data pointer
+ /// is an opaque \c DeclarationName pointer.
+ static bool FindOrdinaryMember(CXXBaseSpecifier *Specifier, CXXBasePath &Path,
+ void *Name);
+
+ /// \brief Base-class lookup callback that determines whether there exists
+ /// a member with the given name that can be used in a nested-name-specifier.
+ ///
+ /// This callback can be used with \c lookupInBases() to find membes of
+ /// the given name within a C++ class hierarchy that can occur within
+ /// nested-name-specifiers.
+ static bool FindNestedNameSpecifierMember(CXXBaseSpecifier *Specifier,
+ CXXBasePath &Path,
+ void *UserData);
/// 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 ||
+ static bool classof(const Decl *D) {
+ return D->getKind() == CXXRecord ||
D->getKind() == ClassTemplateSpecialization ||
- D->getKind() == ClassTemplatePartialSpecialization;
+ D->getKind() == ClassTemplatePartialSpecialization;
}
static bool classof(const CXXRecordDecl *D) { return true; }
- static bool classof(const ClassTemplateSpecializationDecl *D) {
- return true;
+ static bool classof(const ClassTemplateSpecializationDecl *D) {
+ return true;
}
};
@@ -512,42 +887,60 @@ public:
class CXXMethodDecl : public FunctionDecl {
protected:
CXXMethodDecl(Kind DK, CXXRecordDecl *RD, SourceLocation L,
- DeclarationName N, QualType T,
+ DeclarationName N, QualType T, DeclaratorInfo *DInfo,
bool isStatic, bool isInline)
- : FunctionDecl(DK, RD, L, N, T, (isStatic ? Static : None),
+ : FunctionDecl(DK, RD, L, N, T, DInfo, (isStatic ? Static : None),
isInline) {}
public:
static CXXMethodDecl *Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation L, DeclarationName N,
- QualType T, bool isStatic = false,
+ QualType T, DeclaratorInfo *DInfo,
+ bool isStatic = false,
bool isInline = false);
-
+
bool isStatic() const { return getStorageClass() == Static; }
bool isInstance() const { return !isStatic(); }
- bool isVirtual() const {
- return isVirtualAsWritten() ||
- (begin_overridden_methods() != end_overridden_methods());
- }
+ bool isVirtual() const {
+ CXXMethodDecl *CD =
+ cast<CXXMethodDecl>(const_cast<CXXMethodDecl*>(this)->getCanonicalDecl());
- ///
- void addOverriddenMethod(const CXXMethodDecl *MD);
+ if (CD->isVirtualAsWritten())
+ return true;
+
+ return (CD->begin_overridden_methods() != CD->end_overridden_methods());
+ }
- typedef const CXXMethodDecl ** method_iterator;
+ /// \brief Determine whether this is a usual deallocation function
+ /// (C++ [basic.stc.dynamic.deallocation]p2), which is an overloaded
+ /// delete or delete[] operator with a particular signature.
+ bool isUsualDeallocationFunction() const;
+ const CXXMethodDecl *getCanonicalDecl() const {
+ return cast<CXXMethodDecl>(FunctionDecl::getCanonicalDecl());
+ }
+ CXXMethodDecl *getCanonicalDecl() {
+ return cast<CXXMethodDecl>(FunctionDecl::getCanonicalDecl());
+ }
+
+ ///
+ 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());
+ 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() {
+ CXXRecordDecl *getParent() {
return const_cast<CXXRecordDecl *>(
cast<CXXRecordDecl>(FunctionDecl::getParent()));
}
@@ -557,11 +950,11 @@ public:
QualType getThisType(ASTContext &C) const;
unsigned getTypeQualifiers() const {
- return getType()->getAsFunctionProtoType()->getTypeQuals();
+ return getType()->getAs<FunctionProtoType>()->getTypeQuals();
}
// Implement isa/cast/dyncast/etc.
- static bool classof(const Decl *D) {
+ static bool classof(const Decl *D) {
return D->getKind() >= CXXMethod && D->getKind() <= CXXConversion;
}
static bool classof(const CXXMethodDecl *D) { return true; }
@@ -589,38 +982,63 @@ class CXXBaseOrMemberInitializer {
uintptr_t BaseOrMember;
/// Args - The arguments used to initialize the base or member.
- Expr **Args;
+ Stmt **Args;
unsigned NumArgs;
-
+
+ /// \brief Stores either the constructor to call to initialize this base or
+ /// member (a CXXConstructorDecl pointer), or stores the anonymous union of
+ /// which the initialized value is a member.
+ ///
+ /// When the value is a FieldDecl pointer, 'BaseOrMember' is class's
+ /// anonymous union data member, this field holds the FieldDecl for the
+ /// member of the anonymous union being initialized.
+ /// @code
+ /// struct X {
+ /// X() : au_i1(123) {}
+ /// union {
+ /// int au_i1;
+ /// float au_f1;
+ /// };
+ /// };
+ /// @endcode
+ /// In above example, BaseOrMember holds the field decl. for anonymous union
+ /// and AnonUnionMember holds field decl for au_i1.
+ llvm::PointerUnion<CXXConstructorDecl *, FieldDecl *> CtorOrAnonUnion;
+
/// IdLoc - Location of the id in ctor-initializer list.
SourceLocation IdLoc;
+ /// RParenLoc - Location of the right paren of the ctor-initializer.
+ SourceLocation RParenLoc;
+
public:
/// CXXBaseOrMemberInitializer - Creates a new base-class initializer.
- explicit
+ explicit
CXXBaseOrMemberInitializer(QualType BaseType, Expr **Args, unsigned NumArgs,
- SourceLocation L);
+ CXXConstructorDecl *C,
+ SourceLocation L, SourceLocation R);
/// CXXBaseOrMemberInitializer - Creates a new member initializer.
- explicit
+ explicit
CXXBaseOrMemberInitializer(FieldDecl *Member, Expr **Args, unsigned NumArgs,
- SourceLocation L);
+ CXXConstructorDecl *C,
+ SourceLocation L, SourceLocation R);
/// ~CXXBaseOrMemberInitializer - Destroy the base or member initializer.
~CXXBaseOrMemberInitializer();
/// arg_iterator - Iterates through the member initialization
/// arguments.
- typedef Expr **arg_iterator;
+ typedef ExprIterator arg_iterator;
/// arg_const_iterator - Iterates through the member initialization
/// arguments.
- typedef Expr * const * arg_const_iterator;
+ typedef ConstExprIterator const_arg_iterator;
/// getBaseOrMember - get the generic 'member' representing either the field
/// or a base class.
void* getBaseOrMember() const { return reinterpret_cast<void*>(BaseOrMember); }
-
+
/// isBaseInitializer - Returns true when this initializer is
/// initializing a base class.
bool isBaseInitializer() const { return (BaseOrMember & 0x1) != 0; }
@@ -633,8 +1051,8 @@ public:
/// 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())
+ Type *getBaseClass() {
+ if (isBaseInitializer())
return reinterpret_cast<Type*>(BaseOrMember & ~0x01);
else
return 0;
@@ -644,8 +1062,8 @@ public:
/// 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())
+ const Type *getBaseClass() const {
+ if (isBaseInitializer())
return reinterpret_cast<const Type*>(BaseOrMember & ~0x01);
else
return 0;
@@ -654,24 +1072,40 @@ public:
/// getMember - If this is a member initializer, returns the
/// declaration of the non-static data member being
/// initialized. Otherwise, returns NULL.
- FieldDecl *getMember() {
+ FieldDecl *getMember() {
if (isMemberInitializer())
- return reinterpret_cast<FieldDecl *>(BaseOrMember);
+ return reinterpret_cast<FieldDecl *>(BaseOrMember);
else
return 0;
}
+ void setMember(FieldDecl * anonUnionField) {
+ BaseOrMember = reinterpret_cast<uintptr_t>(anonUnionField);
+ }
+
+ FieldDecl *getAnonUnionMember() const {
+ return CtorOrAnonUnion.dyn_cast<FieldDecl *>();
+ }
+ void setAnonUnionMember(FieldDecl *anonMember) {
+ CtorOrAnonUnion = anonMember;
+ }
+
+ const CXXConstructorDecl *getConstructor() const {
+ return CtorOrAnonUnion.dyn_cast<CXXConstructorDecl *>();
+ }
+
SourceLocation getSourceLocation() const { return IdLoc; }
-
- /// 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; }
+ SourceLocation getRParenLoc() const { return RParenLoc; }
- /// 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; }
+ /// arg_begin() - Retrieve an iterator to the first initializer argument.
+ arg_iterator arg_begin() { return Args; }
+ /// arg_begin() - Retrieve an iterator to the first initializer argument.
+ const_arg_iterator const_arg_begin() const { return Args; }
+
+ /// arg_end() - Retrieve an iterator past the last initializer argument.
+ arg_iterator arg_end() { return Args + NumArgs; }
+ /// arg_end() - Retrieve an iterator past the last initializer argument.
+ const_arg_iterator const_arg_end() const { return Args + NumArgs; }
/// getNumArgs - Determine the number of arguments used to
/// initialize the member or base.
@@ -680,7 +1114,7 @@ public:
/// CXXConstructorDecl - Represents a C++ constructor within a
/// class. For example:
-///
+///
/// @code
/// class X {
/// public:
@@ -698,82 +1132,86 @@ class CXXConstructorDecl : public CXXMethodDecl {
/// explicitly defaulted (i.e., defined with " = default") will have
/// @c !Implicit && ImplicitlyDefined.
bool ImplicitlyDefined : 1;
-
+
/// Support for base and member initializers.
- /// BaseOrMemberInitializers - The arguments used to initialize the base
+ /// BaseOrMemberInitializers - The arguments used to initialize the base
/// or member.
CXXBaseOrMemberInitializer **BaseOrMemberInitializers;
unsigned NumBaseOrMemberInitializers;
-
+
CXXConstructorDecl(CXXRecordDecl *RD, SourceLocation L,
- DeclarationName N, QualType T,
+ DeclarationName N, QualType T, DeclaratorInfo *DInfo,
bool isExplicit, bool isInline, bool isImplicitlyDeclared)
- : CXXMethodDecl(CXXConstructor, RD, L, N, T, false, isInline),
+ : CXXMethodDecl(CXXConstructor, RD, L, N, T, DInfo, false, isInline),
Explicit(isExplicit), ImplicitlyDefined(false),
- BaseOrMemberInitializers(0), NumBaseOrMemberInitializers(0) {
+ BaseOrMemberInitializers(0), NumBaseOrMemberInitializers(0) {
setImplicit(isImplicitlyDeclared);
}
virtual void Destroy(ASTContext& C);
-
+
public:
static CXXConstructorDecl *Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation L, DeclarationName N,
- QualType T, bool isExplicit,
+ QualType T, DeclaratorInfo *DInfo,
+ bool isExplicit,
bool isInline, bool isImplicitlyDeclared);
- /// isExplicit - Whether this constructor was marked "explicit" or not.
+ /// 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() &&
+ bool isImplicitlyDefined(ASTContext &C) const {
+ assert(isThisDeclarationADefinition() &&
"Can only get the implicit-definition flag once the "
"constructor has been defined");
- return ImplicitlyDefined;
+ return ImplicitlyDefined;
}
/// setImplicitlyDefined - Set whether this constructor was
/// implicitly defined or not.
- void setImplicitlyDefined(bool ID) {
- assert(isThisDeclarationADefinition() &&
+ void setImplicitlyDefined(bool ID) {
+ assert(isThisDeclarationADefinition() &&
"Can only set the implicit-definition flag once the constructor "
"has been defined");
- ImplicitlyDefined = ID;
+ ImplicitlyDefined = ID;
}
-
+
/// init_iterator - Iterates through the member/base initializer list.
typedef CXXBaseOrMemberInitializer **init_iterator;
-
+
/// init_const_iterator - Iterates through the memberbase initializer list.
typedef CXXBaseOrMemberInitializer * const * init_const_iterator;
-
- /// begin() - Retrieve an iterator to the first initializer.
- init_iterator begin() { return BaseOrMemberInitializers; }
+
+ /// init_begin() - Retrieve an iterator to the first initializer.
+ init_iterator init_begin() { return BaseOrMemberInitializers; }
/// begin() - Retrieve an iterator to the first initializer.
- init_const_iterator begin() const { return BaseOrMemberInitializers; }
-
- /// end() - Retrieve an iterator past the last initializer.
- init_iterator end() {
- return BaseOrMemberInitializers + NumBaseOrMemberInitializers;
+ init_const_iterator init_begin() const { return BaseOrMemberInitializers; }
+
+ /// init_end() - Retrieve an iterator past the last initializer.
+ init_iterator init_end() {
+ return BaseOrMemberInitializers + NumBaseOrMemberInitializers;
}
/// end() - Retrieve an iterator past the last initializer.
- init_const_iterator end() const {
- return BaseOrMemberInitializers + NumBaseOrMemberInitializers;
+ init_const_iterator init_end() const {
+ return BaseOrMemberInitializers + NumBaseOrMemberInitializers;
}
-
+
/// getNumArgs - Determine the number of arguments used to
/// initialize the member or base.
- unsigned getNumBaseOrMemberInitializers() const {
- return NumBaseOrMemberInitializers;
+ unsigned getNumBaseOrMemberInitializers() const {
+ return NumBaseOrMemberInitializers;
+ }
+
+ void setNumBaseOrMemberInitializers(unsigned numBaseOrMemberInitializers) {
+ NumBaseOrMemberInitializers = numBaseOrMemberInitializers;
+ }
+
+ void setBaseOrMemberInitializers(CXXBaseOrMemberInitializer ** initializers) {
+ BaseOrMemberInitializers = initializers;
}
-
- void setBaseOrMemberInitializers(ASTContext &C,
- CXXBaseOrMemberInitializer **Initializers,
- unsigned NumInitializers);
-
/// isDefaultConstructor - Whether this constructor is a default
/// constructor (C++ [class.ctor]p5), which can be used to
/// default-initialize a class of this type.
@@ -804,10 +1242,10 @@ public:
/// isConvertingConstructor - Whether this constructor is a
/// converting constructor (C++ [class.conv.ctor]), which can be
/// used for user-defined conversions.
- bool isConvertingConstructor() const;
+ bool isConvertingConstructor(bool AllowExplicit) const;
// Implement isa/cast/dyncast/etc.
- static bool classof(const Decl *D) {
+ static bool classof(const Decl *D) {
return D->getKind() == CXXConstructor;
}
static bool classof(const CXXConstructorDecl *D) { return true; }
@@ -815,7 +1253,7 @@ public:
/// CXXDestructorDecl - Represents a C++ destructor within a
/// class. For example:
-///
+///
/// @code
/// class X {
/// public:
@@ -823,6 +1261,13 @@ public:
/// };
/// @endcode
class CXXDestructorDecl : public CXXMethodDecl {
+public:
+ enum KindOfObjectToDestroy {
+ VBASE = 0x1,
+ DRCTNONVBASE = 0x2,
+ ANYBASE = 0x3
+ };
+private:
/// 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
@@ -831,40 +1276,141 @@ class CXXDestructorDecl : public CXXMethodDecl {
/// @c !Implicit && ImplicitlyDefined.
bool ImplicitlyDefined : 1;
+ /// Support for base and member destruction.
+ /// BaseOrMemberDestructions - The arguments used to destruct the base
+ /// or member. Each uintptr_t value represents one of base classes (either
+ /// virtual or direct non-virtual base), or non-static data member
+ /// to be destroyed. The low two bits encode the kind of object
+ /// being destroyed.
+ uintptr_t *BaseOrMemberDestructions;
+ unsigned NumBaseOrMemberDestructions;
+
CXXDestructorDecl(CXXRecordDecl *RD, SourceLocation L,
DeclarationName N, QualType T,
bool isInline, bool isImplicitlyDeclared)
- : CXXMethodDecl(CXXDestructor, RD, L, N, T, false, isInline),
- ImplicitlyDefined(false) {
+ : CXXMethodDecl(CXXDestructor, RD, L, N, T, /*DInfo=*/0, false, isInline),
+ ImplicitlyDefined(false),
+ BaseOrMemberDestructions(0), NumBaseOrMemberDestructions(0) {
setImplicit(isImplicitlyDeclared);
}
+ virtual void Destroy(ASTContext& C);
public:
static CXXDestructorDecl *Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation L, DeclarationName N,
- QualType T, bool isInline,
+ 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() &&
+ bool isImplicitlyDefined() const {
+ assert(isThisDeclarationADefinition() &&
"Can only get the implicit-definition flag once the destructor has been defined");
- return ImplicitlyDefined;
+ return ImplicitlyDefined;
}
/// setImplicitlyDefined - Set whether this destructor was
/// implicitly defined or not.
- void setImplicitlyDefined(bool ID) {
- assert(isThisDeclarationADefinition() &&
+ void setImplicitlyDefined(bool ID) {
+ assert(isThisDeclarationADefinition() &&
"Can only set the implicit-definition flag once the destructor has been defined");
- ImplicitlyDefined = ID;
+ ImplicitlyDefined = ID;
+ }
+
+ /// destr_iterator - Iterates through the member/base destruction list.
+
+ /// destr_const_iterator - Iterates through the member/base destruction list.
+ typedef uintptr_t const destr_const_iterator;
+
+ /// destr_begin() - Retrieve an iterator to the first destructed member/base.
+ uintptr_t* destr_begin() {
+ return BaseOrMemberDestructions;
+ }
+ /// destr_begin() - Retrieve an iterator to the first destructed member/base.
+ uintptr_t* destr_begin() const {
+ return BaseOrMemberDestructions;
+ }
+
+ /// destr_end() - Retrieve an iterator past the last destructed member/base.
+ uintptr_t* destr_end() {
+ return BaseOrMemberDestructions + NumBaseOrMemberDestructions;
+ }
+ /// destr_end() - Retrieve an iterator past the last destructed member/base.
+ uintptr_t* destr_end() const {
+ return BaseOrMemberDestructions + NumBaseOrMemberDestructions;
+ }
+
+ /// getNumBaseOrMemberDestructions - Number of base and non-static members
+ /// to destroy.
+ unsigned getNumBaseOrMemberDestructions() const {
+ return NumBaseOrMemberDestructions;
+ }
+
+ /// setNumBaseOrMemberDestructions - Set number of base and non-static members
+ /// to destroy.
+ void setNumBaseOrMemberDestructions(unsigned numBaseOrMemberDestructions) {
+ NumBaseOrMemberDestructions = numBaseOrMemberDestructions;
+ }
+
+ /// getBaseOrMemberToDestroy - get the generic 'member' representing either
+ /// the field or a base class.
+ uintptr_t* getBaseOrMemberToDestroy() const {
+ return BaseOrMemberDestructions;
+ }
+
+ /// setBaseOrMemberToDestroy - set the generic 'member' representing either
+ /// the field or a base class.
+ void setBaseOrMemberDestructions(uintptr_t* baseOrMemberDestructions) {
+ BaseOrMemberDestructions = baseOrMemberDestructions;
+ }
+
+ /// isVbaseToDestroy - returns true, if object is virtual base.
+ bool isVbaseToDestroy(uintptr_t Vbase) const {
+ return (Vbase & VBASE) != 0;
+ }
+ /// isDirectNonVBaseToDestroy - returns true, if object is direct non-virtual
+ /// base.
+ bool isDirectNonVBaseToDestroy(uintptr_t DrctNonVbase) const {
+ return (DrctNonVbase & DRCTNONVBASE) != 0;
+ }
+ /// isAnyBaseToDestroy - returns true, if object is any base (virtual or
+ /// direct non-virtual)
+ bool isAnyBaseToDestroy(uintptr_t AnyBase) const {
+ return (AnyBase & ANYBASE) != 0;
+ }
+ /// isMemberToDestroy - returns true if object is a non-static data member.
+ bool isMemberToDestroy(uintptr_t Member) const {
+ return (Member & ANYBASE) == 0;
+ }
+ /// getAnyBaseClassToDestroy - Get the type for the given base class object.
+ Type *getAnyBaseClassToDestroy(uintptr_t Base) const {
+ if (isAnyBaseToDestroy(Base))
+ return reinterpret_cast<Type*>(Base & ~0x03);
+ return 0;
+ }
+ /// getMemberToDestroy - Get the member for the given object.
+ FieldDecl *getMemberToDestroy(uintptr_t Member) const {
+ if (isMemberToDestroy(Member))
+ return reinterpret_cast<FieldDecl *>(Member);
+ return 0;
+ }
+ /// getVbaseClassToDestroy - Get the virtual base.
+ Type *getVbaseClassToDestroy(uintptr_t Vbase) const {
+ if (isVbaseToDestroy(Vbase))
+ return reinterpret_cast<Type*>(Vbase & ~0x01);
+ return 0;
+ }
+ /// getDirectNonVBaseClassToDestroy - Get the virtual base.
+ Type *getDirectNonVBaseClassToDestroy(uintptr_t Base) const {
+ if (isDirectNonVBaseToDestroy(Base))
+ return reinterpret_cast<Type*>(Base & ~0x02);
+ return 0;
}
// Implement isa/cast/dyncast/etc.
- static bool classof(const Decl *D) {
+ static bool classof(const Decl *D) {
return D->getKind() == CXXDestructor;
}
static bool classof(const CXXDestructorDecl *D) { return true; }
@@ -872,7 +1418,7 @@ public:
/// CXXConversionDecl - Represents a C++ conversion function within a
/// class. For example:
-///
+///
/// @code
/// class X {
/// public:
@@ -886,16 +1432,16 @@ class CXXConversionDecl : public CXXMethodDecl {
bool Explicit : 1;
CXXConversionDecl(CXXRecordDecl *RD, SourceLocation L,
- DeclarationName N, QualType T,
+ DeclarationName N, QualType T, DeclaratorInfo *DInfo,
bool isInline, bool isExplicit)
- : CXXMethodDecl(CXXConversion, RD, L, N, T, false, isInline),
+ : CXXMethodDecl(CXXConversion, RD, L, N, T, DInfo, false, isInline),
Explicit(isExplicit) { }
public:
static CXXConversionDecl *Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation L, DeclarationName N,
- QualType T, bool isInline,
- bool isExplicit);
+ QualType T, DeclaratorInfo *DInfo,
+ bool isInline, bool isExplicit);
/// isExplicit - Whether this is an explicit conversion operator
/// (C++0x only). Explicit conversion operators are only considered
@@ -904,17 +1450,81 @@ public:
/// getConversionType - Returns the type that this conversion
/// function is converting to.
- QualType getConversionType() const {
- return getType()->getAsFunctionType()->getResultType();
+ QualType getConversionType() const {
+ return getType()->getAs<FunctionType>()->getResultType();
}
// Implement isa/cast/dyncast/etc.
- static bool classof(const Decl *D) {
+ static bool classof(const Decl *D) {
return D->getKind() == CXXConversion;
}
static bool classof(const CXXConversionDecl *D) { return true; }
};
+/// FriendDecl - Represents the declaration of a friend entity,
+/// which can be a function, a type, or a templated function or type.
+// For example:
+///
+/// @code
+/// template <typename T> class A {
+/// friend int foo(T);
+/// friend class B;
+/// friend T; // only in C++0x
+/// template <typename U> friend class C;
+/// template <typename U> friend A& operator+=(A&, const U&) { ... }
+/// };
+/// @endcode
+///
+/// The semantic context of a friend decl is its declaring class.
+class FriendDecl : public Decl {
+public:
+ typedef llvm::PointerUnion<NamedDecl*,Type*> FriendUnion;
+
+private:
+ // The declaration that's a friend of this class.
+ FriendUnion Friend;
+
+ // Location of the 'friend' specifier.
+ SourceLocation FriendLoc;
+
+ FriendDecl(DeclContext *DC, SourceLocation L, FriendUnion Friend,
+ SourceLocation FriendL)
+ : Decl(Decl::Friend, DC, L),
+ Friend(Friend),
+ FriendLoc(FriendL) {
+ }
+
+public:
+ static FriendDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, FriendUnion Friend_,
+ SourceLocation FriendL);
+
+ /// If this friend declaration names an (untemplated but
+ /// possibly dependent) type, return the type; otherwise
+ /// return null. This is used only for C++0x's unelaborated
+ /// friend type declarations.
+ Type *getFriendType() const {
+ return Friend.dyn_cast<Type*>();
+ }
+
+ /// If this friend declaration doesn't name an unelaborated
+ /// type, return the inner declaration.
+ NamedDecl *getFriendDecl() const {
+ return Friend.dyn_cast<NamedDecl*>();
+ }
+
+ /// Retrieves the location of the 'friend' keyword.
+ SourceLocation getFriendLoc() const {
+ return FriendLoc;
+ }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) {
+ return D->getKind() == Decl::Friend;
+ }
+ static bool classof(const FriendDecl *D) { return true; }
+};
+
/// LinkageSpecDecl - This represents a linkage specification. For example:
/// extern "C" void foo();
///
@@ -934,14 +1544,14 @@ private:
/// HadBraces - Whether this linkage specification had curly braces or not.
bool HadBraces : 1;
- LinkageSpecDecl(DeclContext *DC, SourceLocation L, LanguageIDs lang,
+ LinkageSpecDecl(DeclContext *DC, SourceLocation L, LanguageIDs lang,
bool Braces)
- : Decl(LinkageSpec, DC, L),
+ : Decl(LinkageSpec, DC, L),
DeclContext(LinkageSpec), Language(lang), HadBraces(Braces) { }
public:
- static LinkageSpecDecl *Create(ASTContext &C, DeclContext *DC,
- SourceLocation L, LanguageIDs Lang,
+ static LinkageSpecDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, LanguageIDs Lang,
bool Braces);
LanguageIDs getLanguage() const { return Language; }
@@ -1008,8 +1618,8 @@ class UsingDirectiveDecl : public NamedDecl {
NamespaceDecl *Nominated,
DeclContext *CommonAncestor)
: NamedDecl(Decl::UsingDirective, DC, L, getName()),
- NamespaceLoc(NamespcLoc), QualifierRange(QualifierRange),
- Qualifier(Qualifier), IdentLoc(IdentLoc),
+ NamespaceLoc(NamespcLoc), QualifierRange(QualifierRange),
+ Qualifier(Qualifier), IdentLoc(IdentLoc),
NominatedNamespace(Nominated? Nominated->getOriginalNamespace() : 0),
CommonAncestor(CommonAncestor) {
}
@@ -1074,20 +1684,20 @@ class NamespaceAliasDecl : public NamedDecl {
/// \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
+
+ /// 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,
+
+ 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),
+ : NamedDecl(Decl::NamespaceAlias, DC, L, Alias), AliasLoc(AliasLoc),
QualifierRange(QualifierRange), Qualifier(Qualifier),
IdentLoc(IdentLoc), Namespace(Namespace) { }
@@ -1106,7 +1716,7 @@ public:
return cast<NamespaceDecl>(Namespace);
}
-
+
const NamespaceDecl *getNamespace() const {
return const_cast<NamespaceAliasDecl*>(this)->getNamespace();
}
@@ -1115,14 +1725,14 @@ public:
/// 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,
+ static NamespaceAliasDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, SourceLocation AliasLoc,
+ IdentifierInfo *Alias,
SourceRange QualifierRange,
NestedNameSpecifier *Qualifier,
- SourceLocation IdentLoc,
+ SourceLocation IdentLoc,
NamedDecl *Namespace);
-
+
static bool classof(const Decl *D) {
return D->getKind() == Decl::NamespaceAlias;
}
@@ -1132,20 +1742,23 @@ public:
/// UsingDecl - Represents a C++ using-declaration. For example:
/// using someNameSpace::someIdentifier;
class UsingDecl : public NamedDecl {
-
/// \brief The source range that covers the nested-name-specifier
/// preceding the declaration name.
SourceRange NestedNameRange;
+
/// \brief The source location of the target declaration name.
SourceLocation TargetNameLocation;
+
/// \brief The source location of the "using" location itself.
SourceLocation UsingLocation;
+
/// \brief Target declaration.
NamedDecl* TargetDecl;
- /// \brief Target declaration.
+
+ /// \brief Target nested name specifier.
NestedNameSpecifier* TargetNestedNameDecl;
- // Had 'typename' keyword.
+ // \brief Has 'typename' keyword.
bool IsTypeName;
UsingDecl(DeclContext *DC, SourceLocation L, SourceRange NNR,
@@ -1154,7 +1767,7 @@ class UsingDecl : public NamedDecl {
: NamedDecl(Decl::Using, DC, L, Target->getDeclName()),
NestedNameRange(NNR), TargetNameLocation(TargetNL),
UsingLocation(UL), TargetDecl(Target),
- TargetNestedNameDecl(TargetNNS), IsTypeName(IsTypeNameArg) {
+ TargetNestedNameDecl(TargetNNS), IsTypeName(IsTypeNameArg) {
this->IdentifierNamespace = TargetDecl->getIdentifierNamespace();
}
@@ -1162,23 +1775,23 @@ public:
/// \brief Returns the source range that covers the nested-name-specifier
/// preceding the namespace name.
SourceRange getNestedNameRange() { return NestedNameRange; }
-
+
/// \brief Returns the source location of the target declaration name.
SourceLocation getTargetNameLocation() { return TargetNameLocation; }
-
+
/// \brief Returns the source location of the "using" location itself.
SourceLocation getUsingLocation() { return UsingLocation; }
-
+
/// \brief getTargetDecl - Returns target specified by using-decl.
NamedDecl *getTargetDecl() { return TargetDecl; }
const NamedDecl *getTargetDecl() const { return TargetDecl; }
-
+
/// \brief Get target nested name declaration.
- NestedNameSpecifier* getTargetNestedNameDecl() {
- return TargetNestedNameDecl;
+ NestedNameSpecifier* getTargetNestedNameDecl() {
+ return TargetNestedNameDecl;
}
-
- /// isTypeName - Return true if using decl had 'typename'.
+
+ /// isTypeName - Return true if using decl has 'typename'.
bool isTypeName() const { return IsTypeName; }
static UsingDecl *Create(ASTContext &C, DeclContext *DC,
@@ -1191,27 +1804,85 @@ public:
}
static bool classof(const UsingDecl *D) { return true; }
};
-
+
+/// UnresolvedUsingDecl - Represents a using declaration whose name can not
+/// yet be resolved.
+class UnresolvedUsingDecl : public NamedDecl {
+ /// \brief The source range that covers the nested-name-specifier
+ /// preceding the declaration name.
+ SourceRange TargetNestedNameRange;
+
+ /// \brief The source location of the target declaration name.
+ SourceLocation TargetNameLocation;
+
+ NestedNameSpecifier *TargetNestedNameSpecifier;
+
+ DeclarationName TargetName;
+
+ // \brief Has 'typename' keyword.
+ bool IsTypeName;
+
+ UnresolvedUsingDecl(DeclContext *DC, SourceLocation UsingLoc,
+ SourceRange TargetNNR, NestedNameSpecifier *TargetNNS,
+ SourceLocation TargetNameLoc, DeclarationName TargetName,
+ bool IsTypeNameArg)
+ : NamedDecl(Decl::UnresolvedUsing, DC, UsingLoc, TargetName),
+ TargetNestedNameRange(TargetNNR), TargetNameLocation(TargetNameLoc),
+ TargetNestedNameSpecifier(TargetNNS), TargetName(TargetName),
+ IsTypeName(IsTypeNameArg) { }
+
+public:
+ /// \brief Returns the source range that covers the nested-name-specifier
+ /// preceding the namespace name.
+ SourceRange getTargetNestedNameRange() const { return TargetNestedNameRange; }
+
+ /// \brief Get target nested name declaration.
+ NestedNameSpecifier* getTargetNestedNameSpecifier() {
+ return TargetNestedNameSpecifier;
+ }
+
+ /// \brief Returns the source location of the target declaration name.
+ SourceLocation getTargetNameLocation() const { return TargetNameLocation; }
+
+ /// \brief Returns the source location of the target declaration name.
+ DeclarationName getTargetName() const { return TargetName; }
+
+ bool isTypeName() const { return IsTypeName; }
+
+ static UnresolvedUsingDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation UsingLoc,
+ SourceRange TargetNNR,
+ NestedNameSpecifier *TargetNNS,
+ SourceLocation TargetNameLoc,
+ DeclarationName TargetName,
+ bool IsTypeNameArg);
+
+ static bool classof(const Decl *D) {
+ return D->getKind() == Decl::UnresolvedUsing;
+ }
+ static bool classof(const UnresolvedUsingDecl *D) { return true; }
+};
+
/// StaticAssertDecl - Represents a C++0x static_assert declaration.
class StaticAssertDecl : public Decl {
Expr *AssertExpr;
StringLiteral *Message;
- StaticAssertDecl(DeclContext *DC, SourceLocation L,
+ 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);
@@ -1225,7 +1896,7 @@ public:
/// 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
index 6c1231c..d9e40d4 100644
--- a/include/clang/AST/DeclContextInternals.h
+++ b/include/clang/AST/DeclContextInternals.h
@@ -57,13 +57,13 @@ public:
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;
@@ -74,9 +74,9 @@ public:
}
return *this;
}
-
+
bool isNull() const { return (Data & ~0x03) == 0; }
-
+
NamedDecl *getAsDecl() const {
if ((Data & 0x03) != DK_Decl)
return 0;
@@ -135,27 +135,27 @@ public:
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],
+ 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) {
@@ -169,7 +169,7 @@ public:
setOnlyValue(D);
return true;
}
-
+
// Determine if this declaration is actually a redeclaration.
VectorTy &Vec = *getAsVector();
for (VectorTy::iterator OD = Vec.begin(), ODEnd = Vec.end();
@@ -183,10 +183,10 @@ public:
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");
@@ -197,7 +197,7 @@ public:
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)
@@ -217,4 +217,4 @@ typedef llvm::DenseMap<DeclarationName, StoredDeclsList> StoredDeclsMap;
} // end namespace clang
-#endif
+#endif
diff --git a/include/clang/AST/DeclGroup.h b/include/clang/AST/DeclGroup.h
index 15a8ade..790ea3c 100644
--- a/include/clang/AST/DeclGroup.h
+++ b/include/clang/AST/DeclGroup.h
@@ -18,7 +18,7 @@
#include <cassert>
namespace clang {
-
+
class ASTContext;
class Decl;
class DeclGroup;
@@ -27,7 +27,7 @@ class DeclGroupIterator;
class DeclGroup {
// FIXME: Include a TypeSpecifier object.
unsigned NumDecls;
-
+
private:
DeclGroup() : NumDecls(0) {}
DeclGroup(unsigned numdecls, Decl** decls);
@@ -38,34 +38,34 @@ public:
unsigned size() const { return NumDecls; }
- Decl*& operator[](unsigned i) {
+ Decl*& operator[](unsigned i) {
assert (i < NumDecls && "Out-of-bounds access.");
return *((Decl**) (this+1));
}
-
- Decl* const& operator[](unsigned i) const {
+
+ 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 };
+ enum Kind { SingleDeclKind=0x0, DeclGroupKind=0x1, Mask=0x1 };
Decl* D;
Kind getKind() const {
return (Kind) (reinterpret_cast<uintptr_t>(D) & Mask);
- }
-
-public:
+ }
+
+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();
@@ -73,10 +73,10 @@ public:
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; }
@@ -88,7 +88,7 @@ public:
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));
@@ -96,7 +96,7 @@ public:
const DeclGroup &getDeclGroup() const {
return const_cast<DeclGroupRef*>(this)->getDeclGroup();
}
-
+
iterator begin() {
if (isSingleDecl())
return D ? &D : 0;
@@ -109,13 +109,13 @@ public:
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;
@@ -130,7 +130,7 @@ public:
return X;
}
};
-
+
} // end clang namespace
namespace llvm {
diff --git a/include/clang/AST/DeclNodes.def b/include/clang/AST/DeclNodes.def
index 1e44403..79a0d36 100644
--- a/include/clang/AST/DeclNodes.def
+++ b/include/clang/AST/DeclNodes.def
@@ -91,39 +91,43 @@ ABSTRACT_DECL(Named, Decl)
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)
+ ABSTRACT_DECL(Declarator, ValueDecl)
+ DECL(Function, DeclaratorDecl)
+ DECL(CXXMethod, FunctionDecl)
+ DECL(CXXConstructor, CXXMethodDecl)
+ DECL(CXXDestructor, CXXMethodDecl)
+ DECL(CXXConversion, CXXMethodDecl)
+ DECL(Field, DeclaratorDecl)
+ DECL(ObjCIvar, FieldDecl)
+ DECL(ObjCAtDefsField, FieldDecl)
+ DECL(Var, DeclaratorDecl)
+ 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(Using, NamedDecl)
+ DECL(UnresolvedUsing, NamedDecl)
DECL(ObjCMethod, NamedDecl)
DECL(ObjCContainer, NamedDecl)
DECL(ObjCCategory, ObjCContainerDecl)
DECL(ObjCProtocol, ObjCContainerDecl)
DECL(ObjCInterface, ObjCContainerDecl)
+ ABSTRACT_DECL(ObjCImpl, ObjCContainerDecl)
+ DECL(ObjCCategoryImpl, ObjCImplDecl)
+ DECL(ObjCImplementation, ObjCImplDecl)
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(Friend, Decl)
+DECL(FriendTemplate, Decl)
DECL(StaticAssert, Decl)
LAST_DECL(Block, Decl)
@@ -132,21 +136,20 @@ 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(Named, OverloadedFunction, ObjCCompatibleAlias)
+DECL_RANGE(ObjCContainer, ObjCContainer, ObjCImplementation)
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(Declarator, Function, NonTypeTemplateParm)
DECL_RANGE(Function, Function, CXXConversion)
DECL_RANGE(Template, Template, TemplateTemplateParm)
DECL_RANGE(ObjCImpl, ObjCCategoryImpl, ObjCImplementation)
diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h
index 2fcdaa3..2b12bb5 100644
--- a/include/clang/AST/DeclObjC.h
+++ b/include/clang/AST/DeclObjC.h
@@ -43,17 +43,17 @@ public:
~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
@@ -64,30 +64,30 @@ 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).
+/// 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;
-///
+/// - (NSMenu *)menu;
+///
/// Instance method that takes 2 NSView arguments:
/// - (void)replaceSubview:(NSView *)oldView with:(NSView *)newView;
///
@@ -106,27 +106,27 @@ private:
/// 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 '{'.
-
+ 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;
@@ -137,7 +137,7 @@ private:
/// 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,
@@ -150,48 +150,55 @@ private:
IsInstance(isInstance), IsVariadic(isVariadic),
IsSynthesized(isSynthesized),
DeclImplementation(impControl), objcDeclQualifier(OBJC_TQ_None),
- MethodDeclType(T),
+ MethodDeclType(T),
EndLoc(endLoc), Body(0), SelfDecl(0), CmdDecl(0) {}
virtual ~ObjCMethodDecl() {}
-
+
+ /// \brief A definition will return its interface declaration.
+ /// An interface declaration will return its definition.
+ /// Otherwise it will return itself.
+ virtual ObjCMethodDecl *getNextRedeclaration();
+
public:
-
+
/// Destroy - Call destructors and release memory.
virtual void Destroy(ASTContext& C);
static ObjCMethodDecl *Create(ASTContext &C,
- SourceLocation beginLoc,
+ SourceLocation beginLoc,
SourceLocation endLoc, Selector SelInfo,
QualType T, DeclContext *contextDecl,
bool isInstance = true,
bool isVariadic = false,
bool isSynthesized = false,
ImplementationControl impControl = None);
-
+
+ virtual ObjCMethodDecl *getCanonicalDecl();
+
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);
+ virtual 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;
@@ -212,7 +219,7 @@ public:
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
@@ -223,31 +230,34 @@ public:
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;
+ void setDeclImplementation(ImplementationControl ic) {
+ DeclImplementation = ic;
}
- ImplementationControl getImplementationControl() const {
- return ImplementationControl(DeclImplementation);
+ ImplementationControl getImplementationControl() const {
+ return ImplementationControl(DeclImplementation);
}
- virtual Stmt *getBody() const {
- return (Stmt*) Body;
+ virtual Stmt *getBody() const {
+ return (Stmt*) Body;
}
CompoundStmt *getCompoundBody() { return (CompoundStmt*)Body; }
void setBody(Stmt *B) { Body = B; }
+ /// \brief Returns whether this specific method is a definition.
+ bool isThisDeclarationADefinition() const { return Body; }
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return D->getKind() == ObjCMethod; }
static bool classof(const ObjCMethodDecl *D) { return true; }
@@ -263,9 +273,9 @@ public:
struct ObjCMethodList {
ObjCMethodDecl *Method;
ObjCMethodList *Next;
-
+
ObjCMethodList() {
- Method = 0;
+ Method = 0;
Next = 0;
}
ObjCMethodList(ObjCMethodDecl *M, ObjCMethodList *C) {
@@ -275,15 +285,14 @@ struct ObjCMethodList {
};
/// ObjCContainerDecl - Represents a container for method declarations.
-/// Current sub-classes are ObjCInterfaceDecl, ObjCCategoryDecl, and
-/// ObjCProtocolDecl.
-/// FIXME: Use for ObjC implementation decls.
+/// Current sub-classes are ObjCInterfaceDecl, ObjCCategoryDecl,
+/// ObjCProtocolDecl, and ObjCImplDecl.
///
class ObjCContainerDecl : public NamedDecl, public DeclContext {
SourceLocation AtEndLoc; // marks the end of the method container.
public:
- ObjCContainerDecl(Kind DK, DeclContext *DC, SourceLocation L,
+ ObjCContainerDecl(Kind DK, DeclContext *DC, SourceLocation L,
IdentifierInfo *Id)
: NamedDecl(DK, DC, L, Id), DeclContext(DK) {}
@@ -291,24 +300,24 @@ public:
// Iterator access to properties.
typedef specific_decl_iterator<ObjCPropertyDecl> prop_iterator;
- prop_iterator prop_begin() const {
+ prop_iterator prop_begin() const {
return prop_iterator(decls_begin());
}
- prop_iterator prop_end() const {
+ prop_iterator prop_end() const {
return prop_iterator(decls_end());
}
-
+
// Iterator access to instance/class methods.
typedef specific_decl_iterator<ObjCMethodDecl> method_iterator;
- method_iterator meth_begin() const {
+ method_iterator meth_begin() const {
return method_iterator(decls_begin());
}
- method_iterator meth_end() const {
+ method_iterator meth_end() const {
return method_iterator(decls_end());
}
- typedef filtered_decl_iterator<ObjCMethodDecl,
- &ObjCMethodDecl::isInstanceMethod>
+ typedef filtered_decl_iterator<ObjCMethodDecl,
+ &ObjCMethodDecl::isInstanceMethod>
instmeth_iterator;
instmeth_iterator instmeth_begin() const {
return instmeth_iterator(decls_begin());
@@ -317,8 +326,8 @@ public:
return instmeth_iterator(decls_end());
}
- typedef filtered_decl_iterator<ObjCMethodDecl,
- &ObjCMethodDecl::isClassMethod>
+ typedef filtered_decl_iterator<ObjCMethodDecl,
+ &ObjCMethodDecl::isClassMethod>
classmeth_iterator;
classmeth_iterator classmeth_begin() const {
return classmeth_iterator(decls_begin());
@@ -328,23 +337,28 @@ public:
}
// Get the local instance/class method declared in this interface.
- ObjCMethodDecl *getInstanceMethod(Selector Sel) const;
- ObjCMethodDecl *getClassMethod(Selector Sel) const;
+ ObjCMethodDecl *getMethod(Selector Sel, bool isInstance) const;
+ ObjCMethodDecl *getInstanceMethod(Selector Sel) const {
+ return getMethod(Sel, true/*isInstance*/);
+ }
+ ObjCMethodDecl *getClassMethod(Selector Sel) const {
+ return getMethod(Sel, false/*isInstance*/);
+ }
ObjCIvarDecl *getIvarDecl(IdentifierInfo *Id) const;
- ObjCMethodDecl *getMethod(Selector Sel, bool isInstance) const {
- return isInstance ? getInstanceMethod(Sel) : getClassMethod(Sel);
- }
-
ObjCPropertyDecl *FindPropertyDeclaration(IdentifierInfo *PropertyId) const;
// Marks the end of the container.
SourceLocation getAtEndLoc() const { return AtEndLoc; }
void setAtEndLoc(SourceLocation L) { AtEndLoc = L; }
-
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(getLocation(), getAtEndLoc());
+ }
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) {
- return D->getKind() >= ObjCContainerFirst &&
+ return D->getKind() >= ObjCContainerFirst &&
D->getKind() <= ObjCContainerLast;
}
static bool classof(const ObjCContainerDecl *D) { return true; }
@@ -360,11 +374,11 @@ public:
/// ObjCInterfaceDecl - Represents an ObjC class declaration. For example:
///
/// // MostPrimitive declares no super class (not particularly useful).
-/// @interface MostPrimitive
+/// @interface MostPrimitive
/// // no instance variables or methods.
/// @end
///
-/// // NSResponder inherits from NSObject & implements NSCoding (a protocol).
+/// // NSResponder inherits from NSObject & implements NSCoding (a protocol).
/// @interface NSResponder : NSObject <NSCoding>
/// { // instance variables are represented by ObjCIvarDecl.
/// id nextResponder; // nextResponder instance variable.
@@ -383,32 +397,32 @@ class ObjCInterfaceDecl : public ObjCContainerDecl {
/// 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.
@@ -416,16 +430,27 @@ public:
static ObjCInterfaceDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation atLoc,
- IdentifierInfo *Id,
+ IdentifierInfo *Id,
SourceLocation ClassLoc = SourceLocation(),
bool ForwardDecl = false,
bool isInternal = false);
- const ObjCList<ObjCProtocolDecl> &getReferencedProtocols() const {
- return ReferencedProtocols;
+ const ObjCList<ObjCProtocolDecl> &getReferencedProtocols() const {
+ return ReferencedProtocols;
}
-
+
+ ObjCImplementationDecl *getImplementation() const;
+ void setImplementation(ObjCImplementationDecl *ImplD);
+
ObjCCategoryDecl *FindCategoryDeclaration(IdentifierInfo *CategoryId) const;
+ // Get the local instance/class method declared in a category.
+ ObjCMethodDecl *getCategoryInstanceMethod(Selector Sel) const;
+ ObjCMethodDecl *getCategoryClassMethod(Selector Sel) const;
+ ObjCMethodDecl *getCategoryMethod(Selector Sel, bool isInstance) const {
+ return isInstance ? getInstanceMethod(Sel)
+ : getClassMethod(Sel);
+ }
+
typedef ObjCList<ObjCProtocolDecl>::iterator protocol_iterator;
protocol_iterator protocol_begin() const {return ReferencedProtocols.begin();}
protocol_iterator protocol_end() const { return ReferencedProtocols.end(); }
@@ -436,29 +461,34 @@ public:
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);
}
-
+
+ /// mergeClassExtensionProtocolList - Merge class extension's protocol list
+ /// into the protocol list for this class.
+ void mergeClassExtensionProtocolList(ObjCProtocolDecl *const* List, unsigned Num,
+ ASTContext &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) {
+ 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 {
@@ -470,7 +500,7 @@ public:
}
return false;
}
-
+
ObjCIvarDecl *lookupInstanceVariable(IdentifierInfo *IVarName,
ObjCInterfaceDecl *&ClassDeclared);
ObjCIvarDecl *lookupInstanceVariable(IdentifierInfo *IVarName) {
@@ -480,26 +510,41 @@ public:
// Lookup a method. First, we search locally. If a method isn't
// found, we search referenced protocols and class categories.
- ObjCMethodDecl *lookupInstanceMethod(Selector Sel);
- ObjCMethodDecl *lookupClassMethod(Selector Sel);
+ ObjCMethodDecl *lookupMethod(Selector Sel, bool isInstance) const;
+ ObjCMethodDecl *lookupInstanceMethod(Selector Sel) const {
+ return lookupMethod(Sel, true/*isInstance*/);
+ }
+ ObjCMethodDecl *lookupClassMethod(Selector Sel) const {
+ return lookupMethod(Sel, false/*isInstance*/);
+ }
ObjCInterfaceDecl *lookupInheritedClass(const IdentifierInfo *ICName);
+
+ // Lookup a method in the classes implementation hierarchy.
+ ObjCMethodDecl *lookupPrivateInstanceMethod(const Selector &Sel);
- // Location information, modeled after the Stmt API.
+ // 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; }
-
+
+ /// ClassImplementsProtocol - Checks that 'lProto' protocol
+ /// has been implemented in IDecl class, its super class or categories (if
+ /// lookupCategory is true).
+ bool ClassImplementsProtocol(ObjCProtocolDecl *lProto,
+ bool lookupCategory,
+ bool RHSIsQualifiedID = false);
+
// Low-level accessor
Type *getTypeForDecl() const { return TypeForDecl; }
void setTypeForDecl(Type *TD) const { TypeForDecl = TD; }
@@ -528,18 +573,19 @@ 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),
+ QualType T, DeclaratorInfo *DInfo, AccessControl ac, Expr *BW)
+ : FieldDecl(ObjCIvar, DC, L, Id, T, DInfo, BW, /*Mutable=*/false),
DeclAccess(ac) {}
-
+
public:
static ObjCIvarDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L,
IdentifierInfo *Id, QualType T,
+ DeclaratorInfo *DInfo,
AccessControl ac, Expr *BW = NULL);
-
+
void setAccessControl(AccessControl ac) { DeclAccess = ac; }
AccessControl getAccessControl() const { return AccessControl(DeclAccess); }
@@ -547,7 +593,7 @@ public:
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; }
@@ -556,21 +602,23 @@ private:
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) {}
-
+ : FieldDecl(ObjCAtDefsField, DC, L, Id, T,
+ /*DInfo=*/0, // FIXME: Do ObjCAtDefs have declarators ?
+ 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.
@@ -579,8 +627,8 @@ public:
};
/// 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++
+/// 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>
@@ -597,7 +645,7 @@ public:
///
/// 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,
+/// 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;
@@ -605,78 +653,83 @@ public:
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),
+ : ObjCContainerDecl(ObjCProtocol, DC, L, Id),
isForwardProtoDecl(true) {
}
-
+
virtual ~ObjCProtocolDecl() {}
-
+
public:
- static ObjCProtocolDecl *Create(ASTContext &C, DeclContext *DC,
+ 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 {
+
+ 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(Selector Sel);
- ObjCMethodDecl *lookupClassMethod(Selector Sel);
-
+ ObjCMethodDecl *lookupMethod(Selector Sel, bool isInstance) const;
+ ObjCMethodDecl *lookupInstanceMethod(Selector Sel) const {
+ return lookupMethod(Sel, true/*isInstance*/);
+ }
+ ObjCMethodDecl *lookupClassMethod(Selector Sel) const {
+ return lookupMethod(Sel, false/*isInstance*/);
+ }
+
bool isForwardDecl() const { return isForwardProtoDecl; }
void setForwardDecl(bool val) { isForwardProtoDecl = val; }
- // Location information, modeled after the Stmt API.
+ // 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,
+
+ 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,
+ ObjCInterfaceDecl *const *Elts = 0,
unsigned nElts = 0);
-
+
typedef ObjCList<ObjCInterfaceDecl>::iterator iterator;
iterator begin() const { return ForwardDecls.begin(); }
iterator end() const { return ForwardDecls.end(); }
@@ -686,33 +739,33 @@ public:
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);
+ ASTContext &C);
virtual ~ObjCForwardProtocolDecl() {}
-
+
public:
static ObjCForwardProtocolDecl *Create(ASTContext &C, DeclContext *DC,
- SourceLocation L,
+ 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(); }
@@ -731,7 +784,7 @@ public:
/// 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
+/// 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:
///
@@ -743,51 +796,54 @@ public:
/// 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)
+/// 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; }
-
+
+ ObjCCategoryImplDecl *getImplementation() const;
+ void setImplementation(ObjCCategoryImplDecl *ImplD);
+
/// 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 {
+
+ 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;
@@ -796,98 +852,67 @@ public:
NextClassCategory = ClassInterface->getCategoryList();
ClassInterface->setCategoryList(this);
}
- // Location information, modeled after the Stmt API.
+ // 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 ObjCImplDecl : public ObjCContainerDecl {
/// 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) {}
-
+ : ObjCContainerDecl(DK, DC, L,
+ classInterface? classInterface->getIdentifier() : 0),
+ ClassInterface(classInterface) {}
+
public:
virtual ~ObjCImplDecl() {}
-
+
const ObjCInterfaceDecl *getClassInterface() const { return ClassInterface; }
ObjCInterfaceDecl *getClassInterface() { return ClassInterface; }
- void setClassInterface(ObjCInterfaceDecl *IFace) { ClassInterface = IFace; }
+ void setClassInterface(ObjCInterfaceDecl *IFace);
- void addInstanceMethod(ObjCMethodDecl *method) {
+ void addInstanceMethod(ObjCMethodDecl *method) {
// FIXME: Context should be set correctly before we get here.
method->setLexicalDeclContext(this);
- addDecl(method);
+ addDecl(method);
}
- void addClassMethod(ObjCMethodDecl *method) {
+ void addClassMethod(ObjCMethodDecl *method) {
// FIXME: Context should be set correctly before we get here.
method->setLexicalDeclContext(this);
- addDecl(method);
+ addDecl(method);
}
-
- // Get the local instance/class method declared in this interface.
- ObjCMethodDecl *getInstanceMethod(Selector Sel) const;
- ObjCMethodDecl *getClassMethod(Selector Sel) const;
- ObjCMethodDecl *getMethod(Selector Sel, bool isInstance) const {
- return isInstance ? getInstanceMethod(Sel)
- : getClassMethod(Sel);
- }
-
+
void addPropertyImplementation(ObjCPropertyImplDecl *property);
-
+
ObjCPropertyImplDecl *FindPropertyImplDecl(IdentifierInfo *propertyId) const;
ObjCPropertyImplDecl *FindPropertyImplIvarDecl(IdentifierInfo *ivarId) const;
// Iterator access to properties.
typedef specific_decl_iterator<ObjCPropertyImplDecl> propimpl_iterator;
- propimpl_iterator propimpl_begin() const {
+ propimpl_iterator propimpl_begin() const {
return propimpl_iterator(decls_begin());
}
- propimpl_iterator propimpl_end() const {
+ propimpl_iterator propimpl_end() const {
return propimpl_iterator(decls_end());
}
- typedef filtered_decl_iterator<ObjCMethodDecl,
- &ObjCMethodDecl::isInstanceMethod>
- instmeth_iterator;
- instmeth_iterator instmeth_begin() const {
- return instmeth_iterator(decls_begin());
- }
- instmeth_iterator instmeth_end() const {
- return instmeth_iterator(decls_end());
- }
-
- typedef filtered_decl_iterator<ObjCMethodDecl,
- &ObjCMethodDecl::isClassMethod>
- classmeth_iterator;
- classmeth_iterator classmeth_begin() const {
- return classmeth_iterator(decls_begin());
- }
- classmeth_iterator classmeth_end() const {
- return classmeth_iterator(decls_end());
+ static bool classof(const Decl *D) {
+ return D->getKind() >= ObjCImplFirst && D->getKind() <= ObjCImplLast;
}
-
- // Location information, modeled after the Stmt API.
- SourceLocation getLocStart() const { return getLocation(); }
- SourceLocation getLocEnd() const { return EndLoc; }
- void setLocEnd(SourceLocation LE) { EndLoc = LE; };
+ static bool classof(const ObjCImplDecl *D) { return true; }
};
-
-/// 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
+
+/// 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)
@@ -909,34 +934,30 @@ 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;
+ IdentifierInfo *getIdentifier() const {
+ return Id;
}
void setIdentifier(IdentifierInfo *II) { Id = II; }
+ ObjCCategoryDecl *getCategoryClass() const;
+
/// 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
@@ -948,30 +969,30 @@ public:
/// @end
/// @endcode
///
-/// Typically, instance variables are specified in the class interface,
+/// 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 {
+class ObjCImplementationDecl : public ObjCImplDecl {
/// Implementation Class's super class.
ObjCInterfaceDecl *SuperClass;
-
- ObjCImplementationDecl(DeclContext *DC, SourceLocation L,
+
+ ObjCImplementationDecl(DeclContext *DC, SourceLocation L,
ObjCInterfaceDecl *classInterface,
ObjCInterfaceDecl *superDecl)
- : ObjCImplDecl(ObjCImplementation, DC, L, classInterface),
+ : ObjCImplDecl(ObjCImplementation, DC, L, classInterface),
SuperClass(superDecl){}
-public:
- static ObjCImplementationDecl *Create(ASTContext &C, DeclContext *DC,
- SourceLocation L,
+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();
+ IdentifierInfo *getIdentifier() const {
+ return getClassInterface()->getIdentifier();
}
/// getNameAsCString - Get the name of identifier for the class
@@ -989,41 +1010,35 @@ public:
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() const {
- return ivar_iterator(decls_begin());
+ ivar_iterator ivar_begin() const {
+ return ivar_iterator(decls_begin());
}
- ivar_iterator ivar_end() const {
+ ivar_iterator ivar_end() const {
return ivar_iterator(decls_end());
}
- unsigned ivar_size() const {
+ unsigned ivar_size() const {
return std::distance(ivar_begin(), ivar_end());
}
- bool ivar_empty() const {
+ bool ivar_empty() const {
return ivar_begin() == ivar_end();
}
-
+
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
+/// 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) {}
@@ -1035,12 +1050,12 @@ public:
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.
@@ -1050,13 +1065,13 @@ public:
class ObjCPropertyDecl : public NamedDecl {
public:
enum PropertyAttributeKind {
- OBJC_PR_noattr = 0x00,
- OBJC_PR_readonly = 0x01,
+ OBJC_PR_noattr = 0x00,
+ OBJC_PR_readonly = 0x01,
OBJC_PR_getter = 0x02,
- OBJC_PR_assign = 0x04,
- OBJC_PR_readwrite = 0x08,
+ OBJC_PR_assign = 0x04,
+ OBJC_PR_readwrite = 0x08,
OBJC_PR_retain = 0x10,
- OBJC_PR_copy = 0x20,
+ OBJC_PR_copy = 0x20,
OBJC_PR_nonatomic = 0x40,
OBJC_PR_setter = 0x80
};
@@ -1066,27 +1081,27 @@ public:
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,
+ ObjCPropertyDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
QualType T)
: NamedDecl(ObjCProperty, DC, L, Id), DeclType(T),
PropertyAttributes(OBJC_PR_noattr), PropertyImplementation(None),
- GetterName(Selector()),
+ GetterName(Selector()),
SetterName(Selector()),
GetterMethodDecl(0), SetterMethodDecl(0) , PropertyIvarDecl(0) {}
public:
- static ObjCPropertyDecl *Create(ASTContext &C, DeclContext *DC,
- SourceLocation L,
+ static ObjCPropertyDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L,
IdentifierInfo *Id, QualType T,
PropertyControl propControl = None);
QualType getType() const { return DeclType; }
@@ -1095,14 +1110,14 @@ public:
PropertyAttributeKind getPropertyAttributes() const {
return PropertyAttributeKind(PropertyAttributes);
}
- void setPropertyAttributes(PropertyAttributeKind PRVal) {
+ void setPropertyAttributes(PropertyAttributeKind PRVal) {
PropertyAttributes |= PRVal;
}
void makeitReadWriteAttribute(void) {
PropertyAttributes &= ~OBJC_PR_readonly;
PropertyAttributes |= OBJC_PR_readwrite;
- }
+ }
// Helper methods for accessing attributes.
@@ -1124,38 +1139,38 @@ public:
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
+/// ObjCPropertyImplDecl - Represents implementation declaration of a property
/// in a class or category implementation block. For example:
/// @synthesize prop1 = ivar1;
///
@@ -1174,21 +1189,24 @@ private:
ObjCIvarDecl *PropertyIvarDecl;
ObjCPropertyImplDecl(DeclContext *DC, SourceLocation atLoc, SourceLocation L,
- ObjCPropertyDecl *property,
- Kind PK,
+ ObjCPropertyDecl *property,
+ Kind PK,
ObjCIvarDecl *ivarDecl)
- : Decl(ObjCPropertyImpl, DC, L), AtLoc(atLoc),
+ : 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,
+ SourceLocation atLoc, SourceLocation L,
+ ObjCPropertyDecl *property,
+ Kind PK,
ObjCIvarDecl *ivarDecl);
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(AtLoc, getLocation());
+ }
SourceLocation getLocStart() const { return AtLoc; }
void setAtLoc(SourceLocation Loc) { AtLoc = Loc; }
@@ -1200,7 +1218,7 @@ public:
Kind getPropertyImplementation() const {
return PropertyIvarDecl ? Synthesize : Dynamic;
}
-
+
ObjCIvarDecl *getPropertyIvarDecl() const {
return PropertyIvarDecl;
}
@@ -1209,7 +1227,7 @@ public:
static bool classof(const Decl *D) {
return D->getKind() == ObjCPropertyImpl;
}
- static bool classof(const ObjCPropertyImplDecl *D) { return true; }
+ static bool classof(const ObjCPropertyImplDecl *D) { return true; }
};
} // end namespace clang
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h
index 5d0fe15..8d44676 100644
--- a/include/clang/AST/DeclTemplate.h
+++ b/include/clang/AST/DeclTemplate.h
@@ -49,38 +49,38 @@ class TemplateParameterList {
unsigned NumParams;
TemplateParameterList(SourceLocation TemplateLoc, SourceLocation LAngleLoc,
- Decl **Params, unsigned NumParams,
+ NamedDecl **Params, unsigned NumParams,
SourceLocation RAngleLoc);
public:
- static TemplateParameterList *Create(ASTContext &C,
+ static TemplateParameterList *Create(ASTContext &C,
SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
- Decl **Params,
+ NamedDecl **Params,
unsigned NumParams,
SourceLocation RAngleLoc);
/// iterator - Iterates through the template parameters in this list.
- typedef Decl** iterator;
+ typedef NamedDecl** iterator;
/// const_iterator - Iterates through the template parameters in this list.
- typedef Decl* const* const_iterator;
+ typedef NamedDecl* const* const_iterator;
- iterator begin() { return reinterpret_cast<Decl **>(this + 1); }
+ iterator begin() { return reinterpret_cast<NamedDecl **>(this + 1); }
const_iterator begin() const {
- return reinterpret_cast<Decl * const *>(this + 1);
+ return reinterpret_cast<NamedDecl * const *>(this + 1);
}
iterator end() { return begin() + NumParams; }
const_iterator end() const { return begin() + NumParams; }
unsigned size() const { return NumParams; }
- Decl* getParam(unsigned Idx) {
+ NamedDecl* getParam(unsigned Idx) {
assert(Idx < size() && "Template parameter index out-of-range");
return begin()[Idx];
}
- const Decl* getParam(unsigned Idx) const {
+ const NamedDecl* getParam(unsigned Idx) const {
assert(Idx < size() && "Template parameter index out-of-range");
return begin()[Idx];
}
@@ -115,10 +115,10 @@ class TemplateArgument {
bool CopyArgs;
} Args;
};
-
+
/// \brief Location of the beginning of this template argument.
SourceLocation StartLoc;
-
+
public:
/// \brief The type of template argument we're storing.
enum ArgKind {
@@ -133,21 +133,21 @@ public:
/// The template argument is a value- or type-dependent expression
/// stored in an Expr*.
Expression = 4,
-
+
/// The template argument is actually a parameter pack. Arguments are stored
/// in the Args struct.
Pack = 5
} Kind;
-
+
/// \brief Construct an empty, invalid template argument.
TemplateArgument() : TypeOrValue(0), StartLoc(), Kind(Null) { }
-
+
/// \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.
@@ -156,7 +156,7 @@ public:
TypeOrValue = reinterpret_cast<uintptr_t>(D);
StartLoc = Loc;
}
-
+
/// \brief Construct an integral constant template argument.
TemplateArgument(SourceLocation Loc, const llvm::APSInt &Value,
QualType Type)
@@ -165,14 +165,14 @@ public:
Integer.Type = Type.getAsOpaquePtr();
StartLoc = Loc;
}
-
- /// \brief Construct a template argument that is an expression.
+
+ /// \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) {
@@ -188,27 +188,27 @@ public:
TypeOrValue = Other.TypeOrValue;
StartLoc = Other.StartLoc;
}
-
+
TemplateArgument& operator=(const TemplateArgument& Other) {
// FIXME: Does not provide the strong guarantee for exception
// safety.
using llvm::APSInt;
-
+
// FIXME: Handle Packs
assert(Kind != Pack && "FIXME: Handle packs");
assert(Other.Kind != Pack && "FIXME: Handle packs");
-
+
if (Kind == Other.Kind && Kind == Integral) {
// Copy integral values.
*this->getAsIntegral() = *Other.getAsIntegral();
- Integer.Type = Other.Integer.Type;
+ 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;
@@ -216,133 +216,131 @@ public:
TypeOrValue = Other.TypeOrValue;
}
StartLoc = Other.StartLoc;
-
+
return *this;
}
-
+
~TemplateArgument() {
using llvm::APSInt;
-
+
if (Kind == Integral)
getAsIntegral()->~APSInt();
else if (Kind == Pack && Args.CopyArgs)
delete[] Args.Args;
}
-
+
/// \brief Return the kind of stored template argument.
ArgKind getKind() const { return Kind; }
-
+
/// \brief Determine whether this template argument has no value.
bool isNull() const { return Kind == Null; }
-
+
/// \brief Retrieve the template argument as a type.
QualType getAsType() const {
if (Kind != Type)
return QualType();
-
- return QualType::getFromOpaquePtr(
- reinterpret_cast<void*>(TypeOrValue));
+
+ 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);
}
-
+
void setIntegralType(QualType T) {
- assert(Kind == Integral &&
+ assert(Kind == Integral &&
"Cannot set the integral type of a non-integral template argument");
Integer.Type = T.getAsOpaquePtr();
};
-
+
/// \brief Retrieve the template argument as an expression.
Expr *getAsExpr() const {
if (Kind != Expression)
return 0;
-
+
return reinterpret_cast<Expr *>(TypeOrValue);
}
-
+
/// \brief Iterator that traverses the elements of a template argument pack.
typedef const TemplateArgument * pack_iterator;
-
- /// \brief Iterator referencing the first argument of a template argument
+
+ /// \brief Iterator referencing the first argument of a template argument
/// pack.
pack_iterator pack_begin() const {
assert(Kind == Pack);
return Args.Args;
}
-
+
/// \brief Iterator referencing one past the last argument of a template
/// argument pack.
pack_iterator pack_end() const {
assert(Kind == Pack);
return Args.Args + Args.NumArgs;
}
-
+
/// \brief The number of template arguments in the given template argument
/// pack.
unsigned pack_size() const {
assert(Kind == Pack);
return Args.NumArgs;
}
-
+
/// \brief Retrieve the location where the template argument starts.
SourceLocation getLocation() const { return StartLoc; }
-
+
/// \brief Construct a template argument pack.
void setArgumentPack(TemplateArgument *Args, unsigned NumArgs, bool CopyArgs);
-
+
/// \brief Used to insert TemplateArguments into FoldingSets.
- void Profile(llvm::FoldingSetNodeID &ID) const {
+ void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context) const {
ID.AddInteger(Kind);
switch (Kind) {
case Null:
break;
-
+
case Type:
getAsType().Profile(ID);
break;
-
+
case Declaration:
- ID.AddPointer(getAsDecl()); // FIXME: Must be canonical!
+ ID.AddPointer(getAsDecl()? getAsDecl()->getCanonicalDecl() : 0);
break;
-
+
case Integral:
getAsIntegral()->Profile(ID);
getIntegralType().Profile(ID);
break;
-
+
case Expression:
- // FIXME: We need a canonical representation of expressions.
- ID.AddPointer(getAsExpr());
+ getAsExpr()->Profile(ID, Context, true);
break;
-
+
case Pack:
ID.AddInteger(Args.NumArgs);
for (unsigned I = 0; I != Args.NumArgs; ++I)
- Args.Args[I].Profile(ID);
+ Args.Args[I].Profile(ID, Context);
}
}
};
@@ -352,47 +350,47 @@ class TemplateArgumentListBuilder {
TemplateArgument *StructuredArgs;
unsigned MaxStructuredArgs;
unsigned NumStructuredArgs;
-
+
TemplateArgument *FlatArgs;
unsigned MaxFlatArgs;
unsigned NumFlatArgs;
-
+
bool AddingToPack;
unsigned PackBeginIndex;
-
+
public:
TemplateArgumentListBuilder(const TemplateParameterList *Parameters,
unsigned NumTemplateArgs)
- : StructuredArgs(0), MaxStructuredArgs(Parameters->size()),
- NumStructuredArgs(0), FlatArgs(0),
+ : StructuredArgs(0), MaxStructuredArgs(Parameters->size()),
+ NumStructuredArgs(0), FlatArgs(0),
MaxFlatArgs(std::max(MaxStructuredArgs, NumTemplateArgs)), NumFlatArgs(0),
AddingToPack(false), PackBeginIndex(0) { }
-
+
void Append(const TemplateArgument& Arg);
void BeginPack();
void EndPack();
-
+
void ReleaseArgs();
-
- unsigned flatSize() const {
+
+ unsigned flatSize() const {
return NumFlatArgs;
}
const TemplateArgument *getFlatArguments() const {
return FlatArgs;
}
-
+
unsigned structuredSize() const {
// If we don't have any structured args, just reuse the flat size.
if (!StructuredArgs)
return flatSize();
-
+
return NumStructuredArgs;
}
const TemplateArgument *getStructuredArguments() const {
// If we don't have any structured args, just reuse the flat args.
if (!StructuredArgs)
return getFlatArguments();
-
+
return StructuredArgs;
}
};
@@ -408,44 +406,47 @@ class TemplateArgumentList {
/// The integer value will be non-zero to indicate that this
/// template argument list does not own the pointer.
llvm::PointerIntPair<const TemplateArgument *, 1> FlatArguments;
-
+
/// \brief The number of template arguments in this template
/// argument list.
unsigned NumFlatArguments;
-
+
llvm::PointerIntPair<const TemplateArgument *, 1> StructuredArguments;
unsigned NumStructuredArguments;
-
+
public:
TemplateArgumentList(ASTContext &Context,
TemplateArgumentListBuilder &Builder,
bool TakeArgs);
+
+ /// \brief Produces a shallow copy of the given template argument list
+ TemplateArgumentList(const TemplateArgumentList &Other);
~TemplateArgumentList();
-
+
/// \brief Retrieve the template argument at a given index.
- const TemplateArgument &get(unsigned Idx) const {
+ const TemplateArgument &get(unsigned Idx) const {
assert(Idx < NumFlatArguments && "Invalid template argument index");
return getFlatArgumentList()[Idx];
}
-
+
/// \brief Retrieve the template argument at a given index.
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 NumFlatArguments; }
-
+
/// \brief Retrieve the number of template arguments in the
/// flattened template argument list.
unsigned flat_size() const { return NumFlatArguments; }
-
+
/// \brief Retrieve the flattened template argument list.
- const TemplateArgument *getFlatArgumentList() const {
+ const TemplateArgument *getFlatArgumentList() const {
return FlatArguments.getPointer();
}
};
-
+
//===----------------------------------------------------------------------===//
// Kinds of Templates
//===----------------------------------------------------------------------===//
@@ -459,15 +460,13 @@ protected:
// This is probably never used.
TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L,
DeclarationName Name)
- : NamedDecl(DK, DC, L, Name), TemplatedDecl(0), TemplateParams(0)
- { }
+ : 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)
- { }
+ : 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,
@@ -499,82 +498,161 @@ protected:
NamedDecl *TemplatedDecl;
TemplateParameterList* TemplateParams;
};
-
-/// \brief Provides information about a function template specialization,
+
+/// \brief Provides information about a function template specialization,
/// which is a FunctionDecl that has been explicitly specialization or
/// instantiated from a function template.
class FunctionTemplateSpecializationInfo : public llvm::FoldingSetNode {
public:
- /// \brief The function template specialization that this structure
+ /// \brief The function template specialization that this structure
/// describes.
FunctionDecl *Function;
-
- /// \brief The function template from which this function template
+
+ /// \brief The function template from which this function template
/// specialization was generated.
///
- /// The bit will be 0 for an implicit instantiation, 1 for an explicit
- /// specialization.
- llvm::PointerIntPair<FunctionTemplateDecl *, 1> Template;
-
+ /// The two bits are contain the top 4 values of TemplateSpecializationKind.
+ llvm::PointerIntPair<FunctionTemplateDecl *, 2> Template;
+
/// \brief The template arguments used to produce the function template
/// specialization from the function template.
const TemplateArgumentList *TemplateArguments;
+
+ /// \brief The point at which this function template specialization was
+ /// first instantiated.
+ SourceLocation PointOfInstantiation;
/// \brief Retrieve the template from which this function was specialized.
FunctionTemplateDecl *getTemplate() const { return Template.getPointer(); }
+
+ /// \brief Determine what kind of template specialization this is.
+ TemplateSpecializationKind getTemplateSpecializationKind() const {
+ return (TemplateSpecializationKind)(Template.getInt() + 1);
+ }
+
+ /// \brief Set the template specialization kind.
+ void setTemplateSpecializationKind(TemplateSpecializationKind TSK) {
+ assert(TSK != TSK_Undeclared &&
+ "Cannot encode TSK_Undeclared for a function template specialization");
+ Template.setInt(TSK - 1);
+ }
+
+ /// \brief Retrieve the first point of instantiation of this function
+ /// template specialization.
+ ///
+ /// The point of instantiation may be an invalid source location if this
+ /// function has yet to be instantiated.
+ SourceLocation getPointOfInstantiation() const {
+ return PointOfInstantiation;
+ }
- /// \brief Determine whether this is an explicit specialization.
- bool isExplicitSpecialization() const { return Template.getInt(); }
-
- /// \brief Set whether this is an explicit specialization or an implicit
- /// instantiation.
- void setExplicitSpecialization(bool ES) {
- Template.setInt(ES);
+ /// \brief Set the (first) point of instantiation of this function template
+ /// specialization.
+ void setPointOfInstantiation(SourceLocation POI) {
+ PointOfInstantiation = POI;
}
void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, TemplateArguments->getFlatArgumentList(),
- TemplateArguments->flat_size());
+ Profile(ID, TemplateArguments->getFlatArgumentList(),
+ TemplateArguments->flat_size(),
+ Function->getASTContext());
}
-
- static void
- Profile(llvm::FoldingSetNodeID &ID, const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs) {
+
+ static void
+ Profile(llvm::FoldingSetNodeID &ID, const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs, ASTContext &Context) {
ID.AddInteger(NumTemplateArgs);
for (unsigned Arg = 0; Arg != NumTemplateArgs; ++Arg)
- TemplateArgs[Arg].Profile(ID);
- }
+ TemplateArgs[Arg].Profile(ID, Context);
+ }
+};
+
+/// \brief Provides information a specialization of a member of a class
+/// template, which may be a member function, static data member, or
+/// member class.
+class MemberSpecializationInfo {
+ // The member declaration from which this member was instantiated, and the
+ // manner in which the instantiation occurred (in the lower two bits).
+ llvm::PointerIntPair<NamedDecl *, 2> MemberAndTSK;
+
+ // The point at which this member was first instantiated.
+ SourceLocation PointOfInstantiation;
+
+public:
+ explicit
+ MemberSpecializationInfo(NamedDecl *IF, TemplateSpecializationKind TSK)
+ : MemberAndTSK(IF, TSK - 1), PointOfInstantiation() {
+ assert(TSK != TSK_Undeclared &&
+ "Cannot encode undeclared template specializations for members");
+ }
+
+ /// \brief Retrieve the member declaration from which this member was
+ /// instantiated.
+ NamedDecl *getInstantiatedFrom() const { return MemberAndTSK.getPointer(); }
+
+ /// \brief Determine what kind of template specialization this is.
+ TemplateSpecializationKind getTemplateSpecializationKind() const {
+ return (TemplateSpecializationKind)(MemberAndTSK.getInt() + 1);
+ }
+
+ /// \brief Set the template specialization kind.
+ void setTemplateSpecializationKind(TemplateSpecializationKind TSK) {
+ assert(TSK != TSK_Undeclared &&
+ "Cannot encode undeclared template specializations for members");
+ MemberAndTSK.setInt(TSK - 1);
+ }
+
+ /// \brief Retrieve the first point of instantiation of this member.
+ /// If the point of instantiation is an invalid location, then this member
+ /// has not yet been instantiated.
+ SourceLocation getPointOfInstantiation() const {
+ return PointOfInstantiation;
+ }
+
+ /// \brief Set the first point of instantiation.
+ void setPointOfInstantiation(SourceLocation POI) {
+ PointOfInstantiation = POI;
+ }
};
/// Declaration of a template function.
-class FunctionTemplateDecl : public TemplateDecl {
+class FunctionTemplateDecl : public TemplateDecl {
protected:
/// \brief Data that is common to all of the declarations of a given
/// function template.
struct Common {
+ Common() : InstantiatedFromMember(0, false) { }
+
/// \brief The function template specializations for this function
/// template, including explicit specializations and instantiations.
llvm::FoldingSet<FunctionTemplateSpecializationInfo> Specializations;
+
+ /// \brief The member function template from which this was most
+ /// directly instantiated (or null).
+ ///
+ /// The boolean value indicates whether this member function template
+ /// was explicitly specialized.
+ llvm::PointerIntPair<FunctionTemplateDecl*, 1, bool> InstantiatedFromMember;
};
-
+
/// \brief A pointer to the previous declaration (if this is a redeclaration)
/// or to the data that is common to all declarations of this function
/// template.
llvm::PointerUnion<Common*, FunctionTemplateDecl*> CommonOrPrev;
-
- /// \brief Retrieves the "common" pointer shared by all
+
+ /// \brief Retrieves the "common" pointer shared by all
/// (re-)declarations of the same function template. Calling this routine
/// may implicitly allocate memory for the common pointer.
Common *getCommonPtr();
-
+
FunctionTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name,
TemplateParameterList *Params, NamedDecl *Decl)
: TemplateDecl(FunctionTemplate, DC, L, Name, Params, Decl),
CommonOrPrev((Common*)0) { }
-
+
public:
void Destroy(ASTContext &C);
-
+
/// Get the underlying function declaration of the template.
FunctionDecl *getTemplatedDecl() const {
return static_cast<FunctionDecl*>(TemplatedDecl);
@@ -585,7 +663,7 @@ public:
llvm::FoldingSet<FunctionTemplateSpecializationInfo> &getSpecializations() {
return getCommonPtr()->Specializations;
}
-
+
/// \brief Retrieve the previous declaration of this function template, or
/// NULL if no such declaration exists.
const FunctionTemplateDecl *getPreviousDeclaration() const {
@@ -597,12 +675,71 @@ public:
FunctionTemplateDecl *getPreviousDeclaration() {
return CommonOrPrev.dyn_cast<FunctionTemplateDecl*>();
}
-
+
/// \brief Set the previous declaration of this function template.
void setPreviousDeclaration(FunctionTemplateDecl *Prev) {
if (Prev)
CommonOrPrev = Prev;
}
+
+ virtual FunctionTemplateDecl *getCanonicalDecl();
+
+ /// \brief Retrieve the member function template that this function template
+ /// was instantiated from.
+ ///
+ /// This routine will return non-NULL for member function templates of
+ /// class templates. For example, given:
+ ///
+ /// \code
+ /// template <typename T>
+ /// struct X {
+ /// template <typename U> void f();
+ /// };
+ /// \endcode
+ ///
+ /// X<int>::A<float> is a CXXMethodDecl (whose parent is X<int>, a
+ /// ClassTemplateSpecializationDecl) for which getPrimaryTemplate() will
+ /// return X<int>::f, a FunctionTemplateDecl (whose parent is again
+ /// X<int>) for which getInstantiatedFromMemberTemplate() will return
+ /// X<T>::f, a FunctionTemplateDecl (whose parent is X<T>, a
+ /// ClassTemplateDecl).
+ ///
+ /// \returns NULL if this is not an instantiation of a member function
+ /// template.
+ FunctionTemplateDecl *getInstantiatedFromMemberTemplate() {
+ return getCommonPtr()->InstantiatedFromMember.getPointer();
+ }
+
+ void setInstantiatedFromMemberTemplate(FunctionTemplateDecl *FTD) {
+ assert(!getCommonPtr()->InstantiatedFromMember.getPointer());
+ getCommonPtr()->InstantiatedFromMember.setPointer(FTD);
+ }
+
+ /// \brief Determines whether this template was a specialization of a
+ /// member template.
+ ///
+ /// In the following example, the function template \c X<int>::f is a
+ /// member specialization.
+ ///
+ /// \code
+ /// template<typename T>
+ /// struct X {
+ /// template<typename U> void f(T, U);
+ /// };
+ ///
+ /// template<> template<typename T>
+ /// void X<int>::f(int, T);
+ /// \endcode
+ bool isMemberSpecialization() {
+ return getCommonPtr()->InstantiatedFromMember.getInt();
+ }
+
+ /// \brief Note that this member template is a specialization.
+ void setMemberSpecialization() {
+ assert(getCommonPtr()->InstantiatedFromMember.getPointer() &&
+ "Only member templates can be member template specializations");
+ getCommonPtr()->InstantiatedFromMember.setInt(true);
+ }
/// Create a template function node.
static FunctionTemplateDecl *Create(ASTContext &C, DeclContext *DC,
@@ -629,8 +766,7 @@ public:
/// 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
-{
+class TemplateParmPosition {
protected:
// FIXME: This should probably never be called, but it's here as
TemplateParmPosition()
@@ -652,7 +788,7 @@ public:
/// Get the position of the template parameter within its parameter list.
unsigned getPosition() const { return Position; }
-
+
/// Get the index of the template parameter within its parameter list.
unsigned getIndex() const { return Position; }
};
@@ -681,10 +817,10 @@ class TemplateTypeParmDecl : public TypeDecl {
/// \brief The default template argument, if any.
QualType DefaultArgument;
- TemplateTypeParmDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
+ TemplateTypeParmDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
bool Typename, QualType Type, bool ParameterPack)
: TypeDecl(TemplateTypeParm, DC, L, Id), Typename(Typename),
- InheritedDefault(false), ParameterPack(ParameterPack), DefaultArgument() {
+ InheritedDefault(false), ParameterPack(ParameterPack), DefaultArgument() {
TypeForDecl = Type.getTypePtr();
}
@@ -745,21 +881,20 @@ class NonTypeTemplateParmDecl
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)
+ DeclaratorInfo *DInfo)
+ : VarDecl(NonTypeTemplateParm, DC, L, Id, T, DInfo, VarDecl::None),
+ 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());
+ unsigned P, IdentifierInfo *Id, QualType T, DeclaratorInfo *DInfo);
using TemplateParmPosition::getDepth;
using TemplateParmPosition::getPosition;
using TemplateParmPosition::getIndex;
-
+
/// \brief Determine whether this template parameter has a default
/// argument.
bool hasDefaultArgument() const { return DefaultArgument; }
@@ -811,7 +946,7 @@ public:
using TemplateParmPosition::getDepth;
using TemplateParmPosition::getPosition;
using TemplateParmPosition::getIndex;
-
+
/// \brief Determine whether this template parameter has a default
/// argument.
bool hasDefaultArgument() const { return DefaultArgument; }
@@ -834,24 +969,6 @@ public:
static bool classof(const TemplateTemplateParmDecl *D) { return true; }
};
-// \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.
///
@@ -861,28 +978,47 @@ enum TemplateSpecializationKind {
///
/// \code
/// template<typename T> class array;
-///
-/// template<>
+///
+/// template<>
/// class array<bool> { }; // class template specialization array<bool>
/// \endcode
-class ClassTemplateSpecializationDecl
+class ClassTemplateSpecializationDecl
: public CXXRecordDecl, public llvm::FoldingSetNode {
+
+ /// \brief Structure that stores information about a class template
+ /// specialization that was instantiated from a class template partial
+ /// specialization.
+ struct SpecializedPartialSpecialization {
+ /// \brief The class template partial specialization from which this
+ /// class template specialization was instantiated.
+ ClassTemplatePartialSpecializationDecl *PartialSpecialization;
+
+ /// \brief The template argument list deduced for the class template
+ /// partial specialization itself.
+ TemplateArgumentList *TemplateArgs;
+ };
+
/// \brief The template that this specialization specializes
- ClassTemplateDecl *SpecializedTemplate;
+ llvm::PointerUnion<ClassTemplateDecl *, SpecializedPartialSpecialization *>
+ SpecializedTemplate;
/// \brief The template arguments used to describe this specialization.
TemplateArgumentList TemplateArgs;
+ /// \brief The point where this template was instantiated (if any)
+ SourceLocation PointOfInstantiation;
+
/// \brief The kind of specialization this declaration refers to.
/// Really a value of type TemplateSpecializationKind.
- unsigned SpecializationKind : 2;
+ unsigned SpecializationKind : 3;
protected:
ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK,
DeclContext *DC, SourceLocation L,
ClassTemplateDecl *SpecializedTemplate,
- TemplateArgumentListBuilder &Builder);
-
+ TemplateArgumentListBuilder &Builder,
+ ClassTemplateSpecializationDecl *PrevDecl);
+
public:
static ClassTemplateSpecializationDecl *
Create(ASTContext &Context, DeclContext *DC, SourceLocation L,
@@ -890,12 +1026,18 @@ public:
TemplateArgumentListBuilder &Builder,
ClassTemplateSpecializationDecl *PrevDecl);
+ virtual void Destroy(ASTContext& C);
+
+ virtual void getNameForDiagnostic(std::string &S,
+ const PrintingPolicy &Policy,
+ bool Qualified) const;
+
/// \brief Retrieve the template that this specialization specializes.
- ClassTemplateDecl *getSpecializedTemplate() const {
- return SpecializedTemplate;
- }
+ ClassTemplateDecl *getSpecializedTemplate() const;
- const TemplateArgumentList &getTemplateArgs() const {
+ /// \brief Retrieve the template arguments of the class template
+ /// specialization.
+ const TemplateArgumentList &getTemplateArgs() const {
return TemplateArgs;
}
@@ -909,6 +1051,67 @@ public:
SpecializationKind = TSK;
}
+ /// \brief Get the point of instantiation (if any), or null if none.
+ SourceLocation getPointOfInstantiation() const {
+ return PointOfInstantiation;
+ }
+
+ void setPointOfInstantiation(SourceLocation Loc) {
+ assert(Loc.isValid() && "point of instantiation must be valid!");
+ PointOfInstantiation = Loc;
+ }
+
+ /// \brief If this class template specialization is an instantiation of
+ /// a template (rather than an explicit specialization), return the
+ /// class template or class template partial specialization from which it
+ /// was instantiated.
+ llvm::PointerUnion<ClassTemplateDecl *,
+ ClassTemplatePartialSpecializationDecl *>
+ getInstantiatedFrom() const {
+ if (getSpecializationKind() != TSK_ImplicitInstantiation &&
+ getSpecializationKind() != TSK_ExplicitInstantiationDefinition &&
+ getSpecializationKind() != TSK_ExplicitInstantiationDeclaration)
+ return (ClassTemplateDecl*)0;
+
+ if (SpecializedPartialSpecialization *PartialSpec
+ = SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization*>())
+ return PartialSpec->PartialSpecialization;
+
+ return const_cast<ClassTemplateDecl*>(
+ SpecializedTemplate.get<ClassTemplateDecl*>());
+ }
+
+ /// \brief Retrieve the set of template arguments that should be used
+ /// to instantiate members of the class template or class template partial
+ /// specialization from which this class template specialization was
+ /// instantiated.
+ ///
+ /// \returns For a class template specialization instantiated from the primary
+ /// template, this function will return the same template arguments as
+ /// getTemplateArgs(). For a class template specialization instantiated from
+ /// a class template partial specialization, this function will return the
+ /// deduced template arguments for the class template partial specialization
+ /// itself.
+ const TemplateArgumentList &getTemplateInstantiationArgs() const {
+ if (SpecializedPartialSpecialization *PartialSpec
+ = SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization*>())
+ return *PartialSpec->TemplateArgs;
+
+ return getTemplateArgs();
+ }
+
+ /// \brief Note that this class template specialization is actually an
+ /// instantiation of the given class template partial specialization whose
+ /// template arguments have been deduced.
+ void setInstantiationOf(ClassTemplatePartialSpecializationDecl *PartialSpec,
+ TemplateArgumentList *TemplateArgs) {
+ SpecializedPartialSpecialization *PS
+ = new (getASTContext()) SpecializedPartialSpecialization();
+ PS->PartialSpecialization = PartialSpec;
+ PS->TemplateArgs = TemplateArgs;
+ SpecializedTemplate = PS;
+ }
+
/// \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) {
@@ -916,18 +1119,19 @@ public:
}
void Profile(llvm::FoldingSetNodeID &ID) const {
- Profile(ID, TemplateArgs.getFlatArgumentList(), TemplateArgs.flat_size());
+ Profile(ID, TemplateArgs.getFlatArgumentList(), TemplateArgs.flat_size(),
+ getASTContext());
}
- static void
- Profile(llvm::FoldingSetNodeID &ID, const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs) {
+ static void
+ Profile(llvm::FoldingSetNodeID &ID, const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs, ASTContext &Context) {
ID.AddInteger(NumTemplateArgs);
for (unsigned Arg = 0; Arg != NumTemplateArgs; ++Arg)
- TemplateArgs[Arg].Profile(ID);
+ TemplateArgs[Arg].Profile(ID, Context);
}
- static bool classof(const Decl *D) {
+ static bool classof(const Decl *D) {
return D->getKind() == ClassTemplateSpecialization ||
D->getKind() == ClassTemplatePartialSpecialization;
}
@@ -941,19 +1145,21 @@ public:
}
};
-class ClassTemplatePartialSpecializationDecl
- : public ClassTemplateSpecializationDecl
-{
- /// \brief The list of template parameters
+class ClassTemplatePartialSpecializationDecl
+ : public ClassTemplateSpecializationDecl {
+ /// \brief The list of template parameters
TemplateParameterList* TemplateParams;
ClassTemplatePartialSpecializationDecl(ASTContext &Context,
DeclContext *DC, SourceLocation L,
TemplateParameterList *Params,
ClassTemplateDecl *SpecializedTemplate,
- TemplateArgumentListBuilder &Builder)
- : ClassTemplateSpecializationDecl(Context, ClassTemplatePartialSpecialization,
- DC, L, SpecializedTemplate, Builder),
+ TemplateArgumentListBuilder &Builder,
+ ClassTemplatePartialSpecializationDecl *PrevDecl)
+ : ClassTemplateSpecializationDecl(Context,
+ ClassTemplatePartialSpecialization,
+ DC, L, SpecializedTemplate, Builder,
+ PrevDecl),
TemplateParams(Params) { }
public:
@@ -971,7 +1177,7 @@ public:
// FIXME: Add Profile support!
- static bool classof(const Decl *D) {
+ static bool classof(const Decl *D) {
return D->getKind() == ClassTemplatePartialSpecialization;
}
@@ -986,29 +1192,41 @@ protected:
/// \brief Data that is common to all of the declarations of a given
/// class template.
struct Common {
+ Common() : InstantiatedFromMember(0, 0) {}
+
/// \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>
+ llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>
PartialSpecializations;
/// \brief The injected-class-name type for this class template.
QualType InjectedClassNameType;
+
+ /// \brief The templated member class from which this was most
+ /// directly instantiated (or null).
+ ///
+ /// The boolean value indicates whether this member class template
+ /// was explicitly specialized.
+ llvm::PointerIntPair<ClassTemplateDecl *, 1, bool> InstantiatedFromMember;
};
+ // FIXME: Combine PreviousDeclaration with CommonPtr, as in
+ // FunctionTemplateDecl.
+
/// \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)
@@ -1028,6 +1246,8 @@ public:
return PreviousDeclaration;
}
+ virtual ClassTemplateDecl *getCanonicalDecl();
+
/// Create a class template node.
static ClassTemplateDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
@@ -1048,6 +1268,16 @@ public:
return CommonPtr->PartialSpecializations;
}
+ /// \brief Find a class template partial specialization with the given
+ /// type T.
+ ///
+ /// \brief A dependent type that names a specialization of this class
+ /// template.
+ ///
+ /// \returns the class template partial specialization that exactly matches
+ /// the type \p T, or NULL if no such partial specialization exists.
+ ClassTemplatePartialSpecializationDecl *findPartialSpecialization(QualType T);
+
/// \brief Retrieve the type of the injected-class-name for this
/// class template.
///
@@ -1064,6 +1294,61 @@ public:
/// \endcode
QualType getInjectedClassNameType(ASTContext &Context);
+ /// \brief Retrieve the member class template that this class template was
+ /// derived from.
+ ///
+ /// This routine will return non-NULL for templated member classes of
+ /// class templates. For example, given:
+ ///
+ /// \code
+ /// template <typename T>
+ /// struct X {
+ /// template <typename U> struct A {};
+ /// };
+ /// \endcode
+ ///
+ /// X<int>::A<float> is a ClassTemplateSpecializationDecl (whose parent
+ /// is X<int>, also a CTSD) for which getSpecializedTemplate() will
+ /// return X<int>::A<U>, a TemplateClassDecl (whose parent is again
+ /// X<int>) for which getInstantiatedFromMemberTemplate() will return
+ /// X<T>::A<U>, a TemplateClassDecl (whose parent is X<T>, also a TCD).
+ ///
+ /// \returns null if this is not an instantiation of a member class template.
+ ClassTemplateDecl *getInstantiatedFromMemberTemplate() const {
+ return CommonPtr->InstantiatedFromMember.getPointer();
+ }
+
+ void setInstantiatedFromMemberTemplate(ClassTemplateDecl *CTD) {
+ assert(!CommonPtr->InstantiatedFromMember.getPointer());
+ CommonPtr->InstantiatedFromMember.setPointer(CTD);
+ }
+
+ /// \brief Determines whether this template was a specialization of a
+ /// member template.
+ ///
+ /// In the following example, the member template \c X<int>::Inner is a
+ /// member specialization.
+ ///
+ /// \code
+ /// template<typename T>
+ /// struct X {
+ /// template<typename U> struct Inner;
+ /// };
+ ///
+ /// template<> template<typename T>
+ /// struct X<int>::Inner { /* ... */ };
+ /// \endcode
+ bool isMemberSpecialization() {
+ return CommonPtr->InstantiatedFromMember.getInt();
+ }
+
+ /// \brief Note that this member template is a specialization.
+ void setMemberSpecialization() {
+ assert(CommonPtr->InstantiatedFromMember.getPointer() &&
+ "Only member templates can be member template specializations");
+ CommonPtr->InstantiatedFromMember.setInt(true);
+ }
+
// Implement isa/cast/dyncast support
static bool classof(const Decl *D)
{ return D->getKind() == ClassTemplate; }
@@ -1073,8 +1358,87 @@ public:
virtual void Destroy(ASTContext& C);
};
+/// Declaration of a friend template. For example:
+///
+/// template <typename T> class A {
+/// friend class MyVector<T>; // not a friend template
+/// template <typename U> friend class B; // friend template
+/// template <typename U> friend class Foo<T>::Nested; // friend template
+class FriendTemplateDecl : public Decl {
+public:
+ typedef llvm::PointerUnion<NamedDecl*,Type*> FriendUnion;
+
+private:
+ // The number of template parameters; always non-zero.
+ unsigned NumParams;
+
+ // The parameter list.
+ TemplateParameterList **Params;
+
+ // The declaration that's a friend of this class.
+ FriendUnion Friend;
+
+ // Location of the 'friend' specifier.
+ SourceLocation FriendLoc;
+
+
+ FriendTemplateDecl(DeclContext *DC, SourceLocation Loc,
+ unsigned NParams,
+ TemplateParameterList **Params,
+ FriendUnion Friend,
+ SourceLocation FriendLoc)
+ : Decl(Decl::FriendTemplate, DC, Loc),
+ NumParams(NParams),
+ Params(Params),
+ Friend(Friend),
+ FriendLoc(FriendLoc)
+ {}
+
+public:
+ static FriendTemplateDecl *Create(ASTContext &Context,
+ DeclContext *DC, SourceLocation Loc,
+ unsigned NParams,
+ TemplateParameterList **Params,
+ FriendUnion Friend,
+ SourceLocation FriendLoc);
+
+ /// If this friend declaration names a templated type (or
+ /// a dependent member type of a templated type), return that
+ /// type; otherwise return null.
+ Type *getFriendType() const {
+ return Friend.dyn_cast<Type*>();
+ }
+
+ /// If this friend declaration names a templated function (or
+ /// a member function of a templated type), return that type;
+ /// otherwise return null.
+ NamedDecl *getFriendDecl() const {
+ return Friend.dyn_cast<NamedDecl*>();
+ }
+
+ /// Retrieves the location of the 'friend' keyword.
+ SourceLocation getFriendLoc() const {
+ return FriendLoc;
+ }
+
+ TemplateParameterList *getTemplateParameterList(unsigned i) const {
+ assert(i <= NumParams);
+ return Params[i];
+ }
+
+ unsigned getNumTemplateParameters() const {
+ return NumParams;
+ }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) {
+ return D->getKind() == Decl::FriendTemplate;
+ }
+ static bool classof(const FriendTemplateDecl *D) { return true; }
+};
+
/// Implementation of inline functions that require the template declarations
-inline AnyFunctionDecl::AnyFunctionDecl(FunctionTemplateDecl *FTD)
+inline AnyFunctionDecl::AnyFunctionDecl(FunctionTemplateDecl *FTD)
: Function(FTD) { }
} /* end of namespace clang */
diff --git a/include/clang/AST/DeclarationName.h b/include/clang/AST/DeclarationName.h
index db14099..ed4ac6b 100644
--- a/include/clang/AST/DeclarationName.h
+++ b/include/clang/AST/DeclarationName.h
@@ -15,6 +15,8 @@
#include "clang/Basic/IdentifierTable.h"
#include "clang/AST/Type.h"
+#include "clang/AST/CanonicalType.h"
+#include "clang/Basic/PartialDiagnostic.h"
namespace llvm {
template <typename T> struct DenseMapInfo;
@@ -100,7 +102,7 @@ private:
/// CXXSpecialName, returns a pointer to it. Otherwise, returns
/// a NULL pointer.
CXXSpecialName *getAsCXXSpecialName() const {
- if (getNameKind() >= CXXConstructorName &&
+ if (getNameKind() >= CXXConstructorName &&
getNameKind() <= CXXConversionFunctionName)
return reinterpret_cast<CXXSpecialName *>(Ptr & ~PtrMask);
return 0;
@@ -115,16 +117,16 @@ private:
// Construct a declaration name from the name of a C++ constructor,
// destructor, or conversion function.
- DeclarationName(CXXSpecialName *Name)
- : Ptr(reinterpret_cast<uintptr_t>(Name)) {
+ 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)) {
+ DeclarationName(CXXOperatorIdName *Name)
+ : Ptr(reinterpret_cast<uintptr_t>(Name)) {
assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXOperatorId");
Ptr |= StoredDeclarationNameExtra;
}
@@ -144,8 +146,8 @@ public:
DeclarationName() : Ptr(0) { }
// Construct a declaration name from an IdentifierInfo *.
- DeclarationName(const IdentifierInfo *II)
- : Ptr(reinterpret_cast<uintptr_t>(II)) {
+ DeclarationName(const IdentifierInfo *II)
+ : Ptr(reinterpret_cast<uintptr_t>(II)) {
assert((Ptr & PtrMask) == 0 && "Improperly aligned IdentifierInfo");
}
@@ -157,8 +159,8 @@ public:
// operator bool() - Evaluates true when this declaration name is
// non-empty.
- operator bool() const {
- return ((Ptr & PtrMask) != 0) ||
+ operator bool() const {
+ return ((Ptr & PtrMask) != 0) ||
(reinterpret_cast<IdentifierInfo *>(Ptr & ~PtrMask));
}
@@ -170,10 +172,10 @@ public:
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;
@@ -181,7 +183,7 @@ public:
/// getAsIdentifierInfo - Retrieve the IdentifierInfo * stored in
/// this declaration name, or NULL if this declaration name isn't a
/// simple identifier.
- IdentifierInfo *getAsIdentifierInfo() const {
+ IdentifierInfo *getAsIdentifierInfo() const {
if (isIdentifier())
return reinterpret_cast<IdentifierInfo *>(Ptr);
return 0;
@@ -195,12 +197,18 @@ public:
/// an opaque pointer.
void *getAsOpaquePtr() const { return reinterpret_cast<void*>(Ptr); }
+ static DeclarationName getFromOpaquePtr(void *P) {
+ DeclarationName N;
+ N.Ptr = reinterpret_cast<uintptr_t> (P);
+ return N;
+ }
+
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.
@@ -290,32 +298,32 @@ public:
/// getCXXConstructorName - Returns the name of a C++ constructor
/// for the given Type.
- DeclarationName getCXXConstructorName(QualType Ty) {
+ DeclarationName getCXXConstructorName(CanQualType Ty) {
return getCXXSpecialName(DeclarationName::CXXConstructorName, Ty);
}
/// getCXXDestructorName - Returns the name of a C++ destructor
/// for the given Type.
- DeclarationName getCXXDestructorName(QualType Ty) {
+ DeclarationName getCXXDestructorName(CanQualType Ty) {
return getCXXSpecialName(DeclarationName::CXXDestructorName, Ty);
}
/// getCXXConversionFunctionName - Returns the name of a C++
/// conversion function for the given Type.
- DeclarationName getCXXConversionFunctionName(QualType Ty) {
+ DeclarationName getCXXConversionFunctionName(CanQualType 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);
+ DeclarationName getCXXSpecialName(DeclarationName::NameKind Kind,
+ CanQualType 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 <<.
@@ -325,7 +333,15 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
Diagnostic::ak_declarationname);
return DB;
}
-
+
+/// Insertion operator for partial diagnostics. This allows binding
+/// DeclarationName's into a partial diagnostic with <<.
+inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
+ DeclarationName N) {
+ PD.AddTaggedVal(N.getAsOpaqueInteger(),
+ Diagnostic::ak_declarationname);
+ return PD;
+}
} // end namespace clang
@@ -344,7 +360,7 @@ struct DenseMapInfo<clang::DeclarationName> {
static unsigned getHashValue(clang::DeclarationName);
- static inline bool
+ static inline bool
isEqual(clang::DeclarationName LHS, clang::DeclarationName RHS) {
return LHS == RHS;
}
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index 6a1046e..d5dff50 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -20,6 +20,7 @@
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
#include <vector>
namespace clang {
@@ -42,20 +43,20 @@ class Expr : public Stmt {
QualType TR;
protected:
- /// TypeDependent - Whether this expression is type-dependent
+ /// TypeDependent - Whether this expression is type-dependent
/// (C++ [temp.dep.expr]).
bool TypeDependent : 1;
- /// ValueDependent - Whether this expression is value-dependent
+ /// 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)
+ Expr(StmtClass SC, QualType T)
: Stmt(SC), TypeDependent(false), ValueDependent(false) {
- setType(T);
+ setType(T);
}
Expr(StmtClass SC, QualType T, bool TD, bool VD)
@@ -66,9 +67,18 @@ protected:
/// \brief Construct an empty expression.
explicit Expr(StmtClass SC, EmptyShell) : Stmt(SC) { }
-public:
+public:
+ /// \brief Increases the reference count for this expression.
+ ///
+ /// Invoke the Retain() operation when this expression
+ /// is being shared by another owner.
+ Expr *Retain() {
+ Stmt::Retain();
+ return this;
+ }
+
QualType getType() const { return TR; }
- void setType(QualType t) {
+ 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
@@ -76,16 +86,16 @@ public:
// 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()) &&
+ assert((TR.isNull() || !TR->isReferenceType()) &&
"Expressions can't have reference type");
- TR = t;
+ 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.
+ /// value-dependent.
/// @code
/// template<int Size, char (&Chars)[Size]> struct meta_string;
/// @endcode
@@ -100,7 +110,7 @@ public:
/// example, the expressions "x" and "x + y" are type-dependent in
/// the following code, but "y" is not type-dependent:
/// @code
- /// template<typename T>
+ /// template<typename T>
/// void add(T x, int y) {
/// x + y;
/// }
@@ -118,14 +128,14 @@ public:
/// 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
@@ -150,10 +160,10 @@ public:
// 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,
+ /// 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.
///
@@ -177,7 +187,7 @@ public:
};
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();
@@ -185,7 +195,7 @@ public:
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
@@ -200,16 +210,16 @@ public:
/// 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
@@ -221,7 +231,7 @@ public:
unsigned Diag;
const Expr *DiagExpr;
SourceLocation DiagLoc;
-
+
EvalResult() : HasSideEffects(false), Diag(0), DiagExpr(0) {}
};
@@ -239,25 +249,41 @@ public:
/// 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.
+ /// EvaluateAsLValue - Evaluate an expression to see if it's a lvalue
+ /// with link time known address.
bool EvaluateAsLValue(EvalResult &Result, ASTContext &Ctx) const;
+ /// EvaluateAsAnyLValue - The same as EvaluateAsLValue, except that it
+ /// also succeeds on stack based, immutable address lvalues.
+ bool EvaluateAsAnyLValue(EvalResult &Result, ASTContext &Ctx) const;
+
+ /// \brief Enumeration used to describe how \c isNullPointerConstant()
+ /// should cope with value-dependent expressions.
+ enum NullPointerConstantValueDependence {
+ /// \brief Specifies that the expression should never be value-dependent.
+ NPC_NeverValueDependent = 0,
+
+ /// \brief Specifies that a value-dependent expression of integral or
+ /// dependent type should be considered a null pointer constant.
+ NPC_ValueDependentIsNull,
+
+ /// \brief Specifies that a value-dependent expression should be considered
+ /// to never be a null pointer constant.
+ NPC_ValueDependentIsNotNull
+ };
+
/// 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;
+ bool isNullPointerConstant(ASTContext &Ctx,
+ NullPointerConstantValueDependence NPC) const;
/// isOBJCGCCandidate - Return true if this expression may be used in a read/
- /// write barrier.
+ /// 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,
+ /// 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();
@@ -265,12 +291,12 @@ public:
/// 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();
}
@@ -280,18 +306,18 @@ public:
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) {
+ static bool classof(const Stmt *T) {
return T->getStmtClass() >= firstExprConstant &&
- T->getStmtClass() <= lastExprConstant;
+ T->getStmtClass() <= lastExprConstant;
}
static bool classof(const Expr *) { return true; }
};
-
+
//===----------------------------------------------------------------------===//
// Primary Expressions.
//===----------------------------------------------------------------------===//
@@ -299,7 +325,7 @@ public:
/// DeclRefExpr - [C99 6.5.1p2] - A reference to a declared variable, function,
/// enum, etc.
class DeclRefExpr : public Expr {
- NamedDecl *D;
+ NamedDecl *D;
SourceLocation Loc;
protected:
@@ -315,14 +341,14 @@ protected:
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) :
+ 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) :
+ 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)
+ explicit DeclRefExpr(EmptyShell Empty)
: Expr(DeclRefExprClass, Empty) { }
NamedDecl *getDecl() { return D; }
@@ -332,14 +358,14 @@ public:
SourceLocation getLocation() const { return Loc; }
void setLocation(SourceLocation L) { Loc = L; }
virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
-
- static bool classof(const Stmt *T) {
+
+ static bool classof(const Stmt *T) {
return T->getStmtClass() == DeclRefExprClass ||
T->getStmtClass() == CXXConditionDeclExprClass ||
- T->getStmtClass() == QualifiedDeclRefExprClass;
+ T->getStmtClass() == QualifiedDeclRefExprClass;
}
static bool classof(const DeclRefExpr *) { return true; }
-
+
// Iterators
virtual child_iterator child_begin();
virtual child_iterator child_end();
@@ -353,38 +379,35 @@ public:
Function,
PrettyFunction
};
-
+
private:
SourceLocation Loc;
IdentType Type;
public:
- PredefinedExpr(SourceLocation l, QualType type, IdentType IT)
- : Expr(PredefinedExprClass, type), Loc(l), Type(IT) {}
-
+ PredefinedExpr(SourceLocation l, QualType type, IdentType IT)
+ : Expr(PredefinedExprClass, type, type->isDependentType(),
+ type->isDependentType()), Loc(l), Type(IT) {}
+
/// \brief Construct an empty predefined expression.
- explicit PredefinedExpr(EmptyShell Empty)
+ 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.
-
+ static std::string ComputeName(ASTContext &Context, IdentType IT,
+ const Decl *CurrentDecl);
+
virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
- static bool classof(const Stmt *T) {
- return T->getStmtClass() == PredefinedExprClass;
+ 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();
@@ -394,7 +417,7 @@ class IntegerLiteral : public Expr {
llvm::APInt Value;
SourceLocation Loc;
public:
- // type should be IntTy, LongTy, LongLongTy, UnsignedIntTy, UnsignedLongTy,
+ // 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) {
@@ -402,11 +425,9 @@ public:
}
/// \brief Construct an empty integer literal.
- explicit IntegerLiteral(EmptyShell Empty)
+ 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); }
@@ -416,11 +437,11 @@ public:
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 Stmt *T) {
+ return T->getStmtClass() == IntegerLiteralClass;
}
static bool classof(const IntegerLiteral *) { return true; }
-
+
// Iterators
virtual child_iterator child_begin();
virtual child_iterator child_end();
@@ -439,21 +460,19 @@ public:
/// \brief Construct an empty character literal.
CharacterLiteral(EmptyShell Empty) : Expr(CharacterLiteralClass, Empty) { }
- CharacterLiteral* Clone(ASTContext &C) const;
-
- SourceLocation getLoc() const { return Loc; }
+ SourceLocation getLocation() 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 Stmt *T) {
+ return T->getStmtClass() == CharacterLiteralClass;
}
static bool classof(const CharacterLiteral *) { return true; }
@@ -467,16 +486,14 @@ class FloatingLiteral : public Expr {
bool IsExact : 1;
SourceLocation Loc;
public:
- FloatingLiteral(const llvm::APFloat &V, bool isexact,
+ FloatingLiteral(const llvm::APFloat &V, bool isexact,
QualType Type, SourceLocation L)
- : Expr(FloatingLiteralClass, Type), Value(V), IsExact(isexact), Loc(L) {}
+ : Expr(FloatingLiteralClass, Type), Value(V), IsExact(isexact), Loc(L) {}
/// \brief Construct an empty floating-point literal.
- explicit FloatingLiteral(EmptyShell Empty)
+ 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; }
@@ -487,7 +504,7 @@ public:
/// 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; }
@@ -495,14 +512,14 @@ public:
// 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 Stmt *T) {
+ return T->getStmtClass() == FloatingLiteralClass;
}
static bool classof(const FloatingLiteral *) { return true; }
-
+
// Iterators
virtual child_iterator child_begin();
virtual child_iterator child_end();
@@ -518,23 +535,21 @@ class ImaginaryLiteral : public Expr {
public:
ImaginaryLiteral(Expr *val, QualType Ty)
: Expr(ImaginaryLiteralClass, Ty), Val(val) {}
-
+
/// \brief Build an empty imaginary literal.
- explicit ImaginaryLiteral(EmptyShell Empty)
+ 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 Stmt *T) {
+ return T->getStmtClass() == ImaginaryLiteralClass;
}
static bool classof(const ImaginaryLiteral *) { return true; }
-
+
// Iterators
virtual child_iterator child_begin();
virtual child_iterator child_end();
@@ -564,6 +579,10 @@ class StringLiteral : public Expr {
SourceLocation TokLocs[1];
StringLiteral(QualType Ty) : Expr(StringLiteralClass, Ty) {}
+
+protected:
+ virtual void DoDestroy(ASTContext &C);
+
public:
/// This is the "fully general" constructor that allows representation of
/// strings formed from multiple concatenated tokens.
@@ -572,7 +591,7 @@ public:
const SourceLocation *Loc, unsigned NumStrs);
/// Simple constructor for string literals made from one token.
- static StringLiteral *Create(ASTContext &C, const char *StrData,
+ 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);
@@ -581,33 +600,35 @@ public:
/// \brief Construct an empty string literal.
static StringLiteral *CreateEmpty(ASTContext &C, unsigned NumStrs);
- StringLiteral* Clone(ASTContext &C) const;
- void Destroy(ASTContext &C);
-
+ llvm::StringRef getString() const {
+ return llvm::StringRef(StrData, ByteLength);
+ }
+ // FIXME: These are deprecated, replace with StringRef.
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);
+ void setString(ASTContext &C, llvm::StringRef Str);
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])
+ llvm::StringRef Str = getString();
+ for (unsigned i = 0, e = Str.size(); i != e; ++i)
+ if (!isascii(Str[i]) || !Str[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) {
+ void setStrTokenLoc(unsigned TokNum, SourceLocation L) {
assert(TokNum < NumConcatenated && "Invalid tok number");
TokLocs[TokNum] = L;
}
@@ -616,14 +637,14 @@ public:
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]);
+ 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 Stmt *T) {
+ return T->getStmtClass() == StringLiteralClass;
}
static bool classof(const StringLiteral *) { return true; }
-
+
// Iterators
virtual child_iterator child_begin();
virtual child_iterator child_end();
@@ -637,11 +658,11 @@ class ParenExpr : public Expr {
public:
ParenExpr(SourceLocation l, SourceLocation r, Expr *val)
: Expr(ParenExprClass, val->getType(),
- val->isTypeDependent(), val->isValueDependent()),
+ val->isTypeDependent(), val->isValueDependent()),
L(l), R(r), Val(val) {}
-
+
/// \brief Construct an empty parenthesized expression.
- explicit ParenExpr(EmptyShell Empty)
+ explicit ParenExpr(EmptyShell Empty)
: Expr(ParenExprClass, Empty) { }
const Expr *getSubExpr() const { return cast<Expr>(Val); }
@@ -658,11 +679,11 @@ public:
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 Stmt *T) {
+ return T->getStmtClass() == ParenExprClass;
}
static bool classof(const ParenExpr *) { return true; }
-
+
// Iterators
virtual child_iterator child_begin();
virtual child_iterator child_end();
@@ -680,7 +701,7 @@ public:
/// 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
+/// subexpression is a compound literal with the various MemberExpr and
/// ArraySubscriptExpr's applied to it.
///
class UnaryOperator : public Expr {
@@ -700,16 +721,16 @@ private:
Stmt *Val;
Opcode Opc;
SourceLocation Loc;
-public:
+public:
UnaryOperator(Expr *input, Opcode opc, QualType type, SourceLocation l)
: Expr(UnaryOperatorClass, type,
input->isTypeDependent() && opc != OffsetOf,
- input->isValueDependent()),
+ input->isValueDependent()),
Val(input), Opc(opc), Loc(l) {}
/// \brief Build an empty unary operator.
- explicit UnaryOperator(EmptyShell Empty)
+ explicit UnaryOperator(EmptyShell Empty)
: Expr(UnaryOperatorClass, Empty), Opc(AddrOf) { }
Opcode getOpcode() const { return Opc; }
@@ -738,7 +759,8 @@ public:
bool isIncrementDecrementOp() const { return Opc>=PostInc && Opc<=PreDec; }
bool isOffsetOfOp() const { return Opc == OffsetOf; }
static bool isArithmeticOp(Opcode Op) { return Op >= Plus && Op <= LNot; }
-
+ bool isArithmeticOp() const { return isArithmeticOp(Opc); }
+
/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it
/// corresponds to, e.g. "sizeof" or "[pre]++"
static const char *getOpcodeStr(Opcode Op);
@@ -758,12 +780,12 @@ public:
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 Stmt *T) {
+ return T->getStmtClass() == UnaryOperatorClass;
}
static bool classof(const UnaryOperator *) { return true; }
-
+
// Iterators
virtual child_iterator child_begin();
virtual child_iterator child_end();
@@ -779,8 +801,12 @@ class SizeOfAlignOfExpr : public Expr {
Stmt *Ex;
} Argument;
SourceLocation OpLoc, RParenLoc;
+
+protected:
+ virtual void DoDestroy(ASTContext& C);
+
public:
- SizeOfAlignOfExpr(bool issizeof, QualType T,
+ SizeOfAlignOfExpr(bool issizeof, QualType T,
QualType resultType, SourceLocation op,
SourceLocation rp) :
Expr(SizeOfAlignOfExprClass, resultType,
@@ -791,7 +817,7 @@ public:
Argument.Ty = T.getAsOpaquePtr();
}
- SizeOfAlignOfExpr(bool issizeof, Expr *E,
+ SizeOfAlignOfExpr(bool issizeof, Expr *E,
QualType resultType, SourceLocation op,
SourceLocation rp) :
Expr(SizeOfAlignOfExprClass, resultType,
@@ -806,8 +832,6 @@ public:
explicit SizeOfAlignOfExpr(EmptyShell Empty)
: Expr(SizeOfAlignOfExprClass, Empty) { }
- virtual void Destroy(ASTContext& C);
-
bool isSizeOf() const { return isSizeof; }
void setSizeof(bool S) { isSizeof = S; }
@@ -825,9 +849,9 @@ public:
}
void setArgument(Expr *E) { Argument.Ex = E; isType = false; }
- void setArgument(QualType T) {
- Argument.Ty = T.getAsOpaquePtr();
- isType = true;
+ void setArgument(QualType T) {
+ Argument.Ty = T.getAsOpaquePtr();
+ isType = true;
}
/// Gets the argument type, or the type of the argument expression, whichever
@@ -846,11 +870,11 @@ public:
return SourceRange(OpLoc, RParenLoc);
}
- static bool classof(const Stmt *T) {
- return T->getStmtClass() == SizeOfAlignOfExprClass;
+ 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();
@@ -863,7 +887,7 @@ public:
/// ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting.
class ArraySubscriptExpr : public Expr {
enum { LHS, RHS, END_EXPR=2 };
- Stmt* SubExprs[END_EXPR];
+ Stmt* SubExprs[END_EXPR];
SourceLocation RBracketLoc;
public:
ArraySubscriptExpr(Expr *lhs, Expr *rhs, QualType t,
@@ -875,7 +899,7 @@ public:
SubExprs[LHS] = lhs;
SubExprs[RHS] = rhs;
}
-
+
/// \brief Create an empty array subscript expression.
explicit ArraySubscriptExpr(EmptyShell Shell)
: Expr(ArraySubscriptExprClass, Shell) { }
@@ -896,37 +920,37 @@ public:
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() {
+
+ Expr *getBase() {
return cast<Expr>(getRHS()->getType()->isIntegerType() ? getLHS():getRHS());
}
-
- const Expr *getBase() const {
+
+ const Expr *getBase() const {
return cast<Expr>(getRHS()->getType()->isIntegerType() ? getLHS():getRHS());
}
-
- Expr *getIdx() {
+
+ 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 {
+ }
+
+ 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 Stmt *T) {
+ return T->getStmtClass() == ArraySubscriptExprClass;
}
static bool classof(const ArraySubscriptExpr *) { return true; }
-
+
// Iterators
virtual child_iterator child_begin();
virtual child_iterator child_end();
@@ -934,9 +958,9 @@ public:
/// 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)",
+/// 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
+/// 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 {
@@ -944,31 +968,37 @@ class CallExpr : public Expr {
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);
-
+
+ virtual void DoDestroy(ASTContext& C);
+
public:
- CallExpr(ASTContext& C, Expr *fn, Expr **args, unsigned numargs, QualType t,
+ 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(ASTContext &C, StmtClass SC, 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; }
-
+
+ /// \brief If the callee is a FunctionDecl, return it. Otherwise return 0.
+ FunctionDecl *getDirectCallee();
+ const FunctionDecl *getDirectCallee() const {
+ return const_cast<CallExpr*>(this)->getDirectCallee();
+ }
+
/// 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!");
@@ -978,26 +1008,26 @@ public:
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; }
@@ -1005,23 +1035,23 @@ public:
/// 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
+
+ /// 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 {
+ virtual SourceRange getSourceRange() const {
return SourceRange(getCallee()->getLocStart(), RParenLoc);
}
-
- static bool classof(const Stmt *T) {
+
+ static bool classof(const Stmt *T) {
return T->getStmtClass() == CallExprClass ||
T->getStmtClass() == CXXOperatorCallExprClass ||
- T->getStmtClass() == CXXMemberCallExprClass;
+ T->getStmtClass() == CXXMemberCallExprClass;
}
static bool classof(const CallExpr *) { return true; }
static bool classof(const CXXOperatorCallExpr *) { return true; }
@@ -1032,31 +1062,131 @@ public:
virtual child_iterator child_end();
};
+/// \brief Represents the qualifier that may precede a C++ name, e.g., the
+/// "std::" in "std::sort".
+struct NameQualifier {
+ /// \brief The nested name specifier.
+ NestedNameSpecifier *NNS;
+
+ /// \brief The source range covered by the nested name specifier.
+ SourceRange Range;
+};
+
+/// \brief Represents an explicit template argument list in C++, e.g.,
+/// the "<int>" in "sort<int>".
+struct ExplicitTemplateArgumentList {
+ /// \brief The source location of the left angle bracket ('<');
+ SourceLocation LAngleLoc;
+
+ /// \brief The source location of the right angle bracket ('>');
+ SourceLocation RAngleLoc;
+
+ /// \brief The number of template arguments in TemplateArgs.
+ /// The actual template arguments (if any) are stored after the
+ /// ExplicitTemplateArgumentList structure.
+ unsigned NumTemplateArgs;
+
+ /// \brief Retrieve the template arguments
+ TemplateArgument *getTemplateArgs() {
+ return reinterpret_cast<TemplateArgument *> (this + 1);
+ }
+
+ /// \brief Retrieve the template arguments
+ const TemplateArgument *getTemplateArgs() const {
+ return reinterpret_cast<const TemplateArgument *> (this + 1);
+ }
+};
+
/// 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;
+ bool IsArrow : 1;
+
+ /// \brief True if this member expression used a nested-name-specifier to
+ /// refer to the member, e.g., "x->Base::f". When true, a NameQualifier
+ /// structure is allocated immediately after the MemberExpr.
+ bool HasQualifier : 1;
+
+ /// \brief True if this member expression specified a template argument list
+ /// explicitly, e.g., x->f<int>. When true, an ExplicitTemplateArgumentList
+ /// structure (and its TemplateArguments) are allocated immediately after
+ /// the MemberExpr or, if the member expression also has a qualifier, after
+ /// the NameQualifier structure.
+ bool HasExplicitTemplateArgumentList : 1;
+
+ /// \brief Retrieve the qualifier that preceded the member name, if any.
+ NameQualifier *getMemberQualifier() {
+ if (!HasQualifier)
+ return 0;
+
+ return reinterpret_cast<NameQualifier *> (this + 1);
+ }
+
+ /// \brief Retrieve the qualifier that preceded the member name, if any.
+ const NameQualifier *getMemberQualifier() const {
+ return const_cast<MemberExpr *>(this)->getMemberQualifier();
+ }
+
+ /// \brief Retrieve the explicit template argument list that followed the
+ /// member template name, if any.
+ ExplicitTemplateArgumentList *getExplicitTemplateArgumentList() {
+ if (!HasExplicitTemplateArgumentList)
+ return 0;
+
+ if (!HasQualifier)
+ return reinterpret_cast<ExplicitTemplateArgumentList *>(this + 1);
+
+ return reinterpret_cast<ExplicitTemplateArgumentList *>(
+ getMemberQualifier() + 1);
+ }
+
+ /// \brief Retrieve the explicit template argument list that followed the
+ /// member template name, if any.
+ const ExplicitTemplateArgumentList *getExplicitTemplateArgumentList() const {
+ return const_cast<MemberExpr *>(this)->getExplicitTemplateArgumentList();
+ }
+
+ MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual,
+ SourceRange qualrange, NamedDecl *memberdecl, SourceLocation l,
+ bool has_explicit, SourceLocation langle,
+ const TemplateArgument *targs, unsigned numtargs,
+ SourceLocation rangle, QualType ty);
+
public:
MemberExpr(Expr *base, bool isarrow, NamedDecl *memberdecl, SourceLocation l,
- QualType ty)
- : Expr(MemberExprClass, ty,
+ QualType ty)
+ : Expr(MemberExprClass, ty,
base->isTypeDependent(), base->isValueDependent()),
- Base(base), MemberDecl(memberdecl), MemberLoc(l), IsArrow(isarrow) {}
+ Base(base), MemberDecl(memberdecl), MemberLoc(l), IsArrow(isarrow),
+ HasQualifier(false), HasExplicitTemplateArgumentList(false) {}
/// \brief Build an empty member reference expression.
- explicit MemberExpr(EmptyShell Empty) : Expr(MemberExprClass, Empty) { }
+ explicit MemberExpr(EmptyShell Empty)
+ : Expr(MemberExprClass, Empty), HasQualifier(false),
+ HasExplicitTemplateArgumentList(false) { }
+
+ static MemberExpr *Create(ASTContext &C, Expr *base, bool isarrow,
+ NestedNameSpecifier *qual, SourceRange qualrange,
+ NamedDecl *memberdecl,
+ SourceLocation l,
+ bool has_explicit,
+ SourceLocation langle,
+ const TemplateArgument *targs,
+ unsigned numtargs,
+ SourceLocation rangle,
+ QualType ty);
void setBase(Expr *E) { Base = E; }
Expr *getBase() const { return cast<Expr>(Base); }
@@ -1068,6 +1198,73 @@ public:
NamedDecl *getMemberDecl() const { return MemberDecl; }
void setMemberDecl(NamedDecl *D) { MemberDecl = D; }
+ /// \brief Determines whether this member expression actually had
+ /// a C++ nested-name-specifier prior to the name of the member, e.g.,
+ /// x->Base::foo.
+ bool hasQualifier() const { return HasQualifier; }
+
+ /// \brief If the member name was qualified, retrieves the source range of
+ /// the nested-name-specifier that precedes the member name. Otherwise,
+ /// returns an empty source range.
+ SourceRange getQualifierRange() const {
+ if (!HasQualifier)
+ return SourceRange();
+
+ return getMemberQualifier()->Range;
+ }
+
+ /// \brief If the member name was qualified, retrieves the
+ /// nested-name-specifier that precedes the member name. Otherwise, returns
+ /// NULL.
+ NestedNameSpecifier *getQualifier() const {
+ if (!HasQualifier)
+ return 0;
+
+ return getMemberQualifier()->NNS;
+ }
+
+ /// \brief Determines whether this member expression actually had a C++
+ /// template argument list explicitly specified, e.g., x.f<int>.
+ bool hasExplicitTemplateArgumentList() {
+ return HasExplicitTemplateArgumentList;
+ }
+
+ /// \brief Retrieve the location of the left angle bracket following the
+ /// member name ('<'), if any.
+ SourceLocation getLAngleLoc() const {
+ if (!HasExplicitTemplateArgumentList)
+ return SourceLocation();
+
+ return getExplicitTemplateArgumentList()->LAngleLoc;
+ }
+
+ /// \brief Retrieve the template arguments provided as part of this
+ /// template-id.
+ const TemplateArgument *getTemplateArgs() const {
+ if (!HasExplicitTemplateArgumentList)
+ return 0;
+
+ return getExplicitTemplateArgumentList()->getTemplateArgs();
+ }
+
+ /// \brief Retrieve the number of template arguments provided as part of this
+ /// template-id.
+ unsigned getNumTemplateArgs() const {
+ if (!HasExplicitTemplateArgumentList)
+ return 0;
+
+ return getExplicitTemplateArgumentList()->NumTemplateArgs;
+ }
+
+ /// \brief Retrieve the location of the right angle bracket following the
+ /// template arguments ('>').
+ SourceLocation getRAngleLoc() const {
+ if (!HasExplicitTemplateArgumentList)
+ return SourceLocation();
+
+ return getExplicitTemplateArgumentList()->RAngleLoc;
+ }
+
bool isArrow() const { return IsArrow; }
void setArrow(bool A) { IsArrow = A; }
@@ -1079,25 +1276,29 @@ public:
virtual SourceRange getSourceRange() const {
// If we have an implicit base (like a C++ implicit this),
// make sure not to return its location
+ SourceLocation EndLoc = MemberLoc;
+ if (HasExplicitTemplateArgumentList)
+ EndLoc = getRAngleLoc();
+
SourceLocation BaseLoc = getBase()->getLocStart();
if (BaseLoc.isInvalid())
- return SourceRange(MemberLoc, MemberLoc);
- return SourceRange(BaseLoc, MemberLoc);
+ return SourceRange(MemberLoc, EndLoc);
+ return SourceRange(BaseLoc, EndLoc);
}
-
+
virtual SourceLocation getExprLoc() const { return MemberLoc; }
- static bool classof(const Stmt *T) {
- return T->getStmtClass() == MemberExprClass;
+ 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]
+/// CompoundLiteralExpr - [C99 6.5.2.5]
///
class CompoundLiteralExpr : public Expr {
/// LParenLoc - If non-null, this is the location of the left paren in a
@@ -1111,7 +1312,7 @@ public:
bool fileScope)
: Expr(CompoundLiteralExprClass, ty), LParenLoc(lparenloc), Init(init),
FileScope(fileScope) {}
-
+
/// \brief Construct an empty compound literal.
explicit CompoundLiteralExpr(EmptyShell Empty)
: Expr(CompoundLiteralExprClass, Empty) { }
@@ -1135,11 +1336,11 @@ public:
return SourceRange(LParenLoc, Init->getLocEnd());
}
- static bool classof(const Stmt *T) {
- return T->getStmtClass() == CompoundLiteralExprClass;
+ 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();
@@ -1150,28 +1351,85 @@ public:
/// representation in the source code (ExplicitCastExpr's derived
/// classes).
class CastExpr : public Expr {
+public:
+ /// CastKind - the kind of cast this represents.
+ enum CastKind {
+ /// CK_Unknown - Unknown cast kind.
+ /// FIXME: The goal is to get rid of this and make all casts have a
+ /// kind so that the AST client doesn't have to try to figure out what's
+ /// going on.
+ CK_Unknown,
+
+ /// CK_BitCast - Used for reinterpret_cast.
+ CK_BitCast,
+
+ /// CK_NoOp - Used for const_cast.
+ CK_NoOp,
+
+ /// CK_DerivedToBase - Derived to base class casts.
+ CK_DerivedToBase,
+
+ /// CK_Dynamic - Dynamic cast.
+ CK_Dynamic,
+
+ /// CK_ToUnion - Cast to union (GCC extension).
+ CK_ToUnion,
+
+ /// CK_ArrayToPointerDecay - Array to pointer decay.
+ CK_ArrayToPointerDecay,
+
+ // CK_FunctionToPointerDecay - Function to pointer decay.
+ CK_FunctionToPointerDecay,
+
+ /// CK_NullToMemberPointer - Null pointer to member pointer.
+ CK_NullToMemberPointer,
+
+ /// CK_BaseToDerivedMemberPointer - Member pointer in base class to
+ /// member pointer in derived class.
+ CK_BaseToDerivedMemberPointer,
+
+ /// CK_UserDefinedConversion - Conversion using a user defined type
+ /// conversion function.
+ CK_UserDefinedConversion,
+
+ /// CK_ConstructorConversion - Conversion by constructor
+ CK_ConstructorConversion,
+
+ /// CK_IntegralToPointer - Integral to pointer
+ CK_IntegralToPointer,
+
+ /// CK_PointerToIntegral - Pointer to integral
+ CK_PointerToIntegral
+ };
+
+private:
+ CastKind Kind;
Stmt *Op;
protected:
- CastExpr(StmtClass SC, QualType ty, Expr *op) :
+ CastExpr(StmtClass SC, QualType ty, const CastKind kind, 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) {}
-
+ ty->isDependentType() || (op && op->isValueDependent())),
+ Kind(kind), Op(op) {}
+
/// \brief Construct an empty cast.
- CastExpr(StmtClass SC, EmptyShell Empty)
+ CastExpr(StmtClass SC, EmptyShell Empty)
: Expr(SC, Empty) { }
-
+
public:
+ CastKind getCastKind() const { return Kind; }
+ void setCastKind(CastKind K) { Kind = K; }
+ const char *getCastKindName() const;
+
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) {
+ static bool classof(const Stmt *T) {
StmtClass SC = T->getStmtClass();
if (SC >= CXXNamedCastExprClass && SC <= CXXFunctionalCastExprClass)
return true;
@@ -1182,7 +1440,7 @@ public:
return false;
}
static bool classof(const CastExpr *) { return true; }
-
+
// Iterators
virtual child_iterator child_begin();
virtual child_iterator child_end();
@@ -1200,7 +1458,7 @@ public:
/// @code
/// class Base { };
/// class Derived : public Base { };
-/// void f(Derived d) {
+/// void f(Derived d) {
/// Base& b = d; // initializer is an ImplicitCastExpr to an lvalue of type Base
/// }
/// @endcode
@@ -1209,11 +1467,11 @@ class ImplicitCastExpr : public CastExpr {
bool LvalueCast;
public:
- ImplicitCastExpr(QualType ty, Expr *op, bool Lvalue) :
- CastExpr(ImplicitCastExprClass, ty, op), LvalueCast(Lvalue) { }
+ ImplicitCastExpr(QualType ty, CastKind kind, Expr *op, bool Lvalue) :
+ CastExpr(ImplicitCastExprClass, ty, kind, op), LvalueCast(Lvalue) { }
/// \brief Construct an empty implicit cast.
- explicit ImplicitCastExpr(EmptyShell Shell)
+ explicit ImplicitCastExpr(EmptyShell Shell)
: CastExpr(ImplicitCastExprClass, Shell) { }
@@ -1227,14 +1485,14 @@ public:
/// 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 Stmt *T) {
+ return T->getStmtClass() == ImplicitCastExprClass;
}
static bool classof(const ImplicitCastExpr *) { return true; }
};
/// ExplicitCastExpr - An explicit cast written in the source
-/// code.
+/// code.
///
/// This class is effectively an abstract class, because it provides
/// the basic representation of an explicitly-written cast without
@@ -1255,11 +1513,12 @@ class ExplicitCastExpr : public CastExpr {
QualType TypeAsWritten;
protected:
- ExplicitCastExpr(StmtClass SC, QualType exprTy, Expr *op, QualType writtenTy)
- : CastExpr(SC, exprTy, op), TypeAsWritten(writtenTy) {}
+ ExplicitCastExpr(StmtClass SC, QualType exprTy, CastKind kind,
+ Expr *op, QualType writtenTy)
+ : CastExpr(SC, exprTy, kind, op), TypeAsWritten(writtenTy) {}
/// \brief Construct an empty explicit cast.
- ExplicitCastExpr(StmtClass SC, EmptyShell Shell)
+ ExplicitCastExpr(StmtClass SC, EmptyShell Shell)
: CastExpr(SC, Shell) { }
public:
@@ -1268,7 +1527,7 @@ public:
QualType getTypeAsWritten() const { return TypeAsWritten; }
void setTypeAsWritten(QualType T) { TypeAsWritten = T; }
- static bool classof(const Stmt *T) {
+ static bool classof(const Stmt *T) {
StmtClass SC = T->getStmtClass();
if (SC >= ExplicitCastExprClass && SC <= CStyleCastExprClass)
return true;
@@ -1287,13 +1546,13 @@ 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),
+ CStyleCastExpr(QualType exprTy, CastKind kind, Expr *op, QualType writtenTy,
+ SourceLocation l, SourceLocation r) :
+ ExplicitCastExpr(CStyleCastExprClass, exprTy, kind, op, writtenTy),
LPLoc(l), RPLoc(r) {}
/// \brief Construct an empty C-style explicit cast.
- explicit CStyleCastExpr(EmptyShell Shell)
+ explicit CStyleCastExpr(EmptyShell Shell)
: ExplicitCastExpr(CStyleCastExprClass, Shell) { }
SourceLocation getLParenLoc() const { return LPLoc; }
@@ -1305,8 +1564,8 @@ public:
virtual SourceRange getSourceRange() const {
return SourceRange(LPLoc, getSubExpr()->getSourceRange().getEnd());
}
- static bool classof(const Stmt *T) {
- return T->getStmtClass() == CStyleCastExprClass;
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CStyleCastExprClass;
}
static bool classof(const CStyleCastExpr *) { return true; }
};
@@ -1358,22 +1617,22 @@ private:
Stmt* SubExprs[END_EXPR];
Opcode Opc;
SourceLocation OpLoc;
-public:
-
+public:
+
BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy,
SourceLocation opLoc)
: Expr(BinaryOperatorClass, ResTy,
lhs->isTypeDependent() || rhs->isTypeDependent(),
- lhs->isValueDependent() || rhs->isValueDependent()),
+ lhs->isValueDependent() || rhs->isValueDependent()),
Opc(opc), OpLoc(opLoc) {
SubExprs[LHS] = lhs;
SubExprs[RHS] = rhs;
- assert(!isCompoundAssignmentOp() &&
+ assert(!isCompoundAssignmentOp() &&
"Use ArithAssignBinaryOperator for compound assignments");
}
/// \brief Construct an empty binary operator.
- explicit BinaryOperator(EmptyShell Empty)
+ explicit BinaryOperator(EmptyShell Empty)
: Expr(BinaryOperatorClass, Empty), Opc(Comma) { }
SourceLocation getOperatorLoc() const { return OpLoc; }
@@ -1390,7 +1649,7 @@ public:
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);
@@ -1412,19 +1671,19 @@ public:
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; }
+ 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) {
+
+ static bool classof(const Stmt *S) {
return S->getStmtClass() == BinaryOperatorClass ||
- S->getStmtClass() == CompoundAssignOperatorClass;
+ S->getStmtClass() == CompoundAssignOperatorClass;
}
static bool classof(const BinaryOperator *) { return true; }
@@ -1440,7 +1699,7 @@ protected:
SubExprs[RHS] = rhs;
}
- BinaryOperator(StmtClass SC, EmptyShell Empty)
+ BinaryOperator(StmtClass SC, EmptyShell Empty)
: Expr(SC, Empty), Opc(MulAssign) { }
};
@@ -1461,7 +1720,7 @@ public:
: BinaryOperator(lhs, rhs, opc, ResType, OpLoc, true),
ComputationLHSType(CompLHSType),
ComputationResultType(CompResultType) {
- assert(isCompoundAssignmentOp() &&
+ assert(isCompoundAssignmentOp() &&
"Only should be used for compound assignments");
}
@@ -1479,8 +1738,8 @@ public:
void setComputationResultType(QualType T) { ComputationResultType = T; }
static bool classof(const CompoundAssignOperator *) { return true; }
- static bool classof(const Stmt *S) {
- return S->getStmtClass() == CompoundAssignOperatorClass;
+ static bool classof(const Stmt *S) {
+ return S->getStmtClass() == CompoundAssignOperatorClass;
}
};
@@ -1490,16 +1749,20 @@ public:
class ConditionalOperator : public Expr {
enum { COND, LHS, RHS, END_EXPR };
Stmt* SubExprs[END_EXPR]; // Left/Middle/Right hand sides.
+ SourceLocation QuestionLoc, ColonLoc;
public:
- ConditionalOperator(Expr *cond, Expr *lhs, Expr *rhs, QualType t)
+ ConditionalOperator(Expr *cond, SourceLocation QLoc, Expr *lhs,
+ SourceLocation CLoc, 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() ||
+ (cond->isValueDependent() ||
(lhs && lhs->isValueDependent()) ||
- (rhs && rhs->isValueDependent()))) {
+ (rhs && rhs->isValueDependent()))),
+ QuestionLoc(QLoc),
+ ColonLoc(CLoc) {
SubExprs[COND] = cond;
SubExprs[LHS] = lhs;
SubExprs[RHS] = rhs;
@@ -1519,29 +1782,35 @@ public:
// 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.
+ // 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; }
+ SourceLocation getQuestionLoc() const { return QuestionLoc; }
+ void setQuestionLoc(SourceLocation L) { QuestionLoc = L; }
+
+ SourceLocation getColonLoc() const { return ColonLoc; }
+ void setColonLoc(SourceLocation L) { ColonLoc = L; }
+
virtual SourceRange getSourceRange() const {
return SourceRange(getCond()->getLocStart(), getRHS()->getLocEnd());
}
- static bool classof(const Stmt *T) {
- return T->getStmtClass() == ConditionalOperatorClass;
+ 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();
@@ -1555,9 +1824,9 @@ 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)
+ explicit AddrLabelExpr(EmptyShell Empty)
: Expr(AddrLabelExprClass, Empty) { }
SourceLocation getAmpAmpLoc() const { return AmpAmpLoc; }
@@ -1568,15 +1837,15 @@ public:
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;
+ return T->getStmtClass() == AddrLabelExprClass;
}
static bool classof(const AddrLabelExpr *) { return true; }
-
+
// Iterators
virtual child_iterator child_begin();
virtual child_iterator child_end();
@@ -1592,7 +1861,7 @@ 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) { }
@@ -1603,17 +1872,17 @@ public:
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;
+ return T->getStmtClass() == StmtExprClass;
}
static bool classof(const StmtExpr *) { return true; }
-
+
// Iterators
virtual child_iterator child_begin();
virtual child_iterator child_end();
@@ -1628,8 +1897,8 @@ class TypesCompatibleExpr : public Expr {
QualType Type2;
SourceLocation BuiltinLoc, RParenLoc;
public:
- TypesCompatibleExpr(QualType ReturnType, SourceLocation BLoc,
- QualType t1, QualType t2, SourceLocation RP) :
+ TypesCompatibleExpr(QualType ReturnType, SourceLocation BLoc,
+ QualType t1, QualType t2, SourceLocation RP) :
Expr(TypesCompatibleExprClass, ReturnType), Type1(t1), Type2(t2),
BuiltinLoc(BLoc), RParenLoc(RP) {}
@@ -1641,21 +1910,21 @@ public:
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;
+ return T->getStmtClass() == TypesCompatibleExprClass;
}
static bool classof(const TypesCompatibleExpr *) { return true; }
-
+
// Iterators
virtual child_iterator child_begin();
virtual child_iterator child_end();
@@ -1677,25 +1946,28 @@ class ShuffleVectorExpr : public Expr {
Stmt **SubExprs;
unsigned NumExprs;
+protected:
+ virtual void DoDestroy(ASTContext &C);
+
public:
- ShuffleVectorExpr(Expr **args, unsigned nexpr,
- QualType Type, SourceLocation BLoc,
- SourceLocation RP) :
+ ShuffleVectorExpr(ASTContext &C, Expr **args, unsigned nexpr,
+ QualType Type, SourceLocation BLoc,
+ SourceLocation RP) :
Expr(ShuffleVectorExprClass, Type), BuiltinLoc(BLoc),
RParenLoc(RP), NumExprs(nexpr) {
-
- SubExprs = new Stmt*[nexpr];
+
+ SubExprs = new (C) Stmt*[nexpr];
for (unsigned i = 0; i < nexpr; i++)
SubExprs[i] = args[i];
}
/// \brief Build an empty vector-shuffle expression.
- explicit ShuffleVectorExpr(EmptyShell Empty)
+ 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; }
@@ -1703,19 +1975,17 @@ public:
return SourceRange(BuiltinLoc, RParenLoc);
}
static bool classof(const Stmt *T) {
- return T->getStmtClass() == ShuffleVectorExprClass;
+ return T->getStmtClass() == ShuffleVectorExprClass;
}
static bool classof(const ShuffleVectorExpr *) { return true; }
-
- ~ShuffleVectorExpr() {
- delete [] SubExprs;
- }
-
+
+ ~ShuffleVectorExpr() {}
+
/// 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!");
@@ -1726,20 +1996,20 @@ public:
return cast<Expr>(SubExprs[Index]);
}
- void setExprs(Expr ** Exprs, unsigned NumExprs);
+ void setExprs(ASTContext &C, 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
+/// 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
@@ -1753,13 +2023,13 @@ class ChooseExpr : public Expr {
SourceLocation BuiltinLoc, RParenLoc;
public:
ChooseExpr(SourceLocation BLoc, Expr *cond, Expr *lhs, Expr *rhs, QualType t,
- SourceLocation RP)
- : Expr(ChooseExprClass, t),
+ SourceLocation RP, bool TypeDependent, bool ValueDependent)
+ : Expr(ChooseExprClass, t, TypeDependent, ValueDependent),
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) { }
@@ -1783,7 +2053,7 @@ public:
SourceLocation getBuiltinLoc() const { return BuiltinLoc; }
void setBuiltinLoc(SourceLocation L) { BuiltinLoc = L; }
-
+
SourceLocation getRParenLoc() const { return RParenLoc; }
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
@@ -1791,10 +2061,10 @@ public:
return SourceRange(BuiltinLoc, RParenLoc);
}
static bool classof(const Stmt *T) {
- return T->getStmtClass() == ChooseExprClass;
+ return T->getStmtClass() == ChooseExprClass;
}
static bool classof(const ChooseExpr *) { return true; }
-
+
// Iterators
virtual child_iterator child_begin();
virtual child_iterator child_end();
@@ -1811,14 +2081,12 @@ class GNUNullExpr : public Expr {
SourceLocation TokenLoc;
public:
- GNUNullExpr(QualType Ty, SourceLocation Loc)
+ 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; }
@@ -1827,10 +2095,10 @@ public:
return SourceRange(TokenLoc);
}
static bool classof(const Stmt *T) {
- return T->getStmtClass() == GNUNullExprClass;
+ return T->getStmtClass() == GNUNullExprClass;
}
static bool classof(const GNUNullExpr *) { return true; }
-
+
// Iterators
virtual child_iterator child_begin();
virtual child_iterator child_end();
@@ -1846,7 +2114,7 @@ public:
Val(e),
BuiltinLoc(BLoc),
RParenLoc(RPLoc) { }
-
+
/// \brief Create an empty __builtin_va_start expression.
explicit VAArgExpr(EmptyShell Empty) : Expr(VAArgExprClass, Empty) { }
@@ -1856,23 +2124,23 @@ public:
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();
+ virtual child_iterator child_end();
};
-
+
/// @brief Describes an C or C++ initializer list.
///
/// InitListExpr describes an initializer list, which can be used to
@@ -1911,9 +2179,10 @@ public:
/// return NULL, indicating that the current initializer list also
/// serves as its syntactic form.
class InitListExpr : public Expr {
+ // FIXME: Eliminate this vector in favor of ASTContext allocation
std::vector<Stmt *> InitExprs;
SourceLocation LBraceLoc, RBraceLoc;
-
+
/// Contains the initializer list that describes the syntactic form
/// written in the source code.
InitListExpr *SyntacticForm;
@@ -1932,27 +2201,27 @@ public:
/// \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 {
+
+ 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) {
+
+ 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) {
+
+ 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
@@ -1984,7 +2253,7 @@ public:
bool isExplicit() {
return LBraceLoc.isValid() && RBraceLoc.isValid();
}
-
+
SourceLocation getLBraceLoc() const { return LBraceLoc; }
void setLBraceLoc(SourceLocation Loc) { LBraceLoc = Loc; }
SourceLocation getRBraceLoc() const { return RBraceLoc; }
@@ -1993,30 +2262,30 @@ public:
/// @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) {
+ 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;
+ 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(); }
@@ -2030,7 +2299,7 @@ public:
/// 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;
@@ -2070,7 +2339,7 @@ private:
unsigned NumSubExprs : 16;
- DesignatedInitExpr(QualType Ty, unsigned NumDesignators,
+ DesignatedInitExpr(QualType Ty, unsigned NumDesignators,
const Designator *Designators,
SourceLocation EqualOrColonLoc, bool GNUSyntax,
Expr **IndexExprs, unsigned NumIndexExprs,
@@ -2080,6 +2349,9 @@ private:
: Expr(DesignatedInitExprClass, EmptyShell()),
NumDesignators(0), Designators(0), NumSubExprs(NumSubExprs) { }
+protected:
+ virtual void DoDestroy(ASTContext &C);
+
public:
/// A field designator, e.g., ".x".
struct FieldDesignator {
@@ -2090,10 +2362,10 @@ public:
/// 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;
};
@@ -2109,7 +2381,7 @@ public:
/// indices. Only valid for GNU array-range designators.
unsigned EllipsisLoc;
/// The location of the ']' terminating the array range designator.
- unsigned RBracketLoc;
+ unsigned RBracketLoc;
};
/// @brief Represents a single C99 designator.
@@ -2138,8 +2410,8 @@ public:
Designator() {}
/// @brief Initializes a field designator.
- Designator(const IdentifierInfo *FieldName, SourceLocation DotLoc,
- SourceLocation FieldLoc)
+ Designator(const IdentifierInfo *FieldName, SourceLocation DotLoc,
+ SourceLocation FieldLoc)
: Kind(FieldDesignator) {
Field.NameOrField = reinterpret_cast<uintptr_t>(FieldName) | 0x01;
Field.DotLoc = DotLoc.getRawEncoding();
@@ -2147,7 +2419,7 @@ public:
}
/// @brief Initializes an array designator.
- Designator(unsigned Index, SourceLocation LBracketLoc,
+ Designator(unsigned Index, SourceLocation LBracketLoc,
SourceLocation RBracketLoc)
: Kind(ArrayDesignator) {
ArrayOrRange.Index = Index;
@@ -2157,7 +2429,7 @@ public:
}
/// @brief Initializes a GNU array-range designator.
- Designator(unsigned Index, SourceLocation LBracketLoc,
+ Designator(unsigned Index, SourceLocation LBracketLoc,
SourceLocation EllipsisLoc, SourceLocation RBracketLoc)
: Kind(ArrayRangeDesignator) {
ArrayOrRange.Index = Index;
@@ -2227,7 +2499,7 @@ public:
}
};
- static DesignatedInitExpr *Create(ASTContext &C, Designator *Designators,
+ static DesignatedInitExpr *Create(ASTContext &C, Designator *Designators,
unsigned NumDesignators,
Expr **IndexExprs, unsigned NumIndexExprs,
SourceLocation EqualOrColonLoc,
@@ -2241,8 +2513,8 @@ public:
// Iterator access to the designators.
typedef Designator* designators_iterator;
designators_iterator designators_begin() { return Designators; }
- designators_iterator designators_end() {
- return Designators + NumDesignators;
+ designators_iterator designators_end() {
+ return Designators + NumDesignators;
}
Designator *getDesignator(unsigned Idx) { return &designators_begin()[Idx]; }
@@ -2264,7 +2536,7 @@ public:
void setGNUSyntax(bool GNU) { GNUSyntax = GNU; }
/// @brief Retrieve the initializer value.
- Expr *getInit() const {
+ Expr *getInit() const {
return cast<Expr>(*const_cast<DesignatedInitExpr*>(this)->child_begin());
}
@@ -2294,21 +2566,19 @@ public:
/// \brief Replaces the designator at index @p Idx with the series
/// of designators in [First, Last).
- void ExpandDesignator(unsigned Idx, const Designator *First,
+ 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;
+ return T->getStmtClass() == DesignatedInitExprClass;
}
static bool classof(const DesignatedInitExpr *) { return true; }
// Iterators
virtual child_iterator child_begin();
- virtual child_iterator child_end();
+ virtual child_iterator child_end();
};
/// \brief Represents an implicitly-generated value initialization of
@@ -2319,16 +2589,16 @@ public:
/// initializations not explicitly specified by the user.
///
/// \see InitListExpr
-class ImplicitValueInitExpr : public Expr {
+class ImplicitValueInitExpr : public Expr {
public:
- explicit ImplicitValueInitExpr(QualType ty)
+ 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) {
+ static bool classof(const Stmt *T) {
return T->getStmtClass() == ImplicitValueInitExprClass;
}
static bool classof(const ImplicitValueInitExpr *) { return true; }
@@ -2337,13 +2607,60 @@ public:
return SourceRange();
}
- ImplicitValueInitExpr *Clone(ASTContext &C) const;
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+
+class ParenListExpr : public Expr {
+ Stmt **Exprs;
+ unsigned NumExprs;
+ SourceLocation LParenLoc, RParenLoc;
+
+protected:
+ virtual void DoDestroy(ASTContext& C);
+
+public:
+ ParenListExpr(ASTContext& C, SourceLocation lparenloc, Expr **exprs,
+ unsigned numexprs, SourceLocation rparenloc);
+
+ ~ParenListExpr() {}
+
+ /// \brief Build an empty paren list.
+ //explicit ParenListExpr(EmptyShell Empty) : Expr(ParenListExprClass, Empty) { }
+
+ unsigned getNumExprs() const { return NumExprs; }
+
+ const Expr* getExpr(unsigned Init) const {
+ assert(Init < getNumExprs() && "Initializer access out of range!");
+ return cast_or_null<Expr>(Exprs[Init]);
+ }
+
+ Expr* getExpr(unsigned Init) {
+ assert(Init < getNumExprs() && "Initializer access out of range!");
+ return cast_or_null<Expr>(Exprs[Init]);
+ }
+
+ Expr **getExprs() { return reinterpret_cast<Expr **>(Exprs); }
+
+ SourceLocation getLParenLoc() const { return LParenLoc; }
+ SourceLocation getRParenLoc() const { return RParenLoc; }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(LParenLoc, RParenLoc);
+ }
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ParenListExprClass;
+ }
+ static bool classof(const ParenListExpr *) { return true; }
// Iterators
virtual child_iterator child_begin();
- virtual child_iterator child_end();
+ virtual child_iterator child_end();
};
+
//===----------------------------------------------------------------------===//
// Clang Extensions
//===----------------------------------------------------------------------===//
@@ -2363,9 +2680,9 @@ class ExtVectorElementExpr : public Expr {
public:
ExtVectorElementExpr(QualType ty, Expr *base, IdentifierInfo &accessor,
SourceLocation loc)
- : Expr(ExtVectorElementExprClass, ty),
+ : Expr(ExtVectorElementExprClass, ty),
Base(base), Accessor(&accessor), AccessorLoc(loc) {}
-
+
/// \brief Build an empty vector element expression.
explicit ExtVectorElementExpr(EmptyShell Empty)
: Expr(ExtVectorElementExprClass, Empty) { }
@@ -2382,28 +2699,28 @@ public:
/// 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 Stmt *T) {
+ return T->getStmtClass() == ExtVectorElementExprClass;
}
static bool classof(const ExtVectorElementExpr *) { return true; }
-
+
// Iterators
virtual child_iterator child_begin();
virtual child_iterator child_end();
@@ -2418,7 +2735,7 @@ protected:
bool HasBlockDeclRefExprs;
public:
BlockExpr(BlockDecl *BD, QualType ty, bool hasBlockDeclRefExprs)
- : Expr(BlockExprClass, ty),
+ : Expr(BlockExprClass, ty),
TheBlock(BD), HasBlockDeclRefExprs(hasBlockDeclRefExprs) {}
/// \brief Build an empty block expression.
@@ -2445,25 +2762,25 @@ public:
bool hasBlockDeclRefExprs() const { return HasBlockDeclRefExprs; }
void setHasBlockDeclRefExprs(bool BDRE) { HasBlockDeclRefExprs = BDRE; }
- static bool classof(const Stmt *T) {
+ 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;
+ ValueDecl *D;
SourceLocation Loc;
bool IsByRef : 1;
bool ConstQualAdded : 1;
public:
- BlockDeclRefExpr(ValueDecl *d, QualType t, SourceLocation l, bool ByRef,
+ BlockDeclRefExpr(ValueDecl *d, QualType t, SourceLocation l, bool ByRef,
bool constAdded = false) :
Expr(BlockDeclRefExprClass, t), D(d), Loc(l), IsByRef(ByRef),
ConstQualAdded(constAdded) {}
@@ -2472,7 +2789,7 @@ public:
// block.
explicit BlockDeclRefExpr(EmptyShell Empty)
: Expr(BlockDeclRefExprClass, Empty) { }
-
+
ValueDecl *getDecl() { return D; }
const ValueDecl *getDecl() const { return D; }
void setDecl(ValueDecl *VD) { D = VD; }
@@ -2481,18 +2798,18 @@ public:
void setLocation(SourceLocation L) { Loc = L; }
virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
-
+
bool isByRef() const { return IsByRef; }
void setByRef(bool BR) { IsByRef = BR; }
-
+
bool isConstQualAdded() const { return ConstQualAdded; }
void setConstQualAdded(bool C) { ConstQualAdded = C; }
- static bool classof(const Stmt *T) {
- return T->getStmtClass() == BlockDeclRefExprClass;
+ 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();
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index 7d76a49..3f66b1f 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -22,6 +22,7 @@ namespace clang {
class CXXConstructorDecl;
class CXXDestructorDecl;
+ class CXXMethodDecl;
class CXXTemporary;
//===--------------------------------------------------------------------===//
@@ -46,15 +47,19 @@ class CXXOperatorCallExpr : public CallExpr {
OverloadedOperatorKind Operator;
public:
- CXXOperatorCallExpr(ASTContext& C, OverloadedOperatorKind Op, Expr *fn,
- Expr **args, unsigned numargs, QualType t,
+ 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) {}
+ explicit CXXOperatorCallExpr(ASTContext& C, EmptyShell Empty) :
+ CallExpr(C, CXXOperatorCallExprClass, Empty) { }
+
/// getOperator - Returns the kind of overloaded operator that this
/// expression refers to.
OverloadedOperatorKind getOperator() const { return Operator; }
+ void setOperator(OverloadedOperatorKind Kind) { Operator = Kind; }
/// getOperatorLoc - Returns the location of the operator symbol in
/// the expression. When @c getOperator()==OO_Call, this is the
@@ -64,9 +69,9 @@ public:
SourceLocation getOperatorLoc() const { return getRParenLoc(); }
virtual SourceRange getSourceRange() const;
-
- static bool classof(const Stmt *T) {
- return T->getStmtClass() == CXXOperatorCallExprClass;
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CXXOperatorCallExprClass;
}
static bool classof(const CXXOperatorCallExpr *) { return true; }
};
@@ -90,7 +95,7 @@ public:
/// operation would return "x".
Expr *getImplicitObjectArgument();
- static bool classof(const Stmt *T) {
+ static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXMemberCallExprClass;
}
static bool classof(const CXXMemberCallExpr *) { return true; }
@@ -108,9 +113,9 @@ 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) {}
+ CXXNamedCastExpr(StmtClass SC, QualType ty, CastKind kind, Expr *op,
+ QualType writtenTy, SourceLocation l)
+ : ExplicitCastExpr(SC, ty, kind, op, writtenTy), Loc(l) {}
public:
const char *getCastName() const;
@@ -123,7 +128,7 @@ public:
virtual SourceRange getSourceRange() const {
return SourceRange(Loc, getSubExpr()->getSourceRange().getEnd());
}
- static bool classof(const Stmt *T) {
+ static bool classof(const Stmt *T) {
switch (T->getStmtClass()) {
case CXXNamedCastExprClass:
case CXXStaticCastExprClass:
@@ -139,32 +144,34 @@ public:
};
/// 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) {}
+ CXXStaticCastExpr(QualType ty, CastKind kind, Expr *op,
+ QualType writtenTy, SourceLocation l)
+ : CXXNamedCastExpr(CXXStaticCastExprClass, ty, kind, op, writtenTy, l) {}
- static bool classof(const Stmt *T) {
+ 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
+/// (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) {}
+ CXXDynamicCastExpr(QualType ty, CastKind kind, Expr *op, QualType writtenTy,
+ SourceLocation l)
+ : CXXNamedCastExpr(CXXDynamicCastExprClass, ty, kind, op, writtenTy, l) {}
- static bool classof(const Stmt *T) {
+ static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXDynamicCastExprClass;
}
static bool classof(const CXXDynamicCastExpr *) { return true; }
@@ -173,16 +180,17 @@ public:
/// 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) {}
+ CXXReinterpretCastExpr(QualType ty, CastKind kind, Expr *op,
+ QualType writtenTy, SourceLocation l)
+ : CXXNamedCastExpr(CXXReinterpretCastExprClass, ty, kind, op,
+ writtenTy, l) {}
- static bool classof(const Stmt *T) {
+ static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXReinterpretCastExprClass;
}
static bool classof(const CXXReinterpretCastExpr *) { return true; }
@@ -190,41 +198,39 @@ public:
/// 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,
+ CXXConstCastExpr(QualType ty, Expr *op, QualType writtenTy,
SourceLocation l)
- : CXXNamedCastExpr(CXXConstCastExprClass, ty, op, writtenTy, l) {}
+ : CXXNamedCastExpr(CXXConstCastExprClass, ty, CK_NoOp, op, writtenTy, l) {}
- static bool classof(const Stmt *T) {
+ 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) :
+ 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) {
+
+ 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();
@@ -237,8 +243,6 @@ 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) {
@@ -318,7 +322,7 @@ class CXXThisExpr : public Expr {
SourceLocation Loc;
public:
- CXXThisExpr(SourceLocation L, QualType Type)
+ 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)
@@ -327,7 +331,7 @@ public:
virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
- static bool classof(const Stmt *T) {
+ static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXThisExprClass;
}
static bool classof(const CXXThisExpr *) { return true; }
@@ -379,14 +383,20 @@ public:
/// supply arguments for all of the parameters.
class CXXDefaultArgExpr : public Expr {
ParmVarDecl *Param;
+
+protected:
+ CXXDefaultArgExpr(StmtClass SC, ParmVarDecl *param)
+ : Expr(SC, param->hasUnparsedDefaultArg() ?
+ param->getType().getNonReferenceType()
+ : param->getDefaultArg()->getType()),
+ Param(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) { }
+ static CXXDefaultArgExpr *Create(ASTContext &C, ParmVarDecl *Param) {
+ return new (C) CXXDefaultArgExpr(CXXDefaultArgExprClass, Param);
+ }
// Retrieve the parameter that the argument was created from.
const ParmVarDecl *getParam() const { return Param; }
@@ -416,36 +426,39 @@ public:
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,
+ static CXXTemporary *Create(ASTContext &C,
const CXXDestructorDecl *Destructor);
- void Destroy(ASTContext &C);
-
+
+ void Destroy(ASTContext &Ctx);
+
const CXXDestructorDecl *getDestructor() const { return Destructor; }
};
-/// CXXBindTemporaryExpr - Represents binding an expression to a temporary,
+/// 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)
+ CXXBindTemporaryExpr(CXXTemporary *temp, Expr* subexpr)
: Expr(CXXBindTemporaryExprClass,
subexpr->getType()), Temp(temp), SubExpr(subexpr) { }
- ~CXXBindTemporaryExpr() { }
+ ~CXXBindTemporaryExpr() { }
+
+protected:
+ virtual void DoDestroy(ASTContext &C);
public:
- static CXXBindTemporaryExpr *Create(ASTContext &C, CXXTemporary *Temp,
+ static CXXBindTemporaryExpr *Create(ASTContext &C, CXXTemporary *Temp,
Expr* SubExpr);
- void Destroy(ASTContext &C);
-
+
CXXTemporary *getTemporary() { return Temp; }
const CXXTemporary *getTemporary() const { return Temp; }
@@ -453,7 +466,9 @@ public:
Expr *getSubExpr() { return cast<Expr>(SubExpr); }
void setSubExpr(Expr *E) { SubExpr = E; }
- virtual SourceRange getSourceRange() const { return SourceRange(); }
+ virtual SourceRange getSourceRange() const {
+ return SubExpr->getSourceRange();
+ }
// Implement isa/cast/dyncast/etc.
static bool classof(const Stmt *T) {
@@ -471,32 +486,38 @@ class CXXConstructExpr : public Expr {
CXXConstructorDecl *Constructor;
bool Elidable;
-
+
Stmt **Args;
unsigned NumArgs;
-
protected:
- CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T,
+ CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T,
CXXConstructorDecl *d, bool elidable,
Expr **args, unsigned numargs);
- ~CXXConstructExpr() { }
+ ~CXXConstructExpr() { }
+
+ virtual void DoDestroy(ASTContext &C);
public:
+ /// \brief Construct an empty C++ construction expression that will store
+ /// \p numargs arguments.
+ CXXConstructExpr(EmptyShell Empty, ASTContext &C, unsigned numargs);
+
static CXXConstructExpr *Create(ASTContext &C, QualType T,
- CXXConstructorDecl *D, bool Elidable,
+ CXXConstructorDecl *D, bool Elidable,
Expr **Args, unsigned NumArgs);
-
- void Destroy(ASTContext &C);
-
- CXXConstructorDecl* getConstructor() const { return Constructor; }
+
+ CXXConstructorDecl* getConstructor() const { return Constructor; }
+ void setConstructor(CXXConstructorDecl *C) { Constructor = C; }
+
/// \brief Whether this construction is elidable.
bool isElidable() const { return Elidable; }
-
+ void setElidable(bool E) { Elidable = E; }
+
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; }
@@ -504,14 +525,36 @@ public:
unsigned getNumArgs() const { return NumArgs; }
- virtual SourceRange getSourceRange() const { return SourceRange(); }
+ /// getArg - Return the specified argument.
+ Expr *getArg(unsigned Arg) {
+ assert(Arg < NumArgs && "Arg access out of range!");
+ return cast<Expr>(Args[Arg]);
+ }
+ const Expr *getArg(unsigned Arg) const {
+ assert(Arg < NumArgs && "Arg access out of range!");
+ return cast<Expr>(Args[Arg]);
+ }
+
+ /// setArg - Set the specified argument.
+ void setArg(unsigned Arg, Expr *ArgExpr) {
+ assert(Arg < NumArgs && "Arg access out of range!");
+ Args[Arg] = ArgExpr;
+ }
+
+ virtual SourceRange getSourceRange() const {
+ // FIXME: Should we know where the parentheses are, if there are any?
+ if (NumArgs == 0)
+ return SourceRange();
+
+ return SourceRange(Args[0]->getLocStart(), Args[NumArgs - 1]->getLocEnd());
+ }
- static bool classof(const Stmt *T) {
+ 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();
@@ -524,20 +567,21 @@ 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) {}
+ CXXFunctionalCastExpr(QualType ty, QualType writtenTy,
+ SourceLocation tyBeginLoc, CastKind kind,
+ Expr *castExpr, SourceLocation rParenLoc)
+ : ExplicitCastExpr(CXXFunctionalCastExprClass, ty, kind, 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 Stmt *T) {
+ return T->getStmtClass() == CXXFunctionalCastExprClass;
}
static bool classof(const CXXFunctionalCastExpr *) { return true; }
};
@@ -545,7 +589,7 @@ public:
/// @brief Represents a C++ functional cast expression that builds a
/// temporary object.
///
-/// This expression type represents a C++ "functional" cast
+/// 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
@@ -566,12 +610,12 @@ class CXXTemporaryObjectExpr : public CXXConstructExpr {
SourceLocation RParenLoc;
public:
- CXXTemporaryObjectExpr(ASTContext &C, CXXConstructorDecl *Cons,
- QualType writtenTy, SourceLocation tyBeginLoc,
- Expr **Args,unsigned NumArgs,
+ CXXTemporaryObjectExpr(ASTContext &C, CXXConstructorDecl *Cons,
+ QualType writtenTy, SourceLocation tyBeginLoc,
+ Expr **Args,unsigned NumArgs,
SourceLocation rParenLoc);
- ~CXXTemporaryObjectExpr() { }
+ ~CXXTemporaryObjectExpr() { }
SourceLocation getTypeBeginLoc() const { return TyBeginLoc; }
SourceLocation getRParenLoc() const { return RParenLoc; }
@@ -579,7 +623,7 @@ public:
virtual SourceRange getSourceRange() const {
return SourceRange(TyBeginLoc, RParenLoc);
}
- static bool classof(const Stmt *T) {
+ static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXTemporaryObjectExprClass;
}
static bool classof(const CXXTemporaryObjectExpr *) { return true; }
@@ -596,30 +640,28 @@ class CXXZeroInitValueExpr : public Expr {
public:
CXXZeroInitValueExpr(QualType ty, SourceLocation tyBeginLoc,
- SourceLocation rParenLoc ) :
+ 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();
+ 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) {
+ 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();
@@ -634,28 +676,26 @@ class CXXConditionDeclExpr : public DeclRefExpr {
public:
CXXConditionDeclExpr(SourceLocation startLoc,
SourceLocation eqLoc, VarDecl *var)
- : DeclRefExpr(CXXConditionDeclExprClass, 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) {
+
+ 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();
@@ -707,7 +747,7 @@ public:
QualType getAllocatedType() const {
assert(getType()->isPointerType());
- return getType()->getAsPointerType()->getPointeeType();
+ return getType()->getAs<PointerType>()->getPointeeType();
}
FunctionDecl *getOperatorNew() const { return OperatorNew; }
@@ -831,6 +871,108 @@ public:
virtual child_iterator child_end();
};
+/// \brief Represents a C++ pseudo-destructor (C++ [expr.pseudo]).
+///
+/// Example:
+///
+/// \code
+/// template<typename T>
+/// void destroy(T* ptr) {
+/// ptr->~T();
+/// }
+/// \endcode
+///
+/// When the template is parsed, the expression \c ptr->~T will be stored as
+/// a member reference expression. If it then instantiated with a scalar type
+/// as a template argument for T, the resulting expression will be a
+/// pseudo-destructor expression.
+class CXXPseudoDestructorExpr : public Expr {
+ /// \brief The base expression (that is being destroyed).
+ Stmt *Base;
+
+ /// \brief Whether the operator was an arrow ('->'); otherwise, it was a
+ /// period ('.').
+ bool IsArrow : 1;
+
+ /// \brief The location of the '.' or '->' operator.
+ SourceLocation OperatorLoc;
+
+ /// \brief The nested-name-specifier that follows the operator, if present.
+ NestedNameSpecifier *Qualifier;
+
+ /// \brief The source range that covers the nested-name-specifier, if
+ /// present.
+ SourceRange QualifierRange;
+
+ /// \brief The type being destroyed.
+ QualType DestroyedType;
+
+ /// \brief The location of the type after the '~'.
+ SourceLocation DestroyedTypeLoc;
+
+public:
+ CXXPseudoDestructorExpr(ASTContext &Context,
+ Expr *Base, bool isArrow, SourceLocation OperatorLoc,
+ NestedNameSpecifier *Qualifier,
+ SourceRange QualifierRange,
+ QualType DestroyedType,
+ SourceLocation DestroyedTypeLoc)
+ : Expr(CXXPseudoDestructorExprClass,
+ Context.getPointerType(Context.getFunctionType(Context.VoidTy, 0, 0,
+ false, 0)),
+ /*isTypeDependent=*/false,
+ /*isValueDependent=*/Base->isValueDependent()),
+ Base(static_cast<Stmt *>(Base)), IsArrow(isArrow),
+ OperatorLoc(OperatorLoc), Qualifier(Qualifier),
+ QualifierRange(QualifierRange), DestroyedType(DestroyedType),
+ DestroyedTypeLoc(DestroyedTypeLoc) { }
+
+ void setBase(Expr *E) { Base = E; }
+ Expr *getBase() const { return cast<Expr>(Base); }
+
+ /// \brief Determines whether this member expression actually had
+ /// a C++ nested-name-specifier prior to the name of the member, e.g.,
+ /// x->Base::foo.
+ bool hasQualifier() const { return Qualifier != 0; }
+
+ /// \brief If the member name was qualified, retrieves the source range of
+ /// the nested-name-specifier that precedes the member name. Otherwise,
+ /// returns an empty source range.
+ SourceRange getQualifierRange() const { return QualifierRange; }
+
+ /// \brief If the member name was qualified, retrieves the
+ /// nested-name-specifier that precedes the member name. Otherwise, returns
+ /// NULL.
+ NestedNameSpecifier *getQualifier() const { return Qualifier; }
+
+ /// \brief Determine whether this pseudo-destructor expression was written
+ /// using an '->' (otherwise, it used a '.').
+ bool isArrow() const { return IsArrow; }
+ void setArrow(bool A) { IsArrow = A; }
+
+ /// \brief Retrieve the location of the '.' or '->' operator.
+ SourceLocation getOperatorLoc() const { return OperatorLoc; }
+
+ /// \brief Retrieve the type that is being destroyed.
+ QualType getDestroyedType() const { return DestroyedType; }
+
+ /// \brief Retrieve the location of the type being destroyed.
+ SourceLocation getDestroyedTypeLoc() const { return DestroyedTypeLoc; }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(Base->getLocStart(), DestroyedTypeLoc);
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CXXPseudoDestructorExprClass;
+ }
+ static bool classof(const CXXPseudoDestructorExpr *) { 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.
///
@@ -848,7 +990,7 @@ public:
/// }
/// @endcode
class UnresolvedFunctionNameExpr : public Expr {
- /// The name that was present in the source
+ /// The name that was present in the source
DeclarationName Name;
/// The location of this name in the source code
@@ -867,9 +1009,7 @@ public:
virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
- UnresolvedFunctionNameExpr* Clone(ASTContext &C) const;
-
- static bool classof(const Stmt *T) {
+ static bool classof(const Stmt *T) {
return T->getStmtClass() == UnresolvedFunctionNameExprClass;
}
static bool classof(const UnresolvedFunctionNameExpr *) { return true; }
@@ -909,7 +1049,7 @@ public:
QualType getQueriedType() const { return QueriedType; }
- bool EvaluateTrait() const;
+ bool EvaluateTrait(ASTContext&) const;
static bool classof(const Stmt *T) {
return T->getStmtClass() == UnaryTypeTraitExprClass;
@@ -934,9 +1074,9 @@ class QualifiedDeclRefExpr : public DeclRefExpr {
NestedNameSpecifier *NNS;
public:
- QualifiedDeclRefExpr(NamedDecl *d, QualType t, SourceLocation l, bool TD,
+ QualifiedDeclRefExpr(NamedDecl *d, QualType t, SourceLocation l, bool TD,
bool VD, SourceRange R, NestedNameSpecifier *NNS)
- : DeclRefExpr(QualifiedDeclRefExprClass, d, t, l, TD, VD),
+ : DeclRefExpr(QualifiedDeclRefExprClass, d, t, l, TD, VD),
QualifierRange(R), NNS(NNS) { }
/// \brief Retrieve the source range of the nested-name-specifier.
@@ -946,8 +1086,8 @@ public:
/// declaration.
NestedNameSpecifier *getQualifier() const { return NNS; }
- virtual SourceRange getSourceRange() const {
- return SourceRange(QualifierRange.getBegin(), getLocation());
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(QualifierRange.getBegin(), getLocation());
}
static bool classof(const Stmt *T) {
@@ -985,11 +1125,16 @@ class UnresolvedDeclRefExpr : public Expr {
/// declaration name.
NestedNameSpecifier *NNS;
+ /// \brief Whether this expr is an address of (&) operand.
+ bool IsAddressOfOperand;
+
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) { }
+ SourceRange R, NestedNameSpecifier *NNS,
+ bool IsAddressOfOperand)
+ : Expr(UnresolvedDeclRefExprClass, T, true, true),
+ Name(N), Loc(L), QualifierRange(R), NNS(NNS),
+ IsAddressOfOperand(IsAddressOfOperand) { }
/// \brief Retrieve the name that this expression refers to.
DeclarationName getDeclName() const { return Name; }
@@ -1004,8 +1149,11 @@ public:
/// declaration.
NestedNameSpecifier *getQualifier() const { return NNS; }
- virtual SourceRange getSourceRange() const {
- return SourceRange(QualifierRange.getBegin(), getLocation());
+ /// \brief Retrieve whether this is an address of (&) operand.
+
+ bool isAddressOfOperand() const { return IsAddressOfOperand; }
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(QualifierRange.getBegin(), getLocation());
}
static bool classof(const Stmt *T) {
@@ -1017,40 +1165,42 @@ public:
virtual StmtIterator child_end();
};
-/// \brief An expression that refers to a C++ template-id, such as
-/// @c isa<FunctionDecl>.
+/// \brief An expression that refers to a C++ template-id, such as
+/// @c isa<FunctionDecl>.
class TemplateIdRefExpr : public Expr {
/// \brief If this template-id was qualified-id, e.g., @c std::sort<int>,
/// this nested name specifier contains the @c std::.
NestedNameSpecifier *Qualifier;
-
+
/// \brief If this template-id was a qualified-id, e.g., @c std::sort<int>,
/// this covers the source code range of the @c std::.
SourceRange QualifierRange;
-
+
/// \brief The actual template to which this template-id refers.
TemplateName Template;
-
+
/// \brief The source location of the template name.
SourceLocation TemplateNameLoc;
/// \brief The source location of the left angle bracket ('<');
SourceLocation LAngleLoc;
-
+
/// \brief The source location of the right angle bracket ('>');
SourceLocation RAngleLoc;
-
+
/// \brief The number of template arguments in TemplateArgs.
unsigned NumTemplateArgs;
-
+
TemplateIdRefExpr(QualType T,
NestedNameSpecifier *Qualifier, SourceRange QualifierRange,
TemplateName Template, SourceLocation TemplateNameLoc,
- SourceLocation LAngleLoc,
+ SourceLocation LAngleLoc,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs,
SourceLocation RAngleLoc);
-
+
+ virtual void DoDestroy(ASTContext &Context);
+
public:
static TemplateIdRefExpr *
Create(ASTContext &Context, QualType T,
@@ -1058,77 +1208,77 @@ public:
TemplateName Template, SourceLocation TemplateNameLoc,
SourceLocation LAngleLoc, const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs, SourceLocation RAngleLoc);
-
- void Destroy(ASTContext &Context);
-
+
/// \brief Retrieve the nested name specifier used to qualify the name of
/// this template-id, e.g., the "std::sort" in @c std::sort<int>, or NULL
/// if this template-id was an unqualified-id.
NestedNameSpecifier *getQualifier() const { return Qualifier; }
-
+
/// \brief Retrieve the source range describing the nested name specifier
/// used to qualified the name of this template-id, if the name was qualified.
SourceRange getQualifierRange() const { return QualifierRange; }
-
+
/// \brief Retrieve the name of the template referenced, e.g., "sort" in
/// @c std::sort<int>;
TemplateName getTemplateName() const { return Template; }
-
+
/// \brief Retrieve the location of the name of the template referenced, e.g.,
/// the location of "sort" in @c std::sort<int>.
SourceLocation getTemplateNameLoc() const { return TemplateNameLoc; }
-
- /// \brief Retrieve the location of the left angle bracket following the
+
+ /// \brief Retrieve the location of the left angle bracket following the
/// template name ('<').
SourceLocation getLAngleLoc() const { return LAngleLoc; }
-
+
/// \brief Retrieve the template arguments provided as part of this
/// template-id.
- const TemplateArgument *getTemplateArgs() const {
+ const TemplateArgument *getTemplateArgs() const {
return reinterpret_cast<const TemplateArgument *>(this + 1);
}
-
+
/// \brief Retrieve the number of template arguments provided as part of this
/// template-id.
unsigned getNumTemplateArgs() const { return NumTemplateArgs; }
-
- /// \brief Retrieve the location of the right angle bracket following the
+
+ /// \brief Retrieve the location of the right angle bracket following the
/// template arguments ('>').
SourceLocation getRAngleLoc() const { return RAngleLoc; }
-
+
virtual SourceRange getSourceRange() const {
return SourceRange(Qualifier? QualifierRange.getBegin() : TemplateNameLoc,
RAngleLoc);
}
-
+
// Iterators
virtual child_iterator child_begin();
virtual child_iterator child_end();
-
- static bool classof(const Stmt *T) {
+
+ static bool classof(const Stmt *T) {
return T->getStmtClass() == TemplateIdRefExprClass;
}
static bool classof(const TemplateIdRefExpr *) { return true; }
};
-
+
class CXXExprWithTemporaries : public Expr {
Stmt *SubExpr;
-
+
CXXTemporary **Temps;
unsigned NumTemps;
bool ShouldDestroyTemps;
-
- CXXExprWithTemporaries(Expr *SubExpr, CXXTemporary **Temps,
+
+ CXXExprWithTemporaries(Expr *SubExpr, CXXTemporary **Temps,
unsigned NumTemps, bool ShouldDestroyTemps);
~CXXExprWithTemporaries();
-
+
+protected:
+ virtual void DoDestroy(ASTContext &C);
+
public:
static CXXExprWithTemporaries *Create(ASTContext &C, Expr *SubExpr,
CXXTemporary **Temps, unsigned NumTemps,
bool ShouldDestroyTemporaries);
- void Destroy(ASTContext &C);
-
+
unsigned getNumTemporaries() const { return NumTemps; }
CXXTemporary *getTemporary(unsigned i) {
assert(i < NumTemps && "Index out of range");
@@ -1138,16 +1288,18 @@ public:
assert(i < NumTemps && "Index out of range");
return Temps[i];
}
-
+
bool shouldDestroyTemporaries() const { return ShouldDestroyTemps; }
-
+
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(); }
+ virtual SourceRange getSourceRange() const {
+ return SubExpr->getSourceRange();
+ }
// Implement isa/cast/dyncast/etc.
static bool classof(const Stmt *T) {
@@ -1196,7 +1348,7 @@ class CXXUnresolvedConstructExpr : public Expr {
/// \brief The number of arguments used to construct the type.
unsigned NumArgs;
-
+
CXXUnresolvedConstructExpr(SourceLocation TyBegin,
QualType T,
SourceLocation LParenLoc,
@@ -1205,7 +1357,7 @@ class CXXUnresolvedConstructExpr : public Expr {
SourceLocation RParenLoc);
public:
- static CXXUnresolvedConstructExpr *Create(ASTContext &C,
+ static CXXUnresolvedConstructExpr *Create(ASTContext &C,
SourceLocation TyBegin,
QualType T,
SourceLocation LParenLoc,
@@ -1247,7 +1399,7 @@ public:
virtual SourceRange getSourceRange() const {
return SourceRange(TyBeginLoc, RParenLoc);
}
- static bool classof(const Stmt *T) {
+ static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXUnresolvedConstructExprClass;
}
static bool classof(const CXXUnresolvedConstructExpr *) { return true; }
@@ -1257,37 +1409,108 @@ public:
virtual child_iterator child_end();
};
-/// \brief
+/// \brief Represents a C++ member access expression where the actual member
+/// referenced could not be resolved, e.g., because the base expression or the
+/// member name was dependent.
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;
+ bool IsArrow : 1;
+
+ /// \brief Whether this member expression has explicitly-specified template
+ /// arguments.
+ bool HasExplicitTemplateArgumentList : 1;
/// \brief The location of the '->' or '.' operator.
SourceLocation OperatorLoc;
+ /// \brief The nested-name-specifier that precedes the member name, if any.
+ NestedNameSpecifier *Qualifier;
+
+ /// \brief The source range covering the nested name specifier.
+ SourceRange QualifierRange;
+
+ /// \brief In a qualified member access expression such as t->Base::f, this
+ /// member stores the resolves of name lookup in the context of the member
+ /// access expression, to be used at instantiation time.
+ ///
+ /// FIXME: This member, along with the Qualifier and QualifierRange, could
+ /// be stuck into a structure that is optionally allocated at the end of
+ /// the CXXUnresolvedMemberExpr, to save space in the common case.
+ NamedDecl *FirstQualifierFoundInScope;
+
/// \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.
+ /// FIXME: could also be a template-id
DeclarationName Member;
/// \brief The location of the member name.
SourceLocation MemberLoc;
+ /// \brief Retrieve the explicit template argument list that followed the
+ /// member template name, if any.
+ ExplicitTemplateArgumentList *getExplicitTemplateArgumentList() {
+ if (!HasExplicitTemplateArgumentList)
+ return 0;
+
+ return reinterpret_cast<ExplicitTemplateArgumentList *>(this + 1);
+ }
+
+ /// \brief Retrieve the explicit template argument list that followed the
+ /// member template name, if any.
+ const ExplicitTemplateArgumentList *getExplicitTemplateArgumentList() const {
+ return const_cast<CXXUnresolvedMemberExpr *>(this)
+ ->getExplicitTemplateArgumentList();
+ }
+
+ CXXUnresolvedMemberExpr(ASTContext &C,
+ Expr *Base, bool IsArrow,
+ SourceLocation OperatorLoc,
+ NestedNameSpecifier *Qualifier,
+ SourceRange QualifierRange,
+ NamedDecl *FirstQualifierFoundInScope,
+ DeclarationName Member,
+ SourceLocation MemberLoc,
+ bool HasExplicitTemplateArgs,
+ SourceLocation LAngleLoc,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ SourceLocation RAngleLoc);
+
public:
- CXXUnresolvedMemberExpr(ASTContext &C,
- Expr *Base, bool IsArrow,
+ CXXUnresolvedMemberExpr(ASTContext &C,
+ Expr *Base, bool IsArrow,
SourceLocation OperatorLoc,
+ NestedNameSpecifier *Qualifier,
+ SourceRange QualifierRange,
+ NamedDecl *FirstQualifierFoundInScope,
DeclarationName Member,
SourceLocation MemberLoc)
- : Expr(CXXUnresolvedMemberExprClass, C.DependentTy, true, true),
- Base(Base), IsArrow(IsArrow), OperatorLoc(OperatorLoc),
- Member(Member), MemberLoc(MemberLoc) { }
+ : Expr(CXXUnresolvedMemberExprClass, C.DependentTy, true, true),
+ Base(Base), IsArrow(IsArrow), HasExplicitTemplateArgumentList(false),
+ OperatorLoc(OperatorLoc),
+ Qualifier(Qualifier), QualifierRange(QualifierRange),
+ FirstQualifierFoundInScope(FirstQualifierFoundInScope),
+ Member(Member), MemberLoc(MemberLoc) { }
+
+ static CXXUnresolvedMemberExpr *
+ Create(ASTContext &C,
+ Expr *Base, bool IsArrow,
+ SourceLocation OperatorLoc,
+ NestedNameSpecifier *Qualifier,
+ SourceRange QualifierRange,
+ NamedDecl *FirstQualifierFoundInScope,
+ DeclarationName Member,
+ SourceLocation MemberLoc,
+ bool HasExplicitTemplateArgs,
+ SourceLocation LAngleLoc,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ SourceLocation RAngleLoc);
/// \brief Retrieve the base object of this member expressions,
/// e.g., the \c x in \c x.m.
@@ -1303,6 +1526,29 @@ public:
SourceLocation getOperatorLoc() const { return OperatorLoc; }
void setOperatorLoc(SourceLocation L) { OperatorLoc = L; }
+ /// \brief Retrieve the nested-name-specifier that qualifies the member
+ /// name.
+ NestedNameSpecifier *getQualifier() const { return Qualifier; }
+
+ /// \brief Retrieve the source range covering the nested-name-specifier
+ /// that qualifies the member name.
+ SourceRange getQualifierRange() const { return QualifierRange; }
+
+ /// \brief Retrieve the first part of the nested-name-specifier that was
+ /// found in the scope of the member access expression when the member access
+ /// was initially parsed.
+ ///
+ /// This function only returns a useful result when member access expression
+ /// uses a qualified member name, e.g., "x.Base::f". Here, the declaration
+ /// returned by this function describes what was found by unqualified name
+ /// lookup for the identifier "Base" within the scope of the member access
+ /// expression itself. At template instantiation time, this information is
+ /// combined with the results of name lookup into the type of the object
+ /// expression itself (the class type of x).
+ NamedDecl *getFirstQualifierFoundInScope() const {
+ return FirstQualifierFoundInScope;
+ }
+
/// \brief Retrieve the name of the member that this expression
/// refers to.
DeclarationName getMember() const { return Member; }
@@ -1313,11 +1559,58 @@ public:
SourceLocation getMemberLoc() const { return MemberLoc; }
void setMemberLoc(SourceLocation L) { MemberLoc = L; }
+ /// \brief Determines whether this member expression actually had a C++
+ /// template argument list explicitly specified, e.g., x.f<int>.
+ bool hasExplicitTemplateArgumentList() {
+ return HasExplicitTemplateArgumentList;
+ }
+
+ /// \brief Retrieve the location of the left angle bracket following the
+ /// member name ('<'), if any.
+ SourceLocation getLAngleLoc() const {
+ if (!HasExplicitTemplateArgumentList)
+ return SourceLocation();
+
+ return getExplicitTemplateArgumentList()->LAngleLoc;
+ }
+
+ /// \brief Retrieve the template arguments provided as part of this
+ /// template-id.
+ const TemplateArgument *getTemplateArgs() const {
+ if (!HasExplicitTemplateArgumentList)
+ return 0;
+
+ return getExplicitTemplateArgumentList()->getTemplateArgs();
+ }
+
+ /// \brief Retrieve the number of template arguments provided as part of this
+ /// template-id.
+ unsigned getNumTemplateArgs() const {
+ if (!HasExplicitTemplateArgumentList)
+ return 0;
+
+ return getExplicitTemplateArgumentList()->NumTemplateArgs;
+ }
+
+ /// \brief Retrieve the location of the right angle bracket following the
+ /// template arguments ('>').
+ SourceLocation getRAngleLoc() const {
+ if (!HasExplicitTemplateArgumentList)
+ return SourceLocation();
+
+ return getExplicitTemplateArgumentList()->RAngleLoc;
+ }
+
virtual SourceRange getSourceRange() const {
+ if (HasExplicitTemplateArgumentList)
+ return SourceRange(Base->getSourceRange().getBegin(),
+ getRAngleLoc());
+
return SourceRange(Base->getSourceRange().getBegin(),
MemberLoc);
}
- static bool classof(const Stmt *T) {
+
+ static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXUnresolvedMemberExprClass;
}
static bool classof(const CXXUnresolvedMemberExpr *) { return true; }
diff --git a/include/clang/AST/ExprObjC.h b/include/clang/AST/ExprObjC.h
index e00833b..0613f4c 100644
--- a/include/clang/AST/ExprObjC.h
+++ b/include/clang/AST/ExprObjC.h
@@ -22,7 +22,7 @@ namespace clang {
class ASTContext;
class ObjCMethodDecl;
class ObjCPropertyDecl;
-
+
/// ObjCStringLiteral, used for Objective-C string literals
/// i.e. @"foo".
class ObjCStringLiteral : public Expr {
@@ -34,8 +34,6 @@ public:
explicit ObjCStringLiteral(EmptyShell Empty)
: Expr(ObjCStringLiteralClass, Empty) {}
- ObjCStringLiteral* Clone(ASTContext &C) const;
-
StringLiteral *getString() { return cast<StringLiteral>(String); }
const StringLiteral *getString() const { return cast<StringLiteral>(String); }
void setString(StringLiteral *S) { String = S; }
@@ -43,20 +41,20 @@ public:
SourceLocation getAtLoc() const { return AtLoc; }
void setAtLoc(SourceLocation L) { AtLoc = L; }
- virtual SourceRange getSourceRange() const {
+ virtual SourceRange getSourceRange() const {
return SourceRange(AtLoc, String->getLocEnd());
}
-
- static bool classof(const Stmt *T) {
- return T->getStmtClass() == ObjCStringLiteralClass;
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ObjCStringLiteralClass;
}
- static bool classof(const ObjCStringLiteral *) { return true; }
-
+ 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.
@@ -64,32 +62,32 @@ class ObjCEncodeExpr : public Expr {
QualType EncType;
SourceLocation AtLoc, RParenLoc;
public:
- ObjCEncodeExpr(QualType T, QualType ET,
+ ObjCEncodeExpr(QualType T, QualType ET,
SourceLocation at, SourceLocation rp)
- : Expr(ObjCEncodeExprClass, T, ET->isDependentType(),
+ : Expr(ObjCEncodeExprClass, T, ET->isDependentType(),
ET->isDependentType()), 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();
@@ -106,11 +104,9 @@ public:
explicit ObjCSelectorExpr(EmptyShell Empty)
: Expr(ObjCSelectorExprClass, Empty) {}
- ObjCSelectorExpr *Clone(ASTContext &C) const;
-
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; }
@@ -119,26 +115,26 @@ public:
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 *TheProtocol;
+class ObjCProtocolExpr : public Expr {
+ ObjCProtocolDecl *TheProtocol;
SourceLocation AtLoc, RParenLoc;
public:
ObjCProtocolExpr(QualType T, ObjCProtocolDecl *protocol,
@@ -148,11 +144,9 @@ public:
explicit ObjCProtocolExpr(EmptyShell Empty)
: Expr(ObjCProtocolExprClass, Empty) {}
- ObjCProtocolExpr *Clone(ASTContext &C) const;
-
ObjCProtocolDecl *getProtocol() const { return TheProtocol; }
void setProtocol(ObjCProtocolDecl *P) { TheProtocol = P; }
-
+
SourceLocation getAtLoc() const { return AtLoc; }
SourceLocation getRParenLoc() const { return RParenLoc; }
void setAtLoc(SourceLocation L) { AtLoc = L; }
@@ -161,12 +155,12 @@ public:
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();
@@ -179,44 +173,44 @@ class ObjCIvarRefExpr : public Expr {
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) :
+ 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 {
+ virtual SourceRange getSourceRange() const {
return isFreeIvar() ? SourceRange(Loc)
- : SourceRange(getBase()->getLocStart(), Loc);
+ : SourceRange(getBase()->getLocStart(), Loc);
}
-
- static bool classof(const Stmt *T) {
- return T->getStmtClass() == ObjCIvarRefExprClass;
+
+ 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();
@@ -231,113 +225,129 @@ private:
SourceLocation IdLoc;
Stmt *Base;
public:
- ObjCPropertyRefExpr(ObjCPropertyDecl *PD, QualType t,
+ 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 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 {
+/// ObjCImplicitSetterGetterRefExpr - A dot-syntax expression to access two
+/// methods; one to set a value to an 'ivar' (Setter) and the other to access
+/// an 'ivar' (Setter).
+/// An example for use of this AST is:
+/// @code
+/// @interface Test { }
+/// - (Test *)crash;
+/// - (void)setCrash: (Test*)value;
+/// @end
+/// void foo(Test *p1, Test *p2)
+/// {
+/// p2.crash = p1.crash; // Uses ObjCImplicitSetterGetterRefExpr AST
+/// }
+/// @endcode
+class ObjCImplicitSetterGetterRefExpr : public Expr {
+ /// Setter - Setter method user declared for setting its 'ivar' to a value
ObjCMethodDecl *Setter;
+ /// Getter - Getter method user declared for accessing 'ivar' it controls.
ObjCMethodDecl *Getter;
- SourceLocation Loc;
+ /// Location of the member in the dot syntax notation. This is location
+ /// of the getter method.
+ SourceLocation MemberLoc;
// FIXME: Swizzle these into a single pointer.
Stmt *Base;
- ObjCInterfaceDecl *ClassProp;
+ ObjCInterfaceDecl *InterfaceDecl;
+ /// Location of the receiver class in the dot syntax notation
+ /// used to call a class method setter/getter.
SourceLocation ClassLoc;
-
+
public:
- ObjCKVCRefExpr(ObjCMethodDecl *getter,
- QualType t,
+ ObjCImplicitSetterGetterRefExpr(ObjCMethodDecl *getter,
+ QualType t,
ObjCMethodDecl *setter,
SourceLocation l, Expr *base)
- : Expr(ObjCKVCRefExprClass, t), Setter(setter),
- Getter(getter), Loc(l), Base(base), ClassProp(0),
+ : Expr(ObjCImplicitSetterGetterRefExprClass, t), Setter(setter),
+ Getter(getter), MemberLoc(l), Base(base), InterfaceDecl(0),
ClassLoc(SourceLocation()) {
}
- ObjCKVCRefExpr(ObjCMethodDecl *getter,
- QualType t,
+ ObjCImplicitSetterGetterRefExpr(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) {
+ : Expr(ObjCImplicitSetterGetterRefExprClass, t), Setter(setter),
+ Getter(getter), MemberLoc(l), Base(0), InterfaceDecl(C), ClassLoc(CL) {
}
- explicit ObjCKVCRefExpr(EmptyShell Empty) : Expr(ObjCKVCRefExprClass, Empty){}
+ explicit ObjCImplicitSetterGetterRefExpr(EmptyShell Empty)
+ : Expr(ObjCImplicitSetterGetterRefExprClass, Empty){}
ObjCMethodDecl *getGetterMethod() const { return Getter; }
ObjCMethodDecl *getSetterMethod() const { return Setter; }
- ObjCInterfaceDecl *getClassProp() const { return ClassProp; }
+ ObjCInterfaceDecl *getInterfaceDecl() const { return InterfaceDecl; }
void setGetterMethod(ObjCMethodDecl *D) { Getter = D; }
void setSetterMethod(ObjCMethodDecl *D) { Setter = D; }
- void setClassProp(ObjCInterfaceDecl *D) { ClassProp = D; }
-
+ void setInterfaceDecl(ObjCInterfaceDecl *D) { InterfaceDecl = D; }
+
virtual SourceRange getSourceRange() const {
if (Base)
- return SourceRange(getBase()->getLocStart(), Loc);
- return SourceRange(ClassLoc, Loc);
+ return SourceRange(getBase()->getLocStart(), MemberLoc);
+ return SourceRange(ClassLoc, MemberLoc);
}
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 getLocation() const { return MemberLoc; }
+ void setLocation(SourceLocation L) { MemberLoc = 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 Stmt *T) {
+ return T->getStmtClass() == ObjCImplicitSetterGetterRefExprClass;
}
- static bool classof(const ObjCKVCRefExpr *) { return true; }
-
+ static bool classof(const ObjCImplicitSetterGetterRefExpr *) { 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).
+
+ // 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;
@@ -350,7 +360,7 @@ class ObjCMessageExpr : public Expr {
// 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.
@@ -366,28 +376,28 @@ public:
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() {
+ 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();
}
@@ -395,36 +405,36 @@ public:
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;
+ /// 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.
+ /// 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;
+ 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!");
@@ -439,13 +449,13 @@ public:
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();
@@ -458,14 +468,14 @@ public:
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]; }
@@ -477,16 +487,16 @@ public:
class ObjCSuperExpr : public Expr {
SourceLocation Loc;
public:
- ObjCSuperExpr(SourceLocation L, QualType Type)
+ 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) {
+ static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCSuperExprClass;
}
static bool classof(const ObjCSuperExpr *) { return true; }
@@ -496,6 +506,52 @@ public:
virtual child_iterator child_end();
};
+/// ObjCIsaExpr - Represent X->isa and X.isa when X is an ObjC 'id' type.
+/// (similiar in spirit to MemberExpr).
+class ObjCIsaExpr : public Expr {
+ /// Base - the expression for the base object pointer.
+ Stmt *Base;
+
+ /// IsaMemberLoc - This is the location of the 'isa'.
+ SourceLocation IsaMemberLoc;
+
+ /// IsArrow - True if this is "X->F", false if this is "X.F".
+ bool IsArrow;
+public:
+ ObjCIsaExpr(Expr *base, bool isarrow, SourceLocation l, QualType ty)
+ : Expr(ObjCIsaExprClass, ty),
+ Base(base), IsaMemberLoc(l), IsArrow(isarrow) {}
+
+ /// \brief Build an empty expression.
+ explicit ObjCIsaExpr(EmptyShell Empty) : Expr(ObjCIsaExprClass, Empty) { }
+
+ void setBase(Expr *E) { Base = E; }
+ Expr *getBase() const { return cast<Expr>(Base); }
+
+ 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 getIsaMemberLoc() const { return IsaMemberLoc; }
+ void setIsaMemberLoc(SourceLocation L) { IsaMemberLoc = L; }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(getBase()->getLocStart(), IsaMemberLoc);
+ }
+
+ virtual SourceLocation getExprLoc() const { return IsaMemberLoc; }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ObjCIsaExprClass;
+ }
+ static bool classof(const ObjCIsaExpr *) { 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
index 6f862a5..0670d1a 100644
--- a/include/clang/AST/ExternalASTSource.h
+++ b/include/clang/AST/ExternalASTSource.h
@@ -33,7 +33,7 @@ struct VisibleDeclaration {
/// \brief The name of the declarations.
DeclarationName Name;
- /// \brief The ID numbers of all of the declarations with this 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;
@@ -65,7 +65,7 @@ public:
/// replaced with the sorted set of source ranges corresponding to
/// comments in the source code.
virtual void ReadComments(std::vector<SourceRange> &Comments) = 0;
-
+
/// \brief Resolve a type ID into a type, potentially building a new
/// type.
virtual QualType GetType(uint32_t ID) = 0;
@@ -151,7 +151,7 @@ public:
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)
@@ -177,7 +177,7 @@ public:
/// \returns a pointer to the AST node.
T* get(ExternalASTSource *Source) const {
if (isOffset()) {
- assert(Source &&
+ assert(Source &&
"Cannot deserialize a lazy pointer without an AST source");
Ptr = reinterpret_cast<uint64_t>((Source->*Get)(Ptr >> 1));
}
diff --git a/include/clang/AST/NestedNameSpecifier.h b/include/clang/AST/NestedNameSpecifier.h
index b304cc8..1594b09 100644
--- a/include/clang/AST/NestedNameSpecifier.h
+++ b/include/clang/AST/NestedNameSpecifier.h
@@ -14,6 +14,7 @@
#ifndef LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H
#define LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H
+#include "clang/Basic/Diagnostic.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/PointerIntPair.h"
@@ -26,7 +27,7 @@ namespace clang {
class ASTContext;
class NamespaceDecl;
class IdentifierInfo;
-class PrintingPolicy;
+struct PrintingPolicy;
class Type;
class LangOptions;
@@ -80,8 +81,8 @@ private:
/// \brief Copy constructor used internally to clone nested name
/// specifiers.
- NestedNameSpecifier(const NestedNameSpecifier &Other)
- : llvm::FoldingSetNode(Other), Prefix(Other.Prefix),
+ NestedNameSpecifier(const NestedNameSpecifier &Other)
+ : llvm::FoldingSetNode(Other), Prefix(Other.Prefix),
Specifier(Other.Specifier) {
}
@@ -89,7 +90,7 @@ private:
/// \brief Either find or insert the given nested name specifier
/// mockup in the given context.
- static NestedNameSpecifier *FindOrInsert(ASTContext &Context,
+ static NestedNameSpecifier *FindOrInsert(ASTContext &Context,
const NestedNameSpecifier &Mockup);
public:
@@ -98,20 +99,28 @@ public:
/// 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,
+ 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,
+ 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,
+ static NestedNameSpecifier *Create(ASTContext &Context,
+ NestedNameSpecifier *Prefix,
bool Template, Type *T);
+ /// \brief Builds a specifier that consists of just an identifier.
+ ///
+ /// The nested-name-specifier is assumed to be dependent, but has no
+ /// prefix because the prefix is implied by something outside of the
+ /// nested name specifier, e.g., in "x->Base::f", the "x" has a dependent
+ /// type.
+ static NestedNameSpecifier *Create(ASTContext &Context, IdentifierInfo *II);
+
/// \brief Returns the nested name specifier representing the global
/// scope.
static NestedNameSpecifier *GlobalSpecifier(ASTContext &Context);
@@ -126,10 +135,10 @@ public:
NestedNameSpecifier *getPrefix() const { return Prefix.getPointer(); }
/// \brief Determine what kind of nested name specifier is stored.
- SpecifierKind getKind() const {
+ SpecifierKind getKind() const {
if (Specifier == 0)
return Global;
- return (SpecifierKind)Prefix.getInt();
+ return (SpecifierKind)Prefix.getInt();
}
/// \brief Retrieve the identifier stored in this nested name
@@ -140,7 +149,7 @@ public:
return 0;
}
-
+
/// \brief Retrieve the namespace stored in this nested name
/// specifier.
NamespaceDecl *getAsNamespace() const {
@@ -152,7 +161,7 @@ public:
/// \brief Retrieve the type stored in this nested name specifier.
Type *getAsType() const {
- if (Prefix.getInt() == TypeSpec ||
+ if (Prefix.getInt() == TypeSpec ||
Prefix.getInt() == TypeSpecWithTemplate)
return (Type *)Specifier;
@@ -179,6 +188,15 @@ public:
void dump(const LangOptions &LO);
};
+/// Insertion operator for diagnostics. This allows sending NestedNameSpecifiers
+/// into a diagnostic with <<.
+inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
+ NestedNameSpecifier *NNS) {
+ DB.AddTaggedVal(reinterpret_cast<intptr_t>(NNS),
+ Diagnostic::ak_nestednamespec);
+ return DB;
+}
+
}
#endif
diff --git a/include/clang/AST/ParentMap.h b/include/clang/AST/ParentMap.h
index c669991..f826e11 100644
--- a/include/clang/AST/ParentMap.h
+++ b/include/clang/AST/ParentMap.h
@@ -17,7 +17,7 @@
namespace clang {
class Stmt;
class Expr;
-
+
class ParentMap {
void* Impl;
public:
@@ -30,7 +30,7 @@ public:
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));
}
@@ -38,13 +38,13 @@ public:
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
index 6ad3a6b..0635ec5 100644
--- a/include/clang/AST/PrettyPrinter.h
+++ b/include/clang/AST/PrettyPrinter.h
@@ -34,9 +34,10 @@ public:
/// declarations should be printed.
struct PrintingPolicy {
/// \brief Create a default printing policy for C.
- PrintingPolicy(const LangOptions &LO)
+ PrintingPolicy(const LangOptions &LO)
: Indentation(2), LangOpts(LO), SuppressSpecifiers(false),
- SuppressTag(false), SuppressTagKind(false), Dump(false) { }
+ SuppressTag(false), SuppressTagKind(false), SuppressScope(false),
+ Dump(false), ConstantArraySizeAsWritten(false) { }
/// \brief The number of spaces to use to indent each line.
unsigned Indentation : 8;
@@ -74,11 +75,32 @@ struct PrintingPolicy {
/// kind of tag, e.g., "struct", "union", "enum".
bool SuppressTagKind : 1;
+ /// \brief Suppresses printing of scope specifiers.
+ bool SuppressScope : 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;
+
+ /// \brief Whether we should print the sizes of constant array expressions
+ /// as written in the sources.
+ ///
+ /// This flag is determines whether arrays types declared as
+ ///
+ /// \code
+ /// int a[4+10*10];
+ /// char a[] = "A string";
+ /// \endcode
+ ///
+ /// will be printed as written or as follows:
+ ///
+ /// \code
+ /// int a[104];
+ /// char a[9] = "A string";
+ /// \endcode
+ bool ConstantArraySizeAsWritten : 1;
};
} // end namespace clang
diff --git a/include/clang/AST/RecordLayout.h b/include/clang/AST/RecordLayout.h
index ab18456..7490b1d 100644
--- a/include/clang/AST/RecordLayout.h
+++ b/include/clang/AST/RecordLayout.h
@@ -18,83 +18,175 @@
namespace clang {
class ASTContext;
+ class FieldDecl;
class RecordDecl;
+ class CXXRecordDecl;
-/// ASTRecordLayout -
+/// 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
+/// 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
+ /// Size - Size of record in bits.
+ uint64_t Size;
+
+ /// DataSize - Size of record in bits without tail padding.
+ uint64_t DataSize;
+
+ /// FieldOffsets - Array of field offsets in bits.
uint64_t *FieldOffsets;
- unsigned Alignment; // Alignment of record in bits.
- unsigned FieldCount; // Number of fields
+
+ // Alignment - Alignment of record in bits.
+ unsigned Alignment;
+
+ // FieldCount - Number of fields.
+ unsigned FieldCount;
+
+ struct CXXRecordLayoutInfo {
+ /// NonVirtualSize - The non-virtual size (in bits) of an object, which is
+ /// the size of the object without virtual bases.
+ uint64_t NonVirtualSize;
+
+ /// NonVirtualAlign - The non-virtual alignment (in bits) of an object,
+ /// which is the alignment of the object without virtual bases.
+ uint64_t NonVirtualAlign;
+
+ /// PrimaryBase - The primary base for our vtable.
+ const CXXRecordDecl *PrimaryBase;
+ /// PrimaryBase - Wether or not the primary base was a virtual base.
+ bool PrimaryBaseWasVirtual;
+
+ /// BaseOffsets - Contains a map from base classes to their offset.
+ /// FIXME: This should really use a SmallPtrMap, once we have one in LLVM :)
+ llvm::DenseMap<const CXXRecordDecl *, uint64_t> BaseOffsets;
+
+ /// VBaseOffsets - Contains a map from vbase classes to their offset.
+ /// FIXME: This should really use a SmallPtrMap, once we have one in LLVM :)
+ llvm::DenseMap<const CXXRecordDecl *, uint64_t> VBaseOffsets;
+ };
+
+ /// CXXInfo - If the record layout is for a C++ record, this will have
+ /// C++ specific information about the record.
+ CXXRecordLayoutInfo *CXXInfo;
+
friend class ASTContext;
+ friend class ASTRecordLayoutBuilder;
- ASTRecordLayout(uint64_t S = 0, unsigned A = 8)
- : Size(S), NextOffset(S), Alignment(A), FieldCount(0) {}
- ~ASTRecordLayout() {
- delete [] FieldOffsets;
+ ASTRecordLayout(uint64_t size, unsigned alignment, unsigned datasize,
+ const uint64_t *fieldoffsets, unsigned fieldcount)
+ : Size(size), DataSize(datasize), FieldOffsets(0), Alignment(alignment),
+ FieldCount(fieldcount), CXXInfo(0) {
+ if (FieldCount > 0) {
+ FieldOffsets = new uint64_t[FieldCount];
+ for (unsigned i = 0; i < FieldCount; ++i)
+ FieldOffsets[i] = fieldoffsets[i];
+ }
}
- /// Initialize record layout. N is the number of fields in this record.
- void InitializeLayout(unsigned N) {
- FieldCount = N;
- FieldOffsets = new uint64_t[N];
- }
+ // Constructor for C++ records.
+ ASTRecordLayout(uint64_t size, unsigned alignment, uint64_t datasize,
+ const uint64_t *fieldoffsets, unsigned fieldcount,
+ uint64_t nonvirtualsize, unsigned nonvirtualalign,
+ const CXXRecordDecl *PB, bool PBVirtual,
+ const std::pair<const CXXRecordDecl *, uint64_t> *bases,
+ unsigned numbases,
+ const std::pair<const CXXRecordDecl *, uint64_t> *vbases,
+ unsigned numvbases)
+ : Size(size), DataSize(datasize), FieldOffsets(0), Alignment(alignment),
+ FieldCount(fieldcount), CXXInfo(new CXXRecordLayoutInfo) {
+ if (FieldCount > 0) {
+ FieldOffsets = new uint64_t[FieldCount];
+ for (unsigned i = 0; i < FieldCount; ++i)
+ FieldOffsets[i] = fieldoffsets[i];
+ }
- /// 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);
+ CXXInfo->PrimaryBase = PB;
+ CXXInfo->PrimaryBaseWasVirtual = PBVirtual;
+ CXXInfo->NonVirtualSize = nonvirtualsize;
+ CXXInfo->NonVirtualAlign = nonvirtualalign;
+ for (unsigned i = 0; i != numbases; ++i)
+ CXXInfo->BaseOffsets[bases[i].first] = bases[i].second;
+ for (unsigned i = 0; i != numvbases; ++i)
+ CXXInfo->VBaseOffsets[vbases[i].first] = vbases[i].second;
}
- void SetFieldOffset(unsigned FieldNo, uint64_t Offset) {
- assert (FieldNo < FieldCount && "Invalid Field No");
- FieldOffsets[FieldNo] = Offset;
+ ~ASTRecordLayout() {
+ delete [] FieldOffsets;
+ delete CXXInfo;
}
- 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;
+
+ /// getDataSize() - Get the record data size, which is the record size
+ /// without tail padding, in bits.
+ uint64_t getDataSize() const {
+ return DataSize;
+ }
+
+ /// getNonVirtualSize - Get the non-virtual size (in bits) of an object,
+ /// which is the size of the object without virtual bases.
+ uint64_t getNonVirtualSize() const {
+ assert(CXXInfo && "Record layout does not have C++ specific info!");
+
+ return CXXInfo->NonVirtualSize;
+ }
+
+ /// getNonVirtualSize - Get the non-virtual alignment (in bits) of an object,
+ /// which is the alignment of the object without virtual bases.
+ unsigned getNonVirtualAlign() const {
+ assert(CXXInfo && "Record layout does not have C++ specific info!");
+
+ return CXXInfo->NonVirtualAlign;
+ }
+
+ /// getPrimaryBase - Get the primary base.
+ const CXXRecordDecl *getPrimaryBase() const {
+ assert(CXXInfo && "Record layout does not have C++ specific info!");
+
+ return CXXInfo->PrimaryBase;
+ }
+ /// getPrimaryBaseWasVirtual - Indicates if the primary base was virtual.
+ bool getPrimaryBaseWasVirtual() const {
+ assert(CXXInfo && "Record layout does not have C++ specific info!");
+
+ return CXXInfo->PrimaryBaseWasVirtual;
+ }
+
+ /// getBaseClassOffset - Get the offset, in bits, for the given base class.
+ uint64_t getBaseClassOffset(const CXXRecordDecl *Base) const {
+ assert(CXXInfo && "Record layout does not have C++ specific info!");
+ assert(CXXInfo->BaseOffsets.count(Base) && "Did not find base!");
+
+ return CXXInfo->BaseOffsets[Base];
+ }
+
+ /// getVBaseClassOffset - Get the offset, in bits, for the given base class.
+ uint64_t getVBaseClassOffset(const CXXRecordDecl *VBase) const {
+ assert(CXXInfo && "Record layout does not have C++ specific info!");
+ assert(CXXInfo->VBaseOffsets.count(VBase) && "Did not find base!");
+
+ return CXXInfo->VBaseOffsets[VBase];
}
};
diff --git a/include/clang/AST/Redeclarable.h b/include/clang/AST/Redeclarable.h
new file mode 100644
index 0000000..458af1f
--- /dev/null
+++ b/include/clang/AST/Redeclarable.h
@@ -0,0 +1,162 @@
+//===-- Redeclarable.h - Base for Decls that can be redeclared -*- 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 Redeclarable interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_REDECLARABLE_H
+#define LLVM_CLANG_AST_REDECLARABLE_H
+
+#include "llvm/ADT/PointerIntPair.h"
+
+namespace clang {
+
+/// \brief Provides common interface for the Decls that can be redeclared.
+template<typename decl_type>
+class Redeclarable {
+
+protected:
+ struct DeclLink : public llvm::PointerIntPair<decl_type *, 1, bool> {
+ DeclLink(decl_type *D, bool isLatest)
+ : llvm::PointerIntPair<decl_type *, 1, bool>(D, isLatest) { }
+
+ typedef llvm::PointerIntPair<decl_type *, 1, bool> base_type;
+
+ bool NextIsPrevious() const { return base_type::getInt() == false; }
+ bool NextIsLatest() const { return base_type::getInt() == true; }
+ decl_type *getNext() const { return base_type::getPointer(); }
+ };
+
+ struct PreviousDeclLink : public DeclLink {
+ PreviousDeclLink(decl_type *D) : DeclLink(D, false) { }
+ };
+
+ struct LatestDeclLink : public DeclLink {
+ LatestDeclLink(decl_type *D) : DeclLink(D, true) { }
+ };
+
+ /// \brief Points to the next redeclaration in the chain.
+ ///
+ /// If NextIsPrevious() is true, this is a link to the previous declaration
+ /// of this same Decl. If NextIsLatest() is true, this is the first
+ /// declaration and Link points to the latest declaration. For example:
+ ///
+ /// #1 int f(int x, int y = 1); // <pointer to #3, true>
+ /// #2 int f(int x = 0, int y); // <pointer to #1, false>
+ /// #3 int f(int x, int y) { return x + y; } // <pointer to #2, false>
+ ///
+ /// If there is only one declaration, it is <pointer to self, true>
+ DeclLink RedeclLink;
+
+public:
+ Redeclarable() : RedeclLink(LatestDeclLink(static_cast<decl_type*>(this))) { }
+
+ /// \brief Return the previous declaration of this declaration or NULL if this
+ /// is the first declaration.
+ decl_type *getPreviousDeclaration() {
+ if (RedeclLink.NextIsPrevious())
+ return RedeclLink.getNext();
+ return 0;
+ }
+ const decl_type *getPreviousDeclaration() const {
+ return const_cast<decl_type *>(
+ static_cast<const decl_type*>(this))->getPreviousDeclaration();
+ }
+
+ /// \brief Return the first declaration of this declaration or itself if this
+ /// is the only declaration.
+ decl_type *getFirstDeclaration() {
+ decl_type *D = static_cast<decl_type*>(this);
+ while (D->getPreviousDeclaration())
+ D = D->getPreviousDeclaration();
+ return D;
+ }
+
+ /// \brief Return the first declaration of this declaration or itself if this
+ /// is the only declaration.
+ const decl_type *getFirstDeclaration() const {
+ const decl_type *D = static_cast<const decl_type*>(this);
+ while (D->getPreviousDeclaration())
+ D = D->getPreviousDeclaration();
+ return D;
+ }
+
+ /// \brief Set the previous declaration. If PrevDecl is NULL, set this as the
+ /// first and only declaration.
+ void setPreviousDeclaration(decl_type *PrevDecl) {
+ decl_type *First;
+
+ if (PrevDecl) {
+ // Point to previous.
+ RedeclLink = PreviousDeclLink(PrevDecl);
+ First = PrevDecl->getFirstDeclaration();
+ assert(First->RedeclLink.NextIsLatest() && "Expected first");
+ } else {
+ // Make this first.
+ First = static_cast<decl_type*>(this);
+ }
+
+ // First one will point to this one as latest.
+ First->RedeclLink = LatestDeclLink(static_cast<decl_type*>(this));
+ }
+
+ /// \brief Iterates through all the redeclarations of the same decl.
+ class redecl_iterator {
+ /// Current - The current declaration.
+ decl_type *Current;
+ decl_type *Starter;
+
+ public:
+ typedef decl_type* value_type;
+ typedef decl_type* reference;
+ typedef decl_type* pointer;
+ typedef std::forward_iterator_tag iterator_category;
+ typedef std::ptrdiff_t difference_type;
+
+ redecl_iterator() : Current(0) { }
+ explicit redecl_iterator(decl_type *C) : Current(C), Starter(C) { }
+
+ reference operator*() const { return Current; }
+ pointer operator->() const { return Current; }
+
+ redecl_iterator& operator++() {
+ assert(Current && "Advancing while iterator has reached end");
+ // Get either previous decl or latest decl.
+ decl_type *Next = Current->RedeclLink.getNext();
+ Current = (Next != Starter ? Next : 0);
+ return *this;
+ }
+
+ redecl_iterator operator++(int) {
+ redecl_iterator tmp(*this);
+ ++(*this);
+ return tmp;
+ }
+
+ friend bool operator==(redecl_iterator x, redecl_iterator y) {
+ return x.Current == y.Current;
+ }
+ friend bool operator!=(redecl_iterator x, redecl_iterator y) {
+ return x.Current != y.Current;
+ }
+ };
+
+ /// \brief Returns iterator for all the redeclarations of the same decl.
+ /// It will iterate at least once (when this decl is the only one).
+ redecl_iterator redecls_begin() const {
+ return redecl_iterator(const_cast<decl_type*>(
+ static_cast<const decl_type*>(this)));
+ }
+ redecl_iterator redecls_end() const { return redecl_iterator(); }
+};
+
+}
+
+#endif
diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h
index 0a64daf..411f215e 100644
--- a/include/clang/AST/Stmt.h
+++ b/include/clang/AST/Stmt.h
@@ -21,11 +21,14 @@
#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 llvm {
+ class FoldingSetNodeID;
+}
+
namespace clang {
class ASTContext;
class Expr;
@@ -36,21 +39,21 @@ namespace clang {
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() : I(0) {}
ExprIterator& operator++() { ++I; return *this; }
ExprIterator operator-(size_t i) { return I-i; }
ExprIterator operator+(size_t i) { return I+i; }
@@ -64,12 +67,12 @@ namespace clang {
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() : I(0) {}
ConstExprIterator& operator++() { ++I; return *this; }
ConstExprIterator operator+(size_t i) { return I+i; }
ConstExprIterator operator-(size_t i) { return I-i; }
@@ -81,12 +84,12 @@ namespace clang {
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 {
@@ -101,7 +104,11 @@ public:
#include "clang/AST/StmtNodes.def"
};
private:
- const StmtClass sClass;
+ /// \brief The statement class.
+ const unsigned sClass : 8;
+
+ /// \brief The reference count for this statement.
+ unsigned RefCount : 24;
// Make vanilla 'new' and 'delete' illegal for Stmts.
protected:
@@ -112,20 +119,20 @@ protected:
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.
+ // 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;
}
@@ -145,23 +152,48 @@ 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) {
+ explicit Stmt(StmtClass SC, EmptyShell) : sClass(SC), RefCount(1) {
if (Stmt::CollectingStats()) Stmt::addStmtClass(SC);
}
+ /// \brief Virtual method that performs the actual destruction of
+ /// this statement.
+ ///
+ /// Subclasses should override this method (not Destroy()) to
+ /// provide class-specific destruction.
+ virtual void DoDestroy(ASTContext &Ctx);
+
public:
- Stmt(StmtClass SC) : sClass(SC) {
+ Stmt(StmtClass SC) : sClass(SC), RefCount(1) {
if (Stmt::CollectingStats()) Stmt::addStmtClass(SC);
}
virtual ~Stmt() {}
-
- virtual void Destroy(ASTContext &Ctx);
- StmtClass getStmtClass() const { return sClass; }
+ /// \brief Destroy the current statement and its children.
+ void Destroy(ASTContext &Ctx) {
+ assert(RefCount >= 1);
+ if (--RefCount == 0)
+ DoDestroy(Ctx);
+ }
+
+ /// \brief Increases the reference count for this statement.
+ ///
+ /// Invoke the Retain() operation when this statement or expression
+ /// is being shared by another owner.
+ Stmt *Retain() {
+ assert(RefCount >= 1);
+ ++RefCount;
+ return this;
+ }
+
+ StmtClass getStmtClass() const {
+ assert(RefCount >= 1 && "Referencing already-destroyed statement!");
+ return (StmtClass)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.
@@ -187,23 +219,23 @@ public:
/// dumpPretty/printPretty - These two methods do a "pretty print" of the AST
/// back to its original source language syntax.
void dumpPretty(ASTContext& Context) const;
- void printPretty(llvm::raw_ostream &OS, PrinterHelper *Helper,
+ void printPretty(llvm::raw_ostream &OS, PrinterHelper *Helper,
const PrintingPolicy &Policy,
unsigned Indentation = 0) const {
printPretty(OS, *(ASTContext*)0, Helper, Policy, Indentation);
}
void printPretty(llvm::raw_ostream &OS, ASTContext &Context,
- PrinterHelper *Helper,
+ PrinterHelper *Helper,
const PrintingPolicy &Policy,
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; }
-
+ 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
@@ -216,46 +248,60 @@ public:
/// 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());
}
+
+ /// \brief Produce a unique representation of the given statement.
+ ///
+ /// \brief ID once the profiling operation is complete, will contain
+ /// the unique representation of the given statement.
+ ///
+ /// \brief Context the AST context in which the statement resides
+ ///
+ /// \brief Canonical whether the profile should be based on the canonical
+ /// representation of this statement (e.g., where non-type template
+ /// parameters are identified by index/level rather than their
+ /// declaration pointers) or the exact representation of the statement as
+ /// written in the source.
+ void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context,
+ bool Canonical);
};
/// 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
+/// 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,
+ 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(); }
-
+ Decl *getSingleDecl() { return DG.getSingleDecl(); }
+
const DeclGroupRef getDeclGroup() const { return DG; }
DeclGroupRef getDeclGroup() { return DG; }
void setDeclGroup(DeclGroupRef DGR) { DG = DGR; }
@@ -268,19 +314,19 @@ public:
SourceRange getSourceRange() const {
return SourceRange(StartLoc, EndLoc);
}
-
- static bool classof(const Stmt *T) {
- return T->getStmtClass() == DeclStmtClass;
+
+ 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(); }
@@ -297,18 +343,16 @@ public:
/// \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 Stmt *T) {
+ return T->getStmtClass() == NullStmtClass;
}
static bool classof(const NullStmt *) { return true; }
-
+
// Iterators
virtual child_iterator child_begin();
virtual child_iterator child_end();
@@ -321,24 +365,24 @@ class CompoundStmt : public Stmt {
unsigned NumStmts;
SourceLocation LBracLoc, RBracLoc;
public:
- CompoundStmt(ASTContext& C, Stmt **StmtStart, unsigned numStmts,
+ 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; }
@@ -366,25 +410,25 @@ public:
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);
+
+ 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 Stmt *T) {
+ return T->getStmtClass() == CompoundStmtClass;
}
static bool classof(const CompoundStmt *) { return true; }
-
+
// Iterators
virtual child_iterator child_begin();
virtual child_iterator child_end();
@@ -398,7 +442,7 @@ protected:
SwitchCase *NextSwitchCase;
SwitchCase(StmtClass SC) : Stmt(SC), NextSwitchCase(0) {}
-
+
public:
const SwitchCase *getNextSwitchCase() const { return NextSwitchCase; }
@@ -409,19 +453,19 @@ public:
Stmt *getSubStmt() { return v_getSubStmt(); }
virtual SourceRange getSourceRange() const { return SourceRange(); }
-
- static bool classof(const Stmt *T) {
- return T->getStmtClass() == CaseStmtClass ||
+
+ 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;
+ 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
+ Stmt* SubExprs[END_EXPR]; // The expression for the RHS is Non-null for
// GNU "case 1 ... 4" extension
SourceLocation CaseLoc;
SourceLocation EllipsisLoc;
@@ -430,7 +474,7 @@ class CaseStmt : public SwitchCase {
virtual Stmt* v_getSubStmt() { return getSubStmt(); }
public:
CaseStmt(Expr *lhs, Expr *rhs, SourceLocation caseLoc,
- SourceLocation ellipsisLoc, SourceLocation colonLoc)
+ SourceLocation ellipsisLoc, SourceLocation colonLoc)
: SwitchCase(CaseStmtClass) {
SubExprs[SUBSTMT] = 0;
SubExprs[LHS] = reinterpret_cast<Stmt*>(lhs);
@@ -454,32 +498,32 @@ public:
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 *getLHS() const {
+ return reinterpret_cast<const Expr*>(SubExprs[LHS]);
}
- const Expr *getRHS() const {
- return reinterpret_cast<const Expr*>(SubExprs[RHS]);
+ 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());
+
+ return SourceRange(CaseLoc, CS->getSubStmt()->getLocEnd());
}
- static bool classof(const Stmt *T) {
- return T->getStmtClass() == CaseStmtClass;
+ 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();
@@ -491,7 +535,7 @@ class DefaultStmt : public SwitchCase {
SourceLocation ColonLoc;
virtual Stmt* v_getSubStmt() { return getSubStmt(); }
public:
- DefaultStmt(SourceLocation DL, SourceLocation CL, Stmt *substmt) :
+ DefaultStmt(SourceLocation DL, SourceLocation CL, Stmt *substmt) :
SwitchCase(DefaultStmtClass), SubStmt(substmt), DefaultLoc(DL),
ColonLoc(CL) {}
@@ -507,14 +551,14 @@ public:
SourceLocation getColonLoc() const { return ColonLoc; }
void setColonLoc(SourceLocation L) { ColonLoc = L; }
- virtual SourceRange getSourceRange() const {
- return SourceRange(DefaultLoc, SubStmt->getLocEnd());
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(DefaultLoc, SubStmt->getLocEnd());
}
- static bool classof(const Stmt *T) {
- return T->getStmtClass() == DefaultStmtClass;
+ 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();
@@ -525,13 +569,13 @@ class LabelStmt : public Stmt {
Stmt *SubStmt;
SourceLocation IdentLoc;
public:
- LabelStmt(SourceLocation IL, IdentifierInfo *label, Stmt *substmt)
- : Stmt(LabelStmtClass), Label(label),
+ 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; }
@@ -541,14 +585,14 @@ public:
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;
+ 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();
@@ -563,8 +607,8 @@ class IfStmt : public Stmt {
SourceLocation IfLoc;
SourceLocation ElseLoc;
public:
- IfStmt(SourceLocation IL, Expr *cond, Stmt *then,
- SourceLocation EL = SourceLocation(), Stmt *elsev = 0)
+ IfStmt(SourceLocation IL, Expr *cond, Stmt *then,
+ SourceLocation EL = SourceLocation(), Stmt *elsev = 0)
: Stmt(IfStmtClass) {
SubExprs[COND] = reinterpret_cast<Stmt*>(cond);
SubExprs[THEN] = then;
@@ -572,14 +616,14 @@ public:
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; }
+ void setThen(Stmt *S) { SubExprs[THEN] = S; }
const Stmt *getElse() const { return SubExprs[ELSE]; }
void setElse(Stmt *S) { SubExprs[ELSE] = S; }
@@ -592,18 +636,18 @@ public:
SourceLocation getElseLoc() const { return ElseLoc; }
void setElseLoc(SourceLocation L) { ElseLoc = L; }
- virtual SourceRange getSourceRange() const {
+ 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 Stmt *T) {
+ return T->getStmtClass() == IfStmtClass;
}
static bool classof(const IfStmt *) { return true; }
-
+
// Iterators
virtual child_iterator child_begin();
virtual child_iterator child_end();
@@ -613,16 +657,20 @@ public:
///
class SwitchStmt : public Stmt {
enum { COND, BODY, END_EXPR };
- Stmt* SubExprs[END_EXPR];
+ Stmt* SubExprs[END_EXPR];
// This points to a linked list of case and default statements.
SwitchCase *FirstCase;
SourceLocation SwitchLoc;
+
+protected:
+ virtual void DoDestroy(ASTContext &Ctx);
+
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) { }
@@ -635,28 +683,34 @@ public:
Stmt *getBody() { return SubExprs[BODY]; }
void setBody(Stmt *S) { SubExprs[BODY] = S; }
SwitchCase *getSwitchCaseList() { return FirstCase; }
+
+ /// \brief Set the case list for this switch statement.
+ ///
+ /// The caller is responsible for incrementing the retain counts on
+ /// all of the SwitchCase statements in this list.
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;
+ 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->Retain();
SC->setNextSwitchCase(FirstCase);
FirstCase = SC;
}
- virtual SourceRange getSourceRange() const {
- return SourceRange(SwitchLoc, SubExprs[BODY]->getLocEnd());
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(SwitchLoc, SubExprs[BODY]->getLocEnd());
}
- static bool classof(const Stmt *T) {
- return T->getStmtClass() == SwitchStmtClass;
+ 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();
@@ -675,7 +729,7 @@ public:
SubExprs[BODY] = body;
WhileLoc = WL;
}
-
+
/// \brief Build an empty while statement.
explicit WhileStmt(EmptyShell Empty) : Stmt(WhileStmtClass, Empty) { }
@@ -689,14 +743,14 @@ public:
SourceLocation getWhileLoc() const { return WhileLoc; }
void setWhileLoc(SourceLocation L) { WhileLoc = L; }
- virtual SourceRange getSourceRange() const {
- return SourceRange(WhileLoc, SubExprs[BODY]->getLocEnd());
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(WhileLoc, SubExprs[BODY]->getLocEnd());
}
- static bool classof(const Stmt *T) {
- return T->getStmtClass() == WhileStmtClass;
+ 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();
@@ -717,16 +771,16 @@ public:
: Stmt(DoStmtClass), DoLoc(DL), WhileLoc(WL), RParenLoc(RP) {
SubExprs[COND] = reinterpret_cast<Stmt*>(cond);
SubExprs[BODY] = body;
- }
+ }
/// \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]; }
+ const Stmt *getBody() const { return SubExprs[BODY]; }
void setBody(Stmt *S) { SubExprs[BODY] = S; }
SourceLocation getDoLoc() const { return DoLoc; }
@@ -737,11 +791,11 @@ public:
SourceLocation getRParenLoc() const { return RParenLoc; }
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
- virtual SourceRange getSourceRange() const {
- return SourceRange(DoLoc, RParenLoc);
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(DoLoc, RParenLoc);
}
- static bool classof(const Stmt *T) {
- return T->getStmtClass() == DoStmtClass;
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == DoStmtClass;
}
static bool classof(const DoStmt *) { return true; }
@@ -763,7 +817,7 @@ class ForStmt : public Stmt {
public:
ForStmt(Stmt *Init, Expr *Cond, Expr *Inc, Stmt *Body, SourceLocation FL,
- SourceLocation LP, SourceLocation RP)
+ SourceLocation LP, SourceLocation RP)
: Stmt(ForStmtClass) {
SubExprs[INIT] = Init;
SubExprs[COND] = reinterpret_cast<Stmt*>(Cond);
@@ -773,7 +827,7 @@ public:
LParenLoc = LP;
RParenLoc = RP;
}
-
+
/// \brief Build an empty for statement.
explicit ForStmt(EmptyShell Empty) : Stmt(ForStmtClass, Empty) { }
@@ -799,19 +853,19 @@ public:
SourceLocation getRParenLoc() const { return RParenLoc; }
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
- virtual SourceRange getSourceRange() const {
- return SourceRange(ForLoc, SubExprs[BODY]->getLocEnd());
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(ForLoc, SubExprs[BODY]->getLocEnd());
}
- static bool classof(const Stmt *T) {
- return T->getStmtClass() == ForStmtClass;
+ 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 {
@@ -819,9 +873,9 @@ class GotoStmt : public Stmt {
SourceLocation GotoLoc;
SourceLocation LabelLoc;
public:
- GotoStmt(LabelStmt *label, SourceLocation GL, SourceLocation LL)
+ 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) { }
@@ -833,14 +887,14 @@ public:
SourceLocation getLabelLoc() const { return LabelLoc; }
void setLabelLoc(SourceLocation L) { LabelLoc = L; }
- virtual SourceRange getSourceRange() const {
- return SourceRange(GotoLoc, LabelLoc);
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(GotoLoc, LabelLoc);
}
- static bool classof(const Stmt *T) {
- return T->getStmtClass() == GotoStmtClass;
+ 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();
@@ -853,20 +907,20 @@ class IndirectGotoStmt : public Stmt {
SourceLocation StarLoc;
Stmt *Target;
public:
- IndirectGotoStmt(SourceLocation gotoLoc, SourceLocation starLoc,
+ 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)
+ 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); }
@@ -874,12 +928,12 @@ public:
virtual SourceRange getSourceRange() const {
return SourceRange(GotoLoc, Target->getLocEnd());
}
-
- static bool classof(const Stmt *T) {
- return T->getStmtClass() == IndirectGotoStmtClass;
+
+ 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();
@@ -892,24 +946,22 @@ 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);
+ 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 Stmt *T) {
+ return T->getStmtClass() == ContinueStmtClass;
}
static bool classof(const ContinueStmt *) { return true; }
-
+
// Iterators
virtual child_iterator child_begin();
virtual child_iterator child_end();
@@ -921,7 +973,7 @@ 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) { }
@@ -930,13 +982,11 @@ public:
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 Stmt *T) {
+ return T->getStmtClass() == BreakStmtClass;
}
static bool classof(const BreakStmt *) { return true; }
-
+
// Iterators
virtual child_iterator child_begin();
virtual child_iterator child_end();
@@ -956,7 +1006,7 @@ class ReturnStmt : public Stmt {
Stmt *RetExpr;
SourceLocation RetLoc;
public:
- ReturnStmt(SourceLocation RL, Expr *E = 0) : Stmt(ReturnStmtClass),
+ ReturnStmt(SourceLocation RL, Expr *E = 0) : Stmt(ReturnStmtClass),
RetExpr((Stmt*) E), RetLoc(RL) {}
/// \brief Build an empty return expression.
@@ -970,12 +1020,12 @@ public:
void setReturnLoc(SourceLocation L) { RetLoc = L; }
virtual SourceRange getSourceRange() const;
-
- static bool classof(const Stmt *T) {
- return T->getStmtClass() == ReturnStmtClass;
+
+ 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();
@@ -989,18 +1039,18 @@ class AsmStmt : public Stmt {
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,
+ 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);
@@ -1043,10 +1093,10 @@ public:
: 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;
@@ -1056,7 +1106,7 @@ public:
assert(isOperand());
return OperandNo;
}
-
+
/// getModifier - Get the modifier for this operand, if present. This
/// returns '\0' if there was no modifier.
char getModifier() const {
@@ -1064,16 +1114,16 @@ public:
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.
+ //// 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; }
@@ -1086,72 +1136,72 @@ public:
/// 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; }
-
+
+ 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,
+ 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]; }
@@ -1161,62 +1211,62 @@ public:
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
-
+
+ // Child iterators
+
virtual child_iterator child_begin();
virtual child_iterator child_end();
};
diff --git a/include/clang/AST/StmtCXX.h b/include/clang/AST/StmtCXX.h
index 2338f14..28fe348 100644
--- a/include/clang/AST/StmtCXX.h
+++ b/include/clang/AST/StmtCXX.h
@@ -29,13 +29,14 @@ class CXXCatchStmt : public Stmt {
/// The handler block.
Stmt *HandlerBlock;
+protected:
+ virtual void DoDestroy(ASTContext& Ctx);
+
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());
}
diff --git a/include/clang/AST/StmtGraphTraits.h b/include/clang/AST/StmtGraphTraits.h
index 1bfac6a..25d0152 100644
--- a/include/clang/AST/StmtGraphTraits.h
+++ b/include/clang/AST/StmtGraphTraits.h
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This file defines a template specialization of llvm::GraphTraits to
+// This file defines a template specialization of llvm::GraphTraits to
// treat ASTs (Stmt*) as graphs
//
//===----------------------------------------------------------------------===//
@@ -20,7 +20,7 @@
#include "llvm/ADT/DepthFirstIterator.h"
namespace llvm {
-
+
//template <typename T> struct GraphTraits;
@@ -28,23 +28,23 @@ 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);
}
@@ -55,29 +55,29 @@ 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();
+ 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
index 35bd5ad..2d523ff 100644
--- a/include/clang/AST/StmtIterator.h
+++ b/include/clang/AST/StmtIterator.h
@@ -14,54 +14,54 @@
#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>
+#include <iterator>
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;
+ uintptr_t RawVAPtr;
Decl** DGE;
bool inDecl() const {
return (RawVAPtr & Flags) == DeclMode;
}
-
+
bool inDeclGroup() const {
return (RawVAPtr & Flags) == DeclGroupMode;
}
-
- bool inSizeOfTypeVA() const {
+
+ 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());
+ 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) {}
@@ -70,22 +70,22 @@ protected:
StmtIteratorBase(Decl** dgi, Decl** dge);
StmtIteratorBase() : stmt(NULL), RawVAPtr(0) {}
};
-
-
+
+
template <typename DERIVED, typename REFERENCE>
-class StmtIteratorImpl : public StmtIteratorBase,
+class StmtIteratorImpl : public StmtIteratorBase,
public std::iterator<std::forward_iterator_tag,
- REFERENCE, ptrdiff_t,
- REFERENCE, REFERENCE> {
+ REFERENCE, ptrdiff_t,
+ REFERENCE, REFERENCE> {
protected:
StmtIteratorImpl(const StmtIteratorBase& RHS) : StmtIteratorBase(RHS) {}
public:
- StmtIteratorImpl() {}
+ 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();
@@ -95,36 +95,36 @@ public:
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 {
+
+ REFERENCE operator*() const {
return (REFERENCE) (inStmt() ? *stmt : GetDeclExpr());
}
-
- REFERENCE operator->() const { return operator*(); }
+
+ 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)
+ StmtIterator(Decl** dgi, Decl** dge)
: StmtIteratorImpl<StmtIterator,Stmt*&>(dgi, dge) {}
StmtIterator(VariableArrayType* t):StmtIteratorImpl<StmtIterator,Stmt*&>(t) {}
@@ -133,10 +133,10 @@ struct StmtIterator : public StmtIteratorImpl<StmtIterator,Stmt*&> {
struct ConstStmtIterator : public StmtIteratorImpl<ConstStmtIterator,
const Stmt*> {
- explicit ConstStmtIterator() :
+ explicit ConstStmtIterator() :
StmtIteratorImpl<ConstStmtIterator,const Stmt*>() {}
-
- ConstStmtIterator(const StmtIterator& RHS) :
+
+ ConstStmtIterator(const StmtIterator& RHS) :
StmtIteratorImpl<ConstStmtIterator,const Stmt*>(RHS) {}
};
diff --git a/include/clang/AST/StmtNodes.def b/include/clang/AST/StmtNodes.def
index a95a627..8d7e4b5 100644
--- a/include/clang/AST/StmtNodes.def
+++ b/include/clang/AST/StmtNodes.def
@@ -25,6 +25,10 @@
# define EXPR(Type, Base) STMT(Type, Base)
#endif
+#ifndef ABSTRACT_EXPR
+# define ABSTRACT_EXPR(Type, Base) EXPR(Type, Base)
+#endif
+
// Normal Statements.
STMT(NullStmt , Stmt)
FIRST_STMT(NullStmt)
@@ -64,7 +68,7 @@ STMT(CXXTryStmt , Stmt)
LAST_STMT(CXXTryStmt)
// Expressions.
-EXPR(Expr , Stmt)
+ABSTRACT_EXPR(Expr , Stmt)
FIRST_EXPR(Expr)
EXPR(PredefinedExpr , Expr)
EXPR(DeclRefExpr , Expr)
@@ -91,6 +95,7 @@ EXPR(ExtVectorElementExpr , Expr)
EXPR(InitListExpr , Expr)
EXPR(DesignatedInitExpr , Expr)
EXPR(ImplicitValueInitExpr , Expr)
+EXPR(ParenListExpr , Expr)
EXPR(VAArgExpr , Expr)
// GNU Extensions.
@@ -119,6 +124,7 @@ EXPR(CXXZeroInitValueExpr , Expr)
EXPR(CXXConditionDeclExpr , DeclRefExpr)
EXPR(CXXNewExpr , Expr)
EXPR(CXXDeleteExpr , Expr)
+EXPR(CXXPseudoDestructorExpr, Expr)
EXPR(UnresolvedFunctionNameExpr , Expr)
EXPR(UnaryTypeTraitExpr , Expr)
EXPR(QualifiedDeclRefExpr , DeclRefExpr)
@@ -139,8 +145,9 @@ EXPR(ObjCSelectorExpr , Expr)
EXPR(ObjCProtocolExpr , Expr)
EXPR(ObjCIvarRefExpr , Expr)
EXPR(ObjCPropertyRefExpr , Expr)
-EXPR(ObjCKVCRefExpr , Expr)
+EXPR(ObjCImplicitSetterGetterRefExpr , Expr)
EXPR(ObjCSuperExpr , Expr)
+EXPR(ObjCIsaExpr , Expr)
// Clang Extensions.
EXPR(ShuffleVectorExpr , Expr)
@@ -149,8 +156,9 @@ EXPR(BlockDeclRefExpr , Expr)
LAST_EXPR(BlockDeclRefExpr)
-#undef STMT
+#undef ABSTRACT_EXPR
#undef EXPR
+#undef STMT
#undef FIRST_STMT
#undef LAST_STMT
#undef FIRST_EXPR
diff --git a/include/clang/AST/StmtObjC.h b/include/clang/AST/StmtObjC.h
index 8ae7071..3fd8f16 100644
--- a/include/clang/AST/StmtObjC.h
+++ b/include/clang/AST/StmtObjC.h
@@ -27,47 +27,47 @@ class ObjCForCollectionStmt : public Stmt {
SourceLocation ForLoc;
SourceLocation RParenLoc;
public:
- ObjCForCollectionStmt(Stmt *Elem, Expr *Collect, Stmt *Body,
+ ObjCForCollectionStmt(Stmt *Elem, Expr *Collect, Stmt *Body,
SourceLocation FCL, SourceLocation RPL);
- explicit ObjCForCollectionStmt(EmptyShell Empty) :
+ explicit ObjCForCollectionStmt(EmptyShell Empty) :
Stmt(ObjCForCollectionStmtClass, Empty) { }
-
+
Stmt *getElement() { return SubExprs[ELEM]; }
- Expr *getCollection() {
- return reinterpret_cast<Expr*>(SubExprs[COLLECTION]);
+ Expr *getCollection() {
+ return reinterpret_cast<Expr*>(SubExprs[COLLECTION]);
}
Stmt *getBody() { return SubExprs[BODY]; }
-
+
const Stmt *getElement() const { return SubExprs[ELEM]; }
- const Expr *getCollection() const {
+ 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) {
+ 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());
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(ForLoc, SubExprs[BODY]->getLocEnd());
}
- static bool classof(const Stmt *T) {
- return T->getStmtClass() == ObjCForCollectionStmtClass;
+ 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:
@@ -78,95 +78,95 @@ private:
public:
ObjCAtCatchStmt(SourceLocation atCatchLoc, SourceLocation rparenloc,
- ParmVarDecl *catchVarDecl,
+ ParmVarDecl *catchVarDecl,
Stmt *atCatchStmt, Stmt *atCatchList);
- explicit ObjCAtCatchStmt(EmptyShell Empty) :
+ 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() {
+ ObjCAtCatchStmt *getNextCatchStmt() {
return static_cast<ObjCAtCatchStmt*>(SubExprs[NEXT_CATCH]);
}
void setNextCatchStmt(Stmt *S) { SubExprs[NEXT_CATCH] = S; }
-
- const ParmVarDecl *getCatchParamDecl() const {
- return ExceptionDecl;
+
+ const ParmVarDecl *getCatchParamDecl() const {
+ return ExceptionDecl;
}
- ParmVarDecl *getCatchParamDecl() {
- 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());
+
+ 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
+
+/// ObjCAtFinallyStmt - This represent objective-c's @finally Statement
class ObjCAtFinallyStmt : public Stmt {
Stmt *AtFinallyStmt;
- SourceLocation AtFinallyLoc;
+ SourceLocation AtFinallyLoc;
public:
ObjCAtFinallyStmt(SourceLocation atFinallyLoc, Stmt *atFinallyStmt)
- : Stmt(ObjCAtFinallyStmtClass),
+ : Stmt(ObjCAtFinallyStmtClass),
AtFinallyStmt(atFinallyStmt), AtFinallyLoc(atFinallyLoc) {}
- explicit ObjCAtFinallyStmt(EmptyShell Empty) :
+ 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());
+
+ 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
+
+/// 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;
+ Stmt* SubStmts[END_EXPR];
+
+ SourceLocation AtTryLoc;
public:
- ObjCAtTryStmt(SourceLocation atTryLoc, Stmt *atTryStmt,
- Stmt *atCatchStmt,
+ ObjCAtTryStmt(SourceLocation atTryLoc, Stmt *atTryStmt,
+ Stmt *atCatchStmt,
Stmt *atFinallyStmt)
: Stmt(ObjCAtTryStmtClass) {
SubStmts[TRY] = atTryStmt;
@@ -174,41 +174,41 @@ public:
SubStmts[FINALLY] = atFinallyStmt;
AtTryLoc = atTryLoc;
}
- explicit ObjCAtTryStmt(EmptyShell Empty) :
+ 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]);
+
+ const ObjCAtCatchStmt *getCatchStmts() const {
+ return dyn_cast_or_null<ObjCAtCatchStmt>(SubStmts[CATCH]);
}
- ObjCAtCatchStmt *getCatchStmts() {
- 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]);
+
+ const ObjCAtFinallyStmt *getFinallyStmt() const {
+ return dyn_cast_or_null<ObjCAtFinallyStmt>(SubStmts[FINALLY]);
}
- ObjCAtFinallyStmt *getFinallyStmt() {
- 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());
+ 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();
};
@@ -223,7 +223,7 @@ private:
enum { SYNC_EXPR, SYNC_BODY, END_EXPR };
Stmt* SubStmts[END_EXPR];
SourceLocation AtSynchronizedLoc;
-
+
public:
ObjCAtSynchronizedStmt(SourceLocation atSynchronizedLoc, Stmt *synchExpr,
Stmt *synchBody)
@@ -232,41 +232,41 @@ public:
SubStmts[SYNC_BODY] = synchBody;
AtSynchronizedLoc = atSynchronizedLoc;
}
- explicit ObjCAtSynchronizedStmt(EmptyShell Empty) :
+ 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]);
+ 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]);
+
+ const Expr *getSynchExpr() const {
+ return reinterpret_cast<Expr*>(SubStmts[SYNC_EXPR]);
}
- Expr *getSynchExpr() {
- 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());
+
+ 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;
@@ -276,28 +276,28 @@ public:
: Stmt(ObjCAtThrowStmtClass), Throw(throwExpr) {
AtThrowLoc = atThrowLoc;
}
- explicit ObjCAtThrowStmt(EmptyShell Empty) :
+ 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, 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();
};
diff --git a/include/clang/AST/StmtVisitor.h b/include/clang/AST/StmtVisitor.h
index 4f4066a..3a52550 100644
--- a/include/clang/AST/StmtVisitor.h
+++ b/include/clang/AST/StmtVisitor.h
@@ -20,17 +20,17 @@
#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.
@@ -53,7 +53,7 @@ public:
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);
@@ -101,7 +101,7 @@ public:
case UnaryOperator::OffsetOf: DISPATCH(UnaryOffsetOf, UnaryOperator);
}
}
-
+
// Top switch stmt: dispatch to VisitFooStmt for each FooStmt.
switch (S->getStmtClass()) {
default: assert(0 && "Unknown stmt kind!");
@@ -110,7 +110,7 @@ public:
#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) \
@@ -127,7 +127,7 @@ public:
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)
@@ -148,7 +148,7 @@ public:
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) \
@@ -158,13 +158,13 @@ public:
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(); }
};
diff --git a/include/clang/AST/TemplateName.h b/include/clang/AST/TemplateName.h
index 511934c..66ff34c 100644
--- a/include/clang/AST/TemplateName.h
+++ b/include/clang/AST/TemplateName.h
@@ -26,9 +26,11 @@ namespace clang {
class DependentTemplateName;
class IdentifierInfo;
class NestedNameSpecifier;
-class PrintingPolicy;
+struct PrintingPolicy;
class QualifiedTemplateName;
+class NamedDecl;
class TemplateDecl;
+class OverloadedFunctionDecl;
/// \brief Represents a C++ template name within the type system.
///
@@ -58,7 +60,8 @@ class TemplateDecl;
/// 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 *,
+ typedef llvm::PointerUnion4<TemplateDecl *, OverloadedFunctionDecl *,
+ QualifiedTemplateName *,
DependentTemplateName *> StorageType;
StorageType Storage;
@@ -70,17 +73,32 @@ class TemplateName {
public:
TemplateName() : Storage() { }
explicit TemplateName(TemplateDecl *Template) : Storage(Template) { }
+ explicit TemplateName(OverloadedFunctionDecl *FunctionTemplates)
+ : Storage(FunctionTemplates) { }
explicit TemplateName(QualifiedTemplateName *Qual) : Storage(Qual) { }
explicit TemplateName(DependentTemplateName *Dep) : Storage(Dep) { }
+ /// \brief Determine whether this template name is NULL.
+ bool isNull() const { return Storage.isNull(); }
+
/// \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.
+ /// declaration because it is a dependent name, or if it refers to a
+ /// set of function templates, returns NULL.
TemplateDecl *getAsTemplateDecl() const;
+ /// \brief Retrieve the the underlying, overloaded function template
+ // declarations that this template name refers to, if known.
+ ///
+ /// \returns The set of overloaded function templates that this template
+ /// name refers to, if known. If the template name does not refer to a
+ /// specific set of function templates because it is a dependent name or
+ /// refers to a single template, returns NULL.
+ OverloadedFunctionDecl *getAsOverloadedFunctionDecl() const;
+
/// \brief Retrieve the underlying qualified template name
/// structure, if any.
QualifiedTemplateName *getAsQualifiedTemplateName() const {
@@ -119,8 +137,8 @@ public:
void *getAsVoidPointer() const { return Storage.getOpaqueValue(); }
/// \brief Build a template name from a void pointer.
- static TemplateName getFromVoidPointer(void *Ptr) {
- return TemplateName(Ptr);
+ static TemplateName getFromVoidPointer(void *Ptr) {
+ return TemplateName(Ptr);
}
};
@@ -145,15 +163,21 @@ class QualifiedTemplateName : public llvm::FoldingSetNode {
/// this name with DependentTemplateName).
llvm::PointerIntPair<NestedNameSpecifier *, 1> Qualifier;
- /// \brief The template declaration that this qualified name refers
- /// to.
- TemplateDecl *Template;
+ /// \brief The template declaration or set of overloaded function templates
+ /// that this qualified name refers to.
+ NamedDecl *Template;
friend class ASTContext;
QualifiedTemplateName(NestedNameSpecifier *NNS, bool TemplateKeyword,
TemplateDecl *Template)
- : Qualifier(NNS, TemplateKeyword? 1 : 0), Template(Template) { }
+ : Qualifier(NNS, TemplateKeyword? 1 : 0),
+ Template(reinterpret_cast<NamedDecl *>(Template)) { }
+
+ QualifiedTemplateName(NestedNameSpecifier *NNS, bool TemplateKeyword,
+ OverloadedFunctionDecl *Template)
+ : Qualifier(NNS, TemplateKeyword? 1 : 0),
+ Template(reinterpret_cast<NamedDecl *>(Template)) { }
public:
/// \brief Return the nested name specifier that qualifies this name.
@@ -163,16 +187,26 @@ public:
/// keyword.
bool hasTemplateKeyword() const { return Qualifier.getInt(); }
+ /// \brief The template declaration or set of overloaded functions that
+ /// that qualified name refers to.
+ NamedDecl *getDecl() const { return Template; }
+
/// \brief The template declaration to which this qualified name
- /// refers.
- TemplateDecl *getTemplateDecl() const { return Template; }
+ /// refers, or NULL if this qualified name refers to a set of overloaded
+ /// function templates.
+ TemplateDecl *getTemplateDecl() const;
+
+ /// \brief The set of overloaded function tempaltes to which this qualified
+ /// name refers, or NULL if this qualified name refers to a single
+ /// template declaration.
+ OverloadedFunctionDecl *getOverloadedFunctionDecl() const;
void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getQualifier(), hasTemplateKeyword(), getTemplateDecl());
+ Profile(ID, getQualifier(), hasTemplateKeyword(), getDecl());
}
- static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS,
- bool TemplateKeyword, TemplateDecl *Template) {
+ static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS,
+ bool TemplateKeyword, NamedDecl *Template) {
ID.AddPointer(NNS);
ID.AddBoolean(TemplateKeyword);
ID.AddPointer(Template);
@@ -183,7 +217,7 @@ public:
/// resolved prior to template instantiation.
///
/// This kind of template name refers to a dependent template name,
-/// including its nested name specifier. For example,
+/// including its nested name specifier (if any). 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.
@@ -205,11 +239,11 @@ class DependentTemplateName : public llvm::FoldingSetNode {
friend class ASTContext;
- DependentTemplateName(NestedNameSpecifier *Qualifier,
+ DependentTemplateName(NestedNameSpecifier *Qualifier,
const IdentifierInfo *Name)
: Qualifier(Qualifier), Name(Name), CanonicalTemplateName(this) { }
- DependentTemplateName(NestedNameSpecifier *Qualifier,
+ DependentTemplateName(NestedNameSpecifier *Qualifier,
const IdentifierInfo *Name,
TemplateName Canon)
: Qualifier(Qualifier), Name(Name), CanonicalTemplateName(Canon) { }
@@ -226,7 +260,7 @@ public:
Profile(ID, getQualifier(), getName());
}
- static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS,
+ static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS,
const IdentifierInfo *Name) {
ID.AddPointer(NNS);
ID.AddPointer(Name);
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index a00c0c4..89776b9 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -19,6 +19,7 @@
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/TemplateName.h"
#include "llvm/Support/Casting.h"
+#include "llvm/Support/type_traits.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/PointerIntPair.h"
@@ -29,7 +30,13 @@ using llvm::cast;
using llvm::cast_or_null;
using llvm::dyn_cast;
using llvm::dyn_cast_or_null;
-namespace clang { class Type; }
+namespace clang {
+ enum {
+ TypeAlignmentInBits = 3,
+ TypeAlignment = 1 << TypeAlignmentInBits
+ };
+ class Type; class ExtQuals;
+}
namespace llvm {
template <typename T>
@@ -41,7 +48,16 @@ namespace llvm {
static inline ::clang::Type *getFromVoidPointer(void *P) {
return static_cast< ::clang::Type*>(P);
}
- enum { NumLowBitsAvailable = 3 };
+ enum { NumLowBitsAvailable = clang::TypeAlignmentInBits };
+ };
+ template<>
+ class PointerLikeTypeTraits< ::clang::ExtQuals*> {
+ public:
+ static inline void *getAsVoidPointer(::clang::ExtQuals *P) { return P; }
+ static inline ::clang::ExtQuals *getFromVoidPointer(void *P) {
+ return static_cast< ::clang::ExtQuals*>(P);
+ }
+ enum { NumLowBitsAvailable = clang::TypeAlignmentInBits };
};
}
@@ -66,54 +82,359 @@ namespace clang {
class StmtIteratorBase;
class TemplateArgument;
class QualifiedNameType;
- class PrintingPolicy;
+ struct 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;
+/// Qualifiers - The collection of all-type qualifiers we support.
+/// Clang supports five independent qualifiers:
+/// * C99: const, volatile, and restrict
+/// * Embedded C (TR18037): address spaces
+/// * Objective C: the GC attributes (none, weak, or strong)
+class Qualifiers {
public:
- enum TQ { // NOTE: These flags must be kept in sync with DeclSpec::TQ.
+ enum TQ { // NOTE: These flags must be kept in sync with DeclSpec::TQ.
Const = 0x1,
Restrict = 0x2,
Volatile = 0x4,
- CVRFlags = Const|Restrict|Volatile
+ CVRMask = Const | Volatile | Restrict
};
-
- enum GCAttrTypes {
+
+ enum GC {
GCNone = 0,
Weak,
Strong
};
-
+
+ enum {
+ /// The maximum supported address space number.
+ /// 24 bits should be enough for anyone.
+ MaxAddressSpace = 0xffffffu,
+
+ /// The width of the "fast" qualifier mask.
+ FastWidth = 2,
+
+ /// The fast qualifier mask.
+ FastMask = (1 << FastWidth) - 1
+ };
+
+ Qualifiers() : Mask(0) {}
+
+ static Qualifiers fromFastMask(unsigned Mask) {
+ Qualifiers Qs;
+ Qs.addFastQualifiers(Mask);
+ return Qs;
+ }
+
+ static Qualifiers fromCVRMask(unsigned CVR) {
+ Qualifiers Qs;
+ Qs.addCVRQualifiers(CVR);
+ return Qs;
+ }
+
+ // Deserialize qualifiers from an opaque representation.
+ static Qualifiers fromOpaqueValue(unsigned opaque) {
+ Qualifiers Qs;
+ Qs.Mask = opaque;
+ return Qs;
+ }
+
+ // Serialize these qualifiers into an opaque representation.
+ unsigned getAsOpaqueValue() const {
+ return Mask;
+ }
+
+ bool hasConst() const { return Mask & Const; }
+ void setConst(bool flag) {
+ Mask = (Mask & ~Const) | (flag ? Const : 0);
+ }
+ void removeConst() { Mask &= ~Const; }
+ void addConst() { Mask |= Const; }
+
+ bool hasVolatile() const { return Mask & Volatile; }
+ void setVolatile(bool flag) {
+ Mask = (Mask & ~Volatile) | (flag ? Volatile : 0);
+ }
+ void removeVolatile() { Mask &= ~Volatile; }
+ void addVolatile() { Mask |= Volatile; }
+
+ bool hasRestrict() const { return Mask & Restrict; }
+ void setRestrict(bool flag) {
+ Mask = (Mask & ~Restrict) | (flag ? Restrict : 0);
+ }
+ void removeRestrict() { Mask &= ~Restrict; }
+ void addRestrict() { Mask |= Restrict; }
+
+ bool hasCVRQualifiers() const { return getCVRQualifiers(); }
+ unsigned getCVRQualifiers() const { return Mask & CVRMask; }
+ void setCVRQualifiers(unsigned mask) {
+ assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits");
+ Mask = (Mask & ~CVRMask) | mask;
+ }
+ void removeCVRQualifiers(unsigned mask) {
+ assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits");
+ Mask &= ~mask;
+ }
+ void removeCVRQualifiers() {
+ removeCVRQualifiers(CVRMask);
+ }
+ void addCVRQualifiers(unsigned mask) {
+ assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits");
+ Mask |= mask;
+ }
+
+ bool hasObjCGCAttr() const { return Mask & GCAttrMask; }
+ GC getObjCGCAttr() const { return GC((Mask & GCAttrMask) >> GCAttrShift); }
+ void setObjCGCAttr(GC type) {
+ Mask = (Mask & ~GCAttrMask) | (type << GCAttrShift);
+ }
+ void removeObjCGCAttr() { setObjCGCAttr(GCNone); }
+ void addObjCGCAttr(GC type) {
+ assert(type);
+ setObjCGCAttr(type);
+ }
+
+ bool hasAddressSpace() const { return Mask & AddressSpaceMask; }
+ unsigned getAddressSpace() const { return Mask >> AddressSpaceShift; }
+ void setAddressSpace(unsigned space) {
+ assert(space <= MaxAddressSpace);
+ Mask = (Mask & ~AddressSpaceMask)
+ | (((uint32_t) space) << AddressSpaceShift);
+ }
+ void removeAddressSpace() { setAddressSpace(0); }
+ void addAddressSpace(unsigned space) {
+ assert(space);
+ setAddressSpace(space);
+ }
+
+ // Fast qualifiers are those that can be allocated directly
+ // on a QualType object.
+ bool hasFastQualifiers() const { return getFastQualifiers(); }
+ unsigned getFastQualifiers() const { return Mask & FastMask; }
+ void setFastQualifiers(unsigned mask) {
+ assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits");
+ Mask = (Mask & ~FastMask) | mask;
+ }
+ void removeFastQualifiers(unsigned mask) {
+ assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits");
+ Mask &= ~mask;
+ }
+ void removeFastQualifiers() {
+ removeFastQualifiers(FastMask);
+ }
+ void addFastQualifiers(unsigned mask) {
+ assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits");
+ Mask |= mask;
+ }
+
+ /// hasNonFastQualifiers - Return true if the set contains any
+ /// qualifiers which require an ExtQuals node to be allocated.
+ bool hasNonFastQualifiers() const { return Mask & ~FastMask; }
+ Qualifiers getNonFastQualifiers() const {
+ Qualifiers Quals = *this;
+ Quals.setFastQualifiers(0);
+ return Quals;
+ }
+
+ /// hasQualifiers - Return true if the set contains any qualifiers.
+ bool hasQualifiers() const { return Mask; }
+ bool empty() const { return !Mask; }
+
+ /// \brief Add the qualifiers from the given set to this set.
+ void addQualifiers(Qualifiers Q) {
+ // If the other set doesn't have any non-boolean qualifiers, just
+ // bit-or it in.
+ if (!(Q.Mask & ~CVRMask))
+ Mask |= Q.Mask;
+ else {
+ Mask |= (Q.Mask & CVRMask);
+ if (Q.hasAddressSpace())
+ addAddressSpace(Q.getAddressSpace());
+ if (Q.hasObjCGCAttr())
+ addObjCGCAttr(Q.getObjCGCAttr());
+ }
+ }
+
+ bool operator==(Qualifiers Other) const { return Mask == Other.Mask; }
+ bool operator!=(Qualifiers Other) const { return Mask != Other.Mask; }
+
+ operator bool() const { return hasQualifiers(); }
+
+ Qualifiers &operator+=(Qualifiers R) {
+ addQualifiers(R);
+ return *this;
+ }
+
+ // Union two qualifier sets. If an enumerated qualifier appears
+ // in both sets, use the one from the right.
+ friend Qualifiers operator+(Qualifiers L, Qualifiers R) {
+ L += R;
+ return L;
+ }
+
+ std::string getAsString() const;
+ std::string getAsString(const PrintingPolicy &Policy) const {
+ std::string Buffer;
+ getAsStringInternal(Buffer, Policy);
+ return Buffer;
+ }
+ void getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const;
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddInteger(Mask);
+ }
+
+private:
+
+ // bits: |0 1 2|3 .. 4|5 .. 31|
+ // |C R V|GCAttr|AddrSpace|
+ uint32_t Mask;
+
+ static const uint32_t GCAttrMask = 0x18;
+ static const uint32_t GCAttrShift = 3;
+ static const uint32_t AddressSpaceMask = ~(CVRMask | GCAttrMask);
+ static const uint32_t AddressSpaceShift = 5;
+};
+
+
+/// ExtQuals - We can encode up to three bits in the low bits of a
+/// type pointer, but there are many more type qualifiers that we want
+/// to be able to apply to an arbitrary type. Therefore we have this
+/// struct, intended to be heap-allocated and used by QualType to
+/// store qualifiers.
+///
+/// The current design tags the 'const' and 'restrict' qualifiers in
+/// two low bits on the QualType pointer; a third bit records whether
+/// the pointer is an ExtQuals node. 'const' was chosen because it is
+/// orders of magnitude more common than the other two qualifiers, in
+/// both library and user code. It's relatively rare to see
+/// 'restrict' in user code, but many standard C headers are saturated
+/// with 'restrict' declarations, so that representing them efficiently
+/// is a critical goal of this representation.
+class ExtQuals : public llvm::FoldingSetNode {
+ // NOTE: changing the fast qualifiers should be straightforward as
+ // long as you don't make 'const' non-fast.
+ // 1. Qualifiers:
+ // a) Modify the bitmasks (Qualifiers::TQ and DeclSpec::TQ).
+ // Fast qualifiers must occupy the low-order bits.
+ // b) Update Qualifiers::FastWidth and FastMask.
+ // 2. QualType:
+ // a) Update is{Volatile,Restrict}Qualified(), defined inline.
+ // b) Update remove{Volatile,Restrict}, defined near the end of
+ // this header.
+ // 3. ASTContext:
+ // a) Update get{Volatile,Restrict}Type.
+
+ /// Context - the context to which this set belongs. We save this
+ /// here so that QualifierCollector can use it to reapply extended
+ /// qualifiers to an arbitrary type without requiring a context to
+ /// be pushed through every single API dealing with qualifiers.
+ ASTContext& Context;
+
+ /// BaseType - the underlying type that this qualifies
+ const Type *BaseType;
+
+ /// Quals - the immutable set of qualifiers applied by this
+ /// node; always contains extended qualifiers.
+ Qualifiers Quals;
+
+public:
+ ExtQuals(ASTContext& Context, const Type *Base, Qualifiers Quals)
+ : Context(Context), BaseType(Base), Quals(Quals)
+ {
+ assert(Quals.hasNonFastQualifiers()
+ && "ExtQuals created with no fast qualifiers");
+ assert(!Quals.hasFastQualifiers()
+ && "ExtQuals created with fast qualifiers");
+ }
+
+ Qualifiers getQualifiers() const { return Quals; }
+
+ bool hasVolatile() const { return Quals.hasVolatile(); }
+
+ bool hasObjCGCAttr() const { return Quals.hasObjCGCAttr(); }
+ Qualifiers::GC getObjCGCAttr() const { return Quals.getObjCGCAttr(); }
+
+ bool hasAddressSpace() const { return Quals.hasAddressSpace(); }
+ unsigned getAddressSpace() const { return Quals.getAddressSpace(); }
+
+ const Type *getBaseType() const { return BaseType; }
+
+ ASTContext &getContext() const { return Context; }
+
+public:
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ Profile(ID, getBaseType(), Quals);
+ }
+ static void Profile(llvm::FoldingSetNodeID &ID,
+ const Type *BaseType,
+ Qualifiers Quals) {
+ assert(!Quals.hasFastQualifiers() && "fast qualifiers in ExtQuals hash!");
+ ID.AddPointer(BaseType);
+ Quals.Profile(ID);
+ }
+};
+
+
+/// QualType - For efficiency, we don't store CV-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 two 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. A third bit
+/// indicates whether there are extended qualifiers present, in which
+/// case the pointer points to a special structure.
+class QualType {
+ // Thankfully, these are efficiently composable.
+ llvm::PointerIntPair<llvm::PointerUnion<const Type*,const ExtQuals*>,
+ Qualifiers::FastWidth> Value;
+
+ bool hasExtQuals() const {
+ return Value.getPointer().is<const ExtQuals*>();
+ }
+
+ const ExtQuals *getExtQualsUnsafe() const {
+ return Value.getPointer().get<const ExtQuals*>();
+ }
+
+ const Type *getTypePtrUnsafe() const {
+ return Value.getPointer().get<const Type*>();
+ }
+
+ friend class QualifierCollector;
+public:
QualType() {}
-
+
QualType(const Type *Ptr, unsigned Quals)
- : Value(const_cast<Type*>(Ptr), Quals) {}
+ : Value(Ptr, Quals) {}
+ QualType(const ExtQuals *Ptr, unsigned Quals)
+ : Value(Ptr, Quals) {}
+
+ unsigned getFastQualifiers() const { return Value.getInt(); }
+ void setFastQualifiers(unsigned Quals) { Value.setInt(Quals); }
+
+ /// Retrieves a pointer to the underlying (unqualified) type.
+ /// This should really return a const Type, but it's not worth
+ /// changing all the users right now.
+ Type *getTypePtr() const {
+ if (hasNonFastQualifiers())
+ return const_cast<Type*>(getExtQualsUnsafe()->getBaseType());
+ return const_cast<Type*>(getTypePtrUnsafe());
+ }
- 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();
}
@@ -121,65 +442,125 @@ public:
Type *operator->() const {
return getTypePtr();
}
-
+
/// isNull - Return true if this QualType doesn't point to a type yet.
bool isNull() const {
- return getTypePtr() == 0;
+ return Value.getPointer().isNull();
}
bool isConstQualified() const {
- return (getCVRQualifiers() & Const) ? true : false;
+ return (getFastQualifiers() & Qualifiers::Const);
+ }
+ bool isRestrictQualified() const {
+ return (getFastQualifiers() & Qualifiers::Restrict);
}
bool isVolatileQualified() const {
- return (getCVRQualifiers() & Volatile) ? true : false;
+ return (hasNonFastQualifiers() && getExtQualsUnsafe()->hasVolatile());
}
- bool isRestrictQualified() const {
- return (getCVRQualifiers() & Restrict) ? true : false;
+
+ // Determines whether this type has any direct qualifiers.
+ bool hasQualifiers() const {
+ return getFastQualifiers() || hasNonFastQualifiers();
+ }
+
+ bool hasNonFastQualifiers() const {
+ return hasExtQuals();
+ }
+
+ // Retrieves the set of qualifiers belonging to this type.
+ Qualifiers getQualifiers() const {
+ Qualifiers Quals;
+ if (hasNonFastQualifiers())
+ Quals = getExtQualsUnsafe()->getQualifiers();
+ Quals.addFastQualifiers(getFastQualifiers());
+ return Quals;
}
- 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); }
+ // Retrieves the CVR qualifiers of this type.
+ unsigned getCVRQualifiers() const {
+ unsigned CVR = getFastQualifiers();
+ if (isVolatileQualified()) CVR |= Qualifiers::Volatile;
+ return CVR;
+ }
- void removeConst() { Value.setInt(Value.getInt() & ~Const); }
- void removeVolatile() { Value.setInt(Value.getInt() & ~Volatile); }
- void removeRestrict() { Value.setInt(Value.getInt() & ~Restrict); }
+ bool isConstant(ASTContext& Ctx) const {
+ return QualType::isConstant(*this, Ctx);
+ }
- QualType getQualifiedType(unsigned TQs) const {
- return QualType(getTypePtr(), TQs);
+ // Don't promise in the API that anything besides 'const' can be
+ // easily added.
+
+ /// addConst - add the specified type qualifier to this QualType.
+ void addConst() {
+ addFastQualifiers(Qualifiers::Const);
+ }
+ QualType withConst() const {
+ return withFastQualifiers(Qualifiers::Const);
}
- QualType getWithAdditionalQualifiers(unsigned TQs) const {
- return QualType(getTypePtr(), TQs|getCVRQualifiers());
+
+ void addFastQualifiers(unsigned TQs) {
+ assert(!(TQs & ~Qualifiers::FastMask)
+ && "non-fast qualifier bits set in mask!");
+ Value.setInt(Value.getInt() | TQs);
+ }
+
+ void removeConst();
+ void removeVolatile();
+ void removeRestrict();
+ void removeCVRQualifiers(unsigned Mask);
+
+ void removeFastQualifiers() { Value.setInt(0); }
+ void removeFastQualifiers(unsigned Mask) {
+ assert(!(Mask & ~Qualifiers::FastMask) && "mask has non-fast qualifiers");
+ Value.setInt(Value.getInt() & ~Mask);
+ }
+
+ // Creates a type with the given qualifiers in addition to any
+ // qualifiers already on this type.
+ QualType withFastQualifiers(unsigned TQs) const {
+ QualType T = *this;
+ T.addFastQualifiers(TQs);
+ return T;
+ }
+
+ // Creates a type with exactly the given fast qualifiers, removing
+ // any existing fast qualifiers.
+ QualType withExactFastQualifiers(unsigned TQs) const {
+ return withoutFastQualifiers().withFastQualifiers(TQs);
+ }
+
+ // Removes fast qualifiers, but leaves any extended qualifiers in place.
+ QualType withoutFastQualifiers() const {
+ QualType T = *this;
+ T.removeFastQualifiers();
+ return T;
}
- QualType withConst() const { return getWithAdditionalQualifiers(Const); }
- QualType withVolatile() const { return getWithAdditionalQualifiers(Volatile);}
- QualType withRestrict() const { return getWithAdditionalQualifiers(Restrict);}
-
- QualType getUnqualifiedType() const;
+ QualType getUnqualifiedType() const { return QualType(getTypePtr(), 0); }
+
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;
+ ///
+ /// Qualifiers are left in place.
+ QualType getDesugaredType() const {
+ return QualType::getDesugaredType(*this);
+ }
/// operator==/!= - Indicate whether the specified types and qualifiers are
/// identical.
- bool operator==(const QualType &RHS) const {
- return Value == RHS.Value;
+ friend bool operator==(const QualType &LHS, const QualType &RHS) {
+ return LHS.Value == RHS.Value;
}
- bool operator!=(const QualType &RHS) const {
- return Value != RHS.Value;
+ friend bool operator!=(const QualType &LHS, const QualType &RHS) {
+ return LHS.Value != RHS.Value;
}
std::string getAsString() const;
@@ -190,31 +571,40 @@ public:
}
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;
+ inline Qualifiers::GC getObjCGCAttr() const;
/// isObjCGCWeak true when Type is objc's weak.
bool isObjCGCWeak() const {
- return getObjCGCAttr() == Weak;
+ return getObjCGCAttr() == Qualifiers::Weak;
}
/// isObjCGCStrong true when Type is objc's strong.
bool isObjCGCStrong() const {
- return getObjCGCAttr() == Strong;
+ return getObjCGCAttr() == Qualifiers::Strong;
}
+
+ /// getNoReturnAttr - Returns true if the type has the noreturn attribute,
+ /// false otherwise.
+ bool getNoReturnAttr() const;
+
+private:
+ // These methods are implemented in a separate translation unit;
+ // "static"-ize them to avoid creating temporary QualTypes in the
+ // caller.
+ static bool isConstant(QualType T, ASTContext& Ctx);
+ static QualType getDesugaredType(QualType T);
};
} // end clang.
@@ -230,7 +620,7 @@ template<> struct simplify_type<const ::clang::QualType> {
};
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> {
@@ -241,9 +631,10 @@ public:
static inline clang::QualType getFromVoidPointer(void *P) {
return clang::QualType::getFromOpaquePtr(P);
}
- // CVR qualifiers go in low bits.
+ // Various qualifiers go in low bits.
enum { NumLowBitsAvailable = 0 };
};
+
} // end namespace llvm
namespace clang {
@@ -281,7 +672,10 @@ public:
#include "clang/AST/TypeNodes.def"
TagFirst = Record, TagLast = Enum
};
-
+
+protected:
+ enum { TypeClassBitSize = 6 };
+
private:
QualType CanonicalType;
@@ -291,7 +685,7 @@ private:
/// 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;
+ unsigned TC : TypeClassBitSize;
Type(const Type&); // DO NOT IMPLEMENT.
void operator=(const Type&); // DO NOT IMPLEMENT.
@@ -304,15 +698,15 @@ protected:
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):
+ /// 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++
@@ -324,7 +718,7 @@ public:
/// 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.
+ /// routine will need to determine if the size is actually required.
bool isIncompleteType() const;
/// isIncompleteOrObjectType - Return true if this is an incomplete or object
@@ -339,13 +733,13 @@ public:
/// 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)
@@ -354,7 +748,7 @@ public:
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).
@@ -368,13 +762,14 @@ public:
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 isFunctionNoProtoType() const { return getAs<FunctionNoProtoType>(); }
+ bool isFunctionProtoType() const { return getAs<FunctionProtoType>(); }
bool isPointerType() const;
+ bool isAnyPointerType() const; // Any C pointer or ObjC object pointer
bool isBlockPointerType() const;
bool isVoidPointerType() const;
bool isReferenceType() const;
@@ -389,21 +784,27 @@ public:
bool isVariableArrayType() const;
bool isDependentSizedArrayType() const;
bool isRecordType() const;
- bool isClassType() const;
- bool isStructureType() 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 isObjCObjectPointerType() const; // Pointer to *any* ObjC object.
+ // FIXME: change this to 'raw' interface type, so we can used 'interface' type
+ // for the common case.
bool isObjCInterfaceType() const; // NSString or NSString<foo>
bool isObjCQualifiedInterfaceType() const; // NSString<foo>
bool isObjCQualifiedIdType() const; // id<foo>
+ bool isObjCQualifiedClassType() const; // Class<foo>
+ bool isObjCIdType() const; // id
+ bool isObjCClassType() const; // Class
+ bool isObjCBuiltinType() const; // 'id' or 'Class'
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
+ /// that its definition somehow depends on a template parameter
/// (C++ [temp.dep.type]).
bool isDependentType() const { return Dependent; }
bool isOverloadableType() const;
@@ -416,41 +817,29 @@ public:
/// hasObjCPointerRepresentation - Whether this type can represent
/// an objective pointer type for the purpose of GC'ability
- bool hasObjCPointerRepresentation() const;
+ 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 ObjCObjectPointerType *getAsObjCObjectPointerType() const;
- const ObjCInterfaceType *getAsObjCInterfaceType() const;
- const ObjCQualifiedInterfaceType *getAsObjCQualifiedInterfaceType() const;
+ // The following is a convenience method that returns an ObjCObjectPointerType
+ // for object declared using an interface.
+ const ObjCObjectPointerType *getAsObjCInterfacePointerType() const;
const ObjCObjectPointerType *getAsObjCQualifiedIdType() const;
- const TemplateTypeParmType *getAsTemplateTypeParmType() const;
+ const ObjCInterfaceType *getAsObjCQualifiedInterfaceType() const;
+ const CXXRecordDecl *getCXXRecordDeclForPointerType() const;
+
+ // Member-template getAs<specific type>'. This scheme will eventually
+ // replace the specific getAsXXXX methods above.
+ //
+ // There are some specializations of this member template listed
+ // immediately following this class.
+ template <typename T> const T *getAs() 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;
@@ -459,15 +848,16 @@ public:
/// 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;
-
+
+ /// getPointeeType - If this is a pointer, ObjC object pointer, or block
+ /// pointer, this returns the respective pointee.
+ QualType getPointeeType() const;
+
+ /// getUnqualifiedDesugaredType() - Return the specified type with
+ /// any "sugar" removed from the type, removing any typedefs,
+ /// typeofs, etc., as well as any qualifiers.
+ const Type *getUnqualifiedDesugaredType() const;
+
/// More type predicates useful for type checking/promotion
bool isPromotableIntegerType() const; // C99 6.3.1.1p2
@@ -492,56 +882,27 @@ public:
/// set of type specifiers.
bool isSpecifierType() const;
+ const char *getTypeClassName() const;
+
QualType getCanonicalTypeInternal() const { return CanonicalType; }
void dump() const;
- virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const = 0;
+ 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; }
-};
+template <> inline const TypedefType *Type::getAs() const {
+ return dyn_cast<TypedefType>(this);
+}
+
+// We can do canonical leaf types faster, because we don't have to
+// worry about preserving child type decoration.
+#define TYPE(Class, Base)
+#define LEAF_TYPE(Class) \
+template <> inline const Class##Type *Type::getAs() const { \
+ return dyn_cast<Class##Type>(CanonicalType); \
+}
+#include "clang/AST/TypeNodes.def"
/// BuiltinType - This class is used for builtin types like 'int'. Builtin
@@ -550,16 +911,18 @@ 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.
+ Char16, // This is 'char16_t' for C++.
+ Char32, // This is 'char32_t' for C++.
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++.
@@ -568,29 +931,35 @@ public:
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.
-
- UndeducedAuto // In C++0x, this represents the type of an auto variable
+
+ UndeducedAuto, // In C++0x, this represents the type of an auto variable
// that has not been deduced yet.
+ ObjCId, // This represents the ObjC 'id' type.
+ ObjCClass // This represents the ObjC 'Class' type.
};
private:
Kind TypeKind;
public:
- BuiltinType(Kind K)
- : Type(Builtin, QualType(), /*Dependent=*/(K == Dependent)),
+ BuiltinType(Kind K)
+ : Type(Builtin, QualType(), /*Dependent=*/(K == Dependent)),
TypeKind(K) {}
-
+
Kind getKind() const { return TypeKind; }
const char *getName(const LangOptions &LO) const;
-
- virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
-
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ 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; }
};
@@ -605,13 +974,17 @@ private:
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;
-
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ 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; }
};
@@ -622,22 +995,26 @@ public:
class ComplexType : public Type, public llvm::FoldingSetNode {
QualType ElementType;
ComplexType(QualType Element, QualType CanonicalPtr) :
- Type(Complex, CanonicalPtr, Element->isDependentType()),
+ 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;
-
+
+ virtual void getAsStringInternal(std::string &InnerString,
+ const PrintingPolicy &Policy) const;
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
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; }
};
@@ -652,18 +1029,22 @@ class PointerType : public Type, public llvm::FoldingSetNode {
}
friend class ASTContext; // ASTContext creates these.
public:
-
- virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
-
+
+ virtual void getAsStringInternal(std::string &InnerString,
+ const PrintingPolicy &Policy) const;
+
QualType getPointeeType() const { return PointeeType; }
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
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; }
};
@@ -675,26 +1056,30 @@ public:
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()),
+ 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;
-
+ virtual void getAsStringInternal(std::string &InnerString,
+ const PrintingPolicy &Policy) const;
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
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 Type *T) {
+ return T->getTypeClass() == BlockPointer;
}
static bool classof(const BlockPointerType *) { return true; }
};
@@ -734,7 +1119,11 @@ class LValueReferenceType : public ReferenceType {
}
friend class ASTContext; // ASTContext creates these
public:
- virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
+ virtual void getAsStringInternal(std::string &InnerString,
+ const PrintingPolicy &Policy) const;
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
static bool classof(const Type *T) {
return T->getTypeClass() == LValueReference;
@@ -750,7 +1139,11 @@ class RValueReferenceType : public ReferenceType {
}
friend class ASTContext; // ASTContext creates these
public:
- virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
+ virtual void getAsStringInternal(std::string &InnerString,
+ const PrintingPolicy &Policy) const;
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
static bool classof(const Type *T) {
return T->getTypeClass() == RValueReference;
@@ -778,7 +1171,11 @@ public:
const Type *getClass() const { return Class; }
- virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
+ virtual void getAsStringInternal(std::string &InnerString,
+ const PrintingPolicy &Policy) const;
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
void Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, getPointeeType(), getClass());
@@ -809,15 +1206,15 @@ public:
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...
@@ -835,10 +1232,15 @@ public:
ArraySizeModifier getSizeModifier() const {
return ArraySizeModifier(SizeModifier);
}
- unsigned getIndexTypeQualifier() const { return IndexTypeQuals; }
-
+ Qualifiers getIndexTypeQualifiers() const {
+ return Qualifiers::fromCVRMask(IndexTypeQuals);
+ }
+ unsigned getIndexTypeCVRQualifiers() const { return IndexTypeQuals; }
+
static bool classof(const Type *T) {
return T->getTypeClass() == ConstantArray ||
+ T->getTypeClass() == ConstantArrayWithExpr ||
+ T->getTypeClass() == ConstantArrayWithoutExpr ||
T->getTypeClass() == VariableArray ||
T->getTypeClass() == IncompleteArray ||
T->getTypeClass() == DependentSizedArray;
@@ -846,23 +1248,33 @@ public:
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.
+/// ConstantArrayType - This class represents the canonical version of
+/// C arrays with a specified constant size. For example, the canonical
+/// type for 'int A[4 + 4*100]' is a ConstantArrayType where the element
+/// type is 'int' and the size is 404.
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) {}
+ : ArrayType(ConstantArray, et, can, sm, tq),
+ Size(size) {}
+protected:
+ ConstantArrayType(TypeClass tc, QualType et, QualType can,
+ const llvm::APInt &size, ArraySizeModifier sm, unsigned tq)
+ : ArrayType(tc, 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;
-
+ virtual void getAsStringInternal(std::string &InnerString,
+ const PrintingPolicy &Policy) const;
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getElementType(), getSize(),
- getSizeModifier(), getIndexTypeQualifier());
+ Profile(ID, getElementType(), getSize(),
+ getSizeModifier(), getIndexTypeCVRQualifiers());
}
static void Profile(llvm::FoldingSetNodeID &ID, QualType ET,
const llvm::APInt &ArraySize, ArraySizeModifier SizeMod,
@@ -872,35 +1284,115 @@ public:
ID.AddInteger(SizeMod);
ID.AddInteger(TypeQuals);
}
- static bool classof(const Type *T) {
- return T->getTypeClass() == ConstantArray;
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == ConstantArray ||
+ T->getTypeClass() == ConstantArrayWithExpr ||
+ T->getTypeClass() == ConstantArrayWithoutExpr;
}
static bool classof(const ConstantArrayType *) { return true; }
};
+/// ConstantArrayWithExprType - This class represents C arrays with a
+/// constant size specified by means of an integer constant expression.
+/// For example 'int A[sizeof(int)]' has ConstantArrayWithExprType where
+/// the element type is 'int' and the size expression is 'sizeof(int)'.
+/// These types are non-canonical.
+class ConstantArrayWithExprType : public ConstantArrayType {
+ /// SizeExpr - The ICE occurring in the concrete syntax.
+ Expr *SizeExpr;
+ /// Brackets - The left and right array brackets.
+ SourceRange Brackets;
+
+ ConstantArrayWithExprType(QualType et, QualType can,
+ const llvm::APInt &size, Expr *e,
+ ArraySizeModifier sm, unsigned tq,
+ SourceRange brackets)
+ : ConstantArrayType(ConstantArrayWithExpr, et, can, size, sm, tq),
+ SizeExpr(e), Brackets(brackets) {}
+ friend class ASTContext; // ASTContext creates these.
+ virtual void Destroy(ASTContext& C);
+
+public:
+ Expr *getSizeExpr() const { return SizeExpr; }
+ SourceRange getBracketsRange() const { return Brackets; }
+ SourceLocation getLBracketLoc() const { return Brackets.getBegin(); }
+ SourceLocation getRBracketLoc() const { return Brackets.getEnd(); }
+
+ virtual void getAsStringInternal(std::string &InnerString,
+ const PrintingPolicy &Policy) const;
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == ConstantArrayWithExpr;
+ }
+ static bool classof(const ConstantArrayWithExprType *) { return true; }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ assert(0 && "Cannot unique ConstantArrayWithExprTypes.");
+ }
+};
+
+/// ConstantArrayWithoutExprType - This class represents C arrays with a
+/// constant size that was not specified by an integer constant expression,
+/// but inferred by static semantics.
+/// For example 'int A[] = { 0, 1, 2 }' has ConstantArrayWithoutExprType.
+/// These types are non-canonical: the corresponding canonical type,
+/// having the size specified in an APInt object, is a ConstantArrayType.
+class ConstantArrayWithoutExprType : public ConstantArrayType {
+
+ ConstantArrayWithoutExprType(QualType et, QualType can,
+ const llvm::APInt &size,
+ ArraySizeModifier sm, unsigned tq)
+ : ConstantArrayType(ConstantArrayWithoutExpr, et, can, size, sm, tq) {}
+ friend class ASTContext; // ASTContext creates these.
+
+public:
+ virtual void getAsStringInternal(std::string &InnerString,
+ const PrintingPolicy &Policy) const;
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == ConstantArrayWithoutExpr;
+ }
+ static bool classof(const ConstantArrayWithoutExprType *) { return true; }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ assert(0 && "Cannot unique ConstantArrayWithoutExprTypes.");
+ }
+};
+
/// 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)
+ 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;
- virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
- static bool classof(const Type *T) {
- return T->getTypeClass() == IncompleteArray;
+ 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());
+ Profile(ID, getElementType(), getSizeModifier(),
+ getIndexTypeCVRQualifiers());
}
-
+
static void Profile(llvm::FoldingSetNodeID &ID, QualType ET,
ArraySizeModifier SizeMod, unsigned TypeQuals) {
ID.AddPointer(ET.getAsOpaquePtr());
@@ -925,32 +1417,43 @@ public:
/// }
///
class VariableArrayType : public ArrayType {
- /// SizeExpr - An assignment expression. VLA's are only permitted within
- /// a function block.
+ /// SizeExpr - An assignment expression. VLA's are only permitted within
+ /// a function block.
Stmt *SizeExpr;
-
+ /// Brackets - The left and right array brackets.
+ SourceRange Brackets;
+
VariableArrayType(QualType et, QualType can, Expr *e,
- ArraySizeModifier sm, unsigned tq)
- : ArrayType(VariableArray, et, can, sm, tq), SizeExpr((Stmt*) e) {}
+ ArraySizeModifier sm, unsigned tq,
+ SourceRange brackets)
+ : ArrayType(VariableArray, et, can, sm, tq),
+ SizeExpr((Stmt*) e), Brackets(brackets) {}
friend class ASTContext; // ASTContext creates these.
virtual void Destroy(ASTContext& C);
public:
- Expr *getSizeExpr() const {
+ 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;
+ SourceRange getBracketsRange() const { return Brackets; }
+ SourceLocation getLBracketLoc() const { return Brackets.getBegin(); }
+ SourceLocation getRBracketLoc() const { return Brackets.getEnd(); }
+
+ virtual void getAsStringInternal(std::string &InnerString,
+ const PrintingPolicy &Policy) const;
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ 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.");
}
@@ -959,7 +1462,7 @@ public:
/// DependentSizedArrayType - This type represents an array type in
/// C++ whose size is a value-dependent expression. For example:
/// @code
-/// template<typename T, int Size>
+/// template<typename T, int Size>
/// class array {
/// T data[Size];
/// };
@@ -968,35 +1471,54 @@ public:
/// until template instantiation occurs, at which point this will
/// become either a ConstantArrayType or a VariableArrayType.
class DependentSizedArrayType : public ArrayType {
+ ASTContext &Context;
+
/// 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) {}
+ /// Brackets - The left and right array brackets.
+ SourceRange Brackets;
+
+ DependentSizedArrayType(ASTContext &Context, QualType et, QualType can,
+ Expr *e, ArraySizeModifier sm, unsigned tq,
+ SourceRange brackets)
+ : ArrayType(DependentSizedArray, et, can, sm, tq),
+ Context(Context), SizeExpr((Stmt*) e), Brackets(brackets) {}
friend class ASTContext; // ASTContext creates these.
virtual void Destroy(ASTContext& C);
public:
- Expr *getSizeExpr() const {
+ 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;
+ SourceRange getBracketsRange() const { return Brackets; }
+ SourceLocation getLBracketLoc() const { return Brackets.getBegin(); }
+ SourceLocation getRBracketLoc() const { return Brackets.getEnd(); }
+
+ virtual void getAsStringInternal(std::string &InnerString,
+ const PrintingPolicy &Policy) const;
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ 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.");
+ Profile(ID, Context, getElementType(),
+ getSizeModifier(), getIndexTypeCVRQualifiers(), getSizeExpr());
}
+
+ static void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context,
+ QualType ET, ArraySizeModifier SizeMod,
+ unsigned TypeQuals, Expr *E);
};
/// DependentSizedExtVectorType - This type represent an extended vector type
@@ -1007,71 +1529,88 @@ public:
/// typedef T __attribute__((ext_vector_type(Size))) type;
/// }
/// @endcode
-class DependentSizedExtVectorType : public Type {
+class DependentSizedExtVectorType : public Type, public llvm::FoldingSetNode {
+ ASTContext &Context;
Expr *SizeExpr;
/// ElementType - The element type of the array.
QualType ElementType;
SourceLocation loc;
-
- DependentSizedExtVectorType(QualType ElementType, QualType can,
- Expr *SizeExpr, SourceLocation loc)
- : Type (DependentSizedExtVector, can, true),
- SizeExpr(SizeExpr), ElementType(ElementType), loc(loc) {}
+
+ DependentSizedExtVectorType(ASTContext &Context, QualType ElementType,
+ QualType can, Expr *SizeExpr, SourceLocation loc)
+ : Type (DependentSizedExtVector, can, true),
+ Context(Context), SizeExpr(SizeExpr), ElementType(ElementType),
+ loc(loc) {}
friend class ASTContext;
virtual void Destroy(ASTContext& C);
public:
- const Expr *getSizeExpr() const { return SizeExpr; }
+ Expr *getSizeExpr() const { return SizeExpr; }
QualType getElementType() const { return ElementType; }
SourceLocation getAttributeLoc() const { return loc; }
- virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == DependentSizedExtVector;
+ virtual void getAsStringInternal(std::string &InnerString,
+ const PrintingPolicy &Policy) const;
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == DependentSizedExtVector;
}
- static bool classof(const DependentSizedExtVectorType *) { return true; }
+ static bool classof(const DependentSizedExtVectorType *) { return true; }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, Context, getElementType(), getSizeExpr());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context,
+ QualType ElementType, Expr *SizeExpr);
};
-
+
/// 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
+/// __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) {}
+ 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; }
+ unsigned getNumElements() const { return NumElements; }
+
+ virtual void getAsStringInternal(std::string &InnerString,
+ const PrintingPolicy &Policy) const;
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
- 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,
+ 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 Type *T) {
+ return T->getTypeClass() == Vector || T->getTypeClass() == ExtVector;
}
static bool classof(const VectorType *) { return true; }
};
@@ -1083,7 +1622,7 @@ public:
/// 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) {}
+ VectorType(ExtVector, vecType, nElements, canonType) {}
friend class ASTContext; // ASTContext creates these.
public:
static int getPointAccessorIdx(char c) {
@@ -1122,21 +1661,25 @@ public:
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;
+ virtual void getAsStringInternal(std::string &InnerString,
+ const PrintingPolicy &Policy) const;
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
- static bool classof(const Type *T) {
- return T->getTypeClass() == ExtVector;
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == ExtVector;
}
static bool classof(const ExtVectorType *) { return true; }
};
@@ -1157,21 +1700,26 @@ class FunctionType : public Type {
/// cv-qualifier-seq, [...], are part of the function type.
///
unsigned TypeQuals : 3;
-
+
+ /// NoReturn - Indicates if the function type is attribute noreturn.
+ unsigned NoReturn : 1;
+
// The type returned by the function.
QualType ResultType;
protected:
FunctionType(TypeClass tc, QualType res, bool SubclassInfo,
- unsigned typeQuals, QualType Canonical, bool Dependent)
+ unsigned typeQuals, QualType Canonical, bool Dependent,
+ bool noReturn = false)
: Type(tc, Canonical, Dependent),
- SubClassData(SubclassInfo), TypeQuals(typeQuals), ResultType(res) {}
+ SubClassData(SubclassInfo), TypeQuals(typeQuals), NoReturn(noReturn),
+ ResultType(res) {}
bool getSubClassData() const { return SubClassData; }
unsigned getTypeQuals() const { return TypeQuals; }
public:
-
+
QualType getResultType() const { return ResultType; }
+ bool getNoReturnAttr() const { return NoReturn; }
-
static bool classof(const Type *T) {
return T->getTypeClass() == FunctionNoProto ||
T->getTypeClass() == FunctionProto;
@@ -1182,22 +1730,29 @@ public:
/// 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) {}
+ FunctionNoProtoType(QualType Result, QualType Canonical,
+ bool NoReturn = false)
+ : FunctionType(FunctionNoProto, Result, false, 0, Canonical,
+ /*Dependent=*/false, NoReturn) {}
friend class ASTContext; // ASTContext creates these.
public:
// No additional state past what FunctionType provides.
-
- virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
+
+ virtual void getAsStringInternal(std::string &InnerString,
+ const PrintingPolicy &Policy) const;
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getResultType());
+ Profile(ID, getResultType(), getNoReturnAttr());
}
- static void Profile(llvm::FoldingSetNodeID &ID, QualType ResultType) {
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType ResultType,
+ bool NoReturn) {
+ ID.AddInteger(NoReturn);
ID.AddPointer(ResultType.getAsOpaquePtr());
}
-
+
static bool classof(const Type *T) {
return T->getTypeClass() == FunctionNoProto;
}
@@ -1223,10 +1778,10 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
FunctionProtoType(QualType Result, const QualType *ArgArray, unsigned numArgs,
bool isVariadic, unsigned typeQuals, bool hasExs,
bool hasAnyExs, const QualType *ExArray,
- unsigned numExs, QualType Canonical)
+ unsigned numExs, QualType Canonical, bool NoReturn)
: FunctionType(FunctionProto, Result, isVariadic, typeQuals, Canonical,
- (Result->isDependentType() ||
- hasAnyDependentType(ArgArray, numArgs))),
+ (Result->isDependentType() ||
+ hasAnyDependentType(ArgArray, numArgs)), NoReturn),
NumArgs(numArgs), NumExceptions(numExs), HasExceptionSpec(hasExs),
AnyExceptionSpec(hasAnyExs) {
// Fill in the trailing argument array.
@@ -1273,14 +1828,14 @@ public:
assert(i < NumExceptions && "Invalid exception number!");
return exception_begin()[i];
}
- bool hasEmptyExceptionSpec() const {
- return hasExceptionSpec() && !hasAnyExceptionSpec() &&
+ 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);
@@ -1296,7 +1851,11 @@ public:
return exception_begin() + NumExceptions;
}
- virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
+ virtual void getAsStringInternal(std::string &InnerString,
+ const PrintingPolicy &Policy) const;
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
static bool classof(const Type *T) {
return T->getTypeClass() == FunctionProto;
@@ -1308,22 +1867,23 @@ public:
arg_type_iterator ArgTys, unsigned NumArgs,
bool isVariadic, unsigned TypeQuals,
bool hasExceptionSpec, bool anyExceptionSpec,
- unsigned NumExceptions, exception_iterator Exs);
+ unsigned NumExceptions, exception_iterator Exs,
+ bool NoReturn);
};
class TypedefType : public Type {
TypedefDecl *Decl;
protected:
- TypedefType(TypeClass tc, TypedefDecl *D, QualType can)
+ 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:
@@ -1331,8 +1891,12 @@ public:
/// 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;
+
+ bool isSugared() const { return true; }
+ QualType desugar() 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; }
@@ -1341,29 +1905,66 @@ public:
/// TypeOfExprType (GCC extension).
class TypeOfExprType : public Type {
Expr *TOExpr;
- TypeOfExprType(Expr *E, QualType can);
+
+protected:
+ TypeOfExprType(Expr *E, QualType can = QualType());
friend class ASTContext; // ASTContext creates these.
public:
Expr *getUnderlyingExpr() const { return TOExpr; }
-
- virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
+
+ /// \brief Remove a single level of sugar.
+ QualType desugar() const;
+
+ /// \brief Returns whether this type directly provides sugar.
+ bool isSugared() const { return true; }
+
+ 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; }
};
+/// Subclass of TypeOfExprType that is used for canonical, dependent
+/// typeof(expr) types.
+class DependentTypeOfExprType
+ : public TypeOfExprType, public llvm::FoldingSetNode {
+ ASTContext &Context;
+
+public:
+ DependentTypeOfExprType(ASTContext &Context, Expr *E)
+ : TypeOfExprType(E), Context(Context) { }
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, Context, getUnderlyingExpr());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context,
+ Expr *E);
+};
+
/// TypeOfType (GCC extension).
class TypeOfType : public Type {
QualType TOType;
- TypeOfType(QualType T, QualType can)
+ 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;
+
+ /// \brief Remove a single level of sugar.
+ QualType desugar() const { return getUnderlyingType(); }
+
+ /// \brief Returns whether this type directly provides sugar.
+ bool isSugared() const { return true; }
+
+ 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; }
@@ -1372,18 +1973,51 @@ public:
/// DecltypeType (C++0x)
class DecltypeType : public Type {
Expr *E;
- DecltypeType(Expr *E, QualType can);
+
+ // FIXME: We could get rid of UnderlyingType if we wanted to: We would have to
+ // Move getDesugaredType to ASTContext so that it can call getDecltypeForExpr
+ // from it.
+ QualType UnderlyingType;
+
+protected:
+ DecltypeType(Expr *E, QualType underlyingType, QualType can = QualType());
friend class ASTContext; // ASTContext creates these.
public:
Expr *getUnderlyingExpr() const { return E; }
-
- virtual void getAsStringInternal(std::string &InnerString,
+ QualType getUnderlyingType() const { return UnderlyingType; }
+
+ /// \brief Remove a single level of sugar.
+ QualType desugar() const { return getUnderlyingType(); }
+
+ /// \brief Returns whether this type directly provides sugar.
+ bool isSugared() const { return !isDependentType(); }
+
+ virtual void getAsStringInternal(std::string &InnerString,
const PrintingPolicy &Policy) const;
-
+
static bool classof(const Type *T) { return T->getTypeClass() == Decltype; }
static bool classof(const DecltypeType *) { return true; }
};
-
+
+/// Subclass of DecltypeType that is used for canonical, dependent
+/// C++0x decltype types.
+class DependentDecltypeType : public DecltypeType, public llvm::FoldingSetNode {
+ ASTContext &Context;
+
+public:
+ DependentDecltypeType(ASTContext &Context, Expr *E);
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, Context, getUnderlyingExpr());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context,
+ Expr *E);
+};
+
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
@@ -1397,17 +2031,18 @@ class TagType : public Type {
protected:
TagType(TypeClass TC, TagDecl *D, QualType can);
-public:
+public:
TagDecl *getDecl() const { return decl.getPointer(); }
-
+
/// @brief Determines whether this type is in the process of being
- /// defined.
+ /// defined.
bool isBeingDefined() const { return decl.getInt(); }
- void setBeingDefined(bool Def) { decl.setInt(Def? 1 : 0); }
+ void setBeingDefined(bool Def) const { decl.setInt(Def? 1 : 0); }
- virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
+ virtual void getAsStringInternal(std::string &InnerString,
+ const PrintingPolicy &Policy) const;
- static bool classof(const Type *T) {
+ static bool classof(const Type *T) {
return T->getTypeClass() >= TagFirst && T->getTypeClass() <= TagLast;
}
static bool classof(const TagType *) { return true; }
@@ -1425,20 +2060,23 @@ protected:
: 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
+
+ // 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.
+ // 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; }
-
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
static bool classof(const TagType *T);
static bool classof(const Type *T) {
return isa<TagType>(T) && classof(cast<TagType>(T));
@@ -1453,11 +2091,14 @@ class EnumType : public TagType {
: TagType(Enum, reinterpret_cast<TagDecl*>(D), QualType()) { }
friend class ASTContext; // ASTContext creates these.
public:
-
+
EnumDecl *getDecl() const {
return reinterpret_cast<EnumDecl*>(TagType::getDecl());
}
-
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
static bool classof(const TagType *T);
static bool classof(const Type *T) {
return isa<TagType>(T) && classof(cast<TagType>(T));
@@ -1465,18 +2106,83 @@ public:
static bool classof(const EnumType *) { return true; }
};
+/// ElaboratedType - A non-canonical type used to represents uses of
+/// elaborated type specifiers in C++. For example:
+///
+/// void foo(union MyUnion);
+/// ^^^^^^^^^^^^^
+///
+/// At the moment, for efficiency we do not create elaborated types in
+/// C, since outside of typedefs all references to structs would
+/// necessarily be elaborated.
+class ElaboratedType : public Type, public llvm::FoldingSetNode {
+public:
+ enum TagKind {
+ TK_struct,
+ TK_union,
+ TK_class,
+ TK_enum
+ };
+
+private:
+ /// The tag that was used in this elaborated type specifier.
+ TagKind Tag;
+
+ /// The underlying type.
+ QualType UnderlyingType;
+
+ explicit ElaboratedType(QualType Ty, TagKind Tag, QualType Canon)
+ : Type(Elaborated, Canon, Canon->isDependentType()),
+ Tag(Tag), UnderlyingType(Ty) { }
+ friend class ASTContext; // ASTContext creates these.
+
+public:
+ TagKind getTagKind() const { return Tag; }
+ QualType getUnderlyingType() const { return UnderlyingType; }
+
+ /// \brief Remove a single level of sugar.
+ QualType desugar() const { return getUnderlyingType(); }
+
+ /// \brief Returns whether this type directly provides sugar.
+ bool isSugared() const { return true; }
+
+ static const char *getNameForTagKind(TagKind Kind) {
+ switch (Kind) {
+ 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";
+ }
+ }
+
+ virtual void getAsStringInternal(std::string &InnerString,
+ const PrintingPolicy &Policy) const;
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getUnderlyingType(), getTagKind());
+ }
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType T, TagKind Tag) {
+ ID.AddPointer(T.getAsOpaquePtr());
+ ID.AddInteger(Tag);
+ }
+
+ static bool classof(const ElaboratedType*) { return true; }
+ static bool classof(const Type *T) { return T->getTypeClass() == Elaborated; }
+};
+
class TemplateTypeParmType : public Type, public llvm::FoldingSetNode {
unsigned Depth : 15;
unsigned Index : 16;
unsigned ParameterPack : 1;
IdentifierInfo *Name;
- TemplateTypeParmType(unsigned D, unsigned I, bool PP, IdentifierInfo *N,
- QualType Canon)
+ TemplateTypeParmType(unsigned D, unsigned I, bool PP, IdentifierInfo *N,
+ QualType Canon)
: Type(TemplateTypeParm, Canon, /*Dependent=*/true),
Depth(D), Index(I), ParameterPack(PP), Name(N) { }
- TemplateTypeParmType(unsigned D, unsigned I, bool PP)
+ TemplateTypeParmType(unsigned D, unsigned I, bool PP)
: Type(TemplateTypeParm, QualType(this, 0), /*Dependent=*/true),
Depth(D), Index(I), ParameterPack(PP), Name(0) { }
@@ -1487,15 +2193,19 @@ public:
unsigned getIndex() const { return Index; }
bool isParameterPack() const { return ParameterPack; }
IdentifierInfo *getName() const { return Name; }
-
- virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
+
+ virtual void getAsStringInternal(std::string &InnerString,
+ const PrintingPolicy &Policy) const;
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
void Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, Depth, Index, ParameterPack, Name);
}
- static void Profile(llvm::FoldingSetNodeID &ID, unsigned Depth,
- unsigned Index, bool ParameterPack,
+ static void Profile(llvm::FoldingSetNodeID &ID, unsigned Depth,
+ unsigned Index, bool ParameterPack,
IdentifierInfo *Name) {
ID.AddInteger(Depth);
ID.AddInteger(Index);
@@ -1503,8 +2213,8 @@ public:
ID.AddPointer(Name);
}
- static bool classof(const Type *T) {
- return T->getTypeClass() == TemplateTypeParm;
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == TemplateTypeParm;
}
static bool classof(const TemplateTypeParmType *T) { return true; }
};
@@ -1518,23 +2228,27 @@ public:
/// 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
+/// 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
+class TemplateSpecializationType
: public Type, public llvm::FoldingSetNode {
- /// \brief The name of the template being specialized.
+ // FIXME: Currently needed for profiling expressions; can we avoid this?
+ ASTContext &Context;
+
+ /// \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,
+ TemplateSpecializationType(ASTContext &Context,
+ TemplateName T,
const TemplateArgument *Args,
unsigned NumArgs, QualType Canon);
@@ -1546,7 +2260,7 @@ public:
/// \brief Determine whether any of the given template arguments are
/// dependent.
static bool anyDependentTemplateArguments(const TemplateArgument *Args,
- unsigned NumArgs);
+ unsigned NumArgs);
/// \brief Print a template argument list, including the '<' and '>'
/// enclosing the template arguments.
@@ -1563,7 +2277,7 @@ public:
TemplateName getTemplateName() const { return Template; }
/// \brief Retrieve the template arguments.
- const TemplateArgument *getArgs() const {
+ const TemplateArgument *getArgs() const {
return reinterpret_cast<const TemplateArgument *>(this + 1);
}
@@ -1574,17 +2288,22 @@ public:
/// \precondition @c isArgType(Arg)
const TemplateArgument &getArg(unsigned Idx) const;
- virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
+ virtual void getAsStringInternal(std::string &InnerString,
+ const PrintingPolicy &Policy) const;
+
+ bool isSugared() const { return !isDependentType(); }
+ QualType desugar() const { return getCanonicalTypeInternal(); }
void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, Template, getArgs(), NumArgs);
+ Profile(ID, Template, getArgs(), NumArgs, Context);
}
static void Profile(llvm::FoldingSetNodeID &ID, TemplateName T,
- const TemplateArgument *Args, unsigned NumArgs);
+ const TemplateArgument *Args, unsigned NumArgs,
+ ASTContext &Context);
- static bool classof(const Type *T) {
- return T->getTypeClass() == TemplateSpecialization;
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == TemplateSpecialization;
}
static bool classof(const TemplateSpecializationType *T) { return true; }
};
@@ -1617,7 +2336,14 @@ public:
/// \brief Retrieve the type named by the qualified-id.
QualType getNamedType() const { return NamedType; }
- virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
+ /// \brief Remove a single level of sugar.
+ QualType desugar() const { return getNamedType(); }
+
+ /// \brief Returns whether this type directly provides sugar.
+ bool isSugared() const { return true; }
+
+ virtual void getAsStringInternal(std::string &InnerString,
+ const PrintingPolicy &Policy) const;
void Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, NNS, NamedType);
@@ -1629,8 +2355,8 @@ public:
NamedType.Profile(ID);
}
- static bool classof(const Type *T) {
- return T->getTypeClass() == QualifiedName;
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == QualifiedName;
}
static bool classof(const QualifiedNameType *T) { return true; }
};
@@ -1651,7 +2377,7 @@ class TypenameType : public Type, public llvm::FoldingSetNode {
/// \brief The nested name specifier containing the qualifier.
NestedNameSpecifier *NNS;
- typedef llvm::PointerUnion<const IdentifierInfo *,
+ typedef llvm::PointerUnion<const IdentifierInfo *,
const TemplateSpecializationType *> NameType;
/// \brief The type that this typename specifier refers to.
@@ -1659,15 +2385,15 @@ class TypenameType : public Type, public llvm::FoldingSetNode {
TypenameType(NestedNameSpecifier *NNS, const IdentifierInfo *Name,
QualType CanonType)
- : Type(Typename, CanonType, true), NNS(NNS), Name(Name) {
- assert(NNS->isDependent() &&
+ : 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() &&
+ : Type(Typename, CanonType, true), NNS(NNS), Name(Ty) {
+ assert(NNS->isDependent() &&
"TypenameType requires a dependent nested-name-specifier");
}
@@ -1683,8 +2409,8 @@ public:
/// 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 *>();
+ const IdentifierInfo *getIdentifier() const {
+ return Name.dyn_cast<const IdentifierInfo *>();
}
/// \brief Retrieve the type named by the typename specifier as a
@@ -1693,7 +2419,11 @@ public:
return Name.dyn_cast<const TemplateSpecializationType *>();
}
- virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
+ virtual void getAsStringInternal(std::string &InnerString,
+ const PrintingPolicy &Policy) const;
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
void Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, NNS, Name);
@@ -1705,35 +2435,112 @@ public:
ID.AddPointer(Name.getOpaqueValue());
}
- static bool classof(const Type *T) {
- return T->getTypeClass() == Typename;
+ 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>".
+class ObjCInterfaceType : public Type, public llvm::FoldingSetNode {
+ ObjCInterfaceDecl *Decl;
+
+ // 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;
+
+ ObjCInterfaceType(ObjCInterfaceDecl *D,
+ ObjCProtocolDecl **Protos, unsigned NumP) :
+ Type(ObjCInterface, QualType(), /*Dependent=*/false),
+ Decl(D), Protocols(Protos, Protos+NumP) { }
+ friend class ASTContext; // ASTContext creates these.
+public:
+ ObjCInterfaceDecl *getDecl() const { return Decl; }
+
+ /// getNumProtocols - Return the number of qualifying protocols in this
+ /// interface type, or 0 if there are none.
+ unsigned getNumProtocols() const { return Protocols.size(); }
+
+ /// qual_iterator and friends: this provides access to the (potentially empty)
+ /// list of protocols qualifying this interface.
+ 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(); }
+ bool qual_empty() const { return Protocols.size() == 0; }
+
+ virtual void getAsStringInternal(std::string &InnerString,
+ const PrintingPolicy &Policy) const;
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ 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() == ObjCInterface;
+ }
+ static bool classof(const ObjCInterfaceType *) { return true; }
+};
+
/// ObjCObjectPointerType - Used to represent 'id', 'Interface *', 'id <p>',
/// and 'Interface <p> *'.
///
/// Duplicate protocols are removed and protocol list is canonicalized to be in
/// alphabetical order.
class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode {
- ObjCInterfaceDecl *Decl;
+ QualType PointeeType; // A builtin or interface type.
+
// List of protocols for this protocol conforming object type
// List is sorted on protocol name. No protocol is entered more than once.
llvm::SmallVector<ObjCProtocolDecl*, 8> Protocols;
- ObjCObjectPointerType(ObjCInterfaceDecl *D,
- ObjCProtocolDecl **Protos, unsigned NumP) :
+ ObjCObjectPointerType(QualType T, ObjCProtocolDecl **Protos, unsigned NumP) :
Type(ObjCObjectPointer, QualType(), /*Dependent=*/false),
- Decl(D), Protocols(Protos, Protos+NumP) { }
+ PointeeType(T), Protocols(Protos, Protos+NumP) { }
friend class ASTContext; // ASTContext creates these.
public:
- ObjCInterfaceDecl *getDecl() const { return Decl; }
-
+ // Get the pointee type. Pointee will either be:
+ // - a built-in type (for 'id' and 'Class').
+ // - an interface type (for user-defined types).
+ // - a TypedefType whose canonical type is an interface (as in 'T' below).
+ // For example: typedef NSObject T; T *var;
+ QualType getPointeeType() const { return PointeeType; }
+
+ const ObjCInterfaceType *getInterfaceType() const {
+ return PointeeType->getAs<ObjCInterfaceType>();
+ }
+ /// getInterfaceDecl - returns an interface decl for user-defined types.
+ ObjCInterfaceDecl *getInterfaceDecl() const {
+ return getInterfaceType() ? getInterfaceType()->getDecl() : 0;
+ }
+ /// isObjCIdType - true for "id".
+ bool isObjCIdType() const {
+ return getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCId) &&
+ !Protocols.size();
+ }
+ /// isObjCClassType - true for "Class".
+ bool isObjCClassType() const {
+ return getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCClass) &&
+ !Protocols.size();
+ }
/// isObjCQualifiedIdType - true for "id <p>".
- bool isObjCQualifiedIdType() const { return Decl == 0 && Protocols.size(); }
-
+ bool isObjCQualifiedIdType() const {
+ return getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCId) &&
+ Protocols.size();
+ }
+ /// isObjCQualifiedClassType - true for "Class <p>".
+ bool isObjCQualifiedClassType() const {
+ return getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCClass) &&
+ Protocols.size();
+ }
/// qual_iterator and friends: this provides access to the (potentially empty)
/// list of protocols qualifying this interface.
typedef llvm::SmallVector<ObjCProtocolDecl*, 8>::const_iterator qual_iterator;
@@ -1746,156 +2553,198 @@ public:
/// interface type, or 0 if there are none.
unsigned getNumProtocols() const { return Protocols.size(); }
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
void Profile(llvm::FoldingSetNodeID &ID);
- static void Profile(llvm::FoldingSetNodeID &ID,
- const ObjCInterfaceDecl *Decl,
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType T,
ObjCProtocolDecl **protocols, unsigned NumProtocols);
- virtual void getAsStringInternal(std::string &InnerString,
+ virtual void getAsStringInternal(std::string &InnerString,
const PrintingPolicy &Policy) const;
- static bool classof(const Type *T) {
- return T->getTypeClass() == ObjCObjectPointer;
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == ObjCObjectPointer;
}
static bool classof(const ObjCObjectPointerType *) { 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>.
+/// \brief An ObjC Protocol list that qualifies a type.
///
-/// 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.
+/// This is used only for keeping detailed type source information, it should
+/// not participate in the semantics of the type system.
+/// The protocol list is not canonicalized.
+class ObjCProtocolListType : public Type, public llvm::FoldingSetNode {
+ QualType BaseType;
+
+ // List of protocols for this protocol conforming object type.
llvm::SmallVector<ObjCProtocolDecl*, 4> Protocols;
- ObjCQualifiedInterfaceType(ObjCInterfaceDecl *D,
- ObjCProtocolDecl **Protos, unsigned NumP) :
- ObjCInterfaceType(ObjCQualifiedInterface, D),
- Protocols(Protos, Protos+NumP) { }
+ ObjCProtocolListType(QualType T, ObjCProtocolDecl **Protos, unsigned NumP) :
+ Type(ObjCProtocolList, QualType(), /*Dependent=*/false),
+ BaseType(T), Protocols(Protos, Protos+NumP) { }
friend class ASTContext; // ASTContext creates these.
+
public:
-
- unsigned getNumProtocols() const {
- return Protocols.size();
- }
+ QualType getBaseType() const { return BaseType; }
+
+ /// \brief Provides access to the list of protocols qualifying the base type.
+ typedef llvm::SmallVector<ObjCProtocolDecl*, 4>::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;
-
+ bool qual_empty() const { return Protocols.size() == 0; }
+
+ /// \brief Return the number of qualifying protocols.
+ unsigned getNumProtocols() const { return Protocols.size(); }
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
void Profile(llvm::FoldingSetNodeID &ID);
- static void Profile(llvm::FoldingSetNodeID &ID,
- const ObjCInterfaceDecl *Decl,
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType T,
ObjCProtocolDecl **protocols, unsigned NumProtocols);
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == ObjCQualifiedInterface;
+ virtual void getAsStringInternal(std::string &InnerString,
+ const PrintingPolicy &Policy) const;
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == ObjCProtocolList;
}
- static bool classof(const ObjCQualifiedInterfaceType *) { return true; }
+ static bool classof(const ObjCProtocolListType *) { return true; }
};
-
-inline ObjCInterfaceType::qual_iterator ObjCInterfaceType::qual_begin() const {
- if (const ObjCQualifiedInterfaceType *QIT =
- dyn_cast<ObjCQualifiedInterfaceType>(this))
- return QIT->qual_begin();
- return 0;
+
+/// A qualifier set is used to build a set of qualifiers.
+class QualifierCollector : public Qualifiers {
+ ASTContext *Context;
+
+public:
+ QualifierCollector(Qualifiers Qs = Qualifiers())
+ : Qualifiers(Qs), Context(0) {}
+ QualifierCollector(ASTContext &Context, Qualifiers Qs = Qualifiers())
+ : Qualifiers(Qs), Context(&Context) {}
+
+ void setContext(ASTContext &C) { Context = &C; }
+
+ /// Collect any qualifiers on the given type and return an
+ /// unqualified type.
+ const Type *strip(QualType QT) {
+ addFastQualifiers(QT.getFastQualifiers());
+ if (QT.hasNonFastQualifiers()) {
+ const ExtQuals *EQ = QT.getExtQualsUnsafe();
+ Context = &EQ->getContext();
+ addQualifiers(EQ->getQualifiers());
+ return EQ->getBaseType();
+ }
+ return QT.getTypePtrUnsafe();
+ }
+
+ /// Apply the collected qualifiers to the given type.
+ QualType apply(QualType QT) const;
+
+ /// Apply the collected qualifiers to the given type.
+ QualType apply(const Type* T) const;
+
+};
+
+
+// Inline function definitions.
+
+inline void QualType::removeConst() {
+ removeFastQualifiers(Qualifiers::Const);
}
-inline ObjCInterfaceType::qual_iterator ObjCInterfaceType::qual_end() const {
- if (const ObjCQualifiedInterfaceType *QIT =
- dyn_cast<ObjCQualifiedInterfaceType>(this))
- return QIT->qual_end();
- return 0;
+
+inline void QualType::removeRestrict() {
+ removeFastQualifiers(Qualifiers::Restrict);
}
-/// 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;
+inline void QualType::removeVolatile() {
+ QualifierCollector Qc;
+ const Type *Ty = Qc.strip(*this);
+ if (Qc.hasVolatile()) {
+ Qc.removeVolatile();
+ *this = Qc.apply(Ty);
+ }
}
-// Inline function definitions.
+inline void QualType::removeCVRQualifiers(unsigned Mask) {
+ assert(!(Mask & ~Qualifiers::CVRMask) && "mask has non-CVR bits");
+
+ // Fast path: we don't need to touch the slow qualifiers.
+ if (!(Mask & ~Qualifiers::FastMask)) {
+ removeFastQualifiers(Mask);
+ return;
+ }
-/// 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);
+ QualifierCollector Qc;
+ const Type *Ty = Qc.strip(*this);
+ Qc.removeCVRQualifiers(Mask);
+ *this = Qc.apply(Ty);
}
/// getAddressSpace - Return the address space of this type.
inline unsigned QualType::getAddressSpace() const {
+ if (hasNonFastQualifiers()) {
+ const ExtQuals *EQ = getExtQualsUnsafe();
+ if (EQ->hasAddressSpace())
+ return EQ->getAddressSpace();
+ }
+
QualType CT = getTypePtr()->getCanonicalTypeInternal();
+ if (CT.hasNonFastQualifiers()) {
+ const ExtQuals *EQ = CT.getExtQualsUnsafe();
+ if (EQ->hasAddressSpace())
+ return EQ->getAddressSpace();
+ }
+
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 {
+inline Qualifiers::GC QualType::getObjCGCAttr() const {
+ if (hasNonFastQualifiers()) {
+ const ExtQuals *EQ = getExtQualsUnsafe();
+ if (EQ->hasObjCGCAttr())
+ return EQ->getObjCGCAttr();
+ }
+
QualType CT = getTypePtr()->getCanonicalTypeInternal();
+ if (CT.hasNonFastQualifiers()) {
+ const ExtQuals *EQ = CT.getExtQualsUnsafe();
+ if (EQ->hasObjCGCAttr())
+ return EQ->getObjCGCAttr();
+ }
+
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;
+ if (const ObjCObjectPointerType *PT = CT->getAs<ObjCObjectPointerType>())
+ return PT->getPointeeType().getObjCGCAttr();
+ // We most look at all pointer types, not just pointer to interface types.
+ if (const PointerType *PT = CT->getAs<PointerType>())
+ return PT->getPointeeType().getObjCGCAttr();
+ return Qualifiers::GCNone;
+}
+
+ /// getNoReturnAttr - Returns true if the type has the noreturn attribute,
+ /// false otherwise.
+inline bool QualType::getNoReturnAttr() const {
+ QualType CT = getTypePtr()->getCanonicalTypeInternal();
+ if (const PointerType *PT = getTypePtr()->getAs<PointerType>()) {
+ if (const FunctionType *FT = PT->getPointeeType()->getAs<FunctionType>())
+ return FT->getNoReturnAttr();
+ } else if (const FunctionType *FT = getTypePtr()->getAs<FunctionType>())
+ return FT->getNoReturnAttr();
+
+ return false;
}
-
+
/// 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 {
+ // FIXME: work on arbitrary qualifiers
unsigned MyQuals = this->getCVRQualifiers();
unsigned OtherQuals = Other.getCVRQualifiers();
if (getAddressSpace() != Other.getAddressSpace())
@@ -1908,6 +2757,7 @@ inline bool QualType::isMoreQualifiedThan(QualType Other) const {
/// int" is at least as qualified as "const int", "volatile int",
/// "int", and "const volatile int".
inline bool QualType::isAtLeastAsQualifiedAs(QualType Other) const {
+ // FIXME: work on arbitrary qualifiers
unsigned MyQuals = this->getCVRQualifiers();
unsigned OtherQuals = Other.getCVRQualifiers();
if (getAddressSpace() != Other.getAddressSpace())
@@ -1925,31 +2775,31 @@ inline bool QualType::isAtLeastAsQualifiedAs(QualType Other) const {
/// 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())
+ if (const ReferenceType *RefType = (*this)->getAs<ReferenceType>())
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();
+ if (const PointerType *PT = getAs<PointerType>())
+ return PT->getPointeeType()->getAs<ObjCInterfaceType>();
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());
+ return isa<PointerType>(CanonicalType.getUnqualifiedType());
+}
+inline bool Type::isAnyPointerType() const {
+ return isPointerType() || isObjCObjectPointerType();
}
inline bool Type::isBlockPointerType() const {
- return isa<BlockPointerType>(CanonicalType.getUnqualifiedType());
+ return isa<BlockPointerType>(CanonicalType.getUnqualifiedType());
}
inline bool Type::isReferenceType() const {
return isa<ReferenceType>(CanonicalType.getUnqualifiedType());
@@ -1961,7 +2811,7 @@ inline bool Type::isRValueReferenceType() const {
return isa<RValueReferenceType>(CanonicalType.getUnqualifiedType());
}
inline bool Type::isFunctionPointerType() const {
- if (const PointerType* T = getAsPointerType())
+ if (const PointerType* T = getAs<PointerType>())
return T->getPointeeType()->isFunctionType();
else
return false;
@@ -1970,7 +2820,7 @@ inline bool Type::isMemberPointerType() const {
return isa<MemberPointerType>(CanonicalType.getUnqualifiedType());
}
inline bool Type::isMemberFunctionPointerType() const {
- if (const MemberPointerType* T = getAsMemberPointerType())
+ if (const MemberPointerType* T = getAs<MemberPointerType>())
return T->getPointeeType()->isFunctionType();
else
return false;
@@ -2008,21 +2858,35 @@ inline bool Type::isObjCObjectPointerType() const {
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 {
- if (const ObjCObjectPointerType *OPT = getAsObjCObjectPointerType()) {
+ if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>())
return OPT->isObjCQualifiedIdType();
- }
return false;
}
+inline bool Type::isObjCQualifiedClassType() const {
+ if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>())
+ return OPT->isObjCQualifiedClassType();
+ return false;
+}
+inline bool Type::isObjCIdType() const {
+ if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>())
+ return OPT->isObjCIdType();
+ return false;
+}
+inline bool Type::isObjCClassType() const {
+ if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>())
+ return OPT->isObjCClassType();
+ return false;
+}
+inline bool Type::isObjCBuiltinType() const {
+ return isObjCIdType() || isObjCClassType();
+}
inline bool Type::isTemplateTypeParmType() const {
return isa<TemplateTypeParmType>(CanonicalType.getUnqualifiedType());
}
inline bool Type::isSpecificBuiltinType(unsigned K) const {
- if (const BuiltinType *BT = getAsBuiltinType())
+ if (const BuiltinType *BT = getAs<BuiltinType>())
if (BT->getKind() == (BuiltinType::Kind) K)
return true;
return false;
@@ -2036,12 +2900,12 @@ inline bool Type::isOverloadableType() const {
inline bool Type::hasPointerRepresentation() const {
return (isPointerType() || isReferenceType() || isBlockPointerType() ||
- isObjCInterfaceType() || isObjCQualifiedIdType() ||
+ isObjCInterfaceType() || isObjCObjectPointerType() ||
isObjCQualifiedInterfaceType() || isNullPtrType());
}
inline bool Type::hasObjCPointerRepresentation() const {
- return (isObjCInterfaceType() || isObjCQualifiedIdType() ||
+ return (isObjCInterfaceType() || isObjCObjectPointerType() ||
isObjCQualifiedInterfaceType());
}
@@ -2054,6 +2918,21 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
return DB;
}
+/// Member-template getAs<specific type>'.
+template <typename T> const T *Type::getAs() const {
+ // If this is directly a T type, return it.
+ if (const T *Ty = dyn_cast<T>(this))
+ return Ty;
+
+ // If the canonical form of this type isn't the right kind, reject it.
+ if (!isa<T>(CanonicalType))
+ return 0;
+
+ // If this is a typedef for the type, strip the typedef off without
+ // losing all typedef information.
+ return cast<T>(getUnqualifiedDesugaredType());
+}
+
} // end namespace clang
#endif
diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h
new file mode 100644
index 0000000..a618437
--- /dev/null
+++ b/include/clang/AST/TypeLoc.h
@@ -0,0 +1,538 @@
+//===--- TypeLoc.h - Type Source Info Wrapper -------------------*- 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 TypeLoc interface and subclasses.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_TYPELOC_H
+#define LLVM_CLANG_AST_TYPELOC_H
+
+#include "clang/AST/Type.h"
+
+namespace clang {
+ class ParmVarDecl;
+ class TypeSpecLoc;
+ class DeclaratorInfo;
+
+/// \brief Base wrapper for a particular "section" of type source info.
+///
+/// A client should use the TypeLoc subclasses through cast/dyn_cast in order to
+/// get at the actual information.
+class TypeLoc {
+protected:
+ QualType Ty;
+ void *Data;
+
+public:
+ TypeLoc() : Data(0) { }
+ TypeLoc(QualType ty, void *opaqueData) : Ty(ty), Data(opaqueData) { }
+
+ bool isNull() const { return Ty.isNull(); }
+ operator bool() const { return !isNull(); }
+
+ /// \brief Returns the size of type source info data block for the given type.
+ static unsigned getFullDataSizeForType(QualType Ty);
+
+ /// \brief Get the type for which this source info wrapper provides
+ /// information.
+ QualType getSourceType() const { return Ty; }
+
+ /// \brief Get the pointer where source information is stored.
+ void *getOpaqueData() const { return Data; }
+
+ SourceRange getSourceRange() const;
+
+ /// \brief Find the TypeSpecLoc that is part of this TypeLoc.
+ TypeSpecLoc getTypeSpecLoc() const;
+
+ /// \brief Find the TypeSpecLoc that is part of this TypeLoc and return its
+ /// SourceRange.
+ SourceRange getTypeSpecRange() const;
+
+ /// \brief Returns the size of the type source info data block.
+ unsigned getFullDataSize() const;
+
+ /// \brief Get the next TypeLoc pointed by this TypeLoc, e.g for "int*" the
+ /// TypeLoc is a PointerLoc and next TypeLoc is for "int".
+ TypeLoc getNextTypeLoc() const;
+
+ friend bool operator==(const TypeLoc &LHS, const TypeLoc &RHS) {
+ return LHS.Ty == RHS.Ty && LHS.Data == RHS.Data;
+ }
+
+ friend bool operator!=(const TypeLoc &LHS, const TypeLoc &RHS) {
+ return !(LHS == RHS);
+ }
+
+ static bool classof(const TypeLoc *TL) { return true; }
+};
+
+/// \brief Base wrapper of type source info data for type-spec types.
+class TypeSpecLoc : public TypeLoc {
+public:
+ static bool classof(const TypeLoc *TL);
+ static bool classof(const TypeSpecLoc *TL) { return true; }
+};
+
+/// \brief Base wrapper of type source info data for types part of a declarator,
+/// excluding type-spec types.
+class DeclaratorLoc : public TypeLoc {
+public:
+ /// \brief Find the TypeSpecLoc that is part of this DeclaratorLoc.
+ TypeSpecLoc getTypeSpecLoc() const;
+
+ static bool classof(const TypeLoc *TL);
+ static bool classof(const DeclaratorLoc *TL) { return true; }
+};
+
+/// \brief The default wrapper for type-spec types that are not handled by
+/// another specific wrapper.
+class DefaultTypeSpecLoc : public TypeSpecLoc {
+ struct Info {
+ SourceLocation StartLoc;
+ };
+
+public:
+ SourceLocation getStartLoc() const {
+ return static_cast<Info*>(Data)->StartLoc;
+ }
+ void setStartLoc(SourceLocation Loc) {
+ static_cast<Info*>(Data)->StartLoc = Loc;
+ }
+ SourceRange getSourceRange() const {
+ return SourceRange(getStartLoc(), getStartLoc());
+ }
+
+ /// \brief Returns the size of the type source info data block that is
+ /// specific to this type.
+ unsigned getLocalDataSize() const { return sizeof(Info); }
+
+ /// \brief Returns the size of the type source info data block.
+ unsigned getFullDataSize() const { return getLocalDataSize(); }
+
+ static bool classof(const TypeLoc *TL);
+ static bool classof(const DefaultTypeSpecLoc *TL) { return true; }
+};
+
+/// \brief Wrapper for source info for typedefs.
+class TypedefLoc : public TypeSpecLoc {
+ struct Info {
+ SourceLocation NameLoc;
+ };
+
+public:
+ SourceLocation getNameLoc() const {
+ return static_cast<Info*>(Data)->NameLoc;
+ }
+ void setNameLoc(SourceLocation Loc) {
+ static_cast<Info*>(Data)->NameLoc = Loc;
+ }
+ SourceRange getSourceRange() const {
+ return SourceRange(getNameLoc(), getNameLoc());
+ }
+
+ TypedefDecl *getTypedefDecl() const {
+ return cast<TypedefType>(Ty)->getDecl();
+ }
+
+ /// \brief Returns the size of the type source info data block that is
+ /// specific to this type.
+ unsigned getLocalDataSize() const { return sizeof(Info); }
+
+ /// \brief Returns the size of the type source info data block.
+ unsigned getFullDataSize() const { return getLocalDataSize(); }
+
+ static bool classof(const TypeLoc *TL);
+ static bool classof(const TypedefLoc *TL) { return true; }
+};
+
+/// \brief Wrapper for source info for ObjC interfaces.
+class ObjCInterfaceLoc : public TypeSpecLoc {
+ struct Info {
+ SourceLocation NameLoc;
+ };
+
+public:
+ SourceLocation getNameLoc() const {
+ return static_cast<Info*>(Data)->NameLoc;
+ }
+ void setNameLoc(SourceLocation Loc) {
+ static_cast<Info*>(Data)->NameLoc = Loc;
+ }
+ SourceRange getSourceRange() const {
+ return SourceRange(getNameLoc(), getNameLoc());
+ }
+
+ ObjCInterfaceDecl *getIFaceDecl() const {
+ return cast<ObjCInterfaceType>(Ty)->getDecl();
+ }
+
+ /// \brief Returns the size of the type source info data block that is
+ /// specific to this type.
+ unsigned getLocalDataSize() const { return sizeof(Info); }
+
+ /// \brief Returns the size of the type source info data block.
+ unsigned getFullDataSize() const { return getLocalDataSize(); }
+
+ static bool classof(const TypeLoc *TL);
+ static bool classof(const TypedefLoc *TL) { return true; }
+};
+
+/// \brief Wrapper for source info for ObjC protocol lists.
+class ObjCProtocolListLoc : public TypeSpecLoc {
+ struct Info {
+ SourceLocation LAngleLoc, RAngleLoc;
+ };
+ // SourceLocations are stored after Info, one for each Protocol.
+ SourceLocation *getProtocolLocArray() const {
+ return reinterpret_cast<SourceLocation*>(static_cast<Info*>(Data) + 1);
+ }
+
+public:
+ SourceLocation getLAngleLoc() const {
+ return static_cast<Info*>(Data)->LAngleLoc;
+ }
+ void setLAngleLoc(SourceLocation Loc) {
+ static_cast<Info*>(Data)->LAngleLoc = Loc;
+ }
+
+ SourceLocation getRAngleLoc() const {
+ return static_cast<Info*>(Data)->RAngleLoc;
+ }
+ void setRAngleLoc(SourceLocation Loc) {
+ static_cast<Info*>(Data)->RAngleLoc = Loc;
+ }
+
+ unsigned getNumProtocols() const {
+ return cast<ObjCProtocolListType>(Ty)->getNumProtocols();
+ }
+
+ SourceLocation getProtocolLoc(unsigned i) const {
+ assert(i < getNumProtocols() && "Index is out of bounds!");
+ return getProtocolLocArray()[i];
+ }
+ void setProtocolLoc(unsigned i, SourceLocation Loc) {
+ assert(i < getNumProtocols() && "Index is out of bounds!");
+ getProtocolLocArray()[i] = Loc;
+ }
+
+ ObjCProtocolDecl *getProtocol(unsigned i) const {
+ assert(i < getNumProtocols() && "Index is out of bounds!");
+ return *(cast<ObjCProtocolListType>(Ty)->qual_begin() + i);
+ }
+
+ TypeLoc getBaseTypeLoc() const {
+ void *Next = static_cast<char*>(Data) + getLocalDataSize();
+ return TypeLoc(cast<ObjCProtocolListType>(Ty)->getBaseType(), Next);
+ }
+
+ SourceRange getSourceRange() const {
+ return SourceRange(getLAngleLoc(), getRAngleLoc());
+ }
+
+ /// \brief Returns the size of the type source info data block that is
+ /// specific to this type.
+ unsigned getLocalDataSize() const {
+ return sizeof(Info) + getNumProtocols() * sizeof(SourceLocation);
+ }
+
+ /// \brief Returns the size of the type source info data block.
+ unsigned getFullDataSize() const {
+ return getLocalDataSize() + getBaseTypeLoc().getFullDataSize();
+ }
+
+ static bool classof(const TypeLoc *TL);
+ static bool classof(const ObjCProtocolListLoc *TL) { return true; }
+};
+
+/// \brief Wrapper for source info for pointers.
+class PointerLoc : public DeclaratorLoc {
+ struct Info {
+ SourceLocation StarLoc;
+ };
+
+public:
+ SourceLocation getStarLoc() const {
+ return static_cast<Info*>(Data)->StarLoc;
+ }
+ void setStarLoc(SourceLocation Loc) {
+ static_cast<Info*>(Data)->StarLoc = Loc;
+ }
+
+ TypeLoc getPointeeLoc() const {
+ void *Next = static_cast<char*>(Data) + getLocalDataSize();
+ return TypeLoc(cast<PointerType>(Ty)->getPointeeType(), Next);
+ }
+
+ /// \brief Find the TypeSpecLoc that is part of this PointerLoc.
+ TypeSpecLoc getTypeSpecLoc() const {
+ return getPointeeLoc().getTypeSpecLoc();
+ }
+
+ SourceRange getSourceRange() const {
+ return SourceRange(getStarLoc(), getStarLoc());
+ }
+
+ /// \brief Returns the size of the type source info data block that is
+ /// specific to this type.
+ unsigned getLocalDataSize() const { return sizeof(Info); }
+
+ /// \brief Returns the size of the type source info data block.
+ unsigned getFullDataSize() const {
+ return getLocalDataSize() + getPointeeLoc().getFullDataSize();
+ }
+
+ static bool classof(const TypeLoc *TL);
+ static bool classof(const PointerLoc *TL) { return true; }
+};
+
+/// \brief Wrapper for source info for block pointers.
+class BlockPointerLoc : public DeclaratorLoc {
+ struct Info {
+ SourceLocation CaretLoc;
+ };
+
+public:
+ SourceLocation getCaretLoc() const {
+ return static_cast<Info*>(Data)->CaretLoc;
+ }
+ void setCaretLoc(SourceLocation Loc) {
+ static_cast<Info*>(Data)->CaretLoc = Loc;
+ }
+
+ TypeLoc getPointeeLoc() const {
+ void *Next = static_cast<char*>(Data) + getLocalDataSize();
+ return TypeLoc(cast<BlockPointerType>(Ty)->getPointeeType(), Next);
+ }
+
+ /// \brief Find the TypeSpecLoc that is part of this BlockPointerLoc.
+ TypeSpecLoc getTypeSpecLoc() const {
+ return getPointeeLoc().getTypeSpecLoc();
+ }
+
+ SourceRange getSourceRange() const {
+ return SourceRange(getCaretLoc(), getCaretLoc());
+ }
+
+ /// \brief Returns the size of the type source info data block that is
+ /// specific to this type.
+ unsigned getLocalDataSize() const { return sizeof(Info); }
+
+ /// \brief Returns the size of the type source info data block.
+ unsigned getFullDataSize() const {
+ return getLocalDataSize() + getPointeeLoc().getFullDataSize();
+ }
+
+ static bool classof(const TypeLoc *TL);
+ static bool classof(const BlockPointerLoc *TL) { return true; }
+};
+
+/// \brief Wrapper for source info for member pointers.
+class MemberPointerLoc : public DeclaratorLoc {
+ struct Info {
+ SourceLocation StarLoc;
+ };
+
+public:
+ SourceLocation getStarLoc() const {
+ return static_cast<Info*>(Data)->StarLoc;
+ }
+ void setStarLoc(SourceLocation Loc) {
+ static_cast<Info*>(Data)->StarLoc = Loc;
+ }
+
+ TypeLoc getPointeeLoc() const {
+ void *Next = static_cast<char*>(Data) + getLocalDataSize();
+ return TypeLoc(cast<MemberPointerType>(Ty)->getPointeeType(), Next);
+ }
+
+ /// \brief Find the TypeSpecLoc that is part of this MemberPointerLoc.
+ TypeSpecLoc getTypeSpecLoc() const {
+ return getPointeeLoc().getTypeSpecLoc();
+ }
+
+ SourceRange getSourceRange() const {
+ return SourceRange(getStarLoc(), getStarLoc());
+ }
+
+ /// \brief Returns the size of the type source info data block that is
+ /// specific to this type.
+ unsigned getLocalDataSize() const { return sizeof(Info); }
+
+ /// \brief Returns the size of the type source info data block.
+ unsigned getFullDataSize() const {
+ return getLocalDataSize() + getPointeeLoc().getFullDataSize();
+ }
+
+ static bool classof(const TypeLoc *TL);
+ static bool classof(const MemberPointerLoc *TL) { return true; }
+};
+
+/// \brief Wrapper for source info for references.
+class ReferenceLoc : public DeclaratorLoc {
+ struct Info {
+ SourceLocation AmpLoc;
+ };
+
+public:
+ SourceLocation getAmpLoc() const {
+ return static_cast<Info*>(Data)->AmpLoc;
+ }
+ void setAmpLoc(SourceLocation Loc) {
+ static_cast<Info*>(Data)->AmpLoc = Loc;
+ }
+
+ TypeLoc getPointeeLoc() const {
+ void *Next = static_cast<char*>(Data) + getLocalDataSize();
+ return TypeLoc(cast<ReferenceType>(Ty)->getPointeeType(), Next);
+ }
+
+ /// \brief Find the TypeSpecLoc that is part of this ReferenceLoc.
+ TypeSpecLoc getTypeSpecLoc() const {
+ return getPointeeLoc().getTypeSpecLoc();
+ }
+
+ SourceRange getSourceRange() const {
+ return SourceRange(getAmpLoc(), getAmpLoc());
+ }
+
+ /// \brief Returns the size of the type source info data block that is
+ /// specific to this type.
+ unsigned getLocalDataSize() const { return sizeof(Info); }
+
+ /// \brief Returns the size of the type source info data block.
+ unsigned getFullDataSize() const {
+ return getLocalDataSize() + getPointeeLoc().getFullDataSize();
+ }
+
+ static bool classof(const TypeLoc *TL);
+ static bool classof(const ReferenceLoc *TL) { return true; }
+};
+
+/// \brief Wrapper for source info for functions.
+class FunctionLoc : public DeclaratorLoc {
+ struct Info {
+ SourceLocation LParenLoc, RParenLoc;
+ };
+ // ParmVarDecls* are stored after Info, one for each argument.
+ ParmVarDecl **getParmArray() const {
+ return reinterpret_cast<ParmVarDecl**>(static_cast<Info*>(Data) + 1);
+ }
+
+public:
+ SourceLocation getLParenLoc() const {
+ return static_cast<Info*>(Data)->LParenLoc;
+ }
+ void setLParenLoc(SourceLocation Loc) {
+ static_cast<Info*>(Data)->LParenLoc = Loc;
+ }
+
+ SourceLocation getRParenLoc() const {
+ return static_cast<Info*>(Data)->RParenLoc;
+ }
+ void setRParenLoc(SourceLocation Loc) {
+ static_cast<Info*>(Data)->RParenLoc = Loc;
+ }
+
+ unsigned getNumArgs() const {
+ if (isa<FunctionNoProtoType>(Ty))
+ return 0;
+ return cast<FunctionProtoType>(Ty)->getNumArgs();
+ }
+ ParmVarDecl *getArg(unsigned i) const { return getParmArray()[i]; }
+ void setArg(unsigned i, ParmVarDecl *VD) { getParmArray()[i] = VD; }
+
+ TypeLoc getArgLoc(unsigned i) const;
+
+ TypeLoc getResultLoc() const {
+ void *Next = static_cast<char*>(Data) + getLocalDataSize();
+ return TypeLoc(cast<FunctionType>(Ty)->getResultType(), Next);
+ }
+
+ /// \brief Find the TypeSpecLoc that is part of this FunctionLoc.
+ TypeSpecLoc getTypeSpecLoc() const {
+ return getResultLoc().getTypeSpecLoc();
+ }
+ SourceRange getSourceRange() const {
+ return SourceRange(getLParenLoc(), getRParenLoc());
+ }
+
+ /// \brief Returns the size of the type source info data block that is
+ /// specific to this type.
+ unsigned getLocalDataSize() const {
+ return sizeof(Info) + getNumArgs() * sizeof(ParmVarDecl*);
+ }
+
+ /// \brief Returns the size of the type source info data block.
+ unsigned getFullDataSize() const {
+ return getLocalDataSize() + getResultLoc().getFullDataSize();
+ }
+
+ static bool classof(const TypeLoc *TL);
+ static bool classof(const FunctionLoc *TL) { return true; }
+};
+
+/// \brief Wrapper for source info for arrays.
+class ArrayLoc : public DeclaratorLoc {
+ struct Info {
+ SourceLocation LBracketLoc, RBracketLoc;
+ Expr *Size;
+ };
+public:
+ SourceLocation getLBracketLoc() const {
+ return static_cast<Info*>(Data)->LBracketLoc;
+ }
+ void setLBracketLoc(SourceLocation Loc) {
+ static_cast<Info*>(Data)->LBracketLoc = Loc;
+ }
+
+ SourceLocation getRBracketLoc() const {
+ return static_cast<Info*>(Data)->RBracketLoc;
+ }
+ void setRBracketLoc(SourceLocation Loc) {
+ static_cast<Info*>(Data)->RBracketLoc = Loc;
+ }
+
+ Expr *getSizeExpr() const {
+ return static_cast<Info*>(Data)->Size;
+ }
+ void setSizeExpr(Expr *Size) {
+ static_cast<Info*>(Data)->Size = Size;
+ }
+
+ TypeLoc getElementLoc() const {
+ void *Next = static_cast<char*>(Data) + getLocalDataSize();
+ return TypeLoc(cast<ArrayType>(Ty)->getElementType(), Next);
+ }
+
+ /// \brief Find the TypeSpecLoc that is part of this ArrayLoc.
+ TypeSpecLoc getTypeSpecLoc() const {
+ return getElementLoc().getTypeSpecLoc();
+ }
+ SourceRange getSourceRange() const {
+ return SourceRange(getLBracketLoc(), getRBracketLoc());
+ }
+
+ /// \brief Returns the size of the type source info data block that is
+ /// specific to this type.
+ unsigned getLocalDataSize() const { return sizeof(Info); }
+
+ /// \brief Returns the size of the type source info data block.
+ unsigned getFullDataSize() const {
+ return getLocalDataSize() + getElementLoc().getFullDataSize();
+ }
+
+ static bool classof(const TypeLoc *TL);
+ static bool classof(const ArrayLoc *TL) { return true; }
+};
+
+}
+
+#endif
diff --git a/include/clang/AST/TypeLocNodes.def b/include/clang/AST/TypeLocNodes.def
new file mode 100644
index 0000000..107ea85
--- /dev/null
+++ b/include/clang/AST/TypeLocNodes.def
@@ -0,0 +1,55 @@
+//===-- TypeLocNodes.def - Metadata about TypeLoc wrappers ------*- 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 TypeLoc info database. Each node is
+// enumerated by providing its name (e.g., "PointerLoc" or "ArrayLoc"),
+// base class (e.g., "TypeSpecLoc" or "DeclaratorLoc"), and the Type subclass
+// that the TypeLoc is associated with.
+//
+// TYPELOC(Class, Base, Type) - Description of the TypeLoc subclass.
+//
+// ABSTRACT_TYPELOC(Class) - Refers to TypeSpecLoc and DeclaratorLoc.
+//
+// TYPESPEC_TYPELOC(Class, Type) - A TypeLoc referring to a type-spec type.
+//
+// DECLARATOR_TYPELOC(Class, Type) - A TypeLoc referring to a type part of
+// a declarator, excluding type-spec types.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ABSTRACT_TYPELOC
+# define ABSTRACT_TYPELOC(Class) TYPELOC(Class, TypeLoc, Type)
+#endif
+
+#ifndef TYPESPEC_TYPELOC
+# define TYPESPEC_TYPELOC(Class, Type) TYPELOC(Class, TypeSpecLoc, Type)
+#endif
+
+#ifndef DECLARATOR_TYPELOC
+# define DECLARATOR_TYPELOC(Class, Type) TYPELOC(Class, DeclaratorLoc, Type)
+#endif
+
+TYPESPEC_TYPELOC(DefaultTypeSpecLoc, Type)
+TYPESPEC_TYPELOC(TypedefLoc, TypedefType)
+TYPESPEC_TYPELOC(ObjCInterfaceLoc, ObjCInterfaceType)
+TYPESPEC_TYPELOC(ObjCProtocolListLoc, ObjCProtocolListType)
+DECLARATOR_TYPELOC(PointerLoc, PointerType)
+DECLARATOR_TYPELOC(BlockPointerLoc, BlockPointerType)
+DECLARATOR_TYPELOC(MemberPointerLoc, MemberPointerType)
+DECLARATOR_TYPELOC(ReferenceLoc, ReferenceType)
+DECLARATOR_TYPELOC(FunctionLoc, FunctionType)
+DECLARATOR_TYPELOC(ArrayLoc, ArrayType)
+ABSTRACT_TYPELOC(DeclaratorLoc)
+ABSTRACT_TYPELOC(TypeSpecLoc)
+
+
+#undef DECLARATOR_TYPELOC
+#undef TYPESPEC_TYPELOC
+#undef ABSTRACT_TYPELOC
+#undef TYPELOC
diff --git a/include/clang/AST/TypeLocVisitor.h b/include/clang/AST/TypeLocVisitor.h
new file mode 100644
index 0000000..df386ca
--- /dev/null
+++ b/include/clang/AST/TypeLocVisitor.h
@@ -0,0 +1,58 @@
+//===--- TypeLocVisitor.h - Visitor for TypeLoc 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 TypeLocVisitor interface.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_AST_TYPELOCVISITOR_H
+#define LLVM_CLANG_AST_TYPELOCVISITOR_H
+
+#include "clang/AST/TypeLoc.h"
+#include "clang/AST/TypeVisitor.h"
+
+namespace clang {
+
+#define DISPATCH(CLASS) \
+ return static_cast<ImplClass*>(this)->Visit ## CLASS(cast<CLASS>(TyLoc))
+
+template<typename ImplClass, typename RetTy=void>
+class TypeLocVisitor {
+ class TypeDispatch : public TypeVisitor<TypeDispatch, RetTy> {
+ ImplClass *Impl;
+ TypeLoc TyLoc;
+
+ public:
+ TypeDispatch(ImplClass *impl, TypeLoc &tyLoc) : Impl(impl), TyLoc(tyLoc) { }
+#define ABSTRACT_TYPELOC(CLASS)
+#define TYPELOC(CLASS, PARENT, TYPE) \
+ RetTy Visit##TYPE(TYPE *) { \
+ return Impl->Visit##CLASS(reinterpret_cast<CLASS&>(TyLoc)); \
+ }
+#include "clang/AST/TypeLocNodes.def"
+ };
+
+public:
+ RetTy Visit(TypeLoc TyLoc) {
+ TypeDispatch TD(static_cast<ImplClass*>(this), TyLoc);
+ return TD.Visit(TyLoc.getSourceType().getTypePtr());
+ }
+
+#define TYPELOC(CLASS, PARENT, TYPE) RetTy Visit##CLASS(CLASS TyLoc) { \
+ DISPATCH(PARENT); \
+}
+#include "clang/AST/TypeLocNodes.def"
+
+ RetTy VisitTypeLoc(TypeLoc TyLoc) { return RetTy(); }
+};
+
+#undef DISPATCH
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_AST_TYPELOCVISITOR_H
diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def
index 64a09d8..6c6bd20 100644
--- a/include/clang/AST/TypeNodes.def
+++ b/include/clang/AST/TypeNodes.def
@@ -31,6 +31,12 @@
// type that is always dependent. Clients that do not need to deal
// with uninstantiated C++ templates can ignore these types.
//
+// There is a fifth macro, independent of the others. Most clients
+// will not need to use it.
+//
+// LEAF_TYPE(Class) - A type that never has inner types. Clients
+// which can operate on such types more efficiently may wish to do so.
+//
//===----------------------------------------------------------------------===//
#ifndef ABSTRACT_TYPE
@@ -45,7 +51,6 @@
# define DEPENDENT_TYPE(Class, Base) TYPE(Class, Base)
#endif
-TYPE(ExtQual, Type)
TYPE(Builtin, Type)
TYPE(FixedWidthInt, Type)
TYPE(Complex, Type)
@@ -57,6 +62,8 @@ TYPE(RValueReference, ReferenceType)
TYPE(MemberPointer, Type)
ABSTRACT_TYPE(Array, Type)
TYPE(ConstantArray, ArrayType)
+NON_CANONICAL_TYPE(ConstantArrayWithExpr, ConstantArrayType)
+NON_CANONICAL_TYPE(ConstantArrayWithoutExpr, ConstantArrayType)
TYPE(IncompleteArray, ArrayType)
TYPE(VariableArray, ArrayType)
DEPENDENT_TYPE(DependentSizedArray, ArrayType)
@@ -73,13 +80,25 @@ NON_CANONICAL_TYPE(Decltype, Type)
ABSTRACT_TYPE(Tag, Type)
TYPE(Record, TagType)
TYPE(Enum, TagType)
+NON_CANONICAL_TYPE(Elaborated, Type)
DEPENDENT_TYPE(TemplateTypeParm, Type)
TYPE(TemplateSpecialization, Type)
NON_CANONICAL_TYPE(QualifiedName, Type)
DEPENDENT_TYPE(Typename, Type)
TYPE(ObjCInterface, Type)
TYPE(ObjCObjectPointer, Type)
-TYPE(ObjCQualifiedInterface, ObjCInterfaceType)
+NON_CANONICAL_TYPE(ObjCProtocolList, Type)
+
+// These types are always leaves in the type hierarchy.
+#ifdef LEAF_TYPE
+LEAF_TYPE(Enum)
+LEAF_TYPE(Builtin)
+LEAF_TYPE(FixedWidthInt)
+LEAF_TYPE(ObjCInterface)
+LEAF_TYPE(ObjCObjectPointer)
+LEAF_TYPE(TemplateTypeParm)
+#undef LEAF_TYPE
+#endif
#undef DEPENDENT_TYPE
#undef NON_CANONICAL_TYPE
diff --git a/include/clang/AST/TypeOrdering.h b/include/clang/AST/TypeOrdering.h
index 4f60273..652f4f7 100644
--- a/include/clang/AST/TypeOrdering.h
+++ b/include/clang/AST/TypeOrdering.h
@@ -37,7 +37,7 @@ namespace llvm {
template<> struct DenseMapInfo<clang::QualType> {
static inline clang::QualType getEmptyKey() { return clang::QualType(); }
- static inline clang::QualType getTombstoneKey() {
+ static inline clang::QualType getTombstoneKey() {
using clang::QualType;
return QualType::getFromOpaquePtr(reinterpret_cast<clang::Type *>(-1));
}
@@ -51,11 +51,11 @@ namespace llvm {
return LHS == RHS;
}
- static bool isPod() {
+ 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;
+ return true;
}
};
}
diff --git a/include/clang/AST/TypeVisitor.h b/include/clang/AST/TypeVisitor.h
index a02e39b..19f7f42 100644
--- a/include/clang/AST/TypeVisitor.h
+++ b/include/clang/AST/TypeVisitor.h
@@ -17,10 +17,10 @@
#include "clang/AST/Type.h"
namespace clang {
-
+
#define DISPATCH(CLASS) \
return static_cast<ImplClass*>(this)->Visit ## CLASS(static_cast<CLASS*>(T))
-
+
template<typename ImplClass, typename RetTy=void>
class TypeVisitor {
public:
@@ -28,15 +28,17 @@ public:
// Top switch stmt: dispatch to VisitFooStmt for each FooStmt.
switch (T->getTypeClass()) {
default: assert(0 && "Unknown type class!");
-#define ABSTRACT_TYPE(CLASS, PARENT)
+#define ABSTRACT_TYPE(CLASS, PARENT)
#define TYPE(CLASS, PARENT) case Type::CLASS: DISPATCH(CLASS##Type);
#include "clang/AST/TypeNodes.def"
}
}
-
+
// If the implementation chooses not to implement a certain visit method, fall
// back on superclass.
-#define TYPE(CLASS, PARENT) RetTy Visit##CLASS##Type(CLASS##Type *T) { DISPATCH(PARENT); }
+#define TYPE(CLASS, PARENT) RetTy Visit##CLASS##Type(CLASS##Type *T) { \
+ DISPATCH(PARENT); \
+}
#include "clang/AST/TypeNodes.def"
// Base case, ignore it. :)
diff --git a/include/clang/Analysis/Analyses/LiveVariables.h b/include/clang/Analysis/Analyses/LiveVariables.h
index b41cd68..17f772d 100644
--- a/include/clang/Analysis/Analyses/LiveVariables.h
+++ b/include/clang/Analysis/Analyses/LiveVariables.h
@@ -23,7 +23,7 @@ namespace clang {
class Stmt;
class DeclRefExpr;
class SourceManager;
-
+
struct LiveVariables_ValueTypes {
struct ObserverTy;
@@ -35,77 +35,77 @@ struct LiveVariables_ValueTypes {
// (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,
+ 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.
+ /// 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
diff --git a/include/clang/Analysis/Analyses/UninitializedValues.h b/include/clang/Analysis/Analyses/UninitializedValues.h
index 7a9da03..8a967c3 100644
--- a/include/clang/Analysis/Analyses/UninitializedValues.h
+++ b/include/clang/Analysis/Analyses/UninitializedValues.h
@@ -24,7 +24,7 @@ namespace clang {
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.
@@ -32,39 +32,39 @@ class UninitializedValues_ValueTypes {
public:
struct ObserverTy;
-
- struct AnalysisDataTy : public StmtDeclBitVector_Types::AnalysisDataTy {
+
+ 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,
+ 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> {
+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);
diff --git a/include/clang/Analysis/AnalysisDiagnostic.h b/include/clang/Analysis/AnalysisDiagnostic.h
index 3ee7335..114ae74 100644
--- a/include/clang/Analysis/AnalysisDiagnostic.h
+++ b/include/clang/Analysis/AnalysisDiagnostic.h
@@ -13,7 +13,7 @@
#include "clang/Basic/Diagnostic.h"
namespace clang {
- namespace diag {
+ namespace diag {
enum {
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE) ENUM,
#define ANALYSISSTART
diff --git a/include/clang/Analysis/CFG.h b/include/clang/Analysis/CFG.h
new file mode 100644
index 0000000..e6f4cf9
--- /dev/null
+++ b/include/clang/Analysis/CFG.h
@@ -0,0 +1,451 @@
+//===--- 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 "clang/Analysis/Support/BumpVector.h"
+#include <cassert>
+
+namespace llvm {
+ class raw_ostream;
+}
+namespace clang {
+ class Stmt;
+ class Expr;
+ class CFG;
+ class PrinterHelper;
+ class LangOptions;
+ class ASTContext;
+
+/// 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 {
+ class StatementList {
+ typedef BumpVector<Stmt*> ImplTy;
+ ImplTy Impl;
+ public:
+ StatementList(BumpVectorContext &C) : Impl(C, 4) {}
+
+ typedef std::reverse_iterator<ImplTy::iterator> iterator;
+ typedef std::reverse_iterator<ImplTy::const_iterator> const_iterator;
+ typedef ImplTy::iterator reverse_iterator;
+ typedef ImplTy::const_iterator const_reverse_iterator;
+
+ void push_back(Stmt *s, BumpVectorContext &C) { Impl.push_back(s, C); }
+ Stmt *front() const { return Impl.back(); }
+ Stmt *back() const { return Impl.front(); }
+
+ iterator begin() { return Impl.rbegin(); }
+ iterator end() { return Impl.rend(); }
+ const_iterator begin() const { return Impl.rbegin(); }
+ const_iterator end() const { return Impl.rend(); }
+ reverse_iterator rbegin() { return Impl.begin(); }
+ reverse_iterator rend() { return Impl.end(); }
+ const_reverse_iterator rbegin() const { return Impl.begin(); }
+ const_reverse_iterator rend() const { return Impl.end(); }
+
+ Stmt* operator[](size_t i) const {
+ assert(i < Impl.size());
+ return Impl[Impl.size() - 1 - i];
+ }
+
+ size_t size() const { return Impl.size(); }
+ bool empty() const { return Impl.empty(); }
+ };
+
+ /// Stmts - The set of statements in the basic block.
+ StatementList 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 BumpVector<CFGBlock*> AdjacentBlocks;
+ AdjacentBlocks Preds;
+ AdjacentBlocks Succs;
+
+public:
+ explicit CFGBlock(unsigned blockid, BumpVectorContext &C)
+ : Stmts(C), Label(NULL), Terminator(NULL), LoopTarget(NULL),
+ BlockID(blockid), Preds(C, 1), Succs(C, 1) {}
+ ~CFGBlock() {};
+
+ // Statement iterators
+ typedef StatementList::iterator iterator;
+ typedef StatementList::const_iterator const_iterator;
+ typedef StatementList::reverse_iterator reverse_iterator;
+ typedef StatementList::const_reverse_iterator const_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 { 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 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();
+
+ unsigned getBlockID() const { return BlockID; }
+
+ void dump(const CFG *cfg, const LangOptions &LO) const;
+ void print(llvm::raw_ostream &OS, const CFG* cfg, const LangOptions &LO) const;
+ void printTerminator(llvm::raw_ostream &OS, const LangOptions &LO) const;
+
+ void addSuccessor(CFGBlock* Block, BumpVectorContext &C) {
+ if (Block)
+ Block->Preds.push_back(this, C);
+ Succs.push_back(Block, C);
+ }
+
+ void appendStmt(Stmt* Statement, BumpVectorContext &C) {
+ Stmts.push_back(Statement, C);
+ }
+};
+
+
+/// 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, ASTContext *C);
+
+ /// 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; }
+
+ /// setIndirectGotoBlock - Set the block used for indirect goto jumps.
+ /// This is typically used only during CFG construction.
+ void setIndirectGotoBlock(CFGBlock* B) { IndirectGotoBlock = B; }
+
+ //===--------------------------------------------------------------------===//
+ // Block Iterators
+ //===--------------------------------------------------------------------===//
+
+ typedef BumpVector<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();
+
+ /// getNumBlockIDs - Returns the total number of BlockIDs allocated (which
+ /// start at 0).
+ unsigned getNumBlockIDs() const { return NumBlockIDs; }
+
+ //===--------------------------------------------------------------------===//
+ // CFG Debugging: Pretty-Printing and Visualization.
+ //===--------------------------------------------------------------------===//
+
+ void viewCFG(const LangOptions &LO) const;
+ void print(llvm::raw_ostream& OS, const LangOptions &LO) const;
+ void dump(const LangOptions &LO) const;
+
+ //===--------------------------------------------------------------------===//
+ // Internal: constructors and data.
+ //===--------------------------------------------------------------------===//
+
+ CFG() : Entry(NULL), Exit(NULL), IndirectGotoBlock(NULL), NumBlockIDs(0),
+ BlkExprMap(NULL), Blocks(BlkBVC, 10) {};
+
+ ~CFG();
+
+ llvm::BumpPtrAllocator& getAllocator() {
+ return BlkBVC.getAllocator();
+ }
+
+ BumpVectorContext &getBumpVectorContext() {
+ return BlkBVC;
+ }
+
+private:
+ CFGBlock* Entry;
+ CFGBlock* Exit;
+ CFGBlock* IndirectGotoBlock; // Special block to contain collective dispatch
+ // for indirect gotos
+ 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;
+
+ BumpVectorContext BlkBVC;
+
+ CFGBlockListTy Blocks;
+
+};
+} // 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/Analysis/CallGraph.h b/include/clang/Analysis/CallGraph.h
new file mode 100644
index 0000000..fabeea3
--- /dev/null
+++ b/include/clang/Analysis/CallGraph.h
@@ -0,0 +1,147 @@
+//== CallGraph.cpp - Call graph 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 defined the CallGraph and CallGraphNode classes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_CALLGRAPH
+#define LLVM_CLANG_ANALYSIS_CALLGRAPH
+
+#include "clang/Index/ASTLocation.h"
+#include "clang/Index/Entity.h"
+#include "clang/Index/Program.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/GraphTraits.h"
+#include "llvm/ADT/STLExtras.h"
+#include <vector>
+#include <map>
+
+namespace clang {
+
+class CallGraphNode {
+ idx::Entity F;
+ typedef std::pair<idx::ASTLocation, CallGraphNode*> CallRecord;
+ std::vector<CallRecord> CalledFunctions;
+
+public:
+ CallGraphNode(idx::Entity f) : F(f) {}
+
+ typedef std::vector<CallRecord>::iterator iterator;
+ typedef std::vector<CallRecord>::const_iterator const_iterator;
+
+ iterator begin() { return CalledFunctions.begin(); }
+ iterator end() { return CalledFunctions.end(); }
+ const_iterator begin() const { return CalledFunctions.begin(); }
+ const_iterator end() const { return CalledFunctions.end(); }
+
+ void addCallee(idx::ASTLocation L, CallGraphNode *Node) {
+ CalledFunctions.push_back(std::make_pair(L, Node));
+ }
+
+ bool hasCallee() const { return begin() != end(); }
+
+ std::string getName() const { return F.getPrintableName(); }
+
+ Decl *getDecl(ASTContext &Ctx) const { return F.getDecl(Ctx); }
+};
+
+class CallGraph {
+ /// Program manages all Entities.
+ idx::Program Prog;
+
+ typedef std::map<idx::Entity, CallGraphNode *> FunctionMapTy;
+
+ /// FunctionMap owns all CallGraphNodes.
+ FunctionMapTy FunctionMap;
+
+ /// CallerCtx maps a caller to its ASTContext.
+ llvm::DenseMap<CallGraphNode *, ASTContext *> CallerCtx;
+
+ /// Root node is the 'main' function or 0.
+ CallGraphNode *Root;
+
+ /// ExternalCallingNode has edges to all external functions.
+ CallGraphNode *ExternalCallingNode;
+
+public:
+ CallGraph();
+ ~CallGraph();
+
+ typedef FunctionMapTy::iterator iterator;
+ typedef FunctionMapTy::const_iterator const_iterator;
+
+ iterator begin() { return FunctionMap.begin(); }
+ iterator end() { return FunctionMap.end(); }
+ const_iterator begin() const { return FunctionMap.begin(); }
+ const_iterator end() const { return FunctionMap.end(); }
+
+ CallGraphNode *getRoot() { return Root; }
+
+ CallGraphNode *getExternalCallingNode() { return ExternalCallingNode; }
+
+ void addTU(ASTUnit &AST);
+
+ idx::Program &getProgram() { return Prog; }
+
+ CallGraphNode *getOrInsertFunction(idx::Entity F);
+
+ Decl *getDecl(CallGraphNode *Node);
+
+ void print(llvm::raw_ostream &os);
+ void dump();
+
+ void ViewCallGraph() const;
+};
+
+} // end clang namespace
+
+namespace llvm {
+
+template <> struct GraphTraits<clang::CallGraph> {
+ typedef clang::CallGraph GraphType;
+ typedef clang::CallGraphNode NodeType;
+
+ typedef std::pair<clang::idx::ASTLocation, NodeType*> CGNPairTy;
+ typedef std::pointer_to_unary_function<CGNPairTy, NodeType*> CGNDerefFun;
+
+ typedef mapped_iterator<NodeType::iterator, CGNDerefFun> ChildIteratorType;
+
+ static NodeType *getEntryNode(GraphType *CG) {
+ return CG->getExternalCallingNode();
+ }
+
+ static ChildIteratorType child_begin(NodeType *N) {
+ return map_iterator(N->begin(), CGNDerefFun(CGNDeref));
+ }
+ static ChildIteratorType child_end(NodeType *N) {
+ return map_iterator(N->end(), CGNDerefFun(CGNDeref));
+ }
+
+ typedef std::pair<clang::idx::Entity, NodeType*> PairTy;
+ typedef std::pointer_to_unary_function<PairTy, NodeType*> DerefFun;
+
+ typedef mapped_iterator<GraphType::const_iterator, DerefFun> nodes_iterator;
+
+ static nodes_iterator nodes_begin(const GraphType &CG) {
+ return map_iterator(CG.begin(), DerefFun(CGDeref));
+ }
+ static nodes_iterator nodes_end(const GraphType &CG) {
+ return map_iterator(CG.end(), DerefFun(CGDeref));
+ }
+
+ static NodeType *CGNDeref(CGNPairTy P) { return P.second; }
+
+ static NodeType *CGDeref(PairTy P) { return P.second; }
+};
+
+} // end llvm namespace
+
+#endif
diff --git a/include/clang/Analysis/FlowSensitive/DataflowSolver.h b/include/clang/Analysis/FlowSensitive/DataflowSolver.h
index 3861259..f505bca 100644
--- a/include/clang/Analysis/FlowSensitive/DataflowSolver.h
+++ b/include/clang/Analysis/FlowSensitive/DataflowSolver.h
@@ -14,7 +14,7 @@
#ifndef LLVM_CLANG_ANALYSES_DATAFLOW_SOLVER
#define LLVM_CLANG_ANALYSES_DATAFLOW_SOLVER
-#include "clang/AST/CFG.h"
+#include "clang/Analysis/CFG.h"
#include "clang/Analysis/ProgramPoint.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "functional" // STL
@@ -24,7 +24,7 @@ namespace clang {
//===----------------------------------------------------------------------===//
/// DataflowWorkListTy - Data structure representing the worklist used for
/// dataflow algorithms.
-//===----------------------------------------------------------------------===//
+//===----------------------------------------------------------------------===//
class DataflowWorkListTy {
typedef llvm::SmallPtrSet<const CFGBlock*,20> BlockSet;
@@ -33,15 +33,15 @@ 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;
+ return B;
}
-
+
/// isEmpty - Return true if the worklist is empty.
bool isEmpty() const { return wlist.empty(); }
};
@@ -59,22 +59,22 @@ 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 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);
+ return BlockEdge(Prev, B, 0);
}
-
+
static BlockEdge NextEdge(const CFGBlock* B, const CFGBlock* Next) {
- return BlockEdge(B, Next);
+ return BlockEdge(B, Next, 0);
}
};
@@ -82,22 +82,22 @@ 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 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 NextBegin(const CFGBlock* B) { return B->pred_begin(); }
static NextBItr NextEnd(const CFGBlock* B) { return B->pred_end(); }
-
+
static StmtItr StmtBegin(const CFGBlock* B) { return B->rbegin(); }
- static StmtItr StmtEnd(const CFGBlock* B) { return B->rend(); }
-
+ static StmtItr StmtEnd(const CFGBlock* B) { return B->rend(); }
+
static BlockEdge PrevEdge(const CFGBlock* B, const CFGBlock* Prev) {
- return BlockEdge(B, Prev);
+ return BlockEdge(B, Prev, 0);
}
-
+
static BlockEdge NextEdge(const CFGBlock* B, const CFGBlock* Next) {
- return BlockEdge(Next, B);
+ return BlockEdge(Next, B, 0);
}
};
} // end namespace dataflow
@@ -105,7 +105,7 @@ template <> struct ItrTraits<backward_analysis_tag> {
//===----------------------------------------------------------------------===//
/// DataflowSolverTy - Generic dataflow solver.
//===----------------------------------------------------------------------===//
-
+
template <typename _DFValuesTy, // Usually a subclass of DataflowValues
typename _TransferFuncsTy,
typename _MergeOperatorTy,
@@ -120,7 +120,7 @@ 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;
@@ -130,24 +130,24 @@ public:
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() {}
-
+ ~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);
+ 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
@@ -162,10 +162,10 @@ public:
ProcessBlock(B, recordStmtValues, AnalysisDirTag());
}
}
-
+
void runOnBlock(const CFGBlock& B, bool recordStmtValues) {
runOnBlock(&B, recordStmtValues);
- }
+ }
void runOnBlock(CFG::iterator& I, bool recordStmtValues) {
runOnBlock(*I, recordStmtValues);
}
@@ -177,81 +177,87 @@ public:
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);
-
+ WorkList.enqueue(&**I);
+
while (!WorkList.isEmpty()) {
const CFGBlock* B = WorkList.dequeue();
- ProcessMerge(cfg,B);
+ ProcessMerge(cfg, B);
ProcessBlock(B, recordStmtValues, AnalysisDirTag());
- UpdateEdges(cfg,B,TF.getVal());
+ UpdateEdges(cfg, B, TF.getVal());
}
- }
-
+ }
+
void ProcessMerge(CFG& cfg, const CFGBlock* B) {
- ValTy& V = TF.getVal();
+ 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){
+ CFGBlock *PrevBlk = *I;
+
+ if (!PrevBlk)
+ continue;
+
typename EdgeDataMapTy::iterator EI =
- M.find(ItrTraits::PrevEdge(B, *I));
+ M.find(ItrTraits::PrevEdge(B, PrevBlk));
if (EI != M.end()) {
if (firstMerge) {
firstMerge = false;
V.copyValues(EI->second);
}
- else Merge(V,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));
+
+ 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));
+ 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();
@@ -263,14 +269,15 @@ private:
// 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);
+ if (CFGBlock *NextBlk = *I)
+ UpdateEdgeValue(ItrTraits::NextEdge(B, NextBlk),V, NextBlk);
}
-
+
/// UpdateEdgeValue - Update the value associated with a given edge.
void UpdateEdgeValue(BlockEdge E, ValTy& V, const CFGBlock* TargetBlock) {
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);
@@ -280,7 +287,7 @@ private:
WorkList.enqueue(TargetBlock);
}
}
-
+
private:
DFValuesTy& D;
DataflowWorkListTy WorkList;
diff --git a/include/clang/Analysis/FlowSensitive/DataflowValues.h b/include/clang/Analysis/FlowSensitive/DataflowValues.h
index d6427a5..648fe33 100644
--- a/include/clang/Analysis/FlowSensitive/DataflowValues.h
+++ b/include/clang/Analysis/FlowSensitive/DataflowValues.h
@@ -16,7 +16,7 @@
#ifndef LLVM_CLANG_ANALYSES_DATAFLOW_VALUES
#define LLVM_CLANG_ANALYSES_DATAFLOW_VALUES
-#include "clang/AST/CFG.h"
+#include "clang/Analysis/CFG.h"
#include "clang/Analysis/ProgramPoint.h"
#include "llvm/ADT/DenseMap.h"
@@ -24,7 +24,7 @@
/// 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 {
@@ -34,19 +34,19 @@ 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 typename ValueTypes::AnalysisDataTy AnalysisDataTy;
typedef _AnalysisDirTag AnalysisDirTag;
typedef llvm::DenseMap<ProgramPoint, ValTy> EdgeDataMapTy;
typedef llvm::DenseMap<const CFGBlock*, ValTy> BlockDataMapTy;
@@ -60,15 +60,15 @@ 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; }
-
+ bool isForwardAnalysis(dataflow::backward_analysis_tag) { return false; }
+
//===--------------------------------------------------------------------===//
// Initialization and accessors methods.
//===--------------------------------------------------------------------===//
@@ -76,10 +76,10 @@ private:
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) {};
+ void InitializeValues(const CFG& cfg) {};
/// getEdgeData - Retrieves the dataflow values associated with a
@@ -89,28 +89,28 @@ public:
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
+ /// 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.
+ /// 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
+
+ /// 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.
+ /// 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.
@@ -120,11 +120,11 @@ public:
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.
@@ -138,35 +138,35 @@ public:
/// 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.
+ /// 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
index 9ff3f52..1da15fb 100644
--- a/include/clang/Analysis/LocalCheckers.h
+++ b/include/clang/Analysis/LocalCheckers.h
@@ -31,23 +31,29 @@ class BugReporter;
class ObjCImplementationDecl;
class LangOptions;
class GRExprEngine;
-
-void CheckDeadStores(LiveVariables& L, BugReporter& BR);
-
+
+void CheckDeadStores(CFG &cfg, LiveVariables &L, ParentMap &map,
+ BugReporter& BR);
+
void CheckUninitializedValues(CFG& cfg, ASTContext& Ctx, Diagnostic& Diags,
bool FullUninitTaint=false);
-
+
GRTransferFuncs* MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled,
- const LangOptions& lopts);
-
-void CheckObjCDealloc(ObjCImplementationDecl* D, const LangOptions& L,
+ const LangOptions& lopts);
+
+void CheckObjCDealloc(const ObjCImplementationDecl* D, const LangOptions& L,
BugReporter& BR);
-
-void CheckObjCInstMethSignature(ObjCImplementationDecl* ID, BugReporter& BR);
-void CheckObjCUnusedIvar(ObjCImplementationDecl* D, BugReporter& BR);
-
-void RegisterAppleChecks(GRExprEngine& Eng);
-
+
+void CheckObjCInstMethSignature(const ObjCImplementationDecl *ID,
+ BugReporter& BR);
+
+void CheckObjCUnusedIvar(const ObjCImplementationDecl *D, BugReporter& BR);
+
+void RegisterAppleChecks(GRExprEngine& Eng, const Decl &D);
+
+void CheckSecuritySyntaxOnly(const Decl *D, BugReporter &BR);
+
+
} // end namespace clang
#endif
diff --git a/include/clang/Analysis/PathDiagnostic.h b/include/clang/Analysis/PathDiagnostic.h
index 994b35e..a08afe2 100644
--- a/include/clang/Analysis/PathDiagnostic.h
+++ b/include/clang/Analysis/PathDiagnostic.h
@@ -17,6 +17,7 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/Diagnostic.h"
#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/FoldingSet.h"
#include <vector>
#include <deque>
@@ -24,12 +25,17 @@
#include <algorithm>
namespace clang {
-
+
+class Stmt;
+class Decl;
+class Preprocessor;
+
//===----------------------------------------------------------------------===//
// High-level interface for handlers of path-sensitive diagnostics.
//===----------------------------------------------------------------------===//
class PathDiagnostic;
+
class Stmt;
class Decl;
class Preprocessor;
@@ -38,21 +44,18 @@ 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; }
+
+ 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.
//===----------------------------------------------------------------------===//
@@ -60,11 +63,11 @@ public:
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;
@@ -75,27 +78,27 @@ private:
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;
@@ -104,27 +107,29 @@ public:
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; }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const;
};
class PathDiagnosticLocationPair {
@@ -134,19 +139,24 @@ 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();
}
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ Start.Profile(ID);
+ End.Profile(ID);
+ }
};
//===----------------------------------------------------------------------===//
// Path "pieces" for path-sensitive diagnostics.
-//===----------------------------------------------------------------------===//
+//===----------------------------------------------------------------------===//
class PathDiagnosticPiece {
public:
@@ -159,7 +169,7 @@ private:
const Kind kind;
const DisplayHint Hint;
std::vector<SourceRange> ranges;
-
+
// Do not implement:
PathDiagnosticPiece();
PathDiagnosticPiece(const PathDiagnosticPiece &P);
@@ -167,42 +177,42 @@ private:
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 {
+
+ range_iterator ranges_end() const {
return ranges_begin() + ranges.size();
}
@@ -213,15 +223,17 @@ public:
}
code_modifications_iterator code_modifications_end() const {
- return CodeModificationHints.empty()? 0
+ return CodeModificationHints.empty()? 0
: &CodeModificationHints[0] + CodeModificationHints.size();
}
static inline bool classof(const PathDiagnosticPiece* P) {
return true;
}
-};
+ virtual void Profile(llvm::FoldingSetNodeID &ID) const;
+};
+
class PathDiagnosticSpotPiece : public PathDiagnosticPiece {
private:
PathDiagnosticLocation Pos;
@@ -234,30 +246,32 @@ public:
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(); }
-};
+ virtual void Profile(llvm::FoldingSetNodeID &ID) const;
+};
+
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:
@@ -267,40 +281,40 @@ public:
: 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(); }
@@ -308,7 +322,7 @@ public:
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(); }
@@ -317,171 +331,177 @@ public:
static inline bool classof(const PathDiagnosticPiece* P) {
return P->getKind() == ControlFlow;
}
-};
+ virtual void Profile(llvm::FoldingSetNodeID &ID) const;
+};
+
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;
}
+
+ virtual void Profile(llvm::FoldingSetNodeID &ID) const;
};
/// 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 {
+class PathDiagnostic : public llvm::FoldingSetNode {
std::deque<PathDiagnosticPiece*> path;
unsigned Size;
std::string BugType;
std::string Desc;
std::string Category;
std::deque<std::string> OtherDesc;
-
-public:
+
+public:
PathDiagnostic();
-
+
PathDiagnostic(const char* bugtype, const char* desc, const char* category);
-
- PathDiagnostic(const std::string& bugtype, const std::string& desc,
+
+ 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; }
-
+ 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) {
+ assert(piece);
path.push_front(piece);
++Size;
}
-
+
void push_back(PathDiagnosticPiece* piece) {
+ assert(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:
+ 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:
+ 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();
}
-};
-
+ void Profile(llvm::FoldingSetNodeID &ID) const;
+};
} //end clang namespace
#endif
diff --git a/include/clang/Analysis/PathSensitive/AnalysisContext.h b/include/clang/Analysis/PathSensitive/AnalysisContext.h
new file mode 100644
index 0000000..ffe282d
--- /dev/null
+++ b/include/clang/Analysis/PathSensitive/AnalysisContext.h
@@ -0,0 +1,167 @@
+//=== AnalysisContext.h - Analysis context 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 AnalysisContext, a class that manages the analysis context
+// data for path sensitive analysis.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSISCONTEXT_H
+#define LLVM_CLANG_ANALYSIS_ANALYSISCONTEXT_H
+
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/DenseMap.h"
+
+namespace clang {
+
+class Decl;
+class Stmt;
+class CFG;
+class LiveVariables;
+class ParentMap;
+class ImplicitParamDecl;
+
+/// AnalysisContext contains the context data for the function or method under
+/// analysis.
+class AnalysisContext {
+ const Decl *D;
+
+ // AnalysisContext owns the following data.
+ CFG *cfg;
+ LiveVariables *liveness;
+ ParentMap *PM;
+
+public:
+ AnalysisContext(const Decl *d) : D(d), cfg(0), liveness(0), PM(0) {}
+ ~AnalysisContext();
+
+ const Decl *getDecl() { return D; }
+ Stmt *getBody();
+ CFG *getCFG();
+ ParentMap &getParentMap();
+ LiveVariables *getLiveVariables();
+
+ /// Return the ImplicitParamDecl* associated with 'self' if this
+ /// AnalysisContext wraps an ObjCMethodDecl. Returns NULL otherwise.
+ const ImplicitParamDecl *getSelfDecl() const;
+};
+
+class AnalysisContextManager {
+ typedef llvm::DenseMap<const Decl*, AnalysisContext*> ContextMap;
+ ContextMap Contexts;
+public:
+ ~AnalysisContextManager();
+
+ AnalysisContext *getContext(const Decl *D);
+};
+
+class LocationContext : public llvm::FoldingSetNode {
+public:
+ enum ContextKind { StackFrame, Scope };
+
+private:
+ ContextKind Kind;
+ AnalysisContext *Ctx;
+ const LocationContext *Parent;
+
+protected:
+ LocationContext(ContextKind k, AnalysisContext *ctx,
+ const LocationContext *parent)
+ : Kind(k), Ctx(ctx), Parent(parent) {}
+
+public:
+ ContextKind getKind() const { return Kind; }
+
+ AnalysisContext *getAnalysisContext() const { return Ctx; }
+
+ const LocationContext *getParent() const { return Parent; }
+
+ const Decl *getDecl() const { return getAnalysisContext()->getDecl(); }
+
+ CFG *getCFG() const { return getAnalysisContext()->getCFG(); }
+
+ LiveVariables *getLiveVariables() const {
+ return getAnalysisContext()->getLiveVariables();
+ }
+
+ ParentMap &getParentMap() const {
+ return getAnalysisContext()->getParentMap();
+ }
+
+ const ImplicitParamDecl *getSelfDecl() const {
+ return Ctx->getSelfDecl();
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, Kind, Ctx, Parent);
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, ContextKind k,
+ AnalysisContext *ctx, const LocationContext *parent);
+
+ static bool classof(const LocationContext*) { return true; }
+};
+
+class StackFrameContext : public LocationContext {
+ const Stmt *CallSite;
+
+public:
+ StackFrameContext(AnalysisContext *ctx, const LocationContext *parent,
+ const Stmt *s)
+ : LocationContext(StackFrame, ctx, parent), CallSite(s) {}
+
+ Stmt const *getCallSite() const { return CallSite; }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getAnalysisContext(), getParent(), CallSite);
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx,
+ const LocationContext *parent, const Stmt *s);
+
+ static bool classof(const LocationContext* Ctx) {
+ return Ctx->getKind() == StackFrame;
+ }
+};
+
+class ScopeContext : public LocationContext {
+ const Stmt *Enter;
+
+public:
+ ScopeContext(AnalysisContext *ctx, const LocationContext *parent,
+ const Stmt *s)
+ : LocationContext(Scope, ctx, parent), Enter(s) {}
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getAnalysisContext(), getParent(), Enter);
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx,
+ const LocationContext *parent, const Stmt *s);
+
+ static bool classof(const LocationContext* Ctx) {
+ return Ctx->getKind() == Scope;
+ }
+};
+
+class LocationContextManager {
+ llvm::FoldingSet<LocationContext> Contexts;
+
+public:
+ StackFrameContext *getStackFrame(AnalysisContext *ctx,
+ const LocationContext *parent,
+ const Stmt *s);
+
+ ScopeContext *getScope(AnalysisContext *ctx, const LocationContext *parent,
+ const Stmt *s);
+};
+
+} // end clang namespace
+#endif
diff --git a/include/clang/Analysis/PathSensitive/AnalysisManager.h b/include/clang/Analysis/PathSensitive/AnalysisManager.h
new file mode 100644
index 0000000..e97f805
--- /dev/null
+++ b/include/clang/Analysis/PathSensitive/AnalysisManager.h
@@ -0,0 +1,140 @@
+//== AnalysisManager.h - Path sensitive analysis data manager ------*- C++ -*-//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the AnalysisManager class that manages the data and policy
+// for path sensitive analysis.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSISMANAGER_H
+#define LLVM_CLANG_ANALYSIS_ANALYSISMANAGER_H
+
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Analysis/PathSensitive/AnalysisContext.h"
+#include "clang/Analysis/PathDiagnostic.h"
+
+namespace clang {
+
+class AnalysisManager : public BugReporterData {
+ AnalysisContextManager AnaCtxMgr;
+ LocationContextManager LocCtxMgr;
+
+ ASTContext &Ctx;
+ Diagnostic &Diags;
+ const LangOptions &LangInfo;
+
+ llvm::OwningPtr<PathDiagnosticClient> PD;
+
+ // Configurable components creators.
+ StoreManagerCreator CreateStoreMgr;
+ ConstraintManagerCreator CreateConstraintMgr;
+
+ enum AnalysisScope { ScopeTU, ScopeDecl } AScope;
+
+ bool DisplayedFunction;
+ bool VisualizeEGDot;
+ bool VisualizeEGUbi;
+ bool PurgeDead;
+
+ /// 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.
+ bool EagerlyAssume;
+ bool TrimGraph;
+
+public:
+ AnalysisManager(ASTContext &ctx, Diagnostic &diags,
+ const LangOptions &lang, PathDiagnosticClient *pd,
+ StoreManagerCreator storemgr,
+ ConstraintManagerCreator constraintmgr,
+ bool displayProgress, bool vizdot, bool vizubi,
+ bool purge, bool eager, bool trim)
+
+ : Ctx(ctx), Diags(diags), LangInfo(lang), PD(pd),
+ CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr),
+ AScope(ScopeDecl), DisplayedFunction(!displayProgress),
+ VisualizeEGDot(vizdot), VisualizeEGUbi(vizubi), PurgeDead(purge),
+ EagerlyAssume(eager), TrimGraph(trim) {}
+
+ StoreManagerCreator getStoreManagerCreator() {
+ return CreateStoreMgr;
+ };
+
+ ConstraintManagerCreator getConstraintManagerCreator() {
+ return CreateConstraintMgr;
+ }
+
+ virtual ASTContext &getASTContext() {
+ return Ctx;
+ }
+
+ virtual SourceManager &getSourceManager() {
+ return getASTContext().getSourceManager();
+ }
+
+ virtual Diagnostic &getDiagnostic() {
+ return Diags;
+ }
+
+ const LangOptions &getLangOptions() const {
+ return LangInfo;
+ }
+
+ virtual PathDiagnosticClient *getPathDiagnosticClient() {
+ return PD.get();
+ }
+
+ bool shouldVisualizeGraphviz() const { return VisualizeEGDot; }
+
+ bool shouldVisualizeUbigraph() const { return VisualizeEGUbi; }
+
+ bool shouldVisualize() const {
+ return VisualizeEGDot || VisualizeEGUbi;
+ }
+
+ bool shouldTrimGraph() const { return TrimGraph; }
+
+ bool shouldPurgeDead() const { return PurgeDead; }
+
+ bool shouldEagerlyAssume() const { return EagerlyAssume; }
+
+ void DisplayFunction(Decl *D);
+
+ CFG *getCFG(Decl const *D) {
+ return AnaCtxMgr.getContext(D)->getCFG();
+ }
+
+ LiveVariables *getLiveVariables(Decl const *D) {
+ return AnaCtxMgr.getContext(D)->getLiveVariables();
+ }
+
+ ParentMap &getParentMap(Decl const *D) {
+ return AnaCtxMgr.getContext(D)->getParentMap();
+ }
+
+ // Get the top level stack frame.
+ StackFrameContext *getStackFrame(Decl const *D) {
+ return LocCtxMgr.getStackFrame(AnaCtxMgr.getContext(D), 0, 0);
+ }
+
+ // Get a stack frame with parent.
+ StackFrameContext const *getStackFrame(Decl const *D,
+ LocationContext const *Parent,
+ Stmt const *S) {
+ return LocCtxMgr.getStackFrame(AnaCtxMgr.getContext(D), Parent, S);
+ }
+};
+
+}
+
+#endif
diff --git a/include/clang/Analysis/PathSensitive/BasicValueFactory.h b/include/clang/Analysis/PathSensitive/BasicValueFactory.h
index b694e9b2..12f0ce2 100644
--- a/include/clang/Analysis/PathSensitive/BasicValueFactory.h
+++ b/include/clang/Analysis/PathSensitive/BasicValueFactory.h
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
//
// This file defines BasicValueFactory, a class that manages the lifetime
-// of APSInt objects and symbolic constraints used by GRExprEngine
+// of APSInt objects and symbolic constraints used by GRExprEngine
// and related classes.
//
//===----------------------------------------------------------------------===//
@@ -24,25 +24,43 @@
#include "llvm/ADT/ImmutableList.h"
namespace clang {
-
+
+ class GRState;
+
class CompoundValData : public llvm::FoldingSetNode {
QualType T;
llvm::ImmutableList<SVal> L;
public:
- CompoundValData(QualType t, llvm::ImmutableList<SVal> l)
+ 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(); }
-
+ 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 LazyCompoundValData : public llvm::FoldingSetNode {
+ const GRState *state;
+ const TypedRegion *region;
+public:
+ LazyCompoundValData(const GRState *st, const TypedRegion *r)
+ : state(st), region(r) {}
+
+ const GRState *getState() const { return state; }
+ const TypedRegion *getRegion() const { return region; }
+
+ static void Profile(llvm::FoldingSetNodeID& ID, const GRState *state,
+ const TypedRegion *region);
+
+ void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, state, region); }
+};
+
class BasicValueFactory {
typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<llvm::APSInt> >
APSIntSetTy;
@@ -56,44 +74,54 @@ class BasicValueFactory {
llvm::ImmutableList<SVal>::Factory SValListFactory;
llvm::FoldingSet<CompoundValData> CompoundValDataSet;
+ llvm::FoldingSet<LazyCompoundValData> LazyCompoundValDataSet;
public:
- BasicValueFactory(ASTContext& ctx, llvm::BumpPtrAllocator& Alloc)
+ BasicValueFactory(ASTContext& ctx, llvm::BumpPtrAllocator& Alloc)
: Ctx(ctx), BPAlloc(Alloc), PersistentSVals(0), PersistentSValPairs(0),
SValListFactory(Alloc) {}
~BasicValueFactory();
- ASTContext& getContext() const { return Ctx; }
+ ASTContext& getContext() const { return Ctx; }
const llvm::APSInt& getValue(const llvm::APSInt& X);
const llvm::APSInt& getValue(const llvm::APInt& X, bool isUnsigned);
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 &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 &Convert(QualType T, const llvm::APSInt &From) {
+ assert(T->isIntegerType() || Loc::IsLocType(T));
+ unsigned bitwidth = Ctx.getTypeSize(T);
+ bool isUnsigned = T->isUnsignedIntegerType() || Loc::IsLocType(T);
- return getValue(From.getSExtValue(),
- To.getBitWidth(),
- To.isUnsigned());
+ if (isUnsigned == From.isUnsigned() && bitwidth == From.getBitWidth())
+ return From;
+
+ return getValue(From.getSExtValue(), bitwidth, 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()));
}
@@ -103,44 +131,51 @@ public:
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 &getIntWithPtrWidth(uint64_t X, bool isUnsigned) {
+ return getValue(X, 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,
+
+ const CompoundValData *getCompoundValData(QualType T,
llvm::ImmutableList<SVal> Vals);
-
+
+ const LazyCompoundValData *getLazyCompoundValData(const GRState *state,
+ const TypedRegion *region);
+
llvm::ImmutableList<SVal> getEmptySValList() {
return SValListFactory.GetEmptyList();
}
-
+
llvm::ImmutableList<SVal> consVals(SVal X, llvm::ImmutableList<SVal> L) {
return SValListFactory.Add(X, L);
}
@@ -148,13 +183,13 @@ public:
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);
-
+ getPersistentSValPair(const SVal& V1, const SVal& V2);
+
const SVal* getPersistentSVal(SVal X);
};
diff --git a/include/clang/Analysis/PathSensitive/BugReporter.h b/include/clang/Analysis/PathSensitive/BugReporter.h
index 90fd9d8..1434fce 100644
--- a/include/clang/Analysis/PathSensitive/BugReporter.h
+++ b/include/clang/Analysis/PathSensitive/BugReporter.h
@@ -27,7 +27,7 @@
#include <list>
namespace clang {
-
+
class PathDiagnostic;
class PathDiagnosticPiece;
class PathDiagnosticClient;
@@ -40,7 +40,7 @@ class GRState;
class Stmt;
class BugType;
class ParentMap;
-
+
//===----------------------------------------------------------------------===//
// Interface for individual bug reports.
//===----------------------------------------------------------------------===//
@@ -48,22 +48,22 @@ class ParentMap;
class BugReporterVisitor {
public:
virtual ~BugReporterVisitor();
- virtual PathDiagnosticPiece* VisitNode(const ExplodedNode<GRState>* N,
- const ExplodedNode<GRState>* PrevN,
+ virtual PathDiagnosticPiece* VisitNode(const ExplodedNode* N,
+ const ExplodedNode* 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;
+ const ExplodedNode *EndNode;
SourceRange R;
-
+
protected:
friend class BugReporter;
friend class BugReportEquivClass;
@@ -71,79 +71,78 @@ protected:
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;
+ virtual const ExplodedNode*
+ getOriginalNode(const ExplodedNode* N) = 0;
};
-
- BugReport(BugType& bt, const char* desc, const ExplodedNode<GRState> *n)
+
+ BugReport(BugType& bt, const char* desc, const ExplodedNode *n)
: BT(bt), Description(desc), EndNode(n) {}
-
+
BugReport(BugType& bt, const char* shortDesc, const char* desc,
- const ExplodedNode<GRState> *n)
+ const ExplodedNode *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; }
-
+ const ExplodedNode* 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 Stmt* getStmt() 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);
-
+ const ExplodedNode* 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 void getRanges(const SourceRange*& beg, const SourceRange*& end);
- virtual PathDiagnosticPiece* VisitNode(const ExplodedNode<GRState>* N,
- const ExplodedNode<GRState>* PrevN,
+ virtual PathDiagnosticPiece* VisitNode(const ExplodedNode* N,
+ const ExplodedNode* PrevN,
BugReporterContext& BR);
-
+
virtual void registerInitialVisitors(BugReporterContext& BRC,
- const ExplodedNode<GRState>* N) {}
+ const ExplodedNode* 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:
@@ -165,7 +164,7 @@ public:
BugReport* operator*() const { return *impl; }
BugReport* operator->() const { return *impl; }
};
-
+
class const_iterator {
std::list<BugReport*>::const_iterator impl;
public:
@@ -176,64 +175,70 @@ public:
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;
+ bool SuppressonSink;
public:
- BugType(const char *name, const char* cat) : Name(name), Category(cat) {}
+ BugType(const char *name, const char* cat)
+ : Name(name), Category(cat), SuppressonSink(false) {}
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);
+ /// isSuppressOnSink - Returns true if bug reports associated with this bug
+ /// type should be suppressed if the end node of the report is post-dominated
+ /// by a sink node.
+ bool isSuppressOnSink() const { return SuppressonSink; }
+ void setSuppressOnSink(bool x) { SuppressonSink = x; }
+
+ virtual void FlushReports(BugReporter& 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)
+ RangedBugReport(BugType& D, const char* description, ExplodedNode *n)
: BugReport(D, description, n) {}
-
+
RangedBugReport(BugType& D, const char *shortDescription,
- const char *description, ExplodedNode<GRState> *n)
+ const char *description, ExplodedNode *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) {
-
+ void getRanges(const SourceRange*& beg, const SourceRange*& end) {
+
if (Ranges.empty()) {
beg = NULL;
end = NULL;
@@ -244,7 +249,36 @@ public:
}
}
};
-
+
+class EnhancedBugReport : public RangedBugReport {
+public:
+ typedef void (*VisitorCreator)(BugReporterContext &BRcC, const void *data,
+ const ExplodedNode *N);
+
+private:
+ typedef std::vector<std::pair<VisitorCreator, const void*> > Creators;
+ Creators creators;
+
+public:
+ EnhancedBugReport(BugType& D, const char* description, ExplodedNode *n)
+ : RangedBugReport(D, description, n) {}
+
+ EnhancedBugReport(BugType& D, const char *shortDescription,
+ const char *description, ExplodedNode *n)
+ : RangedBugReport(D, shortDescription, description, n) {}
+
+ ~EnhancedBugReport() {}
+
+ void registerInitialVisitors(BugReporterContext& BRC, const ExplodedNode* N) {
+ for (Creators::iterator I = creators.begin(), E = creators.end(); I!=E; ++I)
+ I->first(BRC, I->second, N);
+ }
+
+ void addVisitorCreator(VisitorCreator creator, const void *data) {
+ creators.push_back(std::make_pair(creator, data));
+ }
+};
+
//===----------------------------------------------------------------------===//
// BugReporter and friends.
//===----------------------------------------------------------------------===//
@@ -252,15 +286,12 @@ public:
class BugReporterData {
public:
virtual ~BugReporterData();
- virtual Diagnostic& getDiagnostic() = 0;
- virtual PathDiagnosticClient* getPathDiagnosticClient() = 0;
- virtual ASTContext& getContext() = 0;
+ virtual Diagnostic& getDiagnostic() = 0;
+ virtual PathDiagnosticClient* getPathDiagnosticClient() = 0;
+ virtual ASTContext& getASTContext() = 0;
virtual SourceManager& getSourceManager() = 0;
- virtual CFG* getCFG() = 0;
- virtual ParentMap& getParentMap() = 0;
- virtual LiveVariables* getLiveVariables() = 0;
};
-
+
class BugReporter {
public:
enum Kind { BaseBRKind, GRBugReporterKind };
@@ -270,9 +301,9 @@ private:
BugTypesTy::Factory F;
BugTypesTy BugTypes;
- const Kind kind;
+ const Kind kind;
BugReporterData& D;
-
+
void FlushReport(BugReportEquivClass& EQ);
protected:
@@ -281,40 +312,34 @@ protected:
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(); }
-
+
+ ASTContext& getContext() { return D.getASTContext(); }
+
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);
@@ -322,28 +347,28 @@ public:
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; }
};
@@ -351,95 +376,87 @@ public:
class GRBugReporter : public BugReporter {
GRExprEngine& Eng;
llvm::SmallSet<SymbolRef, 10> NotableSymbols;
-public:
+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; }
+ GRExprEngine &getEngine() { return Eng; }
/// getGraph - Get the exploded graph created by the analysis engine
/// for the analyzed method or function.
- ExplodedGraph<GRState>& getGraph();
-
+ ExplodedGraph &getGraph();
+
/// getStateManager - Return the state manager used by the analysis
/// engine.
- GRStateManager& getStateManager();
-
+ 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(); }
-
+ visitor_iterator visitor_end() { return Callbacks.end(); }
+
+ GRBugReporter& getBugReporter() { return BR; }
+
+ ExplodedGraph &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;
+
+ virtual BugReport::NodeResolver& getNodeResolver() = 0;
};
class DiagBugReport : public RangedBugReport {
@@ -448,19 +465,37 @@ class DiagBugReport : public RangedBugReport {
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); }
-
+
+ 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(); }
};
+//===----------------------------------------------------------------------===//
+//===----------------------------------------------------------------------===//
+
+namespace bugreporter {
+
+const Stmt *GetDerefExpr(const ExplodedNode *N);
+const Stmt *GetReceiverExpr(const ExplodedNode *N);
+const Stmt *GetDenomExpr(const ExplodedNode *N);
+const Stmt *GetCalleeExpr(const ExplodedNode *N);
+const Stmt *GetRetValExpr(const ExplodedNode *N);
+
+void registerTrackNullOrUndefValue(BugReporterContext& BRC, const void *stmt,
+ const ExplodedNode* N);
+
+} // end namespace clang::bugreporter
+
+//===----------------------------------------------------------------------===//
+
} // end clang namespace
#endif
diff --git a/include/clang/Analysis/PathSensitive/Checker.h b/include/clang/Analysis/PathSensitive/Checker.h
new file mode 100644
index 0000000..4e00d69c
--- /dev/null
+++ b/include/clang/Analysis/PathSensitive/Checker.h
@@ -0,0 +1,122 @@
+//== Checker.h - Abstract interface for checkers -----------------*- C++ -*--=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines Checker and CheckerVisitor, classes used for creating
+// domain-specific checks.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_CHECKER
+#define LLVM_CLANG_ANALYSIS_CHECKER
+#include "clang/Analysis/Support/SaveAndRestore.h"
+#include "clang/Analysis/PathSensitive/GRCoreEngine.h"
+#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/AST/StmtCXX.h"
+#include "clang/AST/StmtObjC.h"
+
+//===----------------------------------------------------------------------===//
+// Checker interface.
+//===----------------------------------------------------------------------===//
+
+namespace clang {
+ class GRExprEngine;
+
+class CheckerContext {
+ ExplodedNodeSet &Dst;
+ GRStmtNodeBuilder &B;
+ GRExprEngine &Eng;
+ ExplodedNode *Pred;
+ SaveAndRestore<bool> OldSink;
+ SaveAndRestore<const void*> OldTag;
+ SaveAndRestore<ProgramPoint::Kind> OldPointKind;
+ SaveOr OldHasGen;
+
+public:
+ CheckerContext(ExplodedNodeSet &dst,
+ GRStmtNodeBuilder &builder,
+ GRExprEngine &eng,
+ ExplodedNode *pred,
+ const void *tag, bool preVisit)
+ : Dst(dst), B(builder), Eng(eng), Pred(pred),
+ OldSink(B.BuildSinks), OldTag(B.Tag),
+ OldPointKind(B.PointKind), OldHasGen(B.HasGeneratedNode) {
+ //assert(Dst.empty()); // This is a fake assertion.
+ // See GRExprEngine::CheckerVisit(), CurrSet is repeatedly used.
+ B.Tag = tag;
+ if (preVisit)
+ B.PointKind = ProgramPoint::PreStmtKind;
+ }
+
+ ~CheckerContext() {
+ if (!B.BuildSinks && !B.HasGeneratedNode)
+ Dst.Add(Pred);
+ }
+
+ ConstraintManager &getConstraintManager() {
+ return Eng.getConstraintManager();
+ }
+ ExplodedNodeSet &getNodeSet() { return Dst; }
+ GRStmtNodeBuilder &getNodeBuilder() { return B; }
+ ExplodedNode *&getPredecessor() { return Pred; }
+ const GRState *getState() { return B.GetState(Pred); }
+
+ ASTContext &getASTContext() {
+ return Eng.getContext();
+ }
+
+ ExplodedNode *GenerateNode(const Stmt *S, bool markAsSink = false) {
+ return GenerateNode(S, getState(), markAsSink);
+ }
+
+ ExplodedNode *GenerateNode(const Stmt* S, const GRState *state,
+ bool markAsSink = false) {
+ ExplodedNode *node = B.generateNode(S, state, Pred);
+
+ if (markAsSink && node)
+ node->markAsSink();
+
+ return node;
+ }
+
+ void addTransition(ExplodedNode *node) {
+ Dst.Add(node);
+ }
+
+ void EmitReport(BugReport *R) {
+ Eng.getBugReporter().EmitReport(R);
+ }
+};
+
+class Checker {
+private:
+ friend class GRExprEngine;
+
+ void GR_Visit(ExplodedNodeSet &Dst,
+ GRStmtNodeBuilder &Builder,
+ GRExprEngine &Eng,
+ const Stmt *stmt,
+ ExplodedNode *Pred, bool isPrevisit) {
+ CheckerContext C(Dst, Builder, Eng, Pred, getTag(), isPrevisit);
+ assert(isPrevisit && "Only previsit supported for now.");
+ _PreVisit(C, stmt);
+ }
+
+public:
+ virtual ~Checker() {}
+ virtual void _PreVisit(CheckerContext &C, const Stmt *stmt) = 0;
+ virtual const void *getTag() = 0;
+};
+
+} // end clang namespace
+
+#endif
+
diff --git a/include/clang/Analysis/PathSensitive/CheckerVisitor.def b/include/clang/Analysis/PathSensitive/CheckerVisitor.def
new file mode 100644
index 0000000..ff6528d
--- /dev/null
+++ b/include/clang/Analysis/PathSensitive/CheckerVisitor.def
@@ -0,0 +1,18 @@
+//===-- CheckerVisitor.def - Metadata for CheckerVisitor ----------------*-===//
+//
+// 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 nodes accepted by the CheckerVisitor class.
+//
+//===---------------------------------------------------------------------===//
+
+PREVISIT(CallExpr)
+PREVISIT(ObjCMessageExpr)
+PREVISIT(BinaryOperator)
+
+#undef PREVISIT
diff --git a/include/clang/Analysis/PathSensitive/CheckerVisitor.h b/include/clang/Analysis/PathSensitive/CheckerVisitor.h
new file mode 100644
index 0000000..e74f49c
--- /dev/null
+++ b/include/clang/Analysis/PathSensitive/CheckerVisitor.h
@@ -0,0 +1,59 @@
+//== CheckerVisitor.h - Abstract visitor for checkers ------------*- C++ -*--=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines CheckerVisitor.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_CHECKERVISITOR
+#define LLVM_CLANG_ANALYSIS_CHECKERVISITOR
+#include "clang/Analysis/PathSensitive/Checker.h"
+
+namespace clang {
+
+//===----------------------------------------------------------------------===//
+// Checker visitor interface. Used by subclasses of Checker to specify their
+// own checker visitor logic.
+//===----------------------------------------------------------------------===//
+
+/// CheckerVisitor - This class implements a simple visitor for Stmt subclasses.
+/// Since Expr derives from Stmt, this also includes support for visiting Exprs.
+template<typename ImplClass>
+class CheckerVisitor : public Checker {
+public:
+ virtual void _PreVisit(CheckerContext &C, const Stmt *stmt) {
+ PreVisit(C, stmt);
+ }
+
+ void PreVisit(CheckerContext &C, const Stmt *S) {
+ switch (S->getStmtClass()) {
+ default:
+ assert(false && "Unsupport statement.");
+ return;
+ case Stmt::CompoundAssignOperatorClass:
+ static_cast<ImplClass*>(this)->PreVisitBinaryOperator(C,
+ static_cast<const BinaryOperator*>(S));
+ break;
+#define PREVISIT(NAME) \
+case Stmt::NAME ## Class:\
+static_cast<ImplClass*>(this)->PreVisit ## NAME(C,static_cast<const NAME*>(S));\
+break;
+#include "clang/Analysis/PathSensitive/CheckerVisitor.def"
+ }
+ }
+
+#define PREVISIT(NAME) \
+void PreVisit ## NAME(CheckerContext &C, const NAME* S) {}
+#include "clang/Analysis/PathSensitive/CheckerVisitor.def"
+};
+
+} // end clang namespace
+
+#endif
+
diff --git a/include/clang/Analysis/PathSensitive/ConstraintManager.h b/include/clang/Analysis/PathSensitive/ConstraintManager.h
index 689bebb..37a1408 100644
--- a/include/clang/Analysis/PathSensitive/ConstraintManager.h
+++ b/include/clang/Analysis/PathSensitive/ConstraintManager.h
@@ -30,26 +30,32 @@ class SVal;
class ConstraintManager {
public:
virtual ~ConstraintManager();
- virtual const GRState *Assume(const GRState *state, SVal Cond,
+ virtual const GRState *Assume(const GRState *state, DefinedSVal Cond,
bool Assumption) = 0;
- virtual const GRState *AssumeInBound(const GRState *state, SVal Idx,
- SVal UpperBound, bool Assumption) = 0;
+ virtual const GRState *AssumeInBound(const GRState *state, DefinedSVal Idx,
+ DefinedSVal UpperBound, bool Assumption) = 0;
+
+ std::pair<const GRState*, const GRState*> AssumeDual(const GRState *state,
+ DefinedSVal Cond) {
+ return std::make_pair(Assume(state, Cond, true),
+ Assume(state, Cond, false));
+ }
virtual const llvm::APSInt* getSymVal(const GRState *state,
SymbolRef sym) const = 0;
- virtual bool isEqual(const GRState *state, SymbolRef sym,
+ virtual bool isEqual(const GRState *state, SymbolRef sym,
const llvm::APSInt& V) const = 0;
virtual const GRState *RemoveDeadBindings(const GRState *state,
SymbolReaper& SymReaper) = 0;
- virtual void print(const GRState *state, llvm::raw_ostream& Out,
+ virtual void print(const GRState *state, llvm::raw_ostream& Out,
const char* nl, const char *sep) = 0;
virtual void EndPath(const GRState *state) {}
-
+
/// 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
diff --git a/include/clang/Analysis/PathSensitive/Environment.h b/include/clang/Analysis/PathSensitive/Environment.h
index 6f8a126..6d5c567 100644
--- a/include/clang/Analysis/PathSensitive/Environment.h
+++ b/include/clang/Analysis/PathSensitive/Environment.h
@@ -26,125 +26,78 @@
namespace clang {
+class AnalysisContext;
class EnvironmentManager;
class ValueManager;
class LiveVariables;
+
class Environment {
private:
friend class EnvironmentManager;
-
+
// Type definitions.
typedef llvm::ImmutableMap<const Stmt*,SVal> BindingsTy;
// Data.
- BindingsTy SubExprBindings;
- BindingsTy BlkExprBindings;
-
- Environment(BindingsTy seb, BindingsTy beb)
- : SubExprBindings(seb), BlkExprBindings(beb) {}
-
+ BindingsTy ExprBindings;
+ AnalysisContext *ACtx;
+
+ Environment(BindingsTy eb, AnalysisContext *aCtx)
+ : ExprBindings(eb), ACtx(aCtx) {}
+
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(const Stmt* E) const {
- const SVal* X = SubExprBindings.lookup(cast<Expr>(E));
- return X ? *X : UnknownVal();
- }
-
- SVal LookupBlkExpr(const Stmt* E) const {
- const SVal* X = BlkExprBindings.lookup(E);
- return X ? *X : UnknownVal();
- }
-
+ typedef BindingsTy::iterator iterator;
+ iterator begin() const { return ExprBindings.begin(); }
+ iterator end() const { return ExprBindings.end(); }
+
SVal LookupExpr(const Stmt* E) const {
- const SVal* X = SubExprBindings.lookup(E);
- if (X) return *X;
- X = BlkExprBindings.lookup(E);
+ const SVal* X = ExprBindings.lookup(E);
return X ? *X : UnknownVal();
}
-
+
SVal GetSVal(const Stmt* Ex, ValueManager& ValMgr) const;
- SVal GetBlkExprSVal(const Stmt* Ex, ValueManager& ValMgr) const;
-
+
+ AnalysisContext &getAnalysisContext() const { return *ACtx; }
+
/// 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);
+ E->ExprBindings.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;
+ return ExprBindings == RHS.ExprBindings;
}
};
-
+
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, const Stmt* E) {
- return Environment(Env.SubExprBindings, F.Remove(Env.BlkExprBindings, E));
- }
-
- Environment RemoveSubExpr(const Environment& Env, const Stmt* E) {
- return Environment(F.Remove(Env.SubExprBindings, E), Env.BlkExprBindings);
+ Environment getInitialEnvironment(AnalysisContext *ACtx) {
+ return Environment(F.GetEmptyMap(), ACtx);
}
-
- Environment AddBlkExpr(const Environment& Env, const Stmt *E, SVal V) {
- return Environment(Env.SubExprBindings, F.Add(Env.BlkExprBindings, E, V));
- }
-
- Environment AddSubExpr(const Environment& Env, const 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, const 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);
+ Environment BindExpr(Environment Env, const Stmt *S, SVal V,
+ bool Invalidate);
+ Environment RemoveDeadBindings(Environment Env, const Stmt *S,
+ SymbolReaper &SymReaper, const GRState *ST,
+ llvm::SmallVectorImpl<const MemRegion*>& RegionRoots);
};
-
+
} // end clang namespace
#endif
diff --git a/include/clang/Analysis/PathSensitive/ExplodedGraph.h b/include/clang/Analysis/PathSensitive/ExplodedGraph.h
index 8494d93..a7bbdf9 100644
--- a/include/clang/Analysis/PathSensitive/ExplodedGraph.h
+++ b/include/clang/Analysis/PathSensitive/ExplodedGraph.h
@@ -16,6 +16,7 @@
#define LLVM_CLANG_ANALYSIS_EXPLODEDGRAPH
#include "clang/Analysis/ProgramPoint.h"
+#include "clang/Analysis/PathSensitive/AnalysisContext.h"
#include "clang/AST/Decl.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/FoldingSet.h"
@@ -25,193 +26,158 @@
#include "llvm/ADT/GraphTraits.h"
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/Support/Casting.h"
+#include "clang/Analysis/Support/BumpVector.h"
namespace clang {
-class GRCoreEngineImpl;
-class ExplodedNodeImpl;
+class GRState;
class CFG;
class ASTContext;
-
-class GRStmtNodeBuilderImpl;
-class GRBranchNodeBuilderImpl;
-class GRIndirectGotoNodeBuilderImpl;
-class GRSwitchNodeBuilderImpl;
-class GREndPathNodebuilderImpl;
+class ExplodedGraph;
//===----------------------------------------------------------------------===//
// 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 ExplodedNode : public llvm::FoldingSetNode {
+ friend class ExplodedGraph;
+ friend class GRCoreEngine;
+ friend class GRStmtNodeBuilder;
+ friend class GRBranchNodeBuilder;
+ friend class GRIndirectGotoNodeBuilder;
+ friend class GRSwitchNodeBuilder;
+ friend class GREndPathNodeBuilder;
+
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());
+ ExplodedNode *getNode() const {
+ return reinterpret_cast<ExplodedNode*>(getPtr());
}
-
+
public:
NodeGroup() : P(0) {}
-
- ~NodeGroup();
-
- ExplodedNodeImpl** begin() const;
-
- ExplodedNodeImpl** end() const;
-
+
+ ExplodedNode **begin() const;
+
+ ExplodedNode **end() const;
+
unsigned size() const;
-
- bool empty() const { return size() == 0; }
-
- void addNode(ExplodedNodeImpl* N);
-
+
+ bool empty() const { return (P & ~Mask) == 0; }
+
+ void addNode(ExplodedNode* N, ExplodedGraph &G);
+
void setFlag() {
- assert (P == 0);
+ 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;
-
+ const GRState* 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:
-
+
+ explicit ExplodedNode(const ProgramPoint& loc, const GRState* state)
+ : Location(loc), State(state) {}
+
/// 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);
+ const LocationContext *getLocationContext() const {
+ return getLocation().getLocationContext();
}
-};
+ const Decl &getCodeDecl() const { return *getLocationContext()->getDecl(); }
-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);
+ CFG &getCFG() const { return *getLocationContext()->getCFG(); }
+
+ ParentMap &getParentMap() const {return getLocationContext()->getParentMap();}
+
+ LiveVariables &getLiveVariables() const {
+ return *getLocationContext()->getLiveVariables();
}
-
- // Profiling (for FoldingSet).
-
- static inline void Profile(llvm::FoldingSetNodeID& ID,
- const ProgramPoint& Loc,
- const StateTy* state) {
+
+ const GRState* getState() const { return State; }
+
+ template <typename T>
+ const T* getLocationAs() const { return llvm::dyn_cast<T>(&Location); }
+
+ static void Profile(llvm::FoldingSetNodeID &ID,
+ const ProgramPoint& Loc, const GRState* state) {
ID.Add(Loc);
- GRTrait<StateTy>::Profile(ID, state);
+ ID.AddPointer(state);
}
-
- inline void Profile(llvm::FoldingSetNodeID& ID) const {
+
+ void Profile(llvm::FoldingSetNodeID& ID) const {
Profile(ID, getLocation(), getState());
}
-
- void addPredecessor(ExplodedNode* V) {
- ExplodedNodeImpl::addPredecessor(V);
- }
-
+
+ /// addPredeccessor - Adds a predecessor to the current node, and
+ /// in tandem add this node as a successor of the other node.
+ void addPredecessor(ExplodedNode* V, ExplodedGraph &G);
+
+ 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(); }
+
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(); }
+ pred_iterator pred_begin() { return Preds.begin(); }
+ pred_iterator pred_end() { return 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(); }
+ succ_iterator succ_begin() { return Succs.begin(); }
+ succ_iterator succ_end() { return Succs.end(); }
const_succ_iterator succ_begin() const {
return const_cast<ExplodedNode*>(this)->succ_begin();
@@ -219,23 +185,40 @@ public:
const_succ_iterator succ_end() const {
return const_cast<ExplodedNode*>(this)->succ_end();
}
+
+ // For debugging.
+
+public:
+
+ class Auditor {
+ public:
+ virtual ~Auditor();
+ virtual void AddEdge(ExplodedNode* Src, ExplodedNode* Dst) = 0;
+ };
+
+ static void SetAuditor(Auditor* A);
};
-class InterExplodedGraphMapImpl;
+// FIXME: Is this class necessary?
+class InterExplodedGraphMap {
+ llvm::DenseMap<const ExplodedNode*, ExplodedNode*> M;
+ friend class ExplodedGraph;
-class ExplodedGraphImpl {
+public:
+ ExplodedNode* getMappedNode(const ExplodedNode* N) const;
+
+ InterExplodedGraphMap() {};
+ virtual ~InterExplodedGraphMap() {}
+};
+
+class ExplodedGraph {
protected:
- friend class GRCoreEngineImpl;
- friend class GRStmtNodeBuilderImpl;
- friend class GRBranchNodeBuilderImpl;
- friend class GRIndirectGotoNodeBuilderImpl;
- friend class GRSwitchNodeBuilderImpl;
- friend class GREndPathNodeBuilderImpl;
-
+ friend class GRCoreEngine;
+
// Type definitions.
- typedef llvm::SmallVector<ExplodedNodeImpl*,2> RootsTy;
- typedef llvm::SmallVector<ExplodedNodeImpl*,10> EndNodesTy;
-
+ typedef llvm::SmallVector<ExplodedNode*,2> RootsTy;
+ typedef llvm::SmallVector<ExplodedNode*,10> EndNodesTy;
+
/// Roots - The roots of the simulation graph. Usually there will be only
/// one, but clients are free to establish multiple subgraphs within a single
/// SimulGraph. Moreover, these subgraphs can often merge when paths from
@@ -245,338 +228,199 @@ protected:
/// 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;
-
+
+ /// Nodes - The nodes in the graph.
+ llvm::FoldingSet<ExplodedNode> Nodes;
+
+ /// BVC - Allocator and context for allocating nodes and their predecessor
+ /// and successor groups.
+ BumpVectorContext BVC;
+
/// 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;
+public:
+ /// 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.
+
+ ExplodedNode* getNode(const ProgramPoint& L, const GRState *State,
+ bool* IsNew = 0);
+
+ ExplodedGraph* MakeEmptyGraph() const {
+ return new ExplodedGraph(Ctx);
+ }
/// addRoot - Add an untyped node to the set of roots.
- ExplodedNodeImpl* addRoot(ExplodedNodeImpl* V) {
+ ExplodedNode* addRoot(ExplodedNode* V) {
Roots.push_back(V);
return V;
}
/// addEndOfPath - Add an untyped node to the set of EOP nodes.
- ExplodedNodeImpl* addEndOfPath(ExplodedNodeImpl* V) {
+ ExplodedNode* addEndOfPath(ExplodedNode* 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() {}
+ ExplodedGraph(ASTContext& ctx) : Ctx(ctx), NumNodes(0) {}
+
+ ~ExplodedGraph() {}
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 ExplodedNode NodeTy;
+ typedef llvm::FoldingSet<ExplodedNode> AllNodesTy;
typedef NodeTy** roots_iterator;
- typedef const NodeTy** const_roots_iterator;
+ typedef NodeTy* const * 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();
- }
+ typedef NodeTy* const * const_eop_iterator;
+ typedef AllNodesTy::iterator node_iterator;
+ typedef AllNodesTy::const_iterator const_node_iterator;
- 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();
- }
+ node_iterator nodes_begin() { return Nodes.begin(); }
- 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>*>
+ 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 Roots.begin(); }
+
+ roots_iterator roots_end() { return Roots.end(); }
+
+ const_roots_iterator roots_begin() const { return Roots.begin(); }
+
+ const_roots_iterator roots_end() const { return Roots.end(); }
+
+ eop_iterator eop_begin() { return EndNodes.begin(); }
+
+ eop_iterator eop_end() { return EndNodes.end(); }
+
+ const_eop_iterator eop_begin() const { return EndNodes.begin(); }
+
+ const_eop_iterator eop_end() const { return EndNodes.end(); }
+
+ llvm::BumpPtrAllocator & getAllocator() { return BVC.getAllocator(); }
+ BumpVectorContext &getNodeAllocator() { return BVC; }
+
+ ASTContext& getContext() { return Ctx; }
+
+ typedef llvm::DenseMap<const ExplodedNode*, ExplodedNode*> NodeMap;
+
+ std::pair<ExplodedGraph*, InterExplodedGraphMap*>
Trim(const NodeTy* const* NBeg, const NodeTy* const* NEnd,
- llvm::DenseMap<const void*, const void*> *InverseMap = 0) const {
-
- 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());
- }
+ llvm::DenseMap<const void*, const void*> *InverseMap = 0) const;
+
+ ExplodedGraph* TrimInternal(const ExplodedNode* const * NBeg,
+ const ExplodedNode* const * NEnd,
+ InterExplodedGraphMap *M,
+ llvm::DenseMap<const void*, const void*> *InverseMap) const;
};
-template <typename StateTy>
class ExplodedNodeSet {
-
- typedef ExplodedNode<StateTy> NodeTy;
- typedef llvm::SmallPtrSet<NodeTy*,5> ImplTy;
+ typedef llvm::SmallPtrSet<ExplodedNode*,5> ImplTy;
ImplTy Impl;
-
+
public:
- ExplodedNodeSet(NodeTy* N) {
- assert (N && !static_cast<ExplodedNodeImpl*>(N)->isSink());
+ ExplodedNodeSet(ExplodedNode* N) {
+ assert (N && !static_cast<ExplodedNode*>(N)->isSink());
Impl.insert(N);
}
-
+
ExplodedNodeSet() {}
-
- inline void Add(NodeTy* N) {
- if (N && !static_cast<ExplodedNodeImpl*>(N)->isSink()) Impl.insert(N);
+
+ inline void Add(ExplodedNode* N) {
+ if (N && !static_cast<ExplodedNode*>(N)->isSink()) Impl.insert(N);
+ }
+
+ ExplodedNodeSet& operator=(const ExplodedNodeSet &X) {
+ Impl = X.Impl;
+ return *this;
}
-
- typedef typename ImplTy::iterator iterator;
- typedef typename ImplTy::const_iterator const_iterator;
+
+ typedef ImplTy::iterator iterator;
+ typedef 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;
+ template<> struct GraphTraits<clang::ExplodedNode*> {
+ typedef clang::ExplodedNode NodeType;
+ typedef 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;
+
+ template<> struct GraphTraits<const clang::ExplodedNode*> {
+ typedef const clang::ExplodedNode NodeType;
+ typedef NodeType::const_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
index eca591d..015c82e 100644
--- a/include/clang/Analysis/PathSensitive/GRAuditor.h
+++ b/include/clang/Analysis/PathSensitive/GRAuditor.h
@@ -1,5 +1,5 @@
//==- GRAuditor.h - Observers of the creation of ExplodedNodes------*- C++ -*-//
-//
+//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
@@ -18,22 +18,18 @@
#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 ExplodedNode;
+class GRStateManager;
+
class GRAuditor {
public:
- typedef ExplodedNode<STATE> NodeTy;
- typedef typename STATE::ManagerTy ManagerTy;
-
virtual ~GRAuditor() {}
- virtual bool Audit(NodeTy* N, ManagerTy& M) = 0;
+ virtual bool Audit(ExplodedNode* N, GRStateManager& M) = 0;
};
-
-
+
+
} // end clang namespace
#endif
diff --git a/include/clang/Analysis/PathSensitive/GRBlockCounter.h b/include/clang/Analysis/PathSensitive/GRBlockCounter.h
index b4fd270..67ed953 100644
--- a/include/clang/Analysis/PathSensitive/GRBlockCounter.h
+++ b/include/clang/Analysis/PathSensitive/GRBlockCounter.h
@@ -1,5 +1,5 @@
//==- GRBlockCounter.h - ADT for counting block visits -------------*- C++ -*-//
-//
+//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
@@ -24,27 +24,27 @@ namespace clang {
class GRBlockCounter {
void* Data;
-
- GRBlockCounter(void* D) : Data(D) {}
+
+ 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
index 0fbdbde..02e0b027 100644
--- a/include/clang/Analysis/PathSensitive/GRCoreEngine.h
+++ b/include/clang/Analysis/PathSensitive/GRCoreEngine.h
@@ -1,5 +1,5 @@
-//==- GRCoreEngine.h - Path-Sensitive Dataflow Engine ------------------*- C++ -*-//
-//
+//==- GRCoreEngine.h - Path-Sensitive Dataflow Engine --------------*- C++ -*-//
+//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
@@ -20,646 +20,416 @@
#include "clang/Analysis/PathSensitive/GRWorkList.h"
#include "clang/Analysis/PathSensitive/GRBlockCounter.h"
#include "clang/Analysis/PathSensitive/GRAuditor.h"
+#include "clang/Analysis/PathSensitive/GRSubEngine.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
+/// GRCoreEngine - 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)
+/// The template class GRCoreEngine (which subclasses GRCoreEngine)
/// 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;
-
+class GRCoreEngine {
+ friend class GRStmtNodeBuilder;
+ friend class GRBranchNodeBuilder;
+ friend class GRIndirectGotoNodeBuilder;
+ friend class GRSwitchNodeBuilder;
+ friend class GREndPathNodeBuilder;
+
+ GRSubEngine& SubEngine;
+
/// G - The simulation graph. Each node is a (location,state) pair.
- llvm::OwningPtr<ExplodedGraphImpl> G;
-
+ llvm::OwningPtr<ExplodedGraph> 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 GenerateNode(const ProgramPoint& Loc, const GRState* State,
+ ExplodedNode* Pred);
+
+ void HandleBlockEdge(const BlockEdge& E, ExplodedNode* Pred);
+ void HandleBlockEntrance(const BlockEntrance& E, ExplodedNode* Pred);
+ void HandleBlockExit(CFGBlock* B, ExplodedNode* Pred);
void HandlePostStmt(const PostStmt& S, CFGBlock* B,
- unsigned StmtIdx, ExplodedNodeImpl *Pred);
-
+ unsigned StmtIdx, ExplodedNode *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;
+ ExplodedNode* Pred);
+
+ /// Get the initial state from the subengine.
+ const GRState* getInitialState(const LocationContext *InitLoc) {
+ return SubEngine.getInitialState(InitLoc);
+ }
+
+ void ProcessEndPath(GREndPathNodeBuilder& Builder);
+
+ void ProcessStmt(Stmt* S, GRStmtNodeBuilder& Builder);
+
- virtual void ProcessStmt(Stmt* S, GRStmtNodeBuilderImpl& Builder) = 0;
+ bool ProcessBlockEntrance(CFGBlock* Blk, const GRState* State,
+ GRBlockCounter BC);
- virtual void ProcessBranch(Stmt* Condition, Stmt* Terminator,
- GRBranchNodeBuilderImpl& Builder) = 0;
- virtual void ProcessIndirectGoto(GRIndirectGotoNodeBuilderImpl& Builder) = 0;
-
- virtual void ProcessSwitch(GRSwitchNodeBuilderImpl& Builder) = 0;
+ void ProcessBranch(Stmt* Condition, Stmt* Terminator,
+ GRBranchNodeBuilder& Builder);
+
+
+ void ProcessIndirectGoto(GRIndirectGotoNodeBuilder& Builder);
+
+
+ void ProcessSwitch(GRSwitchNodeBuilder& Builder);
private:
- GRCoreEngineImpl(const GRCoreEngineImpl&); // Do not implement.
- GRCoreEngineImpl& operator=(const GRCoreEngineImpl&);
-
-protected:
- GRCoreEngineImpl(ExplodedGraphImpl* g, GRWorkList* wl)
- : G(g), WList(wl), BCounterFactory(g->getAllocator()) {}
-
+ GRCoreEngine(const GRCoreEngine&); // Do not implement.
+ GRCoreEngine& operator=(const GRCoreEngine&);
+
public:
+ /// Construct a GRCoreEngine object to analyze the provided CFG using
+ /// a DFS exploration of the exploded graph.
+ GRCoreEngine(ASTContext& ctx, GRSubEngine& subengine)
+ : SubEngine(subengine), G(new ExplodedGraph(ctx)),
+ WList(GRWorkList::MakeBFS()),
+ BCounterFactory(G->getAllocator()) {}
+
+ /// 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(ASTContext& ctx, GRWorkList* wlist, GRSubEngine& subengine)
+ : SubEngine(subengine), G(new ExplodedGraph(ctx)), WList(wlist),
+ BCounterFactory(G->getAllocator()) {}
+
+ ~GRCoreEngine() {
+ delete WList;
+ }
+
+ /// getGraph - Returns the exploded graph.
+ ExplodedGraph& getGraph() { return *G.get(); }
+
+ /// takeGraph - Returns the exploded graph. Ownership of the graph is
+ /// transfered to the caller.
+ ExplodedGraph* takeGraph() { return G.take(); }
+
/// 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(); }
+ bool ExecuteWorkList(const LocationContext *L, unsigned Steps);
};
-
-class GRStmtNodeBuilderImpl {
- GRCoreEngineImpl& Eng;
+
+class GRStmtNodeBuilder {
+ GRCoreEngine& Eng;
CFGBlock& B;
const unsigned Idx;
- ExplodedNodeImpl* Pred;
- ExplodedNodeImpl* LastNode;
-
- typedef llvm::SmallPtrSet<ExplodedNodeImpl*,5> DeferredTy;
+ ExplodedNode* Pred;
+ ExplodedNode* LastNode;
+ GRStateManager& Mgr;
+ GRAuditor* Auditor;
+
+public:
+ bool PurgingDeadSymbols;
+ bool BuildSinks;
+ bool HasGeneratedNode;
+ ProgramPoint::Kind PointKind;
+ const void *Tag;
+
+ const GRState* CleanedState;
+
+
+ typedef llvm::SmallPtrSet<ExplodedNode*,5> DeferredTy;
DeferredTy Deferred;
-
- void GenerateAutoTransition(ExplodedNodeImpl* N);
-
+
+ void GenerateAutoTransition(ExplodedNode* N);
+
public:
- GRStmtNodeBuilderImpl(CFGBlock* b, unsigned idx,
- ExplodedNodeImpl* N, GRCoreEngineImpl* e);
-
- ~GRStmtNodeBuilderImpl();
-
- ExplodedNodeImpl* getBasePredecessor() const { return Pred; }
-
- ExplodedNodeImpl* getLastNode() const {
+ GRStmtNodeBuilder(CFGBlock* b, unsigned idx, ExplodedNode* N,
+ GRCoreEngine* e, GRStateManager &mgr);
+
+ ~GRStmtNodeBuilder();
+
+ ExplodedNode* getBasePredecessor() const { return Pred; }
+
+ ExplodedNode* getLastNode() const {
return LastNode ? (LastNode->isSink() ? NULL : LastNode) : NULL;
}
-
+
+ // FIXME: This should not be exposed.
+ GRWorkList *getWorkList() { return Eng.WList; }
+
+ void SetCleanedState(const GRState* St) {
+ CleanedState = St;
+ }
+
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);
+ ExplodedNode* generateNode(PostStmt PP,const GRState* St,ExplodedNode* Pred) {
+ HasGeneratedNode = true;
+ return generateNodeInternal(PP, St, Pred);
}
-
- 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);
+
+ ExplodedNode* generateNode(const Stmt *S, const GRState *St,
+ ExplodedNode *Pred, ProgramPoint::Kind K) {
+ HasGeneratedNode = true;
+
+ if (PurgingDeadSymbols)
+ K = ProgramPoint::PostPurgeDeadSymbolsKind;
+
+ return generateNodeInternal(S, St, Pred, K, Tag);
}
-
+
+ ExplodedNode* generateNode(const Stmt *S, const GRState *St,
+ ExplodedNode *Pred) {
+ return generateNode(S, St, Pred, PointKind);
+ }
+
+ ExplodedNode*
+ generateNodeInternal(const ProgramPoint &PP, const GRState* State,
+ ExplodedNode* Pred);
+
+ ExplodedNode*
+ generateNodeInternal(const Stmt* S, const GRState* State, ExplodedNode* Pred,
+ ProgramPoint::Kind K = ProgramPoint::PostStmtKind,
+ const void *tag = 0);
+
/// 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);
- }
+ void setAuditor(GRAuditor* A) { Auditor = A; }
-
- GRBlockCounter getBlockCounter() const {
- return NB.getBlockCounter();
- }
-
- unsigned getCurrentBlockCount() const {
- return NB.getCurrentBlockCount();
- }
-
- const StateTy* GetState(NodeTy* Pred) const {
- if ((ExplodedNodeImpl*) Pred == NB.getBasePredecessor())
+ const GRState* GetState(ExplodedNode* Pred) const {
+ if ((ExplodedNode*) Pred == 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) {
+
+ ExplodedNode* MakeNode(ExplodedNodeSet& Dst, Stmt* S, ExplodedNode* Pred,
+ const GRState* 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);
-
+
+ ExplodedNode* MakeNode(ExplodedNodeSet& Dst, Stmt* S, ExplodedNode* Pred,
+ const GRState* St, ProgramPoint::Kind K) {
+
+ const GRState* 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) {
+
+ ExplodedNode* 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) {
+
+ ExplodedNode* MakeSinkNode(ExplodedNodeSet& Dst, Stmt* S,
+ ExplodedNode* Pred, const GRState* St) {
bool Tmp = BuildSinks;
BuildSinks = true;
- NodeTy* N = MakeNode(Dst, S, Pred, St);
+ ExplodedNode* 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;
+
+class GRBranchNodeBuilder {
+ GRCoreEngine& Eng;
CFGBlock* Src;
CFGBlock* DstT;
CFGBlock* DstF;
- ExplodedNodeImpl* Pred;
+ ExplodedNode* Pred;
- typedef llvm::SmallVector<ExplodedNodeImpl*,3> DeferredTy;
+ typedef llvm::SmallVector<ExplodedNode*,3> DeferredTy;
DeferredTy Deferred;
-
+
bool GeneratedTrue;
bool GeneratedFalse;
-
+ bool InFeasibleTrue;
+ bool InFeasibleFalse;
+
public:
- GRBranchNodeBuilderImpl(CFGBlock* src, CFGBlock* dstT, CFGBlock* dstF,
- ExplodedNodeImpl* pred, GRCoreEngineImpl* e)
+ GRBranchNodeBuilder(CFGBlock* src, CFGBlock* dstT, CFGBlock* dstF,
+ ExplodedNode* pred, GRCoreEngine* 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; }
+ GeneratedTrue(false), GeneratedFalse(false),
+ InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) {}
+
+ ~GRBranchNodeBuilder();
+
+ ExplodedNode* getPredecessor() const { return Pred; }
+
+ const ExplodedGraph& getGraph() const { return *Eng.G; }
+
GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
-
- ExplodedNodeImpl* generateNodeImpl(const void* State, bool branch);
-
+
+ ExplodedNode* generateNode(const GRState* 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();
+ void markInfeasible(bool branch) {
+ if (branch)
+ InFeasibleTrue = GeneratedTrue = true;
+ else
+ InFeasibleFalse = GeneratedFalse = true;
}
- NodeTy* generateNode(const StateTy* St, bool branch) {
- return static_cast<NodeTy*>(NB.generateNodeImpl(St, branch));
+ bool isFeasible(bool branch) {
+ return branch ? !InFeasibleTrue : !InFeasibleFalse;
}
-
- GRBlockCounter getBlockCounter() const {
- return NB.getBlockCounter();
- }
-
- CFGBlock* getTargetBlock(bool branch) const {
- return NB.getTargetBlock(branch);
- }
-
- void markInfeasible(bool branch) {
- NB.markInfeasible(branch);
+
+ const GRState* getState() const {
+ return getPredecessor()->getState();
}
};
-
-class GRIndirectGotoNodeBuilderImpl {
- GRCoreEngineImpl& Eng;
+
+class GRIndirectGotoNodeBuilder {
+ GRCoreEngine& Eng;
CFGBlock* Src;
CFGBlock& DispatchBlock;
Expr* E;
- ExplodedNodeImpl* Pred;
+ ExplodedNode* Pred;
+
public:
- GRIndirectGotoNodeBuilderImpl(ExplodedNodeImpl* pred, CFGBlock* src,
- Expr* e, CFGBlock* dispatch,
- GRCoreEngineImpl* eng)
+ GRIndirectGotoNodeBuilder(ExplodedNode* pred, CFGBlock* src, Expr* e,
+ CFGBlock* dispatch, GRCoreEngine* eng)
: Eng(*eng), Src(src), DispatchBlock(*dispatch), E(e), Pred(pred) {}
-
- class Iterator {
+ class iterator {
CFGBlock::succ_iterator I;
-
- friend class GRIndirectGotoNodeBuilderImpl;
- Iterator(CFGBlock::succ_iterator i) : I(i) {}
+
+ friend class GRIndirectGotoNodeBuilder;
+ iterator(CFGBlock::succ_iterator i) : I(i) {}
public:
-
- Iterator& operator++() { ++I; return *this; }
- bool operator!=(const Iterator& X) const { return I != X.I; }
-
+
+ iterator& operator++() { ++I; return *this; }
+ bool operator!=(const iterator& X) const { return I != X.I; }
+
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;
+ iterator begin() { return iterator(DispatchBlock.succ_begin()); }
+ iterator end() { return iterator(DispatchBlock.succ_end()); }
-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());
- }
+ ExplodedNode* generateNode(const iterator& I, const GRState* State,
+ bool isSink = false);
+
+ Expr* getTarget() const { return E; }
+
+ const GRState* getState() const { return Pred->State; }
};
-
-class GRSwitchNodeBuilderImpl {
- GRCoreEngineImpl& Eng;
+
+class GRSwitchNodeBuilder {
+ GRCoreEngine& Eng;
CFGBlock* Src;
Expr* Condition;
- ExplodedNodeImpl* Pred;
+ ExplodedNode* Pred;
+
public:
- GRSwitchNodeBuilderImpl(ExplodedNodeImpl* pred, CFGBlock* src,
- Expr* condition, GRCoreEngineImpl* eng)
+ GRSwitchNodeBuilder(ExplodedNode* pred, CFGBlock* src,
+ Expr* condition, GRCoreEngine* eng)
: Eng(*eng), Src(src), Condition(condition), Pred(pred) {}
-
- class Iterator {
+
+ class iterator {
CFGBlock::succ_reverse_iterator I;
-
- friend class GRSwitchNodeBuilderImpl;
- Iterator(CFGBlock::succ_reverse_iterator i) : I(i) {}
+
+ friend class GRSwitchNodeBuilder;
+ iterator(CFGBlock::succ_reverse_iterator i) : I(i) {}
+
public:
-
- Iterator& operator++() { ++I; return *this; }
- bool operator!=(const Iterator& X) const { return I != X.I; }
-
+ iterator& operator++() { ++I; return *this; }
+ bool operator!=(const iterator& X) const { return I != X.I; }
+
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);
-
+
+ iterator begin() { return iterator(Src->succ_rbegin()+1); }
+ iterator end() { return iterator(Src->succ_rend()); }
+
+ ExplodedNode* generateCaseStmtNode(const iterator& I, const GRState* State);
+
+ ExplodedNode* generateDefaultCaseNode(const GRState* State,
+ bool isSink = false);
+
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());
- }
+ const GRState* getState() const { return Pred->State; }
};
-
-class GREndPathNodeBuilderImpl {
- GRCoreEngineImpl& Eng;
+class GREndPathNodeBuilder {
+ GRCoreEngine& Eng;
CFGBlock& B;
- ExplodedNodeImpl* Pred;
+ ExplodedNode* 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; }
-};
+ GREndPathNodeBuilder(CFGBlock* b, ExplodedNode* N, GRCoreEngine* e)
+ : Eng(*e), B(*b), Pred(N), HasGeneratedNode(false) {}
+ ~GREndPathNodeBuilder();
+
+ ExplodedNode* getPredecessor() const { return Pred; }
-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));
+ return Eng.WList->getBlockCounter();
}
-
- 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);
+ unsigned getCurrentBlockCount() const {
+ return getBlockCounter().getNumVisited(B.getBlockID());
}
- 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());
+ ExplodedNode* generateNode(const GRState* State, const void *tag = 0,
+ ExplodedNode *P = 0);
+
+ CFGBlock* getBlock() const { return &B; }
+
+ const GRState* getState() const {
+ return getPredecessor()->getState();
}
};
diff --git a/include/clang/Analysis/PathSensitive/GRExprEngine.h b/include/clang/Analysis/PathSensitive/GRExprEngine.h
index f05bc68..e5c61e6 100644
--- a/include/clang/Analysis/PathSensitive/GRExprEngine.h
+++ b/include/clang/Analysis/PathSensitive/GRExprEngine.h
@@ -16,111 +16,86 @@
#ifndef LLVM_CLANG_ANALYSIS_GREXPRENGINE
#define LLVM_CLANG_ANALYSIS_GREXPRENGINE
+#include "clang/Analysis/PathSensitive/AnalysisManager.h"
+#include "clang/Analysis/PathSensitive/GRSubEngine.h"
#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/SValuator.h"
#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/AST/Type.h"
#include "clang/AST/ExprObjC.h"
-namespace clang {
-
+namespace clang {
+
class PathDiagnosticClient;
class Diagnostic;
class ObjCForCollectionStmt;
+ class Checker;
+
+class GRExprEngine : public GRSubEngine {
+ AnalysisManager &AMgr;
+
+ GRCoreEngine CoreEngine;
-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;
+ ExplodedGraph& G;
/// Builder - The current GRStmtNodeBuilder which is used when building the
/// nodes for a given statement.
- StmtNodeBuilder* Builder;
-
+ GRStmtNodeBuilder* 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;
-
+
/// SVator - SValuator object that creates SVals from expressions.
- llvm::OwningPtr<SValuator> SVator;
-
+ SValuator &SVator;
+
/// EntryNode - The immediate predecessor node.
- NodeTy* EntryNode;
+ ExplodedNode* EntryNode;
/// CleanedState - The state for EntryNode "cleaned" of all dead
/// variables and symbols (as determined by a liveness analysis).
- const GRState* CleanedState;
-
+ const 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;
+ std::vector<Checker*> Checkers;
- /// 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;
-
+ typedef llvm::SmallPtrSet<ExplodedNode*,2> ErrorNodes;
+ typedef llvm::DenseMap<ExplodedNode*, 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).
@@ -130,7 +105,7 @@ public:
/// 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;
@@ -138,65 +113,55 @@ public:
/// 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
+
+ /// UndefDeref - 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
+ /// 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
+
+ /// 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.
@@ -209,136 +174,124 @@ public:
/// 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(AnalysisManager &mgr);
~GRExprEngine();
-
- void ExecuteWorkList(unsigned Steps = 150000) {
- CoreEngine.ExecuteWorkList(Steps);
+
+ void ExecuteWorkList(const LocationContext *L, unsigned Steps = 150000) {
+ CoreEngine.ExecuteWorkList(L, 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(); }
-
+
+ AnalysisManager &getAnalysisManager() const { return AMgr; }
+
+ SValuator &getSValuator() { return SVator; }
+
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; }
-
+
+ void ViewGraph(ExplodedNode** Beg, ExplodedNode** End);
+
/// 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; }
+ const GRState* getInitialState(const LocationContext *InitLoc);
+
+ ExplodedGraph& getGraph() { return G; }
+ const ExplodedGraph& 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;
+
+ void registerCheck(Checker *check) {
+ Checkers.push_back(check);
}
-
- bool isUndefStore(const NodeTy* N) const {
- return N->isSink() && UndefStores.count(const_cast<NodeTy*>(N)) != 0;
+
+ bool isRetStackAddr(const ExplodedNode* N) const {
+ return N->isSink() && RetsStackAddr.count(const_cast<ExplodedNode*>(N)) != 0;
}
-
- bool isImplicitNullDeref(const NodeTy* N) const {
- return N->isSink() && ImplicitNullDeref.count(const_cast<NodeTy*>(N)) != 0;
+
+ bool isUndefControlFlow(const ExplodedNode* N) const {
+ return N->isSink() && UndefBranches.count(const_cast<ExplodedNode*>(N)) != 0;
}
-
- bool isExplicitNullDeref(const NodeTy* N) const {
- return N->isSink() && ExplicitNullDeref.count(const_cast<NodeTy*>(N)) != 0;
+
+ bool isUndefStore(const ExplodedNode* N) const {
+ return N->isSink() && UndefStores.count(const_cast<ExplodedNode*>(N)) != 0;
}
-
- bool isUndefDeref(const NodeTy* N) const {
- return N->isSink() && UndefDeref.count(const_cast<NodeTy*>(N)) != 0;
+
+ bool isImplicitNullDeref(const ExplodedNode* N) const {
+ return N->isSink() && ImplicitNullDeref.count(const_cast<ExplodedNode*>(N)) != 0;
}
-
- bool isImplicitBadDivide(const NodeTy* N) const {
- return N->isSink() && ImplicitBadDivides.count(const_cast<NodeTy*>(N)) != 0;
+
+ bool isExplicitNullDeref(const ExplodedNode* N) const {
+ return N->isSink() && ExplicitNullDeref.count(const_cast<ExplodedNode*>(N)) != 0;
}
-
- bool isExplicitBadDivide(const NodeTy* N) const {
- return N->isSink() && ExplicitBadDivides.count(const_cast<NodeTy*>(N)) != 0;
+
+ bool isUndefDeref(const ExplodedNode* N) const {
+ return N->isSink() && UndefDeref.count(const_cast<ExplodedNode*>(N)) != 0;
}
-
- bool isNoReturnCall(const NodeTy* N) const {
- return N->isSink() && NoReturnCalls.count(const_cast<NodeTy*>(N)) != 0;
+
+ bool isNoReturnCall(const ExplodedNode* N) const {
+ return N->isSink() && NoReturnCalls.count(const_cast<ExplodedNode*>(N)) != 0;
}
-
- bool isUndefResult(const NodeTy* N) const {
- return N->isSink() && UndefResults.count(const_cast<NodeTy*>(N)) != 0;
+
+ bool isUndefResult(const ExplodedNode* N) const {
+ return N->isSink() && UndefResults.count(const_cast<ExplodedNode*>(N)) != 0;
}
-
- bool isBadCall(const NodeTy* N) const {
- return N->isSink() && BadCalls.count(const_cast<NodeTy*>(N)) != 0;
+
+ bool isBadCall(const ExplodedNode* N) const {
+ return N->isSink() && BadCalls.count(const_cast<ExplodedNode*>(N)) != 0;
}
-
- bool isUndefArg(const NodeTy* N) const {
+
+ bool isUndefArg(const ExplodedNode* N) const {
return N->isSink() &&
- (UndefArgs.find(const_cast<NodeTy*>(N)) != UndefArgs.end() ||
- MsgExprUndefArgs.find(const_cast<NodeTy*>(N)) != MsgExprUndefArgs.end());
+ (UndefArgs.find(const_cast<ExplodedNode*>(N)) != UndefArgs.end() ||
+ MsgExprUndefArgs.find(const_cast<ExplodedNode*>(N)) != MsgExprUndefArgs.end());
}
-
- bool isUndefReceiver(const NodeTy* N) const {
- return N->isSink() && UndefReceivers.count(const_cast<NodeTy*>(N)) != 0;
+
+ bool isUndefReceiver(const ExplodedNode* N) const {
+ return N->isSink() && UndefReceivers.count(const_cast<ExplodedNode*>(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(); }
-
+ 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(); }
-
+ 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();
}
@@ -346,9 +299,9 @@ public:
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();
@@ -358,60 +311,42 @@ public:
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(); }
-
+ 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 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() {
+ oob_memacc_iterator implicit_oob_memacc_begin() {
return ImplicitOOBMemAccesses.begin();
}
oob_memacc_iterator implicit_oob_memacc_end() {
@@ -426,45 +361,45 @@ public:
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);
-
+ /// nodes by processing the 'effects' of a block-level statement.
+ void ProcessStmt(Stmt* S, GRStmtNodeBuilder& 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);
-
+ void ProcessBranch(Stmt* Condition, Stmt* Term, GRBranchNodeBuilder& builder);
+
/// ProcessIndirectGoto - Called by GRCoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a computed goto jump.
- void ProcessIndirectGoto(IndirectGotoNodeBuilder& builder);
-
+ void ProcessIndirectGoto(GRIndirectGotoNodeBuilder& builder);
+
/// ProcessSwitch - Called by GRCoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a switch statement.
- void ProcessSwitch(SwitchNodeBuilder& builder);
-
+ void ProcessSwitch(GRSwitchNodeBuilder& 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) {
+ void ProcessEndPath(GREndPathNodeBuilder& 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();
@@ -472,204 +407,198 @@ public:
const BasicValueFactory& getBasicVals() const {
return StateMgr.getBasicVals();
}
-
- ValueManager &getValueManager() { return ValMgr; }
+
+ 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) {
+ const GRState* GetState(ExplodedNode* N) {
return N == EntryNode ? CleanedState : N->getState();
}
-
+
public:
- NodeTy* MakeNode(NodeSet& Dst, Stmt* S, NodeTy* Pred, const GRState* St,
+ ExplodedNode* MakeNode(ExplodedNodeSet& Dst, Stmt* S, ExplodedNode* Pred, const GRState* St,
ProgramPoint::Kind K = ProgramPoint::PostStmtKind,
const void *tag = 0);
protected:
-
+ /// CheckerVisit - Dispatcher for performing checker-specific logic
+ /// at specific statements.
+ void CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src, bool isPrevisit);
+
/// 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);
-
+ void Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& 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);
-
+ void VisitLValue(Expr* Ex, ExplodedNode* Pred, ExplodedNodeSet& Dst);
+
/// VisitArraySubscriptExpr - Transfer function for array accesses.
- void VisitArraySubscriptExpr(ArraySubscriptExpr* Ex, NodeTy* Pred,
- NodeSet& Dst, bool asLValue);
-
+ void VisitArraySubscriptExpr(ArraySubscriptExpr* Ex, ExplodedNode* Pred,
+ ExplodedNodeSet& Dst, bool asLValue);
+
/// VisitAsmStmt - Transfer function logic for inline asm.
- void VisitAsmStmt(AsmStmt* A, NodeTy* Pred, NodeSet& Dst);
-
+ void VisitAsmStmt(AsmStmt* A, ExplodedNode* Pred, ExplodedNodeSet& Dst);
+
void VisitAsmStmtHelperOutputs(AsmStmt* A,
AsmStmt::outputs_iterator I,
AsmStmt::outputs_iterator E,
- NodeTy* Pred, NodeSet& Dst);
-
+ ExplodedNode* Pred, ExplodedNodeSet& Dst);
+
void VisitAsmStmtHelperInputs(AsmStmt* A,
AsmStmt::inputs_iterator I,
AsmStmt::inputs_iterator E,
- NodeTy* Pred, NodeSet& Dst);
-
+ ExplodedNode* Pred, ExplodedNodeSet& Dst);
+
/// VisitBinaryOperator - Transfer function logic for binary operators.
- void VisitBinaryOperator(BinaryOperator* B, NodeTy* Pred, NodeSet& Dst);
+ void VisitBinaryOperator(BinaryOperator* B, ExplodedNode* Pred, ExplodedNodeSet& Dst);
+
-
/// VisitCall - Transfer function for function calls.
- void VisitCall(CallExpr* CE, NodeTy* Pred,
+ void VisitCall(CallExpr* CE, ExplodedNode* Pred,
CallExpr::arg_iterator AI, CallExpr::arg_iterator AE,
- NodeSet& Dst);
- void VisitCallRec(CallExpr* CE, NodeTy* Pred,
+ ExplodedNodeSet& Dst);
+ void VisitCallRec(CallExpr* CE, ExplodedNode* Pred,
CallExpr::arg_iterator AI, CallExpr::arg_iterator AE,
- NodeSet& Dst, const FunctionProtoType *,
+ ExplodedNodeSet& 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);
+ void VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred, ExplodedNodeSet& 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);
-
+ void VisitCompoundLiteralExpr(CompoundLiteralExpr* CL, ExplodedNode* Pred,
+ ExplodedNodeSet& Dst, bool asLValue);
+
/// VisitDeclRefExpr - Transfer function logic for DeclRefExprs.
- void VisitDeclRefExpr(DeclRefExpr* DR, NodeTy* Pred, NodeSet& Dst,
- bool asLValue);
-
+ void VisitDeclRefExpr(DeclRefExpr* DR, ExplodedNode* Pred, ExplodedNodeSet& Dst,
+ bool asLValue);
+
/// VisitDeclStmt - Transfer function logic for DeclStmts.
- void VisitDeclStmt(DeclStmt* DS, NodeTy* Pred, NodeSet& Dst);
-
+ void VisitDeclStmt(DeclStmt* DS, ExplodedNode* Pred, ExplodedNodeSet& Dst);
+
/// VisitGuardedExpr - Transfer function logic for ?, __builtin_choose
- void VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R, NodeTy* Pred, NodeSet& Dst);
+ void VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R, ExplodedNode* Pred, ExplodedNodeSet& Dst);
- void VisitInitListExpr(InitListExpr* E, NodeTy* Pred, NodeSet& Dst);
+ void VisitInitListExpr(InitListExpr* E, ExplodedNode* Pred, ExplodedNodeSet& Dst);
/// VisitLogicalExpr - Transfer function logic for '&&', '||'
- void VisitLogicalExpr(BinaryOperator* B, NodeTy* Pred, NodeSet& Dst);
-
+ void VisitLogicalExpr(BinaryOperator* B, ExplodedNode* Pred, ExplodedNodeSet& Dst);
+
/// VisitMemberExpr - Transfer function for member expressions.
- void VisitMemberExpr(MemberExpr* M, NodeTy* Pred, NodeSet& Dst,bool asLValue);
-
+ void VisitMemberExpr(MemberExpr* M, ExplodedNode* Pred, ExplodedNodeSet& Dst,bool asLValue);
+
/// VisitObjCIvarRefExpr - Transfer function logic for ObjCIvarRefExprs.
- void VisitObjCIvarRefExpr(ObjCIvarRefExpr* DR, NodeTy* Pred, NodeSet& Dst,
- bool asLValue);
+ void VisitObjCIvarRefExpr(ObjCIvarRefExpr* DR, ExplodedNode* Pred, ExplodedNodeSet& 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);
-
+ void VisitObjCForCollectionStmt(ObjCForCollectionStmt* S, ExplodedNode* Pred,
+ ExplodedNodeSet& Dst);
+
+ void VisitObjCForCollectionStmtAux(ObjCForCollectionStmt* S, ExplodedNode* Pred,
+ ExplodedNodeSet& Dst, SVal ElementV);
+
/// VisitObjCMessageExpr - Transfer function for ObjC message expressions.
- void VisitObjCMessageExpr(ObjCMessageExpr* ME, NodeTy* Pred, NodeSet& Dst);
-
+ void VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred, ExplodedNodeSet& 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);
-
+ ExplodedNode* Pred, ExplodedNodeSet& Dst);
+
+ void VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, ExplodedNode* Pred,
+ ExplodedNodeSet& Dst);
+
/// VisitReturnStmt - Transfer function logic for return statements.
- void VisitReturnStmt(ReturnStmt* R, NodeTy* Pred, NodeSet& Dst);
-
+ void VisitReturnStmt(ReturnStmt* R, ExplodedNode* Pred, ExplodedNodeSet& Dst);
+
/// VisitSizeOfAlignOfExpr - Transfer function for sizeof.
- void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex, NodeTy* Pred,
- NodeSet& Dst);
-
+ void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex, ExplodedNode* Pred,
+ ExplodedNodeSet& Dst);
+
/// VisitUnaryOperator - Transfer function logic for unary operators.
- void VisitUnaryOperator(UnaryOperator* B, NodeTy* Pred, NodeSet& Dst,
+ void VisitUnaryOperator(UnaryOperator* B, ExplodedNode* Pred, ExplodedNodeSet& Dst,
bool asLValue);
-
- const GRState* CheckDivideZero(Expr* Ex, const GRState* St, NodeTy* Pred,
- SVal Denom);
-
+
+ const GRState* CheckDivideZero(Expr* Ex, const GRState* St, ExplodedNode* 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 SVator->EvalCast(cast<Loc>(X), CastT);
- else
- return SVator->EvalCast(cast<NonLoc>(X), CastT);
- }
-
+ void EvalEagerlyAssume(ExplodedNodeSet& Dst, ExplodedNodeSet& Src, Expr *Ex);
+
SVal EvalMinus(SVal X) {
- return X.isValid() ? SVator->EvalMinus(cast<NonLoc>(X)) : X;
+ return X.isValid() ? SVator.EvalMinus(cast<NonLoc>(X)) : X;
}
-
+
SVal EvalComplement(SVal X) {
- return X.isValid() ? SVator->EvalComplement(cast<NonLoc>(X)) : X;
+ return X.isValid() ? SVator.EvalComplement(cast<NonLoc>(X)) : X;
}
-
+
+ bool EvalBuiltinFunction(const FunctionDecl *FD, CallExpr *CE,
+ ExplodedNode *Pred, ExplodedNodeSet &Dst);
+
public:
-
- SVal EvalBinOp(BinaryOperator::Opcode op, NonLoc L, NonLoc R, QualType T) {
- return SVator->EvalBinOpNN(op, L, R, T);
- }
- SVal EvalBinOp(BinaryOperator::Opcode op, NonLoc L, SVal R, QualType T) {
- return R.isValid() ? SVator->EvalBinOpNN(op, L, cast<NonLoc>(R), T) : R;
+ SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode op,
+ NonLoc L, NonLoc R, QualType T) {
+ return SVator.EvalBinOpNN(state, op, L, R, T);
}
-
+
SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode op,
- SVal lhs, SVal rhs, QualType T);
+ NonLoc L, SVal R, QualType T) {
+ return R.isValid() ? SVator.EvalBinOpNN(state, op, L, cast<NonLoc>(R), T) : R;
+ }
-protected:
-
- void EvalCall(NodeSet& Dst, CallExpr* CE, SVal L, NodeTy* Pred);
+ SVal EvalBinOp(const GRState *ST, BinaryOperator::Opcode Op,
+ SVal LHS, SVal RHS, QualType T) {
+ return SVator.EvalBinOp(ST, Op, LHS, RHS, T);
+ }
- void EvalObjCMessageExpr(NodeSet& Dst, ObjCMessageExpr* ME, NodeTy* Pred) {
+protected:
+ void EvalCall(ExplodedNodeSet& Dst, CallExpr* CE, SVal L, ExplodedNode* Pred);
+
+ void EvalObjCMessageExpr(ExplodedNodeSet& Dst, ObjCMessageExpr* ME, ExplodedNode* 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,
+ void EvalReturn(ExplodedNodeSet& Dst, ReturnStmt* s, ExplodedNode* 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,
+ void EvalBind(ExplodedNodeSet& Dst, Expr* Ex, ExplodedNode* Pred,
const GRState* St, SVal location, SVal Val);
-
+
public:
- void EvalLoad(NodeSet& Dst, Expr* Ex, NodeTy* Pred,
+ void EvalLoad(ExplodedNodeSet& Dst, Expr* Ex, ExplodedNode* Pred,
const GRState* St, SVal location, const void *tag = 0);
-
- NodeTy* EvalLocation(Stmt* Ex, NodeTy* Pred,
+
+ ExplodedNode* EvalLocation(Stmt* Ex, ExplodedNode* Pred,
const GRState* St, SVal location,
const void *tag = 0);
-
- void EvalStore(NodeSet& Dst, Expr* E, NodeTy* Pred, const GRState* St,
+
+ void EvalStore(ExplodedNodeSet& Dst, Expr* E, ExplodedNode* Pred, const GRState* St,
SVal TargetLV, SVal Val, const void *tag = 0);
-
- void EvalStore(NodeSet& Dst, Expr* E, Expr* StoreE, NodeTy* Pred,
+
+ void EvalStore(ExplodedNodeSet& Dst, Expr* E, Expr* StoreE, ExplodedNode* 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
index 0f3a137..60db406 100644
--- a/include/clang/Analysis/PathSensitive/GRExprEngineBuilders.h
+++ b/include/clang/Analysis/PathSensitive/GRExprEngineBuilders.h
@@ -15,38 +15,15 @@
#ifndef LLVM_CLANG_ANALYSIS_GREXPRENGINE_BUILDERS
#define LLVM_CLANG_ANALYSIS_GREXPRENGINE_BUILDERS
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "clang/Analysis/Support/SaveAndRestore.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;
+ ExplodedNodeSet &Dst;
+ GRStmtNodeBuilder &B;
GRExprEngine& Eng;
- GRExprEngine::NodeTy* Pred;
+ ExplodedNode* Pred;
const GRState* state;
const Stmt* stmt;
const unsigned OldSize;
@@ -57,25 +34,25 @@ class GRStmtNodeBuilderRef {
private:
friend class GRExprEngine;
-
+
GRStmtNodeBuilderRef(); // do not implement
void operator=(const GRStmtNodeBuilderRef&); // do not implement
-
- GRStmtNodeBuilderRef(GRExprEngine::NodeSet &dst,
- GRExprEngine::StmtNodeBuilder &builder,
+
+ GRStmtNodeBuilderRef(ExplodedNodeSet &dst,
+ GRStmtNodeBuilder &builder,
GRExprEngine& eng,
- GRExprEngine::NodeTy* pred,
+ ExplodedNode* 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.
+ // 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);
@@ -85,14 +62,14 @@ public:
}
const GRState *getState() { return state; }
-
+
GRStateManager& getStateManager() {
return Eng.getStateManager();
}
-
- GRExprEngine::NodeTy* MakeNode(const GRState* state) {
- return B.MakeNode(Dst, const_cast<Stmt*>(stmt), Pred, state);
- }
+
+ ExplodedNode* MakeNode(const GRState* state) {
+ return B.MakeNode(Dst, const_cast<Stmt*>(stmt), Pred, state);
+ }
};
} // end clang namespace
diff --git a/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h b/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h
index e54b31d..978ff08 100644
--- a/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h
+++ b/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h
@@ -20,16 +20,16 @@
#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> {
+class ExplodedGraph;
+
+
+class GRSimpleAPICheck : public GRAuditor {
public:
GRSimpleAPICheck() {}
virtual ~GRSimpleAPICheck() {}
diff --git a/include/clang/Analysis/PathSensitive/GRState.h b/include/clang/Analysis/PathSensitive/GRState.h
index 0da8f52..d8b9d56 100644
--- a/include/clang/Analysis/PathSensitive/GRState.h
+++ b/include/clang/Analysis/PathSensitive/GRState.h
@@ -49,12 +49,12 @@ 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* 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;
@@ -66,68 +66,78 @@ template <typename T> struct GRStateTrait {
//===----------------------------------------------------------------------===//
class GRStateManager;
-
+
/// 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.
+public:
typedef llvm::ImmutableSet<llvm::APSInt*> IntSetTy;
- typedef llvm::ImmutableMap<void*, void*> GenericDataMap;
-
- typedef GRStateManager ManagerTy;
-
+ typedef llvm::ImmutableMap<void*, void*> GenericDataMap;
+
private:
void operator=(const GRState& R) const;
-
+
friend class GRStateManager;
- GRStateManager *Mgr;
+ GRStateManager *StateMgr;
Environment Env;
Store St;
// FIXME: Make these private.
public:
GenericDataMap GDM;
-
+
public:
-
+
/// This ctor is used when creating the first GRState object.
- GRState(GRStateManager *mgr, const Environment& env, Store st,
- GenericDataMap gdm)
- : Mgr(mgr),
+ GRState(GRStateManager *mgr, const Environment& env,
+ Store st, GenericDataMap gdm)
+ : StateMgr(mgr),
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(),
- Mgr(RHS.Mgr),
+ StateMgr(RHS.StateMgr),
Env(RHS.Env),
St(RHS.St),
GDM(RHS.GDM) {}
-
+
/// getStateManager - Return the GRStateManager associated with this state.
- GRStateManager &getStateManager() const { return *Mgr; }
-
+ GRStateManager &getStateManager() const {
+ return *StateMgr;
+ }
+
+ /// getAnalysisContext - Return the AnalysisContext associated with this
+ /// state.
+ AnalysisContext &getAnalysisContext() const {
+ return Env.getAnalysisContext();
+ }
+
/// 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; }
-
+
+ void setStore(Store s) { St = s; }
+
/// getGDM - Return the generic data map associated with this state.
GenericDataMap getGDM() const { return GDM; }
-
+
+ void setGDM(GenericDataMap gdm) { GDM = gdm; }
+
/// Profile - Profile the contents of a GRState object for use
/// in a FoldingSet.
static void Profile(llvm::FoldingSetNodeID& ID, const GRState* V) {
+ // FIXME: Do we need to include the AnalysisContext in the profile?
V->Env.Profile(ID);
ID.AddPointer(V->St);
V->GDM.Profile(ID);
@@ -138,28 +148,19 @@ public:
void Profile(llvm::FoldingSetNodeID& ID) const {
Profile(ID, this);
}
-
+
SVal LookupExpr(Expr* E) const {
return Env.LookupExpr(E);
}
-
+
/// makeWithStore - Return a GRState with the same values as the current
/// state with the exception of using the specified Store.
const GRState *makeWithStore(Store store) const;
-
- // 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(); }
-
+
BasicValueFactory &getBasicVals() const;
SymbolManager &getSymbolManager() const;
GRTransferFuncs &getTransferFuncs() const;
-
+
//==---------------------------------------------------------------------==//
// Constraints on values.
//==---------------------------------------------------------------------==//
@@ -192,91 +193,85 @@ public:
// FIXME: (a) should probably disappear since it is redundant with (b).
// (i.e., (b) could just be set to NULL).
//
-
- const GRState *assume(SVal condition, bool assumption) const;
-
- const GRState *assumeInBound(SVal idx, SVal upperBound,
+
+ const GRState *Assume(DefinedOrUnknownSVal cond, bool assumption) const;
+
+ const GRState *AssumeInBound(DefinedOrUnknownSVal idx,
+ DefinedOrUnknownSVal upperBound,
bool assumption) const;
-
+
//==---------------------------------------------------------------------==//
// Utility methods for getting regions.
//==---------------------------------------------------------------------==//
- const VarRegion* getRegion(const VarDecl* D) const;
-
- const MemRegion* getSelfRegion() const;
+ const VarRegion* getRegion(const VarDecl *D, const LocationContext *LC) const;
//==---------------------------------------------------------------------==//
// Binding and retrieving values to/from the environment and symbolic store.
//==---------------------------------------------------------------------==//
-
+
/// 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 CompoundLiteralExpr* CL,
SVal V) const;
-
- const GRState *bindExpr(const Stmt* Ex, SVal V, bool isBlkExpr,
- bool Invalidate) const;
-
- const GRState *bindExpr(const Stmt* Ex, SVal V, bool Invalidate = true) const;
-
- const GRState *bindBlkExpr(const Stmt *Ex, SVal V) const {
- return bindExpr(Ex, V, true, false);
- }
-
- const GRState *bindDecl(const VarDecl* VD, SVal IVal) const;
-
- const GRState *bindDeclWithNoInit(const VarDecl* VD) const;
-
+
+ const GRState *BindExpr(const Stmt *S, SVal V, bool Invalidate = true) const;
+
+ const GRState *bindDecl(const VarDecl *VD, const LocationContext *LC,
+ SVal V) const;
+
+ const GRState *bindDeclWithNoInit(const VarDecl *VD,
+ const LocationContext *LC) const;
+
const GRState *bindLoc(Loc location, SVal V) const;
-
+
const GRState *bindLoc(SVal location, SVal V) const;
-
+
const GRState *unbindLoc(Loc LV) const;
/// Get the lvalue for a variable reference.
- SVal getLValue(const VarDecl *decl) const;
-
+ SVal getLValue(const VarDecl *D, const LocationContext *LC) const;
+
/// Get the lvalue for a StringLiteral.
SVal getLValue(const StringLiteral *literal) const;
-
+
SVal getLValue(const CompoundLiteralExpr *literal) const;
-
+
/// Get the lvalue for an ivar reference.
SVal getLValue(const ObjCIvarDecl *decl, SVal base) const;
-
+
/// Get the lvalue for a field reference.
- SVal getLValue(SVal Base, const FieldDecl *decl) const;
-
+ SVal getLValue(const FieldDecl *decl, SVal Base) const;
+
/// Get the lvalue for an array index.
- SVal getLValue(QualType ElementType, SVal Base, SVal Idx) const;
-
+ SVal getLValue(QualType ElementType, SVal Idx, SVal Base) const;
+
const llvm::APSInt *getSymVal(SymbolRef sym) const;
SVal getSVal(const Stmt* Ex) const;
-
- SVal getBlkExprSVal(const Stmt* Ex) const;
-
+
SVal getSValAsScalarOrLoc(const Stmt *Ex) const;
-
+
SVal getSVal(Loc LV, QualType T = QualType()) const;
-
+
SVal getSVal(const MemRegion* R) const;
-
+
SVal getSValAsScalarOrLoc(const MemRegion *R) const;
+ const llvm::APSInt *getSymVal(SymbolRef sym);
+
bool scanReachableSymbols(SVal val, SymbolVisitor& visitor) const;
template <typename CB> CB scanReachableSymbols(SVal val) const;
-
+
//==---------------------------------------------------------------------==//
// Accessing the Generic Data Map (GDM).
//==---------------------------------------------------------------------==//
void* const* FindGDM(void* K) const;
-
+
template<typename T>
const GRState *add(typename GRStateTrait<T>::key_type K) const;
@@ -285,31 +280,31 @@ public:
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>
typename GRStateTrait<T>::context_type get_context() const;
-
-
+
+
template<typename T>
const GRState *remove(typename GRStateTrait<T>::key_type K) const;
template<typename T>
const GRState *remove(typename GRStateTrait<T>::key_type K,
typename GRStateTrait<T>::context_type C) const;
-
+
template<typename T>
const GRState *set(typename GRStateTrait<T>::data_type D) const;
-
+
template<typename T>
const GRState *set(typename GRStateTrait<T>::key_type K,
- typename GRStateTrait<T>::value_type E) const;
+ typename GRStateTrait<T>::value_type E) const;
template<typename T>
const GRState *set(typename GRStateTrait<T>::key_type K,
@@ -321,7 +316,7 @@ public:
void* const* d = FindGDM(GRStateTrait<T>::GDMIndex());
return GRStateTrait<T>::Contains(GRStateTrait<T>::MakeData(d), key);
}
-
+
// State pretty-printing.
class Printer {
public:
@@ -329,66 +324,55 @@ public:
virtual void Print(llvm::raw_ostream& Out, const GRState* state,
const char* nl, const char* sep) = 0;
};
-
+
// Pretty-printing.
void print(llvm::raw_ostream& Out, const char *nl = "\n",
- const char *sep = "") const;
+ const char *sep = "") const;
+
+ void printStdErr() const;
+
+ void printDOT(llvm::raw_ostream& Out) const;
- void printStdErr() const;
-
- void printDOT(llvm::raw_ostream& Out) 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;
+ 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)
+ 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.
//===----------------------------------------------------------------------===//
@@ -396,22 +380,21 @@ public:
class GRStateManager {
friend class GRExprEngine;
friend class GRState;
-
+
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;
@@ -421,52 +404,36 @@ private:
/// 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;
-
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));
+ llvm::BumpPtrAllocator& alloc)
+ : EnvMgr(alloc),
+ GDMFactory(alloc),
+ ValueMgr(alloc, Ctx, *this),
+ Alloc(alloc) {
+ StoreMgr.reset((*CreateStoreManager)(*this));
+ ConstraintMgr.reset((*CreateConstraintManager)(*this));
}
-
+
~GRStateManager();
- const GRState *getInitialState();
-
+ const GRState *getInitialState(const LocationContext *InitLoc);
+
ASTContext &getContext() { return ValueMgr.getContext(); }
- const ASTContext &getContext() const { return ValueMgr.getContext(); }
-
- const Decl &getCodeDecl() { return codedecl; }
+ const ASTContext &getContext() const { return ValueMgr.getContext(); }
+
GRTransferFuncs& getTransferFuncs() { return *TF; }
BasicValueFactory &getBasicVals() {
@@ -475,18 +442,17 @@ public:
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() {
@@ -495,28 +461,22 @@ public:
const MemRegionManager& getRegionManager() const {
return ValueMgr.getRegionManager();
}
-
+
StoreManager& getStoreManager() { return *StoreMgr; }
ConstraintManager& getConstraintManager() { return *ConstraintMgr; }
- const GRState* RemoveDeadBindings(const GRState* St, Stmt* Loc,
+ 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);
- }
-
public:
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 & manipulate the Store.
void iterBindings(const GRState* state, StoreManager::BindingsHandler& F) {
@@ -525,9 +485,9 @@ public:
const GRState* getPersistentState(GRState& Impl);
- bool isEqual(const GRState* state, Expr* Ex, const llvm::APSInt& V);
- bool isEqual(const GRState* state, Expr* Ex, uint64_t);
-
+ bool isEqual(const GRState* state, const Expr* Ex, const llvm::APSInt& V);
+ bool isEqual(const GRState* state, const Expr* Ex, uint64_t);
+
//==---------------------------------------------------------------------==//
// Generic Data Map methods.
//==---------------------------------------------------------------------==//
@@ -545,21 +505,21 @@ public:
// 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.
+
+ // 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(),
+
+ return addGDM(st, GRStateTrait<T>::GDMIndex(),
GRStateTrait<T>::MakeVoidPtr(GRStateTrait<T>::Set(st->get<T>(), K, V, C)));
}
@@ -575,22 +535,22 @@ public:
const GRState* remove(const GRState* st,
typename GRStateTrait<T>::key_type K,
typename GRStateTrait<T>::context_type C) {
-
- return addGDM(st, GRStateTrait<T>::GDMIndex(),
+
+ 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);
}
@@ -602,84 +562,96 @@ public:
ConstraintMgr->EndPath(St);
}
};
-
+
//===----------------------------------------------------------------------===//
// Out-of-line method definitions for GRState.
//===----------------------------------------------------------------------===//
-inline const VarRegion* GRState::getRegion(const VarDecl* D) const {
- return Mgr->getRegionManager().getVarRegion(D);
+inline const llvm::APSInt *GRState::getSymVal(SymbolRef sym) {
+ return getStateManager().getSymVal(this, sym);
}
-
-inline const MemRegion* GRState::getSelfRegion() const {
- return Mgr->StoreMgr->getSelfRegion(getStore());
+
+inline const VarRegion* GRState::getRegion(const VarDecl *D,
+ const LocationContext *LC) const {
+ return getStateManager().getRegionManager().getVarRegion(D, LC);
}
+
+inline const GRState *GRState::Assume(DefinedOrUnknownSVal Cond,
+ bool Assumption) const {
+ if (Cond.isUnknown())
+ return this;
-inline const GRState *GRState::assume(SVal Cond, bool Assumption) const {
- return Mgr->ConstraintMgr->Assume(this, Cond, Assumption);
+ return getStateManager().ConstraintMgr->Assume(this, cast<DefinedSVal>(Cond),
+ Assumption);
}
-inline const GRState *GRState::assumeInBound(SVal Idx, SVal UpperBound,
+inline const GRState *GRState::AssumeInBound(DefinedOrUnknownSVal Idx,
+ DefinedOrUnknownSVal UpperBound,
bool Assumption) const {
- return Mgr->ConstraintMgr->AssumeInBound(this, Idx, UpperBound, Assumption);
-}
+ if (Idx.isUnknown() || UpperBound.isUnknown())
+ return this;
+
+ ConstraintManager &CM = *getStateManager().ConstraintMgr;
+ return CM.AssumeInBound(this, cast<DefinedSVal>(Idx),
+ cast<DefinedSVal>(UpperBound), Assumption);
+}
inline const GRState *GRState::bindCompoundLiteral(const CompoundLiteralExpr* CL,
SVal V) const {
- return Mgr->StoreMgr->BindCompoundLiteral(this, CL, V);
+ return getStateManager().StoreMgr->BindCompoundLiteral(this, CL, V);
}
-
-inline const GRState *GRState::bindDecl(const VarDecl* VD, SVal IVal) const {
- return Mgr->StoreMgr->BindDecl(this, VD, IVal);
+
+inline const GRState *GRState::bindDecl(const VarDecl* VD,
+ const LocationContext *LC,
+ SVal IVal) const {
+ return getStateManager().StoreMgr->BindDecl(this, VD, LC, IVal);
}
-inline const GRState *GRState::bindDeclWithNoInit(const VarDecl* VD) const {
- return Mgr->StoreMgr->BindDeclWithNoInit(this, VD);
+inline const GRState *GRState::bindDeclWithNoInit(const VarDecl* VD,
+ const LocationContext *LC) const {
+ return getStateManager().StoreMgr->BindDeclWithNoInit(this, VD, LC);
}
-
+
inline const GRState *GRState::bindLoc(Loc LV, SVal V) const {
- return Mgr->StoreMgr->Bind(this, LV, V);
+ return getStateManager().StoreMgr->Bind(this, LV, V);
}
inline const GRState *GRState::bindLoc(SVal LV, SVal V) const {
return !isa<Loc>(LV) ? this : bindLoc(cast<Loc>(LV), V);
}
-
-inline SVal GRState::getLValue(const VarDecl* VD) const {
- return Mgr->StoreMgr->getLValueVar(this, VD);
+
+inline SVal GRState::getLValue(const VarDecl* VD,
+ const LocationContext *LC) const {
+ return getStateManager().StoreMgr->getLValueVar(VD, LC);
}
inline SVal GRState::getLValue(const StringLiteral *literal) const {
- return Mgr->StoreMgr->getLValueString(this, literal);
+ return getStateManager().StoreMgr->getLValueString(literal);
}
-
+
inline SVal GRState::getLValue(const CompoundLiteralExpr *literal) const {
- return Mgr->StoreMgr->getLValueCompoundLiteral(this, literal);
+ return getStateManager().StoreMgr->getLValueCompoundLiteral(literal);
}
inline SVal GRState::getLValue(const ObjCIvarDecl *D, SVal Base) const {
- return Mgr->StoreMgr->getLValueIvar(this, D, Base);
+ return getStateManager().StoreMgr->getLValueIvar(D, Base);
}
-
-inline SVal GRState::getLValue(SVal Base, const FieldDecl* D) const {
- return Mgr->StoreMgr->getLValueField(this, Base, D);
+
+inline SVal GRState::getLValue(const FieldDecl* D, SVal Base) const {
+ return getStateManager().StoreMgr->getLValueField(D, Base);
}
-
-inline SVal GRState::getLValue(QualType ElementType, SVal Base, SVal Idx) const{
- return Mgr->StoreMgr->getLValueElement(this, ElementType, Base, Idx);
+
+inline SVal GRState::getLValue(QualType ElementType, SVal Idx, SVal Base) const{
+ return getStateManager().StoreMgr->getLValueElement(ElementType, Idx, Base);
}
-
+
inline const llvm::APSInt *GRState::getSymVal(SymbolRef sym) const {
- return Mgr->getSymVal(this, sym);
-}
-
-inline SVal GRState::getSVal(const Stmt* Ex) const {
- return Env.GetSVal(Ex, Mgr->ValueMgr);
+ return getStateManager().getSymVal(this, sym);
}
-inline SVal GRState::getBlkExprSVal(const Stmt* Ex) const {
- return Env.GetBlkExprSVal(Ex, Mgr->ValueMgr);
+inline SVal GRState::getSVal(const Stmt* Ex) const {
+ return Env.GetSVal(Ex, getStateManager().ValueMgr);
}
inline SVal GRState::getSValAsScalarOrLoc(const Stmt *S) const {
@@ -688,69 +660,69 @@ inline SVal GRState::getSValAsScalarOrLoc(const Stmt *S) const {
if (Loc::IsLocType(T) || T->isIntegerType())
return getSVal(S);
}
-
+
return UnknownVal();
}
inline SVal GRState::getSVal(Loc LV, QualType T) const {
- return Mgr->StoreMgr->Retrieve(this, LV, T);
+ return getStateManager().StoreMgr->Retrieve(this, LV, T).getSVal();
}
inline SVal GRState::getSVal(const MemRegion* R) const {
- return Mgr->StoreMgr->Retrieve(this, loc::MemRegionVal(R));
+ return getStateManager().StoreMgr->Retrieve(this, loc::MemRegionVal(R)).getSVal();
}
-
+
inline BasicValueFactory &GRState::getBasicVals() const {
- return Mgr->getBasicVals();
+ return getStateManager().getBasicVals();
}
inline SymbolManager &GRState::getSymbolManager() const {
- return Mgr->getSymbolManager();
+ return getStateManager().getSymbolManager();
}
-
+
inline GRTransferFuncs &GRState::getTransferFuncs() const {
- return Mgr->getTransferFuncs();
+ return getStateManager().getTransferFuncs();
}
template<typename T>
const GRState *GRState::add(typename GRStateTrait<T>::key_type K) const {
- return Mgr->add<T>(this, K, get_context<T>());
+ return getStateManager().add<T>(this, K, get_context<T>());
}
-
+
template <typename T>
typename GRStateTrait<T>::context_type GRState::get_context() const {
- return Mgr->get_context<T>();
+ return getStateManager().get_context<T>();
}
-
+
template<typename T>
const GRState *GRState::remove(typename GRStateTrait<T>::key_type K) const {
- return Mgr->remove<T>(this, K, get_context<T>());
+ return getStateManager().remove<T>(this, K, get_context<T>());
}
template<typename T>
const GRState *GRState::remove(typename GRStateTrait<T>::key_type K,
typename GRStateTrait<T>::context_type C) const {
- return Mgr->remove<T>(this, K, C);
+ return getStateManager().remove<T>(this, K, C);
}
-
+
template<typename T>
const GRState *GRState::set(typename GRStateTrait<T>::data_type D) const {
- return Mgr->set<T>(this, D);
+ return getStateManager().set<T>(this, D);
}
-
+
template<typename T>
const GRState *GRState::set(typename GRStateTrait<T>::key_type K,
typename GRStateTrait<T>::value_type E) const {
- return Mgr->set<T>(this, K, E, get_context<T>());
+ return getStateManager().set<T>(this, K, E, get_context<T>());
}
-
+
template<typename T>
const GRState *GRState::set(typename GRStateTrait<T>::key_type K,
typename GRStateTrait<T>::value_type E,
typename GRStateTrait<T>::context_type C) const {
- return Mgr->set<T>(this, K, E, C);
+ return getStateManager().set<T>(this, K, E, C);
}
-
+
template <typename CB>
CB GRState::scanReachableSymbols(SVal val) const {
CB cb(this);
diff --git a/include/clang/Analysis/PathSensitive/GRStateTrait.h b/include/clang/Analysis/PathSensitive/GRStateTrait.h
index ce43cda..5189a1f 100644
--- a/include/clang/Analysis/PathSensitive/GRStateTrait.h
+++ b/include/clang/Analysis/PathSensitive/GRStateTrait.h
@@ -1,5 +1,5 @@
//==- GRStateTrait.h - Partial implementations of GRStateTrait -----*- C++ -*-//
-//
+//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
@@ -27,59 +27,59 @@ namespace llvm {
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 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);
+ 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 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();
@@ -88,60 +88,60 @@ namespace clang {
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);
+ 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;
-
+ 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)
+ 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);
+ return new typename data_type::Factory(Alloc);
}
-
+
static void DeleteContext(void* Ctx) {
delete (typename data_type::Factory*) Ctx;
- }
+ }
};
} // end clang namespace
diff --git a/include/clang/Analysis/PathSensitive/GRSubEngine.h b/include/clang/Analysis/PathSensitive/GRSubEngine.h
new file mode 100644
index 0000000..62e36f9
--- /dev/null
+++ b/include/clang/Analysis/PathSensitive/GRSubEngine.h
@@ -0,0 +1,68 @@
+//== GRSubEngine.h - Interface of the subengine of 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 the interface of a subengine of the GRCoreEngine.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_ANALYSIS_GRSUBENGINE_H
+#define LLVM_CLANG_ANALYSIS_GRSUBENGINE_H
+
+namespace clang {
+
+class Stmt;
+class CFGBlock;
+class GRState;
+class GRStateManager;
+class GRBlockCounter;
+class GRStmtNodeBuilder;
+class GRBranchNodeBuilder;
+class GRIndirectGotoNodeBuilder;
+class GRSwitchNodeBuilder;
+class GREndPathNodeBuilder;
+class LocationContext;
+
+class GRSubEngine {
+public:
+ virtual ~GRSubEngine() {}
+
+ virtual const GRState* getInitialState(const LocationContext *InitLoc) = 0;
+
+ virtual GRStateManager& getStateManager() = 0;
+
+ /// ProcessStmt - Called by GRCoreEngine. Used to generate new successor
+ /// nodes by processing the 'effects' of a block-level statement.
+ virtual void ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder) = 0;
+
+ /// 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.
+ virtual bool ProcessBlockEntrance(CFGBlock* B, const GRState* St,
+ GRBlockCounter BC) = 0;
+
+ /// ProcessBranch - Called by GRCoreEngine. Used to generate successor
+ /// nodes by processing the 'effects' of a branch condition.
+ virtual void ProcessBranch(Stmt* Condition, Stmt* Term,
+ GRBranchNodeBuilder& builder) = 0;
+
+ /// ProcessIndirectGoto - Called by GRCoreEngine. Used to generate successor
+ /// nodes by processing the 'effects' of a computed goto jump.
+ virtual void ProcessIndirectGoto(GRIndirectGotoNodeBuilder& builder) = 0;
+
+ /// ProcessSwitch - Called by GRCoreEngine. Used to generate successor
+ /// nodes by processing the 'effects' of a switch statement.
+ virtual void ProcessSwitch(GRSwitchNodeBuilder& builder) = 0;
+
+ /// ProcessEndPath - Called by GRCoreEngine. Used to generate end-of-path
+ /// nodes when the control reaches the end of a function.
+ virtual void ProcessEndPath(GREndPathNodeBuilder& builder) = 0;
+};
+
+}
+
+#endif
diff --git a/include/clang/Analysis/PathSensitive/GRTransferFuncs.h b/include/clang/Analysis/PathSensitive/GRTransferFuncs.h
index db23f81..5f7b2cb 100644
--- a/include/clang/Analysis/PathSensitive/GRTransferFuncs.h
+++ b/include/clang/Analysis/PathSensitive/GRTransferFuncs.h
@@ -21,66 +21,68 @@
#include <vector>
namespace clang {
-
+
class GRExprEngine;
class BugReporter;
class ObjCMessageExpr;
class GRStmtNodeBuilderRef;
-
+
class GRTransferFuncs {
public:
GRTransferFuncs() {}
virtual ~GRTransferFuncs() {}
-
+
virtual void RegisterPrinters(std::vector<GRState::Printer*>& Printers) {}
virtual void RegisterChecks(BugReporter& BR) {}
-
+
// Calls.
-
- virtual void EvalCall(ExplodedNodeSet<GRState>& Dst,
+
+ virtual void EvalCall(ExplodedNodeSet& Dst,
GRExprEngine& Engine,
- GRStmtNodeBuilder<GRState>& Builder,
+ GRStmtNodeBuilder& Builder,
CallExpr* CE, SVal L,
- ExplodedNode<GRState>* Pred) {}
-
- virtual void EvalObjCMessageExpr(ExplodedNodeSet<GRState>& Dst,
+ ExplodedNode* Pred) {}
+
+ virtual void EvalObjCMessageExpr(ExplodedNodeSet& Dst,
GRExprEngine& Engine,
- GRStmtNodeBuilder<GRState>& Builder,
+ GRStmtNodeBuilder& Builder,
ObjCMessageExpr* ME,
- ExplodedNode<GRState>* Pred) {}
-
+ ExplodedNode* 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,
+ GREndPathNodeBuilder& Builder) {}
+
+
+ virtual void EvalDeadSymbols(ExplodedNodeSet& Dst,
GRExprEngine& Engine,
- GRStmtNodeBuilder<GRState>& Builder,
- ExplodedNode<GRState>* Pred,
+ GRStmtNodeBuilder& Builder,
+ ExplodedNode* Pred,
Stmt* S, const GRState* state,
SymbolReaper& SymReaper) {}
-
- // Return statements.
- virtual void EvalReturn(ExplodedNodeSet<GRState>& Dst,
+
+ // Return statements.
+ virtual void EvalReturn(ExplodedNodeSet& Dst,
GRExprEngine& Engine,
- GRStmtNodeBuilder<GRState>& Builder,
+ GRStmtNodeBuilder& Builder,
ReturnStmt* S,
- ExplodedNode<GRState>* Pred) {}
+ ExplodedNode* Pred) {}
- // Assumptions.
+ // Assumptions.
virtual const GRState* EvalAssume(const GRState *state,
SVal Cond, bool Assumption) {
return state;
}
};
-
+
+GRTransferFuncs *CreateCallInliner(ASTContext &ctx);
+
} // end clang namespace
#endif
diff --git a/include/clang/Analysis/PathSensitive/GRWorkList.h b/include/clang/Analysis/PathSensitive/GRWorkList.h
index c765322..17b83fd 100644
--- a/include/clang/Analysis/PathSensitive/GRWorkList.h
+++ b/include/clang/Analysis/PathSensitive/GRWorkList.h
@@ -1,5 +1,5 @@
//==- GRWorkList.h - Worklist class used by GRCoreEngine -----------*- C++ -*-//
-//
+//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
@@ -17,31 +17,31 @@
#include "clang/Analysis/PathSensitive/GRBlockCounter.h"
-namespace clang {
+namespace clang {
class ExplodedNodeImpl;
-
+
class GRWorkListUnit {
- ExplodedNodeImpl* Node;
+ ExplodedNode* Node;
GRBlockCounter Counter;
CFGBlock* Block;
unsigned BlockIdx;
-
+
public:
- GRWorkListUnit(ExplodedNodeImpl* N, GRBlockCounter C,
+ GRWorkListUnit(ExplodedNode* N, GRBlockCounter C,
CFGBlock* B, unsigned idx)
: Node(N),
Counter(C),
Block(B),
BlockIdx(idx) {}
-
- explicit GRWorkListUnit(ExplodedNodeImpl* N, GRBlockCounter C)
+
+ explicit GRWorkListUnit(ExplodedNode* N, GRBlockCounter C)
: Node(N),
Counter(C),
Block(NULL),
BlockIdx(0) {}
-
- ExplodedNodeImpl* getNode() const { return Node; }
+
+ ExplodedNode* getNode() const { return Node; }
GRBlockCounter getBlockCounter() const { return Counter; }
CFGBlock* getBlock() const { return Block; }
unsigned getIndex() const { return BlockIdx; }
@@ -52,25 +52,25 @@ class GRWorkList {
public:
virtual ~GRWorkList();
virtual bool hasWork() const = 0;
-
+
virtual void Enqueue(const GRWorkListUnit& U) = 0;
- void Enqueue(ExplodedNodeImpl* N, CFGBlock& B, unsigned idx) {
+ void Enqueue(ExplodedNode* N, CFGBlock& B, unsigned idx) {
Enqueue(GRWorkListUnit(N, CurrentCounter, &B, idx));
}
-
- void Enqueue(ExplodedNodeImpl* N) {
+
+ void Enqueue(ExplodedNode* 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
+} // end clang namespace
#endif
diff --git a/include/clang/Analysis/PathSensitive/MemRegion.h b/include/clang/Analysis/PathSensitive/MemRegion.h
index 5926229..0e48769 100644
--- a/include/clang/Analysis/PathSensitive/MemRegion.h
+++ b/include/clang/Analysis/PathSensitive/MemRegion.h
@@ -31,10 +31,15 @@
namespace llvm { class raw_ostream; }
namespace clang {
-
+
class MemRegionManager;
-class MemSpaceRegion;
-
+class MemSpaceRegion;
+class LocationContext;
+
+//===----------------------------------------------------------------------===//
+// Base region classes.
+//===----------------------------------------------------------------------===//
+
/// MemRegion - The root abstract class for all memory regions.
class MemRegion : public llvm::FoldingSetNode {
public:
@@ -46,55 +51,57 @@ public:
CodeTextRegionKind,
CompoundLiteralRegionKind,
StringRegionKind, ElementRegionKind,
- TypedViewRegionKind,
// Decl Regions.
BEG_DECL_REGIONS,
VarRegionKind, FieldRegionKind,
ObjCIvarRegionKind, ObjCObjectRegionKind,
END_DECL_REGIONS,
- END_TYPED_REGIONS };
+ END_TYPED_REGIONS };
private:
const Kind kind;
-
+
protected:
MemRegion(Kind k) : kind(k) {}
virtual ~MemRegion();
- ASTContext &getContext() const;
public:
+ ASTContext &getContext() const;
+
virtual void Profile(llvm::FoldingSetNodeID& ID) const = 0;
virtual MemRegionManager* getMemRegionManager() const = 0;
std::string getString() const;
-
+
const MemSpaceRegion *getMemorySpace() const;
-
+
+ const MemRegion *getBaseRegion() const;
+
bool hasStackStorage() const;
-
+
bool hasParametersStorage() const;
-
+
bool hasGlobalsStorage() const;
-
+
bool hasGlobalsOrParametersStorage() const;
-
+
bool hasHeapStorage() const;
-
+
bool hasHeapOrStackStorage() const;
- virtual void print(llvm::raw_ostream& os) const;
+ virtual void dumpToStream(llvm::raw_ostream& os) const;
+
+ void dump() const;
+
+ Kind getKind() const { return kind; }
- void printStdErr() const;
-
- Kind getKind() const { return kind; }
-
template<typename RegionTy> const RegionTy* getAs() const;
-
+
virtual bool isBoundable() const { return false; }
static bool classof(const MemRegion*) { return true; }
};
-
+
/// MemSpaceRegion - A memory region that represents and "memory space";
/// for example, the set of global variables, the stack frame, etc.
class MemSpaceRegion : public MemRegion {
@@ -105,7 +112,7 @@ protected:
MemSpaceRegion(MemRegionManager *mgr) : MemRegion(MemSpaceRegionKind),
Mgr(mgr) {}
-
+
MemRegionManager* getMemRegionManager() const {
return Mgr;
}
@@ -124,13 +131,13 @@ public:
/// are subclasses of SubRegion.
class SubRegion : public MemRegion {
protected:
- const MemRegion* superRegion;
+ const MemRegion* superRegion;
SubRegion(const MemRegion* sReg, Kind k) : MemRegion(k), superRegion(sReg) {}
public:
const MemRegion* getSuperRegion() const {
return superRegion;
}
-
+
MemRegionManager* getMemRegionManager() const;
bool isSubRegionOf(const MemRegion* R) const;
@@ -140,6 +147,32 @@ public:
}
};
+//===----------------------------------------------------------------------===//
+// Auxillary data classes for use with MemRegions.
+//===----------------------------------------------------------------------===//
+
+class ElementRegion;
+
+class RegionRawOffset : public std::pair<const MemRegion*, int64_t> {
+private:
+ friend class ElementRegion;
+
+ RegionRawOffset(const MemRegion* reg, int64_t offset = 0)
+ : std::pair<const MemRegion*, int64_t>(reg, offset) {}
+
+public:
+ // FIXME: Eventually support symbolic offsets.
+ int64_t getByteOffset() const { return second; }
+ const MemRegion *getRegion() const { return first; }
+
+ void dumpToStream(llvm::raw_ostream& os) const;
+ void dump() const;
+};
+
+//===----------------------------------------------------------------------===//
+// MemRegion subclasses.
+//===----------------------------------------------------------------------===//
+
/// AllocaRegion - A region that represents an untyped blob of bytes created
/// by a call to 'alloca'.
class AllocaRegion : public SubRegion {
@@ -151,43 +184,45 @@ protected:
AllocaRegion(const Expr* ex, unsigned cnt, const MemRegion *superRegion)
: SubRegion(superRegion, AllocaRegionKind), Cnt(cnt), Ex(ex) {}
-
+
public:
-
+
const Expr* getExpr() const { return Ex; }
-
+
+ bool isBoundable() const { return true; }
+
void Profile(llvm::FoldingSetNodeID& ID) const;
static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Expr* Ex,
unsigned Cnt, const MemRegion *superRegion);
-
- void print(llvm::raw_ostream& os) const;
-
+
+ void dumpToStream(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;
+ return T.getTypePtr() ? T.getDesugaredType() : T;
}
-
+
QualType getDesugaredLocationType(ASTContext& C) const {
- return getLocationType(C)->getDesugaredType();
+ return getLocationType(C).getDesugaredType();
}
bool isBoundable() const {
@@ -205,32 +240,12 @@ public:
/// 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;
+ const FunctionDecl *FD;
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) {}
+ CodeTextRegion(const FunctionDecl* fd, const MemRegion* sreg)
+ : TypedRegion(sreg, CodeTextRegionKind), FD(fd) {}
QualType getValueType(ASTContext &C) const {
// Do not get the object type of a CodeTextRegion.
@@ -239,30 +254,21 @@ public:
}
QualType getLocationType(ASTContext &C) const {
- return LocationType;
+ return C.getPointerType(FD->getType());
}
- 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);
+ const FunctionDecl *getDecl() const {
+ return FD;
}
-
- SymbolRef getSymbol() const {
- assert(codekind == Symbolic);
- return const_cast<SymbolRef>(static_cast<const SymbolRef>(Data));
- }
-
+
bool isBoundable() const { return false; }
-
- virtual void print(llvm::raw_ostream& os) const;
+
+ virtual void dumpToStream(llvm::raw_ostream& os) const;
void Profile(llvm::FoldingSetNodeID& ID) const;
- static void ProfileRegion(llvm::FoldingSetNodeID& ID,
- const void* data, QualType t, const MemRegion*);
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FunctionDecl *FD,
+ const MemRegion*);
static bool classof(const MemRegion* R) {
return R->getKind() == CodeTextRegionKind;
@@ -279,25 +285,27 @@ protected:
const SymbolRef sym;
public:
- SymbolicRegion(const SymbolRef s, const MemRegion* sreg)
+ SymbolicRegion(const SymbolRef s, const MemRegion* sreg)
: SubRegion(sreg, SymbolicRegionKind), sym(s) {}
-
+
SymbolRef getSymbol() const {
return sym;
}
+ bool isBoundable() const { return true; }
+
void Profile(llvm::FoldingSetNodeID& ID) const;
static void ProfileRegion(llvm::FoldingSetNodeID& ID,
SymbolRef sym,
const MemRegion* superRegion);
-
- void print(llvm::raw_ostream& os) const;
-
+
+ void dumpToStream(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 {
@@ -315,7 +323,7 @@ protected:
public:
const StringLiteral* getStringLiteral() const { return Str; }
-
+
QualType getValueType(ASTContext& C) const {
return Str->getType();
}
@@ -326,53 +334,13 @@ public:
ProfileRegion(ID, Str, superRegion);
}
- void print(llvm::raw_ostream& os) const;
+ void dumpToStream(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() 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.
@@ -383,7 +351,7 @@ private:
CompoundLiteralRegion(const CompoundLiteralExpr* cl, const MemRegion* sReg)
: TypedRegion(sReg, CompoundLiteralRegionKind), CL(cl) {}
-
+
static void ProfileRegion(llvm::FoldingSetNodeID& ID,
const CompoundLiteralExpr* CL,
const MemRegion* superRegion);
@@ -395,11 +363,11 @@ public:
bool isBoundable() const { return !CL->isFileScope(); }
void Profile(llvm::FoldingSetNodeID& ID) const;
-
- void print(llvm::raw_ostream& os) const;
+
+ void dumpToStream(llvm::raw_ostream& os) const;
const CompoundLiteralExpr* getLiteralExpr() const { return CL; }
-
+
static bool classof(const MemRegion* R) {
return R->getKind() == CompoundLiteralRegionKind;
}
@@ -414,41 +382,51 @@ protected:
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) {}
+
+ // Data.
+ const LocationContext *LC;
+
+ // Constructors and private methods.
+ VarRegion(const VarDecl* vd, const LocationContext *lC, const MemRegion* sReg)
+ : DeclRegion(vd, sReg, VarRegionKind), LC(lC) {}
static void ProfileRegion(llvm::FoldingSetNodeID& ID, const VarDecl* VD,
- const MemRegion* superRegion) {
+ const LocationContext *LC,
+ const MemRegion *superRegion) {
DeclRegion::ProfileRegion(ID, VD, superRegion, VarRegionKind);
+ ID.AddPointer(LC);
}
-
-public:
- const VarDecl* getDecl() const { return cast<VarDecl>(D); }
-
- QualType getValueType(ASTContext& C) const {
+
+ void Profile(llvm::FoldingSetNodeID& ID) const;
+
+public:
+ const VarDecl *getDecl() const { return cast<VarDecl>(D); }
+
+ const LocationContext *getLocationContext() const { return LC; }
+
+ QualType getValueType(ASTContext& C) const {
// FIXME: We can cache this if needed.
return C.getCanonicalType(getDecl()->getType());
- }
-
- void print(llvm::raw_ostream& os) const;
-
+ }
+
+ void dumpToStream(llvm::raw_ostream& os) const;
+
static bool classof(const MemRegion* R) {
return R->getKind() == VarRegionKind;
- }
+ }
};
class FieldRegion : public DeclRegion {
@@ -458,57 +436,57 @@ class FieldRegion : public DeclRegion {
: DeclRegion(fd, sReg, FieldRegionKind) {}
public:
-
- void print(llvm::raw_ostream& os) const;
-
+
+ void dumpToStream(llvm::raw_ostream& os) const;
+
const FieldDecl* getDecl() const { return cast<FieldDecl>(D); }
-
- QualType getValueType(ASTContext& C) const {
+
+ QualType getValueType(ASTContext& C) const {
// FIXME: We can cache this if needed.
return C.getCanonicalType(getDecl()->getType());
- }
+ }
static void ProfileRegion(llvm::FoldingSetNodeID& ID, const 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,
const 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) {}
@@ -516,11 +494,13 @@ class ObjCIvarRegion : public DeclRegion {
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(); }
-
+
+ void dumpToStream(llvm::raw_ostream& os) const;
+
static bool classof(const MemRegion* R) {
return R->getKind() == ObjCIvarRegionKind;
}
@@ -539,7 +519,7 @@ class ElementRegion : public TypedRegion {
cast<nonloc::ConcreteInt>(&Idx)->getValue().isSigned()) &&
"The index must be signed");
}
-
+
static void ProfileRegion(llvm::FoldingSetNodeID& ID, QualType elementType,
SVal Idx, const MemRegion* superRegion);
@@ -550,12 +530,14 @@ public:
QualType getValueType(ASTContext&) const {
return ElementType;
}
-
+
QualType getElementType() const {
return ElementType;
}
-
- void print(llvm::raw_ostream& os) const;
+
+ RegionRawOffset getAsRawOffset() const;
+
+ void dumpToStream(llvm::raw_ostream& os) const;
void Profile(llvm::FoldingSetNodeID& ID) const;
@@ -563,25 +545,13 @@ public:
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;
+ if (const RegionTy* RT = dyn_cast<RegionTy>(this))
+ return RT;
+
+ return NULL;
}
//===----------------------------------------------------------------------===//
@@ -592,7 +562,7 @@ class MemRegionManager {
ASTContext &C;
llvm::BumpPtrAllocator& A;
llvm::FoldingSet<MemRegion> Regions;
-
+
MemSpaceRegion *globals;
MemSpaceRegion *stack;
MemSpaceRegion *stackArguments;
@@ -604,11 +574,11 @@ public:
MemRegionManager(ASTContext &c, llvm::BumpPtrAllocator& a)
: C(c), A(a), globals(0), stack(0), stackArguments(0), heap(0),
unknown(0), code(0) {}
-
+
~MemRegionManager() {}
-
+
ASTContext &getContext() { return C; }
-
+
/// getStackRegion - Retrieve the memory region associated with the
/// current stack frame.
MemSpaceRegion *getStackRegion();
@@ -616,11 +586,11 @@ public:
/// getStackArgumentsRegion - Retrieve the memory region associated with
/// function/method arguments of the current stack frame.
MemSpaceRegion *getStackArgumentsRegion();
-
+
/// getGlobalsRegion - Retrieve the memory region associated with
/// all global variables.
MemSpaceRegion *getGlobalsRegion();
-
+
/// getHeapRegion - Retrieve the memory region associated with the
/// generic "heap".
MemSpaceRegion *getHeapRegion();
@@ -633,69 +603,77 @@ public:
/// 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);
-
+ 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);
-
+ /// a specified VarDecl and LocationContext.
+ VarRegion* getVarRegion(const VarDecl *D, const LocationContext *LC);
+
/// getElementRegion - Retrieve the memory region associated with the
/// associated element type, index, and super region.
- ElementRegion* getElementRegion(QualType elementType, SVal Idx,
- const MemRegion* superRegion,ASTContext &Ctx);
+ ElementRegion *getElementRegion(QualType elementType, SVal Idx,
+ const MemRegion *superRegion,
+ ASTContext &Ctx);
+
+ ElementRegion *getElementRegionWithSuper(const ElementRegion *ER,
+ const MemRegion *superRegion) {
+ return getElementRegion(ER->getElementType(), ER->getIndex(),
+ superRegion, ER->getContext());
+ }
/// 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,
+ FieldRegion *getFieldRegion(const FieldDecl* fd,
const MemRegion* superRegion);
-
+
+ FieldRegion *getFieldRegionWithSuper(const FieldRegion *FR,
+ const MemRegion *superRegion) {
+ return getFieldRegion(FR->getDecl(), 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,
+ ObjCIvarRegion *getObjCIvarRegion(const ObjCIvarDecl* ivd,
const MemRegion* superRegion);
- TypedViewRegion* getTypedViewRegion(QualType LValueType,
- const MemRegion* superRegion);
+ CodeTextRegion *getCodeTextRegion(const FunctionDecl *FD);
- CodeTextRegion* getCodeTextRegion(SymbolRef sym, QualType t);
- CodeTextRegion* getCodeTextRegion(const FunctionDecl* fd, QualType t);
-
template <typename RegionTy, typename A1>
RegionTy* getRegion(const A1 a1);
-
+
template <typename RegionTy, typename A1>
- RegionTy* getRegion(const A1 a1, const MemRegion* superRegion);
-
+ RegionTy* getSubRegion(const A1 a1, const MemRegion* superRegion);
+
template <typename RegionTy, typename A1, typename A2>
RegionTy* getRegion(const A1 a1, const A2 a2);
- bool isGlobalsRegion(const MemRegion* R) {
+ bool isGlobalsRegion(const MemRegion* R) {
assert(R);
- return R == globals;
+ return R == globals;
}
-
+
private:
MemSpaceRegion* LazyAllocate(MemSpaceRegion*& region);
};
-
+
//===----------------------------------------------------------------------===//
// Out-of-line member definitions.
//===----------------------------------------------------------------------===//
@@ -703,69 +681,69 @@ private:
inline ASTContext& MemRegion::getContext() const {
return getMemRegionManager()->getContext();
}
-
+
template<typename RegionTy> struct MemRegionManagerTrait;
-
+
template <typename RegionTy, typename A1>
RegionTy* MemRegionManager::getRegion(const A1 a1) {
const typename MemRegionManagerTrait<RegionTy>::SuperRegionTy *superRegion =
MemRegionManagerTrait<RegionTy>::getSuperRegion(*this, a1);
-
- llvm::FoldingSetNodeID ID;
- RegionTy::ProfileRegion(ID, a1, superRegion);
+
+ llvm::FoldingSetNodeID ID;
+ RegionTy::ProfileRegion(ID, a1, superRegion);
void* InsertPos;
RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID,
InsertPos));
-
+
if (!R) {
R = (RegionTy*) A.Allocate<RegionTy>();
new (R) RegionTy(a1, superRegion);
Regions.InsertNode(R, InsertPos);
}
-
+
return R;
}
template <typename RegionTy, typename A1>
-RegionTy* MemRegionManager::getRegion(const A1 a1, const MemRegion *superRegion)
-{
- llvm::FoldingSetNodeID ID;
- RegionTy::ProfileRegion(ID, a1, superRegion);
+RegionTy* MemRegionManager::getSubRegion(const A1 a1,
+ const MemRegion *superRegion) {
+ llvm::FoldingSetNodeID ID;
+ RegionTy::ProfileRegion(ID, a1, superRegion);
void* InsertPos;
RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID,
InsertPos));
-
+
if (!R) {
R = (RegionTy*) A.Allocate<RegionTy>();
new (R) RegionTy(a1, superRegion);
Regions.InsertNode(R, InsertPos);
}
-
+
return R;
}
-
+
template <typename RegionTy, typename A1, typename A2>
RegionTy* MemRegionManager::getRegion(const A1 a1, const A2 a2) {
-
+
const typename MemRegionManagerTrait<RegionTy>::SuperRegionTy *superRegion =
MemRegionManagerTrait<RegionTy>::getSuperRegion(*this, a1, a2);
-
- llvm::FoldingSetNodeID ID;
- RegionTy::ProfileRegion(ID, a1, a2, superRegion);
+
+ llvm::FoldingSetNodeID ID;
+ RegionTy::ProfileRegion(ID, a1, a2, superRegion);
void* InsertPos;
RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID,
InsertPos));
-
+
if (!R) {
R = (RegionTy*) A.Allocate<RegionTy>();
new (R) RegionTy(a1, a2, superRegion);
Regions.InsertNode(R, InsertPos);
}
-
+
return R;
}
-
+
//===----------------------------------------------------------------------===//
// Traits for constructing regions.
//===----------------------------------------------------------------------===//
@@ -776,18 +754,18 @@ template <> struct MemRegionManagerTrait<AllocaRegion> {
const Expr *, unsigned) {
return MRMgr.getStackRegion();
}
-};
-
+};
+
template <> struct MemRegionManagerTrait<CompoundLiteralRegion> {
typedef MemRegion SuperRegionTy;
static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr,
const CompoundLiteralExpr *CL) {
-
- return CL->isFileScope() ? MRMgr.getGlobalsRegion()
+
+ return CL->isFileScope() ? MRMgr.getGlobalsRegion()
: MRMgr.getStackRegion();
}
};
-
+
template <> struct MemRegionManagerTrait<StringRegion> {
typedef MemSpaceRegion SuperRegionTy;
static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr,
@@ -795,20 +773,24 @@ template <> struct MemRegionManagerTrait<StringRegion> {
return MRMgr.getGlobalsRegion();
}
};
-
+
template <> struct MemRegionManagerTrait<VarRegion> {
typedef MemRegion SuperRegionTy;
- static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr,
- const VarDecl *d) {
- if (d->hasLocalStorage()) {
- return isa<ParmVarDecl>(d) || isa<ImplicitParamDecl>(d)
+ static const SuperRegionTy* getSuperRegion(MemRegionManager &MRMgr,
+ const VarDecl *D,
+ const LocationContext *LC) {
+
+ // FIXME: Make stack regions have a location context?
+
+ if (D->hasLocalStorage()) {
+ return isa<ParmVarDecl>(D) || isa<ImplicitParamDecl>(D)
? MRMgr.getStackArgumentsRegion() : MRMgr.getStackRegion();
}
-
+
return MRMgr.getGlobalsRegion();
}
};
-
+
template <> struct MemRegionManagerTrait<SymbolicRegion> {
typedef MemRegion SuperRegionTy;
static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr,
@@ -820,7 +802,7 @@ template <> struct MemRegionManagerTrait<SymbolicRegion> {
template<> struct MemRegionManagerTrait<CodeTextRegion> {
typedef MemSpaceRegion SuperRegionTy;
static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr,
- const FunctionDecl*, QualType) {
+ const FunctionDecl*) {
return MRMgr.getCodeRegion();
}
static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr,
@@ -828,7 +810,7 @@ template<> struct MemRegionManagerTrait<CodeTextRegion> {
return MRMgr.getCodeRegion();
}
};
-
+
} // end clang namespace
//===----------------------------------------------------------------------===//
@@ -836,10 +818,10 @@ template<> struct MemRegionManagerTrait<CodeTextRegion> {
//===----------------------------------------------------------------------===//
namespace llvm {
-static inline raw_ostream& operator<<(raw_ostream& O,
- const clang::MemRegion* R) {
- R->print(O);
- return O;
+static inline raw_ostream& operator<<(raw_ostream& os,
+ const clang::MemRegion* R) {
+ R->dumpToStream(os);
+ return os;
}
} // end llvm namespace
diff --git a/include/clang/Analysis/PathSensitive/SVals.h b/include/clang/Analysis/PathSensitive/SVals.h
index 4bc5e27..4ba3c73 100644
--- a/include/clang/Analysis/PathSensitive/SVals.h
+++ b/include/clang/Analysis/PathSensitive/SVals.h
@@ -18,7 +18,11 @@
#include "clang/Analysis/PathSensitive/SymbolManager.h"
#include "llvm/Support/Casting.h"
#include "llvm/ADT/ImmutableList.h"
-
+
+namespace llvm {
+ class raw_ostream;
+}
+
//==------------------------------------------------------------------------==//
// Base SVal types.
//==------------------------------------------------------------------------==//
@@ -26,40 +30,43 @@
namespace clang {
class CompoundValData;
+class LazyCompoundValData;
+class GRState;
class BasicValueFactory;
class MemRegion;
+class TypedRegion;
class MemRegionManager;
class GRStateManager;
class ValueManager;
-
+
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));
@@ -68,7 +75,7 @@ public:
inline bool operator==(const SVal& R) const {
return getRawKind() == R.getRawKind() && Data == R.Data;
}
-
+
inline bool operator!=(const SVal& R) const {
return !(*this == R);
}
@@ -84,25 +91,25 @@ public:
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.
+ /// CodeTextRegion wrapping a FunctionDecl, return that FunctionDecl.
/// Otherwise return 0.
const FunctionDecl* getAsFunctionDecl() const;
-
- /// getAsLocSymbol - If this SVal is a location (subclasses Loc) and
+
+ /// 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;
@@ -112,9 +119,9 @@ public:
const SymExpr *getAsSymbolicExpression() const;
const MemRegion *getAsRegion() const;
-
- void print(llvm::raw_ostream& OS) const;
- void printStdErr() const;
+
+ void dumpToStream(llvm::raw_ostream& OS) const;
+ void dump() const;
// Iterators.
class symbol_iterator {
@@ -123,14 +130,14 @@ public:
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)
@@ -138,97 +145,135 @@ public:
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; }
+
+ void* getData() const { return Data; }
};
-class NonLoc : public SVal {
+class DefinedOrUnknownSVal : public SVal {
+private:
+ // Do not implement. We want calling these methods to be a compiler
+ // error since they are tautologically false.
+ bool isUndef() const;
+ bool isValid() const;
+
protected:
- NonLoc(unsigned SubKind, const void* d) : SVal(d, false, SubKind) {}
+ explicit DefinedOrUnknownSVal(const void* d, bool isLoc, unsigned ValKind)
+ : SVal(d, isLoc, ValKind) {}
+
+ explicit DefinedOrUnknownSVal(BaseKind k, void *D = NULL)
+ : SVal(k, D) {}
+
+public:
+ // Implement isa<T> support.
+ static inline bool classof(const SVal *V) {
+ return !V->isUndef();
+ }
+};
+class UnknownVal : public DefinedOrUnknownSVal {
public:
- void print(llvm::raw_ostream& Out) const;
+ UnknownVal() : DefinedOrUnknownSVal(UnknownKind) {}
+
+ static inline bool classof(const SVal *V) {
+ return V->getBaseKind() == UnknownKind;
+ }
+};
+class DefinedSVal : public DefinedOrUnknownSVal {
+private:
+ // Do not implement. We want calling these methods to be a compiler
+ // error since they are tautologically true/false.
+ bool isUnknown() const;
+ bool isUnknownOrUndef() const;
+ bool isValid() const;
+protected:
+ DefinedSVal(const void* d, bool isLoc, unsigned ValKind)
+ : DefinedOrUnknownSVal(d, isLoc, ValKind) {}
+public:
+ // Implement isa<T> support.
+ static inline bool classof(const SVal *V) {
+ return !V->isUnknownOrUndef();
+ }
+};
+
+class NonLoc : public DefinedSVal {
+protected:
+ NonLoc(unsigned SubKind, const void* d) : DefinedSVal(d, false, SubKind) {}
+
+public:
+ void dumpToStream(llvm::raw_ostream& Out) const;
+
// Implement isa<T> support.
static inline bool classof(const SVal* V) {
return V->getBaseKind() == NonLocKind;
}
};
-class Loc : public SVal {
+class Loc : public DefinedSVal {
protected:
Loc(unsigned SubKind, const void* D)
- : SVal(const_cast<void*>(D), true, SubKind) {}
+ : DefinedSVal(const_cast<void*>(D), true, SubKind) {}
public:
- void print(llvm::raw_ostream& Out) const;
+ void dumpToStream(llvm::raw_ostream& Out) const;
- Loc(const Loc& X) : SVal(X.Data, true, X.getSubKind()) {}
+ Loc(const Loc& X) : DefinedSVal(X.Data, true, X.getSubKind()) {}
Loc& operator=(const Loc& X) { memcpy(this, &X, sizeof(Loc)); return *this; }
-
+
// 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();
+ return T->isAnyPointerType() || T->isBlockPointerType();
}
};
-
+
//==------------------------------------------------------------------------==//
// Subclasses of NonLoc.
//==------------------------------------------------------------------------==//
namespace nonloc {
-
+
enum Kind { ConcreteIntKind, SymbolValKind, SymExprValKind,
- LocAsIntegerKind, CompoundValKind };
+ LocAsIntegerKind, CompoundValKind, LazyCompoundValKind };
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 &&
+ return V->getBaseKind() == NonLocKind &&
V->getSubKind() == SymbolValKind;
}
-
+
static inline bool classof(const NonLoc* V) {
return V->getSubKind() == SymbolValKind;
}
};
-class SymExprVal : public NonLoc {
+class SymExprVal : public NonLoc {
public:
SymExprVal(const SymExpr *SE)
: NonLoc(SymExprValKind, reinterpret_cast<const void*>(SE)) {}
@@ -236,12 +281,12 @@ public:
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;
}
@@ -250,30 +295,30 @@ public:
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(ValueManager &ValMgr, BinaryOperator::Opcode Op,
const ConcreteInt& R) const;
-
+
ConcreteInt evalComplement(ValueManager &ValMgr) const;
-
+
ConcreteInt evalMinus(ValueManager &ValMgr) 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 {
friend class clang::ValueManager;
@@ -281,28 +326,28 @@ class LocAsInteger : public NonLoc {
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;
}
@@ -317,10 +362,10 @@ public:
const CompoundValData* getValue() const {
return static_cast<CompoundValData*>(Data);
}
-
+
typedef llvm::ImmutableList<SVal>::iterator iterator;
iterator begin() const;
- iterator end() const;
+ iterator end() const;
static bool classof(const SVal* V) {
return V->getBaseKind() == NonLocKind && V->getSubKind() == CompoundValKind;
@@ -330,7 +375,28 @@ public:
return V->getSubKind() == CompoundValKind;
}
};
-
+
+class LazyCompoundVal : public NonLoc {
+ friend class clang::ValueManager;
+
+ LazyCompoundVal(const LazyCompoundValData *D)
+ : NonLoc(LazyCompoundValKind, D) {}
+public:
+ const LazyCompoundValData *getCVData() const {
+ return static_cast<const LazyCompoundValData*>(Data);
+ }
+ const GRState *getState() const;
+ const TypedRegion *getRegion() const;
+
+ static bool classof(const SVal *V) {
+ return V->getBaseKind() == NonLocKind &&
+ V->getSubKind() == LazyCompoundValKind;
+ }
+ static bool classof(const NonLoc *V) {
+ return V->getSubKind() == LazyCompoundValKind;
+ }
+};
+
} // end namespace clang::nonloc
//==------------------------------------------------------------------------==//
@@ -338,27 +404,27 @@ public:
//==------------------------------------------------------------------------==//
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:
@@ -367,35 +433,37 @@ public:
const MemRegion* getRegion() const {
return static_cast<MemRegion*>(Data);
}
-
+
+ const MemRegion* getBaseRegion() const;
+
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);
}
@@ -403,19 +471,26 @@ public:
// 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
+} // end clang::loc namespace
+} // end clang namespace
+
+namespace llvm {
+static inline llvm::raw_ostream& operator<<(llvm::raw_ostream& os,
+ clang::SVal V) {
+ V.dumpToStream(os);
+ return os;
+}
+} // end llvm namespace
#endif
diff --git a/include/clang/Analysis/PathSensitive/SValuator.h b/include/clang/Analysis/PathSensitive/SValuator.h
index 490c04e..e63eb12 100644
--- a/include/clang/Analysis/PathSensitive/SValuator.h
+++ b/include/clang/Analysis/PathSensitive/SValuator.h
@@ -9,7 +9,7 @@
//
// This file defines SValuator, a class that defines the interface for
// "symbolical evaluators" which construct an SVal from an expression.
-//
+//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_ANALYSIS_SVALUATOR
@@ -24,32 +24,66 @@ class GRState;
class ValueManager;
class SValuator {
+ friend class ValueManager;
protected:
ValueManager &ValMgr;
-
+
+ virtual SVal EvalCastNL(NonLoc val, QualType castTy) = 0;
+
+ virtual SVal EvalCastL(Loc val, QualType castTy) = 0;
+
public:
SValuator(ValueManager &valMgr) : ValMgr(valMgr) {}
virtual ~SValuator() {}
+
+ template <typename T>
+ class GenericCastResult : public std::pair<const GRState *, T> {
+ public:
+ const GRState *getState() const { return this->first; }
+ T getSVal() const { return this->second; }
+ GenericCastResult(const GRState *s, T v)
+ : std::pair<const GRState*,T>(s, v) {}
+ };
- virtual SVal EvalCast(NonLoc val, QualType castTy) = 0;
+ class CastResult : public GenericCastResult<SVal> {
+ public:
+ CastResult(const GRState *s, SVal v) : GenericCastResult<SVal>(s, v) {}
+ };
+
+ class DefinedOrUnknownCastResult :
+ public GenericCastResult<DefinedOrUnknownSVal> {
+ public:
+ DefinedOrUnknownCastResult(const GRState *s, DefinedOrUnknownSVal v)
+ : GenericCastResult<DefinedOrUnknownSVal>(s, v) {}
+ };
- virtual SVal EvalCast(Loc val, QualType castTy) = 0;
+ CastResult EvalCast(SVal V, const GRState *ST,
+ QualType castTy, QualType originalType);
+ DefinedOrUnknownCastResult EvalCast(DefinedOrUnknownSVal V, const GRState *ST,
+ QualType castTy, QualType originalType);
+
virtual SVal EvalMinus(NonLoc val) = 0;
-
+
virtual SVal EvalComplement(NonLoc val) = 0;
- virtual SVal EvalBinOpNN(BinaryOperator::Opcode Op, NonLoc lhs,
- NonLoc rhs, QualType resultTy) = 0;
+ virtual SVal EvalBinOpNN(const GRState *state, BinaryOperator::Opcode Op,
+ NonLoc lhs, NonLoc rhs, QualType resultTy) = 0;
virtual SVal EvalBinOpLL(BinaryOperator::Opcode Op, Loc lhs, Loc rhs,
QualType resultTy) = 0;
virtual SVal EvalBinOpLN(const GRState *state, BinaryOperator::Opcode Op,
- Loc lhs, NonLoc rhs, QualType resultTy) = 0;
-};
+ Loc lhs, NonLoc rhs, QualType resultTy) = 0;
-SValuator* CreateSimpleSValuator(ValueManager &valMgr);
+ SVal EvalBinOp(const GRState *ST, BinaryOperator::Opcode Op,
+ SVal L, SVal R, QualType T);
+ DefinedOrUnknownSVal EvalEQ(const GRState *ST, DefinedOrUnknownSVal L,
+ DefinedOrUnknownSVal R);
+};
+
+SValuator* CreateSimpleSValuator(ValueManager &valMgr);
+
} // end clang namespace
#endif
diff --git a/include/clang/Analysis/PathSensitive/Store.h b/include/clang/Analysis/PathSensitive/Store.h
index 5aa5350..3ff253d 100644
--- a/include/clang/Analysis/PathSensitive/Store.h
+++ b/include/clang/Analysis/PathSensitive/Store.h
@@ -23,16 +23,17 @@
#include "llvm/ADT/SmallVector.h"
namespace clang {
-
+
typedef const void* Store;
-class GRState;
+class GRState;
class GRStateManager;
class Stmt;
class Expr;
class ObjCIvarDecl;
class SubRegionMap;
-
+class StackFrameContext;
+
class StoreManager {
protected:
ValueManager &ValMgr;
@@ -43,37 +44,30 @@ protected:
StoreManager(GRStateManager &stateMgr);
-protected:
- virtual const GRState *AddRegionView(const GRState *state,
- const MemRegion *view,
- const MemRegion *base) {
- return state;
- }
-
-public:
+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
+ /// \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;
+ virtual SValuator::CastResult 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
+ /// \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
@@ -81,36 +75,31 @@ public:
virtual const GRState *BindCompoundLiteral(const GRState *state,
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;
-
+ virtual Store getInitialStore(const LocationContext *InitLoc) = 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 *state, const VarDecl *vd) = 0;
+ virtual SVal getLValueVar(const VarDecl *VD, const LocationContext *LC) = 0;
+
+ virtual SVal getLValueString(const StringLiteral* sl) = 0;
+
+ virtual SVal getLValueCompoundLiteral(const CompoundLiteralExpr* cl) = 0;
- virtual SVal getLValueString(const GRState *state,
- const StringLiteral* sl) = 0;
+ virtual SVal getLValueIvar(const ObjCIvarDecl* decl, SVal base) = 0;
- virtual SVal getLValueCompoundLiteral(const GRState *state,
- const CompoundLiteralExpr* cl) = 0;
-
- virtual SVal getLValueIvar(const GRState *state, const ObjCIvarDecl* decl,
- SVal base) = 0;
-
- virtual SVal getLValueField(const GRState *state, SVal base,
- const FieldDecl* D) = 0;
-
- virtual SVal getLValueElement(const GRState *state, QualType elementType,
- SVal base, SVal offset) = 0;
+ virtual SVal getLValueField(const FieldDecl* D, SVal Base) = 0;
+
+ virtual SVal getLValueElement(QualType elementType, SVal offset, SVal Base)=0;
// FIXME: Make out-of-line.
virtual SVal getSizeInElements(const GRState *state, const MemRegion *region){
@@ -120,7 +109,7 @@ public:
/// 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 *region;
@@ -129,33 +118,32 @@ public:
const MemRegion* getRegion() const { return region; }
CastResult(const GRState *s, const MemRegion* r = 0) : state(s), region(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 *region,
- QualType CastToTy);
+ const MemRegion *CastRegion(const MemRegion *region, QualType CastToTy);
/// EvalBinOp - Perform pointer arithmetic.
virtual SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode Op,
Loc lhs, NonLoc rhs, QualType resultTy) {
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,
+
+ virtual void RemoveDeadBindings(GRState &state, Stmt* Loc,
+ SymbolReaper& SymReaper,
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots) = 0;
- virtual const GRState *BindDecl(const GRState *state, const VarDecl *vd,
- SVal initVal) = 0;
+ virtual const GRState *BindDecl(const GRState *ST, const VarDecl *VD,
+ const LocationContext *LC, SVal initVal) = 0;
- virtual const GRState *BindDeclWithNoInit(const GRState *state,
- const VarDecl *vd) = 0;
+ virtual const GRState *BindDeclWithNoInit(const GRState *ST,
+ const VarDecl *VD,
+ const LocationContext *LC) = 0;
+
+ virtual const GRState *InvalidateRegion(const GRState *state,
+ const MemRegion *R,
+ const Expr *E, unsigned Count) = 0;
// FIXME: Make out-of-line.
virtual const GRState *setExtent(const GRState *state,
@@ -163,25 +151,35 @@ public:
return state;
}
- // FIXME: Make out-of-line.
- virtual const GRState *setDefaultValue(const GRState *state,
- const MemRegion *region,
- SVal val) {
+ /// EnterStackFrame - Let the StoreManager to do something when execution
+ /// engine is about to execute into a callee.
+ virtual const GRState *EnterStackFrame(const GRState *state,
+ const StackFrameContext *frame) {
return state;
}
virtual void print(Store store, llvm::raw_ostream& Out,
const char* nl, const char *sep) = 0;
-
+
class BindingsHandler {
- public:
+ public:
virtual ~BindingsHandler();
virtual bool HandleBinding(StoreManager& SMgr, Store store,
const MemRegion *region, SVal val) = 0;
};
-
+
/// iterBindings - Iterate over the bindings in the Store.
- virtual void iterBindings(Store store, BindingsHandler& f) = 0;
+ virtual void iterBindings(Store store, BindingsHandler& f) = 0;
+
+protected:
+ const MemRegion *MakeElementRegion(const MemRegion *Base,
+ QualType pointeeTy, uint64_t index = 0);
+
+ /// CastRetrievedVal - Used by subclasses of StoreManager to implement
+ /// implicit casts that arise from loads from regions that are reinterpreted
+ /// as another region.
+ SValuator::CastResult CastRetrievedVal(SVal val, const GRState *state,
+ const TypedRegion *R, QualType castTy);
};
// FIXME: Do we still need this?
@@ -190,14 +188,14 @@ public:
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 *region, Visitor& V) const = 0;
+
+ virtual bool iterSubRegions(const MemRegion *region, Visitor& V) const = 0;
};
// FIXME: Do we need to pass GRStateManager anymore?
diff --git a/include/clang/Analysis/PathSensitive/SymbolManager.h b/include/clang/Analysis/PathSensitive/SymbolManager.h
index f32a7e3..d3996c6 100644
--- a/include/clang/Analysis/PathSensitive/SymbolManager.h
+++ b/include/clang/Analysis/PathSensitive/SymbolManager.h
@@ -21,66 +21,72 @@
#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"
+#include "llvm/ADT/DenseSet.h"
namespace llvm {
class raw_ostream;
}
-namespace clang {
+namespace clang {
class MemRegion;
+ class TypedRegion;
class ASTContext;
class BasicValueFactory;
}
namespace clang {
-
+
class SymExpr : public llvm::FoldingSetNode {
public:
- enum Kind { BEGIN_SYMBOLS, RegionValueKind, ConjuredKind, END_SYMBOLS,
+ enum Kind { BEGIN_SYMBOLS,
+ RegionValueKind, ConjuredKind, DerivedKind,
+ END_SYMBOLS,
SymIntKind, SymSymKind };
private:
Kind K;
protected:
- SymExpr(Kind k) : K(k) {}
-
+ SymExpr(Kind k) : K(k) {}
+
public:
virtual ~SymExpr() {}
-
- Kind getKind() const { return K; }
-
- virtual QualType getType(ASTContext&) const = 0;
+
+ Kind getKind() const { return K; }
+
+ void dump() const;
+
+ virtual void dumpToStream(llvm::raw_ostream &os) const = 0;
+
+ 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) {}
+ 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) {
+ 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;
// We may cast the region to another type, so the expected type of the symbol
@@ -90,7 +96,7 @@ class SymbolRegionValue : public SymbolData {
public:
SymbolRegionValue(SymbolID sym, const MemRegion *r, QualType t = QualType())
: SymbolData(RegionValueKind, sym), R(r), T(t) {}
-
+
const MemRegion* getRegion() const { return R; }
static void Profile(llvm::FoldingSetNodeID& profile, const MemRegion* R,
@@ -99,11 +105,13 @@ public:
profile.AddPointer(R);
T.Profile(profile);
}
-
+
virtual void Profile(llvm::FoldingSetNodeID& profile) {
Profile(profile, R, T);
}
-
+
+ void dumpToStream(llvm::raw_ostream &os) const;
+
QualType getType(ASTContext&) const;
// Implement isa<T> support.
@@ -123,15 +131,17 @@ public:
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;
-
+
+ void dumpToStream(llvm::raw_ostream &os) const;
+
static void Profile(llvm::FoldingSetNodeID& profile, const Stmt* S,
- QualType T, unsigned Count, const void* SymbolTag) {
+ QualType T, unsigned Count, const void* SymbolTag) {
profile.AddInteger((unsigned) ConjuredKind);
profile.AddPointer(S);
profile.Add(T);
@@ -146,7 +156,39 @@ public:
// Implement isa<T> support.
static inline bool classof(const SymExpr* SE) {
return SE->getKind() == ConjuredKind;
- }
+ }
+};
+
+class SymbolDerived : public SymbolData {
+ SymbolRef parentSymbol;
+ const TypedRegion *R;
+
+public:
+ SymbolDerived(SymbolID sym, SymbolRef parent, const TypedRegion *r)
+ : SymbolData(DerivedKind, sym), parentSymbol(parent), R(r) {}
+
+ SymbolRef getParentSymbol() const { return parentSymbol; }
+ const TypedRegion *getRegion() const { return R; }
+
+ QualType getType(ASTContext&) const;
+
+ void dumpToStream(llvm::raw_ostream &os) const;
+
+ static void Profile(llvm::FoldingSetNodeID& profile, SymbolRef parent,
+ const TypedRegion *r) {
+ profile.AddInteger((unsigned) DerivedKind);
+ profile.AddPointer(r);
+ profile.AddPointer(parent);
+ }
+
+ virtual void Profile(llvm::FoldingSetNodeID& profile) {
+ Profile(profile, parentSymbol, R);
+ }
+
+ // Implement isa<T> support.
+ static inline bool classof(const SymExpr* SE) {
+ return SE->getKind() == DerivedKind;
+ }
};
// SymIntExpr - Represents symbolic expression like 'x' + 3.
@@ -163,14 +205,16 @@ public:
// FIXME: We probably need to make this out-of-line to avoid redundant
// generation of virtual functions.
- QualType getType(ASTContext& C) const { return T; }
-
+ QualType getType(ASTContext& C) const { return T; }
+
BinaryOperator::Opcode getOpcode() const { return Op; }
-
+
+ void dumpToStream(llvm::raw_ostream &os) const;
+
const SymExpr *getLHS() const { return LHS; }
const llvm::APSInt &getRHS() const { return RHS; }
- static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs,
+ static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs,
BinaryOperator::Opcode op, const llvm::APSInt& rhs,
QualType t) {
ID.AddInteger((unsigned) SymIntKind);
@@ -183,11 +227,11 @@ public:
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'.
@@ -204,11 +248,13 @@ public:
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; }
+ void dumpToStream(llvm::raw_ostream &os) const;
+
static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs,
BinaryOperator::Opcode op, const SymExpr *rhs, QualType t) {
ID.AddInteger((unsigned) SymSymKind);
@@ -221,45 +267,48 @@ public:
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;
+ DataSetTy DataSet;
unsigned SymbolCounter;
llvm::BumpPtrAllocator& BPAlloc;
BasicValueFactory &BV;
ASTContext& Ctx;
-
+
public:
- SymbolManager(ASTContext& ctx, BasicValueFactory &bv,
+ 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 SymbolRegionValue* getRegionValueSymbol(const MemRegion* R,
QualType T = QualType());
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) {
+ const void* SymbolTag = 0) {
return getConjuredSymbol(E, E->getType(), VisitCount, SymbolTag);
}
+ const SymbolDerived *getDerivedSymbol(SymbolRef parentSymbol,
+ const TypedRegion *R);
+
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);
@@ -267,29 +316,28 @@ public:
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;
+ typedef llvm::DenseSet<SymbolRef> SetTy;
+
SetTy TheLiving;
SetTy TheDead;
LiveVariables& Liveness;
SymbolManager& SymMgr;
-
+
public:
SymbolReaper(LiveVariables& liveness, SymbolManager& symmgr)
- : TheLiving(F.GetEmptySet()), TheDead(F.GetEmptySet()),
- Liveness(liveness), SymMgr(symmgr) {}
+ : Liveness(liveness), SymMgr(symmgr) {}
+
+ ~SymbolReaper() {}
bool isLive(SymbolRef sym);
@@ -300,19 +348,19 @@ public:
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;
+
+ typedef SetTy::const_iterator dead_iterator;
dead_iterator dead_begin() const { return TheDead.begin(); }
dead_iterator dead_end() const { return TheDead.end(); }
-
+
bool hasDeadSymbols() const {
- return !TheDead.isEmpty();
+ return !TheDead.empty();
}
};
-
+
class SymbolVisitor {
public:
// VisitSymbol - A visitor method invoked by
@@ -321,11 +369,14 @@ public:
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);
+static inline llvm::raw_ostream& operator<<(llvm::raw_ostream& os,
+ const clang::SymExpr *SE) {
+ SE->dumpToStream(os);
+ return os;
}
+} // end llvm namespace
#endif
diff --git a/include/clang/Analysis/PathSensitive/ValueManager.h b/include/clang/Analysis/PathSensitive/ValueManager.h
index 36d1df2..8d162a6 100644
--- a/include/clang/Analysis/PathSensitive/ValueManager.h
+++ b/include/clang/Analysis/PathSensitive/ValueManager.h
@@ -16,82 +16,123 @@
#ifndef LLVM_CLANG_ANALYSIS_AGGREGATE_VALUE_MANAGER_H
#define LLVM_CLANG_ANALYSIS_AGGREGATE_VALUE_MANAGER_H
+#include "llvm/ADT/OwningPtr.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"
+#include "clang/Analysis/PathSensitive/SValuator.h"
namespace llvm { class BumpPtrAllocator; }
-namespace clang {
+namespace clang {
+
+class GRStateManager;
+
class ValueManager {
- ASTContext &Context;
+ ASTContext &Context;
BasicValueFactory BasicVals;
-
+
/// SymMgr - Object that manages the symbol information.
SymbolManager SymMgr;
+ /// SVator - SValuator object that creates SVals from expressions.
+ llvm::OwningPtr<SValuator> SVator;
MemRegionManager MemMgr;
-
+
+ GRStateManager &StateMgr;
+
+ const QualType ArrayIndexTy;
+ const unsigned ArrayIndexWidth;
+
public:
- ValueManager(llvm::BumpPtrAllocator &alloc, ASTContext &context)
- : Context(context), BasicVals(Context, alloc),
- SymMgr(Context, BasicVals, alloc),
- MemMgr(Context, alloc) {}
+ ValueManager(llvm::BumpPtrAllocator &alloc, ASTContext &context,
+ GRStateManager &stateMgr)
+ : Context(context), BasicVals(context, alloc),
+ SymMgr(context, BasicVals, alloc),
+ MemMgr(context, alloc), StateMgr(stateMgr),
+ ArrayIndexTy(context.IntTy),
+ ArrayIndexWidth(context.getTypeSize(ArrayIndexTy)) {
+ // FIXME: Generalize later.
+ SVator.reset(clang::CreateSimpleSValuator(*this));
+ }
// Accessors to submanagers.
-
+
ASTContext &getContext() { return Context; }
const ASTContext &getContext() const { return Context; }
-
+
+ GRStateManager &getStateManager() { return StateMgr; }
+
BasicValueFactory &getBasicValueFactory() { return BasicVals; }
const BasicValueFactory &getBasicValueFactory() const { return BasicVals; }
-
+
SymbolManager &getSymbolManager() { return SymMgr; }
const SymbolManager &getSymbolManager() const { return SymMgr; }
+ SValuator &getSValuator() { return *SVator.get(); }
+
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) {
+ const void* SymbolTag = 0) {
return SymMgr.getConjuredSymbol(E, VisitCount, SymbolTag);
}
/// makeZeroVal - Construct an SVal representing '0' for the specified type.
- SVal makeZeroVal(QualType T);
+ DefinedOrUnknownSVal makeZeroVal(QualType T);
/// getRegionValueSymbolVal - make a unique symbol for value of R.
- SVal getRegionValueSymbolVal(const MemRegion *R, QualType T = QualType());
-
- SVal getRegionValueSymbolValOrUnknown(const MemRegion *R, QualType T) {
- return SymMgr.canSymbolicate(T) ? getRegionValueSymbolVal(R, T)
- : UnknownVal();
+ DefinedOrUnknownSVal getRegionValueSymbolVal(const MemRegion *R,
+ QualType T = QualType());
+
+ DefinedOrUnknownSVal getRegionValueSymbolValOrUnknown(const MemRegion *R,
+ QualType T) {
+ if (SymMgr.canSymbolicate(T))
+ return getRegionValueSymbolVal(R, T);
+ return UnknownVal();
}
-
- SVal getConjuredSymbolVal(const Expr *E, unsigned Count);
- SVal getConjuredSymbolVal(const Expr* E, QualType T, unsigned Count);
- SVal getFunctionPointer(const FunctionDecl* FD);
+ DefinedOrUnknownSVal getConjuredSymbolVal(const void *SymbolTag,
+ const Expr *E, unsigned Count);
+ DefinedOrUnknownSVal getConjuredSymbolVal(const void *SymbolTag,
+ const Expr *E, QualType T,
+ unsigned Count);
+
+ DefinedOrUnknownSVal getDerivedRegionValueSymbolVal(SymbolRef parentSymbol,
+ const TypedRegion *R);
+
+ DefinedSVal getFunctionPointer(const FunctionDecl *FD);
NonLoc makeCompoundVal(QualType T, llvm::ImmutableList<SVal> Vals) {
return nonloc::CompoundVal(BasicVals.getCompoundValData(T, Vals));
}
+ NonLoc makeLazyCompoundVal(const GRState *state, const TypedRegion *R) {
+ return nonloc::LazyCompoundVal(BasicVals.getLazyCompoundValData(state, R));
+ }
+
NonLoc makeZeroArrayIndex() {
- return nonloc::ConcreteInt(BasicVals.getZeroWithPtrWidth(false));
+ return nonloc::ConcreteInt(BasicVals.getValue(0, ArrayIndexTy));
+ }
+
+ NonLoc makeArrayIndex(uint64_t idx) {
+ return nonloc::ConcreteInt(BasicVals.getValue(idx, ArrayIndexTy));
}
+ SVal convertToArrayIndex(SVal V);
+
nonloc::ConcreteInt makeIntVal(const IntegerLiteral* I) {
return nonloc::ConcreteInt(BasicVals.getValue(I->getValue(),
I->getType()->isUnsignedIntegerType()));
@@ -100,7 +141,7 @@ public:
nonloc::ConcreteInt makeIntVal(const llvm::APSInt& V) {
return nonloc::ConcreteInt(BasicVals.getValue(V));
}
-
+
loc::ConcreteInt makeIntLocVal(const llvm::APSInt &v) {
return loc::ConcreteInt(BasicVals.getValue(v));
}
@@ -109,7 +150,10 @@ public:
return nonloc::ConcreteInt(BasicVals.getValue(V, isUnsigned));
}
- NonLoc makeIntVal(uint64_t X, QualType T) {
+ DefinedSVal makeIntVal(uint64_t X, QualType T) {
+ if (Loc::IsLocType(T))
+ return loc::ConcreteInt(BasicVals.getValue(X, T));
+
return nonloc::ConcreteInt(BasicVals.getValue(X, T));
}
@@ -117,6 +161,10 @@ public:
return nonloc::ConcreteInt(BasicVals.getIntValue(X, isUnsigned));
}
+ NonLoc makeIntValWithPtrWidth(uint64_t X, bool isUnsigned) {
+ return nonloc::ConcreteInt(BasicVals.getIntWithPtrWidth(X, isUnsigned));
+ }
+
NonLoc makeIntVal(uint64_t X, unsigned BitWidth, bool isUnsigned) {
return nonloc::ConcreteInt(BasicVals.getValue(X, BitWidth, isUnsigned));
}
@@ -127,10 +175,10 @@ public:
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) {
return nonloc::ConcreteInt(BasicVals.getTruthValue(b, T));
}
diff --git a/include/clang/Analysis/ProgramPoint.h b/include/clang/Analysis/ProgramPoint.h
index d2b536c..666e45b 100644
--- a/include/clang/Analysis/ProgramPoint.h
+++ b/include/clang/Analysis/ProgramPoint.h
@@ -15,7 +15,7 @@
#ifndef LLVM_CLANG_ANALYSIS_PROGRAM_POINT
#define LLVM_CLANG_ANALYSIS_PROGRAM_POINT
-#include "clang/AST/CFG.h"
+#include "clang/Analysis/CFG.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
@@ -24,123 +24,95 @@
#include <utility>
namespace clang {
-
+
+class LocationContext;
+
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,
+ enum Kind { BlockEdgeKind,
+ BlockEntranceKind,
+ BlockExitKind,
+ PreStmtKind,
+ // Keep the following together and in this order.
+ PostStmtKind,
+ PostLocationChecksSucceedKind,
+ PostOutOfBoundsCheckFailedKind,
+ PostNullCheckFailedKind,
+ PostUndefLocationCheckFailedKind,
+ PostLoadKind,
+ PostStoreKind,
+ PostPurgeDeadSymbolsKind,
+ PostStmtCustomKind,
+ PostLValueKind,
MinPostStmtKind = PostStmtKind,
MaxPostStmtKind = PostLValueKind };
private:
- enum { TwoPointers = 0x1, Custom = 0x2, Mask = 0x3 };
-
- std::pair<uintptr_t,uintptr_t> Data;
+ std::pair<const void *, const void *> Data;
+ Kind K;
+
+ // The LocationContext could be NULL to allow ProgramPoint to be used in
+ // context insensitive analysis.
+ const LocationContext *L;
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);
- }
+ ProgramPoint(const void* P, Kind k, const LocationContext *l,
+ const void *tag = 0)
+ : Data(P, NULL), K(k), L(l), Tag(tag) {}
- void* getData2() const {
- Kind k = getKind(); k = k;
- assert(k == BlockEdgeKind || k == PostStmtCustomKind);
- return reinterpret_cast<void*>(Data.second);
- }
-
+ ProgramPoint(const void* P1, const void* P2, Kind k, const LocationContext *l,
+ const void *tag = 0)
+ : Data(P1, P2), K(k), L(l), Tag(tag) {}
+
+protected:
+ const void* getData1() const { return Data.first; }
+ const void* getData2() const { return Data.second; }
const void *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;
- }
- }
+
+public:
+ Kind getKind() const { return K; }
+
+ const LocationContext *getLocationContext() const { return L; }
// 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);
+ Profile(ID);
return ID.ComputeHash();
}
-
+
static bool classof(const ProgramPoint*) { return true; }
bool operator==(const ProgramPoint & RHS) const {
- return Data == RHS.Data && Tag == RHS.Tag;
+ return K == RHS.K && Data == RHS.Data && L == RHS.L && Tag == RHS.Tag;
}
bool operator!=(const ProgramPoint& RHS) const {
- return Data != RHS.Data || Tag != RHS.Tag;
+ return K != RHS.K || Data != RHS.Data || L != RHS.L || 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.AddInteger((unsigned) K);
+ ID.AddPointer(Data.first);
+ ID.AddPointer(Data.second);
+ ID.AddPointer(L);
ID.AddPointer(Tag);
}
};
-
+
class BlockEntrance : public ProgramPoint {
public:
- BlockEntrance(const CFGBlock* B, const void *tag = 0)
- : ProgramPoint(B, BlockEntranceKind, tag) {}
-
+ BlockEntrance(const CFGBlock* B, const LocationContext *L,
+ const void *tag = 0)
+ : ProgramPoint(B, BlockEntranceKind, L, tag) {}
+
CFGBlock* getBlock() const {
- return reinterpret_cast<CFGBlock*>(getData1NoMask());
+ return const_cast<CFGBlock*>(reinterpret_cast<const CFGBlock*>(getData1()));
}
-
+
Stmt* getFirstStmt() const {
- CFGBlock* B = getBlock();
+ const CFGBlock* B = getBlock();
return B->empty() ? NULL : B->front();
}
@@ -151,42 +123,70 @@ public:
class BlockExit : public ProgramPoint {
public:
- BlockExit(const CFGBlock* B) : ProgramPoint(B, BlockExitKind) {}
-
+ BlockExit(const CFGBlock* B, const LocationContext *L)
+ : ProgramPoint(B, BlockExitKind, L) {}
+
CFGBlock* getBlock() const {
- return reinterpret_cast<CFGBlock*>(getData1NoMask());
+ return const_cast<CFGBlock*>(reinterpret_cast<const CFGBlock*>(getData1()));
}
Stmt* getLastStmt() const {
- CFGBlock* B = getBlock();
+ 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) {}
+class StmtPoint : public ProgramPoint {
+public:
+ StmtPoint(const Stmt *S, const void *p2, Kind k, const LocationContext *L,
+ const void *tag)
+ : ProgramPoint(S, p2, k, L, tag) {}
+
+ const Stmt *getStmt() const { return (const Stmt*) getData1(); }
- PostStmt(const Stmt* S, const void* data, bool, const void *tag =0)
- : ProgramPoint(S, data, true, tag) {}
-
+ template <typename T>
+ const T* getStmtAs() const { return llvm::dyn_cast<T>(getStmt()); }
+
+ static bool classof(const ProgramPoint* Location) {
+ unsigned k = Location->getKind();
+ return k >= PreStmtKind && k <= MaxPostStmtKind;
+ }
+};
+
+
+class PreStmt : public StmtPoint {
public:
- PostStmt(const Stmt* S, const void *tag = 0)
- : ProgramPoint(S, PostStmtKind, tag) {}
+ PreStmt(const Stmt *S, const LocationContext *L, const void *tag,
+ const Stmt *SubStmt = 0)
+ : StmtPoint(S, SubStmt, PreStmtKind, L, tag) {}
- Stmt* getStmt() const { return (Stmt*) getData1(); }
-
- template<typename T>
- T* getStmtAs() const { return llvm::dyn_cast<T>(getStmt()); }
+ const Stmt *getSubStmt() const { return (const Stmt*) getData2(); }
+
+ static bool classof(const ProgramPoint* Location) {
+ return Location->getKind() == PreStmtKind;
+ }
+};
+
+class PostStmt : public StmtPoint {
+protected:
+ PostStmt(const Stmt* S, Kind k, const LocationContext *L, const void *tag = 0)
+ : StmtPoint(S, NULL, k, L, tag) {}
+
+ PostStmt(const Stmt* S, const void* data, Kind k, const LocationContext *L,
+ const void *tag =0)
+ : StmtPoint(S, data, k, L, tag) {}
+
+public:
+ explicit PostStmt(const Stmt* S, const LocationContext *L,const void *tag = 0)
+ : StmtPoint(S, NULL, PostStmtKind, L, tag) {}
static bool classof(const ProgramPoint* Location) {
unsigned k = Location->getKind();
@@ -196,40 +196,42 @@ public:
class PostLocationChecksSucceed : public PostStmt {
public:
- PostLocationChecksSucceed(const Stmt* S, const void *tag = 0)
- : PostStmt(S, PostLocationChecksSucceedKind, tag) {}
-
+ PostLocationChecksSucceed(const Stmt* S, const LocationContext *L,
+ const void *tag = 0)
+ : PostStmt(S, PostLocationChecksSucceedKind, L, 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*>* TaggedData,\
+ const LocationContext *L)
+ : PostStmt(S, TaggedData, PostStmtCustomKind, L) {}
const std::pair<const void*, const void*>& getTaggedPair() const {
- return *reinterpret_cast<std::pair<const void*, const void*>*>(getData2());
+ return
+ *reinterpret_cast<const std::pair<const void*, const void*>*>(getData2());
}
-
+
const void* getTag() const { return getTaggedPair().first; }
-
+
const void* getTaggedData() const { return getTaggedPair().second; }
-
+
static bool classof(const ProgramPoint* Location) {
return Location->getKind() == PostStmtCustomKind;
}
};
-
+
class PostOutOfBoundsCheckFailed : public PostStmt {
public:
- PostOutOfBoundsCheckFailed(const Stmt* S, const void *tag = 0)
- : PostStmt(S, PostOutOfBoundsCheckFailedKind, tag) {}
-
+ PostOutOfBoundsCheckFailed(const Stmt* S, const LocationContext *L,
+ const void *tag = 0)
+ : PostStmt(S, PostOutOfBoundsCheckFailedKind, L, tag) {}
+
static bool classof(const ProgramPoint* Location) {
return Location->getKind() == PostOutOfBoundsCheckFailedKind;
}
@@ -237,39 +239,41 @@ public:
class PostUndefLocationCheckFailed : public PostStmt {
public:
- PostUndefLocationCheckFailed(const Stmt* S, const void *tag = 0)
- : PostStmt(S, PostUndefLocationCheckFailedKind, tag) {}
-
+ PostUndefLocationCheckFailed(const Stmt* S, const LocationContext *L,
+ const void *tag = 0)
+ : PostStmt(S, PostUndefLocationCheckFailedKind, L, 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) {}
-
+ PostNullCheckFailed(const Stmt* S, const LocationContext *L,
+ const void *tag = 0)
+ : PostStmt(S, PostNullCheckFailedKind, L, 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) {}
-
+ PostLoad(const Stmt* S, const LocationContext *L, const void *tag = 0)
+ : PostStmt(S, PostLoadKind, L, 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) {}
-
+ PostStore(const Stmt* S, const LocationContext *L, const void *tag = 0)
+ : PostStmt(S, PostStoreKind, L, tag) {}
+
static bool classof(const ProgramPoint* Location) {
return Location->getKind() == PostStoreKind;
}
@@ -277,60 +281,61 @@ public:
class PostLValue : public PostStmt {
public:
- PostLValue(const Stmt* S, const void *tag = 0)
- : PostStmt(S, PostLValueKind, tag) {}
-
+ PostLValue(const Stmt* S, const LocationContext *L, const void *tag = 0)
+ : PostStmt(S, PostLValueKind, L, 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) {}
-
+ PostPurgeDeadSymbols(const Stmt* S, const LocationContext *L,
+ const void *tag = 0)
+ : PostStmt(S, PostPurgeDeadSymbolsKind, L, 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) {}
-
+ BlockEdge(const CFGBlock* B1, const CFGBlock* B2, const LocationContext *L)
+ : ProgramPoint(B1, B2, BlockEdgeKind, L) {}
+
CFGBlock* getSrc() const {
- return static_cast<CFGBlock*>(getData1());
+ return const_cast<CFGBlock*>(static_cast<const CFGBlock*>(getData1()));
}
-
+
CFGBlock* getDst() const {
- return static_cast<CFGBlock*>(getData2());
+ return const_cast<CFGBlock*>(static_cast<const CFGBlock*>(getData2()));
}
-
+
static bool classof(const ProgramPoint* Location) {
return Location->getKind() == BlockEdgeKind;
}
};
-
+
} // end namespace clang
-namespace llvm { // Traits specialization for DenseMap
-
+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));
+ reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getEmptyKey()) & ~0x7;
+ return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x), 0);
}
static inline clang::ProgramPoint getTombstoneKey() {
uintptr_t x =
- reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getTombstoneKey()) & ~0x7;
- return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x));
+ reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getTombstoneKey()) & ~0x7;
+ return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x), 0);
}
static unsigned getHashValue(const clang::ProgramPoint& Loc) {
diff --git a/include/clang/Analysis/Support/BlkExprDeclBitVector.h b/include/clang/Analysis/Support/BlkExprDeclBitVector.h
index a592be8..27ecc66 100644
--- a/include/clang/Analysis/Support/BlkExprDeclBitVector.h
+++ b/include/clang/Analysis/Support/BlkExprDeclBitVector.h
@@ -17,24 +17,24 @@
#ifndef LLVM_CLANG_STMTDECLBVDVAL_H
#define LLVM_CLANG_STMTDECLBVDVAL_H
-#include "clang/AST/CFG.h"
+#include "clang/Analysis/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;
}
@@ -42,35 +42,35 @@ struct DeclBitVector_Types {
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;
+ 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++;
}
@@ -78,44 +78,44 @@ struct DeclBitVector_Types {
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.resize(AD.getNumDecls());
DeclBV.reset();
}
void setDeclValues(AnalysisDataTy& AD) {
- DeclBV.resize(AD.getNumDecls());
+ DeclBV.resize(AD.getNumDecls());
DeclBV.set();
}
-
+
void resetValues(AnalysisDataTy& AD) {
resetDeclValues(AD);
- }
-
- bool operator==(const ValTy& RHS) const {
+ }
+
+ 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));
@@ -124,48 +124,48 @@ struct DeclBitVector_Types {
bool operator()(const NamedDecl* ND, const AnalysisDataTy& AD) const {
return getBit(AD.getIdx(ND));
}
-
- llvm::BitVector::reference getDeclBit(unsigned i) { return DeclBV[i]; }
+
+ 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.
//===--------------------------------------------------------------------===//
@@ -179,13 +179,13 @@ struct StmtDeclBitVector_Types {
void setContext(ASTContext& c) { ctx = &c; }
ASTContext& getContext() {
- assert(ctx && "ASTContext should not be NULL.");
+ 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;
@@ -195,7 +195,7 @@ struct StmtDeclBitVector_Types {
return I;
}
using DeclBitVector_Types::AnalysisDataTy::getIdx;
-
+
unsigned getNumBlkExprs() const { return cfg->getNumBlkExprs(); }
};
@@ -206,101 +206,101 @@ struct StmtDeclBitVector_Types {
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)
+
+ 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)];
- }
+ 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]; }
+
+ 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
diff --git a/include/clang/Analysis/Support/BumpVector.h b/include/clang/Analysis/Support/BumpVector.h
new file mode 100644
index 0000000..a5e11a1
--- /dev/null
+++ b/include/clang/Analysis/Support/BumpVector.h
@@ -0,0 +1,215 @@
+//===-- BumpVector.h - Vector-like ADT that uses bump allocation --*- 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 BumpVector, a vector-like ADT whose contents are
+// allocated from a BumpPtrAllocator.
+//
+//===----------------------------------------------------------------------===//
+
+// FIXME: Most of this is copy-and-paste from SmallVector.h. We can
+// refactor this core logic into something common that is shared between
+// the two. The main thing that is different is the allocation strategy.
+
+#ifndef LLVM_CLANG_BUMP_VECTOR
+#define LLVM_CLANG_BUMP_VECTOR
+
+#include "llvm/Support/type_traits.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/ADT/PointerIntPair.h"
+#include <algorithm>
+
+namespace clang {
+
+class BumpVectorContext {
+ llvm::PointerIntPair<llvm::BumpPtrAllocator*, 1, bool> Alloc;
+public:
+ /// Construct a new BumpVectorContext that creates a new BumpPtrAllocator
+ /// and destroys it when the BumpVectorContext object is destroyed.
+ BumpVectorContext() : Alloc(new llvm::BumpPtrAllocator(), true) {}
+
+ /// Construct a new BumpVectorContext that reuses an existing
+ /// BumpPtrAllocator. This BumpPtrAllocator is not destroyed when the
+ /// BumpVectorContext object is destroyed.
+ BumpVectorContext(llvm::BumpPtrAllocator &A) : Alloc(&A, false) {}
+
+ ~BumpVectorContext() {
+ if (Alloc.getInt())
+ delete Alloc.getPointer();
+ }
+
+ llvm::BumpPtrAllocator &getAllocator() { return *Alloc.getPointer(); }
+};
+
+template<typename T>
+class BumpVector {
+ T *Begin, *End, *Capacity;
+public:
+ // Default ctor - Initialize to empty.
+ explicit BumpVector(BumpVectorContext &C, unsigned N)
+ : Begin(NULL), End(NULL), Capacity(NULL) {
+ reserve(C, N);
+ }
+
+ ~BumpVector() {
+ if (llvm::is_class<T>::value) {
+ // Destroy the constructed elements in the vector.
+ destroy_range(Begin, End);
+ }
+ }
+
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef T value_type;
+ typedef T* iterator;
+ typedef const T* const_iterator;
+
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+
+ // forward iterator creation methods.
+ iterator begin() { return Begin; }
+ const_iterator begin() const { return Begin; }
+ iterator end() { return End; }
+ const_iterator end() const { return 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());}
+
+ bool empty() const { return Begin == End; }
+ size_type size() const { return End-Begin; }
+
+ reference operator[](unsigned idx) {
+ assert(Begin + idx < End);
+ return Begin[idx];
+ }
+ const_reference operator[](unsigned idx) const {
+ assert(Begin + idx < End);
+ return Begin[idx];
+ }
+
+ reference front() {
+ return begin()[0];
+ }
+ const_reference front() const {
+ return begin()[0];
+ }
+
+ reference back() {
+ return end()[-1];
+ }
+ const_reference back() const {
+ return end()[-1];
+ }
+
+ void pop_back() {
+ --End;
+ End->~T();
+ }
+
+ T pop_back_val() {
+ T Result = back();
+ pop_back();
+ return Result;
+ }
+
+ void clear() {
+ if (llvm::is_class<T>::value) {
+ destroy_range(Begin, End);
+ }
+ End = Begin;
+ }
+
+ /// data - Return a pointer to the vector's buffer, even if empty().
+ pointer data() {
+ return pointer(Begin);
+ }
+
+ /// data - Return a pointer to the vector's buffer, even if empty().
+ const_pointer data() const {
+ return const_pointer(Begin);
+ }
+
+ void push_back(const_reference Elt, BumpVectorContext &C) {
+ if (End < Capacity) {
+ Retry:
+ new (End) T(Elt);
+ ++End;
+ return;
+ }
+ grow(C);
+ goto Retry;
+ }
+
+ void reserve(BumpVectorContext &C, unsigned N) {
+ if (unsigned(Capacity-Begin) < N)
+ grow(C, N);
+ }
+
+ /// capacity - Return the total number of elements in the currently allocated
+ /// buffer.
+ size_t capacity() const { return Capacity - Begin; }
+
+private:
+ /// grow - double the size of the allocated memory, guaranteeing space for at
+ /// least one more element or MinSize if specified.
+ void grow(BumpVectorContext &C, size_type MinSize = 0);
+
+ void construct_range(T *S, T *E, const T &Elt) {
+ for (; S != E; ++S)
+ new (S) T(Elt);
+ }
+
+ void destroy_range(T *S, T *E) {
+ while (S != E) {
+ --E;
+ E->~T();
+ }
+ }
+};
+
+// Define this out-of-line to dissuade the C++ compiler from inlining it.
+template <typename T>
+void BumpVector<T>::grow(BumpVectorContext &C, size_t MinSize) {
+ size_t CurCapacity = Capacity-Begin;
+ size_t CurSize = size();
+ size_t NewCapacity = 2*CurCapacity;
+ if (NewCapacity < MinSize)
+ NewCapacity = MinSize;
+
+ // Allocate the memory from the BumpPtrAllocator.
+ T *NewElts = C.getAllocator().template Allocate<T>(NewCapacity);
+
+ // Copy the elements over.
+ if (llvm::is_class<T>::value) {
+ std::uninitialized_copy(Begin, End, NewElts);
+ // Destroy the original elements.
+ destroy_range(Begin, End);
+ }
+ else {
+ // Use memcpy for PODs (std::uninitialized_copy optimizes to memmove).
+ memcpy(NewElts, Begin, CurSize * sizeof(T));
+ }
+
+ // For now, leak 'Begin'. We can add it back to a freelist in
+ // BumpVectorContext.
+ Begin = NewElts;
+ End = NewElts+CurSize;
+ Capacity = Begin+NewCapacity;
+}
+
+} // end: clang namespace
+#endif // end: LLVM_CLANG_BUMP_VECTOR
diff --git a/include/clang/Analysis/Support/Optional.h b/include/clang/Analysis/Support/Optional.h
new file mode 100644
index 0000000..3940007
--- /dev/null
+++ b/include/clang/Analysis/Support/Optional.h
@@ -0,0 +1,55 @@
+//===-- Optional.h - Simple variant for passing optional 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 provides Optional, a template class modeled in the spirit of
+// OCaml's 'opt' variant. The idea is to strongly type whether or not
+// a value can be optional.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_OPTIONAL
+#define LLVM_CLANG_ANALYSIS_OPTIONAL
+
+namespace clang {
+
+template<typename T>
+class Optional {
+ const T x;
+ unsigned hasVal : 1;
+public:
+ explicit Optional() : hasVal(false) {}
+ Optional(const T &y) : x(y), hasVal(true) {}
+
+ static inline Optional create(const T* y) {
+ return y ? Optional(*y) : Optional();
+ }
+
+ const T* getPointer() const { assert(hasVal); return &x; }
+
+ operator bool() const { return hasVal; }
+ const T* operator->() const { return getPointer(); }
+ const T& operator*() const { assert(hasVal); return x; }
+};
+} //end clang namespace
+
+namespace llvm {
+template <typename T>
+struct simplify_type<const ::clang::Optional<T> > {
+ typedef const T* SimpleType;
+ static SimpleType getSimplifiedValue(const ::clang::Optional<T> &Val) {
+ return Val.getPointer();
+ }
+};
+
+template <typename T>
+struct simplify_type< ::clang::Optional<T> >
+ : public simplify_type<const ::clang::Optional<T> > {};
+} // end llvm namespace
+
+#endif
diff --git a/include/clang/Analysis/Support/SaveAndRestore.h b/include/clang/Analysis/Support/SaveAndRestore.h
new file mode 100644
index 0000000..4720c22
--- /dev/null
+++ b/include/clang/Analysis/Support/SaveAndRestore.h
@@ -0,0 +1,44 @@
+//===-- SaveAndRestore.h - Utility -------------------------------*- 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 utility classes that uses RAII to save and restore
+// values.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_SAVERESTORE
+#define LLVM_CLANG_ANALYSIS_SAVERESTORE
+
+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;
+};
+
+}
+#endif
diff --git a/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h b/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h
index ee79c51..3826d3a 100644
--- a/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h
+++ b/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h
@@ -30,28 +30,28 @@ break;
#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:
+public:
void VisitDeclRefExpr(DeclRefExpr* DR) {
- static_cast<ImplClass*>(this)->VisitDecl(DR->getDecl());
+ 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);
+ 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)
@@ -67,7 +67,7 @@ public:
assert(false && "Subtype of ScopedDecl not handled.");
}
}
-
+
DEFAULT_DISPATCH(VarDecl)
DEFAULT_DISPATCH(FunctionDecl)
DEFAULT_DISPATCH_VARDECL(OriginalParmVarDecl)
diff --git a/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h b/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h
index 4d32019..83700a3 100644
--- a/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h
+++ b/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h
@@ -20,12 +20,12 @@
namespace clang {
template <typename ImplClass>
class CFGRecStmtVisitor : public CFGStmtVisitor<ImplClass,void> {
-public:
+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);}
};
diff --git a/include/clang/Analysis/Visitors/CFGStmtVisitor.h b/include/clang/Analysis/Visitors/CFGStmtVisitor.h
index f42bbde..426b9cc 100644
--- a/include/clang/Analysis/Visitors/CFGStmtVisitor.h
+++ b/include/clang/Analysis/Visitors/CFGStmtVisitor.h
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This file defines the CFGStmtVisitor interface, which extends
+// 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.
@@ -18,13 +18,13 @@
#define LLVM_CLANG_ANALYSIS_CFGSTMTVISITOR_H
#include "clang/AST/StmtVisitor.h"
-#include "clang/AST/CFG.h"
+#include "clang/Analysis/CFG.h"
namespace clang {
#define DISPATCH_CASE(CLASS) \
case Stmt::CLASS ## Class: return \
-static_cast<ImplClass*>(this)->BlockStmt_Visit ## CLASS(static_cast<CLASS*>(S));
+static_cast<ImplClass*>(this)->BlockStmt_Visit ## CLASS(static_cast<CLASS*>(S));
#define DEFAULT_BLOCKSTMT_VISIT(CLASS) RetTy BlockStmt_Visit ## CLASS(CLASS *S)\
{ return\
@@ -36,40 +36,40 @@ class CFGStmtVisitor : public StmtVisitor<ImplClass,RetTy> {
Stmt* CurrentBlkStmt;
struct NullifyStmt {
- Stmt*& S;
-
+ Stmt*& S;
+
NullifyStmt(Stmt*& s) : S(s) {}
~NullifyStmt() { S = NULL; }
};
-
+
public:
- CFGStmtVisitor() : CurrentBlkStmt(NULL) {}
-
+ CFGStmtVisitor() : CurrentBlkStmt(NULL) {}
+
Stmt* getCurrentBlkStmt() const { return CurrentBlkStmt; }
-
+
RetTy Visit(Stmt* S) {
- if (S == CurrentBlkStmt ||
+ 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
+ /// 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())
@@ -78,40 +78,40 @@ public:
return static_cast<ImplClass*>(this)->BlockStmt_VisitComma(B);
// Fall through.
}
-
+
default:
if (isa<Expr>(S))
- return
+ return
static_cast<ImplClass*>(this)->BlockStmt_VisitExpr(cast<Expr>(S));
else
- return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S);
+ 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
+ return
static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowExpr(B);
}
-
+
RetTy BlockStmt_VisitComma(BinaryOperator* B) {
return
static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowExpr(B);
@@ -120,21 +120,21 @@ public:
//===--------------------------------------------------------------------===//
// 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;
@@ -142,12 +142,12 @@ public:
return;
}
}
-
+
for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I != E;++I)
- if (*I) static_cast<ImplClass*>(this)->Visit(*I);
+ if (*I) static_cast<ImplClass*>(this)->Visit(*I);
}
-};
-
+};
+
#undef DEFAULT_BLOCKSTMT_VISIT
#undef DISPATCH_CASE
diff --git a/include/clang/Analysis/Visitors/CFGVarDeclVisitor.h b/include/clang/Analysis/Visitors/CFGVarDeclVisitor.h
index 2510123..1bc798f 100644
--- a/include/clang/Analysis/Visitors/CFGVarDeclVisitor.h
+++ b/include/clang/Analysis/Visitors/CFGVarDeclVisitor.h
@@ -18,44 +18,43 @@
#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:
+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) {
+
+ 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));
+ static_cast<ImplClass*>(this)->BlockStmt_Visit(const_cast<Stmt*>(*SI));
}
};
diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def
index c2f4061..2799785 100644
--- a/include/clang/Basic/Builtins.def
+++ b/include/clang/Basic/Builtins.def
@@ -35,7 +35,10 @@
// a -> __builtin_va_list
// A -> "reference" to __builtin_va_list
// V -> Vector, following num elements and a base type.
+// X -> _Complex, followed by the base type.
// P -> FILE
+// J -> jmp_buf
+// SJ -> sigjmp_buf
// . -> "...". This may only occur at the end of the function list.
//
// Types maybe prefixed with the following modifiers:
@@ -54,15 +57,16 @@
// of the function. These must be kept in sync with the predicates in the
// Builtin::Context class. Currently we have:
// n -> nothrow
+// r -> noreturn
// 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
+// 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
+// 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
@@ -72,28 +76,152 @@
#endif
// Standard libc/libm functions:
+BUILTIN(__builtin_atan2 , "ddd" , "nc")
+BUILTIN(__builtin_atan2f, "fff" , "nc")
+BUILTIN(__builtin_atan2l, "LdLdLd", "nc")
+BUILTIN(__builtin_abs , "ii" , "ncF")
+BUILTIN(__builtin_copysign, "ddd", "ncF")
+BUILTIN(__builtin_copysignf, "fff", "ncF")
+BUILTIN(__builtin_copysignl, "LdLdLd", "ncF")
+BUILTIN(__builtin_fabs , "dd" , "ncF")
+BUILTIN(__builtin_fabsf, "ff" , "ncF")
+BUILTIN(__builtin_fabsl, "LdLd", "ncF")
+BUILTIN(__builtin_fmod , "ddd" , "nc")
+BUILTIN(__builtin_fmodf, "fff" , "nc")
+BUILTIN(__builtin_fmodl, "LdLdLd", "nc")
+BUILTIN(__builtin_frexp , "ddi*" , "nc")
+BUILTIN(__builtin_frexpf, "ffi*" , "nc")
+BUILTIN(__builtin_frexpl, "LdLdi*", "nc")
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_ldexp , "ddi" , "nc")
+BUILTIN(__builtin_ldexpf, "ffi" , "nc")
+BUILTIN(__builtin_ldexpl, "LdLdi", "nc")
+BUILTIN(__builtin_modf , "ddd*" , "nc")
+BUILTIN(__builtin_modff, "fff*" , "nc")
+BUILTIN(__builtin_modfl, "LdLdLd*", "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")
+BUILTIN(__builtin_pow , "ddd" , "nc")
+BUILTIN(__builtin_powf, "fff" , "nc")
+BUILTIN(__builtin_powl, "LdLdLd", "nc")
+
+// Standard unary libc/libm functions with double/float/long double variants:
+BUILTIN(__builtin_acos , "dd" , "nc")
+BUILTIN(__builtin_acosf, "ff" , "nc")
+BUILTIN(__builtin_acosl, "LdLd", "nc")
+BUILTIN(__builtin_asin , "dd" , "nc")
+BUILTIN(__builtin_asinf, "ff" , "nc")
+BUILTIN(__builtin_asinl, "LdLd", "nc")
+BUILTIN(__builtin_atan , "dd" , "nc")
+BUILTIN(__builtin_atanf, "ff" , "nc")
+BUILTIN(__builtin_atanl, "LdLd", "nc")
+BUILTIN(__builtin_ceil , "dd" , "nc")
+BUILTIN(__builtin_ceilf, "ff" , "nc")
+BUILTIN(__builtin_ceill, "LdLd", "nc")
+BUILTIN(__builtin_cos , "dd" , "nc")
+BUILTIN(__builtin_cosf, "ff" , "nc")
+BUILTIN(__builtin_cosh , "dd" , "nc")
+BUILTIN(__builtin_coshf, "ff" , "nc")
+BUILTIN(__builtin_coshl, "LdLd", "nc")
+BUILTIN(__builtin_cosl, "LdLd", "nc")
+BUILTIN(__builtin_exp , "dd" , "nc")
+BUILTIN(__builtin_expf, "ff" , "nc")
+BUILTIN(__builtin_expl, "LdLd", "nc")
+BUILTIN(__builtin_floor , "dd" , "nc")
+BUILTIN(__builtin_floorf, "ff" , "nc")
+BUILTIN(__builtin_floorl, "LdLd", "nc")
+BUILTIN(__builtin_log , "dd" , "nc")
+BUILTIN(__builtin_log10 , "dd" , "nc")
+BUILTIN(__builtin_log10f, "ff" , "nc")
+BUILTIN(__builtin_log10l, "LdLd", "nc")
+BUILTIN(__builtin_logf, "ff" , "nc")
+BUILTIN(__builtin_logl, "LdLd", "nc")
+BUILTIN(__builtin_sin , "dd" , "nc")
+BUILTIN(__builtin_sinf, "ff" , "nc")
+BUILTIN(__builtin_sinh , "dd" , "nc")
+BUILTIN(__builtin_sinhf, "ff" , "nc")
+BUILTIN(__builtin_sinhl, "LdLd", "nc")
+BUILTIN(__builtin_sinl, "LdLd", "nc")
+BUILTIN(__builtin_sqrt , "dd" , "nc")
+BUILTIN(__builtin_sqrtf, "ff" , "nc")
+BUILTIN(__builtin_sqrtl, "LdLd", "nc")
+BUILTIN(__builtin_tan , "dd" , "nc")
+BUILTIN(__builtin_tanf, "ff" , "nc")
+BUILTIN(__builtin_tanh , "dd" , "nc")
+BUILTIN(__builtin_tanhf, "ff" , "nc")
+BUILTIN(__builtin_tanhl, "LdLd", "nc")
+BUILTIN(__builtin_tanl, "LdLd", "nc")
+
+// C99 complex builtins
+BUILTIN(__builtin_cabs, "dXd", "Fnc")
+BUILTIN(__builtin_cabsf, "fXf", "Fnc")
+BUILTIN(__builtin_cabsl, "LdXLd", "Fnc")
+BUILTIN(__builtin_cacos, "XdXd", "Fnc")
+BUILTIN(__builtin_cacosf, "XfXf", "Fnc")
+BUILTIN(__builtin_cacosl, "XLdXLd", "Fnc")
+BUILTIN(__builtin_carg, "dXd", "Fnc")
+BUILTIN(__builtin_cargf, "fXf", "Fnc")
+BUILTIN(__builtin_cargl, "LdXLd", "Fnc")
+BUILTIN(__builtin_casin, "XdXd", "Fnc")
+BUILTIN(__builtin_casinf, "XfXf", "Fnc")
+BUILTIN(__builtin_casinl, "XLdXLd", "Fnc")
+BUILTIN(__builtin_catan, "XdXd", "Fnc")
+BUILTIN(__builtin_catanf, "XfXf", "Fnc")
+BUILTIN(__builtin_catanl, "XLdXLd", "Fnc")
+BUILTIN(__builtin_ccos, "XdXd", "Fnc")
+BUILTIN(__builtin_ccosf, "XfXf", "Fnc")
+BUILTIN(__builtin_ccosl, "XLdXLd", "Fnc")
+BUILTIN(__builtin_ccosh, "XdXd", "Fnc")
+BUILTIN(__builtin_ccoshf, "XfXf", "Fnc")
+BUILTIN(__builtin_ccoshl, "XLdXLd", "Fnc")
+BUILTIN(__builtin_cexp, "XdXd", "Fnc")
+BUILTIN(__builtin_cexpf, "XfXf", "Fnc")
+BUILTIN(__builtin_cexpl, "XLdXLd", "Fnc")
+BUILTIN(__builtin_cimag, "dXd", "Fnc")
+BUILTIN(__builtin_cimagf, "fXf", "Fnc")
+BUILTIN(__builtin_cimagl, "LdXLd", "Fnc")
+BUILTIN(__builtin_conj, "dXd", "Fnc")
+BUILTIN(__builtin_conjf, "fXf", "Fnc")
+BUILTIN(__builtin_conjl, "LdXLd", "Fnc")
+BUILTIN(__builtin_clog, "XdXd", "Fnc")
+BUILTIN(__builtin_clogf, "XfXf", "Fnc")
+BUILTIN(__builtin_clogl, "XLdXLd", "Fnc")
+BUILTIN(__builtin_cproj, "XdXd", "Fnc")
+BUILTIN(__builtin_cprojf, "XfXf", "Fnc")
+BUILTIN(__builtin_cprojl, "XLdXLd", "Fnc")
+BUILTIN(__builtin_cpow, "XdXdXd", "Fnc")
+BUILTIN(__builtin_cpowf, "XfXfXf", "Fnc")
+BUILTIN(__builtin_cpowl, "XLdXLdXLd", "Fnc")
+BUILTIN(__builtin_creal, "dXd", "Fnc")
+BUILTIN(__builtin_crealf, "fXf", "Fnc")
+BUILTIN(__builtin_creall, "LdXLd", "Fnc")
+BUILTIN(__builtin_csin, "XdXd", "Fnc")
+BUILTIN(__builtin_csinf, "XfXf", "Fnc")
+BUILTIN(__builtin_csinl, "XLdXLd", "Fnc")
+BUILTIN(__builtin_csinh, "XdXd", "Fnc")
+BUILTIN(__builtin_csinhf, "XfXf", "Fnc")
+BUILTIN(__builtin_csinhl, "XLdXLd", "Fnc")
+BUILTIN(__builtin_csqrt, "XdXd", "Fnc")
+BUILTIN(__builtin_csqrtf, "XfXf", "Fnc")
+BUILTIN(__builtin_csqrtl, "XLdXLd", "Fnc")
+BUILTIN(__builtin_ctan, "XdXd", "Fnc")
+BUILTIN(__builtin_ctanf, "XfXf", "Fnc")
+BUILTIN(__builtin_ctanl, "XLdXLd", "Fnc")
+BUILTIN(__builtin_ctanh, "XdXd", "Fnc")
+BUILTIN(__builtin_ctanhf, "XfXf", "Fnc")
+BUILTIN(__builtin_ctanhl, "XLdXLd", "Fnc")
// FP Comparisons.
BUILTIN(__builtin_isgreater , "i.", "nc")
@@ -103,6 +231,14 @@ BUILTIN(__builtin_islessequal , "i.", "nc")
BUILTIN(__builtin_islessgreater , "i.", "nc")
BUILTIN(__builtin_isunordered , "i.", "nc")
+// Unary FP classification
+// BUILTIN(__builtin_fpclassify, "iiiii.", "nc")
+BUILTIN(__builtin_isfinite, "i.", "nc")
+BUILTIN(__builtin_isinf, "i.", "nc")
+BUILTIN(__builtin_isinf_sign, "i.", "nc")
+BUILTIN(__builtin_isnan, "i.", "nc")
+BUILTIN(__builtin_isnormal, "i.", "nc")
+
// Builtins for arithmetic.
BUILTIN(__builtin_clz , "iUi" , "nc")
BUILTIN(__builtin_clzl , "iULi" , "nc")
@@ -138,6 +274,7 @@ 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_memchr, "v*vC*iz", "nF")
BUILTIN(__builtin_memcmp, "ivC*vC*z", "nF")
BUILTIN(__builtin_memcpy, "v*v*vC*z", "nF")
BUILTIN(__builtin_memmove, "v*v*vC*z", "nF")
@@ -169,6 +306,8 @@ BUILTIN(__builtin_flt_rounds, "i", "nc")
BUILTIN(__builtin_setjmp, "iv**", "")
BUILTIN(__builtin_longjmp, "vv**i", "")
BUILTIN(__builtin_unwind_init, "v", "")
+BUILTIN(__builtin_eh_return_data_regno, "ii", "nc")
+BUILTIN(__builtin_vsnprintf, "ic*zcC*a", "nFP:2:")
// GCC Object size checking builtins
BUILTIN(__builtin_object_size, "zv*i", "n")
@@ -192,7 +331,9 @@ 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_abort, "v", "Fnr")
+BUILTIN(__builtin_trap, "v", "nr")
+BUILTIN(__builtin_unreachable, "v", "nr")
BUILTIN(__builtin_shufflevector, "v." , "nc")
@@ -335,6 +476,8 @@ BUILTIN(__sync_fetch_and_umax, "UiUi*Ui", "n")
// C99 library functions
// C99 stdlib.h
LIBBUILTIN(calloc, "v*zz", "f", "stdlib.h")
+LIBBUILTIN(exit, "vi", "fr", "stdlib.h")
+LIBBUILTIN(_Exit, "vi", "fr", "stdlib.h")
LIBBUILTIN(malloc, "v*z", "f", "stdlib.h")
LIBBUILTIN(realloc, "v*v*z", "f", "stdlib.h")
// C99 string.h
@@ -365,6 +508,8 @@ LIBBUILTIN(vprintf, "icC*a", "fP:0:", "stdio.h")
LIBBUILTIN(vfprintf, "i.", "fP:1:", "stdio.h")
LIBBUILTIN(vsnprintf, "ic*zcC*a", "fP:2:", "stdio.h")
LIBBUILTIN(vsprintf, "ic*cC*a", "fP:1:", "stdio.h")
+// C99
+LIBBUILTIN(longjmp, "vJi", "fr", "setjmp.h")
// Non-C library functions
// FIXME: Non-C-standard stuff shouldn't be builtins in non-GNU mode!
@@ -377,15 +522,17 @@ LIBBUILTIN(strndup, "c*cC*z", "f", "string.h")
// POSIX strings.h
LIBBUILTIN(index, "c*cC*i", "f", "strings.h")
LIBBUILTIN(rindex, "c*cC*i", "f", "strings.h")
+// POSIX unistd.h
+LIBBUILTIN(_exit, "vi", "fr", "unistd.h")
+// POSIX setjmp.h
+LIBBUILTIN(_longjmp, "vJi", "fr", "setjmp.h")
+LIBBUILTIN(siglongjmp, "vSJi", "fr", "setjmp.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")
diff --git a/include/clang/Basic/Builtins.h b/include/clang/Basic/Builtins.h
index f770c50..07f091a 100644
--- a/include/clang/Basic/Builtins.h
+++ b/include/clang/Basic/Builtins.h
@@ -17,6 +17,10 @@
#include <cstring>
+// VC++ defines 'alloca' as an object-like macro, which interferes with our
+// builtins.
+#undef alloca
+
namespace llvm {
template <typename T> class SmallVectorImpl;
}
@@ -63,35 +67,40 @@ public:
/// \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;
}
-
+
/// GetTypeString - Get the type descriptor string for the specified builtin.
const char *GetTypeString(unsigned ID) const {
return GetRecord(ID).Type;
}
-
+
/// 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;
}
-
+
+ /// isNoReturn - Return true if we know this builtin never returns.
+ bool isNoReturn(unsigned ID) const {
+ return strchr(GetRecord(ID).Attributes, 'r') != 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.
@@ -115,7 +124,7 @@ public:
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
diff --git a/include/clang/Basic/ConvertUTF.h b/include/clang/Basic/ConvertUTF.h
index 73e2fcd..4da2ad75 100644
--- a/include/clang/Basic/ConvertUTF.h
+++ b/include/clang/Basic/ConvertUTF.h
@@ -8,9 +8,9 @@
*==------------------------------------------------------------------------==*/
/*
* 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
@@ -18,9 +18,9 @@
* 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
@@ -41,7 +41,7 @@
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.
+ 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,
@@ -53,12 +53,12 @@
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.
+ 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
@@ -75,15 +75,15 @@
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.
+ 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.
+ Fixes & updates, Sept 2001.
------------------------------------------------------------------------ */
@@ -95,10 +95,10 @@
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 */
+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
@@ -108,15 +108,15 @@ typedef unsigned char Boolean; /* 0 or 1 */
#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 */
+ 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
+ strictConversion = 0,
+ lenientConversion
} ConversionFlags;
/* This is for C++ and does no harm in C */
@@ -125,29 +125,29 @@ extern "C" {
#endif
ConversionResult ConvertUTF8toUTF16 (
- const UTF8** sourceStart, const UTF8* sourceEnd,
- UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
+ 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);
-
+ 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);
+ 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);
-
+ 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);
+ 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);
+ const UTF32** sourceStart, const UTF32* sourceEnd,
+ UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
#endif
Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h
index 207710b..380192e 100644
--- a/include/clang/Basic/Diagnostic.h
+++ b/include/clang/Basic/Diagnostic.h
@@ -15,7 +15,9 @@
#define LLVM_CLANG_DIAGNOSTIC_H
#include "clang/Basic/SourceLocation.h"
+#include "llvm/Support/type_traits.h"
#include <string>
+#include <vector>
#include <cassert>
namespace llvm {
@@ -23,12 +25,14 @@ namespace llvm {
}
namespace clang {
- class DiagnosticClient;
- class SourceRange;
+ class DeclContext;
class DiagnosticBuilder;
+ class DiagnosticClient;
class IdentifierInfo;
class LangOptions;
-
+ class PartialDiagnostic;
+ class SourceRange;
+
// Import the diagnostic enums themselves.
namespace diag {
// Start position for diagnostics.
@@ -44,7 +48,7 @@ namespace clang {
};
class CustomDiagInfo;
-
+
/// diag::kind - All of the diagnostics that can be emitted by the frontend.
typedef unsigned kind;
@@ -55,7 +59,7 @@ namespace clang {
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
@@ -67,13 +71,13 @@ namespace clang {
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.
///
@@ -102,7 +106,7 @@ public:
/// \brief Create a code modification hint that inserts the given
/// code string at a specific location.
- static CodeModificationHint CreateInsertion(SourceLocation InsertionLoc,
+ static CodeModificationHint CreateInsertion(SourceLocation InsertionLoc,
const std::string &Code) {
CodeModificationHint Hint;
Hint.InsertionLoc = InsertionLoc;
@@ -120,7 +124,7 @@ public:
/// \brief Create a code modification hint that replaces the given
/// source range with the given code string.
- static CodeModificationHint CreateReplacement(SourceRange RemoveRange,
+ static CodeModificationHint CreateReplacement(SourceRange RemoveRange,
const std::string &Code) {
CodeModificationHint Hint;
Hint.RemoveRange = RemoveRange;
@@ -140,13 +144,13 @@ public:
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 *
@@ -155,14 +159,17 @@ public:
ak_identifierinfo, // IdentifierInfo
ak_qualtype, // QualType
ak_declarationname, // DeclarationName
- ak_nameddecl // NamedDecl *
+ ak_nameddecl, // NamedDecl *
+ ak_nestednamespec, // NestedNameSpecifier *
+ ak_declcontext // DeclContext *
};
-private:
+private:
unsigned char AllExtensionsSilenced; // Used by __extension__
bool IgnoreAllWarnings; // Ignore all warnings: -w
- bool WarningsAsErrors; // Treat warnings like errors:
+ bool WarningsAsErrors; // Treat warnings like errors:
bool SuppressSystemWarnings; // Suppress warnings in system headers.
+ bool SuppressAllDiagnostics; // Suppress all diagnostics.
ExtensionHandling ExtBehavior; // Map extensions onto warnings or errors?
DiagnosticClient *Client;
@@ -172,13 +179,15 @@ private:
/// 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];
-
+
+ typedef std::vector<unsigned char> DiagMappings;
+ mutable std::vector<DiagMappings> DiagMappingsStack;
+
/// 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.
@@ -204,44 +213,70 @@ private:
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; };
-
+
+
+ /// pushMappings - Copies the current DiagMappings and pushes the new copy
+ /// onto the top of the stack.
+ void pushMappings();
+
+ /// popMappings - Pops the current DiagMappings off the top of the stack
+ /// causing the new top of the stack to be the active mappings. Returns
+ /// true if the pop happens, false if there is only one DiagMapping on the
+ /// stack.
+ bool popMappings();
+
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; }
+ /// \brief Suppress all diagnostics, to silence the front end when we
+ /// know that we don't want any more diagnostics to be passed along to the
+ /// client
+ void setSuppressAllDiagnostics(bool Val = true) {
+ SuppressAllDiagnostics = Val;
+ }
+ bool getSuppressAllDiagnostics() const { return SuppressAllDiagnostics; }
+
+ /// \brief Pretend that the last diagnostic issued was ignored. This can
+ /// be used by clients who suppress diagnostics themselves.
+ void setLastDiagnosticIgnored() {
+ LastDiagLevel = Ignored;
+ }
+
/// 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; }
-
+ bool hasAllExtensionsSilenced() { return AllExtensionsSilenced != 0; }
+
/// 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.
@@ -252,7 +287,7 @@ public:
"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.
@@ -263,13 +298,13 @@ public:
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,
@@ -279,12 +314,12 @@ public:
ArgToStringFn(Kind, Val, Modifier, ModLen, Argument, ArgLen, Output,
ArgToStringCookie);
}
-
+
void SetArgToStringFn(ArgToStringFnTy Fn, void *Cookie) {
ArgToStringFn = Fn;
ArgToStringCookie = Cookie;
}
-
+
//===--------------------------------------------------------------------===//
// Diagnostic classification and reporting interfaces.
//
@@ -292,7 +327,7 @@ public:
/// 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
@@ -302,12 +337,12 @@ public:
/// \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.
@@ -326,8 +361,8 @@ public:
/// 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;
-
+ 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.
@@ -337,24 +372,25 @@ public:
/// \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);
+ const DiagMappings &currentMappings = DiagMappingsStack.back();
+ return (diag::Mapping)((currentMappings[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 char &Slot = DiagMappingsStack.back()[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;
@@ -371,7 +407,7 @@ private:
/// 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;
@@ -382,7 +418,7 @@ private:
/// 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.
@@ -395,7 +431,7 @@ private:
/// 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.
@@ -406,11 +442,11 @@ private:
/// 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
@@ -443,14 +479,14 @@ private:
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),
+ : DiagObj(diagObj), NumArgs(0), NumRanges(0),
NumCodeModificationHints(0) {}
-public:
+public:
/// Copy constructor. When copied, this "takes" the diagnostic info from the
/// input and neuters it.
DiagnosticBuilder(const DiagnosticBuilder &D) {
@@ -467,7 +503,7 @@ public:
/// \brief Create an empty DiagnosticBuilder object that represents
/// no actual diagnostic.
- explicit DiagnosticBuilder(SuppressKind)
+ explicit DiagnosticBuilder(SuppressKind)
: DiagObj(0), NumArgs(0), NumRanges(0), NumCodeModificationHints(0) { }
/// \brief Force the diagnostic builder to emit the diagnostic now.
@@ -504,7 +540,7 @@ public:
/// 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(...);
@@ -518,7 +554,7 @@ public:
DiagObj->DiagArgumentsStr[NumArgs++] = S;
}
}
-
+
void AddTaggedVal(intptr_t V, Diagnostic::ArgumentKind Kind) const {
assert(NumArgs < Diagnostic::MaxArguments &&
"Too many arguments to diagnostic!");
@@ -527,14 +563,14 @@ public:
DiagObj->DiagArgumentsVal[NumArgs++] = V;
}
}
-
+
void AddSourceRange(const SourceRange &R) const {
- assert(NumRanges <
+ assert(NumRanges <
sizeof(DiagObj->DiagRanges)/sizeof(DiagObj->DiagRanges[0]) &&
"Too many arguments to diagnostic!");
if (DiagObj)
DiagObj->DiagRanges[NumRanges++] = &R;
- }
+ }
void AddCodeModificationHint(const CodeModificationHint &Hint) const {
assert(NumCodeModificationHints < Diagnostic::MaxCodeModificationHints &&
@@ -579,6 +615,20 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
Diagnostic::ak_identifierinfo);
return DB;
}
+
+// Adds a DeclContext to the diagnostic. The enable_if template magic is here
+// so that we only match those arguments that are (statically) DeclContexts;
+// other arguments that derive from DeclContext (e.g., RecordDecls) will not
+// match.
+template<typename T>
+inline
+typename llvm::enable_if<llvm::is_same<T, DeclContext>,
+ const DiagnosticBuilder &>::type
+operator<<(const DiagnosticBuilder &DB, T *DC) {
+ DB.AddTaggedVal(reinterpret_cast<intptr_t>(DC),
+ Diagnostic::ak_declcontext);
+ return DB;
+}
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
const SourceRange &R) {
@@ -605,7 +655,7 @@ inline DiagnosticBuilder Diagnostic::Report(FullSourceLoc Loc, unsigned DiagID){
//===----------------------------------------------------------------------===//
// 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.
@@ -613,74 +663,74 @@ 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;
}
@@ -690,7 +740,7 @@ public:
}
const CodeModificationHint *getCodeModificationHints() const {
- return DiagObj->NumCodeModificationHints?
+ return DiagObj->NumCodeModificationHints?
&DiagObj->CodeModificationHints[0] : 0;
}
@@ -699,20 +749,20 @@ public:
/// 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
diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td
index e059d5e..cbf9cdb 100644
--- a/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/include/clang/Basic/DiagnosticCommonKinds.td
@@ -41,7 +41,8 @@ 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">;
+ "'long long' is an extension when C99 mode is not enabled">,
+ InGroup<LongLong>;
def warn_integer_too_large : Warning<
"integer constant is too large for its type">;
def warn_integer_too_large_for_signed : Warning<
diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td
index a8dbd68..dfdf0ff 100644
--- a/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/include/clang/Basic/DiagnosticDriverKinds.td
@@ -14,6 +14,8 @@ 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_arch_name : Error<
+ "invalid arch name '%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<
@@ -43,15 +45,21 @@ 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_no_ast_support : Error<
+ "'%0': unable to use AST files with this tool">;
def err_drv_clang_unsupported : Error<
"the clang compiler does not support '%0'">;
def err_drv_command_failed : Error<
"%0 command failed with exit code %1 (use -v to see invocation)">;
def err_drv_command_signalled : Error<
"%0 command failed due to signal %1 (use -v to see invocation)">;
+def err_drv_invalid_mfloat_abi : Error<
+ "invalid float ABI '%0'">;
def warn_drv_input_file_unused : Warning<
"%0: '%1' input unused when '%2' is present">;
+def warn_drv_preprocessed_input_file_unused : Warning<
+ "%0: previously preprocessed input unused when '%1' is present">;
def warn_drv_unused_argument : Warning<
"argument unused during compilation: '%0'">;
def warn_drv_pipe_ignored_with_save_temps : Warning<
@@ -64,5 +72,7 @@ def warn_drv_not_using_clang_arch : Warning<
"not using the clang compiler for the '%0' architecture">;
def warn_drv_clang_unsupported : Warning<
"the clang compiler does not support '%0'">;
+def warn_drv_assuming_mfloat_abi_is : Warning<
+ "unknown platform, assuming -mfloat-abi=%0">;
}
diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td
index 815ae8d..e5c7327 100644
--- a/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -11,8 +11,14 @@ let Component = "Frontend" in {
def err_fe_unknown_triple : Error<
"unknown target triple '%0', please use -triple or -arch">;
+def err_fe_unknown_target_abi : Error<"unknown target ABI '%0'">;
def err_fe_error_reading : Error<"error reading '%0'">;
def err_fe_error_reading_stdin : Error<"error reading stdin">;
+def err_fe_error_backend : Error<"error in backend: %0">, DefaultFatal;
+def err_fe_invalid_ast_file : Error<"invalid AST file: '%0'">, DefaultFatal;
+def err_fe_invalid_ast_action : Error<"invalid action for AST input">, DefaultFatal;
+def err_fe_invalid_code_complete_file
+ : Error<"cannot locate code-completion file %0">, DefaultFatal;
def note_fixit_applied : Note<"FIX-IT applied suggested code changes">;
def note_fixit_in_macro : Note<
@@ -24,6 +30,9 @@ def warn_fixit_no_changes : Note<
"FIX-IT detected errors it could not fix; no output will be generated">;
// PCH reader
+def err_relocatable_without_without_isysroot : Error<
+ "must specify system root with -isysroot when building a relocatable "
+ "PCH file">;
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'">;
@@ -66,6 +75,9 @@ def warn_pch_altivec : Error<
def warn_pch_opencl : Error<
"OpenCL language extensions were %select{disabled|enabled}0 in PCH file "
"but are currently %select{disabled|enabled}1">;
+def warn_pch_elide_constructors : Error<
+ "Elidable copy constructors were %select{disabled|enabled}0 in PCH file "
+ "but are currently %select{disabled|enabled}1">;
def warn_pch_exceptions : Error<
"exceptions were %select{disabled|enabled}0 in PCH file but "
"are currently %select{disabled|enabled}1">;
@@ -80,8 +92,14 @@ 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"
+ "PCH file was compiled %select{without|with}0 thread-safe statics but "
"thread-safe statics are currently %select{disabled|enabled}1">;
+def warn_pch_posix_threads : Error<
+ "PCH file was compiled %select{without|with}0 POSIX thread support but "
+ "POSIX threads are currently %select{disabled|enabled}1">;
+def warn_pch_stack_protector : Error<
+ "stack protector was %select{off|on|required}0 in PCH file but "
+ "is currently %select{off|on|required}1">;
def warn_pch_blocks : Error<
"blocks were %select{disabled|enabled}0 in PCH file but "
"are currently %select{disabled|enabled}1">;
@@ -118,6 +136,8 @@ 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_pch_different_branch : Error<
+ "PCH file built from a different branch (%0) than the compiler (%1)">;
def warn_cmdline_conflicting_macro_def : Error<
"definition of the macro '%0' conflicts with the definition used to "
"build the precompiled header">;
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index 2896f79..c34bdc1 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -19,12 +19,13 @@ def Implicit : DiagGroup<"implicit", [
// Empty DiagGroups: these are recognized by clang but ignored.
+def : DiagGroup<"address">;
def : DiagGroup<"aggregate-return">;
+def : DiagGroup<"attributes">;
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">;
@@ -38,6 +39,7 @@ def FormatExtraArgs : DiagGroup<"format-extra-args">;
def FormatZeroLength : DiagGroup<"format-zero-length">;
def FourByteMultiChar : DiagGroup<"four-char-constants">;
+def : DiagGroup<"import">;
def : DiagGroup<"init-self">;
def : DiagGroup<"inline">;
def : DiagGroup<"int-to-pointer-cast">;
@@ -49,15 +51,17 @@ def : DiagGroup<"missing-noreturn">;
def MultiChar : DiagGroup<"multichar">;
def : DiagGroup<"nested-externs">;
def : DiagGroup<"newline-eof">;
-def : DiagGroup<"long-long">;
+def LongLong : 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<"overflow">;
+def : DiagGroup<"overloaded-virtual">;
def : DiagGroup<"packed">;
def Parentheses : DiagGroup<"parentheses">;
-def : DiagGroup<"pointer-arith">;
+def PointerArith : DiagGroup<"pointer-arith">;
def : DiagGroup<"pointer-to-int-cast">;
def : DiagGroup<"redundant-decls">;
def ReturnType : DiagGroup<"return-type">;
@@ -66,6 +70,9 @@ def : DiagGroup<"shadow">;
def : DiagGroup<"shorten-64-to-32">;
def : DiagGroup<"sign-compare">;
+// Preprocessor warnings.
+def : DiagGroup<"builtin-macro-redefined">;
+
// Just silence warnings about common forms of -Wstrict-aliasing for now.
def : DiagGroup<"strict-aliasing=0">;
def : DiagGroup<"strict-aliasing=1">;
@@ -94,11 +101,14 @@ def UnusedParameter : DiagGroup<"unused-parameter">;
def UnusedValue : DiagGroup<"unused-value">;
def UnusedVariable : DiagGroup<"unused-variable">;
def ReadOnlySetterAttrs : DiagGroup<"readonly-setter-attrs">;
+def Reorder : DiagGroup<"reorder">;
def UndeclaredSelector : DiagGroup<"undeclared-selector">;
+def SuperSubClassMismatch : DiagGroup<"super-class-method-mismatch">;
def : DiagGroup<"variadic-macros">;
def VectorConversions : DiagGroup<"vector-conversions">; // clang specific
def VolatileRegisterVar : DiagGroup<"volatile-register-var">;
def : DiagGroup<"write-strings">;
+def CharSubscript : DiagGroup<"char-subscripts">;
// Aggregation warning settings.
@@ -126,6 +136,7 @@ def Most : DiagGroup<"most", [
Implicit,
MismatchedTags,
MultiChar,
+ ReturnType,
Switch,
Trigraphs,
Uninitialized,
@@ -134,8 +145,8 @@ def Most : DiagGroup<"most", [
UnusedVariable,
VectorConversions,
VolatileRegisterVar,
- ReadOnlySetterAttrs,
- UndeclaredSelector
+ Reorder,
+ CharSubscript
]>;
// -Wall is -Wmost -Wparentheses
diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td
index 6ca50db..3f132c0 100644
--- a/include/clang/Basic/DiagnosticLexKinds.td
+++ b/include/clang/Basic/DiagnosticLexKinds.td
@@ -112,7 +112,8 @@ 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_redef_builtin_macro : Warning<"redefining builtin macro">,
+ InGroup<DiagGroup<"builtin-macro-redefined">>;
def pp_macro_not_used : Warning<"macro is not used">, DefaultIgnore,
InGroup<DiagGroup<"unused-macros">>;
def warn_pp_undef_identifier : Warning<
@@ -226,10 +227,17 @@ def ext_stdc_pragma_syntax_eom :
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 :
+def warn_pragma_diagnostic_gcc_invalid :
ExtWarn<"pragma diagnostic expected 'error', 'warning', 'ignored', or"
" 'fatal'">,
InGroup<UnknownPragmas>;
+def warn_pragma_diagnostic_clang_invalid :
+ ExtWarn<"pragma diagnostic expected 'error', 'warning', 'ignored', 'fatal'"
+ " 'push', or 'pop'">,
+ InGroup<UnknownPragmas>;
+def warn_pragma_diagnostic_clang_cannot_ppp :
+ ExtWarn<"pragma diagnostic pop could not pop, no matching push">,
+ InGroup<UnknownPragmas>;
def warn_pragma_diagnostic_invalid_option :
ExtWarn<"pragma diagnostic expected option name (e.g. \"-Wundef\")">,
InGroup<UnknownPragmas>;
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index d65a97e..6971df5 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -35,6 +35,7 @@ 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 err_friend_storage_spec : Error<"'%0' is invalid in friend declarations">;
def ext_ident_list_in_param : Extension<
"type-less parameter names in function declaration">;
@@ -77,7 +78,7 @@ 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<
+def err_expected_semi_declaration : Error<
"expected ';' at end of declaration">;
def err_expected_semi_decl_list : Error<
"expected ';' at end of declaration list">;
@@ -135,9 +136,13 @@ def err_rvalue_reference : Error<
def err_argument_required_after_attribute : Error<
"argument required after attribute">;
def err_missing_param : Error<"expected parameter declarator">;
+def err_missing_comma_before_ellipsis : Error<
+ "C requires a comma prior to the ellipsis in a variadic function type">;
def err_unexpected_typedef_ident : Error<
"unexpected type name %0: expected identifier">;
def err_expected_class_name : Error<"expected class name">;
+def err_destructor_class_name : Error<
+ "expected the class name after '~' to name a destructor">;
def err_unspecified_vla_size_with_static : Error<
"'static' may not be used with an unspecified variable length array size">;
@@ -150,14 +155,16 @@ 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_friend_invalid_in_context : Error<
+ "'friend' used outside of class">;
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">;
def err_expected_ident_in_using : Error<
"expected an identifier in using directive">;
-def err_unexpected_template_spec_in_using : Error<
- "use of template specialization in using directive not allowed">;
+def err_using_decl_can_not_refer_to_template_spec : Error<
+ "using declaration can not refer to template specialization">;
/// Objective-C parser diagnostics
@@ -272,6 +279,10 @@ def err_expected_type_name_after_typename : Error<
def err_variadic_templates : Error<
"variadic templates are only allowed in C++0x">;
+
+// C++ declarations
+def err_friend_decl_defines_class : Error<
+ "cannot define a type in a friend declaration">;
// Language specific pragmas
// - Generic warnings
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index b1a73d0..b03676d 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -67,6 +67,9 @@ def ext_flexible_array_init : Extension<
// Declarations.
def ext_vla : Extension<
"variable length arrays are a C99 feature, accepted as an extension">;
+def err_vla_cxx : Error<
+ "variable length arrays are not permitted in C++">;
+
def ext_anon_param_requires_type_specifier : Extension<
"type specifier required for unnamed parameter, defaults to int">;
def err_bad_variable_name : Error<
@@ -74,9 +77,11 @@ def err_bad_variable_name : Error<
def err_parameter_name_omitted : Error<"parameter name omitted">;
def warn_unused_parameter : Warning<"unused parameter %0">,
InGroup<UnusedParameter>, DefaultIgnore;
+def warn_unused_variable : Warning<"unused variable %0">,
+ InGroup<UnusedVariable>, DefaultIgnore;
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;
@@ -92,10 +97,18 @@ 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">;
+
+// C++ using declarations
def err_using_requires_qualname : Error<
"using declaration requires a qualified name">;
def err_using_typename_non_type : Error<
"'typename' keyword used on a non-type">;
+def err_using_decl_nested_name_specifier_is_not_a_base_class : Error<
+ "using declaration refers into '%0', which is not a base class of %1">;
+def err_using_decl_can_not_refer_to_class_member : Error<
+ "using declaration can not refer to class member">;
+ def err_using_decl_can_not_refer_to_namespace : Error<
+ "using declaration can not refer to namespace">;
def err_invalid_thread : Error<
"'__thread' is only allowed on variable declarations">;
@@ -104,6 +117,23 @@ def err_thread_non_global : Error<
def err_thread_unsupported : Error<
"thread-local storage is unsupported for the current target">;
+def warn_maybe_falloff_nonvoid_function : Warning<
+ "control may reach end of non-void function">,
+ InGroup<ReturnType>;
+def warn_falloff_nonvoid_function : Warning<
+ "control reaches end of non-void function">,
+ InGroup<ReturnType>;
+def err_maybe_falloff_nonvoid_block : Error<
+ "control may reach end of non-void block">;
+def err_falloff_nonvoid_block : Error<
+ "control reaches end of non-void block">;
+def warn_suggest_noreturn_function : Warning<
+ "function could be attribute 'noreturn'">,
+ InGroup<DiagGroup<"missing-noreturn">>, DefaultIgnore;
+def warn_suggest_noreturn_block : Warning<
+ "block could be attribute 'noreturn'">,
+ InGroup<DiagGroup<"missing-noreturn">>, DefaultIgnore;
+
/// Built-in functions.
def ext_implicit_lib_function_decl : ExtWarn<
"implicitly declaring C library function '%0' with type %1">;
@@ -113,11 +143,27 @@ def note_please_include_header : Note<
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 err_implicit_decl_requires_setjmp : Error<
+ "implicit declaration of '%0' requires inclusion of the header <setjmp.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++">;
+def warn_builtin_unknown : Warning<"use of unknown builtin %0">, DefaultError;
+
+/// main()
+// static/inline main() are not errors in C, just in C++.
+def warn_unusual_main_decl : Warning<"'main' should not be declared "
+ "%select{static|inline|static or inline}0">;
+def err_unusual_main_decl : Error<"'main' is not allowed to be declared "
+ "%select{static|inline|static or inline}0">;
+def err_main_returns_nonint : Error<"'main' must return 'int'">;
+def err_main_surplus_args : Error<"%0 is too many arguments for 'main': "
+ "must be 0, 2, or 3">;
+def warn_main_one_arg : Warning<"one-argument 'main' is usually a mistake">;
+def err_main_arg_wrong : Error<"%select{first|second|third}0 argument of "
+ "'main' should be of type %1">;
/// parser diagnostics
def ext_typedef_without_a_name : ExtWarn<"typedef requires a name">;
@@ -135,6 +181,8 @@ 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_undeclared_var : Warning<
+ "undeclared variable %0 used as an argument for '#pragma unused'">;
def warn_pragma_unused_expected_localvar : Warning<
"only local variables can be arguments to '#pragma unused'">;
def err_unsupported_pragma_weak : Error<
@@ -145,6 +193,8 @@ 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 err_recursive_superclass : Error<
+ "trying to recursively use %0 as 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">;
@@ -166,10 +216,12 @@ 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_dup_implementation_category : Error<
+ "reimplementation of category %1 for 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">;
+ "instance variable %0 has conflicting bit-field width">;
def err_conflicting_ivar_name : Error<
"conflicting instance variable names: %0 vs %1">;
def err_inconsistant_ivar_count : Error<
@@ -183,6 +235,10 @@ def warn_conflicting_ret_types : Warning<
def warn_conflicting_param_types : Warning<
"conflicting parameter types in implementation of %0: %1 vs %2">;
+def warn_implements_nscopying : Warning<
+"default assign attribute on property %0 which implements "
+"NSCopying protocol is not appropriate with -fobjc-gc[-only]">;
+
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">;
@@ -255,11 +311,26 @@ 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_unexpected_friend : Error<
+ "friends can only be classes or functions">;
+def err_enum_friend : Error<
+ "enum types cannot be friends">;
+def err_friend_is_member : Error<
+ "friends cannot be members of the declaring class">;
+def ext_friend_inner_class : Extension<
+ "C++ 98 does not allow inner classes as friends">;
+def err_unelaborated_friend_type : Error<
+ "must specify '%select{struct|union|class|enum}0' to befriend %1">;
+def err_qualified_friend_not_found : Error<
+ "no function named %0 with type %1 was found in the specified scope">;
+def err_introducing_special_friend : Error<
+ "must use a qualified name when declaring a %select{constructor|"
+ "destructor|conversion operator}0 as a friend">;
+def err_tagless_friend_type_template : Error<
+ "friend type templates must use an elaborated type">;
def err_abstract_type_in_decl : Error<
- "%select{return|parameter|variable|field}1 type %0 is an abstract class">;
+ "%select{return|parameter|variable|field}0 type %1 is an abstract class">;
def err_allocation_of_abstract_type : Error<
"allocation of an object of abstract type %0">;
@@ -285,10 +356,17 @@ 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 "
+ "%select{|pointer to |reference to }0incomplete type %1 is not allowed "
"in exception specification">;
def err_mismatched_exception_spec : Error<
"exception specification in declaration does not match previous declaration">;
+def err_override_exception_spec : Error<
+ "exception specification of overriding function is more lax than "
+ "base version">;
+def err_incompatible_exception_specs : Error<
+ "target exception specification is not superset of source">;
+def err_deep_exception_specs_differ : Error<
+ "exception specifications of %select{return|argument}0 types differ">;
// C++ access checking
def err_class_redeclared_with_different_access : Error<
@@ -299,6 +377,12 @@ def note_previous_access_declaration : Note<
// C++ name lookup
def err_incomplete_nested_name_spec : Error<
"incomplete type %0 named in nested name specifier">;
+def err_nested_name_member_ref_lookup_ambiguous : Error<
+ "lookup of %0 in member access expression is ambiguous">;
+def note_ambig_member_ref_object_type : Note<
+ "lookup in the object type %0 refers here">;
+def note_ambig_member_ref_scope : Note<
+ "lookup from the current scope refers here">;
// C++ class members
def err_storageclass_invalid_for_member : Error<
@@ -332,6 +416,21 @@ def err_implicit_object_parameter_init : Error<
"cannot initialize object parameter of type %0 with an expression "
"of type %1">;
+def err_missing_default_constructor : Error<
+ "default constructor for %1 is missing in initialization of "
+ "%select{base class|member}0">;
+def err_illegal_union_member : Error<
+ "union member %0 has a non-trivial %select{constructor|"
+ "copy constructor|copy assignment operator|destructor}1">;
+def note_nontrivial_has_virtual : Note<
+ "because type %0 has a virtual %select{member function|base class}1">;
+def note_nontrivial_has_nontrivial : Note<
+ "because type %0 has a %select{member|base class}1 with a non-trivial "
+ "%select{constructor|copy constructor|copy assignment operator|destructor}2">;
+def note_nontrivial_user_defined : Note<
+ "because type %0 has a user-declared %select{constructor|copy constructor|"
+ "copy assignment operator|destructor}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)">;
@@ -378,9 +477,15 @@ 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">;
+def err_destructor_name : Error<
+ "expected the class name after '~' to name the enclosing class">;
// C++ initialization
def err_lvalue_to_rvalue_ref : Error<"rvalue reference cannot bind to lvalue">;
+def err_invalid_initialization : Error<
+"invalid initialization of reference of type %0 from expression of type %1">;
+def err_lvalue_to_rvalue_ambig_ref : Error<"rvalue reference cannot bind to lvalue "
+ "due to multiple conversion functions">;
// 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 "
@@ -412,6 +517,8 @@ def err_illegal_decl_array_of_auto : Error<
def err_auto_not_allowed : Error<
"'auto' not allowed in %select{function prototype|struct member|union member"
"|class member|exception declaration|template parameter|block literal}0">;
+def err_auto_var_requires_init : Error<
+ "declaration of variable %0 with type %1 requires an initializer">;
// Objective-C++
def err_objc_decls_may_only_appear_in_global_scope : Error<
@@ -464,23 +571,37 @@ 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_space_negative : Error<
+ "address space is negative">;
+def err_attribute_address_space_too_high : Error<
+ "address space is larger than the maximum supported (%0)">;
def err_attribute_address_multiple_qualifiers : Error<
"multiple address spaces specified for type">;
def err_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_arg_with_address_space : Error<
+ "parameter may not be qualified with an address space">;
+def err_attribute_not_string : Error<
+ "argument to %0 attribute was not a string literal">;
+def err_attribute_section_invalid_for_target : Error<
+ "argument to 'section' attribute is not valid for this target: %0">;
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_precede_definition : Warning<
+ "attribute declaration must precede definition">;
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_weak_identifier_undeclared : Warning<
+ "weak identifier %0 never declared">;
+def err_attribute_weak_static : Error<
+ "weak declaration of '%0' must be public">;
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<
@@ -521,6 +642,8 @@ 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_attribute_malloc_pointer_only : Warning<
+ "'malloc' attribute only applies to functions returning a pointer type">;
def warn_transparent_union_nonpointer : Warning<
"'transparent_union' attribute support incomplete; only supported for "
"pointer unions">;
@@ -594,8 +717,16 @@ def err_param_default_argument_references_this : Error<
def err_param_default_argument_nonfunc : Error<
"default arguments can only be specified for parameters in a function "
"declaration">;
+def err_param_default_argument_template_redecl : Error<
+ "default arguments cannot be added to a function template that has already "
+ "been declared">;
+def err_param_default_argument_member_template_redecl : Error<
+ "default arguments cannot be added to an out-of-line definition of a member "
+ "of a %select{class template|class template partial specialization|nested "
+ "class in a template}0">;
+def note_field_decl : Note<"member is declared here">;
def err_defining_default_ctor : Error<
- "cannot define the implicit default constructor for %0, because %select{base class|member}1 "
+ "cannot define the implicit default constructor for %0, because %select{base class|member's type}1 "
"%2 does not have any default constructor">;
def note_previous_class_decl : Note<
"%0 declared here">;
@@ -608,6 +739,12 @@ def note_first_required_here : Note<
def err_unintialized_member : Error<
"cannot define the implicit default constructor for %0, because "
"%select{reference|const}1 member %2 cannot be default-initialized">;
+def err_null_intialized_reference_member : Error<
+ "cannot initialize the member to null in default constructor because "
+ "reference member %0 cannot be null-initialized">;
+def err_unintialized_member_in_ctor : Error<
+ "constructor for %0 must explicitly initialize the "
+ "%select{reference|const}1 member %2 ">;
def err_use_of_default_argument_to_function_declared_later : Error<
"use of default argument to function %0 that is declared later in class %1">;
@@ -639,12 +776,23 @@ def err_ovl_ambiguous_member_call : Error<
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_not_viable : Note<"function not viable because"
+ " of ambiguity in conversion of argument %0">;
+def note_ambiguous_type_conversion: Note<
+ "because of ambiguity in conversion of %0 to %1">;
+def err_ovl_template_candidate : Note<
+ "candidate function template specialization %0">;
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_builtin_binary_candidate : Note<
+ "built-in candidate operator %0 (%1, %2)">;
+def err_ovl_builtin_unary_candidate : Note<
+ "built-in candidate operator %0 (%1)">;
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_ref_init_ambiguous : Error<
+ "reference initialization of type %0 with initializer of type %1 is ambiguous">;
def err_ovl_deleted_init : Error<
"call to %select{unavailable|deleted}0 constructor of %1">;
def err_ovl_ambiguous_oper : Error<
@@ -663,6 +811,10 @@ 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++ Address of Overloaded Function
+def err_addr_ovl_ambiguous : Error<
+ "address of overloaded function %0 is ambiguous">;
+
// C++ Template Declarations
def err_template_param_shadow : Error<
"declaration of %0 shadows template parameter">;
@@ -704,6 +856,12 @@ 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">;
+
+def err_template_variable : Error<"variable %0 declared as a template">;
+def err_template_variable_noparams : Error<
+ "extraneous 'template<>' in declaration of variable %0">;
+def err_template_tag_noparams : Error<
+ "extraneous 'template<>' in declaration of %0 %1">;
// C++ Template Argument Lists
def err_template_arg_list_different_arity : Error<
@@ -776,25 +934,64 @@ def err_template_arg_not_pointer_to_member_form : Error<
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">;
+// C++ template specialization
+def err_template_spec_unknown_kind : Error<
+ "can only provide an explicit %select{<error>|<error>|specialization|"
+ "instantiation|instantiation}0 for a class template, function template, or "
+ "a member function, static data member, or member class of a class template">;
+def note_specialized_entity : Note<
+ "explicitly %select{<error>|<error>|specialized|instantiated|instantiated}0 "
+ "declaration is here">;
+def err_template_spec_decl_function_scope : Error<
+ "explicit %select{<error>|<error>|specialization|instantiation|"
+ "instantiation}0 of %1 in function scope">;
+def err_template_spec_decl_class_scope : Error<
+ "explicit %select{<error>|<error>|specialization|instantiation|"
+ "instantiation}0 of %1 in class scope">;
def err_template_spec_decl_out_of_scope_global : Error<
- "class template %select{|partial }0specialization of %1 must occur in the "
- "global scope">;
+ "%select{class template|class template partial|function template|member "
+ "function|static data member|member class}0 specialization of %1 must "
+ "originally be declared in the global scope">;
def err_template_spec_decl_out_of_scope : Error<
- "class template %select{|partial }0specialization of %1 not in namespace %2">;
-def err_template_spec_decl_function_scope : Error<
- "%select{class template specialization|class template partial specialization|"
- "explicit instantiation}0 of %1 in function scope">;
+ "%select{class template|class template partial|function template|member "
+ "function|static data member|member class}0 specialization of %1 must "
+ "originally be declared in namespace %2">;
def err_template_spec_redecl_out_of_scope : Error<
- "%select{class template specialization|class template partial specialization|"
- "explicit instantiation}0 of %1 not in a namespace enclosing %2">;
+ "%select{class template|class template partial|function template|member "
+ "function|static data member|member class}0 specialization of %1 not in a "
+ "namespace enclosing %2">;
def err_template_spec_redecl_global_scope : Error<
- "%select{class template specialization|class template partial specialization|"
- "explicit instantiation}0 of %1 must occur at global scope">;
+ "%select{class template|class template partial|function template|member "
+ "function|static data member|member class}0 specialization of %1 must occur "
+ "at global scope">;
+def err_spec_member_not_instantiated : Error<
+ "specialization of member %q0 does not specialize an instantiated member">;
+def note_specialized_decl : Note<"attempt to specialize declaration here">;
+def err_specialization_after_instantiation : Error<
+ "explicit specialization of %0 after instantiation">;
+def note_instantiation_required_here : Note<
+ "%select{implicit|explicit}0 instantiation first required here">;
+def err_template_spec_friend : Error<
+ "template specialization declaration cannot be a friend">;
+def err_template_spec_default_arg : Error<
+ "default argument not permitted on an explicit "
+ "%select{instantiation|specialization}0 of function %1">;
+
+// C++ class template specializations and out-of-line definitions
+def err_template_spec_needs_header : Error<
+ "template specialization requires 'template<>'">;
+def err_template_spec_needs_template_parameters : Error<
+ "template specialization or definition requires a template parameter list"
+ "corresponding to the nested type %0">;
+def err_template_param_list_matches_nontemplate : Error<
+ "template parameter list matching the non-templated nested type %0 should "
+ "be empty ('template<>')">;
+def err_template_spec_extra_headers : Error<
+ "extraneous template parameter list in template specialization or "
+ "out-of-line template definition">;
+def err_template_qualified_declarator_no_match : Error<
+ "nested name specifier '%0' for declaration does not refer into a class, "
+ "class template or class template partial specialization">;
// C++ Class Template Partial Specialization
def err_default_arg_in_partial_spec : Error<
@@ -815,9 +1012,19 @@ def warn_partial_specs_not_deducible : Warning<
"deduced; this partial specialization will never be used">;
def note_partial_spec_unused_parameter : Note<
"non-deducible template parameter %0">;
-def unsup_template_partial_spec_ordering : Error<
- "partial ordering of class template partial specializations is not yet "
- "supported">;
+def err_partial_spec_ordering_ambiguous : Error<
+ "ambiguous partial specializations of %0">;
+def note_partial_spec_match : Note<"partial specialization matches %0">;
+
+// C++ Function template specializations
+def err_function_template_spec_no_match : Error<
+ "no function template matches function template specialization %0">;
+def err_function_template_spec_ambiguous : Error<
+ "function template specialization %0 ambiguously refers to more than one "
+ "function template; explicitly specify%select{|additional }1 template "
+ "arguments to identify a particular function template">;
+def note_function_template_spec_matched : Note<
+ "function template matches specialization %0">;
// C++ Template Instantiation
def err_template_recursion_depth_exceeded : Error<
@@ -838,9 +1045,14 @@ def note_template_member_function_here : Note<
"in instantiation of member function %q0 requested here">;
def note_function_template_spec_here : Note<
"in instantiation of function template specialization %q0 requested here">;
+def note_template_static_data_member_def_here : Note<
+ "in instantiation of static data member %q0 requested here">;
def note_default_arg_instantiation_here : Note<
"in instantiation of default argument for '%0' required here">;
+def note_default_function_arg_instantiation_here : Note<
+ "in instantiation of default function argument expression "
+ "for '%0' required here">;
def note_explicit_template_arg_substitution_here : Note<
"while substituting explicitly-specified template arguments into function "
"template %f, here">;
@@ -873,15 +1085,34 @@ 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">;
-
+def err_explicit_instantiation_requires_name : Error<
+ "explicit instantiation declaration requires a name">;
+def err_explicit_instantiation_of_typedef : Error<
+ "explicit instantiation of typedef %0">;
+def err_explicit_instantiation_not_known : Error<
+ "explicit instantiation of %0 does not refer to a function template, member "
+ "function, member class, or static data member">;
+def note_explicit_instantiation_here : Note<
+ "explicit instantiation refers here">;
+def err_explicit_instantiation_data_member_not_instantiated : Error<
+ "explicit instantiation refers to static data member %q0 that is not an "
+ "instantiation">;
+def err_explicit_instantiation_member_function_not_instantiated : Error<
+ "explicit instantiation refers to member function %q0 that is not an "
+ "instantiation">;
+def err_explicit_instantiation_ambiguous : Error<
+ "partial ordering for explicit instantiation of %0 is ambiguous">;
+def note_explicit_instantiation_candidate : Note<
+ "explicit instantiation candidate function template here %0">;
+
// 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">;
+ "typename specifier refers to non-type member %0 in %1">;
def note_typename_refers_here : Note<
"referenced member %0 is declared here">;
+def err_typename_missing : Error<
+ "missing 'typename' prior to dependent type name '%0%1'">;
def err_template_kw_refers_to_non_template : Error<
"%0 following the 'template' keyword does not refer to a template">;
@@ -1018,11 +1249,11 @@ 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_has_zero_width : Error<"named 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)">;
+ "size of anonymous bit-field 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'">;
@@ -1053,6 +1284,8 @@ 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 note_protected_by___block : Note<
+ "jump bypasses setup of __block variable">;
def err_func_returning_array_function : Error<
"function cannot return array or function type %0">;
@@ -1105,16 +1338,16 @@ def err_func_def_incomplete_result : Error<
// Expressions.
def ext_sizeof_function_type : Extension<
- "invalid application of 'sizeof' to a function type">;
+ "invalid application of 'sizeof' to a function type">, InGroup<PointerArith>;
def ext_sizeof_void_type : Extension<
- "invalid application of '%0' to a void type">;
+ "invalid application of '%0' to a void type">, InGroup<PointerArith>;
// 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">;
+ "invalid application of '%select{sizeof|__alignof}0' to bit-field">;
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">;
@@ -1127,6 +1360,11 @@ def warn_floatingpoint_eq : Warning<
"comparing floating point with == or != is unsafe">,
InGroup<DiagGroup<"float-equal">>, DefaultIgnore;
+def warn_shift_negative : Warning<
+ "shift count is negative">;
+def warn_shift_gt_typewidth : Warning<
+ "shift count >= width of type">;
+
def err_sizeof_nonfragile_interface : Error<
"invalid application of '%select{alignof|sizeof}1' to interface %0 in "
"non-fragile ABI">;
@@ -1163,12 +1401,15 @@ 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 warn_subscript_is_char : Warning<"array subscript is of type 'char'">,
+ InGroup<CharSubscript>, DefaultIgnore;
def err_typecheck_incomplete_tag : Error<"incomplete definition of type %0">;
-def err_typecheck_no_member : Error<"no member named %0">;
+def err_no_member : Error<"no member named %0 in %1">;
+
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">;
+ "out-of-line definition of %0 does not match any declaration in %1">;
def err_nonstatic_member_out_of_line : Error<
"non-static data member defined out-of-line">;
def err_qualified_typedef_declarator : Error<
@@ -1191,6 +1432,8 @@ 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 ext_typecheck_decl_incomplete_type : ExtWarn<
+ "tentative definition of variable with internal linkage has incomplete non-array 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<
@@ -1215,6 +1458,10 @@ 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_indirection_requires_nonfragile_object : Error<
+ "indirection cannot be to an interface in non-fragile ABI (%0 invalid)">;
+def err_direct_interface_unsupported : Error<
+ "indirection to an interface is not supported (%0 invalid)">;
def err_typecheck_invalid_operands : Error<
"invalid operands to binary expression (%0 and %1)">;
def err_typecheck_sub_ptr_object : Error<
@@ -1223,8 +1470,12 @@ def err_typecheck_sub_ptr_compatible : Error<
"%0 and %1 are not pointers to compatible types">;
def ext_typecheck_ordered_comparison_of_pointer_integer : ExtWarn<
"ordered comparison between pointer and integer (%0 and %1)">;
+def ext_typecheck_ordered_comparison_of_pointer_and_zero : Extension<
+ "ordered comparison between pointer and zero (%0 and %1) is an extension">;
def ext_typecheck_ordered_comparison_of_function_pointers : ExtWarn<
"ordered comparison of function pointers (%0 and %1)">;
+def ext_typecheck_comparison_of_fptr_to_void : Extension<
+ "equality comparison between function pointer and void pointer (%0 and %1)">;
def ext_typecheck_comparison_of_pointer_integer : ExtWarn<
"comparison between pointer and integer (%0 and %1)">;
def ext_typecheck_comparison_of_distinct_pointers : ExtWarn<
@@ -1271,9 +1522,10 @@ def err_unexpected_interface : Error<
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">;
+ "use of GNU void* extension">, InGroup<PointerArith>;
def ext_gnu_ptr_func_arith : Extension<
- "arithmetic on pointer to function type %0 is a GNU extension">;
+ "arithmetic on pointer to function type %0 is a GNU extension">,
+ InGroup<PointerArith>;
def error_readonly_property_assignment : Error<
"assigning to property with 'readonly' attribute not allowed">;
def ext_integer_increment_complex : Extension<
@@ -1326,36 +1578,56 @@ def note_property_impl_required : Note<
// 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">;
+// These messages adhere to the TryCast pattern: %0 is an int specifying the
+// cast type, %1 is the source type, %2 is the destination type.
+def err_bad_cxx_cast_generic : Error<
+ "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
+ "functional-style cast}0 from %1 to %2 is not allowed">;
+def err_bad_cxx_cast_rvalue : Error<
+ "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
+ "functional-style cast}0 from rvalue to reference type %2">;
def err_bad_cxx_cast_const_away : Error<
- "%0 from %2 to %1 casts away constness">;
+ "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
+ "functional-style cast}0 from %1 to %2 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">;
-
+ "%select{const_cast||||C-style cast|functional-style cast}0 to %2, "
+ "which is not a reference, pointer-to-object, or pointer-to-data-member">;
+def ext_cast_fn_obj : Extension<
+ "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">;
+ "cast from pointer to smaller type %2 loses information">;
+def err_bad_cxx_cast_vector_to_scalar_different_size : Error<
+ "%select{||reinterpret_cast||C-style cast|}0 from vector %1 "
+ "to scalar %2 of different size">;
+def err_bad_cxx_cast_scalar_to_vector_different_size : Error<
+ "%select{||reinterpret_cast||C-style cast|}0 from scalar %1 "
+ "to vector %2 of different size">;
+def err_bad_cxx_cast_vector_to_vector_different_size : Error<
+ "%select{||reinterpret_cast||C-style cast|}0 from vector %1 "
+ "to vector %2 of different size">;
+def err_bad_lvalue_to_rvalue_cast : Error<
+ "cannot cast from lvalue of type %1 to rvalue reference type %2; types are "
+ "not compatible">;
+def err_bad_static_cast_pointer_nonpointer : Error<
+ "cannot cast from type %1 to pointer type %2">;
+def err_bad_static_cast_member_pointer_nonmp : Error<
+ "cannot cast from type %1 to member pointer type %2">;
+def err_bad_static_cast_incomplete : Error<"%0 is an incomplete type">;
+
+// These messages don't adhere to the pattern.
+// FIXME: Display the path somehow better.
+def err_ambiguous_base_to_derived_cast : Error<
+ "ambiguous 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_downcast_from_inaccessible_base : Error<
+ "cannot cast %1 to %0 due to inaccessible conversion path">;
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<
@@ -1375,6 +1647,8 @@ def err_array_size_not_integral : Error<
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 err_ambiguous_delete_operand : Error<"ambiguous conversion of delete "
+ "expression of type %0 to a pointer">;
def warn_delete_incomplete : Warning<
"deleting pointer to incomplete type %0 may cause undefined behaviour">;
def err_decrement_bool : Error<"cannot decrement expression of type bool">;
@@ -1394,6 +1668,9 @@ def err_bad_memptr_rhs : Error<
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 warn_exception_caught_by_earlier_handler : Warning<
+ "exception of type %0 will be caught by earlier handler">;
+def note_previous_exception_handler : Note<"for type %0">;
def err_conditional_void_nonvoid : Error<
"%select{left|right}1 operand to ? is void, but %select{right|left}1 operand "
@@ -1412,6 +1689,22 @@ def err_throw_incomplete_ptr : Error<
def err_return_in_constructor_handler : Error<
"return in the catch of a function try block of a constructor is illegal">;
+def err_ident_in_pseudo_dtor_not_a_type : Error<
+ "identifier %0 in pseudo-destructor expression does not name a type">;
+def err_operator_arrow_circular : Error<
+ "circular pointer delegation detected">;
+def err_pseudo_dtor_base_not_scalar : Error<
+ "object expression of non-scalar type %0 cannot be used in a "
+ "pseudo-destructor expression">;
+def err_pseudo_dtor_type_mismatch : Error<
+ "the type of object expression (%0) does not match the type being destroyed "
+ "(%1) in pseudo-destructor expression">;
+def err_pseudo_dtor_call_with_args : Error<
+ "call to pseudo-destructor cannot have any arguments">;
+def err_dtor_expr_without_call : Error<
+ "%select{destructor reference|pseudo-destructor expression}0 must be "
+ "called immediately with '()'">;
+
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">;
@@ -1419,6 +1712,8 @@ 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_typecheck_ambiguous_condition : Error<
+ "conversion from %0 to %1 is ambiguous">;
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">;
@@ -1429,6 +1724,13 @@ def err_invalid_declarator_in_function : Error<
def err_not_tag_in_scope : Error<
"%0 does not name a tag member in the specified scope">;
+def err_cannot_form_pointer_to_member_of_reference_type : Error<
+ "cannot form a pointer-to-member to member %0 of reference type %1">;
+
+def warn_condition_is_assignment : Warning<"using the result of an "
+ "assignment as a condition without parentheses">,
+ InGroup<Parentheses>;
+
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">;
@@ -1436,6 +1738,8 @@ def warn_value_always_false : Warning<"%0 is always false in this context">;
// FIXME: %2 is an english string here.
def err_typecheck_convert_incompatible : Error<
"incompatible type %2 %1, expected %0">;
+def err_typecheck_convert_ambiguous : Error<
+ "ambiguity in initializing value of type %0 with initializer of type %1">;
def err_cannot_initialize_decl_noname : Error<
"cannot initialize a value of type %0 with an %select{rvalue|lvalue}1 "
"of type %2">;
@@ -1443,8 +1747,6 @@ 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<
@@ -1486,7 +1788,11 @@ def err_block_decl_ref_not_modifiable_lvalue : Error<
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">;
+ "calling function with incomplete return type %0">;
+def err_call_function_incomplete_return : Error<
+ "calling %0 with incomplete return type %1">;
+def note_function_with_incomplete_return_type_declared_here : Note<
+ "%0 declared here">;
def err_call_incomplete_argument : Error<
"argument type %0 is incomplete">;
def err_typecheck_call_too_few_args : Error<
@@ -1513,12 +1819,13 @@ def err_cannot_pass_objc_interface_to_vararg : Error<
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">;
+ "%select{function|block|method|constructor}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_call_invalid_unary_fp : Error<
+ "floating point classification requires argument of floating point type "
+ "(passed in %0)">;
def err_typecheck_cond_expect_scalar : Error<
"used type %0 where arithmetic or pointer type is required">;
def ext_typecheck_cond_one_void : Extension<
@@ -1548,7 +1855,16 @@ 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>;
+def warn_unused_property_expr : Warning<
+ "property access result unused - getters should not have side effects">,
+ InGroup<UnusedValue>;
+def warn_unused_call : Warning<
+ "ignoring return value of function declared with %0 attribute">,
+ InGroup<UnusedValue>;
+def err_incomplete_type_used_in_type_trait_expr : Error<
+ "incomplete type %0 used in type trait expression">;
+
// 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">;
@@ -1606,6 +1922,17 @@ def error_multiple_base_initialization : Error <
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_mem_initializer_mismatch : Error<
+ "Too many arguments for member initializer %0">;
+
+def warn_field_initialized : Warning<
+ "member '%0' will be initialized after">,
+ InGroup<Reorder>, DefaultIgnore;
+def warn_base_initialized : Warning<
+ "base class %0 will be initialized after">,
+ InGroup<Reorder>, DefaultIgnore;
+def note_fieldorbase_initialized_here : Note<
+ "%select{field|base}0 %1">;
def err_base_init_does_not_name_class : Error<
"constructor initializer %0 does not name a class">;
@@ -1690,6 +2017,10 @@ def err_ambiguous_member_multiple_subobject_types : Error<
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">;
+def err_ambiguous_tag_hiding : Error<"a type named %0 is hidden by a "
+ "declaration in a different namespace">;
+def note_hidden_tag : Note<"type declaration hidden">;
+def note_hiding_object : Note<"declaration hides type">;
// C++ operator overloading
def err_operator_overload_needs_class_or_enum : Error<
@@ -1850,6 +2181,9 @@ def ext_return_has_void_expr : Extension<
def warn_noreturn_function_has_return_expr : Warning<
"function %0 declared 'noreturn' should not return">, DefaultError,
InGroup<DiagGroup<"invalid-noreturn">>;
+def warn_falloff_noreturn_function : Warning<
+ "function declared 'noreturn' should not return">,
+ InGroup<DiagGroup<"invalid-noreturn">>;
def err_noreturn_block_has_return_expr : Error<
"block declared 'noreturn' should not return">;
def err_block_on_nonlocal : Error<
@@ -1867,6 +2201,9 @@ def err_shufflevector_argument_too_large : Error<
"index for __builtin_shufflevector must be less than the total number "
"of vector elements">;
+def err_vector_incorrect_num_initializers : Error<
+ "%select{too many|too few}0 elements in vector initialization (expected %1 elements, have %2)">;
+def err_altivec_empty_initializer : Error<"expected initializer">;
def err_stack_const_level : Error<
"level argument for a stack address builtin must be constant">;
@@ -1918,10 +2255,11 @@ 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_c99_array_usage_cxx : Error<
+ "C99-specific array features are not permitted in C++">;
+
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<
@@ -1933,6 +2271,7 @@ 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">;
-
-
+def ext_typecheck_base_super : Warning<
+ "method parameter type %0 does not match "
+ "super class method parameter type %1">, InGroup<SuperSubClassMismatch>, DefaultIgnore;
}
diff --git a/include/clang/Basic/FileManager.h b/include/clang/Basic/FileManager.h
index d6a0cf3..7c9113c 100644
--- a/include/clang/Basic/FileManager.h
+++ b/include/clang/Basic/FileManager.h
@@ -15,19 +15,17 @@
#define LLVM_CLANG_FILEMANAGER_H
#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.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 {
@@ -35,7 +33,7 @@ class DirectoryEntry {
friend class FileManager;
public:
DirectoryEntry() : Name(0) {}
- const char *getName() const { return Name; }
+ const char *getName() const { return Name; }
};
/// FileEntry - Cached information about one file on the disk.
@@ -55,7 +53,7 @@ public:
: 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; }
@@ -63,11 +61,11 @@ public:
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);
}
@@ -87,19 +85,19 @@ public:
/// execution of the front end.
class MemorizeStatCalls : public StatSysCallCache {
public:
- /// \brief The result of a stat() call.
+ /// \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
+ /// \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(); }
@@ -126,22 +124,22 @@ class FileManager {
///
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();
@@ -152,24 +150,24 @@ public:
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 llvm::StringRef &Filename) {
+ return getDirectory(Filename.begin(), Filename.end());
}
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 llvm::StringRef &Filename) {
+ return getFile(Filename.begin(), Filename.end());
}
const FileEntry *getFile(const char *FilenameStart,
const char *FilenameEnd);
-
+
void PrintStats() const;
};
diff --git a/include/clang/Basic/IdentifierTable.h b/include/clang/Basic/IdentifierTable.h
index 57cd311..84c2fc9 100644
--- a/include/clang/Basic/IdentifierTable.h
+++ b/include/clang/Basic/IdentifierTable.h
@@ -21,8 +21,8 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/Support/PointerLikeTypeTraits.h"
-#include <string>
-#include <cassert>
+#include <string>
+#include <cassert>
namespace llvm {
template <typename T> struct DenseMapInfo;
@@ -38,21 +38,21 @@ namespace clang {
/// 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.
+/// 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.
+ 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;
+ 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.
@@ -61,50 +61,50 @@ class IdentifierInfo {
// 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;
+ 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
+
+ /// getName - Return the actual string for this identifier. The returned
/// string is properly null terminated.
///
- const char *getName() const {
+ 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
+ // 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
+ // 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 {
@@ -112,29 +112,29 @@ public:
}
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)
+ if (ObjCOrBuiltinID < tok::NUM_OBJC_KEYWORDS)
return tok::ObjCKeywordKind(ObjCOrBuiltinID);
else
return tok::objc_not_keyword;
@@ -144,15 +144,15 @@ public:
/// 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 {
+ unsigned getBuiltinID() const {
if (ObjCOrBuiltinID >= tok::NUM_OBJC_KEYWORDS)
- return 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
+ assert(ObjCOrBuiltinID - unsigned(tok::NUM_OBJC_KEYWORDS) == ID
&& "ID too large for field!");
}
@@ -170,7 +170,7 @@ public:
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) {
@@ -180,10 +180,10 @@ public:
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) {
@@ -205,7 +205,7 @@ public:
/// 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
@@ -227,13 +227,13 @@ private:
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
@@ -257,7 +257,7 @@ class IdentifierTable {
// BumpPtrAllocator!
typedef llvm::StringMap<IdentifierInfo*, llvm::BumpPtrAllocator> HashTableTy;
HashTableTy HashTable;
-
+
IdentifierInfoLookup* ExternalLookup;
public:
@@ -265,7 +265,7 @@ public:
/// 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;
@@ -274,16 +274,16 @@ public:
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);
@@ -305,7 +305,7 @@ public:
return *II;
}
-
+
/// \brief Creates a new IdentifierInfo from the given string.
///
/// This is a lower-level version of get() that requires that this
@@ -314,14 +314,14 @@ public:
/// identifier sources can use this routine to build IdentifierInfo
/// nodes and then introduce additional information about those
/// identifiers.
- IdentifierInfo &CreateIdentifierInfo(const char *NameStart,
+ 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();
@@ -334,37 +334,32 @@ public:
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());
+ IdentifierInfo &get(const llvm::StringRef& Name) {
+ return get(Name.begin(), Name.end());
}
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
+/// 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,
@@ -372,7 +367,7 @@ class Selector {
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");
@@ -383,7 +378,7 @@ class Selector {
InfoPtr = reinterpret_cast<uintptr_t>(SI);
assert((InfoPtr & ArgFlags) == 0 &&"Insufficiently aligned IdentifierInfo");
}
-
+
IdentifierInfo *getAsIdentifierInfo() const {
if (getIdentifierInfoFlag())
return reinterpret_cast<IdentifierInfo *>(InfoPtr & ~ArgFlags);
@@ -417,19 +412,19 @@ public:
bool isNull() const { return InfoPtr == 0; }
// Predicates to identify the selector type.
- bool isKeywordSelector() const {
- return getIdentifierInfoFlag() != ZeroArg;
+ bool isKeywordSelector() const {
+ return getIdentifierInfoFlag() != ZeroArg;
}
- bool isUnarySelector() const {
+ 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));
}
@@ -452,7 +447,7 @@ public:
/// 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);
}
@@ -519,15 +514,15 @@ struct DenseMapInfo<clang::Selector> {
return clang::Selector::getEmptyMarker();
}
static inline clang::Selector getTombstoneKey() {
- return clang::Selector::getTombstoneMarker();
+ 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; }
};
@@ -537,7 +532,7 @@ template<>
class PointerLikeTypeTraits<clang::IdentifierInfo*> {
public:
static inline void *getAsVoidPointer(clang::IdentifierInfo* P) {
- return P;
+ return P;
}
static inline clang::IdentifierInfo *getFromVoidPointer(void *P) {
return static_cast<clang::IdentifierInfo*>(P);
@@ -549,7 +544,7 @@ template<>
class PointerLikeTypeTraits<const clang::IdentifierInfo*> {
public:
static inline const void *getAsVoidPointer(const clang::IdentifierInfo* P) {
- return P;
+ return P;
}
static inline const clang::IdentifierInfo *getFromVoidPointer(const void *P) {
return static_cast<const clang::IdentifierInfo*>(P);
diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h
index 26688bf..d4d3fe5 100644
--- a/include/clang/Basic/LangOptions.h
+++ b/include/clang/Basic/LangOptions.h
@@ -34,18 +34,17 @@ public:
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 AltiVec : 1; // Support AltiVec-style vector initializers.
unsigned Exceptions : 1; // Support exception handling.
+ unsigned Rtti : 1; // Support rtti information.
unsigned NeXTRuntime : 1; // Use NeXT runtime.
unsigned Freestanding : 1; // Freestanding implementation
@@ -53,6 +52,8 @@ public:
unsigned ThreadsafeStatics : 1; // Whether static initializers are protected
// by locks.
+ unsigned POSIXThreads : 1; // Compiling with POSIX thread support
+ // (-pthread)
unsigned Blocks : 1; // block extension to C
unsigned EmitAllDecls : 1; // Emit all declarations, even if
// they are unused.
@@ -66,7 +67,7 @@ public:
// may be ripped out at any time.
unsigned Optimize : 1; // Whether __OPTIMIZE__ should be defined.
- unsigned OptimizeSize : 1; // Whether __OPTIMIZE_SIZE__ should be
+ unsigned OptimizeSize : 1; // Whether __OPTIMIZE_SIZE__ should be
// defined.
unsigned Static : 1; // Should __STATIC__ be defined (as
// opposed to __DYNAMIC__).
@@ -79,12 +80,14 @@ public:
unsigned ObjCGCBitmapPrint : 1; // Enable printing of gc's bitmap layout
// for __weak/__strong ivars.
- unsigned AccessControl : 1; // Whether C++ access control should
+ unsigned AccessControl : 1; // Whether C++ access control should
// be enabled.
unsigned CharIsSigned : 1; // Whether char is a signed or unsigned type
unsigned OpenCL : 1; // OpenCL C99 language extensions.
+ unsigned ElideConstructors : 1; // Whether C++ copy constructors should be
+ // elided if possible.
private:
unsigned GC : 2; // Objective-C Garbage Collection modes. We
// declare this enum as unsigned because MSVC
@@ -101,46 +104,51 @@ private:
/// the original input file, for example with -save-temps.
const char *MainFileName;
-public:
+public:
unsigned InstantiationDepth; // Maximum template instantiation depth.
+ const char *ObjCConstantStringClass;
+
enum GCMode { NonGC, GCOnly, HybridGC };
enum StackProtectorMode { SSPOff, SSPOn, SSPReq };
- enum VisibilityMode {
- Default,
- Protected,
+ enum VisibilityMode {
+ Default,
+ Protected,
Hidden
};
-
+
LangOptions() {
Trigraphs = BCPLComment = Bool = DollarIdents = AsmPreprocessor = 0;
GNUMode = ImplicitInt = Digraphs = 0;
HexFloats = 0;
GC = ObjC1 = ObjC2 = ObjCNonFragileABI = 0;
+ ObjCConstantStringClass = 0;
C99 = Microsoft = CPlusPlus = CPlusPlus0x = 0;
CXXOperatorNames = PascalStrings = WritableStrings = 0;
Exceptions = NeXTRuntime = Freestanding = NoBuiltin = 0;
+ Rtti = 1;
LaxVectorConversions = 1;
HeinousExtensions = 0;
AltiVec = OpenCL = StackProtector = 0;
-
+
SymbolVisibility = (unsigned) Default;
-
+
// FIXME: The default should be 1.
ThreadsafeStatics = 0;
+ POSIXThreads = 0;
Blocks = 0;
EmitAllDecls = 0;
MathErrno = 1;
// FIXME: The default should be 1.
AccessControl = 0;
-
+ ElideConstructors = 1;
+
OverflowChecking = 0;
ObjCGCBitmapPrint = 0;
- ObjCSenderDispatch = 0;
InstantiationDepth = 99;
-
+
Optimize = 0;
OptimizeSize = 0;
@@ -154,7 +162,7 @@ public:
MainFileName = 0;
}
-
+
GCMode getGCMode() const { return (GCMode) GC; }
void setGCMode(GCMode m) { GC = (unsigned) m; }
@@ -168,8 +176,8 @@ public:
const char *getMainFileName() const { return MainFileName; }
void setMainFileName(const char *Name) { MainFileName = Name; }
- VisibilityMode getVisibilityMode() const {
- return (VisibilityMode) SymbolVisibility;
+ VisibilityMode getVisibilityMode() const {
+ return (VisibilityMode) SymbolVisibility;
}
void setVisibilityMode(VisibilityMode v) { SymbolVisibility = (unsigned) v; }
};
diff --git a/include/clang/Basic/Makefile b/include/clang/Basic/Makefile
index b08d614..6ed5fef 100644
--- a/include/clang/Basic/Makefile
+++ b/include/clang/Basic/Makefile
@@ -9,12 +9,12 @@ TABLEGEN_INC_FILES_COMMON = 1
include $(LEVEL)/Makefile.common
-$(ObjDir)/Diagnostic%Kinds.inc.tmp : Diagnostic.td DiagnosticGroups.td Diagnostic%Kinds.td $(TBLGEN)
+$(ObjDir)/Diagnostic%Kinds.inc.tmp : Diagnostic.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)
+$(ObjDir)/DiagnosticGroups.inc.tmp : Diagnostic.td DiagnosticGroups.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
index f54d670..6524516 100644
--- a/include/clang/Basic/OnDiskHashTable.h
+++ b/include/clang/Basic/OnDiskHashTable.h
@@ -29,7 +29,7 @@ namespace clang {
// 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) {
+inline unsigned BernsteinHash(const char* x) {
unsigned int R = 0;
for ( ; *x != '\0' ; ++x) R = R * 33 + *x;
return R + (R >> 5);
@@ -131,29 +131,29 @@ 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 {
+
+ 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);
@@ -162,7 +162,7 @@ private:
++B.length;
B.head = E;
}
-
+
void resize(size_t newsize) {
Bucket* newBuckets = (Bucket*) std::calloc(newsize, sizeof(Bucket));
// Populate newBuckets with the old entries.
@@ -173,14 +173,14 @@ private:
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) {
@@ -188,7 +188,7 @@ public:
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);
@@ -201,42 +201,42 @@ public:
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 =
+ 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;
+ 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);
}
@@ -254,7 +254,7 @@ 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,
@@ -271,7 +271,7 @@ public:
const unsigned char* getBuckets() const { return Buckets; }
bool isEmpty() const { return NumEntries == 0; }
-
+
class iterator {
internal_key_type key;
const unsigned char* const data;
@@ -282,12 +282,12 @@ public:
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; }
+
+ 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;
@@ -295,25 +295,25 @@ public:
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);
+ 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.
@@ -321,7 +321,7 @@ public:
Items += item_len;
continue;
}
-
+
// Read the key.
const internal_key_type& X =
InfoPtr->ReadKey((const unsigned char* const) Items, L.first);
@@ -331,17 +331,17 @@ public:
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()) {
@@ -349,14 +349,14 @@ public:
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
+#endif
diff --git a/include/clang/Basic/PartialDiagnostic.h b/include/clang/Basic/PartialDiagnostic.h
new file mode 100644
index 0000000..e8cc564
--- /dev/null
+++ b/include/clang/Basic/PartialDiagnostic.h
@@ -0,0 +1,155 @@
+//===--- PartialDiagnostic.h - Diagnostic "closures" ----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a partial diagnostic that can be emitted anwyhere
+// in a DiagnosticBuilder stream.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_PARTIALDIAGNOSTIC_H
+#define LLVM_CLANG_PARTIALDIAGNOSTIC_H
+
+#include "clang/AST/Type.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/STLExtras.h"
+
+namespace clang {
+
+class DeclarationName;
+
+class PartialDiagnostic {
+ struct Storage {
+ Storage() : NumDiagArgs(0), NumDiagRanges(0) { }
+
+ 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.
+ unsigned char NumDiagArgs;
+
+ /// NumDiagRanges - This is the number of ranges in the DiagRanges array.
+ unsigned char NumDiagRanges;
+
+ /// 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];
+
+ /// 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.
+ mutable 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.
+ mutable const SourceRange *DiagRanges[10];
+ };
+
+ /// DiagID - The diagnostic ID.
+ mutable unsigned DiagID;
+
+ /// DiagStorare - Storge for args and ranges.
+ mutable Storage *DiagStorage;
+
+ void AddTaggedVal(intptr_t V, Diagnostic::ArgumentKind Kind) const {
+ if (!DiagStorage)
+ DiagStorage = new Storage;
+
+ assert(DiagStorage->NumDiagArgs < Storage::MaxArguments &&
+ "Too many arguments to diagnostic!");
+ DiagStorage->DiagArgumentsKind[DiagStorage->NumDiagArgs] = Kind;
+ DiagStorage->DiagArgumentsVal[DiagStorage->NumDiagArgs++] = V;
+ }
+
+ void AddSourceRange(const SourceRange &R) const {
+ if (!DiagStorage)
+ DiagStorage = new Storage;
+
+ assert(DiagStorage->NumDiagRanges <
+ llvm::array_lengthof(DiagStorage->DiagRanges) &&
+ "Too many arguments to diagnostic!");
+ DiagStorage->DiagRanges[DiagStorage->NumDiagRanges++] = &R;
+ }
+
+ void operator=(const PartialDiagnostic &); // DO NOT IMPLEMENT
+
+public:
+ PartialDiagnostic(unsigned DiagID)
+ : DiagID(DiagID), DiagStorage(0) { }
+
+ PartialDiagnostic(const PartialDiagnostic &Other)
+ : DiagID(Other.DiagID), DiagStorage(Other.DiagStorage) {
+ Other.DiagID = 0;
+ Other.DiagStorage = 0;
+ }
+
+ ~PartialDiagnostic() {
+ delete DiagStorage;
+ }
+
+ unsigned getDiagID() const { return DiagID; }
+
+ void Emit(const DiagnosticBuilder &DB) const {
+ if (!DiagStorage)
+ return;
+
+ // Add all arguments.
+ for (unsigned i = 0, e = DiagStorage->NumDiagArgs; i != e; ++i) {
+ DB.AddTaggedVal(DiagStorage->DiagArgumentsVal[i],
+ (Diagnostic::ArgumentKind)DiagStorage->DiagArgumentsKind[i]);
+ }
+
+ // Add all ranges.
+ for (unsigned i = 0, e = DiagStorage->NumDiagRanges; i != e; ++i)
+ DB.AddSourceRange(*DiagStorage->DiagRanges[i]);
+ }
+
+ friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
+ QualType T) {
+ PD.AddTaggedVal(reinterpret_cast<intptr_t>(T.getAsOpaquePtr()),
+ Diagnostic::ak_qualtype);
+ return PD;
+ }
+
+ friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
+ unsigned I) {
+ PD.AddTaggedVal(I, Diagnostic::ak_uint);
+ return PD;
+ }
+
+ friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
+ const SourceRange &R) {
+ PD.AddSourceRange(R);
+ return PD;
+ }
+
+ friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
+ DeclarationName N);
+};
+
+inline PartialDiagnostic PDiag(unsigned DiagID = 0) {
+ return PartialDiagnostic(DiagID);
+}
+
+inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
+ const PartialDiagnostic &PD) {
+ PD.Emit(DB);
+ return DB;
+}
+
+
+} // end namespace clang
+#endif
diff --git a/include/clang/Basic/SourceLocation.h b/include/clang/Basic/SourceLocation.h
index 2405c2f..28cf2db 100644
--- a/include/clang/Basic/SourceLocation.h
+++ b/include/clang/Basic/SourceLocation.h
@@ -24,10 +24,10 @@ namespace llvm {
}
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.
///
@@ -36,19 +36,19 @@ class FileID {
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) {
@@ -58,8 +58,8 @@ private:
}
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.
@@ -72,17 +72,17 @@ class SourceLocation {
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.
@@ -96,7 +96,7 @@ private:
L.ID = ID;
return L;
}
-
+
static SourceLocation getMacroLoc(unsigned ID) {
assert((ID & MacroIDBit) == 0 && "Ran out of source locations!");
SourceLocation L;
@@ -104,7 +104,7 @@ private:
return L;
}
public:
-
+
/// getFileLocWithOffset - Return a source location with the specified offset
/// from this file SourceLocation.
SourceLocation getFileLocWithOffset(int Offset) const {
@@ -113,14 +113,14 @@ public:
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) {
@@ -128,7 +128,7 @@ public:
X.ID = Encoding;
return X;
}
-
+
void print(llvm::raw_ostream &OS, const SourceManager &SM) const;
void dump(const SourceManager &SM) const;
};
@@ -140,7 +140,7 @@ inline bool operator==(const SourceLocation &LHS, const SourceLocation &RHS) {
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();
}
@@ -153,24 +153,24 @@ 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 {
@@ -179,21 +179,21 @@ public:
/// Creates a FullSourceLoc where isValid() returns false.
explicit FullSourceLoc() : SrcMgr((SourceManager*) 0) {}
- explicit FullSourceLoc(SourceLocation Loc, SourceManager &SM)
+ 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;
@@ -204,37 +204,37 @@ public:
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
+ friend inline bool
operator==(const FullSourceLoc &LHS, const FullSourceLoc &RHS) {
return LHS.getRawEncoding() == RHS.getRawEncoding() &&
LHS.SrcMgr == RHS.SrcMgr;
}
- friend inline bool
+ 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
@@ -250,13 +250,13 @@ public:
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; }
@@ -264,7 +264,7 @@ public:
/// 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; }
@@ -274,7 +274,7 @@ public:
SourceLocation getIncludeLoc() const { return IncludeLoc; }
};
-
+
} // end namespace clang
namespace llvm {
@@ -286,20 +286,20 @@ namespace llvm {
return clang::FileID();
}
static inline clang::FileID getTombstoneKey() {
- return clang::FileID::getSentinel();
+ 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
index 249ca89..7eb988f 100644
--- a/include/clang/Basic/SourceManager.h
+++ b/include/clang/Basic/SourceManager.h
@@ -24,9 +24,9 @@
namespace llvm {
class MemoryBuffer;
}
-
+
namespace clang {
-
+
class SourceManager;
class FileManager;
class FileEntry;
@@ -46,7 +46,7 @@ namespace SrcMgr {
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 {
@@ -54,17 +54,20 @@ namespace SrcMgr {
/// file. This is owned by the ContentCache object.
mutable const llvm::MemoryBuffer *Buffer;
+ /// The line and column at which we should truncate the file.
+ unsigned TruncateAtLine, TruncateAtColumn;
+
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;
@@ -76,44 +79,57 @@ namespace SrcMgr {
/// 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;
}
-
+
+ /// \brief Truncate this file at the given line and column.
+ ///
+ /// \param Line the line on which to truncate the current file (1-based).
+ /// \param Column the column at which to truncate the current file.
+ /// (1-based).
+ void truncateAt(unsigned Line, unsigned Column);
+
+ /// \brief Determines whether the file was artificially truncated with
+ /// truncateAt().
+ bool isTruncated() const { return TruncateAtLine && TruncateAtColumn; }
+
ContentCache(const FileEntry *Ent = 0)
- : Buffer(0), Entry(Ent), SourceLineCache(0), NumLines(0) {}
+ : Buffer(0), TruncateAtLine(0), TruncateAtColumn(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) {
+ ContentCache(const ContentCache &RHS)
+ : Buffer(0), TruncateAtLine(0), TruncateAtColumn(0), SourceLineCache(0) {
Entry = RHS.Entry;
assert (RHS.Buffer == 0 && RHS.SourceLineCache == 0
&& "Passed ContentCache object cannot own a buffer.");
-
- NumLines = RHS.NumLines;
+
+ NumLines = RHS.NumLines;
}
-
+
private:
// Disable assignments.
- ContentCache &operator=(const ContentCache& RHS);
- };
+ ContentCache &operator=(const ContentCache& RHS);
+ };
/// FileInfo - Information about a FileID, basically just the logical file
/// that it represents and include stack information.
@@ -128,7 +144,7 @@ namespace SrcMgr {
/// 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.
@@ -145,39 +161,39 @@ namespace SrcMgr {
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 {
+ 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
@@ -193,12 +209,12 @@ namespace SrcMgr {
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
@@ -213,7 +229,7 @@ namespace SrcMgr {
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.
@@ -225,10 +241,10 @@ namespace SrcMgr {
};
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;
@@ -238,7 +254,7 @@ namespace SrcMgr {
assert(isInstantiation() && "Not an instantiation SLocEntry!");
return Instantiation;
}
-
+
static SLocEntry get(unsigned Offset, const FileInfo &FI) {
SLocEntry E;
E.Offset = Offset << 1;
@@ -277,18 +293,18 @@ public:
/// 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.
+ /// 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;
@@ -308,49 +324,55 @@ class SourceManager {
/// 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;
-
+
// Cache results for the isBeforeInTranslationUnit method.
mutable FileID LastLFIDForBeforeTUCheck;
mutable FileID LastRFIDForBeforeTUCheck;
mutable bool LastResForBeforeTUCheck;
+
+ // Keep track of the file/line/column that we should truncate.
+ const FileEntry *TruncateFile;
+ unsigned TruncateAtLine;
+ unsigned TruncateAtColumn;
// SourceManager doesn't support copy construction.
explicit SourceManager(const SourceManager&);
- void operator=(const SourceManager&);
+ void operator=(const SourceManager&);
public:
- SourceManager()
- : ExternalSLocEntries(0), LineTable(0), NumLinearScans(0),
- NumBinaryProbes(0) {
+ SourceManager()
+ : ExternalSLocEntries(0), LineTable(0), NumLinearScans(0),
+ NumBinaryProbes(0), TruncateFile(0), TruncateAtLine(0),
+ TruncateAtColumn(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) {
@@ -358,15 +380,15 @@ public:
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,
+ /// 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,
@@ -376,7 +398,7 @@ public:
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.
@@ -386,7 +408,7 @@ public:
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.
@@ -405,31 +427,31 @@ public:
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
@@ -437,14 +459,14 @@ public:
///
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 {
@@ -453,7 +475,7 @@ public:
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 {
@@ -462,18 +484,18 @@ public:
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.
@@ -483,12 +505,12 @@ public:
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;
+ 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
@@ -497,7 +519,7 @@ public:
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.
@@ -505,11 +527,11 @@ public:
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);
}
@@ -520,29 +542,29 @@ public:
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
@@ -551,24 +573,24 @@ public:
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
+ /// 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:
@@ -576,7 +598,7 @@ public:
/// 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
@@ -585,44 +607,44 @@ public:
/// 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;
}
-
+
/// isInExternCSystemHeader - Returns if a SourceLocation is in an "extern C"
/// system header.
bool isInExternCSystemHeader(SourceLocation Loc) const {
return getFileCharacteristic(Loc) == SrcMgr::C_ExternCSystem;
}
-
+
//===--------------------------------------------------------------------===//
// 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 IsFileEntry, bool IsFileExit,
bool IsSystemHeader, bool IsExternCHeader);
/// \brief Determine if the source manager has a line table.
@@ -641,12 +663,18 @@ public:
/// be based upon the first inclusion.
SourceLocation getLocation(const FileEntry *SourceFile,
unsigned Line, unsigned Col) const;
-
+
/// \brief Determines the order of 2 source locations in the translation unit.
///
/// \returns true if LHS source location comes before RHS, false otherwise.
bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const;
+ /// \brief Truncate the given file at the specified line/column.
+ void truncateFileAt(const FileEntry *Entry, unsigned Line, unsigned Column);
+
+ /// \brief Determine whether this file was truncated.
+ bool isTruncatedFile(FileID FID) const;
+
// Iterators over FileInfos.
typedef llvm::DenseMap<const FileEntry*, SrcMgr::ContentCache*>
::const_iterator fileinfo_iterator;
@@ -657,22 +685,22 @@ public:
///
void PrintStats() const;
- // Iteration over the source location entry table.
+ // 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_begin() const {
+ return SLocEntryTable.begin();
}
- sloc_entry_iterator sloc_entry_end() const {
- return SLocEntryTable.end();
+ 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 &&
+ if (ExternalSLocEntries &&
FID.ID < SLocEntryLoaded.size() &&
!SLocEntryLoaded[FID.ID])
ExternalSLocEntries->ReadSLocEntry(FID.ID);
@@ -698,14 +726,14 @@ private:
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.
@@ -714,15 +742,15 @@ private:
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*
+ const SrcMgr::ContentCache*
createMemBufferContentCache(const llvm::MemoryBuffer *Buf);
-
+
FileID getFileIDSlow(unsigned SLocOffset) const;
SourceLocation getInstantiationLocSlowCase(SourceLocation Loc) const;
@@ -730,7 +758,7 @@ private:
std::pair<FileID, unsigned>
getDecomposedInstantiationLocSlowCase(const SrcMgr::SLocEntry *E,
- unsigned Offset) const;
+ unsigned Offset) const;
std::pair<FileID, unsigned>
getDecomposedSpellingLocSlowCase(const SrcMgr::SLocEntry *E,
unsigned Offset) const;
diff --git a/include/clang/Basic/SourceManagerInternals.h b/include/clang/Basic/SourceManagerInternals.h
index 0bcb68e..258989c 100644
--- a/include/clang/Basic/SourceManagerInternals.h
+++ b/include/clang/Basic/SourceManagerInternals.h
@@ -28,22 +28,22 @@ namespace clang {
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,
+
+ /// 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) {
@@ -70,7 +70,7 @@ inline bool operator<(const LineEntry &E, unsigned 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 {
@@ -81,22 +81,22 @@ class LineTableInfo {
/// 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");
@@ -110,7 +110,7 @@ public:
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);
diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h
index 537d553..a1e0a17 100644
--- a/include/clang/Basic/TargetInfo.h
+++ b/include/clang/Basic/TargetInfo.h
@@ -16,31 +16,37 @@
// FIXME: Daniel isn't smart enough to use a prototype for this.
#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/Triple.h"
#include "llvm/Support/DataTypes.h"
#include <cassert>
#include <vector>
#include <string>
-namespace llvm { struct fltSemantics; }
+namespace llvm {
+struct fltSemantics;
+class StringRef;
+}
namespace clang {
class Diagnostic;
+class SourceLocation;
class SourceManager;
class LangOptions;
-
namespace Builtin { struct Info; }
-
+
/// TargetInfo - This class exposes information about the current target.
///
class TargetInfo {
- std::string Triple;
+ llvm::Triple Triple;
protected:
// Target values set by the ctor of the actual target implementation. Default
// values are specified by the TargetInfo constructor.
bool TLSSupported;
unsigned char PointerWidth, PointerAlign;
unsigned char WCharWidth, WCharAlign;
+ unsigned char Char16Width, Char16Align;
+ unsigned char Char32Width, Char32Align;
unsigned char IntWidth, IntAlign;
unsigned char FloatWidth, FloatAlign;
unsigned char DoubleWidth, DoubleAlign;
@@ -55,8 +61,8 @@ protected:
// TargetInfo Constructor. Default initializes all fields.
TargetInfo(const std::string &T);
-
-public:
+
+public:
/// CreateTargetInfo - Return the target info object for the specified target
/// triple.
static TargetInfo* CreateTargetInfo(const std::string &Triple);
@@ -77,7 +83,7 @@ public:
};
protected:
IntType SizeType, IntMaxType, UIntMaxType, PtrDiffType, IntPtrType, WCharType,
- Int64Type;
+ Char16Type, Char32Type, Int64Type;
public:
IntType getSizeType() const { return SizeType; }
IntType getIntMaxType() const { return IntMaxType; }
@@ -87,6 +93,8 @@ public:
}
IntType getIntPtrType() const { return IntPtrType; }
IntType getWCharType() const { return WCharType; }
+ IntType getChar16Type() const { return Char16Type; }
+ IntType getChar32Type() const { return Char32Type; }
IntType getInt64Type() const { return Int64Type; }
/// getPointerWidth - Return the width of pointers on this target, for the
@@ -97,44 +105,50 @@ public:
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
- }
-
+
+ unsigned getCharWidth() const { return 8; } // FIXME
+ unsigned getCharAlign() const { return 8; } // FIXME
+
/// getShortWidth/Align - Return the size of 'signed short' and
- /// 'unsigned short' for this target, in bits.
+ /// '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
+
+ /// getWCharWidth/Align - Return the size of 'wchar_t' for this target, in
/// bits.
unsigned getWCharWidth() const { return WCharWidth; }
unsigned getWCharAlign() const { return WCharAlign; }
+ /// getChar16Width/Align - Return the size of 'char16_t' for this target, in
+ /// bits.
+ unsigned getChar16Width() const { return Char16Width; }
+ unsigned getChar16Align() const { return Char16Align; }
+
+ /// getChar32Width/Align - Return the size of 'char32_t' for this target, in
+ /// bits.
+ unsigned getChar32Width() const { return Char32Width; }
+ unsigned getChar32Align() const { return Char32Align; }
+
/// getFloatWidth/Align/Format - Return the size/align/format of 'float'.
unsigned getFloatWidth() const { return FloatWidth; }
unsigned getFloatAlign() const { return FloatAlign; }
@@ -152,13 +166,13 @@ public:
const llvm::fltSemantics &getLongDoubleFormat() const {
return *LongDoubleFormat;
}
-
+
/// getIntMaxTWidth - Return the size of intmax_t and uintmax_t for this
- /// target, in bits.
+ /// 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
@@ -166,22 +180,22 @@ public:
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,
+ virtual void getTargetBuiltins(const Builtin::Info *&Records,
unsigned &NumRecords) const = 0;
/// getVAListDeclaration - Return the declaration to use for
@@ -196,7 +210,7 @@ public:
// 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,
@@ -207,7 +221,7 @@ public:
};
unsigned Flags;
int TiedOperand;
-
+
std::string ConstraintStr; // constraint: "=rm"
std::string Name; // Operand name: [foo] with no []'s.
public:
@@ -221,11 +235,11 @@ public:
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.
@@ -234,12 +248,12 @@ public:
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.
@@ -261,24 +275,20 @@ public:
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();
+
+ /// getTriple - Return the target triple of the primary target.
+ const llvm::Triple &getTriple() const {
+ return Triple;
}
-
+
const char *getTargetDescription() const {
return DescriptionString;
}
@@ -290,55 +300,56 @@ public:
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 {
+ 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 {
+ 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";
+ /// isValidSectionSpecifier - This is an optional hook that targets can
+ /// implement to perform semantic checking on attribute((section("foo")))
+ /// specifiers. In this case, "foo" is passed in to be checked. If the
+ /// section specifier is invalid, the backend should return a non-empty string
+ /// that indicates the problem.
+ ///
+ /// This hook is a simple quality of implementation feature to catch errors
+ /// and give good diagnostics in cases when the assembler or code generator
+ /// would otherwise reject the section specifier.
+ ///
+ virtual std::string isValidSectionSpecifier(const llvm::StringRef &SR) const {
+ return "";
}
/// getDefaultLangOptions - Allow the target to specify default settings for
/// various language options. These may be overridden by command line
- /// options.
+ /// 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,
+ virtual void getDefaultFeatures(const std::string &CPU,
llvm::StringMap<bool> &Features) const {
}
+ /// getABI - Get the ABI in use.
+ virtual const char *getABI() const {
+ return "";
+ }
+
+ /// setABI - Use the specific ABI.
+ ///
+ /// \return - False on error (invalid ABI name).
+ virtual bool setABI(const std::string &Name) {
+ return false;
+ }
+
/// setFeatureEnabled - Enable or disable a specific target feature,
/// the feature name must be valid.
///
@@ -359,10 +370,17 @@ public:
return RegParmMax;
}
- // isTLSSupported - Whether the target supports thread-local storage
- unsigned isTLSSupported() const {
+ /// isTLSSupported - Whether the target supports thread-local storage.
+ bool isTLSSupported() const {
return TLSSupported;
}
+
+ /// getEHDataRegisterNumber - Return the register number that
+ /// __builtin_eh_return_regno would return with the specified argument.
+ virtual int getEHDataRegisterNumber(unsigned RegNo) const {
+ return -1;
+ }
+
protected:
virtual uint64_t getPointerWidthV(unsigned AddrSpace) const {
@@ -374,11 +392,11 @@ protected:
virtual enum IntType getPtrDiffTypeV(unsigned AddrSpace) const {
return PtrDiffType;
}
- virtual void getGCCRegNames(const char * const *&Names,
+ virtual void getGCCRegNames(const char * const *&Names,
unsigned &NumNames) const = 0;
- virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
unsigned &NumAliases) const = 0;
- virtual bool validateAsmConstraint(const char *&Name,
+ virtual bool validateAsmConstraint(const char *&Name,
TargetInfo::ConstraintInfo &info) const= 0;
};
diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def
index e711996..239712c 100644
--- a/include/clang/Basic/TokenKinds.def
+++ b/include/clang/Basic/TokenKinds.def
@@ -92,6 +92,7 @@ PPKEYWORD(unassert)
TOK(unknown) // Not a token.
TOK(eof) // End of file.
TOK(eom) // End of macro (end of line inside a macro).
+TOK(code_completion) // Code completion marker
// C99 6.4.9: Comments.
TOK(comment) // Comment (only in -E -C[C] mode)
diff --git a/include/clang/Basic/TokenKinds.h b/include/clang/Basic/TokenKinds.h
index 62a9e42..85dc067 100644
--- a/include/clang/Basic/TokenKinds.h
+++ b/include/clang/Basic/TokenKinds.h
@@ -29,7 +29,7 @@ enum TokenKind {
/// 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,
+#define PPKEYWORD(X) pp_##X,
#include "clang/Basic/TokenKinds.def"
NUM_PP_KEYWORDS
};
diff --git a/include/clang/Basic/Version.h b/include/clang/Basic/Version.h
index f0e1aa7..120d5a4 100644
--- a/include/clang/Basic/Version.h
+++ b/include/clang/Basic/Version.h
@@ -7,7 +7,8 @@
//
//===----------------------------------------------------------------------===//
//
-// This header defines version macros for Clang.
+// This header defines version macros and version-related utility functions
+// for Clang.
//
//===----------------------------------------------------------------------===//
@@ -17,12 +18,25 @@
/// \brief Clang major version
#define CLANG_VERSION_MAJOR 1
+// FIXME: Updates to this file must also update CMakeLists.txt and VER.
/// \brief Clang minor version
-#define CLANG_VERSION_MINOR 0
+#define CLANG_VERSION_MINOR 1
+
+/// \brief Clang patchlevel version
+// #define CLANG_VERSION_PATCHLEVEL 1
/// \brief Helper macro for CLANG_VERSION_STRING.
#define CLANG_MAKE_VERSION_STRING2(X) #X
+#ifdef CLANG_VERSION_PATCHLEVEL
+/// \brief Helper macro for CLANG_VERSION_STRING.
+#define CLANG_MAKE_VERSION_STRING(X,Y,Z) CLANG_MAKE_VERSION_STRING2(X.Y.Z)
+
+/// \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,CLANG_VERSION_PATCHLEVEL)
+#else
/// \brief Helper macro for CLANG_VERSION_STRING.
#define CLANG_MAKE_VERSION_STRING(X,Y) CLANG_MAKE_VERSION_STRING2(X.Y)
@@ -30,6 +44,16 @@
/// "1.0".
#define CLANG_VERSION_STRING \
CLANG_MAKE_VERSION_STRING(CLANG_VERSION_MAJOR,CLANG_VERSION_MINOR)
-
+#endif
+
+namespace clang {
+ /// \brief Retrieves the Subversion path that identifies the particular
+ /// Clang branch, tag, or trunk from which this Clang was built.
+ const char *getClangSubversionPath();
+
+ /// \brief Retrieves the Subversion revision number from which this Clang
+ /// was built.
+ unsigned getClangSubversionRevision();
+}
#endif // LLVM_CLANG_BASIC_VERSION_H
diff --git a/include/clang/CodeGen/ModuleBuilder.h b/include/clang/CodeGen/ModuleBuilder.h
index 12b74d5..1871c8f 100644
--- a/include/clang/CodeGen/ModuleBuilder.h
+++ b/include/clang/CodeGen/ModuleBuilder.h
@@ -26,13 +26,13 @@ namespace clang {
class Diagnostic;
class LangOptions;
class CompileOptions;
-
+
class CodeGenerator : public ASTConsumer {
public:
virtual llvm::Module* GetModule() = 0;
- virtual llvm::Module* ReleaseModule() = 0;
+ virtual llvm::Module* ReleaseModule() = 0;
};
-
+
CodeGenerator *CreateLLVMCodeGen(Diagnostic &Diags,
const std::string &ModuleName,
const CompileOptions &CO,
diff --git a/include/clang/Driver/Action.h b/include/clang/Driver/Action.h
index ceef189..679704c 100644
--- a/include/clang/Driver/Action.h
+++ b/include/clang/Driver/Action.h
@@ -26,7 +26,7 @@ namespace clang {
namespace driver {
class Arg;
-/// Action - Represent an abstract compilation step to perform.
+/// 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.
@@ -63,15 +63,15 @@ private:
/// 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)
+ 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) {}
+ Action(ActionClass _Kind, const ActionList &_Inputs, types::ID _Type)
+ : Kind(_Kind), Type(_Type), Inputs(_Inputs) {}
public:
virtual ~Action();
@@ -90,7 +90,7 @@ public:
const_iterator begin() const { return Inputs.begin(); }
const_iterator end() const { return Inputs.end(); }
- static bool classof(const Action *) { return true; }
+ static bool classof(const Action *) { return true; }
};
class InputAction : public Action {
@@ -100,8 +100,8 @@ public:
const Arg &getInputArg() const { return Input; }
- static bool classof(const Action *A) {
- return A->getKind() == InputClass;
+ static bool classof(const Action *A) {
+ return A->getKind() == InputClass;
}
static bool classof(const InputAction *) { return true; }
};
@@ -116,8 +116,8 @@ public:
const char *getArchName() const { return ArchName; }
- static bool classof(const Action *A) {
- return A->getKind() == BindArchClass;
+ static bool classof(const Action *A) {
+ return A->getKind() == BindArchClass;
}
static bool classof(const BindArchAction *) { return true; }
};
@@ -128,9 +128,9 @@ protected:
JobAction(ActionClass Kind, const ActionList &Inputs, types::ID Type);
public:
- static bool classof(const Action *A) {
+ static bool classof(const Action *A) {
return (A->getKind() >= JobClassFirst &&
- A->getKind() <= JobClassLast);
+ A->getKind() <= JobClassLast);
}
static bool classof(const JobAction *) { return true; }
};
@@ -139,7 +139,7 @@ class PreprocessJobAction : public JobAction {
public:
PreprocessJobAction(Action *Input, types::ID OutputType);
- static bool classof(const Action *A) {
+ static bool classof(const Action *A) {
return A->getKind() == PreprocessJobClass;
}
static bool classof(const PreprocessJobAction *) { return true; }
@@ -149,7 +149,7 @@ class PrecompileJobAction : public JobAction {
public:
PrecompileJobAction(Action *Input, types::ID OutputType);
- static bool classof(const Action *A) {
+ static bool classof(const Action *A) {
return A->getKind() == PrecompileJobClass;
}
static bool classof(const PrecompileJobAction *) { return true; }
@@ -159,7 +159,7 @@ class AnalyzeJobAction : public JobAction {
public:
AnalyzeJobAction(Action *Input, types::ID OutputType);
- static bool classof(const Action *A) {
+ static bool classof(const Action *A) {
return A->getKind() == AnalyzeJobClass;
}
static bool classof(const AnalyzeJobAction *) { return true; }
@@ -169,7 +169,7 @@ class CompileJobAction : public JobAction {
public:
CompileJobAction(Action *Input, types::ID OutputType);
- static bool classof(const Action *A) {
+ static bool classof(const Action *A) {
return A->getKind() == CompileJobClass;
}
static bool classof(const CompileJobAction *) { return true; }
@@ -179,7 +179,7 @@ class AssembleJobAction : public JobAction {
public:
AssembleJobAction(Action *Input, types::ID OutputType);
- static bool classof(const Action *A) {
+ static bool classof(const Action *A) {
return A->getKind() == AssembleJobClass;
}
static bool classof(const AssembleJobAction *) { return true; }
@@ -189,7 +189,7 @@ class LinkJobAction : public JobAction {
public:
LinkJobAction(ActionList &Inputs, types::ID Type);
- static bool classof(const Action *A) {
+ static bool classof(const Action *A) {
return A->getKind() == LinkJobClass;
}
static bool classof(const LinkJobAction *) { return true; }
@@ -199,7 +199,7 @@ class LipoJobAction : public JobAction {
public:
LipoJobAction(ActionList &Inputs, types::ID Type);
- static bool classof(const Action *A) {
+ static bool classof(const Action *A) {
return A->getKind() == LipoJobClass;
}
static bool classof(const LipoJobAction *) { return true; }
diff --git a/include/clang/Driver/Arg.h b/include/clang/Driver/Arg.h
index 6bed2b8..ebf40d4 100644
--- a/include/clang/Driver/Arg.h
+++ b/include/clang/Driver/Arg.h
@@ -49,7 +49,7 @@ namespace driver {
/// 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;
@@ -66,7 +66,7 @@ namespace driver {
protected:
Arg(ArgClass Kind, const Option *Opt, unsigned Index,
const Arg *BaseArg = 0);
-
+
public:
Arg(const Arg &);
virtual ~Arg();
@@ -74,12 +74,12 @@ namespace driver {
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;
+ const Arg &getBaseArg() const {
+ return BaseArg ? *BaseArg : *this;
}
void setBaseArg(const Arg *_BaseArg) {
BaseArg = _BaseArg;
@@ -88,14 +88,14 @@ namespace driver {
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;
@@ -105,7 +105,7 @@ namespace driver {
/// (e.g., Xlinker).
void renderAsInput(const ArgList &Args, ArgStringList &Output) const;
- static bool classof(const Arg *) { return true; }
+ static bool classof(const Arg *) { return true; }
void dump() const;
@@ -124,8 +124,8 @@ namespace driver {
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 Arg *A) {
+ return A->getKind() == Arg::FlagClass;
}
static bool classof(const FlagArg *) { return true; }
};
@@ -140,8 +140,8 @@ namespace driver {
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 Arg *A) {
+ return A->getKind() == Arg::PositionalClass;
}
static bool classof(const PositionalArg *) { return true; }
};
@@ -157,8 +157,8 @@ namespace driver {
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 Arg *A) {
+ return A->getKind() == Arg::JoinedClass;
}
static bool classof(const JoinedArg *) { return true; }
};
@@ -169,7 +169,7 @@ namespace driver {
unsigned NumValues;
public:
- SeparateArg(const Option *Opt, unsigned Index, unsigned NumValues,
+ SeparateArg(const Option *Opt, unsigned Index, unsigned NumValues,
const Arg *BaseArg = 0);
virtual void render(const ArgList &Args, ArgStringList &Output) const;
@@ -177,8 +177,8 @@ namespace driver {
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 Arg *A) {
+ return A->getKind() == Arg::SeparateClass;
}
static bool classof(const SeparateArg *) { return true; }
};
@@ -193,7 +193,7 @@ namespace driver {
std::vector<std::string> Values;
public:
- CommaJoinedArg(const Option *Opt, unsigned Index, const char *Str,
+ CommaJoinedArg(const Option *Opt, unsigned Index, const char *Str,
const Arg *BaseArg = 0);
virtual void render(const ArgList &Args, ArgStringList &Output) const;
@@ -201,8 +201,8 @@ namespace driver {
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 Arg *A) {
+ return A->getKind() == Arg::CommaJoinedClass;
}
static bool classof(const CommaJoinedArg *) { return true; }
};
@@ -211,7 +211,7 @@ namespace driver {
/// values.
class JoinedAndSeparateArg : public Arg {
public:
- JoinedAndSeparateArg(const Option *Opt, unsigned Index,
+ JoinedAndSeparateArg(const Option *Opt, unsigned Index,
const Arg *BaseArg = 0);
virtual void render(const ArgList &Args, ArgStringList &Output) const;
@@ -219,8 +219,8 @@ namespace driver {
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 Arg *A) {
+ return A->getKind() == Arg::JoinedAndSeparateClass;
}
static bool classof(const JoinedAndSeparateArg *) { return true; }
};
diff --git a/include/clang/Driver/ArgList.h b/include/clang/Driver/ArgList.h
index a9c890b..dcb6038 100644
--- a/include/clang/Driver/ArgList.h
+++ b/include/clang/Driver/ArgList.h
@@ -14,8 +14,14 @@
#include "clang/Driver/Util.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
#include <list>
+#include <string>
+
+namespace llvm {
+ class Twine;
+}
namespace clang {
namespace driver {
@@ -64,17 +70,17 @@ namespace driver {
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 {
+ 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 {
+ bool hasArg(options::ID Id0, options::ID Id1, bool Claim=true) const {
return getLastArg(Id0, Id1, Claim) != 0;
}
@@ -104,15 +110,15 @@ namespace driver {
/// AddAllArgs - Render all arguments matching the given ids.
void AddAllArgs(ArgStringList &Output, options::ID Id0) const;
- void AddAllArgs(ArgStringList &Output, options::ID Id0,
+ void AddAllArgs(ArgStringList &Output, options::ID Id0,
options::ID Id1) const;
- void AddAllArgs(ArgStringList &Output, options::ID Id0, options::ID Id1,
+ 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,
+ void AddAllArgValues(ArgStringList &Output, options::ID Id0,
options::ID Id1) const;
/// AddAllArgsTranslated - Render all the arguments matching the
@@ -122,7 +128,7 @@ namespace driver {
/// \param Joined - If true, render the argument as joined with
/// the option specifier.
void AddAllArgsTranslated(ArgStringList &Output, options::ID Id0,
- const char *Translation,
+ const char *Translation,
bool Joined = false) const;
/// ClaimAllArgs - Claim all arguments which match the given
@@ -135,7 +141,14 @@ namespace driver {
/// MakeArgString - Construct a constant string pointer whose
/// lifetime will match that of the ArgList.
- virtual const char *MakeArgString(const char *Str) const = 0;
+ virtual const char *MakeArgString(llvm::StringRef Str) const = 0;
+ const char *MakeArgString(const char *Str) const {
+ return MakeArgString(llvm::StringRef(Str));
+ }
+ const char *MakeArgString(std::string Str) const {
+ return MakeArgString(llvm::StringRef(Str));
+ }
+ const char *MakeArgString(const llvm::Twine &Str) const;
/// @}
};
@@ -167,8 +180,8 @@ namespace driver {
InputArgList(const ArgList &);
~InputArgList();
- virtual const char *getArgString(unsigned Index) const {
- return ArgStrings[Index];
+ virtual const char *getArgString(unsigned Index) const {
+ return ArgStrings[Index];
}
/// getNumInputArgStrings - Return the number of original input
@@ -180,10 +193,10 @@ namespace driver {
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;
+ unsigned MakeIndex(llvm::StringRef String0) const;
+ unsigned MakeIndex(llvm::StringRef String0, llvm::StringRef String1) const;
- virtual const char *MakeArgString(const char *Str) const;
+ virtual const char *MakeArgString(llvm::StringRef Str) const;
/// @}
};
@@ -211,13 +224,13 @@ namespace driver {
~DerivedArgList();
virtual const char *getArgString(unsigned Index) const {
- return BaseArgs.getArgString(Index);
+ return BaseArgs.getArgString(Index);
}
/// @name Arg Synthesis
/// @{
- virtual const char *MakeArgString(const char *Str) const;
+ virtual const char *MakeArgString(llvm::StringRef Str) const;
/// MakeFlagArg - Construct a new FlagArg for the given option
/// \arg Id.
@@ -225,18 +238,18 @@ namespace driver {
/// MakePositionalArg - Construct a new Positional arg for the
/// given option \arg Id, with the provided \arg Value.
- Arg *MakePositionalArg(const Arg *BaseArg, const Option *Opt,
- const char *Value) const;
+ Arg *MakePositionalArg(const Arg *BaseArg, const Option *Opt,
+ llvm::StringRef Value) const;
/// MakeSeparateArg - Construct a new Positional arg for the
/// given option \arg Id, with the provided \arg Value.
- Arg *MakeSeparateArg(const Arg *BaseArg, const Option *Opt,
- const char *Value) const;
+ Arg *MakeSeparateArg(const Arg *BaseArg, const Option *Opt,
+ llvm::StringRef Value) const;
/// MakeJoinedArg - Construct a new Positional arg for the
/// given option \arg Id, with the provided \arg Value.
- Arg *MakeJoinedArg(const Arg *BaseArg, const Option *Opt,
- const char *Value) const;
+ Arg *MakeJoinedArg(const Arg *BaseArg, const Option *Opt,
+ llvm::StringRef Value) const;
/// @}
};
diff --git a/include/clang/Driver/Compilation.h b/include/clang/Driver/Compilation.h
index 6414ef1..56786a7 100644
--- a/include/clang/Driver/Compilation.h
+++ b/include/clang/Driver/Compilation.h
@@ -47,7 +47,8 @@ class Compilation {
JobList Jobs;
/// Cache of translated arguments for a particular tool chain.
- llvm::DenseMap<const ToolChain*, DerivedArgList*> TCArgs;
+ llvm::DenseMap<std::pair<const ToolChain*, const char*>,
+ DerivedArgList*> TCArgs;
/// Temporary files which should be removed on exit.
ArgStringList TempFiles;
@@ -56,7 +57,7 @@ class Compilation {
ArgStringList ResultFiles;
public:
- Compilation(const Driver &D, const ToolChain &DefaultToolChain,
+ Compilation(const Driver &D, const ToolChain &DefaultToolChain,
InputArgList *Args);
~Compilation();
@@ -79,12 +80,15 @@ public:
/// 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);
+ ///
+ /// \param BoundArch - The bound architecture name, or 0.
+ const DerivedArgList &getArgsForToolChain(const ToolChain *TC,
+ const char *BoundArch);
/// addTempFile - Add a file to remove on exit, and returns its
/// argument.
- const char *addTempFile(const char *Name) {
- TempFiles.push_back(Name);
+ const char *addTempFile(const char *Name) {
+ TempFiles.push_back(Name);
return Name;
}
@@ -99,7 +103,7 @@ public:
///
/// \param IssueErrors - Report failures as errors.
/// \return Whether all files were removed successfully.
- bool CleanupFileList(const ArgStringList &Files,
+ bool CleanupFileList(const ArgStringList &Files,
bool IssueErrors=false) const;
/// PrintJob - Print one job in -### format.
@@ -108,7 +112,7 @@ public:
/// \param J - The job to print.
/// \param Terminator - A string to print at the end of the line.
/// \param Quote - Should separate arguments be quoted.
- void PrintJob(llvm::raw_ostream &OS, const Job &J,
+ void PrintJob(llvm::raw_ostream &OS, const Job &J,
const char *Terminator, bool Quote) const;
/// ExecuteCommand - Execute an actual command.
diff --git a/include/clang/Driver/Driver.h b/include/clang/Driver/Driver.h
index c0def2b..c0327a2 100644
--- a/include/clang/Driver/Driver.h
+++ b/include/clang/Driver/Driver.h
@@ -15,12 +15,16 @@
#include "clang/Driver/Phases.h"
#include "clang/Driver/Util.h"
+#include "llvm/ADT/Triple.h"
#include "llvm/System/Path.h" // FIXME: Kill when CompilationInfo
// lands.
#include <list>
#include <set>
#include <string>
+namespace llvm {
+ class raw_ostream;
+}
namespace clang {
namespace driver {
class Action;
@@ -51,11 +55,11 @@ public:
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;
@@ -71,7 +75,7 @@ public:
/// Whether the driver should follow g++ like behavior.
bool CCCIsCXX : 1;
-
+
/// Echo commands while executing (in -v style).
bool CCCEcho : 1;
@@ -99,11 +103,11 @@ public:
private:
/// Only use clang for the given architectures (only used when
/// non-empty).
- std::set<std::string> CCCClangArchs;
+ std::set<llvm::Triple::ArchType> CCCClangArchs;
/// Certain options suppress the 'no input files' warning.
bool SuppressMissingInputWarning : 1;
-
+
std::list<std::string> TempFiles;
std::list<std::string> ResultFiles;
@@ -111,7 +115,7 @@ public:
Driver(const char *_Name, const char *_Dir,
const char *_DefaultHostTriple,
const char *_DefaultImageName,
- Diagnostic &_Diags);
+ bool IsProduction, Diagnostic &_Diags);
~Driver();
/// @name Accessors
@@ -185,14 +189,15 @@ public:
void PrintOptions(const ArgList &Args) const;
/// PrintVersion - Print the driver version.
- void PrintVersion(const Compilation &C) const;
+ void PrintVersion(const Compilation &C, llvm::raw_ostream &OS) 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;
+ std::string GetFilePath(const char *Name, const ToolChain &TC) const;
/// GetProgramPath - Lookup \arg Name in the list of program search
/// paths.
@@ -202,9 +207,10 @@ public:
///
/// \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;
+ std::string 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.
@@ -225,6 +231,7 @@ public:
void BuildJobsForAction(Compilation &C,
const Action *A,
const ToolChain *TC,
+ const char *BoundArch,
bool CanAcceptPipe,
bool AtTopLevel,
const char *LinkingOutput,
@@ -239,7 +246,7 @@ public:
/// \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 char *GetNamedOutputPath(Compilation &C,
const JobAction &JA,
const char *BaseInput,
bool AtTopLevel) const;
@@ -249,15 +256,15 @@ public:
///
/// 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;
+ bool ShouldUseClangCompiler(const Compilation &C, const JobAction &JA,
+ const llvm::Triple &ArchName) const;
/// @}
@@ -268,7 +275,7 @@ public:
/// \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,
+ static bool GetReleaseVersion(const char *Str, unsigned &Major,
unsigned &Minor, unsigned &Micro,
bool &HadExtra);
};
diff --git a/include/clang/Driver/DriverDiagnostic.h b/include/clang/Driver/DriverDiagnostic.h
index 705c342..d4a9da7 100644
--- a/include/clang/Driver/DriverDiagnostic.h
+++ b/include/clang/Driver/DriverDiagnostic.h
@@ -13,7 +13,7 @@
#include "clang/Basic/Diagnostic.h"
namespace clang {
- namespace diag {
+ namespace diag {
enum {
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE) ENUM,
#define DRIVERSTART
diff --git a/include/clang/Driver/HostInfo.h b/include/clang/Driver/HostInfo.h
index b5e80b0..bf67c34 100644
--- a/include/clang/Driver/HostInfo.h
+++ b/include/clang/Driver/HostInfo.h
@@ -20,13 +20,13 @@ namespace driver {
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.
+/// 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 {
protected:
const Driver &TheDriver;
@@ -38,46 +38,49 @@ 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.
+ /// 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.
+ /// 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.
+ /// CreateToolChain - Construct the toolchain to use for this host (which the
+ /// host retains ownership of).
///
- /// \param Args - The argument list, which may be used to alter the
- /// default toolchain, for example in the presence of -m32 or -m64.
+ /// \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.
+ /// \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;
+ virtual ToolChain *CreateToolChain(const ArgList &Args,
+ const char *ArchName=0) const = 0;
};
-const HostInfo *createDarwinHostInfo(const Driver &D,
+const HostInfo *createAuroraUXHostInfo(const Driver &D,
+ const llvm::Triple& Triple);
+const HostInfo *createDarwinHostInfo(const Driver &D,
const llvm::Triple& Triple);
-const HostInfo *createOpenBSDHostInfo(const Driver &D,
+const HostInfo *createOpenBSDHostInfo(const Driver &D,
const llvm::Triple& Triple);
-const HostInfo *createFreeBSDHostInfo(const Driver &D,
+const HostInfo *createFreeBSDHostInfo(const Driver &D,
const llvm::Triple& Triple);
-const HostInfo *createDragonFlyHostInfo(const Driver &D,
+const HostInfo *createDragonFlyHostInfo(const Driver &D,
const llvm::Triple& Triple);
-const HostInfo *createLinuxHostInfo(const Driver &D,
+const HostInfo *createLinuxHostInfo(const Driver &D,
const llvm::Triple& Triple);
-const HostInfo *createUnknownHostInfo(const Driver &D,
+const HostInfo *createUnknownHostInfo(const Driver &D,
const llvm::Triple& Triple);
} // end namespace driver
diff --git a/include/clang/Driver/Job.h b/include/clang/Driver/Job.h
index a23babd..906d731 100644
--- a/include/clang/Driver/Job.h
+++ b/include/clang/Driver/Job.h
@@ -46,7 +46,7 @@ public:
/// either a piped job or a job list.
void addCommand(Command *C);
- static bool classof(const Job *) { return true; }
+ static bool classof(const Job *) { return true; }
};
/// Command - An executable path/name and argument vector to
@@ -63,7 +63,7 @@ class Command : public Job {
ArgStringList Arguments;
public:
- Command(const Action &_Source, const char *_Executable,
+ Command(const Action &_Source, const char *_Executable,
const ArgStringList &_Arguments);
/// getSource - Return the Action which caused the creation of this job.
@@ -73,8 +73,8 @@ public:
const ArgStringList &getArguments() const { return Arguments; }
- static bool classof(const Job *J) {
- return J->getKind() == CommandClass;
+ static bool classof(const Job *J) {
+ return J->getKind() == CommandClass;
}
static bool classof(const Command *) { return true; }
};
@@ -97,15 +97,15 @@ public:
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 Job *J) {
+ return J->getKind() == PipedJobClass;
}
static bool classof(const PipedJob *) { return true; }
};
@@ -133,13 +133,13 @@ public:
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 Job *J) {
+ return J->getKind() == JobListClass;
}
static bool classof(const JobList *) { return true; }
};
-
+
} // end namespace driver
} // end namespace clang
diff --git a/include/clang/Driver/Option.h b/include/clang/Driver/Option.h
index c59faef..c70b648 100644
--- a/include/clang/Driver/Option.h
+++ b/include/clang/Driver/Option.h
@@ -24,7 +24,7 @@ namespace driver {
class Arg;
class InputArgList;
class OptionGroup;
-
+
/// Option - Abstract representation for a single form of driver
/// argument.
///
@@ -57,10 +57,10 @@ namespace driver {
options::ID ID;
/// The option name.
- const char *Name;
+ const char *Name;
/// Group this option is a member of, if any.
- const OptionGroup *Group;
+ const OptionGroup *Group;
/// Option that this is an alias for, if any.
const Option *Alias;
@@ -70,7 +70,7 @@ namespace driver {
/// 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.
@@ -78,18 +78,18 @@ namespace driver {
/// Always render this option as separate form its value.
bool ForceSeparateRender : 1;
-
+
/// Always render this option joined with its value.
- bool ForceJoinedRender : 1;
+ bool ForceJoinedRender : 1;
/// This option is only consumed by the driver.
- bool DriverOption : 1;
+ bool DriverOption : 1;
/// This option should not report argument unused errors.
- bool NoArgumentUnused : 1;
+ bool NoArgumentUnused : 1;
protected:
- Option(OptionClass Kind, options::ID ID, const char *Name,
+ Option(OptionClass Kind, options::ID ID, const char *Name,
const OptionGroup *Group, const Option *Alias);
public:
virtual ~Option();
@@ -108,13 +108,13 @@ namespace driver {
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; }
@@ -125,7 +125,7 @@ namespace driver {
/// getUnaliasedOption - Return the final option this option
/// aliases (itself, if the option has no alias).
- const Option *getUnaliasedOption() const {
+ const Option *getUnaliasedOption() const {
if (Alias) return Alias->getUnaliasedOption();
return this;
}
@@ -149,12 +149,12 @@ namespace driver {
/// 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 {
@@ -163,14 +163,14 @@ namespace driver {
virtual Arg *accept(const InputArgList &Args, unsigned &Index) const;
- static bool classof(const Option *O) {
- return O->getKind() == Option::GroupClass;
+ 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:
@@ -178,8 +178,8 @@ namespace driver {
virtual Arg *accept(const InputArgList &Args, unsigned &Index) const;
- static bool classof(const Option *O) {
- return O->getKind() == Option::InputClass;
+ static bool classof(const Option *O) {
+ return O->getKind() == Option::InputClass;
}
static bool classof(const InputOption *) { return true; }
};
@@ -191,8 +191,8 @@ namespace driver {
virtual Arg *accept(const InputArgList &Args, unsigned &Index) const;
- static bool classof(const Option *O) {
- return O->getKind() == Option::UnknownClass;
+ static bool classof(const Option *O) {
+ return O->getKind() == Option::UnknownClass;
}
static bool classof(const UnknownOption *) { return true; }
};
@@ -201,52 +201,52 @@ namespace driver {
class FlagOption : public Option {
public:
- FlagOption(options::ID ID, const char *Name, const OptionGroup *Group,
+ 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 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,
+ 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 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,
+ 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 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,
+ 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 Option *O) {
+ return O->getKind() == Option::CommaJoinedClass;
}
static bool classof(const CommaJoinedOption *) { return true; }
};
@@ -259,15 +259,15 @@ namespace driver {
unsigned NumArgs;
public:
- MultiArgOption(options::ID ID, const char *Name, const OptionGroup *Group,
+ 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 Option *O) {
+ return O->getKind() == Option::MultiArgClass;
}
static bool classof(const MultiArgOption *) { return true; }
};
@@ -276,13 +276,13 @@ namespace driver {
/// prefixes its (non-empty) value, or is follwed by a value.
class JoinedOrSeparateOption : public Option {
public:
- JoinedOrSeparateOption(options::ID ID, const char *Name,
+ 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 Option *O) {
+ return O->getKind() == Option::JoinedOrSeparateClass;
}
static bool classof(const JoinedOrSeparateOption *) { return true; }
};
@@ -291,13 +291,13 @@ namespace driver {
/// value and is followed by another value.
class JoinedAndSeparateOption : public Option {
public:
- JoinedAndSeparateOption(options::ID ID, const char *Name,
+ 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 Option *O) {
+ return O->getKind() == Option::JoinedAndSeparateClass;
}
static bool classof(const JoinedAndSeparateOption *) { return true; }
};
diff --git a/include/clang/Driver/Options.def b/include/clang/Driver/Options.def
index af108a8..4084be6 100644
--- a/include/clang/Driver/Options.def
+++ b/include/clang/Driver/Options.def
@@ -223,6 +223,8 @@ OPTION("--print-prog-name", _print_prog_name, Separate, INVALID, print_prog_name
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("--relocatable-pch", _relocatable_pch, Flag, INVALID, INVALID, "", 0,
+ "Build a relocatable precompiled header", 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)
@@ -322,6 +324,7 @@ 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_errors_fatal", arch__errors__fatal, Flag, INVALID, 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)
@@ -351,6 +354,8 @@ 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-ast", emit_ast, Flag, INVALID, INVALID, "", 0,
+ "Emit Clang AST files for source inputs", 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)
@@ -365,12 +370,15 @@ 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-strcat", fbuiltin_strcat, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fbuiltin-strcpy", fbuiltin_strcpy, Flag, 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("-fcolor-diagnostics", fcolor_diagnostics, Flag, 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("-fconstant-string-class=", fconstant_string_class_EQ, Joined, 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)
@@ -404,6 +412,8 @@ OPTION("-fnested-functions", fnested_functions, Flag, f_Group, INVALID, "", 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-strcat", fno_builtin_strcat, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fno-builtin-strcpy", fno_builtin_strcpy, 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-color-diagnostics", fno_color_diagnostics, Flag, f_Group, INVALID, "", 0, 0, 0)
@@ -413,11 +423,14 @@ OPTION("-fno-diagnostics-fixit-info", fno_diagnostics_fixit_info, Flag, f_Group,
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-exceptions", fno_exceptions, 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-omit-frame-pointer", fno_omit_frame_pointer, Flag, f_Group, INVALID, "", 0, 0, 0)
OPTION("-fno-pascal-strings", fno_pascal_strings, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fno-rtti", fno_rtti, Flag, f_Group, INVALID, "", 0, 0, 0)
OPTION("-fno-show-column", fno_show_column, Flag, f_Group, INVALID, "", 0, 0, 0)
OPTION("-fno-show-source-location", fno_show_source_location, Flag, f_Group, INVALID, "", 0, 0, 0)
OPTION("-fno-stack-protector", fno_stack_protector, Flag, f_Group, INVALID, "", 0, 0, 0)
@@ -447,6 +460,7 @@ 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("-frtti", frtti, Flag, f_Group, INVALID, "", 0, 0, 0)
OPTION("-fshow-source-location", fshow_source_location, Flag, f_Group, INVALID, "", 0, 0, 0)
OPTION("-fsigned-bitfields", fsigned_bitfields, Flag, f_Group, INVALID, "", 0, 0, 0)
OPTION("-fsigned-char", fsigned_char, Flag, f_Group, INVALID, "", 0, 0, 0)
@@ -457,7 +471,6 @@ 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)
@@ -497,10 +510,15 @@ 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("-mabi=", mabi_EQ, Joined, m_Group, INVALID, "d", 0, 0, 0)
OPTION("-march=", march_EQ, Joined, m_Group, INVALID, "d", 0, 0, 0)
+OPTION("-mcmodel=", mcmodel_EQ, Joined, m_Group, INVALID, "d", 0, 0, 0)
OPTION("-mconstant-cfstrings", mconstant_cfstrings, Flag, clang_ignored_m_Group, INVALID, "", 0, 0, 0)
+OPTION("-mcpu=", mcpu_EQ, Joined, m_Group, INVALID, "d", 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("-mfloat-abi=", mfloat_abi_EQ, Joined, m_Group, INVALID, "", 0, 0, 0)
+OPTION("-mhard-float", mhard_float, Flag, 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("-mllvm", mllvm, Separate, INVALID, INVALID, "", 0, 0, 0)
@@ -519,6 +537,7 @@ 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-thumb", mno_thumb, Flag, m_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)
@@ -529,6 +548,7 @@ 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("-mthumb", mthumb, Flag, m_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)
@@ -546,6 +566,7 @@ 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("-nostdclanginc", nostdclanginc, 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)
diff --git a/include/clang/Driver/Options.h b/include/clang/Driver/Options.h
index 8b959d3..7fcaf3f 100644
--- a/include/clang/Driver/Options.h
+++ b/include/clang/Driver/Options.h
@@ -24,7 +24,7 @@ namespace options {
#undef OPTION
};
}
-
+
class Arg;
class InputArgList;
class Option;
@@ -36,7 +36,7 @@ namespace options {
/// 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.
+ /// still use Option instances where convient.
class OptTable {
/// The table of options which have been constructed, indexed by
/// option::ID - 1.
diff --git a/include/clang/Driver/Tool.h b/include/clang/Driver/Tool.h
index d8b37e9..8a89f01 100644
--- a/include/clang/Driver/Tool.h
+++ b/include/clang/Driver/Tool.h
@@ -22,7 +22,7 @@ namespace driver {
class Job;
class JobAction;
class ToolChain;
-
+
typedef llvm::SmallVector<InputInfo, 4> InputInfoList;
/// Tool - Information on a specific compilation tool.
@@ -57,9 +57,9 @@ public:
/// 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 InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &TCArgs,
const char *LinkingOutput) const = 0;
};
diff --git a/include/clang/Driver/ToolChain.h b/include/clang/Driver/ToolChain.h
index c9d0ef1..b7630d8 100644
--- a/include/clang/Driver/ToolChain.h
+++ b/include/clang/Driver/ToolChain.h
@@ -68,18 +68,21 @@ public:
// 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;
+ /// TranslateArgs - Create a new derived argument list for any argument
+ /// translations this ToolChain may wish to perform.
+ ///
+ /// \param BoundArch - The bound architecture name, or 0.
+ virtual DerivedArgList *TranslateArgs(InputArgList &Args,
+ const char *BoundArch) 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;
+ std::string GetFilePath(const Compilation &C, const char *Name) const;
+ std::string GetProgramPath(const Compilation &C, const char *Name,
+ bool WantFile = false) const;
// Platform defaults information
diff --git a/include/clang/Driver/Types.def b/include/clang/Driver/Types.def
index 8d24e50..e01a04c 100644
--- a/include/clang/Driver/Types.def
+++ b/include/clang/Driver/Types.def
@@ -67,8 +67,9 @@ 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("ast", AST, INVALID, "ast", "u")
+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", "")
diff --git a/include/clang/Frontend/ASTConsumers.h b/include/clang/Frontend/ASTConsumers.h
index be45202..f59a0a7 100644
--- a/include/clang/Frontend/ASTConsumers.h
+++ b/include/clang/Frontend/ASTConsumers.h
@@ -14,11 +14,10 @@
#ifndef DRIVER_ASTCONSUMERS_H
#define DRIVER_ASTCONSUMERS_H
-#include "llvm/Support/raw_ostream.h"
#include <string>
-#include <iosfwd>
namespace llvm {
+ class raw_ostream;
class Module;
class LLVMContext;
namespace sys { class Path; }
@@ -30,20 +29,20 @@ class Diagnostic;
class FileManager;
class Preprocessor;
class PreprocessorFactory;
-struct CompileOptions;
+class 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);
+ASTConsumer *CreateASTPrinter(llvm::raw_ostream *OS);
-// AST XML-printer: prints out the AST in a XML format
+// 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,
+// 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);
+ASTConsumer *CreateASTPrinterXML(llvm::raw_ostream *OS);
// AST dumper: dumps the raw AST in human-readable form to stderr; this is
// intended for debugging.
@@ -58,10 +57,14 @@ ASTConsumer *CreateASTViewer();
// to stderr; this is intended for debugging.
ASTConsumer *CreateDeclContextPrinter();
+// RecordLayout dumper: prints out the record layout information for all records
+// in the translation unit; this is intended for debugging.
+ASTConsumer *CreateRecordLayoutDumper();
+
// 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,
+ASTConsumer *CreateObjCRewriter(const std::string &InFile,
+ llvm::raw_ostream *OS,
Diagnostic &Diags,
const LangOptions &LOpts,
bool SilenceRewriteMacroWarning);
@@ -92,7 +95,8 @@ ASTConsumer* CreateHTMLPrinter(llvm::raw_ostream *OS, Diagnostic &D,
// used later with the PCHReader (clang-cc option -include-pch)
// to speed up compile times.
ASTConsumer *CreatePCHGenerator(const Preprocessor &PP,
- llvm::raw_ostream *OS);
+ llvm::raw_ostream *OS,
+ const char *isysroot = 0);
// Block rewriter: rewrites code using the Apple blocks extension to pure
// C code. Output is always sent to stdout.
diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h
index 68c06f5..89eb3b8 100644
--- a/include/clang/Frontend/ASTUnit.h
+++ b/include/clang/Frontend/ASTUnit.h
@@ -14,6 +14,7 @@
#ifndef LLVM_CLANG_FRONTEND_ASTUNIT_H
#define LLVM_CLANG_FRONTEND_ASTUNIT_H
+#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/OwningPtr.h"
#include <string>
@@ -21,7 +22,6 @@ namespace clang {
class FileManager;
class FileEntry;
class SourceManager;
- class DiagnosticClient;
class Diagnostic;
class HeaderSearch;
class TargetInfo;
@@ -32,40 +32,49 @@ namespace clang {
/// \brief Utility class for loading a ASTContext from a PCH file.
///
class ASTUnit {
- llvm::OwningPtr<SourceManager> SourceMgr;
- llvm::OwningPtr<DiagnosticClient> DiagClient;
- llvm::OwningPtr<Diagnostic> Diags;
+ Diagnostic &Diags;
+ SourceManager SourceMgr;
llvm::OwningPtr<HeaderSearch> HeaderInfo;
llvm::OwningPtr<TargetInfo> Target;
llvm::OwningPtr<Preprocessor> PP;
llvm::OwningPtr<ASTContext> Ctx;
- ASTUnit(const ASTUnit&); // do not implement
- ASTUnit &operator=(const ASTUnit &); // do not implement
- ASTUnit();
-
+ ASTUnit(const ASTUnit&); // DO NOT IMPLEMENT
+ ASTUnit &operator=(const ASTUnit &); // DO NOT IMPLEMENT
+ ASTUnit(Diagnostic &_Diag);
+
public:
~ASTUnit();
- const SourceManager &getSourceManager() const { return *SourceMgr.get(); }
- SourceManager &getSourceManager() { return *SourceMgr.get(); }
+ const SourceManager &getSourceManager() const { return SourceMgr; }
+ SourceManager &getSourceManager() { return SourceMgr; }
const Preprocessor &getPreprocessor() const { return *PP.get(); }
Preprocessor &getPreprocessor() { return *PP.get(); }
-
+
const ASTContext &getASTContext() const { return *Ctx.get(); }
ASTContext &getASTContext() { return *Ctx.get(); }
+ const Diagnostic &getDiagnostic() const { return Diags; }
+ Diagnostic &getDiagnostic() { return Diags; }
+
+ FileManager &getFileManager();
+ const std::string &getOriginalSourceFileName();
+
/// \brief Create a ASTUnit from a PCH file.
///
- /// \param Filename PCH filename
+ /// \param Filename - The PCH file to load.
+ ///
+ /// \param Diags - The Diagnostic implementation to use.
///
- /// \param FileMgr The FileManager to use
+ /// \param FileMgr - The FileManager to use.
///
- /// \param ErrMsg Error message to report if the PCH file could not be loaded
+ /// \param ErrMsg - Error message to report if the PCH file could not be
+ /// loaded.
///
- /// \returns the initialized ASTUnit or NULL if the PCH failed to load
+ /// \returns - The initialized ASTUnit or null if the PCH failed to load.
static ASTUnit *LoadFromPCHFile(const std::string &Filename,
+ Diagnostic &Diags,
FileManager &FileMgr,
std::string *ErrMsg = 0);
};
diff --git a/include/clang/Frontend/Analyses.def b/include/clang/Frontend/Analyses.def
index ad799c3..d5e4080 100644
--- a/include/clang/Frontend/Analyses.def
+++ b/include/clang/Frontend/Analyses.def
@@ -24,6 +24,10 @@ ANALYSIS(CFGView, "cfg-view",
ANALYSIS(DisplayLiveVariables, "dump-live-variables",
"Print results of live variable analysis", Code)
+ANALYSIS(SecuritySyntacticChecks, "warn-security-syntactic",
+ "Perform quick security checks that require no data flow",
+ Code)
+
ANALYSIS(WarnDeadStores, "warn-dead-stores",
"Warn about stores to dead variables", Code)
@@ -44,6 +48,10 @@ ANALYSIS(WarnObjCUnusedIvars, "warn-objc-unused-ivars",
ANALYSIS(CheckerCFRef, "checker-cfref",
"Run the [Core] Foundation reference count checker", Code)
+ANALYSIS(InlineCall, "inline-call",
+ "Experimental transfer function inling callees when its definition"
+ " is available.", TranslationUnit)
+
#ifndef ANALYSIS_STORE
#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN)
#endif
@@ -64,6 +72,7 @@ ANALYSIS_CONSTRAINTS(RangeConstraints, "range", "Use constraint tracking of conc
ANALYSIS_DIAGNOSTICS(HTML, "html", "Output analysis results using HTML", CreateHTMLDiagnosticClient, false)
ANALYSIS_DIAGNOSTICS(PLIST, "plist", "Output analysis results using Plists", CreatePlistDiagnosticClient, true)
+ANALYSIS_DIAGNOSTICS(PLIST_HTML, "plist-html", "Output analysis results using HTML wrapped with Plists", CreatePlistHTMLDiagnosticClient, true)
#undef ANALYSIS
#undef ANALYSIS_STORE
diff --git a/include/clang/Frontend/CommandLineSourceLoc.h b/include/clang/Frontend/CommandLineSourceLoc.h
index 1eaa958..59f70ed 100644
--- a/include/clang/Frontend/CommandLineSourceLoc.h
+++ b/include/clang/Frontend/CommandLineSourceLoc.h
@@ -34,46 +34,45 @@ namespace llvm {
///
/// Source locations are of the form filename:line:column.
template<>
- class parser<clang::ParsedSourceLocation>
+ class parser<clang::ParsedSourceLocation>
: public basic_parser<clang::ParsedSourceLocation> {
public:
- bool parse(Option &O, const char *ArgName,
- const std::string &ArgValue,
+ bool parse(Option &O, StringRef ArgName, StringRef ArgValue,
clang::ParsedSourceLocation &Val);
};
- bool
+ bool
parser<clang::ParsedSourceLocation>::
- parse(Option &O, const char *ArgName, const std::string &ArgValue,
+ parse(Option &O, StringRef ArgName, StringRef ArgValue,
clang::ParsedSourceLocation &Val) {
using namespace clang;
- const char *ExpectedFormat
+ const char *ExpectedFormat
= "source location must be of the form filename:line:column";
- std::string::size_type SecondColon = ArgValue.rfind(':');
+ StringRef::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()) {
+
+ unsigned Column;
+ if (ArgValue.substr(SecondColon + 1).getAsInteger(10, Column)) {
std::fprintf(stderr, "%s\n", ExpectedFormat);
return true;
}
+ ArgValue = ArgValue.substr(0, SecondColon);
- std::string::size_type FirstColon = ArgValue.rfind(':', SecondColon-1);
+ StringRef::size_type FirstColon = ArgValue.rfind(':');
if (FirstColon == 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) {
+ unsigned Line;
+ if (ArgValue.substr(FirstColon + 1).getAsInteger(10, Line)) {
std::fprintf(stderr, "%s\n", ExpectedFormat);
return true;
}
-
+
Val.FileName = ArgValue.substr(0, FirstColon);
Val.Line = Line;
Val.Column = Column;
diff --git a/include/clang/Frontend/CompileOptions.h b/include/clang/Frontend/CompileOptions.h
index 75dec00..508af53 100644
--- a/include/clang/Frontend/CompileOptions.h
+++ b/include/clang/Frontend/CompileOptions.h
@@ -67,7 +67,7 @@ public:
Inlining = NoInlining;
DisableRedZone = 0;
NoImplicitFloat = 0;
- }
+ }
};
} // end namespace clang
diff --git a/include/clang/Frontend/DeclXML.def b/include/clang/Frontend/DeclXML.def
index 956d971..36323c2 100644
--- a/include/clang/Frontend/DeclXML.def
+++ b/include/clang/Frontend/DeclXML.def
@@ -91,8 +91,8 @@ NODE_XML(FunctionDecl, "Function")
ATTRIBUTE_FILE_LOCATION_XML
ATTRIBUTE_XML(getDeclContext(), "context")
ATTRIBUTE_XML(getNameAsString(), "name")
- TYPE_ATTRIBUTE_XML(getType()->getAsFunctionType()->getResultType())
- ATTRIBUTE_XML(getType()->getAsFunctionType(), "function_type")
+ TYPE_ATTRIBUTE_XML(getType()->getAs<FunctionType>()->getResultType())
+ ATTRIBUTE_XML(getType()->getAs<FunctionType>(), "function_type")
ATTRIBUTE_ENUM_OPT_XML(getStorageClass(), "storage_class")
ENUM_XML(FunctionDecl::None, "")
ENUM_XML(FunctionDecl::Extern, "extern")
@@ -111,8 +111,8 @@ NODE_XML(CXXMethodDecl, "CXXMethodDecl")
ATTRIBUTE_FILE_LOCATION_XML
ATTRIBUTE_XML(getDeclContext(), "context")
ATTRIBUTE_XML(getNameAsString(), "name")
- TYPE_ATTRIBUTE_XML(getType()->getAsFunctionType()->getResultType())
- ATTRIBUTE_XML(getType()->getAsFunctionType(), "function_type")
+ TYPE_ATTRIBUTE_XML(getType()->getAs<FunctionType>()->getResultType())
+ ATTRIBUTE_XML(getType()->getAs<FunctionType>(), "function_type")
ATTRIBUTE_OPT_XML(isInline(), "inline")
ATTRIBUTE_OPT_XML(isStatic(), "static")
ATTRIBUTE_OPT_XML(isVirtual(), "virtual")
diff --git a/include/clang/Frontend/DocumentXML.h b/include/clang/Frontend/DocumentXML.h
index 4ed11e1..6693ddb 100644
--- a/include/clang/Frontend/DocumentXML.h
+++ b/include/clang/Frontend/DocumentXML.h
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This file implements the XML document class, which provides the means to
+// 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.
//
//===----------------------------------------------------------------------===//
@@ -32,10 +32,9 @@ class NamedDecl;
class FunctionDecl;
class ASTContext;
class LabelStmt;
-
-//---------------------------------------------------------
-namespace XML
-{
+
+//---------------------------------------------------------
+namespace XML {
// id maps:
template<class T>
struct IdMap : llvm::DenseMap<T, unsigned> {};
@@ -47,9 +46,8 @@ namespace XML
struct IdMap<std::string> : std::map<std::string, unsigned> {};
}
-//---------------------------------------------------------
-class DocumentXML
-{
+//---------------------------------------------------------
+class DocumentXML {
public:
DocumentXML(const std::string& rootName, llvm::raw_ostream& out);
@@ -62,24 +60,22 @@ public:
DocumentXML& addSubNode(const std::string& name); // also enters the sub node, returns *this
DocumentXML& toParent(); // returns *this
- void addAttribute(const char* pName, const QualType& pType);
+ void addAttribute(const char* pName, const QualType& pType);
void addAttribute(const char* pName, bool value);
template<class T>
- void addAttribute(const char* pName, const T* value)
- {
+ void addAttribute(const char* pName, const T* value) {
addPtrAttribute(pName, value);
}
template<class T>
- void addAttribute(const char* pName, T* value)
- {
+ void addAttribute(const char* pName, T* value) {
addPtrAttribute(pName, value);
}
template<class T>
void addAttribute(const char* pName, const T& value);
-
+
template<class T>
void addAttributeOptional(const char* pName, const T& value);
@@ -114,7 +110,7 @@ private:
void Indent();
// forced pointer dispatch:
- void addPtrAttribute(const char* pName, const Type* pType);
+ void addPtrAttribute(const char* pName, const Type* pType);
void addPtrAttribute(const char* pName, const NamedDecl* D);
void addPtrAttribute(const char* pName, const DeclContext* D);
void addPtrAttribute(const char* pName, const NamespaceDecl* D); // disambiguation
@@ -136,47 +132,43 @@ private:
// for addAttributeOptional:
static bool isDefault(unsigned value) { return value == 0; }
static bool isDefault(bool value) { return !value; }
+ static bool isDefault(Qualifiers::GC value) { return value == Qualifiers::GCNone; }
static bool isDefault(const std::string& value) { return value.empty(); }
};
//--------------------------------------------------------- inlines
-inline void DocumentXML::initialize(ASTContext &Context)
-{
- Ctx = &Context;
+inline void DocumentXML::initialize(ASTContext &Context) {
+ Ctx = &Context;
}
-//---------------------------------------------------------
+//---------------------------------------------------------
template<class T>
-inline void DocumentXML::addAttribute(const char* pName, const T& value)
-{
+inline void DocumentXML::addAttribute(const char* pName, const T& value) {
Out << ' ' << pName << "=\"" << value << "\"";
}
-//---------------------------------------------------------
-inline void DocumentXML::addPtrAttribute(const char* pName, const char* text)
-{
+//---------------------------------------------------------
+inline void DocumentXML::addPtrAttribute(const char* pName, const char* text) {
Out << ' ' << pName << "=\"" << text << "\"";
}
-//---------------------------------------------------------
-inline void DocumentXML::addAttribute(const char* pName, bool value)
-{
+//---------------------------------------------------------
+inline void DocumentXML::addAttribute(const char* pName, bool value) {
addPtrAttribute(pName, value ? "1" : "0");
}
-//---------------------------------------------------------
+//---------------------------------------------------------
template<class T>
-inline void DocumentXML::addAttributeOptional(const char* pName, const T& value)
-{
- if (!isDefault(value))
- {
+inline void DocumentXML::addAttributeOptional(const char* pName,
+ const T& value) {
+ if (!isDefault(value)) {
addAttribute(pName, value);
}
}
-//---------------------------------------------------------
+//---------------------------------------------------------
-} //namespace clang
+} //namespace clang
#endif //LLVM_CLANG_DOCUMENTXML_H
diff --git a/include/clang/Frontend/FixItRewriter.h b/include/clang/Frontend/FixItRewriter.h
index 7fcd682..fac87af 100644
--- a/include/clang/Frontend/FixItRewriter.h
+++ b/include/clang/Frontend/FixItRewriter.h
@@ -51,7 +51,7 @@ class FixItRewriter : public DiagnosticClient {
unsigned NumFailures;
/// \brief Locations at which we should perform fix-its.
- ///
+ ///
/// When empty, perform fix-it modifications everywhere.
llvm::SmallVector<RequestedSourceLocation, 4> FixItLocations;
@@ -72,7 +72,7 @@ public:
/// \brief Write the modified source file.
///
/// \returns true if there was an error, false otherwise.
- bool WriteFixedFile(const std::string &InFileName,
+ bool WriteFixedFile(const std::string &InFileName,
const std::string &OutFileName = std::string());
/// IncludeInDiagnosticCounts - This method (whose default implementation
diff --git a/include/clang/Frontend/FrontendDiagnostic.h b/include/clang/Frontend/FrontendDiagnostic.h
index 079abae..a044586 100644
--- a/include/clang/Frontend/FrontendDiagnostic.h
+++ b/include/clang/Frontend/FrontendDiagnostic.h
@@ -13,7 +13,7 @@
#include "clang/Basic/Diagnostic.h"
namespace clang {
- namespace diag {
+ namespace diag {
enum {
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE) ENUM,
#define FRONTENDSTART
diff --git a/include/clang/Frontend/InitHeaderSearch.h b/include/clang/Frontend/InitHeaderSearch.h
index 5151666..a90b4ea 100644
--- a/include/clang/Frontend/InitHeaderSearch.h
+++ b/include/clang/Frontend/InitHeaderSearch.h
@@ -14,11 +14,12 @@
#ifndef LLVM_CLANG_FRONTEND_INIT_HEADER_SEARCH_H_
#define LLVM_CLANG_FRONTEND_INIT_HEADER_SEARCH_H_
+#include "clang/Lex/DirectoryLookup.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Triple.h"
#include <string>
#include <vector>
-#include "clang/Lex/DirectoryLookup.h"
-
namespace clang {
class HeaderSearch;
@@ -48,7 +49,7 @@ public:
: Headers(HS), Verbose(verbose), isysroot(iSysroot) {}
/// AddPath - Add the specified path to the specified group list.
- void AddPath(const std::string &Path, IncludeDirGroup Group,
+ void AddPath(const llvm::StringRef &Path, IncludeDirGroup Group,
bool isCXXAware, bool isUserSupplied,
bool isFramework, bool IgnoreSysRoot = false);
@@ -56,13 +57,26 @@ public:
/// header search list.
void AddEnvVarPaths(const char *Name);
+ /// AddGnuCPlusPlusIncludePaths - Add the necessary paths to suport a gnu
+ /// libstdc++.
+ void AddGnuCPlusPlusIncludePaths(const std::string &Base, const char *Dir32,
+ const char *Dir64,
+ const llvm::Triple &triple);
+
+ /// AddMinGWCPlusPlusIncludePaths - Add the necessary paths to suport a MinGW
+ /// libstdc++.
+ void AddMinGWCPlusPlusIncludePaths(const std::string &Base,
+ const char *Arch,
+ const char *Version);
+
/// 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);
+ void AddDefaultSystemIncludePaths(const LangOptions &Lang,
+ const llvm::Triple &triple);
/// Realize - Merges all search path lists into one list and send it to
/// HeaderSearch.
diff --git a/include/clang/Frontend/ManagerRegistry.h b/include/clang/Frontend/ManagerRegistry.h
index ecab67a..f05cfe6 100644
--- a/include/clang/Frontend/ManagerRegistry.h
+++ b/include/clang/Frontend/ManagerRegistry.h
@@ -43,7 +43,7 @@ public:
class RegisterConstraintManager {
public:
RegisterConstraintManager(ConstraintManagerCreator CMC) {
- assert(ManagerRegistry::ConstraintMgrCreator == 0
+ assert(ManagerRegistry::ConstraintMgrCreator == 0
&& "ConstraintMgrCreator already set!");
ManagerRegistry::ConstraintMgrCreator = CMC;
}
diff --git a/include/clang/Frontend/PCHBitCodes.h b/include/clang/Frontend/PCHBitCodes.h
index 80aa248..716780e 100644
--- a/include/clang/Frontend/PCHBitCodes.h
+++ b/include/clang/Frontend/PCHBitCodes.h
@@ -29,7 +29,11 @@ namespace clang {
/// 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;
+ ///
+ /// Version 3 of PCH files also requires that the Subversion branch and
+ /// revision match exactly, since there is no backward compatibility of
+ /// PCH files at this time.
+ const unsigned VERSION_MAJOR = 3;
/// \brief PCH minor version number supported by this version of
/// Clang.
@@ -65,7 +69,7 @@ namespace clang {
typedef uint32_t IdentID;
typedef uint32_t SelectorID;
-
+
/// \brief Describes the various kinds of blocks that occur within
/// a PCH file.
enum BlockIDs {
@@ -106,7 +110,7 @@ namespace clang {
/// 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
@@ -182,7 +186,7 @@ namespace clang {
/// \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,
@@ -212,17 +216,17 @@ namespace clang {
/// \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,
-
+ ORIGINAL_FILE_NAME = 19,
+
/// \brief Record code for the sorted array of source ranges where
/// comments were encountered in the source code.
- COMMENT_RANGES = 21
+ COMMENT_RANGES = 20,
+
+ /// \brief Record code for the Subversion branch and revision information
+ /// of the compiler used to build this PCH file.
+ SVN_BRANCH_REVISION = 21
};
/// \brief Record types used within a source manager block.
@@ -247,7 +251,7 @@ namespace clang {
/// 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
@@ -261,7 +265,7 @@ namespace clang {
/// [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
@@ -329,7 +333,15 @@ namespace clang {
/// \brief The '__int128_t' type.
PREDEF_TYPE_INT128_ID = 22,
/// \brief The type of 'nullptr'.
- PREDEF_TYPE_NULLPTR_ID = 23
+ PREDEF_TYPE_NULLPTR_ID = 23,
+ /// \brief The C++ 'char16_t' type.
+ PREDEF_TYPE_CHAR16_ID = 24,
+ /// \brief The C++ 'char32_t' type.
+ PREDEF_TYPE_CHAR32_ID = 25,
+ /// \brief The ObjC 'id' type.
+ PREDEF_TYPE_OBJC_ID = 26,
+ /// \brief The ObjC 'Class' type.
+ PREDEF_TYPE_OBJC_CLASS = 27
};
/// \brief The number of predefined type IDs that are reserved for
@@ -388,12 +400,18 @@ namespace clang {
TYPE_ENUM = 20,
/// \brief An ObjCInterfaceType record.
TYPE_OBJC_INTERFACE = 21,
- /// \brief An ObjCQualifiedInterfaceType record.
- TYPE_OBJC_QUALIFIED_INTERFACE = 22,
/// \brief An ObjCObjectPointerType record.
- TYPE_OBJC_OBJECT_POINTER = 23,
+ TYPE_OBJC_OBJECT_POINTER = 22,
+ /// \brief An ObjCProtocolListType record.
+ TYPE_OBJC_PROTOCOL_LIST = 23,
/// \brief a DecltypeType record.
- TYPE_DECLTYPE = 24
+ TYPE_DECLTYPE = 24,
+ /// \brief A ConstantArrayWithExprType record.
+ TYPE_CONSTANT_ARRAY_WITH_EXPR = 25,
+ /// \brief A ConstantArrayWithoutExprType record.
+ TYPE_CONSTANT_ARRAY_WITHOUT_EXPR = 26,
+ /// \brief An ElaboratedType record.
+ TYPE_ELABORATED = 27
};
/// \brief The type IDs for special types constructed by semantic
@@ -415,7 +433,17 @@ namespace clang {
/// \brief CFConstantString type
SPECIAL_TYPE_CF_CONSTANT_STRING = 5,
/// \brief Objective-C fast enumeration state type
- SPECIAL_TYPE_OBJC_FAST_ENUMERATION_STATE = 6
+ SPECIAL_TYPE_OBJC_FAST_ENUMERATION_STATE = 6,
+ /// \brief C FILE typedef type
+ SPECIAL_TYPE_FILE = 7,
+ /// \brief C jmp_buf typedef type
+ SPECIAL_TYPE_jmp_buf = 8,
+ /// \brief C sigjmp_buf typedef type
+ SPECIAL_TYPE_sigjmp_buf = 9,
+ /// \brief Objective-C "id" redefinition type
+ SPECIAL_TYPE_OBJC_ID_REDEFINITION = 10,
+ /// \brief Objective-C "Class" redefinition type
+ SPECIAL_TYPE_OBJC_CLASS_REDEFINITION = 11
};
/// \brief Record codes for each kind of declaration.
@@ -611,7 +639,7 @@ namespace clang {
EXPR_BLOCK_DECL_REF,
// Objective-C
-
+
/// \brief An ObjCStringLiteral record.
EXPR_OBJC_STRING_LITERAL,
/// \brief An ObjCEncodeExpr record.
@@ -624,25 +652,34 @@ namespace clang {
EXPR_OBJC_IVAR_REF_EXPR,
/// \brief An ObjCPropertyRefExpr record.
EXPR_OBJC_PROPERTY_REF_EXPR,
- /// \brief An ObjCKVCRefExpr record.
+ /// \brief An ObjCImplicitSetterGetterRefExpr record.
EXPR_OBJC_KVC_REF_EXPR,
/// \brief An ObjCMessageExpr record.
EXPR_OBJC_MESSAGE_EXPR,
/// \brief An ObjCSuperExpr record.
EXPR_OBJC_SUPER_EXPR,
+ /// \brief An ObjCIsa Expr record.
+ EXPR_OBJC_ISA,
- /// \brief An ObjCForCollectionStmt record.
+ /// \brief An ObjCForCollectionStmt record.
STMT_OBJC_FOR_COLLECTION,
- /// \brief An ObjCAtCatchStmt record.
+ /// \brief An ObjCAtCatchStmt record.
STMT_OBJC_CATCH,
- /// \brief An ObjCAtFinallyStmt record.
+ /// \brief An ObjCAtFinallyStmt record.
STMT_OBJC_FINALLY,
- /// \brief An ObjCAtTryStmt record.
+ /// \brief An ObjCAtTryStmt record.
STMT_OBJC_AT_TRY,
- /// \brief An ObjCAtSynchronizedStmt record.
+ /// \brief An ObjCAtSynchronizedStmt record.
STMT_OBJC_AT_SYNCHRONIZED,
- /// \brief An ObjCAtThrowStmt record.
- STMT_OBJC_AT_THROW
+ /// \brief An ObjCAtThrowStmt record.
+ STMT_OBJC_AT_THROW,
+
+ // C++
+
+ /// \brief A CXXOperatorCallExpr record.
+ EXPR_CXX_OPERATOR_CALL,
+ /// \brief A CXXConstructExpr record.
+ EXPR_CXX_CONSTRUCT
};
/// \brief The kinds of designators that can occur in a
diff --git a/include/clang/Frontend/PCHReader.h b/include/clang/Frontend/PCHReader.h
index 8291f46..1230e37 100644
--- a/include/clang/Frontend/PCHReader.h
+++ b/include/clang/Frontend/PCHReader.h
@@ -30,6 +30,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/Bitcode/BitstreamReader.h"
#include "llvm/Support/DataTypes.h"
+#include <deque>
#include <map>
#include <string>
#include <utility>
@@ -54,7 +55,7 @@ class Preprocessor;
class Sema;
class SwitchCase;
class PCHReader;
-class HeaderFileInfo;
+struct HeaderFileInfo;
/// \brief Abstract interface for callback invocations by the PCHReader.
///
@@ -65,21 +66,21 @@ class HeaderFileInfo;
class PCHReaderListener {
public:
virtual ~PCHReaderListener();
-
+
/// \brief Receives the language options.
///
/// \returns true to indicate the options are invalid or false otherwise.
virtual bool ReadLanguageOptions(const LangOptions &LangOpts) {
return false;
}
-
+
/// \brief Receives the target triple.
///
/// \returns true to indicate the target triple is invalid or false otherwise.
virtual bool ReadTargetTriple(const std::string &Triple) {
return false;
}
-
+
/// \brief Receives the contents of the predefines buffer.
///
/// \param PCHPredef The start of the predefines buffer in the PCH
@@ -94,16 +95,16 @@ public:
/// here.
///
/// \returns true to indicate the predefines are invalid or false otherwise.
- virtual bool ReadPredefinesBuffer(const char *PCHPredef,
+ virtual bool ReadPredefinesBuffer(const char *PCHPredef,
unsigned PCHPredefLen,
FileID PCHBufferID,
std::string &SuggestedPredefines) {
return false;
}
-
+
/// \brief Receives a HeaderFileInfo entry.
virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI) {}
-
+
/// \brief Receives __COUNTER__ value.
virtual void ReadCounter(unsigned Value) {}
};
@@ -113,16 +114,16 @@ public:
class PCHValidator : public PCHReaderListener {
Preprocessor &PP;
PCHReader &Reader;
-
+
unsigned NumHeaderInfos;
-
+
public:
PCHValidator(Preprocessor &PP, PCHReader &Reader)
: PP(PP), Reader(Reader), NumHeaderInfos(0) {}
-
+
virtual bool ReadLanguageOptions(const LangOptions &LangOpts);
virtual bool ReadTargetTriple(const std::string &Triple);
- virtual bool ReadPredefinesBuffer(const char *PCHPredef,
+ virtual bool ReadPredefinesBuffer(const char *PCHPredef,
unsigned PCHPredefLen,
FileID PCHBufferID,
std::string &SuggestedPredefines);
@@ -142,8 +143,8 @@ public:
/// 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,
+class PCHReader
+ : public ExternalSemaSource,
public IdentifierInfoLookup,
public ExternalIdentifierLookup,
public ExternalSLocEntrySource {
@@ -153,11 +154,11 @@ public:
private:
/// \ brief The receiver of some callbacks invoked by PCHReader.
llvm::OwningPtr<PCHReaderListener> Listener;
-
+
SourceManager &SourceMgr;
FileManager &FileMgr;
Diagnostic &Diags;
-
+
/// \brief The semantic analysis object that will be processing the
/// PCH file and the translation unit that uses it.
Sema *SemaObj;
@@ -202,10 +203,10 @@ private:
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
+ ///
+ /// 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;
+ std::vector<QualType> TypesLoaded;
/// \brief Offset of each declaration within the bitstream, indexed
/// by the declaration ID (-1).
@@ -272,7 +273,7 @@ private:
/// \brief The total number of selectors stored in the PCH file.
unsigned TotalNumSelectors;
- /// \brief A vector containing selectors that have already been loaded.
+ /// \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
@@ -281,10 +282,10 @@ private:
/// \brief A sorted array of source ranges containing comments.
SourceRange *Comments;
-
+
/// \brief The number of source ranges in the Comments array.
unsigned NumComments;
-
+
/// \brief The set of external definitions stored in the the PCH
/// file.
llvm::SmallVector<uint64_t, 16> ExternalDefinitions;
@@ -309,6 +310,13 @@ private:
/// file.
std::string OriginalFileName;
+ /// \brief Whether this precompiled header is a relocatable PCH file.
+ bool RelocatablePCH;
+
+ /// \brief The system include root to be used when loading the
+ /// precompiled header.
+ const char *isysroot;
+
/// \brief Mapping from switch-case IDs in the PCH file to
/// switch-case statements.
std::map<unsigned, SwitchCase *> SwitchCaseStmts;
@@ -362,6 +370,40 @@ private:
/// Number of visible decl contexts read/total.
unsigned NumVisibleDeclContextsRead, TotalVisibleDeclContexts;
+ /// \brief When a type or declaration is being loaded from the PCH file, an
+ /// instantance of this RAII object will be available on the stack to
+ /// indicate when we are in a recursive-loading situation.
+ class LoadingTypeOrDecl {
+ PCHReader &Reader;
+ LoadingTypeOrDecl *Parent;
+
+ LoadingTypeOrDecl(const LoadingTypeOrDecl&); // do not implement
+ LoadingTypeOrDecl &operator=(const LoadingTypeOrDecl&); // do not implement
+
+ public:
+ explicit LoadingTypeOrDecl(PCHReader &Reader);
+ ~LoadingTypeOrDecl();
+ };
+ friend class LoadingTypeOrDecl;
+
+ /// \brief If we are currently loading a type or declaration, points to the
+ /// most recent LoadingTypeOrDecl object on the stack.
+ LoadingTypeOrDecl *CurrentlyLoadingTypeOrDecl;
+
+ /// \brief An IdentifierInfo that has been loaded but whose top-level
+ /// declarations of the same name have not (yet) been loaded.
+ struct PendingIdentifierInfo {
+ IdentifierInfo *II;
+ llvm::SmallVector<uint32_t, 4> DeclIDs;
+ };
+
+ /// \brief The set of identifiers that were read while the PCH reader was
+ /// (recursively) loading declarations.
+ ///
+ /// The declarations on the identifier chain for these identifiers will be
+ /// loaded once the recursive loading has completed.
+ std::deque<PendingIdentifierInfo> PendingIdentifierInfos;
+
/// \brief FIXME: document!
llvm::SmallVector<uint64_t, 4> SpecialTypes;
@@ -392,14 +434,17 @@ private:
/// there are differences that the PCH reader can work around, this
/// predefines buffer may contain additional definitions.
std::string SuggestedPredefines;
-
+
+ void MaybeAddSystemRootToFilename(std::string &Filename);
+
PCHReadResult ReadPCHBlock();
- bool CheckPredefinesBuffer(const char *PCHPredef,
+ bool CheckPredefinesBuffer(const char *PCHPredef,
unsigned PCHPredefLen,
FileID PCHBufferID);
+ bool ParseLineTable(llvm::SmallVectorImpl<uint64_t> &Record);
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);
@@ -413,39 +458,62 @@ private:
PCHReader(const PCHReader&); // do not implement
PCHReader &operator=(const PCHReader &); // do not implement
-
public:
typedef llvm::SmallVector<uint64_t, 64> RecordData;
/// \brief Load the PCH file and validate its contents against the given
/// Preprocessor.
- PCHReader(Preprocessor &PP, ASTContext *Context);
-
+ ///
+ /// \param PP the preprocessor associated with the context in which this
+ /// precompiled header will be loaded.
+ ///
+ /// \param Context the AST context that this precompiled header will be
+ /// loaded into.
+ ///
+ /// \param isysroot If non-NULL, the system include path specified by the
+ /// user. This is only used with relocatable PCH files. If non-NULL,
+ /// a relocatable PCH file will use the default path "/".
+ PCHReader(Preprocessor &PP, ASTContext *Context, const char *isysroot = 0);
+
/// \brief Load the PCH file without using any pre-initialized Preprocessor.
///
/// The necessary information to initialize a Preprocessor later can be
/// obtained by setting a PCHReaderListener.
- PCHReader(SourceManager &SourceMgr, FileManager &FileMgr, Diagnostic &Diags);
+ ///
+ /// \param SourceMgr the source manager into which the precompiled header
+ /// will be loaded.
+ ///
+ /// \param FileMgr the file manager into which the precompiled header will
+ /// be loaded.
+ ///
+ /// \param Diags the diagnostics system to use for reporting errors and
+ /// warnings relevant to loading the precompiled header.
+ ///
+ /// \param isysroot If non-NULL, the system include path specified by the
+ /// user. This is only used with relocatable PCH files. If non-NULL,
+ /// a relocatable PCH file will use the default path "/".
+ PCHReader(SourceManager &SourceMgr, FileManager &FileMgr,
+ Diagnostic &Diags, const char *isysroot = 0);
~PCHReader();
/// \brief Load the precompiled header designated by the given file
/// name.
PCHReadResult ReadPCH(const std::string &FileName);
-
+
/// \brief Set the PCH callbacks listener.
void setListener(PCHReaderListener *listener) {
Listener.reset(listener);
}
-
+
/// \brief Set the Preprocessor to use.
void setPreprocessor(Preprocessor &pp) {
PP = &pp;
}
-
+
/// \brief Sets and initializes the given Context.
void InitializeContext(ASTContext &Context);
- /// \brief Retrieve the name of the original source file name
+ /// \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
@@ -465,7 +533,7 @@ public:
/// replaced with the sorted set of source ranges corresponding to
/// comments in the source code.
virtual void ReadComments(std::vector<SourceRange> &Comments);
-
+
/// \brief Resolve a type ID into a type, potentially building a new
/// type.
virtual QualType GetType(pch::TypeID ID);
@@ -551,10 +619,13 @@ public:
///
/// \returns a pair of Objective-C methods lists containing the
/// instance and factory methods, respectively, with this selector.
- virtual std::pair<ObjCMethodList, ObjCMethodList>
+ virtual std::pair<ObjCMethodList, ObjCMethodList>
ReadMethodPool(Selector Sel);
void SetIdentifierInfo(unsigned ID, IdentifierInfo *II);
+ void SetGloballyVisibleDecls(IdentifierInfo *II,
+ const llvm::SmallVectorImpl<uint32_t> &DeclIDs,
+ bool Nonrecursive = false);
/// \brief Report a diagnostic.
DiagnosticBuilder Diag(unsigned DiagID);
@@ -563,11 +634,11 @@ public:
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);
}
@@ -576,7 +647,7 @@ public:
virtual void ReadSLocEntry(unsigned ID);
Selector DecodeSelector(unsigned Idx);
-
+
Selector GetSelector(const RecordData &Record, unsigned &Idx) {
return DecodeSelector(Record[Idx++]);
}
@@ -599,13 +670,13 @@ public:
/// \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);
@@ -670,16 +741,16 @@ public:
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
index c663442..a807cd7 100644
--- a/include/clang/Frontend/PCHWriter.h
+++ b/include/clang/Frontend/PCHWriter.h
@@ -40,6 +40,24 @@ class SourceManager;
class SwitchCase;
class TargetInfo;
+/// A structure for putting "fast"-unqualified QualTypes into a
+/// DenseMap. This uses the standard pointer hash function.
+struct UnsafeQualTypeDenseMapInfo {
+ static inline bool isEqual(QualType A, QualType B) { return A == B; }
+ static inline bool isPod() { return true; }
+ static inline QualType getEmptyKey() {
+ return QualType::getFromOpaquePtr((void*) 1);
+ }
+ static inline QualType getTombstoneKey() {
+ return QualType::getFromOpaquePtr((void*) 2);
+ }
+ static inline unsigned getHashValue(QualType T) {
+ assert(!T.getFastQualifiers() && "hash invalid for types with fast quals");
+ uintptr_t v = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
+ return (unsigned(v) >> 4) ^ (unsigned(v) >> 9);
+ }
+};
+
/// \brief Writes a precompiled header containing the contents of a
/// translation unit.
///
@@ -76,9 +94,11 @@ private:
///
/// 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;
+ /// stored in the stream, the ID number is shifted by 2 bits to
+ /// allow for the const/volatile qualifiers.
+ ///
+ /// Keys in the map never have const/volatile qualifiers.
+ llvm::DenseMap<QualType, pch::TypeID, UnsafeQualTypeDenseMapInfo> TypeIDs;
/// \brief Offset of each type in the bitstream, indexed by
/// the type's ID.
@@ -89,7 +109,7 @@ private:
/// \brief Queue containing the types that we still need to
/// emit.
- std::queue<const Type *> TypesToEmit;
+ std::queue<QualType> TypesToEmit;
/// \brief Map that provides the ID numbers of each identifier in
/// the output stream.
@@ -98,21 +118,21 @@ private:
/// 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.
///
@@ -141,7 +161,7 @@ private:
/// \brief Mapping from SwitchCase statements to IDs.
std::map<SwitchCase *, unsigned> SwitchCaseIDs;
-
+
/// \brief Mapping from LabelStmt statements to IDs.
std::map<LabelStmt *, unsigned> LabelIDs;
@@ -160,18 +180,19 @@ private:
unsigned NumVisibleDeclContexts;
void WriteBlockInfoBlock();
- void WriteMetadata(ASTContext &Context);
+ void WriteMetadata(ASTContext &Context, const char *isysroot);
void WriteLanguageOptions(const LangOptions &LangOpts);
- void WriteStatCache(MemorizeStatCalls &StatCalls);
- void WriteSourceManagerBlock(SourceManager &SourceMgr,
- const Preprocessor &PP);
+ void WriteStatCache(MemorizeStatCalls &StatCalls, const char* isysroot);
+ void WriteSourceManagerBlock(SourceManager &SourceMgr,
+ const Preprocessor &PP,
+ const char* isysroot);
void WritePreprocessor(const Preprocessor &PP);
void WriteComments(ASTContext &Context);
- void WriteType(const Type *T);
+ void WriteType(QualType 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);
@@ -179,14 +200,24 @@ private:
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);
+ ///
+ /// \param SemaRef a reference to the semantic analysis object that processed
+ /// the AST to be written into the precompiled header.
+ ///
+ /// \param StatCalls the object that cached all of the stat() calls made while
+ /// searching for source files and headers.
+ ///
+ /// \param isysroot if non-NULL, write a relocatable PCH file whose headers
+ /// are relative to the given system root.
+ void WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls,
+ const char* isysroot);
/// \brief Emit a source location.
void AddSourceLocation(SourceLocation Loc, RecordData &Record);
@@ -205,7 +236,7 @@ public:
/// \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);
@@ -215,7 +246,7 @@ public:
///
/// The identifier must refer to a macro.
uint64_t getMacroOffset(const IdentifierInfo *II) {
- assert(MacroOffsets.find(II) != MacroOffsets.end() &&
+ assert(MacroOffsets.find(II) != MacroOffsets.end() &&
"Identifier does not name a macro");
return MacroOffsets[II];
}
diff --git a/include/clang/Frontend/PathDiagnosticClients.h b/include/clang/Frontend/PathDiagnosticClients.h
index 028cd85..8cb6898 100644
--- a/include/clang/Frontend/PathDiagnosticClients.h
+++ b/include/clang/Frontend/PathDiagnosticClients.h
@@ -14,7 +14,9 @@
#ifndef LLVM_CLANG_FRONTEND_PATH_DIAGNOSTIC_CLIENTS_H
#define LLVM_CLANG_FRONTEND_PATH_DIAGNOSTIC_CLiENTS_H
+#include <memory>
#include <string>
+#include "llvm/ADT/SmallVector.h"
namespace clang {
@@ -22,13 +24,31 @@ 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);
-}
+class PathDiagnosticClientFactory {
+public:
+ PathDiagnosticClientFactory() {}
+ virtual ~PathDiagnosticClientFactory() {}
+ virtual const char *getName() const = 0;
+
+ virtual PathDiagnosticClient*
+ createPathDiagnosticClient(llvm::SmallVectorImpl<std::string> *FilesMade) = 0;
+};
+
+PathDiagnosticClient*
+CreateHTMLDiagnosticClient(const std::string& prefix, Preprocessor* PP = 0,
+ PreprocessorFactory* PPF = 0,
+ llvm::SmallVectorImpl<std::string>* FilesMade = 0);
+
+PathDiagnosticClientFactory*
+CreateHTMLDiagnosticClientFactory(const std::string& prefix,
+ Preprocessor* PP = 0,
+ PreprocessorFactory* PPF = 0);
+
+PathDiagnosticClient*
+CreatePlistDiagnosticClient(const std::string& prefix, Preprocessor* PP,
+ PreprocessorFactory* PPF,
+ PathDiagnosticClientFactory *PF = 0);
+
+} // end clang namespace
#endif
diff --git a/include/clang/Frontend/StmtXML.def b/include/clang/Frontend/StmtXML.def
index 26430f7..fd79cf0 100644
--- a/include/clang/Frontend/StmtXML.def
+++ b/include/clang/Frontend/StmtXML.def
@@ -78,6 +78,9 @@
# define CONTEXT_ATTRIBUTE_XML( FN ) ATTRIBUTE_XML(FN, "context")
#endif
+NODE_XML(Stmt, "Stmt_Unsupported") // fallback for unsupproted statements
+ ATTRIBUTE_FILE_LOCATION_XML
+END_NODE_XML
NODE_XML(NullStmt, "NullStmt")
ATTRIBUTE_FILE_LOCATION_XML
diff --git a/include/clang/Frontend/TextDiagnosticPrinter.h b/include/clang/Frontend/TextDiagnosticPrinter.h
index f8408bd..0fd8d44 100644
--- a/include/clang/Frontend/TextDiagnosticPrinter.h
+++ b/include/clang/Frontend/TextDiagnosticPrinter.h
@@ -52,7 +52,7 @@ public:
unsigned messageLength = 0,
bool useColors = false)
: OS(os), LangOpts(0),
- LastCaretDiagnosticWasNote(false), ShowColumn(showColumn),
+ LastCaretDiagnosticWasNote(false), ShowColumn(showColumn),
CaretDiagnostics(caretDiagnistics), ShowLocation(showLocation),
PrintRangeInfo(printRangeInfo),
PrintDiagnosticOption(printDiagnosticOption),
@@ -63,7 +63,7 @@ public:
void setLangOptions(const LangOptions *LO) {
LangOpts = LO;
}
-
+
void PrintIncludeStack(SourceLocation Loc, const SourceManager &SM);
void HighlightRange(const SourceRange &R,
@@ -72,13 +72,13 @@ public:
std::string &CaretLine,
const std::string &SourceLine);
- void EmitCaretDiagnostic(SourceLocation Loc,
+ 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);
};
diff --git a/include/clang/Frontend/TypeXML.def b/include/clang/Frontend/TypeXML.def
index 2a78fd9..6aca15a 100644
--- a/include/clang/Frontend/TypeXML.def
+++ b/include/clang/Frontend/TypeXML.def
@@ -68,17 +68,8 @@ NODE_XML(QualType, "CvQualifiedType")
ATTRIBUTE_OPT_XML(isConstQualified(), "const") // boolean
ATTRIBUTE_OPT_XML(isVolatileQualified(), "volatile") // boolean
ATTRIBUTE_OPT_XML(isRestrictQualified(), "restrict") // boolean
-END_NODE_XML
-
-NODE_XML(ExtQualType, "ExtQualType")
- ID_ATTRIBUTE_XML
- TYPE_ATTRIBUTE_XML(getBaseType())
- ATTRIBUTE_OPT_XML(getAddressSpace(), "adress_space") // unsigned: Address Space ID - The address space ID this type is qualified with.
- ATTRIBUTE_ENUM_OPT_XML(getObjCGCAttr(), "objc_gc") // GC __weak/__strong attributes
- ENUM_XML(QualType::GCNone, "")
- ENUM_XML(QualType::Weak, "weak")
- ENUM_XML(QualType::Strong, "strong")
- END_ENUM_XML
+ ATTRIBUTE_OPT_XML(getObjCGCAttr(), "objc_gc") // Qualifiers::GC
+ ATTRIBUTE_OPT_XML(getAddressSpace(), "address_space") // unsigned
END_NODE_XML
NODE_XML(BuiltinType, "FundamentalType")
@@ -104,6 +95,8 @@ NODE_XML(BuiltinType, "FundamentalType")
ENUM_XML(BuiltinType::Double, "double");
ENUM_XML(BuiltinType::LongDouble, "long double");
ENUM_XML(BuiltinType::WChar, "wchar_t");
+ ENUM_XML(BuiltinType::Char16, "char16_t");
+ ENUM_XML(BuiltinType::Char32, "char32_t");
ENUM_XML(BuiltinType::NullPtr, "nullptr_t"); // This is the type of C++0x 'nullptr'.
ENUM_XML(BuiltinType::Overload, "overloaded");
ENUM_XML(BuiltinType::Dependent, "dependent");
@@ -173,7 +166,7 @@ NODE_XML(ConstantArrayType, "ArrayType")
ENUM_XML(ArrayType::Static, "static")
ENUM_XML(ArrayType::Star, "star")
END_ENUM_XML
- ATTRIBUTE_OPT_XML(getIndexTypeQualifier(), "index_type_qualifier") // unsigned
+ ATTRIBUTE_OPT_XML(getIndexTypeCVRQualifiers(), "index_type_qualifier") // unsigned
END_NODE_XML
NODE_XML(IncompleteArrayType, "IncompleteArrayType")
@@ -254,10 +247,6 @@ NODE_XML(ObjCInterfaceType, "ObjCInterfaceType")
ID_ATTRIBUTE_XML
END_NODE_XML
-NODE_XML(ObjCQualifiedInterfaceType, "ObjCQualifiedInterfaceType")
- ID_ATTRIBUTE_XML
-END_NODE_XML
-
NODE_XML(ObjCObjectPointerType, "ObjCObjectPointerType")
ID_ATTRIBUTE_XML
END_NODE_XML
diff --git a/include/clang/Frontend/Utils.h b/include/clang/Frontend/Utils.h
index 77df60c..9cbcf8e 100644
--- a/include/clang/Frontend/Utils.h
+++ b/include/clang/Frontend/Utils.h
@@ -34,8 +34,6 @@ class PreprocessorFactory;
class LangOptions;
class Decl;
class Stmt;
-class ASTContext;
-class SourceLocation;
/// ProcessWarningOptions - Initialize the diagnostic client and process the
/// warning options specified on the command line.
@@ -59,7 +57,7 @@ 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,
@@ -78,33 +76,6 @@ void AttachDependencyFileGen(Preprocessor *PP, llvm::raw_ostream *OS,
/// a seekable stream.
void CacheTokens(Preprocessor& PP, llvm::raw_fd_ostream* OS);
-/// \brief Returns the AST node that a source location points to.
-///
-/// Returns a pair of Decl* and Stmt*. If no AST node is found for the source
-/// location, the pair will contain null pointers.
-///
-/// If the source location points to just a declaration, the statement part of
-/// the pair will be null, e.g.,
-/// @code
-/// int foo;
-/// @endcode
-/// If the source location points at 'foo', the pair will contain the VarDecl
-/// of foo and a null Stmt.
-///
-/// If the source location points to a statement node, the returned declaration
-/// will be the immediate 'parent' declaration of the statement node, e.g.,
-/// @code
-/// void f() {
-/// int foo = 100;
-/// ++foo;
-/// }
-/// @endcode
-/// Pointing at '100' will return a <VarDecl 'foo', IntegerLiteral '100'> pair.
-/// Pointing at '++foo' will return a <FunctionDecl 'f', UnaryOperator> pair.
-///
-std::pair<Decl *, Stmt *> ResolveLocationInAST(ASTContext &Ctx,
- SourceLocation Loc);
-
} // end namespace clang
#endif
diff --git a/include/clang/Index/ASTLocation.h b/include/clang/Index/ASTLocation.h
new file mode 100644
index 0000000..9620ec5
--- /dev/null
+++ b/include/clang/Index/ASTLocation.h
@@ -0,0 +1,174 @@
+//===--- ASTLocation.h - A <Decl, Stmt> pair --------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// ASTLocation is Decl or a Stmt and its immediate Decl parent.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_INDEX_ASTLOCATION_H
+#define LLVM_CLANG_INDEX_ASTLOCATION_H
+
+#include "clang/AST/TypeLoc.h"
+#include "llvm/ADT/PointerIntPair.h"
+
+namespace llvm {
+ class raw_ostream;
+}
+
+namespace clang {
+ class Decl;
+ class Stmt;
+ class NamedDecl;
+
+namespace idx {
+ class TranslationUnit;
+
+/// \brief Represents a Decl or a Stmt and its immediate Decl parent. It's
+/// immutable.
+///
+/// ASTLocation is intended to be used as a "pointer" into the AST. It is either
+/// just a Decl, or a Stmt and its Decl parent. Since a single Stmt is devoid
+/// of context, its parent Decl provides all the additional missing information
+/// like the declaration context, ASTContext, etc.
+///
+class ASTLocation {
+public:
+ enum NodeKind {
+ N_Decl, N_NamedRef, N_Stmt, N_Type
+ };
+
+ struct NamedRef {
+ NamedDecl *ND;
+ SourceLocation Loc;
+
+ NamedRef() : ND(0) { }
+ NamedRef(NamedDecl *nd, SourceLocation loc) : ND(nd), Loc(loc) { }
+ };
+
+private:
+ llvm::PointerIntPair<Decl *, 2, NodeKind> ParentDecl;
+
+ union {
+ Decl *D;
+ Stmt *Stm;
+ struct {
+ NamedDecl *ND;
+ unsigned RawLoc;
+ } NDRef;
+ struct {
+ void *TyPtr;
+ void *Data;
+ } Ty;
+ };
+
+public:
+ ASTLocation() { }
+
+ explicit ASTLocation(const Decl *d)
+ : ParentDecl(const_cast<Decl*>(d), N_Decl), D(const_cast<Decl*>(d)) { }
+
+ ASTLocation(const Decl *parentDecl, const Stmt *stm)
+ : ParentDecl(const_cast<Decl*>(parentDecl), N_Stmt),
+ Stm(const_cast<Stmt*>(stm)) {
+ if (!stm) ParentDecl.setPointer(0);
+ }
+
+ ASTLocation(const Decl *parentDecl, NamedDecl *ndRef, SourceLocation loc)
+ : ParentDecl(const_cast<Decl*>(parentDecl), N_NamedRef) {
+ if (ndRef) {
+ NDRef.ND = ndRef;
+ NDRef.RawLoc = loc.getRawEncoding();
+ } else
+ ParentDecl.setPointer(0);
+ }
+
+ ASTLocation(const Decl *parentDecl, TypeLoc tyLoc)
+ : ParentDecl(const_cast<Decl*>(parentDecl), N_Type) {
+ if (tyLoc) {
+ Ty.TyPtr = tyLoc.getSourceType().getAsOpaquePtr();
+ Ty.Data = tyLoc.getOpaqueData();
+ } else
+ ParentDecl.setPointer(0);
+ }
+
+ bool isValid() const { return ParentDecl.getPointer() != 0; }
+ bool isInvalid() const { return !isValid(); }
+
+ NodeKind getKind() const {
+ assert(isValid());
+ return (NodeKind)ParentDecl.getInt();
+ }
+
+ Decl *getParentDecl() const { return ParentDecl.getPointer(); }
+
+ Decl *AsDecl() const {
+ assert(getKind() == N_Decl);
+ return D;
+ }
+ Stmt *AsStmt() const {
+ assert(getKind() == N_Stmt);
+ return Stm;
+ }
+ NamedRef AsNamedRef() const {
+ assert(getKind() == N_NamedRef);
+ return NamedRef(NDRef.ND, SourceLocation::getFromRawEncoding(NDRef.RawLoc));
+ }
+ TypeLoc AsTypeLoc() const {
+ assert(getKind() == N_Type);
+ return TypeLoc(QualType::getFromOpaquePtr(Ty.TyPtr), Ty.Data);
+ }
+
+ Decl *dyn_AsDecl() const { return getKind() == N_Decl ? D : 0; }
+ Stmt *dyn_AsStmt() const { return getKind() == N_Stmt ? Stm : 0; }
+ NamedRef dyn_AsNamedRef() const {
+ return getKind() == N_Type ? AsNamedRef() : NamedRef();
+ }
+ TypeLoc dyn_AsTypeLoc() const {
+ return getKind() == N_Type ? AsTypeLoc() : TypeLoc();
+ }
+
+ bool isDecl() const { return isValid() && getKind() == N_Decl; }
+ bool isStmt() const { return isValid() && getKind() == N_Stmt; }
+ bool isNamedRef() const { return isValid() && getKind() == N_NamedRef; }
+ bool isType() const { return isValid() && getKind() == N_Type; }
+
+ /// \brief Returns the declaration that this ASTLocation references.
+ ///
+ /// If this points to a Decl, that Decl is returned.
+ /// If this points to an Expr that references a Decl, that Decl is returned,
+ /// otherwise it returns NULL.
+ Decl *getReferencedDecl();
+ const Decl *getReferencedDecl() const {
+ return const_cast<ASTLocation*>(this)->getReferencedDecl();
+ }
+
+ SourceRange getSourceRange() const;
+
+ void print(llvm::raw_ostream &OS) const;
+};
+
+/// \brief Like ASTLocation but also contains the TranslationUnit that the
+/// ASTLocation originated from.
+class TULocation : public ASTLocation {
+ TranslationUnit *TU;
+
+public:
+ TULocation(TranslationUnit *tu, ASTLocation astLoc)
+ : ASTLocation(astLoc), TU(tu) {
+ assert(tu && "Passed null translation unit");
+ }
+
+ TranslationUnit *getTU() const { return TU; }
+};
+
+} // namespace idx
+
+} // namespace clang
+
+#endif
diff --git a/include/clang/Index/Analyzer.h b/include/clang/Index/Analyzer.h
new file mode 100644
index 0000000..f6b5465
--- /dev/null
+++ b/include/clang/Index/Analyzer.h
@@ -0,0 +1,56 @@
+//===--- Analyzer.h - Analysis for indexing information ---------*- 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 Analyzer interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_INDEX_ANALYZER_H
+#define LLVM_CLANG_INDEX_ANALYZER_H
+
+namespace clang {
+ class Decl;
+ class ObjCMessageExpr;
+
+namespace idx {
+ class Program;
+ class IndexProvider;
+ class TULocationHandler;
+
+/// \brief Provides indexing information, like finding all references of an
+/// Entity across translation units.
+class Analyzer {
+ Program &Prog;
+ IndexProvider &Idxer;
+
+ Analyzer(const Analyzer&); // do not implement
+ Analyzer &operator=(const Analyzer &); // do not implement
+
+public:
+ explicit Analyzer(Program &prog, IndexProvider &idxer)
+ : Prog(prog), Idxer(idxer) { }
+
+ /// \brief Find all TULocations for declarations of the given Decl and pass
+ /// them to Handler.
+ void FindDeclarations(Decl *D, TULocationHandler &Handler);
+
+ /// \brief Find all TULocations for references of the given Decl and pass
+ /// them to Handler.
+ void FindReferences(Decl *D, TULocationHandler &Handler);
+
+ /// \brief Find methods that may respond to the given message and pass them
+ /// to Handler.
+ void FindObjCMethods(ObjCMessageExpr *MsgE, TULocationHandler &Handler);
+};
+
+} // namespace idx
+
+} // namespace clang
+
+#endif
diff --git a/include/clang/Index/DeclReferenceMap.h b/include/clang/Index/DeclReferenceMap.h
new file mode 100644
index 0000000..73f2fe5
--- /dev/null
+++ b/include/clang/Index/DeclReferenceMap.h
@@ -0,0 +1,50 @@
+//===--- DeclReferenceMap.h - Map Decls to their references -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// DeclReferenceMap creates a mapping from Decls to the ASTLocations that
+// reference them.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_INDEX_DECLREFERENCEMAP_H
+#define LLVM_CLANG_INDEX_DECLREFERENCEMAP_H
+
+#include "clang/Index/ASTLocation.h"
+#include "clang/Index/STLExtras.h"
+#include <map>
+
+namespace clang {
+ class ASTContext;
+ class NamedDecl;
+
+namespace idx {
+
+/// \brief Maps NamedDecls with the ASTLocations that reference them.
+///
+/// References are mapped and retrieved using the canonical decls.
+class DeclReferenceMap {
+public:
+ explicit DeclReferenceMap(ASTContext &Ctx);
+
+ typedef std::multimap<NamedDecl*, ASTLocation> MapTy;
+ typedef pair_value_iterator<MapTy::iterator> astlocation_iterator;
+
+ astlocation_iterator refs_begin(NamedDecl *D) const;
+ astlocation_iterator refs_end(NamedDecl *D) const;
+ bool refs_empty(NamedDecl *D) const;
+
+private:
+ mutable MapTy Map;
+};
+
+} // end idx namespace
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/Index/Entity.h b/include/clang/Index/Entity.h
new file mode 100644
index 0000000..4533a1a
--- /dev/null
+++ b/include/clang/Index/Entity.h
@@ -0,0 +1,143 @@
+//===--- Entity.h - Cross-translation-unit "token" for decls ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Entity is a ASTContext-independent way to refer to declarations that are
+// visible across translation units.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_INDEX_ENTITY_H
+#define LLVM_CLANG_INDEX_ENTITY_H
+
+#include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/DenseMap.h"
+#include <string>
+
+namespace clang {
+ class ASTContext;
+ class Decl;
+
+namespace idx {
+ class Program;
+ class EntityImpl;
+
+/// \brief A ASTContext-independent way to refer to declarations.
+///
+/// Entity is basically the link for declarations that are semantically the same
+/// in multiple ASTContexts. A client will convert a Decl into an Entity and
+/// later use that Entity to find the "same" Decl into another ASTContext.
+/// Declarations that are semantically the same and visible across translation
+/// units will be associated with the same Entity.
+///
+/// An Entity may also refer to declarations that cannot be visible across
+/// translation units, e.g. static functions with the same name in multiple
+/// translation units will be associated with different Entities.
+///
+/// Entities can be checked for equality but note that the same Program object
+/// should be used when getting Entities.
+///
+class Entity {
+ /// \brief Stores the Decl directly if it is not visible outside of its own
+ /// translation unit, otherwise it stores the associated EntityImpl.
+ llvm::PointerUnion<Decl *, EntityImpl *> Val;
+
+ explicit Entity(Decl *D);
+ explicit Entity(EntityImpl *impl) : Val(impl) { }
+ friend class EntityGetter;
+
+public:
+ Entity() { }
+
+ /// \brief Find the Decl that can be referred to by this entity.
+ Decl *getDecl(ASTContext &AST) const;
+
+ /// \brief If this Entity represents a declaration that is internal to its
+ /// translation unit, getInternalDecl() returns it.
+ Decl *getInternalDecl() const {
+ assert(isInternalToTU() && "This Entity is not internal!");
+ return Val.get<Decl *>();
+ }
+
+ /// \brief Get a printable name for debugging purpose.
+ std::string getPrintableName() const;
+
+ /// \brief Get an Entity associated with the given Decl.
+ /// \returns invalid Entity if an Entity cannot refer to this Decl.
+ static Entity get(Decl *D, Program &Prog);
+
+ /// \brief true if the Entity is not visible outside the trasnlation unit.
+ bool isInternalToTU() const {
+ assert(isValid() && "This Entity is not valid!");
+ return Val.is<Decl *>();
+ }
+
+ bool isValid() const { return !Val.isNull(); }
+ bool isInvalid() const { return !isValid(); }
+
+ void *getAsOpaquePtr() const { return Val.getOpaqueValue(); }
+ static Entity getFromOpaquePtr(void *Ptr) {
+ Entity Ent;
+ Ent.Val = llvm::PointerUnion<Decl *, EntityImpl *>::getFromOpaqueValue(Ptr);
+ return Ent;
+ }
+
+ friend bool operator==(const Entity &LHS, const Entity &RHS) {
+ return LHS.getAsOpaquePtr() == RHS.getAsOpaquePtr();
+ }
+
+ // For use in a std::map.
+ friend bool operator < (const Entity &LHS, const Entity &RHS) {
+ return LHS.getAsOpaquePtr() < RHS.getAsOpaquePtr();
+ }
+
+ // For use in DenseMap/DenseSet.
+ static Entity getEmptyMarker() {
+ Entity Ent;
+ Ent.Val =
+ llvm::PointerUnion<Decl *, EntityImpl *>::getFromOpaqueValue((void*)-1);
+ return Ent;
+ }
+ static Entity getTombstoneMarker() {
+ Entity Ent;
+ Ent.Val =
+ llvm::PointerUnion<Decl *, EntityImpl *>::getFromOpaqueValue((void*)-2);
+ return Ent;
+ }
+};
+
+} // namespace idx
+
+} // namespace clang
+
+namespace llvm {
+/// Define DenseMapInfo so that Entities can be used as keys in DenseMap and
+/// DenseSets.
+template<>
+struct DenseMapInfo<clang::idx::Entity> {
+ static inline clang::idx::Entity getEmptyKey() {
+ return clang::idx::Entity::getEmptyMarker();
+ }
+
+ static inline clang::idx::Entity getTombstoneKey() {
+ return clang::idx::Entity::getTombstoneMarker();
+ }
+
+ static unsigned getHashValue(clang::idx::Entity);
+
+ static inline bool
+ isEqual(clang::idx::Entity LHS, clang::idx::Entity RHS) {
+ return LHS == RHS;
+ }
+
+ static inline bool isPod() { return true; }
+};
+
+} // end namespace llvm
+
+#endif
diff --git a/include/clang/Index/GlobalSelector.h b/include/clang/Index/GlobalSelector.h
new file mode 100644
index 0000000..51f9826
--- /dev/null
+++ b/include/clang/Index/GlobalSelector.h
@@ -0,0 +1,99 @@
+//===--- GlobalSelector.h - Cross-translation-unit "token" for selectors --===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// GlobalSelector is a ASTContext-independent way to refer to selectors.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_INDEX_GLOBALSELECTOR_H
+#define LLVM_CLANG_INDEX_GLOBALSELECTOR_H
+
+#include "llvm/ADT/DenseMap.h"
+#include <string>
+
+namespace clang {
+ class ASTContext;
+ class Selector;
+
+namespace idx {
+ class Program;
+
+/// \brief A ASTContext-independent way to refer to selectors.
+class GlobalSelector {
+ void *Val;
+
+ explicit GlobalSelector(void *val) : Val(val) { }
+
+public:
+ GlobalSelector() : Val(0) { }
+
+ /// \brief Get the ASTContext-specific selector.
+ Selector getSelector(ASTContext &AST) const;
+
+ bool isValid() const { return Val != 0; }
+ bool isInvalid() const { return !isValid(); }
+
+ /// \brief Get a printable name for debugging purpose.
+ std::string getPrintableName() const;
+
+ /// \brief Get a GlobalSelector for the ASTContext-specific selector.
+ static GlobalSelector get(Selector Sel, Program &Prog);
+
+ void *getAsOpaquePtr() const { return Val; }
+
+ static GlobalSelector getFromOpaquePtr(void *Ptr) {
+ return GlobalSelector(Ptr);
+ }
+
+ friend bool operator==(const GlobalSelector &LHS, const GlobalSelector &RHS) {
+ return LHS.getAsOpaquePtr() == RHS.getAsOpaquePtr();
+ }
+
+ // For use in a std::map.
+ friend bool operator< (const GlobalSelector &LHS, const GlobalSelector &RHS) {
+ return LHS.getAsOpaquePtr() < RHS.getAsOpaquePtr();
+ }
+
+ // For use in DenseMap/DenseSet.
+ static GlobalSelector getEmptyMarker() { return GlobalSelector((void*)-1); }
+ static GlobalSelector getTombstoneMarker() {
+ return GlobalSelector((void*)-2);
+ }
+};
+
+} // namespace idx
+
+} // namespace clang
+
+namespace llvm {
+/// Define DenseMapInfo so that GlobalSelectors can be used as keys in DenseMap
+/// and DenseSets.
+template<>
+struct DenseMapInfo<clang::idx::GlobalSelector> {
+ static inline clang::idx::GlobalSelector getEmptyKey() {
+ return clang::idx::GlobalSelector::getEmptyMarker();
+ }
+
+ static inline clang::idx::GlobalSelector getTombstoneKey() {
+ return clang::idx::GlobalSelector::getTombstoneMarker();
+ }
+
+ static unsigned getHashValue(clang::idx::GlobalSelector);
+
+ static inline bool
+ isEqual(clang::idx::GlobalSelector LHS, clang::idx::GlobalSelector RHS) {
+ return LHS == RHS;
+ }
+
+ static inline bool isPod() { return true; }
+};
+
+} // end namespace llvm
+
+#endif
diff --git a/include/clang/Index/Handlers.h b/include/clang/Index/Handlers.h
new file mode 100644
index 0000000..655aef9
--- /dev/null
+++ b/include/clang/Index/Handlers.h
@@ -0,0 +1,81 @@
+//===--- Handlers.h - Interfaces for receiving information ------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Abstract interfaces for receiving information.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_INDEX_HANDLERS_H
+#define LLVM_CLANG_INDEX_HANDLERS_H
+
+#include "llvm/ADT/SmallVector.h"
+
+namespace clang {
+
+namespace idx {
+ class Entity;
+ class TranslationUnit;
+ class TULocation;
+
+/// \brief Abstract interface for receiving Entities.
+class EntityHandler {
+public:
+ typedef Entity receiving_type;
+
+ virtual ~EntityHandler();
+ virtual void Handle(Entity Ent) = 0;
+};
+
+/// \brief Abstract interface for receiving TranslationUnits.
+class TranslationUnitHandler {
+public:
+ typedef TranslationUnit* receiving_type;
+
+ virtual ~TranslationUnitHandler();
+ virtual void Handle(TranslationUnit *TU) = 0;
+};
+
+/// \brief Abstract interface for receiving TULocations.
+class TULocationHandler {
+public:
+ typedef TULocation receiving_type;
+
+ virtual ~TULocationHandler();
+ virtual void Handle(TULocation TULoc) = 0;
+};
+
+/// \brief Helper for the Handler classes. Stores the objects into a vector.
+/// example:
+/// @code
+/// Storing<TranslationUnitHandler> TURes;
+/// IndexProvider.GetTranslationUnitsFor(Entity, TURes);
+/// for (Storing<TranslationUnitHandler>::iterator
+/// I = TURes.begin(), E = TURes.end(); I != E; ++I) { ....
+/// @endcode
+template <typename handler_type>
+class Storing : public handler_type {
+ typedef typename handler_type::receiving_type receiving_type;
+ typedef llvm::SmallVector<receiving_type, 8> StoreTy;
+ StoreTy Store;
+
+public:
+ virtual void Handle(receiving_type Obj) {
+ Store.push_back(Obj);
+ }
+
+ typedef typename StoreTy::const_iterator iterator;
+ iterator begin() const { return Store.begin(); }
+ iterator end() const { return Store.end(); }
+};
+
+} // namespace idx
+
+} // namespace clang
+
+#endif
diff --git a/include/clang/Index/IndexProvider.h b/include/clang/Index/IndexProvider.h
new file mode 100644
index 0000000..187dd93
--- /dev/null
+++ b/include/clang/Index/IndexProvider.h
@@ -0,0 +1,38 @@
+//===--- IndexProvider.h - Maps information to translation units -*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Maps information to TranslationUnits.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_INDEX_INDEXPROVIDER_H
+#define LLVM_CLANG_INDEX_INDEXPROVIDER_H
+
+namespace clang {
+
+namespace idx {
+ class Entity;
+ class TranslationUnitHandler;
+ class GlobalSelector;
+
+/// \brief Maps information to TranslationUnits.
+class IndexProvider {
+public:
+ virtual ~IndexProvider();
+ virtual void GetTranslationUnitsFor(Entity Ent,
+ TranslationUnitHandler &Handler) = 0;
+ virtual void GetTranslationUnitsFor(GlobalSelector Sel,
+ TranslationUnitHandler &Handler) = 0;
+};
+
+} // namespace idx
+
+} // namespace clang
+
+#endif
diff --git a/include/clang/Index/Indexer.h b/include/clang/Index/Indexer.h
new file mode 100644
index 0000000..8b1d2dd
--- /dev/null
+++ b/include/clang/Index/Indexer.h
@@ -0,0 +1,75 @@
+//===--- Indexer.h - IndexProvider implementation ---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// IndexProvider implementation.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_INDEX_INDEXER_H
+#define LLVM_CLANG_INDEX_INDEXER_H
+
+#include "clang/Frontend/TextDiagnosticBuffer.h"
+#include "clang/Index/IndexProvider.h"
+#include "clang/Index/Entity.h"
+#include "clang/Index/GlobalSelector.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/DenseMap.h"
+#include "clang/Basic/FileManager.h"
+#include <map>
+
+namespace clang {
+ class ASTContext;
+
+namespace idx {
+ class Program;
+ class TranslationUnit;
+
+/// \brief Maps information to TranslationUnits.
+class Indexer : public IndexProvider {
+public:
+ typedef llvm::SmallPtrSet<TranslationUnit *, 4> TUSetTy;
+ typedef llvm::DenseMap<ASTContext *, TranslationUnit *> CtxTUMapTy;
+ typedef std::map<Entity, TUSetTy> MapTy;
+ typedef std::map<GlobalSelector, TUSetTy> SelMapTy;
+
+ explicit Indexer(Program &prog) :
+ Prog(prog), Diags(&DiagClient) { }
+
+ Program &getProgram() const { return Prog; }
+
+ Diagnostic &getDiagnostics() { return Diags; }
+ const Diagnostic &getDiagnostics() const { return Diags; }
+
+ FileManager &getFileManager() { return FileMgr; }
+ const FileManager &getFileManager() const { return FileMgr; }
+
+ /// \brief Find all Entities and map them to the given translation unit.
+ void IndexAST(TranslationUnit *TU);
+
+ virtual void GetTranslationUnitsFor(Entity Ent,
+ TranslationUnitHandler &Handler);
+ virtual void GetTranslationUnitsFor(GlobalSelector Sel,
+ TranslationUnitHandler &Handler);
+
+private:
+ Program &Prog;
+ TextDiagnosticBuffer DiagClient;
+ Diagnostic Diags;
+ FileManager FileMgr;
+
+ MapTy Map;
+ CtxTUMapTy CtxTUMap;
+ SelMapTy SelMap;
+};
+
+} // namespace idx
+
+} // namespace clang
+
+#endif
diff --git a/include/clang/Index/Program.h b/include/clang/Index/Program.h
new file mode 100644
index 0000000..8039192
--- /dev/null
+++ b/include/clang/Index/Program.h
@@ -0,0 +1,45 @@
+//===--- Program.h - Cross-translation unit information ---------*- 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 idx::Program interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_INDEX_PROGRAM_H
+#define LLVM_CLANG_INDEX_PROGRAM_H
+
+namespace clang {
+ class ASTContext;
+
+namespace idx {
+ class EntityHandler;
+
+/// \brief Top level object that owns and maintains information
+/// that is common across translation units.
+class Program {
+ void *Impl;
+
+ Program(const Program&); // do not implement
+ Program &operator=(const Program &); // do not implement
+ friend class Entity;
+ friend class GlobalSelector;
+
+public:
+ Program();
+ ~Program();
+
+ /// \brief Traverses the AST and passes all the entities to the Handler.
+ void FindEntities(ASTContext &Ctx, EntityHandler &Handler);
+};
+
+} // namespace idx
+
+} // namespace clang
+
+#endif
diff --git a/include/clang/Index/STLExtras.h b/include/clang/Index/STLExtras.h
new file mode 100644
index 0000000..a3693c6
--- /dev/null
+++ b/include/clang/Index/STLExtras.h
@@ -0,0 +1,63 @@
+//===--- STLExtras.h - Helper STL related templates -------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Helper templates for using with the STL.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_INDEX_STLEXTRAS_H
+#define LLVM_CLANG_INDEX_STLEXTRAS_H
+
+namespace clang {
+
+namespace idx {
+
+/// \brief Wraps an iterator whose value_type is a pair, and provides
+/// pair's second object as the value.
+template <typename iter_type>
+class pair_value_iterator {
+ iter_type I;
+
+public:
+ typedef typename iter_type::value_type::second_type value_type;
+ typedef value_type& reference;
+ typedef value_type* pointer;
+ typedef typename iter_type::iterator_category iterator_category;
+ typedef typename iter_type::difference_type difference_type;
+
+ pair_value_iterator() { }
+ pair_value_iterator(iter_type i) : I(i) { }
+
+ reference operator*() const { return I->second; }
+ pointer operator->() const { return &I->second; }
+
+ pair_value_iterator& operator++() {
+ ++I;
+ return *this;
+ }
+
+ pair_value_iterator operator++(int) {
+ pair_value_iterator tmp(*this);
+ ++(*this);
+ return tmp;
+ }
+
+ friend bool operator==(pair_value_iterator L, pair_value_iterator R) {
+ return L.I == R.I;
+ }
+ friend bool operator!=(pair_value_iterator L, pair_value_iterator R) {
+ return L.I != R.I;
+ }
+};
+
+} // end idx namespace
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/Index/SelectorMap.h b/include/clang/Index/SelectorMap.h
new file mode 100644
index 0000000..be01702
--- /dev/null
+++ b/include/clang/Index/SelectorMap.h
@@ -0,0 +1,57 @@
+//===--- SelectorMap.h - Maps selectors to methods and messages -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// SelectorMap creates a mapping from selectors to ObjC method declarations
+// and ObjC message expressions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_INDEX_SELECTORMAP_H
+#define LLVM_CLANG_INDEX_SELECTORMAP_H
+
+#include "clang/Index/ASTLocation.h"
+#include "clang/Index/STLExtras.h"
+#include "clang/Basic/IdentifierTable.h"
+#include <map>
+
+namespace clang {
+ class ASTContext;
+ class ObjCMethodDecl;
+
+namespace idx {
+
+/// \brief Maps NamedDecls with the ASTLocations that reference them.
+///
+/// References are mapped and retrieved using the canonical decls.
+class SelectorMap {
+public:
+ explicit SelectorMap(ASTContext &Ctx);
+
+ typedef std::multimap<Selector, ObjCMethodDecl *> SelMethMapTy;
+ typedef std::multimap<Selector, ASTLocation> SelRefMapTy;
+
+ typedef pair_value_iterator<SelMethMapTy::iterator> method_iterator;
+ typedef pair_value_iterator<SelRefMapTy::iterator> astlocation_iterator;
+
+ method_iterator methods_begin(Selector Sel) const;
+ method_iterator methods_end(Selector Sel) const;
+
+ astlocation_iterator refs_begin(Selector Sel) const;
+ astlocation_iterator refs_end(Selector Sel) const;
+
+private:
+ mutable SelMethMapTy SelMethMap;
+ mutable SelRefMapTy SelRefMap;
+};
+
+} // end idx namespace
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/Index/TranslationUnit.h b/include/clang/Index/TranslationUnit.h
new file mode 100644
index 0000000..bf9e78f
--- /dev/null
+++ b/include/clang/Index/TranslationUnit.h
@@ -0,0 +1,37 @@
+//===--- TranslationUnit.h - Interface for a translation unit ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Abstract interface for a translation unit.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_INDEX_TRANSLATIONUNIT_H
+#define LLVM_CLANG_INDEX_TRANSLATIONUNIT_H
+
+namespace clang {
+ class ASTContext;
+
+namespace idx {
+ class DeclReferenceMap;
+ class SelectorMap;
+
+/// \brief Abstract interface for a translation unit.
+class TranslationUnit {
+public:
+ virtual ~TranslationUnit();
+ virtual ASTContext &getASTContext() = 0;
+ virtual DeclReferenceMap &getDeclReferenceMap() = 0;
+ virtual SelectorMap &getSelectorMap() = 0;
+};
+
+} // namespace idx
+
+} // namespace clang
+
+#endif
diff --git a/include/clang/Index/Utils.h b/include/clang/Index/Utils.h
new file mode 100644
index 0000000..e78ef8a
--- /dev/null
+++ b/include/clang/Index/Utils.h
@@ -0,0 +1,35 @@
+//===--- Utils.h - Misc utilities for indexing-----------------------------===//
+//
+// 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 indexing related
+// functionality.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_INDEX_UTILS_H
+#define LLVM_CLANG_INDEX_UTILS_H
+
+namespace clang {
+ class ASTContext;
+ class SourceLocation;
+
+namespace idx {
+ class ASTLocation;
+
+/// \brief Returns the ASTLocation that a source location points to.
+///
+/// \returns the resolved ASTLocation or an invalid ASTLocation if the source
+/// location could not be resolved.
+ASTLocation ResolveLocationInAST(ASTContext &Ctx, SourceLocation Loc);
+
+} // end namespace idx
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Lex/DirectoryLookup.h b/include/clang/Lex/DirectoryLookup.h
index 618de39..c94a990 100644
--- a/include/clang/Lex/DirectoryLookup.h
+++ b/include/clang/Lex/DirectoryLookup.h
@@ -38,20 +38,20 @@ private:
/// 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;
@@ -62,25 +62,25 @@ public:
bool isUser, bool isFramework)
: DirCharacteristic(DT), UserSupplied(isUser),
LookupType(isFramework ? LT_Framework : LT_NormalDir) {
- u.Dir = dir;
+ 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;
+ 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; }
@@ -90,42 +90,42 @@ public:
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,
+ const char *FilenameEnd,
HeaderSearch &HS) const;
-
+
};
} // end namespace clang
diff --git a/include/clang/Lex/HeaderMap.h b/include/clang/Lex/HeaderMap.h
index d803309..6bb7c25 100644
--- a/include/clang/Lex/HeaderMap.h
+++ b/include/clang/Lex/HeaderMap.h
@@ -30,31 +30,31 @@ namespace clang {
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;
diff --git a/include/clang/Lex/HeaderSearch.h b/include/clang/Lex/HeaderSearch.h
index f21aab1..7517440 100644
--- a/include/clang/Lex/HeaderSearch.h
+++ b/include/clang/Lex/HeaderSearch.h
@@ -30,17 +30,17 @@ class IdentifierInfo;
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.
@@ -51,14 +51,14 @@ struct HeaderFileInfo {
/// external storage.
const IdentifierInfo *ControllingMacro;
- /// \brief The ID number of the controlling macro.
+ /// \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()
+ HeaderFileInfo()
: isImport(false), DirInfo(SrcMgr::C_User),
NumIncludes(0), ControllingMacro(0), ControllingMacroID(0) {}
@@ -71,7 +71,7 @@ struct HeaderFileInfo {
/// 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
@@ -81,7 +81,7 @@ class HeaderSearch {
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.
///
@@ -94,13 +94,13 @@ class HeaderSearch {
/// 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 is a mapping from FileEntry -> HeaderMap, uniquing
/// headermaps. This vector owns the headermap.
std::vector<std::pair<const FileEntry*, const HeaderMap*> > HeaderMaps;
@@ -114,7 +114,7 @@ class HeaderSearch {
unsigned NumFrameworkLookups, NumSubFrameworkLookups;
// HeaderSearch doesn't support default or copy construction.
- explicit HeaderSearch();
+ explicit HeaderSearch();
explicit HeaderSearch(const HeaderSearch&);
void operator=(const HeaderSearch&);
public:
@@ -132,12 +132,12 @@ public:
NoCurDirSearch = noCurDirSearch;
//LookupFileCache.clear();
}
-
+
/// ClearFileInfo - Forget everything we know about headers so far.
void ClearFileInfo() {
FileInfo.clear();
}
-
+
void SetExternalLookup(ExternalIdentifierLookup *EIL) {
ExternalLookup = EIL;
}
@@ -155,7 +155,7 @@ public:
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
@@ -164,7 +164,7 @@ public:
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.
@@ -172,19 +172,19 @@ public:
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) {
@@ -196,13 +196,13 @@ public:
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.
@@ -210,11 +210,11 @@ public:
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;
@@ -223,10 +223,10 @@ public:
// 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);
diff --git a/include/clang/Lex/LexDiagnostic.h b/include/clang/Lex/LexDiagnostic.h
index 03d9b7b..a470aa0 100644
--- a/include/clang/Lex/LexDiagnostic.h
+++ b/include/clang/Lex/LexDiagnostic.h
@@ -13,7 +13,7 @@
#include "clang/Basic/Diagnostic.h"
namespace clang {
- namespace diag {
+ namespace diag {
enum {
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE) ENUM,
#define LEXSTART
diff --git a/include/clang/Lex/Lexer.h b/include/clang/Lex/Lexer.h
index 3a73147..c2db4d3 100644
--- a/include/clang/Lex/Lexer.h
+++ b/include/clang/Lex/Lexer.h
@@ -39,11 +39,12 @@ class Lexer : public PreprocessorLexer {
SourceLocation FileLoc; // Location for start of file.
LangOptions Features; // Features enabled by this language (cache).
bool Is_PragmaLexer; // True if lexer for _Pragma handling.
+ bool IsEofCodeCompletion; // True if EOF is treated as a code-completion.
//===--------------------------------------------------------------------===//
// 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
@@ -52,7 +53,7 @@ class Lexer : public PreprocessorLexer {
/// 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
@@ -65,14 +66,14 @@ class Lexer : public PreprocessorLexer {
// 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
@@ -84,21 +85,21 @@ public:
/// 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,
+ 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; }
@@ -108,7 +109,7 @@ public:
/// 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
@@ -116,14 +117,14 @@ public:
void Lex(Token &Result) {
// Start a new token.
Result.startToken();
-
- // NOTE, any changes here should also change code after calls to
+
+ // 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);
@@ -131,11 +132,11 @@ public:
/// 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.
@@ -144,7 +145,7 @@ public:
Lex(Result);
// Note that lexing to the end of the buffer doesn't implicitly delete the
// lexer when in raw mode.
- return BufferPtr == BufferEnd;
+ return BufferPtr == BufferEnd;
}
/// isKeepWhitespaceMode - Return true if the lexer should return tokens for
@@ -168,23 +169,32 @@ public:
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) {
+ void SetCommentRetentionState(bool Mode) {
assert(!isKeepWhitespaceMode() &&
"Can't play with comment retention state when retaining whitespace");
ExtendedTokenMode = Mode ? 1 : 0;
}
+
+ /// \brief Specify that end-of-file is to be considered a code-completion
+ /// token.
+ ///
+ /// When in this mode, the end-of-file token will be immediately preceded
+ /// by a code-completion token.
+ void SetEofIsCodeCompletion(bool Val = true) {
+ IsEofCodeCompletion = Val;
+ }
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;
@@ -192,20 +202,20 @@ public:
/// 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
@@ -213,7 +223,7 @@ public:
static unsigned MeasureTokenLength(SourceLocation Loc,
const SourceManager &SM,
const LangOptions &LangOpts);
-
+
//===--------------------------------------------------------------------===//
// Internal implementation interfaces.
private:
@@ -228,7 +238,7 @@ private:
/// 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,
+ void FormTokenWithChars(Token &Result, const char *TokEnd,
tok::TokenKind Kind) {
unsigned TokLen = TokEnd-BufferPtr;
Result.setLength(TokLen);
@@ -236,7 +246,7 @@ private:
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.
@@ -245,7 +255,7 @@ private:
//===--------------------------------------------------------------------===//
// Lexer character reading interfaces.
public:
-
+
// This lexer is built on two interfaces for reading characters, both of which
// automatically provide phase 1/2 translation. getAndAdvanceChar is used
// when we know that we will be reading a character from the input buffer and
@@ -260,7 +270,7 @@ public:
// 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
@@ -268,7 +278,7 @@ public:
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
@@ -277,13 +287,13 @@ public:
// 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
@@ -300,7 +310,7 @@ private:
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
@@ -312,16 +322,16 @@ private:
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,
@@ -332,30 +342,30 @@ public:
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);
@@ -363,7 +373,7 @@ private:
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);
diff --git a/include/clang/Lex/LiteralSupport.h b/include/clang/Lex/LiteralSupport.h
index 8ee8ecf..97656f7 100644
--- a/include/clang/Lex/LiteralSupport.h
+++ b/include/clang/Lex/LiteralSupport.h
@@ -17,6 +17,7 @@
#include <string>
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/DataTypes.h"
namespace llvm {
class APInt;
@@ -31,22 +32,22 @@ 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);
@@ -56,8 +57,9 @@ public:
bool isLongLong;
bool isFloat; // 1.0f
bool isImaginary; // 1.0i
-
- bool isIntegerLiteral() const {
+ bool isMicrosoftInteger; // Microsoft suffix extension i8, i16, i32, or i64.
+
+ bool isIntegerLiteral() const {
return !saw_period && !saw_exponent;
}
bool isFloatingLiteral() const {
@@ -66,27 +68,27 @@ public:
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,
+ llvm::APFloat GetFloatValue(const llvm::fltSemantics &Format,
bool* isExact = NULL);
-private:
-
+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) {
@@ -94,7 +96,7 @@ private:
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) {
@@ -102,7 +104,7 @@ private:
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) {
@@ -110,7 +112,7 @@ private:
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) {
@@ -118,7 +120,7 @@ private:
ptr++;
return ptr;
}
-
+
};
/// CharLiteralParser - Perform interpretation and semantic analysis of a
@@ -143,7 +145,7 @@ public:
/// literals) (C99 5.1.1.2p1).
class StringLiteralParser {
Preprocessor &PP;
-
+
unsigned MaxTokenLength;
unsigned SizeBound;
unsigned wchar_tByteWidth;
@@ -155,7 +157,7 @@ public:
bool hadError;
bool AnyWide;
bool Pascal;
-
+
const char *GetString() { return &ResultBuf[0]; }
unsigned GetStringLength() const { return ResultPtr-&ResultBuf[0]; }
@@ -163,14 +165,14 @@ public:
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
index ccd13c8..5887041 100644
--- a/include/clang/Lex/MacroInfo.h
+++ b/include/clang/Lex/MacroInfo.h
@@ -22,7 +22,7 @@
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 {
@@ -39,7 +39,7 @@ class MacroInfo {
/// 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;
@@ -47,21 +47,21 @@ class MacroInfo {
/// 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.
@@ -70,19 +70,19 @@ private:
/// 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
+ /// 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) {
@@ -90,13 +90,13 @@ public:
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; }
@@ -112,13 +112,13 @@ public:
/// 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) {
@@ -132,13 +132,13 @@ public:
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;
@@ -146,7 +146,7 @@ public:
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 {
@@ -154,20 +154,20 @@ public:
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; }
@@ -175,7 +175,7 @@ public:
/// 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 {
@@ -186,22 +186,22 @@ public:
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;
@@ -212,7 +212,7 @@ public:
IsDisabled = true;
}
};
-
+
} // end namespace clang
#endif
diff --git a/include/clang/Lex/MultipleIncludeOpt.h b/include/clang/Lex/MultipleIncludeOpt.h
index 94d4677..5d5d673 100644
--- a/include/clang/Lex/MultipleIncludeOpt.h
+++ b/include/clang/Lex/MultipleIncludeOpt.h
@@ -36,7 +36,7 @@ class MultipleIncludeOpt {
/// 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;
@@ -46,7 +46,7 @@ public:
DidMacroExpansion = false;
TheMacro = 0;
}
-
+
/// Invalidate - Permenantly mark this file as not being suitable for the
/// include-file optimization.
void Invalidate() {
@@ -55,19 +55,19 @@ public:
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.
@@ -80,14 +80,14 @@ public:
// 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;
@@ -100,7 +100,7 @@ public:
/// 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() {
@@ -108,12 +108,12 @@ public:
// 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 {
diff --git a/include/clang/Lex/PPCallbacks.h b/include/clang/Lex/PPCallbacks.h
index e5cbeeb..dd24fb7 100644
--- a/include/clang/Lex/PPCallbacks.h
+++ b/include/clang/Lex/PPCallbacks.h
@@ -23,18 +23,18 @@ namespace clang {
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
@@ -43,25 +43,25 @@ public:
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,
+ 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) {
}
@@ -76,7 +76,7 @@ public:
class PPChainedCallbacks : public PPCallbacks {
PPCallbacks *First, *Second;
-public:
+public:
PPChainedCallbacks(PPCallbacks *_First, PPCallbacks *_Second)
: First(_First), Second(_Second) {}
~PPChainedCallbacks() {
@@ -89,23 +89,23 @@ public:
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,
+
+ 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);
diff --git a/include/clang/Lex/PTHLexer.h b/include/clang/Lex/PTHLexer.h
index 369b818..e96a8c5 100644
--- a/include/clang/Lex/PTHLexer.h
+++ b/include/clang/Lex/PTHLexer.h
@@ -18,42 +18,42 @@
#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:
@@ -62,19 +62,19 @@ protected:
/// Create a PTHLexer for the specified token stream.
PTHLexer(Preprocessor& pp, FileID FID, const unsigned char *D,
const unsigned char* ppcond, PTHManager &PM);
-public:
+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.
@@ -85,12 +85,12 @@ public:
// 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();
diff --git a/include/clang/Lex/PTHManager.h b/include/clang/Lex/PTHManager.h
index 5075764..ff1a172 100644
--- a/include/clang/Lex/PTHManager.h
+++ b/include/clang/Lex/PTHManager.h
@@ -32,29 +32,29 @@ 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;
@@ -65,15 +65,15 @@ class PTHManager : public IdentifierInfoLookup {
/// 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
+
+ /// 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,
@@ -84,11 +84,11 @@ class PTHManager : public IdentifierInfoLookup {
// Do not implement.
PTHManager();
void operator=(const PTHManager&);
-
- /// getSpellingAtPTHOffset - Used by PTHLexer classes to get the cached
+
+ /// 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) {
@@ -98,44 +98,44 @@ class PTHManager : public IdentifierInfoLookup {
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; }
-
+ 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);
-
+ 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
index 136dc6f..ef367fe 100644
--- a/include/clang/Lex/Pragma.h
+++ b/include/clang/Lex/Pragma.h
@@ -37,10 +37,10 @@ class PragmaHandler {
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; }
@@ -57,14 +57,14 @@ class PragmaNamespace : public PragmaHandler {
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) {
@@ -75,12 +75,12 @@ public:
/// namespace.
void RemovePragmaHandler(PragmaHandler *Handler);
- bool IsEmpty() {
- return Handlers.empty();
+ bool IsEmpty() {
+ return Handlers.empty();
}
virtual void HandlePragma(Preprocessor &PP, Token &FirstToken);
-
+
virtual PragmaNamespace *getIfNamespace() { return this; }
};
diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h
index 6d5ed72..0765ac3 100644
--- a/include/clang/Lex/Preprocessor.h
+++ b/include/clang/Lex/Preprocessor.h
@@ -25,11 +25,12 @@
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Allocator.h"
#include <vector>
namespace clang {
-
+
class SourceManager;
class FileManager;
class FileEntry;
@@ -41,7 +42,7 @@ 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
@@ -49,21 +50,21 @@ class DirectoryLookup;
///
class Preprocessor {
Diagnostic *Diags;
- const LangOptions &Features;
+ 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__
@@ -74,7 +75,7 @@ class Preprocessor {
IdentifierInfo *Ident_Pragma, *Ident__VA_ARGS__; // _Pragma, __VA_ARGS__
IdentifierInfo *Ident__has_feature; // __has_feature
IdentifierInfo *Ident__has_builtin; // __has_builtin
-
+
SourceLocation DATELoc, TIMELoc;
unsigned CounterValue; // Next __COUNTER__ value.
@@ -86,7 +87,7 @@ class Preprocessor {
// 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.
@@ -94,42 +95,42 @@ class Preprocessor {
/// 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
+ /// 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.
+ /// 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;
/// BuiltinInfo - Information about builtins.
Builtin::Context BuiltinInfo;
-
+
/// PragmaHandlers - This tracks all of the pragmas that the client registered
/// with this preprocessor.
PragmaNamespace *PragmaHandlers;
-
- /// \brief Tracks all of the comment handlers that the client registered
+
+ /// \brief Tracks all of the comment handlers that the client registered
/// with this preprocessor.
std::vector<CommentHandler *> CommentHandlers;
-
+
/// 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.
@@ -138,7 +139,7 @@ class Preprocessor {
/// 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.
@@ -146,7 +147,7 @@ class Preprocessor {
Lexer *TheLexer;
PTHLexer *ThePTHLexer;
PreprocessorLexer *ThePPLexer;
- TokenLexer *TheTokenLexer;
+ TokenLexer *TheTokenLexer;
const DirectoryLookup *TheDirLookup;
IncludeStackInfo(Lexer *L, PTHLexer* P, PreprocessorLexer* PPL,
@@ -155,19 +156,19 @@ class Preprocessor {
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;
@@ -175,18 +176,18 @@ class Preprocessor {
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;
+ typedef llvm::SmallVector<Token, 1> CachedTokensTy;
/// CachedTokens - Cached tokens are stored here when we do backtracking or
/// lookahead. They are "lexed" by the CachingLex() method.
@@ -223,9 +224,9 @@ public:
SelectorTable &getSelectorTable() { return Selectors; }
Builtin::Context &getBuiltinInfo() { return BuiltinInfo; }
llvm::BumpPtrAllocator &getPreprocessorAllocator() { return BP; }
-
+
void setPTHManager(PTHManager* pm);
-
+
PTHManager *getPTHManager() { return PTH.get(); }
/// SetCommentRetentionState - Control whether or not the preprocessor retains
@@ -234,20 +235,20 @@ public:
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.
@@ -257,32 +258,32 @@ public:
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*,
+ 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
@@ -295,7 +296,7 @@ public:
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".
@@ -309,16 +310,16 @@ public:
/// \brief Add the specified comment handler to the preprocessor.
void AddCommentHandler(CommentHandler *Handler);
-
+
/// \brief Remove the specified comment handler.
///
/// It is an error to remove a handler that has not been registered.
void RemoveCommentHandler(CommentHandler *Handler);
-
+
/// EnterMainSourceFile - Enter the specified FileID as the main source file,
/// which implicitly adds the builtin defines etc.
- void EnterMainSourceFile();
-
+ 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.
@@ -331,7 +332,7 @@ public:
/// ILEnd specifies the location of the ')' for a function-like macro or the
/// identifier for an object-like macro.
void EnterMacro(Token &Identifier, SourceLocation ILEnd, MacroArgs *Args);
-
+
/// EnterTokenStream - Add a "macro" context to the top of the include stack,
/// which will cause the lexer to start returning the specified tokens.
///
@@ -346,7 +347,7 @@ public:
///
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.
@@ -371,7 +372,7 @@ public:
void CommitBacktrackedTokens();
/// Backtrack - Make Preprocessor re-lex the tokens that were lexed since
- /// EnableBacktrackAtThisPos() was previously called.
+ /// EnableBacktrackAtThisPos() was previously called.
void Backtrack();
/// isBacktrackEnabled - True if EnableBacktrackAtThisPos() was called and
@@ -390,7 +391,7 @@ public:
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.
@@ -408,11 +409,11 @@ public:
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
@@ -461,7 +462,7 @@ public:
AnnotatePreviousCachedTokens(Tok);
}
- /// \brief Replace the last token with an annotation token.
+ /// \brief Replace the last token with an annotation token.
///
/// Like AnnotateCachedTokens(), this routine replaces an
/// already-parsed (and resolved) token with an annotation
@@ -481,19 +482,19 @@ public:
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
@@ -521,7 +522,7 @@ public:
// 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.
@@ -539,35 +540,35 @@ public:
/// 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.
@@ -576,26 +577,26 @@ public:
/// 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
+ /// 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);
@@ -604,11 +605,11 @@ public:
/// 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 {
@@ -616,13 +617,13 @@ public:
}
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(),
@@ -631,7 +632,7 @@ private:
CurDirLookup));
CurPPLexer = 0;
}
-
+
void PopIncludeMacroStack() {
CurLexer.reset(IncludeMacroStack.back().TheLexer);
CurPTHLexer.reset(IncludeMacroStack.back().ThePTHLexer);
@@ -640,11 +641,11 @@ private:
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;
@@ -653,13 +654,13 @@ private:
/// #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
@@ -670,34 +671,34 @@ private:
/// 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();
-
+
/// 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.
@@ -707,12 +708,12 @@ private:
/// 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);
@@ -720,7 +721,7 @@ private:
/// 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
@@ -729,7 +730,7 @@ private:
/// 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 "").
@@ -737,7 +738,7 @@ private:
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.
@@ -752,7 +753,7 @@ private:
bool IsFileLexer() const {
return IsFileLexer(CurLexer.get(), CurPPLexer);
}
-
+
//===--------------------------------------------------------------------===//
// Caching stuff.
void CachingLex(Token &Result);
@@ -773,7 +774,7 @@ private:
void HandleDigitDirective(Token &Tok);
void HandleUserDiagnosticDirective(Token &Tok, bool isWarning);
void HandleIdentSCCSDirective(Token &Tok);
-
+
// File inclusion.
void HandleIncludeDirective(Token &Tok,
const DirectoryLookup *LookupFrom = 0,
@@ -781,13 +782,13 @@ private:
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);
@@ -795,7 +796,7 @@ private:
void HandleEndifDirective(Token &Tok);
void HandleElseDirective(Token &Tok);
void HandleElifDirective(Token &Tok);
-
+
// Pragmas.
void HandlePragmaDirective();
public:
@@ -813,18 +814,18 @@ public:
class PreprocessorFactory {
public:
virtual ~PreprocessorFactory();
- virtual Preprocessor* CreatePreprocessor() = 0;
+ virtual Preprocessor* CreatePreprocessor() = 0;
};
-
-/// \brief Abstract base class that describes a handler that will receive
+
+/// \brief Abstract base class that describes a handler that will receive
/// source ranges for each of the comments encountered in the source file.
class CommentHandler {
public:
virtual ~CommentHandler();
-
+
virtual void HandleComment(Preprocessor &PP, SourceRange Comment) = 0;
};
-
+
} // end namespace clang
#endif
diff --git a/include/clang/Lex/PreprocessorLexer.h b/include/clang/Lex/PreprocessorLexer.h
index f98b559..85c44c5 100644
--- a/include/clang/Lex/PreprocessorLexer.h
+++ b/include/clang/Lex/PreprocessorLexer.h
@@ -18,7 +18,7 @@
#include "clang/Lex/Token.h"
#include "llvm/ADT/SmallVector.h"
#include <string>
-
+
namespace clang {
class Preprocessor;
@@ -29,19 +29,19 @@ protected:
/// 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.
@@ -54,40 +54,40 @@ protected:
///
/// 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
+
+ /// 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),
+ : 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).
@@ -102,8 +102,8 @@ protected:
}
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.
@@ -113,44 +113,44 @@ protected:
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(); }
+
+ 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 {
+
+ 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;
diff --git a/include/clang/Lex/ScratchBuffer.h b/include/clang/Lex/ScratchBuffer.h
index 6506f92..f03515f 100644
--- a/include/clang/Lex/ScratchBuffer.h
+++ b/include/clang/Lex/ScratchBuffer.h
@@ -29,13 +29,13 @@ class ScratchBuffer {
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);
};
diff --git a/include/clang/Lex/Token.h b/include/clang/Lex/Token.h
index 2c8f2ad..8acdb30 100644
--- a/include/clang/Lex/Token.h
+++ b/include/clang/Lex/Token.h
@@ -62,14 +62,14 @@ class Token {
/// Kind - The actual flavor of token this is.
///
- unsigned Kind : 8; // DON'T make Kind a 'tok::TokenKind';
+ 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.
@@ -80,7 +80,7 @@ public:
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; }
@@ -94,12 +94,12 @@ public:
is(tok::angle_string_literal);
}
- bool isAnnotation() const {
- return is(tok::annot_typename) ||
+ 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; }
@@ -132,11 +132,11 @@ public:
setLocation(R.getBegin());
setAnnotationEndLoc(R.getEnd());
}
-
+
const char *getName() const {
return tok::getTokenName( (tok::TokenKind) Kind);
}
-
+
/// startToken - Reset all flags to cleared.
///
void startToken() {
@@ -145,7 +145,7 @@ public:
PtrData = 0;
Loc = SourceLocation();
}
-
+
IdentifierInfo *getIdentifierInfo() const {
assert(!isAnnotation() && "Used IdentInfo on annotation token!");
if (isLiteral()) return 0;
@@ -154,7 +154,7 @@ public:
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.
@@ -166,7 +166,7 @@ public:
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;
@@ -175,17 +175,17 @@ public:
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.
@@ -195,32 +195,32 @@ public:
/// setFlagValue - Set a flag to either true or false.
void setFlagValue(TokenFlags Flag, bool Val) {
- if (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.
+
+ /// 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.
///
@@ -233,15 +233,15 @@ 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;
@@ -263,41 +263,41 @@ struct TemplateIdAnnotation {
/// The declaration of the template corresponding to the
/// template-name. This is an Action::DeclTy*.
- void *Template;
+ void *Template;
/// The kind of template that Template refers to.
TemplateNameKind Kind;
/// The location of the '<' before the template argument
- /// list.
+ /// list.
SourceLocation LAngleLoc;
/// The location of the '>' after the template argument
- /// list.
+ /// list.
SourceLocation RAngleLoc;
/// NumArgs - The number of template arguments.
- unsigned NumArgs;
+ 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() {
+ 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() {
+ bool *getTemplateArgIsType() {
return (bool *)(getTemplateArgLocations() + NumArgs);
}
static TemplateIdAnnotation* Allocate(unsigned NumArgs) {
- TemplateIdAnnotation *TemplateId
- = (TemplateIdAnnotation *)std::malloc(sizeof(TemplateIdAnnotation) +
- sizeof(void*) * NumArgs +
+ TemplateIdAnnotation *TemplateId
+ = (TemplateIdAnnotation *)std::malloc(sizeof(TemplateIdAnnotation) +
+ sizeof(void*) * NumArgs +
sizeof(SourceLocation) * NumArgs +
sizeof(bool) * NumArgs);
TemplateId->NumArgs = NumArgs;
diff --git a/include/clang/Lex/TokenConcatenation.h b/include/clang/Lex/TokenConcatenation.h
index dfc05f4..d759e47 100644
--- a/include/clang/Lex/TokenConcatenation.h
+++ b/include/clang/Lex/TokenConcatenation.h
@@ -19,7 +19,7 @@
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?"
@@ -30,40 +30,40 @@ namespace clang {
///
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;
diff --git a/include/clang/Lex/TokenLexer.h b/include/clang/Lex/TokenLexer.h
index c0a61cf..3f13e9c 100644
--- a/include/clang/Lex/TokenLexer.h
+++ b/include/clang/Lex/TokenLexer.h
@@ -21,7 +21,7 @@ namespace clang {
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.
@@ -47,34 +47,34 @@ class TokenLexer {
/// 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:
@@ -87,13 +87,13 @@ public:
: 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.
@@ -102,45 +102,45 @@ public:
: 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
+ /// 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
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h
index d969562..1ee1470 100644
--- a/include/clang/Parse/Action.h
+++ b/include/clang/Parse/Action.h
@@ -22,6 +22,7 @@
#include "clang/Parse/DeclSpec.h"
#include "clang/Parse/Ownership.h"
#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/ADT/PointerUnion.h"
namespace clang {
// Semantic.
@@ -49,7 +50,7 @@ namespace clang {
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.
@@ -102,22 +103,22 @@ public:
typedef ASTMultiPtr<&ActionBase::DeleteStmt> MultiStmtArg;
typedef ASTMultiPtr<&ActionBase::DeleteTemplateParams> MultiTemplateParamsArg;
- class FullExprArg {
+ 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
+ // 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.
@@ -128,7 +129,7 @@ public:
ExprArg Expr;
};
-
+
template<typename T>
FullExprArg FullExpr(T &Arg) {
return FullExprArg(ActOnFinishFullExpr(move(Arg)));
@@ -149,31 +150,47 @@ public:
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.
+ /// an empty string if not. This is used for pretty crash reporting.
virtual std::string getDeclName(DeclPtrTy D) { return ""; }
-
+
/// \brief Invoked for each comment in the source code, providing the source
/// range that contains the comment.
virtual void ActOnComment(SourceRange Comment) { }
-
+
//===--------------------------------------------------------------------===//
// 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::".
+ ///
+ /// \param II the identifier for which we are performing name lookup
+ ///
+ /// \param NameLoc the location of the identifier
+ ///
+ /// \param S the scope in which this name lookup occurs
+ ///
+ /// \param SS if non-NULL, the C++ scope specifier that precedes the
+ /// identifier
+ ///
+ /// \param isClassName whether this is a C++ class-name production, in
+ /// which we can end up referring to a member of an unknown specialization
+ /// that we know (from the grammar) is supposed to be a type. For example,
+ /// this occurs when deriving from "std::vector<T>::allocator_type", where T
+ /// is a template parameter.
+ ///
+ /// \returns the type referred to by this identifier, or NULL if the type
+ /// does not name an identifier.
virtual TypeTy *getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
- Scope *S, const CXXScopeSpec *SS = 0) = 0;
+ Scope *S, const CXXScopeSpec *SS = 0,
+ bool isClassName = false) = 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
@@ -183,20 +200,69 @@ public:
virtual DeclSpec::TST isTagName(IdentifierInfo &II, Scope *S) {
return DeclSpec::TST_unspecified;
}
-
+
+ /// \brief Action called as part of error recovery when the parser has
+ /// determined that the given name must refer to a type, but
+ /// \c getTypeName() did not return a result.
+ ///
+ /// This callback permits the action to give a detailed diagnostic when an
+ /// unknown type name is encountered and, potentially, to try to recover
+ /// by producing a new type in \p SuggestedType.
+ ///
+ /// \param II the name that should be a type.
+ ///
+ /// \param IILoc the location of the name in the source.
+ ///
+ /// \param S the scope in which name lookup was performed.
+ ///
+ /// \param SS if non-NULL, the C++ scope specifier that preceded the name.
+ ///
+ /// \param SuggestedType if the action sets this type to a non-NULL type,
+ /// the parser will recovery by consuming the type name token and then
+ /// pretending that the given type was the type it parsed.
+ ///
+ /// \returns true if a diagnostic was emitted, false otherwise. When false,
+ /// the parser itself will emit a generic "unknown type name" diagnostic.
+ virtual bool DiagnoseUnknownTypeName(const IdentifierInfo &II,
+ SourceLocation IILoc,
+ Scope *S,
+ const CXXScopeSpec *SS,
+ TypeTy *&SuggestedType) {
+ return false;
+ }
+
/// 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;
+ /// \brief Determine whether the given identifier refers to the name of a
+ /// template.
+ ///
+ /// \param S the scope in which name lookup occurs
+ ///
+ /// \param II the identifier that we are querying to determine whether it
+ /// is a template.
+ ///
+ /// \param IdLoc the source location of the identifier
+ ///
+ /// \param SS the C++ scope specifier that precedes the template name, if
+ /// any.
+ ///
+ /// \param EnteringContext whether we are potentially entering the context
+ /// referred to by the scope specifier \p SS
+ ///
+ /// \param Template if the name does refer to a template, the declaration
+ /// of the template that the name refers to.
+ ///
+ /// \returns the kind of template that this name refers to.
+ virtual TemplateNameKind isTemplateName(Scope *S,
+ const IdentifierInfo &II,
+ SourceLocation IdLoc,
+ const CXXScopeSpec *SS,
+ TypeTy *ObjectType,
+ bool EnteringContext,
+ TemplateTy &Template) = 0;
/// ActOnCXXGlobalScopeSpecifier - Return the object that represents the
/// global scope ('::').
@@ -205,17 +271,40 @@ public:
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.
+ /// \brief Parsed an identifier followed by '::' in a C++
+ /// nested-name-specifier.
+ ///
+ /// \param S the scope in which the nested-name-specifier was parsed.
+ ///
+ /// \param SS the nested-name-specifier that precedes the identifier. For
+ /// example, if we are parsing "foo::bar::", \p SS will describe the "foo::"
+ /// that has already been parsed.
+ ///
+ /// \param IdLoc the location of the identifier we have just parsed (e.g.,
+ /// the "bar" in "foo::bar::".
+ ///
+ /// \param CCLoc the location of the '::' at the end of the
+ /// nested-name-specifier.
+ ///
+ /// \param II the identifier that represents the scope that this
+ /// nested-name-specifier refers to, e.g., the "bar" in "foo::bar::".
+ ///
+ /// \param ObjectType if this nested-name-specifier occurs as part of a
+ /// C++ member access expression such as "x->Base::f", the type of the base
+ /// object (e.g., *x in the example, if "x" were a pointer).
+ ///
+ /// \param EnteringContext if true, then we intend to immediately enter the
+ /// context of this nested-name-specifier, e.g., for an out-of-line
+ /// definition of a class member.
+ ///
+ /// \returns a CXXScopeTy* object representing the C++ scope.
virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S,
const CXXScopeSpec &SS,
SourceLocation IdLoc,
SourceLocation CCLoc,
- IdentifierInfo &II) {
+ IdentifierInfo &II,
+ TypeTy *ObjectType,
+ bool EnteringContext) {
return 0;
}
@@ -232,7 +321,7 @@ public:
TypeTy *Type,
SourceRange TypeRange,
SourceLocation CCLoc) {
- return 0;
+ return 0;
}
/// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global
@@ -241,7 +330,9 @@ public:
/// 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) {
+ /// \returns true if an error occurred, false otherwise.
+ virtual bool ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
+ return false;
}
/// ActOnCXXExitDeclaratorScope - Called when a declarator that previously
@@ -281,14 +372,14 @@ public:
return DeclPtrTy();
}
- /// AddInitializerToDecl - This action is called immediately after
- /// ActOnDeclarator (when an initializer is present). The code is factored
+ /// 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,
+ /// initializer. The declaration above should still result in a warning,
/// since the reference to "xx" is uninitialized.
- virtual void AddInitializerToDecl(DeclPtrTy Dcl, FullExprArg Init) {
+ virtual void AddInitializerToDecl(DeclPtrTy Dcl, ExprArg Init) {
return;
}
@@ -302,7 +393,10 @@ public:
/// ActOnUninitializedDecl - This action is called immediately after
/// ActOnDeclarator (when an initializer is *not* present).
- virtual void ActOnUninitializedDecl(DeclPtrTy Dcl) {
+ /// If TypeContainsUndeducedAuto is true, then the type of the declarator
+ /// has an undeduced 'auto' type somewhere.
+ virtual void ActOnUninitializedDecl(DeclPtrTy Dcl,
+ bool TypeContainsUndeducedAuto) {
return;
}
@@ -314,7 +408,7 @@ public:
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.
@@ -352,7 +446,7 @@ public:
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) {}
@@ -360,7 +454,7 @@ public:
/// 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) {
@@ -397,7 +491,7 @@ public:
/// translation unit when EOF is reached and all but the top-level scope is
/// popped.
virtual void ActOnEndOfTranslationUnit() {}
-
+
//===--------------------------------------------------------------------===//
// Type Parsing Callbacks.
//===--------------------------------------------------------------------===//
@@ -406,24 +500,90 @@ public:
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;'
+
+ enum TagUseKind {
+ TUK_Reference, // Reference to a tag: 'struct foo *X;'
+ TUK_Declaration, // Fwd decl of a tag: 'struct foo;'
+ TUK_Definition, // Definition of a tag: 'struct foo { int X; } Y;'
+ TUK_Friend // Friend declaration: 'friend struct foo;'
};
- virtual DeclPtrTy ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
+
+ /// \brief The parser has encountered a tag (e.g., "class X") that should be
+ /// turned into a declaration by the action module.
+ ///
+ /// \param S the scope in which this tag occurs.
+ ///
+ /// \param TagSpec an instance of DeclSpec::TST, indicating what kind of tag
+ /// this is (struct/union/enum/class).
+ ///
+ /// \param TUK how the tag we have encountered is being used, which
+ /// can be a reference to a (possibly pre-existing) tag, a
+ /// declaration of that tag, or the beginning of a definition of
+ /// that tag.
+ ///
+ /// \param KWLoc the location of the "struct", "class", "union", or "enum"
+ /// keyword.
+ ///
+ /// \param SS C++ scope specifier that precedes the name of the tag, e.g.,
+ /// the "std::" in "class std::type_info".
+ ///
+ /// \param Name the name of the tag, e.g., "X" in "struct X". This parameter
+ /// may be NULL, to indicate an anonymous class/struct/union/enum type.
+ ///
+ /// \param NameLoc the location of the name of the tag.
+ ///
+ /// \param Attr the set of attributes that appertain to the tag.
+ ///
+ /// \param AS when this tag occurs within a C++ class, provides the
+ /// current access specifier (AS_public, AS_private, AS_protected).
+ /// Otherwise, it will be AS_none.
+ ///
+ /// \param TemplateParameterLists the set of C++ template parameter lists
+ /// that apply to this tag, if the tag is a declaration or definition (see
+ /// the \p TK parameter). The action module is responsible for determining,
+ /// based on the template parameter lists and the scope specifier, whether
+ /// the declared tag is a class template or not.
+ ///
+ /// \param OwnedDecl the callee should set this flag true when the returned
+ /// declaration is "owned" by this reference. Ownership is handled entirely
+ /// by the action module.
+ ///
+ /// \returns the declaration to which this tag refers.
+ virtual DeclPtrTy ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
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).
+ MultiTemplateParamsArg TemplateParameterLists,
+ bool &OwnedDecl, bool &IsDependent) {
return DeclPtrTy();
}
-
+
+ /// Acts on a reference to a dependent tag name. This arises in
+ /// cases like:
+ ///
+ /// template <class T> class A;
+ /// template <class T> class B {
+ /// friend class A<T>::M; // here
+ /// };
+ ///
+ /// \param TagSpec an instance of DeclSpec::TST corresponding to the
+ /// tag specifier.
+ ///
+ /// \param TUK the tag use kind (either TUK_Friend or TUK_Reference)
+ ///
+ /// \param SS the scope specifier (always defined)
+ virtual TypeResult ActOnDependentTag(Scope *S,
+ unsigned TagSpec,
+ TagUseKind TUK,
+ const CXXScopeSpec &SS,
+ IdentifierInfo *Name,
+ SourceLocation KWLoc,
+ SourceLocation NameLoc) {
+ return TypeResult();
+ }
+
/// Act on @defs() element found when parsing a structure. ClassName is the
- /// name of the referenced class.
+ /// name of the referenced class.
virtual void ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart,
IdentifierInfo *ClassName,
llvm::SmallVectorImpl<DeclPtrTy> &Decls) {}
@@ -432,19 +592,19 @@ public:
Declarator &D, ExprTy *BitfieldWidth) {
return DeclPtrTy();
}
-
+
virtual DeclPtrTy ActOnIvar(Scope *S, SourceLocation DeclStart,
DeclPtrTy IntfDecl,
Declarator &D, ExprTy *BitfieldWidth,
tok::ObjCKeywordKind visibility) {
return DeclPtrTy();
}
-
+
virtual void ActOnFields(Scope* S, SourceLocation RecLoc, DeclPtrTy TagDecl,
- DeclPtrTy *Fields, unsigned NumFields,
+ 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).
@@ -452,7 +612,8 @@ public:
/// 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 void ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagDecl,
+ SourceLocation RBraceLoc) { }
virtual DeclPtrTy ActOnEnumConstant(Scope *S, DeclPtrTy EnumDecl,
DeclPtrTy LastEnumConstant,
@@ -462,7 +623,8 @@ public:
}
virtual void ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
SourceLocation RBraceLoc, DeclPtrTy EnumDecl,
- DeclPtrTy *Elements, unsigned NumElements) {}
+ DeclPtrTy *Elements, unsigned NumElements,
+ Scope *S, AttributeList *AttrList) {}
//===--------------------------------------------------------------------===//
// Statement Parsing Callbacks.
@@ -496,10 +658,10 @@ public:
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){
@@ -513,8 +675,8 @@ public:
return StmtEmpty();
}
- virtual OwningStmtResult ActOnIfStmt(SourceLocation IfLoc,
- FullExprArg CondVal, StmtArg ThenVal,
+ virtual OwningStmtResult ActOnIfStmt(SourceLocation IfLoc,
+ FullExprArg CondVal, StmtArg ThenVal,
SourceLocation ElseLoc,
StmtArg ElseVal) {
return StmtEmpty();
@@ -529,12 +691,12 @@ public:
return StmtEmpty();
}
- virtual OwningStmtResult ActOnWhileStmt(SourceLocation WhileLoc,
+ virtual OwningStmtResult ActOnWhileStmt(SourceLocation WhileLoc,
FullExprArg Cond, StmtArg Body) {
return StmtEmpty();
}
virtual OwningStmtResult ActOnDoStmt(SourceLocation DoLoc, StmtArg Body,
- SourceLocation WhileLoc,
+ SourceLocation WhileLoc,
SourceLocation CondLParen,
ExprArg Cond,
SourceLocation CondRParen) {
@@ -572,11 +734,11 @@ public:
return StmtEmpty();
}
virtual OwningStmtResult ActOnReturnStmt(SourceLocation ReturnLoc,
- FullExprArg RetValExp) {
+ ExprArg RetValExp) {
return StmtEmpty();
}
virtual OwningStmtResult ActOnAsmStmt(SourceLocation AsmLoc,
- bool IsSimple,
+ bool IsSimple,
bool IsVolatile,
unsigned NumOutputs,
unsigned NumInputs,
@@ -647,15 +809,15 @@ public:
/// \brief The current expression and its subexpressions occur within an
/// unevaluated operand (C++0x [expr]p8), such as a constant expression
/// or the subexpression of \c sizeof, where the type or the value of the
- /// expression may be significant but no code will be generated to evaluate
+ /// expression may be significant but no code will be generated to evaluate
/// the value of the expression at run time.
Unevaluated,
-
- /// \brief The current expression is potentially evaluated at run time,
- /// which means that code may be generated to evaluate the value of the
+
+ /// \brief The current expression is potentially evaluated at run time,
+ /// which means that code may be generated to evaluate the value of the
/// expression at run time.
PotentiallyEvaluated,
-
+
/// \brief The current expression may be potentially evaluated or it may
/// be unevaluated, but it is impossible to tell from the lexical context.
/// This evaluation context is used primary for the operand of the C++
@@ -663,17 +825,17 @@ public:
/// it is an lvalue of polymorphic class type (C++ [basic.def.odr]p2).
PotentiallyPotentiallyEvaluated
};
-
+
/// \brief The parser is entering a new expression evaluation context.
///
/// \param NewContext is the new expression evaluation context.
///
/// \returns the previous expression evaluation context.
- virtual ExpressionEvaluationContext
+ virtual ExpressionEvaluationContext
PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext) {
return PotentiallyEvaluated;
}
-
+
/// \brief The parser is existing an expression evaluation context.
///
/// \param OldContext the expression evaluation context that the parser is
@@ -681,10 +843,10 @@ public:
///
/// \param NewContext the expression evaluation context that the parser is
/// returning to.
- virtual void
+ virtual void
PopExpressionEvaluationContext(ExpressionEvaluationContext OldContext,
ExpressionEvaluationContext NewContext) { }
-
+
// Primary Expressions.
/// \brief Retrieve the source range that corresponds to the given
@@ -756,6 +918,12 @@ public:
return move(Val); // Default impl returns operand.
}
+ virtual OwningExprResult ActOnParenListExpr(SourceLocation L,
+ SourceLocation R,
+ MultiExprArg Val) {
+ return ExprEmpty();
+ }
+
// Postfix Expressions.
virtual OwningExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
tok::TokenKind Kind,
@@ -773,7 +941,8 @@ public:
tok::TokenKind OpKind,
SourceLocation MemberLoc,
IdentifierInfo &Member,
- DeclPtrTy ObjCImpDecl) {
+ DeclPtrTy ObjCImpDecl,
+ const CXXScopeSpec *SS = 0) {
return ExprEmpty();
}
@@ -811,8 +980,8 @@ public:
SourceLocation RParenLoc) {
return ExprEmpty();
}
- /// @brief Parsed a C99 designated initializer.
- ///
+ /// @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
@@ -831,8 +1000,9 @@ public:
return ExprEmpty();
}
- virtual OwningExprResult ActOnCastExpr(SourceLocation LParenLoc, TypeTy *Ty,
- SourceLocation RParenLoc, ExprArg Op) {
+ virtual OwningExprResult ActOnCastExpr(Scope *S, SourceLocation LParenLoc,
+ TypeTy *Ty, SourceLocation RParenLoc,
+ ExprArg Op) {
return ExprEmpty();
}
@@ -885,13 +1055,13 @@ public:
}
// __builtin_types_compatible_p(type1, type2)
- virtual OwningExprResult ActOnTypesCompatibleExpr(SourceLocation BuiltinLoc,
+ virtual OwningExprResult ActOnTypesCompatibleExpr(SourceLocation BuiltinLoc,
TypeTy *arg1, TypeTy *arg2,
SourceLocation RPLoc) {
return ExprEmpty();
}
// __builtin_choose_expr(constExpr, expr1, expr2)
- virtual OwningExprResult ActOnChooseExpr(SourceLocation BuiltinLoc,
+ virtual OwningExprResult ActOnChooseExpr(SourceLocation BuiltinLoc,
ExprArg cond, ExprArg expr1,
ExprArg expr2, SourceLocation RPLoc){
return ExprEmpty();
@@ -971,6 +1141,7 @@ public:
/// ActOnUsingDirective - This is called when using-directive is parsed.
virtual DeclPtrTy ActOnUsingDeclaration(Scope *CurScope,
+ AccessSpecifier AS,
SourceLocation UsingLoc,
const CXXScopeSpec &SS,
SourceLocation IdentLoc,
@@ -978,7 +1149,7 @@ public:
OverloadedOperatorKind Op,
AttributeList *AttrList,
bool IsTypeName);
-
+
/// ActOnParamDefaultArgument - Parse default argument for function parameter
virtual void ActOnParamDefaultArgument(DeclPtrTy param,
SourceLocation EqualLoc,
@@ -989,7 +1160,7 @@ public:
/// 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,
+ virtual void ActOnParamUnparsedDefaultArgument(DeclPtrTy param,
SourceLocation EqualLoc,
SourceLocation ArgLoc) { }
@@ -997,7 +1168,7 @@ public:
/// the default argument for the parameter param failed.
virtual void ActOnParamDefaultArgumentError(DeclPtrTy param) { }
- /// AddCXXDirectInitializerToDecl - This action is called immediately after
+ /// 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,
@@ -1063,13 +1234,22 @@ public:
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;
+ /// ActOnFriendFunctionDecl - Parsed a friend function declarator.
+ /// The name is actually a slight misnomer, because the declarator
+ /// is not necessarily a function declarator.
+ virtual DeclPtrTy ActOnFriendFunctionDecl(Scope *S,
+ Declarator &D,
+ bool IsDefinition,
+ MultiTemplateParamsArg TParams) {
+ return DeclPtrTy();
+ }
+
+ /// ActOnFriendTypeDecl - Parsed a friend type declaration.
+ virtual DeclPtrTy ActOnFriendTypeDecl(Scope *S,
+ const DeclSpec &DS,
+ MultiTemplateParamsArg TParams) {
+ return DeclPtrTy();
}
-
//===------------------------- C++ Expressions --------------------------===//
@@ -1171,6 +1351,119 @@ public:
return ExprEmpty();
}
+ /// \brief Invoked when the parser is starting to parse a C++ member access
+ /// expression such as x.f or x->f.
+ ///
+ /// \param S the scope in which the member access expression occurs.
+ ///
+ /// \param Base the expression in which a member is being accessed, e.g., the
+ /// "x" in "x.f".
+ ///
+ /// \param OpLoc the location of the member access operator ("." or "->")
+ ///
+ /// \param OpKind the kind of member access operator ("." or "->")
+ ///
+ /// \param ObjectType originally NULL. The action should fill in this type
+ /// with the type into which name lookup should look to find the member in
+ /// the member access expression.
+ ///
+ /// \returns the (possibly modified) \p Base expression
+ virtual OwningExprResult ActOnStartCXXMemberReference(Scope *S,
+ ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ TypeTy *&ObjectType) {
+ return ExprEmpty();
+ }
+
+ /// ActOnDestructorReferenceExpr - Parsed a destructor reference, for example:
+ ///
+ /// t->~T();
+ virtual OwningExprResult
+ ActOnDestructorReferenceExpr(Scope *S, ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ SourceLocation ClassNameLoc,
+ IdentifierInfo *ClassName,
+ const CXXScopeSpec &SS,
+ bool HasTrailingLParen) {
+ return ExprEmpty();
+ }
+
+ /// ActOnOverloadedOperatorReferenceExpr - Parsed an overloaded operator
+ /// reference, for example:
+ ///
+ /// t.operator++();
+ virtual OwningExprResult
+ ActOnOverloadedOperatorReferenceExpr(Scope *S, ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ SourceLocation ClassNameLoc,
+ OverloadedOperatorKind OverOpKind,
+ const CXXScopeSpec *SS = 0) {
+ return ExprEmpty();
+ }
+
+ /// ActOnConversionOperatorReferenceExpr - Parsed an overloaded conversion
+ /// function reference, for example:
+ ///
+ /// t.operator int();
+ virtual OwningExprResult
+ ActOnConversionOperatorReferenceExpr(Scope *S, ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ SourceLocation ClassNameLoc,
+ TypeTy *Ty,
+ const CXXScopeSpec *SS = 0) {
+ return ExprEmpty();
+ }
+
+ /// \brief Parsed a reference to a member template-id.
+ ///
+ /// This callback will occur instead of ActOnMemberReferenceExpr() when the
+ /// member in question is a template for which the code provides an
+ /// explicitly-specified template argument list, e.g.,
+ ///
+ /// \code
+ /// x.f<int>()
+ /// \endcode
+ ///
+ /// \param S the scope in which the member reference expression occurs
+ ///
+ /// \param Base the expression to the left of the "." or "->".
+ ///
+ /// \param OpLoc the location of the "." or "->".
+ ///
+ /// \param OpKind the kind of operator, which will be "." or "->".
+ ///
+ /// \param SS the scope specifier that precedes the template-id in, e.g.,
+ /// \c x.Base::f<int>().
+ ///
+ /// \param Template the declaration of the template that is being referenced.
+ ///
+ /// \param TemplateNameLoc the location of the template name referred to by
+ /// \p Template.
+ ///
+ /// \param LAngleLoc the location of the left angle bracket ('<')
+ ///
+ /// \param TemplateArgs the (possibly-empty) template argument list provided
+ /// as part of the member reference.
+ ///
+ /// \param RAngleLoc the location of the right angle bracket ('>')
+ virtual OwningExprResult
+ ActOnMemberTemplateIdReferenceExpr(Scope *S, ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ const CXXScopeSpec &SS,
+ // FIXME: "template" keyword?
+ TemplateTy Template,
+ SourceLocation TemplateNameLoc,
+ SourceLocation LAngleLoc,
+ ASTTemplateArgsPtr TemplateArgs,
+ SourceLocation *TemplateArgLocs,
+ SourceLocation RAngleLoc) {
+ return ExprEmpty();
+ }
/// ActOnFinishFullExpr - Called whenever a full expression has been parsed.
/// (C++ [intro.execution]p12).
@@ -1180,18 +1473,18 @@ public:
//===---------------------------- C++ Classes ---------------------------===//
/// ActOnBaseSpecifier - Parsed a base specifier
- virtual BaseResult ActOnBaseSpecifier(DeclPtrTy classdecl,
+ virtual BaseResult ActOnBaseSpecifier(DeclPtrTy classdecl,
SourceRange SpecifierRange,
bool Virtual, AccessSpecifier Access,
- TypeTy *basetype,
+ TypeTy *basetype,
SourceLocation BaseLoc) {
return BaseResult();
}
- virtual void ActOnBaseSpecifiers(DeclPtrTy ClassDecl, BaseTy **Bases,
+ 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
@@ -1199,6 +1492,7 @@ public:
/// specifier on the function.
virtual DeclPtrTy ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS,
Declarator &D,
+ MultiTemplateParamsArg TemplateParameterLists,
ExprTy *BitfieldWidth,
ExprTy *Init,
bool Deleted = false) {
@@ -1223,12 +1517,14 @@ public:
/// 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,
+ /// contains the individual member (and base) initializers.
+ virtual void ActOnMemInitializers(DeclPtrTy ConstructorDecl,
SourceLocation ColonLoc,
MemInitTy **MemInits, unsigned NumMemInits){
}
+ virtual void ActOnDefaultCtorInitializers(DeclPtrTy CDtorDecl) {}
+
/// ActOnFinishCXXMemberSpecification - Invoked after all member declarators
/// are parsed but *before* parsing of inline method definitions.
virtual void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
@@ -1242,17 +1538,17 @@ public:
/// 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), ellipsis specifies whether this is a
+ /// (otherwise, "class" was used), ellipsis specifies whether this is a
/// C++0x parameter pack, EllipsisLoc specifies the start of the ellipsis,
- /// and KeyLoc is the location of the "class" or "typename" keyword.
- // ParamName is the name of the parameter (NULL indicates an unnamed template
+ /// 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, bool Ellipsis,
+ virtual DeclPtrTy ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis,
SourceLocation EllipsisLoc,
SourceLocation KeyLoc,
IdentifierInfo *ParamName,
@@ -1262,8 +1558,8 @@ public:
}
/// ActOnTypeParameterDefault - Adds a default argument (the type
- /// Default) to the given template type parameter (TypeParam).
- virtual void ActOnTypeParameterDefault(DeclPtrTy TypeParam,
+ /// Default) to the given template type parameter (TypeParam).
+ virtual void ActOnTypeParameterDefault(DeclPtrTy TypeParam,
SourceLocation EqualLoc,
SourceLocation DefaultLoc,
TypeTy *Default) {
@@ -1277,7 +1573,7 @@ public:
/// ActOnTemplateParameterList) and the number of previous
/// parameters within this template parameter list.
virtual DeclPtrTy ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
- unsigned Depth,
+ unsigned Depth,
unsigned Position) {
return DeclPtrTy();
}
@@ -1335,7 +1631,7 @@ public:
/// @endcode
///
/// ExportLoc, if valid, is the position of the "export"
- /// keyword. Otherwise, "export" was not specified.
+ /// 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.
@@ -1344,25 +1640,13 @@ public:
virtual TemplateParamsTy *
ActOnTemplateParameterList(unsigned Depth,
SourceLocation ExportLoc,
- SourceLocation TemplateLoc,
+ 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.
///
@@ -1372,10 +1656,6 @@ public:
///
/// \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,
@@ -1385,6 +1665,25 @@ public:
return TypeResult();
};
+ /// \brief Note that a template ID was used with a tag.
+ ///
+ /// \param Type The result of ActOnTemplateIdType.
+ ///
+ /// \param TUK Either TUK_Reference or TUK_Friend. Declarations and
+ /// definitions are interpreted as explicit instantiations or
+ /// specializations.
+ ///
+ /// \param TagSpec The tag keyword that was provided as part of the
+ /// elaborated-type-specifier; either class, struct, union, or enum.
+ ///
+ /// \param TagLoc The location of the tag keyword.
+ virtual TypeResult ActOnTagTemplateIdType(TypeResult Type,
+ TagUseKind TUK,
+ DeclSpec::TST TagSpec,
+ SourceLocation TagLoc) {
+ return TypeResult();
+ }
+
/// \brief Form a reference to a template-id (that will refer to a function)
/// from a template and a list of template arguments.
///
@@ -1402,7 +1701,7 @@ public:
SourceLocation RAngleLoc) {
return ExprError();
}
-
+
/// \brief Form a dependent template name.
///
/// This action forms a dependent template name given the template
@@ -1410,10 +1709,26 @@ public:
/// 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.
+ ///
+ /// \param TemplateKWLoc the location of the "template" keyword (if any).
+ ///
+ /// \param Name the name of the template (an identifier)
+ ///
+ /// \param NameLoc the location of the identifier
+ ///
+ /// \param SS the nested-name-specifier that precedes the "template" keyword
+ /// or the template name. FIXME: If the dependent template name occurs in
+ /// a member access expression, e.g., "x.template f<T>", this
+ /// nested-name-specifier will be empty.
+ ///
+ /// \param ObjectType if this dependent template name occurs in the
+ /// context of a member access expression, the type of the object being
+ /// accessed.
virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
const IdentifierInfo &Name,
SourceLocation NameLoc,
- const CXXScopeSpec &SS) {
+ const CXXScopeSpec &SS,
+ TypeTy *ObjectType) {
return TemplateTy();
}
@@ -1444,8 +1759,8 @@ public:
/// \param TagSpec whether this declares a class, struct, or union
/// (template)
///
- /// \param TK whether this is a declaration or a definition
- ///
+ /// \param TUK whether this is a declaration or a definition
+ ///
/// \param KWLoc the location of the 'class', 'struct', or 'union'
/// keyword.
///
@@ -1464,8 +1779,8 @@ public:
/// 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,
+ ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagUseKind TUK,
+ SourceLocation KWLoc,
const CXXScopeSpec &SS,
TemplateTy Template,
SourceLocation TemplateNameLoc,
@@ -1482,22 +1797,22 @@ public:
/// lists has been parsed.
///
/// This action is similar to ActOnDeclarator(), except that the declaration
- /// being created somehow involves a template, e.g., it is a template
+ /// being created somehow involves a template, e.g., it is a template
/// declaration or specialization.
- virtual DeclPtrTy ActOnTemplateDeclarator(Scope *S,
+ virtual DeclPtrTy ActOnTemplateDeclarator(Scope *S,
MultiTemplateParamsArg TemplateParameterLists,
Declarator &D) {
return DeclPtrTy();
}
-
+
/// \brief Invoked when the parser is beginning to parse a function template
/// or function template specialization definition.
- virtual DeclPtrTy ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
+ virtual DeclPtrTy ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
MultiTemplateParamsArg TemplateParameterLists,
Declarator &D) {
return DeclPtrTy();
}
-
+
/// \brief Process the explicit instantiation of a class template
/// specialization.
///
@@ -1513,6 +1828,9 @@ public:
///
/// \param S the current scope
///
+ /// \param ExternLoc the location of the 'extern' keyword that specifies that
+ /// this is an extern template (if any).
+ ///
/// \param TemplateLoc the location of the 'template' keyword that
/// specifies that this is an explicit instantiation.
///
@@ -1538,8 +1856,10 @@ public:
///
/// \param Attr attributes that apply to this instantiation.
virtual DeclResult
- ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
- unsigned TagSpec,
+ ActOnExplicitInstantiation(Scope *S,
+ SourceLocation ExternLoc,
+ SourceLocation TemplateLoc,
+ unsigned TagSpec,
SourceLocation KWLoc,
const CXXScopeSpec &SS,
TemplateTy Template,
@@ -1551,7 +1871,7 @@ public:
AttributeList *Attr) {
return DeclResult();
}
-
+
/// \brief Process the explicit instantiation of a member class of a
/// class template specialization.
///
@@ -1568,6 +1888,9 @@ public:
///
/// \param S the current scope
///
+ /// \param ExternLoc the location of the 'extern' keyword that specifies that
+ /// this is an extern template (if any).
+ ///
/// \param TemplateLoc the location of the 'template' keyword that
/// specifies that this is an explicit instantiation.
///
@@ -1593,8 +1916,10 @@ public:
///
/// \param Attr attributes that apply to this instantiation.
virtual DeclResult
- ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
- unsigned TagSpec,
+ ActOnExplicitInstantiation(Scope *S,
+ SourceLocation ExternLoc,
+ SourceLocation TemplateLoc,
+ unsigned TagSpec,
SourceLocation KWLoc,
const CXXScopeSpec &SS,
IdentifierInfo *Name,
@@ -1603,6 +1928,38 @@ public:
return DeclResult();
}
+ /// \brief Process the explicit instantiation of a function template or a
+ /// member of a class template.
+ ///
+ /// This routine is invoked when an explicit instantiation of a
+ /// function template or member function 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> void f(T);
+ /// template void f(int); // explicit instantiation
+ /// \endcode
+ ///
+ /// \param S the current scope
+ ///
+ /// \param ExternLoc the location of the 'extern' keyword that specifies that
+ /// this is an extern template (if any).
+ ///
+ /// \param TemplateLoc the location of the 'template' keyword that
+ /// specifies that this is an explicit instantiation.
+ ///
+ /// \param D the declarator describing the declaration to be implicitly
+ /// instantiated.
+ virtual DeclResult ActOnExplicitInstantiation(Scope *S,
+ SourceLocation ExternLoc,
+ SourceLocation TemplateLoc,
+ Declarator &D) {
+ return DeclResult();
+ }
+
+
/// \brief Called when the parser has parsed a C++ typename
/// specifier that ends in an identifier, e.g., "typename T::type".
///
@@ -1617,7 +1974,7 @@ public:
}
/// \brief Called when the parser has parsed a C++ typename
- /// specifier that ends in a template-id, e.g.,
+ /// specifier that ends in a template-id, e.g.,
/// "typename MetaFun::template apply<T1, T2>".
///
/// \param TypenameLoc the location of the 'typename' keyword
@@ -1631,22 +1988,22 @@ public:
}
//===----------------------- Obj-C Declarations -------------------------===//
-
+
// ActOnStartClassInterface - this action is called immediately after parsing
- // the prologue for a class interface (before parsing the instance
+ // the prologue for a class interface (before parsing the instance
// variables). Instance variables are processed by ActOnFields().
virtual DeclPtrTy ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
- IdentifierInfo *ClassName,
+ IdentifierInfo *ClassName,
SourceLocation ClassLoc,
- IdentifierInfo *SuperName,
+ IdentifierInfo *SuperName,
SourceLocation SuperLoc,
- const DeclPtrTy *ProtoRefs,
+ 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(
@@ -1655,11 +2012,11 @@ public:
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,
+ IdentifierInfo *ProtocolName,
SourceLocation ProtocolLoc,
const DeclPtrTy *ProtoRefs,
unsigned NumProtoRefs,
@@ -1670,9 +2027,9 @@ public:
// ActOnStartCategoryInterface - this action is called immdiately after
// parsing the prologue for a category interface.
virtual DeclPtrTy ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
- IdentifierInfo *ClassName,
+ IdentifierInfo *ClassName,
SourceLocation ClassLoc,
- IdentifierInfo *CategoryName,
+ IdentifierInfo *CategoryName,
SourceLocation CategoryLoc,
const DeclPtrTy *ProtoRefs,
unsigned NumProtoRefs,
@@ -1680,13 +2037,13 @@ public:
return DeclPtrTy();
}
// ActOnStartClassImplementation - this action is called immdiately after
- // parsing the prologue for a class implementation. Instance variables are
+ // parsing the prologue for a class implementation. Instance variables are
// processed by ActOnFields().
virtual DeclPtrTy ActOnStartClassImplementation(
SourceLocation AtClassImplLoc,
- IdentifierInfo *ClassName,
+ IdentifierInfo *ClassName,
SourceLocation ClassLoc,
- IdentifierInfo *SuperClassname,
+ IdentifierInfo *SuperClassname,
SourceLocation SuperClassLoc) {
return DeclPtrTy();
}
@@ -1694,12 +2051,12 @@ public:
// parsing the prologue for a category implementation.
virtual DeclPtrTy ActOnStartCategoryImplementation(
SourceLocation AtCatImplLoc,
- IdentifierInfo *ClassName,
+ 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
@@ -1711,7 +2068,7 @@ public:
IdentifierInfo *propertyIvar) { // name of the ivar
return DeclPtrTy();
}
-
+
struct ObjCArgInfo {
IdentifierInfo *Name;
SourceLocation NameLoc;
@@ -1719,12 +2076,12 @@ public:
// in this case.
TypeTy *Type;
ObjCDeclSpec DeclSpec;
-
+
/// ArgAttrs - Attribute list for this argument.
AttributeList *ArgAttrs;
};
- // ActOnMethodDeclaration - called for all method declarations.
+ // ActOnMethodDeclaration - called for all method declarations.
virtual DeclPtrTy ActOnMethodDeclaration(
SourceLocation BeginLoc, // location of the + or -.
SourceLocation EndLoc, // location of the ; or {.
@@ -1736,20 +2093,20 @@ public:
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::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.
+ // 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,
+ virtual void ActOnAtEnd(SourceLocation AtEndLoc,
DeclPtrTy classDecl,
- DeclPtrTy *allMethods = 0,
+ DeclPtrTy *allMethods = 0,
unsigned allNum = 0,
- DeclPtrTy *allProperties = 0,
+ DeclPtrTy *allProperties = 0,
unsigned pNum = 0,
DeclGroupPtrTy *allTUVars = 0,
unsigned tuvNum = 0) {
@@ -1763,7 +2120,7 @@ public:
tok::ObjCKeywordKind MethodImplKind) {
return DeclPtrTy();
}
-
+
virtual OwningExprResult ActOnClassPropertyRefExpr(
IdentifierInfo &receiverName,
IdentifierInfo &propertyName,
@@ -1771,17 +2128,17 @@ public:
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,
+ IdentifierInfo *receivingClassName,
Selector Sel,
SourceLocation lbrac, SourceLocation receiverLoc,
SourceLocation selectorLoc,
- SourceLocation rbrac,
+ SourceLocation rbrac,
ExprTy **ArgExprs, unsigned NumArgs) {
return ExprResult();
}
@@ -1790,7 +2147,7 @@ public:
// is obtained from NumArgs.
virtual ExprResult ActOnInstanceMessage(
ExprTy *receiver, Selector Sel,
- SourceLocation lbrac, SourceLocation selectorLoc, SourceLocation rbrac,
+ SourceLocation lbrac, SourceLocation selectorLoc, SourceLocation rbrac,
ExprTy **ArgExprs, unsigned NumArgs) {
return ExprResult();
}
@@ -1807,7 +2164,7 @@ public:
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.
@@ -1819,7 +2176,7 @@ public:
//===----------------------- Obj-C Expressions --------------------------===//
- virtual ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs,
+ virtual ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs,
ExprTy **Strings,
unsigned NumStrings) {
return ExprResult();
@@ -1832,7 +2189,7 @@ public:
SourceLocation RParenLoc) {
return ExprResult();
}
-
+
virtual ExprResult ParseObjCSelectorExpression(Selector Sel,
SourceLocation AtLoc,
SourceLocation SelLoc,
@@ -1840,37 +2197,38 @@ public:
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_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 PragmaLoc,
SourceLocation LParenLoc,
SourceLocation RParenLoc) {
return;
}
-
+
/// ActOnPragmaUnused - Called on well formed #pragma unused(...).
- virtual void ActOnPragmaUnused(ExprTy **Exprs, unsigned NumExprs,
- SourceLocation PragmaLoc,
+ virtual void ActOnPragmaUnused(const Token *Identifiers,
+ unsigned NumIdentifiers, Scope *CurScope,
+ SourceLocation PragmaLoc,
SourceLocation LParenLoc,
SourceLocation RParenLoc) {
return;
@@ -1891,6 +2249,136 @@ public:
SourceLocation AliasNameLoc) {
return;
}
+
+ /// \name Code completion actions
+ ///
+ /// These actions are used to signal that a code-completion token has been
+ /// found at a point in the grammar where the Action implementation is
+ /// likely to be able to provide a list of possible completions, e.g.,
+ /// after the "." or "->" of a member access expression.
+ ///
+ /// \todo Code completion for designated field initializers
+ /// \todo Code completion for call arguments after a function template-id
+ /// \todo Code completion within a call expression, object construction, etc.
+ /// \todo Code completion within a template argument list.
+ /// \todo Code completion for attributes.
+ //@{
+
+ /// \brief Code completion for an ordinary name that occurs within the given
+ /// scope.
+ ///
+ /// \param S the scope in which the name occurs.
+ virtual void CodeCompleteOrdinaryName(Scope *S) { }
+
+ /// \brief Code completion for a member access expression.
+ ///
+ /// This code completion action is invoked when the code-completion token
+ /// is found after the "." or "->" of a member access expression.
+ ///
+ /// \param S the scope in which the member access expression occurs.
+ ///
+ /// \param Base the base expression (e.g., the x in "x.foo") of the member
+ /// access.
+ ///
+ /// \param OpLoc the location of the "." or "->" operator.
+ ///
+ /// \param IsArrow true when the operator is "->", false when it is ".".
+ virtual void CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *Base,
+ SourceLocation OpLoc,
+ bool IsArrow) { }
+
+ /// \brief Code completion for a reference to a tag.
+ ///
+ /// This code completion action is invoked when the code-completion
+ /// token is found after a tag keyword (struct, union, enum, or class).
+ ///
+ /// \param S the scope in which the tag reference occurs.
+ ///
+ /// \param TagSpec an instance of DeclSpec::TST, indicating what kind of tag
+ /// this is (struct/union/enum/class).
+ virtual void CodeCompleteTag(Scope *S, unsigned TagSpec) { }
+
+ /// \brief Code completion for a case statement.
+ ///
+ /// \brief S the scope in which the case statement occurs.
+ virtual void CodeCompleteCase(Scope *S) { }
+
+ /// \brief Code completion for a call.
+ ///
+ /// \brief S the scope in which the call occurs.
+ ///
+ /// \param Fn the expression describing the function being called.
+ ///
+ /// \param Args the arguments to the function call (so far).
+ ///
+ /// \param NumArgs the number of arguments in \p Args.
+ virtual void CodeCompleteCall(Scope *S, ExprTy *Fn,
+ ExprTy **Args, unsigned NumArgs) { }
+
+ /// \brief Code completion for a C++ nested-name-specifier that precedes a
+ /// qualified-id of some form.
+ ///
+ /// This code completion action is invoked when the code-completion token
+ /// is found after the "::" of a nested-name-specifier.
+ ///
+ /// \param S the scope in which the nested-name-specifier occurs.
+ ///
+ /// \param SS the scope specifier ending with "::".
+ ///
+ /// \parame EnteringContext whether we're entering the context of this
+ /// scope specifier.
+ virtual void CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS,
+ bool EnteringContext) { }
+
+ /// \brief Code completion for a C++ "using" declaration or directive.
+ ///
+ /// This code completion action is invoked when the code-completion token is
+ /// found after the "using" keyword.
+ ///
+ /// \param S the scope in which the "using" occurs.
+ virtual void CodeCompleteUsing(Scope *S) { }
+
+ /// \brief Code completion for a C++ using directive.
+ ///
+ /// This code completion action is invoked when the code-completion token is
+ /// found after "using namespace".
+ ///
+ /// \param S the scope in which the "using namespace" occurs.
+ virtual void CodeCompleteUsingDirective(Scope *S) { }
+
+ /// \brief Code completion for a C++ namespace declaration or namespace
+ /// alias declaration.
+ ///
+ /// This code completion action is invoked when the code-completion token is
+ /// found after "namespace".
+ ///
+ /// \param S the scope in which the "namespace" token occurs.
+ virtual void CodeCompleteNamespaceDecl(Scope *S) { }
+
+ /// \brief Code completion for a C++ namespace alias declaration.
+ ///
+ /// This code completion action is invoked when the code-completion token is
+ /// found after "namespace identifier = ".
+ ///
+ /// \param S the scope in which the namespace alias declaration occurs.
+ virtual void CodeCompleteNamespaceAliasDecl(Scope *S) { }
+
+ /// \brief Code completion for an operator name.
+ ///
+ /// This code completion action is invoked when the code-completion token is
+ /// found after the keyword "operator".
+ ///
+ /// \param S the scope in which the operator keyword occurs.
+ virtual void CodeCompleteOperatorName(Scope *S) { }
+
+ /// \brief Code completion for an ObjC property decl.
+ ///
+ /// This code completion action is invoked when the code-completion token is
+ /// found after the left paren.
+ ///
+ /// \param S the scope in which the operator keyword occurs.
+ virtual void CodeCompleteObjCProperty(Scope *S, ObjCDeclSpec &ODS) { }
+ //@}
};
/// MinimalAction - Minimal actions are used by light-weight clients of the
@@ -1913,38 +2401,61 @@ public:
/// getTypeName - This looks at the IdentifierInfo::FETokenInfo field to
/// determine whether the name is a typedef or not in this scope.
+ ///
+ /// \param II the identifier for which we are performing name lookup
+ ///
+ /// \param NameLoc the location of the identifier
+ ///
+ /// \param S the scope in which this name lookup occurs
+ ///
+ /// \param SS if non-NULL, the C++ scope specifier that precedes the
+ /// identifier
+ ///
+ /// \param isClassName whether this is a C++ class-name production, in
+ /// which we can end up referring to a member of an unknown specialization
+ /// that we know (from the grammar) is supposed to be a type. For example,
+ /// this occurs when deriving from "std::vector<T>::allocator_type", where T
+ /// is a template parameter.
+ ///
+ /// \returns the type referred to by this identifier, or NULL if the type
+ /// does not name an identifier.
virtual TypeTy *getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
- Scope *S, const CXXScopeSpec *SS);
+ Scope *S, const CXXScopeSpec *SS,
+ bool isClassName = false);
/// 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);
+ virtual TemplateNameKind isTemplateName(Scope *S,
+ const IdentifierInfo &II,
+ SourceLocation IdLoc,
+ const CXXScopeSpec *SS,
+ TypeTy *ObjectType,
+ bool EnteringContext,
+ TemplateTy &Template);
/// 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
+
+ /// 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,
+ const DeclPtrTy *ProtoRefs,
unsigned NumProtoRefs,
SourceLocation EndProtoLoc,
AttributeList *AttrList);
@@ -1964,15 +2475,15 @@ public:
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;
-};
-
+};
+
/// \brief RAII object that enters a new expression evaluation context.
-class EnterExpressionEvaluationContext {
+class EnterExpressionEvaluationContext {
/// \brief The action object.
Action &Actions;
-
+
/// \brief The previous expression evaluation context.
Action::ExpressionEvaluationContext PrevContext;
@@ -1981,16 +2492,16 @@ class EnterExpressionEvaluationContext {
public:
EnterExpressionEvaluationContext(Action &Actions,
- Action::ExpressionEvaluationContext NewContext)
- : Actions(Actions), CurContext(NewContext) {
+ Action::ExpressionEvaluationContext NewContext)
+ : Actions(Actions), CurContext(NewContext) {
PrevContext = Actions.PushExpressionEvaluationContext(NewContext);
}
-
+
~EnterExpressionEvaluationContext() {
Actions.PopExpressionEvaluationContext(CurContext, PrevContext);
}
};
-
+
} // end namespace clang
#endif
diff --git a/include/clang/Parse/AttributeList.h b/include/clang/Parse/AttributeList.h
index 50ca88a..9fcc845 100644
--- a/include/clang/Parse/AttributeList.h
+++ b/include/clang/Parse/AttributeList.h
@@ -21,7 +21,7 @@
namespace clang {
class IdentifierInfo;
class Action;
-
+
/// AttributeList - Represents GCC's __attribute__ declaration. There are
/// 4 forms of this construct...they are:
///
@@ -47,7 +47,7 @@ public:
ActionBase::ExprTy **args, unsigned numargs,
AttributeList *Next, bool declspec = false);
~AttributeList();
-
+
enum Kind { // Please keep this list alphabetized.
AT_IBOutlet, // Clang-specific.
AT_address_space,
@@ -69,6 +69,7 @@ public:
AT_format,
AT_format_arg,
AT_gnu_inline,
+ AT_malloc,
AT_mode,
AT_nodebug,
AT_noinline,
@@ -101,67 +102,57 @@ public:
IgnoredAttribute,
UnknownAttribute
};
-
+
IdentifierInfo *getName() const { return AttrName; }
SourceLocation getLoc() const { return AttrLoc; }
IdentifierInfo *getParameterName() const { return ParmName; }
bool isDeclspecAttribute() const { return DeclspecAttribute; }
-
+
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(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);
}
@@ -171,6 +162,24 @@ public:
}
};
+/// addAttributeLists - Add two AttributeLists together
+/// The right-hand list is appended to the left-hand list, if any
+/// A pointer to the joined list is returned.
+/// Note: the lists are not left unmodified.
+inline AttributeList* addAttributeLists (AttributeList *Left,
+ AttributeList *Right) {
+ if (!Left)
+ return Right;
+
+ AttributeList *next = Left, *prev;
+ do {
+ prev = next;
+ next = next->getNext();
+ } while (next);
+ prev->setNext(Right);
+ return Left;
+}
+
} // end namespace clang
#endif
diff --git a/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h
index 300602e..51970f18 100644
--- a/include/clang/Parse/DeclSpec.h
+++ b/include/clang/Parse/DeclSpec.h
@@ -25,7 +25,7 @@ namespace clang {
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.
@@ -42,7 +42,7 @@ public:
SCS_private_extern,
SCS_mutable
};
-
+
// type-specifier
enum TSW {
TSW_unspecified,
@@ -50,24 +50,26 @@ public:
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_char16, // C++0x char16_t
+ TST_char32, // C++0x char32_t
TST_int,
TST_float,
TST_double,
@@ -86,9 +88,9 @@ public:
TST_auto, // C++0x auto
TST_error // erroneous type
};
-
+
// type-qualifiers
- enum TQ { // NOTE: These flags must be kept in sync with QualType::TQ.
+ enum TQ { // NOTE: These flags must be kept in sync with Qualifiers::TQ.
TQ_unspecified = 0,
TQ_const = 1,
TQ_restrict = 2,
@@ -104,9 +106,9 @@ public:
PQ_TypeQualifier = 4,
PQ_FunctionSpecifier = 8
};
-
+
private:
-
+
// storage-class-specifier
/*SCS*/unsigned StorageClassSpec : 3;
bool SCS_thread_specified : 1;
@@ -120,50 +122,45 @@ private:
// 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;
-
+ void *TypeRep;
+
// attributes.
AttributeList *AttrList;
-
- // List of protocol qualifiers for objective-c classes. Used for
+
+ // 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 ProtocolLAngleLoc;
+ SourceLocation *ProtocolLocs;
+
// 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:
-
+public:
+
DeclSpec()
: StorageClassSpec(SCS_unspecified),
SCS_thread_specified(false),
@@ -180,26 +177,28 @@ public:
TypeRep(0),
AttrList(0),
ProtocolQualifiers(0),
- NumProtocolQualifiers(0) {
+ NumProtocolQualifiers(0),
+ ProtocolLocs(0) {
}
~DeclSpec() {
delete AttrList;
delete [] ProtocolQualifiers;
+ delete [] ProtocolLocs;
}
// 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; }
@@ -207,18 +206,22 @@ public:
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::TQ Q);
+ static const char *getSpecifierName(DeclSpec::TSS S);
+ static const char *getSpecifierName(DeclSpec::TSC C);
+ static const char *getSpecifierName(DeclSpec::TSW W);
static const char *getSpecifierName(DeclSpec::SCS S);
-
+
// type-qualifiers
/// getTypeQualifiers - Return a set of TQs.
@@ -226,7 +229,7 @@ public:
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; }
@@ -245,7 +248,7 @@ public:
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 ||
@@ -253,68 +256,81 @@ public:
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);
+
+ /// These methods set the specified attribute of the DeclSpec and
+ /// return false if there was no error. If an error occurs (for
+ /// example, if we tried to set "auto" on a spec with "extern"
+ /// already set), they return true and set PrevSpec and DiagID
+ /// such that
+ /// Diag(Loc, DiagID) << PrevSpec;
+ /// will yield a useful result.
+ ///
+ /// TODO: use a more general approach that still allows these
+ /// diagnostics to be ignored when desired.
+ bool SetStorageClassSpec(SCS S, SourceLocation Loc, const char *&PrevSpec,
+ unsigned &DiagID);
+ bool SetStorageClassSpecThread(SourceLocation Loc, const char *&PrevSpec,
+ unsigned &DiagID);
+ bool SetTypeSpecWidth(TSW W, SourceLocation Loc, const char *&PrevSpec,
+ unsigned &DiagID);
+ bool SetTypeSpecComplex(TSC C, SourceLocation Loc, const char *&PrevSpec,
+ unsigned &DiagID);
+ bool SetTypeSpecSign(TSS S, SourceLocation Loc, const char *&PrevSpec,
+ unsigned &DiagID);
bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec,
- void *Rep = 0, bool Owned = false);
+ unsigned &DiagID, void *Rep = 0, bool Owned = false);
bool SetTypeSpecError();
+ void UpdateTypeRep(void *Rep) { TypeRep = Rep; }
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);
+ unsigned &DiagID, const LangOptions &Lang);
+
+ bool SetFunctionSpecInline(SourceLocation Loc, const char *&PrevSpec,
+ unsigned &DiagID);
+ bool SetFunctionSpecVirtual(SourceLocation Loc, const char *&PrevSpec,
+ unsigned &DiagID);
+ bool SetFunctionSpecExplicit(SourceLocation Loc, const char *&PrevSpec,
+ unsigned &DiagID);
+
+ bool SetFriendSpec(SourceLocation Loc, const char *&PrevSpec,
+ unsigned &DiagID);
+
bool isFriendSpecified() const { return Friend_specified; }
SourceLocation getFriendSpecLoc() const { return FriendLoc; }
- /// AddAttributes - contatenates two attribute lists.
+ /// AddAttributes - contatenates two attribute lists.
/// The GCC attribute syntax allows for the following:
///
- /// short __attribute__(( unused, deprecated ))
+ /// 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))
+ /// 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;
+ AttrList = addAttributeLists(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() {
@@ -322,21 +338,20 @@ public:
AttrList = 0;
return AL;
}
-
+
typedef const ActionBase::DeclPtrTy *ProtocolQualifierListTy;
ProtocolQualifierListTy getProtocolQualifiers() const {
return ProtocolQualifiers;
}
+ SourceLocation *getProtocolLocs() const { return ProtocolLocs; }
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;
- }
-
+ SourceLocation getProtocolLAngleLoc() const { return ProtocolLAngleLoc; }
+ void setProtocolQualifiers(const ActionBase::DeclPtrTy *Protos, unsigned NP,
+ SourceLocation *ProtoLocs,
+ SourceLocation LAngleLoc);
+
/// 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.
@@ -347,7 +362,7 @@ public:
bool isMissingDeclaratorOk();
};
-/// ObjCDeclSpec - This class captures information about
+/// ObjCDeclSpec - This class captures information about
/// "declaration specifiers" specific to objective-c
class ObjCDeclSpec {
public:
@@ -361,47 +376,46 @@ public:
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,
+ 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_copy = 0x20,
DQ_PR_nonatomic = 0x40,
DQ_PR_setter = 0x80
};
-
-
+
+
ObjCDeclSpec() : objcDeclQualifier(DQ_None), PropertyAttributes(DQ_PR_noattr),
- GetterName(0), SetterName(0)
- {}
+ GetterName(0), SetterName(0) { }
ObjCDeclQualifier getObjCDeclQualifier() const { return objcDeclQualifier; }
- void setObjCDeclQualifier(ObjCDeclQualifier DQVal)
+ void setObjCDeclQualifier(ObjCDeclQualifier DQVal)
{ objcDeclQualifier = (ObjCDeclQualifier) (objcDeclQualifier | DQVal); }
-
- ObjCPropertyAttributeKind getPropertyAttributes() const
+
+ ObjCPropertyAttributeKind getPropertyAttributes() const
{ return ObjCPropertyAttributeKind(PropertyAttributes); }
- void setPropertyAttributes(ObjCPropertyAttributeKind PRVal) {
- 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
+ // 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
@@ -441,7 +455,7 @@ public:
ScopeRep = 0;
}
};
-
+
/// CachedTokens - A set of tokens that has been cached for later
/// parsing.
typedef llvm::SmallVector<Token, 4> CachedTokens;
@@ -457,7 +471,9 @@ struct DeclaratorChunk {
/// Loc - The place where this type was defined.
SourceLocation Loc;
-
+ /// EndLoc - If valid, the place where this chunck ends.
+ SourceLocation EndLoc;
+
struct PointerTypeInfo {
/// The type qualifiers: const/volatile/restrict.
unsigned TypeQuals : 3;
@@ -481,20 +497,20 @@ struct DeclaratorChunk {
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
@@ -517,7 +533,7 @@ struct DeclaratorChunk {
ParamInfo(IdentifierInfo *ident, SourceLocation iloc,
ActionBase::DeclPtrTy param,
CachedTokens *DefArgTokens = 0)
- : Ident(ident), IdentLoc(iloc), Param(param),
+ : Ident(ident), IdentLoc(iloc), Param(param),
DefaultArgTokens(DefArgTokens) {}
};
@@ -538,7 +554,7 @@ struct DeclaratorChunk {
bool isVariadic : 1;
/// The type qualifiers: const/volatile/restrict.
- /// The qualifier bitmask values are the same as in QualType.
+ /// The qualifier bitmask values are the same as in QualType.
unsigned TypeQuals : 3;
/// hasExceptionSpec - True if the function has an exception specification.
@@ -678,7 +694,7 @@ struct DeclaratorChunk {
I.Ptr.AttrList = AL;
return I;
}
-
+
/// getReference - Return a DeclaratorChunk for a reference.
///
static DeclaratorChunk getReference(unsigned TypeQuals, SourceLocation Loc,
@@ -691,22 +707,23 @@ struct DeclaratorChunk {
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) {
+ SourceLocation LBLoc, SourceLocation RBLoc) {
DeclaratorChunk I;
I.Kind = Array;
- I.Loc = Loc;
+ I.Loc = LBLoc;
+ I.EndLoc = RBLoc;
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,
@@ -717,9 +734,10 @@ struct DeclaratorChunk {
bool hasAnyExceptionSpec,
ActionBase::TypeTy **Exceptions,
SourceRange *ExceptionRanges,
- unsigned NumExceptions, SourceLocation Loc,
+ unsigned NumExceptions,
+ SourceLocation LPLoc, SourceLocation RPLoc,
Declarator &TheDeclarator);
-
+
/// getBlockPointer - Return a DeclaratorChunk for a block.
///
static DeclaratorChunk getBlockPointer(unsigned TypeQuals, SourceLocation Loc,
@@ -775,12 +793,14 @@ public:
/// 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_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
+ DK_Conversion, // A C++ conversion function (identifier is
// "operator " then the type name)
+ DK_TemplateId // A C++ template-id naming a function template
+ // specialization.
};
private:
@@ -794,7 +814,7 @@ private:
///
TheContext Context;
- /// Kind - What kind of declarator this is.
+ /// Kind - What kind of declarator this is.
DeclaratorKind Kind;
/// DeclTypeInfo - This holds each type that the declarator includes as it is
@@ -811,7 +831,7 @@ private:
/// AttrList - Attributes.
AttributeList *AttrList;
-
+
/// AsmLabel - The asm label, if specified.
ActionBase::ExprTy *AsmLabel;
@@ -824,6 +844,10 @@ private:
/// When Kind is DK_Operator, this is the actual overloaded
/// operator that this declarator names.
OverloadedOperatorKind OperatorKind;
+
+ /// When Kind is DK_TemplateId, this is the template-id annotation that
+ /// contains the template and its template arguments.
+ TemplateIdAnnotation *TemplateId;
};
/// InlineParams - This is a local array used for the first function decl
@@ -832,6 +856,9 @@ private:
DeclaratorChunk::ParamInfo InlineParams[16];
bool InlineParamsUsed;
+ /// Extension - true if the declaration is preceded by __extension__.
+ bool Extension : 1;
+
friend struct DeclaratorChunk;
public:
@@ -840,9 +867,9 @@ public:
Kind(DK_Abstract),
InvalidType(DS.getTypeSpecType() == DeclSpec::TST_error),
GroupingParens(false), AttrList(0), AsmLabel(0), Type(0),
- InlineParamsUsed(false) {
+ InlineParamsUsed(false), Extension(false) {
}
-
+
~Declarator() {
clear();
}
@@ -850,7 +877,7 @@ public:
/// 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
@@ -898,6 +925,10 @@ public:
Identifier = 0;
IdentifierLoc = SourceLocation();
Range = DS.getSourceRange();
+
+ if (Kind == DK_TemplateId)
+ TemplateId->Destroy();
+
Kind = DK_Abstract;
for (unsigned i = 0, e = DeclTypeInfo.size(); i != e; ++i)
@@ -909,9 +940,9 @@ public:
Type = 0;
InlineParamsUsed = false;
}
-
+
/// mayOmitIdentifier - Return true if the identifier is either optional or
- /// not allowed. This is true for typenames, prototypes, and template
+ /// not allowed. This is true for typenames, prototypes, and template
/// parameter lists.
bool mayOmitIdentifier() const {
return Context == TypeNameContext || Context == PrototypeContext ||
@@ -934,7 +965,7 @@ public:
Context == BlockContext ||
Context == ForContext);
}
-
+
/// isPastIdentifier - Return true if we have parsed beyond the point where
/// the
bool isPastIdentifier() const { return IdentifierLoc.isValid(); }
@@ -946,7 +977,7 @@ public:
IdentifierInfo *getIdentifier() const { return Identifier; }
SourceLocation getIdentifierLoc() const { return IdentifierLoc; }
-
+
void SetIdentifier(IdentifierInfo *ID, SourceLocation Loc) {
Identifier = ID;
IdentifierLoc = Loc;
@@ -956,7 +987,7 @@ public:
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) {
@@ -1005,6 +1036,16 @@ public:
SetRangeEnd(EndLoc);
}
+ /// \brief Set this declaration to be a C++ template-id, which includes the
+ /// template (or set of function templates) along with template arguments.
+ void setTemplateId(TemplateIdAnnotation *TemplateId) {
+ assert(TemplateId && "NULL template-id provided to declarator?");
+ IdentifierLoc = TemplateId->TemplateNameLoc;
+ Kind = DK_TemplateId;
+ SetRangeEnd(TemplateId->RAngleLoc);
+ this->TemplateId = TemplateId;
+ }
+
/// 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) {
@@ -1016,7 +1057,7 @@ public:
/// 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 {
@@ -1027,14 +1068,14 @@ public:
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));
@@ -1042,31 +1083,50 @@ public:
/// __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;
+ void AddAttributes(AttributeList *alist, SourceLocation LastLoc) {
+ AttrList = addAttributeLists(AttrList, alist);
if (!LastLoc.isInvalid())
SetRangeEnd(LastLoc);
}
-
+
const AttributeList *getAttributes() const { return AttrList; }
AttributeList *getAttributes() { return AttrList; }
+ /// hasAttributes - do we contain any attributes?
+ bool hasAttributes() const {
+ if (getAttributes() || getDeclSpec().getAttributes()) return true;
+ for (unsigned i = 0, e = getNumTypeObjects(); i != e; ++i)
+ if (getTypeObject(i).getAttrs())
+ return true;
+ return false;
+ }
+
void setAsmLabel(ActionBase::ExprTy *E) { AsmLabel = E; }
ActionBase::ExprTy *getAsmLabel() const { return AsmLabel; }
- ActionBase::TypeTy *getDeclaratorIdType() const { return Type; }
+ void setExtension(bool Val = true) { Extension = Val; }
+ bool getExtension() const { return Extension; }
- OverloadedOperatorKind getOverloadedOperator() const { return OperatorKind; }
+ ActionBase::TypeTy *getDeclaratorIdType() const {
+ assert((Kind == DK_Constructor || Kind == DK_Destructor ||
+ Kind == DK_Conversion) && "Declarator kind does not have a type");
+ return Type;
+ }
+ OverloadedOperatorKind getOverloadedOperator() const {
+ assert(Kind == DK_Operator && "Declarator is not an overloaded operator");
+ return OperatorKind;
+ }
+
+ TemplateIdAnnotation *getTemplateId() {
+ assert(Kind == DK_TemplateId && "Declarator is not a template-id");
+ return TemplateId;
+ }
+
void setInvalidType(bool Val = true) { InvalidType = Val; }
- bool isInvalidType() const {
- return InvalidType || DS.getTypeSpecType() == DeclSpec::TST_error;
+ bool isInvalidType() const {
+ return InvalidType || DS.getTypeSpecType() == DeclSpec::TST_error;
}
void setGroupingParens(bool flag) { GroupingParens = flag; }
diff --git a/include/clang/Parse/Designator.h b/include/clang/Parse/Designator.h
index 026286d..255af59 100644
--- a/include/clang/Parse/Designator.h
+++ b/include/clang/Parse/Designator.h
@@ -18,7 +18,7 @@
#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:
@@ -34,7 +34,7 @@ public:
};
private:
DesignatorKind Kind;
-
+
struct FieldDesignatorInfo {
const IdentifierInfo *II;
unsigned DotLoc;
@@ -50,15 +50,15 @@ private:
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; }
@@ -78,7 +78,7 @@ public:
assert(isFieldDesignator() && "Invalid accessor");
return SourceLocation::getFromRawEncoding(FieldInfo.NameLoc);
}
-
+
ActionBase::ExprTy *getArrayIndex() const {
assert(isArrayDesignator() && "Invalid accessor");
return ArrayInfo.Index;
@@ -92,22 +92,22 @@ public:
assert(isArrayRangeDesignator() && "Invalid accessor");
return ArrayRangeInfo.End;
}
-
+
SourceLocation getLBracketLoc() const {
- assert((isArrayDesignator() || isArrayRangeDesignator()) &&
+ assert((isArrayDesignator() || isArrayRangeDesignator()) &&
"Invalid accessor");
if (isArrayDesignator())
return SourceLocation::getFromRawEncoding(ArrayInfo.LBracketLoc);
- else
+ else
return SourceLocation::getFromRawEncoding(ArrayRangeInfo.LBracketLoc);
}
SourceLocation getRBracketLoc() const {
- assert((isArrayDesignator() || isArrayRangeDesignator()) &&
+ assert((isArrayDesignator() || isArrayRangeDesignator()) &&
"Invalid accessor");
if (isArrayDesignator())
return SourceLocation::getFromRawEncoding(ArrayInfo.RBracketLoc);
- else
+ else
return SourceLocation::getFromRawEncoding(ArrayRangeInfo.RBracketLoc);
}
@@ -135,10 +135,10 @@ public:
D.ArrayInfo.RBracketLoc = 0;
return D;
}
-
+
static Designator getArrayRange(ActionBase::ExprTy *Start,
ActionBase::ExprTy *End,
- SourceLocation LBracketLoc,
+ SourceLocation LBracketLoc,
SourceLocation EllipsisLoc) {
Designator D;
D.Kind = ArrayRangeDesignator;
@@ -151,14 +151,14 @@ public:
}
void setRBracketLoc(SourceLocation RBracketLoc) const {
- assert((isArrayDesignator() || isArrayRangeDesignator()) &&
+ 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) {
@@ -173,7 +173,7 @@ public:
return;
}
}
-
+
/// FreeExprs - Release any unclaimed memory for the expressions in this
/// designator.
void FreeExprs(Action &Actions) {
@@ -190,7 +190,7 @@ public:
}
};
-
+
/// Designation - Represent a full designation, which is a sequence of
/// designators. This class is mostly a helper for InitListDesignations.
class Designation {
@@ -198,10 +198,10 @@ class Designation {
/// 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) {}
@@ -218,14 +218,14 @@ public:
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) {
@@ -233,7 +233,7 @@ public:
Designators[i].FreeExprs(Actions);
}
};
-
+
} // end namespace clang
#endif
diff --git a/include/clang/Parse/Ownership.h b/include/clang/Parse/Ownership.h
index 987edfa..9bd69c5 100644
--- a/include/clang/Parse/Ownership.h
+++ b/include/clang/Parse/Ownership.h
@@ -23,7 +23,7 @@
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
@@ -33,29 +33,29 @@ namespace clang {
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; }
};
}
@@ -218,7 +218,7 @@ namespace clang {
/// 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.
+ /// stored in the low bit of the Val pointer.
template<unsigned UID,
typename PtrTy = void*,
bool CompressInvalid = IsResultPtrLowBitFree<UID>::value>
@@ -252,7 +252,7 @@ namespace clang {
uintptr_t PtrWithInvalid;
typedef llvm::PointerLikeTypeTraits<PtrTy> PtrTraits;
public:
- ActionResult(bool Invalid = false)
+ ActionResult(bool Invalid = false)
: PtrWithInvalid(static_cast<uintptr_t>(Invalid)) { }
template<typename ActualExprTy>
@@ -262,17 +262,17 @@ namespace clang {
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);
+ void *VP = reinterpret_cast<void *>(PtrWithInvalid & ~0x01);
return PtrTraits::getFromVoidPointer(VP);
}
@@ -326,8 +326,7 @@ namespace clang {
/// 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
- {
+ class ASTResultMover {
ASTOwningResult<Destroyer> &Moved;
public:
@@ -339,8 +338,7 @@ namespace clang {
/// 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
- {
+ class ASTMultiMover {
ASTMultiPtr<Destroyer> &Moved;
public:
@@ -357,8 +355,7 @@ namespace clang {
/// 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
- {
+ class ASTOwningPtr {
void *Node;
public:
@@ -400,8 +397,7 @@ namespace clang {
#if !defined(DISABLE_SMART_POINTERS)
template <ASTDestroyer Destroyer>
- class ASTOwningResult
- {
+ class ASTOwningResult {
llvm::PointerIntPair<ActionBase*, 1, bool> ActionInv;
void *Ptr;
@@ -505,8 +501,7 @@ namespace clang {
};
#else
template <ASTDestroyer Destroyer>
- class ASTOwningResult
- {
+ class ASTOwningResult {
public:
typedef ActionBase::ActionResult<DestroyerToUID<Destroyer>::UID> DumbResult;
@@ -522,8 +517,7 @@ namespace clang {
ASTOwningResult(const ASTOwningPtr<Destroyer> &o) : Result(o.get()) { }
/// Assignment from a raw pointer. Takes ownership - beware!
- ASTOwningResult & operator =(void *raw)
- {
+ ASTOwningResult & operator =(void *raw) {
Result = raw;
return *this;
}
@@ -563,8 +557,7 @@ namespace clang {
#endif
template <ASTDestroyer Destroyer>
- class ASTMultiPtr
- {
+ class ASTMultiPtr {
#if !defined(DISABLE_SMART_POINTERS)
ActionBase &Actions;
#endif
@@ -584,7 +577,7 @@ namespace clang {
// Either way, a classic C-style hard cast resolves any issue.
static ASTMultiPtr* hack(moving::ASTMultiMover<Destroyer> & source) {
return (ASTMultiPtr*)source.operator->();
- }
+ }
#endif
ASTMultiPtr(ASTMultiPtr&); // DO NOT IMPLEMENT
@@ -608,7 +601,7 @@ namespace clang {
/// Move constructor
ASTMultiPtr(moving::ASTMultiMover<Destroyer> mover)
#if defined(_MSC_VER)
- // Apply the visual C++ hack supplied above.
+ // Apply the visual C++ hack supplied above.
// Last tested with Visual Studio 2008.
: Actions(hack(mover)->Actions), Nodes(hack(mover)->Nodes), Count(hack(mover)->Count) {
#else
@@ -660,7 +653,7 @@ namespace clang {
}
#endif
};
-
+
class ASTTemplateArgsPtr {
#if !defined(DISABLE_SMART_POINTERS)
ActionBase &Actions;
@@ -668,7 +661,7 @@ namespace clang {
void **Args;
bool *ArgIsType;
mutable unsigned Count;
-
+
#if !defined(DISABLE_SMART_POINTERS)
void destroy() {
if (!Count)
@@ -684,16 +677,16 @@ namespace clang {
public:
ASTTemplateArgsPtr(ActionBase &actions, void **args, bool *argIsType,
- unsigned count) :
+ unsigned count) :
#if !defined(DISABLE_SMART_POINTERS)
- Actions(actions),
+ Actions(actions),
#endif
Args(args), ArgIsType(argIsType), Count(count) { }
// FIXME: Lame, not-fully-type-safe emulation of 'move semantics'.
- ASTTemplateArgsPtr(ASTTemplateArgsPtr &Other) :
+ ASTTemplateArgsPtr(ASTTemplateArgsPtr &Other) :
#if !defined(DISABLE_SMART_POINTERS)
- Actions(Other.Actions),
+ Actions(Other.Actions),
#endif
Args(Other.Args), ArgIsType(Other.ArgIsType), Count(Other.Count) {
#if !defined(DISABLE_SMART_POINTERS)
@@ -734,7 +727,7 @@ namespace clang {
void *operator[](unsigned Arg) const { return Args[Arg]; }
- void **release() const {
+ void **release() const {
#if !defined(DISABLE_SMART_POINTERS)
Count = 0;
#endif
@@ -754,7 +747,7 @@ namespace clang {
ASTOwningVector &operator=(ASTOwningVector &); // do not implement
public:
- explicit ASTOwningVector(ActionBase &Actions)
+ explicit ASTOwningVector(ActionBase &Actions)
#if !defined(DISABLE_SMART_POINTERS)
: Actions(Actions), Owned(true)
#endif
@@ -825,8 +818,7 @@ namespace clang {
template <ASTDestroyer Destroyer> inline
ASTOwningPtr<Destroyer>::ASTOwningPtr(const ASTOwningResult<Destroyer> &o)
- : Node(o.get())
- {}
+ : Node(o.get()) { }
// These versions are hopefully no-ops.
template <ASTDestroyer Destroyer> inline
diff --git a/include/clang/Parse/ParseDiagnostic.h b/include/clang/Parse/ParseDiagnostic.h
index fa600dd..c702e2f 100644
--- a/include/clang/Parse/ParseDiagnostic.h
+++ b/include/clang/Parse/ParseDiagnostic.h
@@ -13,7 +13,7 @@
#include "clang/Basic/Diagnostic.h"
namespace clang {
- namespace diag {
+ namespace diag {
enum {
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE) ENUM,
#define PARSESTART
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index e238054..9cb4677 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -38,8 +38,8 @@ 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.
@@ -47,13 +47,13 @@ public:
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
@@ -66,10 +66,10 @@ class Parser {
/// 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;
@@ -83,21 +83,24 @@ class Parser {
llvm::OwningPtr<PragmaHandler> UnusedHandler;
llvm::OwningPtr<PragmaHandler> WeakHandler;
llvm::OwningPtr<clang::CommentHandler> CommentHandler;
-
+
/// 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;
+ /// The "depth" of the template parameters currently being parsed.
+ unsigned TemplateParameterDepth;
+
/// \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(GTIO), OldGreaterThanIsOperator(GTIO) {
GreaterThanIsOperator = Val;
}
@@ -105,7 +108,7 @@ class Parser {
GreaterThanIsOperator = OldGreaterThanIsOperator;
}
};
-
+
public:
Parser(Preprocessor &PP, Action &Actions);
~Parser();
@@ -114,9 +117,9 @@ public:
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;
@@ -163,24 +166,24 @@ public:
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
+
+ /// 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;
@@ -193,7 +196,7 @@ private:
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 {
@@ -213,7 +216,7 @@ private:
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.
@@ -229,7 +232,7 @@ private:
else
return ConsumeToken();
}
-
+
/// ConsumeParen - This consume method keeps the paren count up-to-date.
///
SourceLocation ConsumeParen() {
@@ -242,7 +245,7 @@ private:
PP.Lex(Tok);
return PrevTokLocation;
}
-
+
/// ConsumeBracket - This consume method keeps the bracket count up-to-date.
///
SourceLocation ConsumeBracket() {
@@ -251,12 +254,12 @@ private:
++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() {
@@ -265,12 +268,12 @@ private:
++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
@@ -282,7 +285,7 @@ private:
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.
@@ -315,12 +318,12 @@ private:
/// for expressions in C.
///
/// This returns true if the token was annotated.
- bool TryAnnotateTypeOrScopeToken();
+ bool TryAnnotateTypeOrScopeToken(bool EnteringContext = false);
/// TryAnnotateCXXScopeToken - Like TryAnnotateTypeOrScopeToken but only
/// annotates C++ scope specifiers. This returns true if the token was
/// annotated.
- bool TryAnnotateCXXScopeToken();
+ bool TryAnnotateCXXScopeToken(bool EnteringContext = false);
/// TentativeParsingAction - An object that is used as a kind of "tentative
/// parsing transaction". It gets instantiated to mark the token position and
@@ -359,8 +362,8 @@ private:
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
@@ -369,7 +372,7 @@ private:
/// 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.
///
@@ -382,7 +385,7 @@ private:
//===--------------------------------------------------------------------===//
// 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
@@ -399,7 +402,7 @@ private:
// 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)
+ ParseScope(Parser *Self, unsigned ScopeFlags, bool ManageScope = true)
: Self(Self) {
if (ManageScope)
Self->EnterScope(ScopeFlags);
@@ -423,7 +426,7 @@ private:
/// EnterScope - Start a new scope.
void EnterScope(unsigned ScopeFlags);
-
+
/// ExitScope - Pop a scope off the scope stack.
void ExitScope();
@@ -433,7 +436,7 @@ private:
DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID);
DiagnosticBuilder Diag(const Token &Tok, unsigned DiagID);
- void SuggestParentheses(SourceLocation Loc, unsigned DK,
+ void SuggestParentheses(SourceLocation Loc, unsigned DK,
SourceRange ParenRange);
/// SkipUntil - Read tokens until we get to the specified token, then consume
@@ -441,9 +444,9 @@ private:
/// 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.
+ /// returns false.
bool SkipUntil(tok::TokenKind T, bool StopAtSemi = true,
bool DontConsume = false) {
return SkipUntil(&T, 1, StopAtSemi, DontConsume);
@@ -462,7 +465,13 @@ private:
struct LexedMethod {
Action::DeclPtrTy D;
CachedTokens Toks;
- explicit LexedMethod(Action::DeclPtrTy MD) : D(MD) {}
+
+ /// \brief Whether this member function had an associated template
+ /// scope. When true, D is a template declaration.
+ /// othewise, it is a member function declaration.
+ bool TemplateScope;
+
+ explicit LexedMethod(Action::DeclPtrTy MD) : D(MD), TemplateScope(false) {}
};
/// LateParsedDefaultArgument - Keeps track of a parameter that may
@@ -470,7 +479,7 @@ private:
/// occurs within a member function declaration inside the class
/// (C++ [class.mem]p2).
struct LateParsedDefaultArgument {
- explicit LateParsedDefaultArgument(Action::DeclPtrTy P,
+ explicit LateParsedDefaultArgument(Action::DeclPtrTy P,
CachedTokens *Toks = 0)
: Param(P), Toks(Toks) { }
@@ -483,22 +492,28 @@ private:
/// 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) { }
+ explicit LateParsedMethodDeclaration(Action::DeclPtrTy M)
+ : Method(M), TemplateScope(false) { }
/// Method - The method declaration.
Action::DeclPtrTy Method;
+ /// \brief Whether this member function had an associated template
+ /// scope. When true, D is a template declaration.
+ /// othewise, it is a member function declaration.
+ bool TemplateScope;
+
/// 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.
+ /// scope at the appropriate times.
llvm::SmallVector<LateParsedDefaultArgument, 8> DefaultArgs;
};
@@ -518,8 +533,8 @@ private:
/// 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),
+ ParsingClass(DeclPtrTy TagOrTemplate, bool TopLevelClass)
+ : TopLevelClass(TopLevelClass), TemplateScope(false),
TagOrTemplate(TagOrTemplate) { }
/// \brief Whether this is a "top-level" class, meaning that it is
@@ -556,47 +571,35 @@ private:
return *ClassStack.top();
}
- /// \brief RAII object used to
+ /// \brief RAII object used to
class ParsingClassDefinition {
Parser &P;
bool Popped;
public:
- ParsingClassDefinition(Parser &P, DeclPtrTy TagOrTemplate, bool TopLevelClass)
- : P(P), Popped(false) {
+ ParsingClassDefinition(Parser &P, DeclPtrTy TagOrTemplate, bool TopLevelClass)
+ : P(P), Popped(false) {
P.PushParsingClass(TagOrTemplate, TopLevelClass);
}
/// \brief Pop this class of the stack.
- void Pop() {
+ void Pop() {
assert(!Popped && "Nested class has already been popped");
Popped = true;
P.PopParsingClass();
}
- ~ParsingClassDefinition() {
+ ~ParsingClassDefinition() {
if (!Popped)
- P.PopParsingClass();
+ 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()
+ ParsedTemplateInfo()
: Kind(NonTemplate), TemplateParams(0), TemplateLoc() { }
ParsedTemplateInfo(TemplateParameterLists *TemplateParams,
@@ -604,9 +607,10 @@ private:
: Kind(isSpecialization? ExplicitSpecialization : Template),
TemplateParams(TemplateParams) { }
- explicit ParsedTemplateInfo(SourceLocation TemplateLoc)
- : Kind(ExplicitInstantiation), TemplateParams(0),
- TemplateLoc(TemplateLoc) { }
+ explicit ParsedTemplateInfo(SourceLocation ExternLoc,
+ SourceLocation TemplateLoc)
+ : Kind(ExplicitInstantiation), TemplateParams(0),
+ ExternLoc(ExternLoc), TemplateLoc(TemplateLoc) { }
/// \brief The kind of template we are parsing.
enum {
@@ -624,11 +628,28 @@ private:
/// and explicit specializations.
TemplateParameterLists *TemplateParams;
+ /// \brief The location of the 'extern' keyword, if any, for an explicit
+ /// instantiation
+ SourceLocation ExternLoc;
+
/// \brief The location of the 'template' keyword, for an explicit
/// instantiation.
SourceLocation TemplateLoc;
};
+ void PushParsingClass(DeclPtrTy TagOrTemplate, bool TopLevelClass);
+ void DeallocateParsedClasses(ParsingClass *Class);
+ void PopParsingClass();
+
+ DeclPtrTy ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D,
+ const ParsedTemplateInfo &TemplateInfo);
+ 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);
+
//===--------------------------------------------------------------------===//
// C99 6.9: External Definitions.
DeclGroupPtrTy ParseExternalDeclaration();
@@ -636,7 +657,7 @@ private:
bool isStartOfFunctionDefinition();
DeclGroupPtrTy ParseDeclarationOrFunctionDefinition(
AccessSpecifier AS = AS_none);
-
+
DeclPtrTy ParseFunctionDefinition(Declarator &D,
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo());
void ParseKNRParamDeclarations(Declarator &D);
@@ -646,20 +667,22 @@ private:
OwningExprResult ParseAsmStringLiteral();
// Objective-C External Declarations
- DeclPtrTy ParseObjCAtDirectives();
+ DeclPtrTy ParseObjCAtDirectives();
DeclPtrTy ParseObjCAtClassDeclaration(SourceLocation atLoc);
- DeclPtrTy ParseObjCAtInterfaceDeclaration(SourceLocation atLoc,
+ DeclPtrTy ParseObjCAtInterfaceDeclaration(SourceLocation atLoc,
AttributeList *prefixAttrs = 0);
- void ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl,
+ void ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl,
SourceLocation atLoc);
bool ParseObjCProtocolReferences(llvm::SmallVectorImpl<Action::DeclPtrTy> &P,
- bool WarnOnDeclarations,
+ llvm::SmallVectorImpl<SourceLocation> &PLocs,
+ bool WarnOnDeclarations,
+ SourceLocation &LAngleLoc,
SourceLocation &EndProtoLoc);
void ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl,
tok::ObjCKeywordKind contextKey);
DeclPtrTy ParseObjCAtProtocolDeclaration(SourceLocation atLoc,
AttributeList *prefixAttrs = 0);
-
+
DeclPtrTy ObjCImpDecl;
DeclPtrTy ParseObjCAtImplementationDeclaration(SourceLocation atLoc);
@@ -667,7 +690,7 @@ private:
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 {
@@ -675,7 +698,7 @@ private:
objc_NumQuals
};
IdentifierInfo *ObjCTypeQuals[objc_NumQuals];
-
+
bool isTokIdentifier_in() const;
TypeTy *ParseObjCTypeName(ObjCDeclSpec &DS);
@@ -686,9 +709,9 @@ private:
DeclPtrTy classDecl,
tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword);
void ParseObjCPropertyAttribute(ObjCDeclSpec &DS);
-
+
DeclPtrTy ParseObjCMethodDefinition();
-
+
//===--------------------------------------------------------------------===//
// C99 6.5: Expressions.
@@ -705,13 +728,15 @@ private:
unsigned MinPrec);
OwningExprResult ParseCastExpression(bool isUnaryExpression,
bool isAddressOfOperand,
- bool &NotCastExpr);
+ bool &NotCastExpr,
+ bool parseParenAsExprList);
OwningExprResult ParseCastExpression(bool isUnaryExpression,
- bool isAddressOfOperand = false);
+ bool isAddressOfOperand = false,
+ bool parseParenAsExprList = false);
OwningExprResult ParsePostfixExpressionSuffix(OwningExprResult LHS);
OwningExprResult ParseSizeofAlignofExpression();
OwningExprResult ParseBuiltinPrimaryExpression();
-
+
OwningExprResult ParseExprAfterTypeofSizeofAlignof(const Token &OpTok,
bool &isCastExpr,
TypeTy *&CastTy,
@@ -722,7 +747,11 @@ private:
typedef llvm::SmallVector<SourceLocation, ExprListSize> CommaLocsTy;
/// ParseExpressionList - Used for C/C++ (argument-)expression-list.
- bool ParseExpressionList(ExprListTy &Exprs, CommaLocsTy &CommaLocs);
+ bool ParseExpressionList(ExprListTy &Exprs, CommaLocsTy &CommaLocs,
+ void (Action::*Completer)(Scope *S, void *Data,
+ ExprTy **Args,
+ unsigned NumArgs) = 0,
+ void *Data = 0);
/// ParenParseOption - Control what ParseParenExpression will parse.
enum ParenParseOption {
@@ -733,31 +762,29 @@ private:
};
OwningExprResult ParseParenExpression(ParenParseOption &ExprType,
bool stopIfCastExpr,
+ bool parseAsExprList,
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);
-
+ bool ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
+ TypeTy *ObjectType,
+ bool EnteringContext);
+
//===--------------------------------------------------------------------===//
// C++ 5.2p1: C++ Casts
OwningExprResult ParseCXXCasts();
@@ -811,7 +838,7 @@ private:
//===--------------------------------------------------------------------===//
// C99 6.7.8: Initialization.
-
+
/// ParseInitializer
/// initializer: [C99 6.7.8]
/// assignment-expression
@@ -831,15 +858,15 @@ private:
//===--------------------------------------------------------------------===//
// 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;
}
@@ -906,7 +933,15 @@ private:
//===--------------------------------------------------------------------===//
// C99 6.7: Declarations.
-
+
+ /// A context for parsing declaration specifiers. TODO: flesh this
+ /// out, there are other significant restrictions on specifiers than
+ /// would be best implemented in the parser.
+ enum DeclSpecContext {
+ DSC_normal, // normal context
+ DSC_class // class context, enables 'friend'
+ };
+
DeclGroupPtrTy ParseDeclaration(unsigned Context, SourceLocation &DeclEnd);
DeclGroupPtrTy ParseSimpleDeclaration(unsigned Context,
SourceLocation &DeclEnd,
@@ -920,15 +955,17 @@ private:
bool ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
const ParsedTemplateInfo &TemplateInfo,
AccessSpecifier AS);
- void ParseDeclarationSpecifiers(DeclSpec &DS,
+ void ParseDeclarationSpecifiers(DeclSpec &DS,
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
- AccessSpecifier AS = AS_none);
- bool ParseOptionalTypeSpecifier(DeclSpec &DS, int &isInvalid,
+ AccessSpecifier AS = AS_none,
+ DeclSpecContext DSC = DSC_normal);
+ bool ParseOptionalTypeSpecifier(DeclSpec &DS, bool &isInvalid,
const char *&PrevSpec,
+ unsigned &DiagID,
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo());
void ParseSpecifierQualifierList(DeclSpec &DS);
-
+
void ParseObjCTypeQualifierList(ObjCDeclSpec &DS);
void ParseEnumSpecifier(SourceLocation TagLoc, DeclSpec &DS,
@@ -938,7 +975,7 @@ private:
DeclPtrTy TagDecl);
void ParseStructDeclaration(DeclSpec &DS,
llvm::SmallVectorImpl<FieldDeclarator> &Fields);
-
+
bool isDeclarationSpecifier();
bool isTypeSpecifierQualifier();
bool isTypeQualifier() const;
@@ -1080,20 +1117,29 @@ private:
class DeclaratorScopeObj {
Parser &P;
CXXScopeSpec &SS;
+ bool EnteredScope;
public:
- DeclaratorScopeObj(Parser &p, CXXScopeSpec &ss) : P(p), SS(ss) {}
+ DeclaratorScopeObj(Parser &p, CXXScopeSpec &ss)
+ : P(p), SS(ss), EnteredScope(false) {}
void EnterDeclaratorScope() {
- if (SS.isSet())
- P.Actions.ActOnCXXEnterDeclaratorScope(P.CurScope, SS);
+ assert(!EnteredScope && "Already entered the scope!");
+ assert(SS.isSet() && "C++ scope was not set!");
+ if (P.Actions.ActOnCXXEnterDeclaratorScope(P.CurScope, SS))
+ SS.setScopeRep(0);
+
+ if (!SS.isInvalid())
+ EnteredScope = true;
}
~DeclaratorScopeObj() {
- if (SS.isSet())
+ if (EnteredScope) {
+ assert(SS.isSet() && "C++ scope was cleared ?");
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.
@@ -1109,10 +1155,10 @@ private:
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,
@@ -1120,25 +1166,30 @@ private:
DeclPtrTy ParseUsingDirective(unsigned Context, SourceLocation UsingLoc,
SourceLocation &DeclEnd);
DeclPtrTy ParseUsingDeclaration(unsigned Context, SourceLocation UsingLoc,
- SourceLocation &DeclEnd);
+ SourceLocation &DeclEnd,
+ AccessSpecifier AS = AS_none);
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);
+ TypeResult ParseClassName(SourceLocation &EndLocation,
+ const CXXScopeSpec *SS = 0,
+ bool DestrExpected = false);
void ParseClassSpecifier(tok::TokenKind TagTokKind, SourceLocation TagLoc,
- DeclSpec &DS,
+ DeclSpec &DS,
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
AccessSpecifier AS = AS_none);
void ParseCXXMemberSpecification(SourceLocation StartLoc, unsigned TagType,
DeclPtrTy TagDecl);
- void ParseCXXClassMemberDeclaration(AccessSpecifier AS);
+ void ParseCXXClassMemberDeclaration(AccessSpecifier AS,
+ const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo());
void ParseConstructorInitializer(DeclPtrTy ConstructorDecl);
MemInitResult ParseMemInitializer(DeclPtrTy ConstructorDecl);
+ void HandleMemberFunctionDefaultArgs(Declarator& DeclaratorInfo,
+ DeclPtrTy ThisDecl);
//===--------------------------------------------------------------------===//
// C++ 10: Derived classes [class.derived]
@@ -1169,9 +1220,9 @@ private:
const ParsedTemplateInfo &TemplateInfo,
SourceLocation &DeclEnd,
AccessSpecifier AS=AS_none);
- bool ParseTemplateParameters(unsigned Depth,
+ bool ParseTemplateParameters(unsigned Depth,
TemplateParameterList &TemplateParams,
- SourceLocation &LAngleLoc,
+ SourceLocation &LAngleLoc,
SourceLocation &RAngleLoc);
bool ParseTemplateParameterList(unsigned Depth,
TemplateParameterList &TemplateParams);
@@ -1185,7 +1236,7 @@ private:
typedef llvm::SmallVector<SourceLocation, 16> TemplateArgLocationList;
bool ParseTemplateIdAfterTemplateName(TemplateTy Template,
- SourceLocation TemplateNameLoc,
+ SourceLocation TemplateNameLoc,
const CXXScopeSpec *SS,
bool ConsumeLastToken,
SourceLocation &LAngleLoc,
@@ -1203,7 +1254,8 @@ private:
TemplateArgIsTypeList &TemplateArgIsType,
TemplateArgLocationList &TemplateArgLocations);
void *ParseTemplateArgument(bool &ArgIsType);
- DeclPtrTy ParseExplicitInstantiation(SourceLocation TemplateLoc,
+ DeclPtrTy ParseExplicitInstantiation(SourceLocation ExternLoc,
+ SourceLocation TemplateLoc,
SourceLocation &DeclEnd);
//===--------------------------------------------------------------------===//
diff --git a/include/clang/Parse/Scope.h b/include/clang/Parse/Scope.h
index 84cc5d5..480b94f 100644
--- a/include/clang/Parse/Scope.h
+++ b/include/clang/Parse/Scope.h
@@ -31,15 +31,15 @@ public:
/// 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,
@@ -49,7 +49,7 @@ public:
/// 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
@@ -65,7 +65,7 @@ public:
/// 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
@@ -74,15 +74,15 @@ 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;
@@ -90,7 +90,7 @@ private:
/// 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.
@@ -119,7 +119,7 @@ private:
/// 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
@@ -151,9 +151,9 @@ public:
///
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
+ /// 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())
@@ -164,9 +164,9 @@ public:
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
+ /// 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())
@@ -176,16 +176,16 @@ public:
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; }
+ const Scope *getBlockParent() const { return BlockParent; }
Scope *getTemplateParamParent() { return TemplateParamParent; }
- const Scope *getTemplateParamParent() const { 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(); }
@@ -222,7 +222,7 @@ public:
}
return false;
}
-
+
/// isTemplateParamScope - Return true if this scope is a C++
/// template parameter scope.
bool isTemplateParamScope() const {
@@ -275,7 +275,7 @@ public:
AnyParent = Parent;
Depth = AnyParent ? AnyParent->Depth+1 : 0;
Flags = ScopeFlags;
-
+
if (AnyParent) {
FnParent = AnyParent->FnParent;
BreakParent = AnyParent->BreakParent;
@@ -291,7 +291,7 @@ public:
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;
@@ -304,7 +304,7 @@ public:
Entity = 0;
}
};
-
+
} // end namespace clang
#endif
diff --git a/include/clang/Rewrite/DeltaTree.h b/include/clang/Rewrite/DeltaTree.h
index 7bf9305..7e07965 100644
--- a/include/clang/Rewrite/DeltaTree.h
+++ b/include/clang/Rewrite/DeltaTree.h
@@ -15,7 +15,7 @@
#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
@@ -32,16 +32,16 @@ namespace clang {
// 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;
+ 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);
+ void AddDelta(unsigned FileIndex, int Delta);
};
} // end namespace clang
diff --git a/include/clang/Rewrite/HTMLRewrite.h b/include/clang/Rewrite/HTMLRewrite.h
index f49d49e..f77e0c6 100644
--- a/include/clang/Rewrite/HTMLRewrite.h
+++ b/include/clang/Rewrite/HTMLRewrite.h
@@ -19,36 +19,36 @@
#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.
+ /// 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,
@@ -61,9 +61,9 @@ namespace html {
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,
+ 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
diff --git a/include/clang/Rewrite/RewriteRope.h b/include/clang/Rewrite/RewriteRope.h
index 7faa451..c0bd741 100644
--- a/include/clang/Rewrite/RewriteRope.h
+++ b/include/clang/Rewrite/RewriteRope.h
@@ -14,15 +14,15 @@
#ifndef LLVM_CLANG_REWRITEROPE_H
#define LLVM_CLANG_REWRITEROPE_H
-#include "llvm/ADT/iterator.h"
#include <cstring>
#include <cassert>
+#include <iterator>
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
@@ -30,21 +30,21 @@ namespace clang {
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.
@@ -57,9 +57,9 @@ namespace clang {
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();
@@ -68,11 +68,11 @@ namespace clang {
: 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();
@@ -82,27 +82,27 @@ namespace clang {
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> {
+ public std::iterator<std::forward_iterator_tag, 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
@@ -115,18 +115,18 @@ namespace clang {
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;
@@ -140,11 +140,11 @@ namespace clang {
private:
void MoveToNextPiece();
};
-
+
//===--------------------------------------------------------------------===//
// RopePieceBTree Class
//===--------------------------------------------------------------------===//
-
+
class RopePieceBTree {
void /*RopePieceBTreeNode*/ *Root;
void operator=(const RopePieceBTree &); // DO NOT IMPLEMENT
@@ -152,15 +152,15 @@ namespace clang {
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);
@@ -169,13 +169,13 @@ namespace clang {
//===--------------------------------------------------------------------===//
// 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;
@@ -184,7 +184,7 @@ class RewriteRope {
public:
RewriteRope() : AllocBuffer(0), AllocOffs(AllocChunkSize) {}
- RewriteRope(const RewriteRope &RHS)
+ RewriteRope(const RewriteRope &RHS)
: Chunks(RHS.Chunks), AllocBuffer(0), AllocOffs(AllocChunkSize) {
}
@@ -192,23 +192,23 @@ public:
// 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;
@@ -224,7 +224,7 @@ public:
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
index c3ee017..29e78fa 100644
--- a/include/clang/Rewrite/Rewriter.h
+++ b/include/clang/Rewrite/Rewriter.h
@@ -22,13 +22,14 @@
#include <cstring>
#include <string>
#include "clang/Rewrite/DeltaTree.h"
+#include "llvm/ADT/StringRef.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
@@ -40,7 +41,7 @@ class RewriteBuffer {
/// 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.
@@ -51,50 +52,47 @@ public:
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,
+ void InsertText(unsigned OrigOffset, const llvm::StringRef &Str,
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);
+
+ /// InsertTextBefore - Insert some text before the specified point, where the
+ /// offset in the buffer is specified relative to the original
+ /// SourceBuffer. The text is inserted before the specified location. This is
+ /// method is the same as InsertText with "InsertAfter == false".
+ void InsertTextBefore(unsigned OrigOffset, const llvm::StringRef &Str) {
+ InsertText(OrigOffset, Str, 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);
+
+ /// InsertTextAfter - Insert some text at the specified point, where the
+ /// offset in the buffer is specified relative to the original SourceBuffer.
+ /// The text is inserted after the specified location.
+ void InsertTextAfter(unsigned OrigOffset, const llvm::StringRef &Str) {
+ InsertText(OrigOffset, Str);
}
-
+
/// 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);
-
+ const llvm::StringRef &NewStr);
+
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
@@ -104,7 +102,7 @@ private: // Methods only usable by Rewriter.
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) {
@@ -117,7 +115,7 @@ private: // Methods only usable by Rewriter.
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
@@ -130,14 +128,14 @@ 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) {
@@ -147,7 +145,7 @@ public:
/// 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.
@@ -155,66 +153,45 @@ public:
/// 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 InsertText(SourceLocation Loc, const llvm::StringRef &Str,
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 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);
- }
-
+ bool InsertTextAfter(SourceLocation Loc, const llvm::StringRef &Str) {
+ return InsertText(Loc, Str);
+ }
+
/// InsertText - Insert the specified string at the specified location in the
/// original buffer. This method returns true (and does nothing) if the input
/// location was not rewritable, false otherwise. Text is
/// inserted before any other text that has been previously inserted
/// at the some point.
- bool InsertTextBefore(SourceLocation Loc, 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 InsertTextBefore(SourceLocation Loc, const llvm::StringRef &Str) {
+ return InsertText(Loc, Str, false);
}
- 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);
-
+ const llvm::StringRef &NewStr);
+
/// 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 {
@@ -232,7 +209,7 @@ public:
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
index c8fd0f5..62ea12a 100644
--- a/include/clang/Rewrite/TokenRewriter.h
+++ b/include/clang/Rewrite/TokenRewriter.h
@@ -24,7 +24,7 @@ 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.
@@ -32,17 +32,17 @@ namespace clang {
/// 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:
@@ -50,30 +50,30 @@ namespace clang {
/// 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/CodeCompleteConsumer.h b/include/clang/Sema/CodeCompleteConsumer.h
new file mode 100644
index 0000000..d2f509d
--- /dev/null
+++ b/include/clang/Sema/CodeCompleteConsumer.h
@@ -0,0 +1,332 @@
+//===---- CodeCompleteConsumer.h - Code Completion 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 CodeCompleteConsumer class.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_SEMA_CODECOMPLETECONSUMER_H
+#define LLVM_CLANG_SEMA_CODECOMPLETECONSUMER_H
+
+#include "llvm/ADT/SmallVector.h"
+#include <memory>
+#include <string>
+
+namespace llvm {
+class raw_ostream;
+}
+
+namespace clang {
+
+class FunctionDecl;
+class FunctionType;
+class FunctionTemplateDecl;
+class NamedDecl;
+class NestedNameSpecifier;
+class Sema;
+
+/// \brief A "string" used to describe how code completion can
+/// be performed for an entity.
+///
+/// A code completion string typically shows how a particular entity can be
+/// used. For example, the code completion string for a function would show
+/// the syntax to call it, including the parentheses, placeholders for the
+/// arguments, etc.
+class CodeCompletionString {
+public:
+ /// \brief The different kinds of "chunks" that can occur within a code
+ /// completion string.
+ enum ChunkKind {
+ /// \brief A piece of text that should be placed in the buffer, e.g.,
+ /// parentheses or a comma in a function call.
+ CK_Text,
+ /// \brief A code completion string that is entirely optional. For example,
+ /// an optional code completion string that describes the default arguments
+ /// in a function call.
+ CK_Optional,
+ /// \brief A string that acts as a placeholder for, e.g., a function
+ /// call argument.
+ CK_Placeholder,
+ /// \brief A piece of text that describes something about the result but
+ /// should not be inserted into the buffer.
+ CK_Informative
+ };
+
+ /// \brief One piece of the code completion string.
+ struct Chunk {
+ /// \brief The kind of data stored in this piece of the code completion
+ /// string.
+ ChunkKind Kind;
+
+ union {
+ /// \brief The text string associated with a CK_Text, CK_Placeholder,
+ /// or CK_Informative chunk.
+ /// The string is owned by the chunk and will be deallocated
+ /// (with delete[]) when the chunk is destroyed.
+ const char *Text;
+
+ /// \brief The code completion string associated with a CK_Optional chunk.
+ /// The optional code completion string is owned by the chunk, and will
+ /// be deallocated (with delete) when the chunk is destroyed.
+ CodeCompletionString *Optional;
+ };
+
+ Chunk() : Kind(CK_Text), Text(0) { }
+
+ private:
+ Chunk(ChunkKind Kind, const char *Text);
+
+ public:
+ /// \brief Create a new text chunk.
+ static Chunk CreateText(const char *Text);
+
+ /// \brief Create a new optional chunk.
+ static Chunk CreateOptional(std::auto_ptr<CodeCompletionString> Optional);
+
+ /// \brief Create a new placeholder chunk.
+ static Chunk CreatePlaceholder(const char *Placeholder);
+
+ /// \brief Create a new informative chunk.
+ static Chunk CreateInformative(const char *Informative);
+
+ /// \brief Destroy this chunk, deallocating any memory it owns.
+ void Destroy();
+ };
+
+private:
+ /// \brief The chunks stored in this string.
+ llvm::SmallVector<Chunk, 4> Chunks;
+
+ CodeCompletionString(const CodeCompletionString &); // DO NOT IMPLEMENT
+ CodeCompletionString &operator=(const CodeCompletionString &); // DITTO
+
+public:
+ CodeCompletionString() { }
+ ~CodeCompletionString();
+
+ typedef llvm::SmallVector<Chunk, 4>::const_iterator iterator;
+ iterator begin() const { return Chunks.begin(); }
+ iterator end() const { return Chunks.end(); }
+
+ /// \brief Add a new text chunk.
+ /// The text string will be copied.
+ void AddTextChunk(const char *Text) {
+ Chunks.push_back(Chunk::CreateText(Text));
+ }
+
+ /// \brief Add a new optional chunk.
+ void AddOptionalChunk(std::auto_ptr<CodeCompletionString> Optional) {
+ Chunks.push_back(Chunk::CreateOptional(Optional));
+ }
+
+ /// \brief Add a new placeholder chunk.
+ /// The placeholder text will be copied.
+ void AddPlaceholderChunk(const char *Placeholder) {
+ Chunks.push_back(Chunk::CreatePlaceholder(Placeholder));
+ }
+
+ /// \brief Add a new informative chunk.
+ /// The text will be copied.
+ void AddInformativeChunk(const char *Text) {
+ Chunks.push_back(Chunk::CreateInformative(Text));
+ }
+
+ /// \brief Retrieve a string representation of the code completion string,
+ /// which is mainly useful for debugging.
+ std::string getAsString() const;
+};
+
+/// \brief Abstract interface for a consumer of code-completion
+/// information.
+class CodeCompleteConsumer {
+public:
+ /// \brief Captures a result of code completion.
+ struct Result {
+ /// \brief Describes the kind of result generated.
+ enum ResultKind {
+ RK_Declaration = 0, //< Refers to a declaration
+ RK_Keyword //< Refers to a keyword or symbol.
+ };
+
+ /// \brief The kind of result stored here.
+ ResultKind Kind;
+
+ union {
+ /// \brief When Kind == RK_Declaration, the declaration we are referring
+ /// to.
+ NamedDecl *Declaration;
+
+ /// \brief When Kind == RK_Keyword, the string representing the keyword
+ /// or symbol's spelling.
+ const char *Keyword;
+ };
+
+ /// \brief Describes how good this result is, with zero being the best
+ /// result and progressively higher numbers representing poorer results.
+ unsigned Rank;
+
+ /// \brief Whether this result is hidden by another name.
+ bool Hidden : 1;
+
+ /// \brief Whether this result was found via lookup into a base class.
+ bool QualifierIsInformative : 1;
+
+ /// \brief Whether this declaration is the beginning of a
+ /// nested-name-specifier and, therefore, should be followed by '::'.
+ bool StartsNestedNameSpecifier : 1;
+
+ /// \brief If the result should have a nested-name-specifier, this is it.
+ /// When \c QualifierIsInformative, the nested-name-specifier is
+ /// informative rather than required.
+ NestedNameSpecifier *Qualifier;
+
+ /// \brief Build a result that refers to a declaration.
+ Result(NamedDecl *Declaration, unsigned Rank,
+ NestedNameSpecifier *Qualifier = 0,
+ bool QualifierIsInformative = false)
+ : Kind(RK_Declaration), Declaration(Declaration), Rank(Rank),
+ Hidden(false), QualifierIsInformative(QualifierIsInformative),
+ StartsNestedNameSpecifier(false), Qualifier(Qualifier) { }
+
+ /// \brief Build a result that refers to a keyword or symbol.
+ Result(const char *Keyword, unsigned Rank)
+ : Kind(RK_Keyword), Keyword(Keyword), Rank(Rank), Hidden(false),
+ QualifierIsInformative(0), StartsNestedNameSpecifier(false),
+ Qualifier(0) { }
+
+ /// \brief Retrieve the declaration stored in this result.
+ NamedDecl *getDeclaration() const {
+ assert(Kind == RK_Declaration && "Not a declaration result");
+ return Declaration;
+ }
+
+ /// \brief Retrieve the keyword stored in this result.
+ const char *getKeyword() const {
+ assert(Kind == RK_Keyword && "Not a keyword result");
+ return Keyword;
+ }
+
+ /// \brief Create a new code-completion string that describes how to insert
+ /// this result into a program.
+ CodeCompletionString *CreateCodeCompletionString(Sema &S);
+ };
+
+ class OverloadCandidate {
+ public:
+ /// \brief Describes the type of overload candidate.
+ enum CandidateKind {
+ /// \brief The candidate is a function declaration.
+ CK_Function,
+ /// \brief The candidate is a function template.
+ CK_FunctionTemplate,
+ /// \brief The "candidate" is actually a variable, expression, or block
+ /// for which we only have a function prototype.
+ CK_FunctionType
+ };
+
+ private:
+ /// \brief The kind of overload candidate.
+ CandidateKind Kind;
+
+ union {
+ /// \brief The function overload candidate, available when
+ /// Kind == CK_Function.
+ FunctionDecl *Function;
+
+ /// \brief The function template overload candidate, available when
+ /// Kind == CK_FunctionTemplate.
+ FunctionTemplateDecl *FunctionTemplate;
+
+ /// \brief The function type that describes the entity being called,
+ /// when Kind == CK_FunctionType.
+ const FunctionType *Type;
+ };
+
+ public:
+ OverloadCandidate(FunctionDecl *Function)
+ : Kind(CK_Function), Function(Function) { }
+
+ OverloadCandidate(FunctionTemplateDecl *FunctionTemplateDecl)
+ : Kind(CK_FunctionTemplate), FunctionTemplate(FunctionTemplate) { }
+
+ OverloadCandidate(const FunctionType *Type)
+ : Kind(CK_FunctionType), Type(Type) { }
+
+ /// \brief Determine the kind of overload candidate.
+ CandidateKind getKind() const { return Kind; }
+
+ /// \brief Retrieve the function overload candidate or the templated
+ /// function declaration for a function template.
+ FunctionDecl *getFunction() const;
+
+ /// \brief Retrieve the function template overload candidate.
+ FunctionTemplateDecl *getFunctionTemplate() const {
+ assert(getKind() == CK_FunctionTemplate && "Not a function template");
+ return FunctionTemplate;
+ }
+
+ /// \brief Retrieve the function type of the entity, regardless of how the
+ /// function is stored.
+ const FunctionType *getFunctionType() const;
+
+ /// \brief Create a new code-completion string that describes the function
+ /// signature of this overload candidate.
+ CodeCompletionString *CreateSignatureString(unsigned CurrentArg,
+ Sema &S) const;
+ };
+
+ /// \brief Deregisters and destroys this code-completion consumer.
+ virtual ~CodeCompleteConsumer();
+
+ /// \name Code-completion callbacks
+ //@{
+ /// \brief Process the finalized code-completion results.
+ virtual void ProcessCodeCompleteResults(Result *Results,
+ unsigned NumResults) { }
+
+ /// \brief Process the set of overload candidates.
+ ///
+ /// \param CurrentArg the index of the current argument.
+ ///
+ /// \param Candidates an array of overload candidates.
+ ///
+ /// \param NumCandidates the number of overload candidates
+ virtual void ProcessOverloadCandidates(unsigned CurrentArg,
+ OverloadCandidate *Candidates,
+ unsigned NumCandidates) { }
+ //@}
+};
+
+/// \brief A simple code-completion consumer that prints the results it
+/// receives in a simple format.
+class PrintingCodeCompleteConsumer : public CodeCompleteConsumer {
+ /// \brief The semantic-analysis object to which this code-completion
+ /// consumer is attached.
+ Sema &SemaRef;
+
+ /// \brief The raw output stream.
+ llvm::raw_ostream &OS;
+
+public:
+ /// \brief Create a new printing code-completion consumer that prints its
+ /// results to the given raw output stream.
+ PrintingCodeCompleteConsumer(Sema &S, llvm::raw_ostream &OS)
+ : SemaRef(S), OS(OS) { }
+
+ /// \brief Prints the finalized code-completion results.
+ virtual void ProcessCodeCompleteResults(Result *Results,
+ unsigned NumResults);
+
+ virtual void ProcessOverloadCandidates(unsigned CurrentArg,
+ OverloadCandidate *Candidates,
+ unsigned NumCandidates);
+};
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_SEMA_CODECOMPLETECONSUMER_H
diff --git a/include/clang/Sema/ExternalSemaSource.h b/include/clang/Sema/ExternalSemaSource.h
index 0f0d375..05c5645 100644
--- a/include/clang/Sema/ExternalSemaSource.h
+++ b/include/clang/Sema/ExternalSemaSource.h
@@ -39,13 +39,13 @@ public:
///
/// \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) {
+ virtual std::pair<ObjCMethodList, ObjCMethodList>
+ ReadMethodPool(Selector Sel) {
return std::pair<ObjCMethodList, ObjCMethodList>();
}
-
+
// isa/cast/dyn_cast support
- static bool classof(const ExternalASTSource *Source) {
+ static bool classof(const ExternalASTSource *Source) {
return Source->SemaSource;
}
static bool classof(const ExternalSemaSource *) { return true; }
diff --git a/include/clang/Sema/ParseAST.h b/include/clang/Sema/ParseAST.h
index bdce5e9..8a245d0 100644
--- a/include/clang/Sema/ParseAST.h
+++ b/include/clang/Sema/ParseAST.h
@@ -18,7 +18,9 @@ namespace clang {
class Preprocessor;
class ASTConsumer;
class ASTContext;
-
+ class CodeCompleteConsumer;
+ class Sema;
+
/// \brief Parse the entire file specified, notifying the ASTConsumer as
/// the file is parsed.
///
@@ -28,9 +30,11 @@ namespace clang {
/// \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,
+ void ParseAST(Preprocessor &pp, ASTConsumer *C,
ASTContext &Ctx, bool PrintStats = false,
- bool CompleteTranslationUnit = true);
+ bool CompleteTranslationUnit = true,
+ CodeCompleteConsumer *(*CreateCodeCompleter)(Sema &, void *Data) = 0,
+ void *CreateCodeCompleterData = 0);
} // end namespace clang
diff --git a/include/clang/Sema/SemaConsumer.h b/include/clang/Sema/SemaConsumer.h
index e8219470..b213daf 100644
--- a/include/clang/Sema/SemaConsumer.h
+++ b/include/clang/Sema/SemaConsumer.h
@@ -35,8 +35,8 @@ namespace clang {
virtual void InitializeSema(Sema &S) {}
// isa/cast/dyn_cast support
- static bool classof(const ASTConsumer *Consumer) {
- return Consumer->SemaConsumer;
+ static bool classof(const ASTConsumer *Consumer) {
+ return Consumer->SemaConsumer;
}
static bool classof(const SemaConsumer *) { return true; }
};
diff --git a/include/clang/Sema/SemaDiagnostic.h b/include/clang/Sema/SemaDiagnostic.h
index de92844..d026339 100644
--- a/include/clang/Sema/SemaDiagnostic.h
+++ b/include/clang/Sema/SemaDiagnostic.h
@@ -13,7 +13,7 @@
#include "clang/Basic/Diagnostic.h"
namespace clang {
- namespace diag {
+ namespace diag {
enum {
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE) ENUM,
#define SEMASTART
diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp
index 4df7671..772a884 100644
--- a/lib/AST/APValue.cpp
+++ b/lib/AST/APValue.cpp
@@ -37,7 +37,7 @@ const APValue &APValue::operator=(const APValue &RHS) {
else if (isFloat())
setFloat(RHS.getFloat());
else if (isVector())
- setVector(((Vec*)(void*)RHS.Data)->Elts, RHS.getVectorLength());
+ setVector(((Vec*)(char*)RHS.Data)->Elts, RHS.getVectorLength());
else if (isComplexInt())
setComplexInt(RHS.getComplexIntReal(), RHS.getComplexIntImag());
else if (isComplexFloat())
@@ -49,17 +49,17 @@ const APValue &APValue::operator=(const APValue &RHS) {
void APValue::MakeUninit() {
if (Kind == Int)
- ((APSInt*)(void*)Data)->~APSInt();
+ ((APSInt*)(char*)Data)->~APSInt();
else if (Kind == Float)
- ((APFloat*)(void*)Data)->~APFloat();
+ ((APFloat*)(char*)Data)->~APFloat();
else if (Kind == Vector)
- ((Vec*)(void*)Data)->~Vec();
+ ((Vec*)(char*)Data)->~Vec();
else if (Kind == ComplexInt)
- ((ComplexAPSInt*)(void*)Data)->~ComplexAPSInt();
+ ((ComplexAPSInt*)(char*)Data)->~ComplexAPSInt();
else if (Kind == ComplexFloat)
- ((ComplexAPFloat*)(void*)Data)->~ComplexAPFloat();
+ ((ComplexAPFloat*)(char*)Data)->~ComplexAPFloat();
else if (Kind == LValue) {
- ((LV*)(void*)Data)->~LV();
+ ((LV*)(char*)Data)->~LV();
}
Kind = Uninitialized;
}
@@ -91,7 +91,7 @@ void APValue::print(llvm::raw_ostream &OS) const {
return;
case Vector:
OS << "Vector: " << getVectorElt(0);
- for (unsigned i = 1; i != getVectorLength(); ++i)
+ for (unsigned i = 1; i != getVectorLength(); ++i)
OS << ", " << getVectorElt(i);
return;
case ComplexInt:
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 2877cc3..85b4fd6 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -15,6 +15,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/TypeLoc.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExternalASTSource.h"
#include "clang/AST/RecordLayout.h"
@@ -24,6 +25,8 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "RecordLayoutBuilder.h"
+
using namespace clang;
enum FloatingRank {
@@ -34,15 +37,18 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM,
TargetInfo &t,
IdentifierTable &idents, SelectorTable &sels,
Builtin::Context &builtins,
- bool FreeMem, unsigned size_reserve) :
- GlobalNestedNameSpecifier(0), CFConstantStringTypeDecl(0),
- ObjCFastEnumerationStateTypeDecl(0), SourceMgr(SM), LangOpts(LOpts),
- LoadedExternalComments(false), FreeMemory(FreeMem), Target(t),
+ bool FreeMem, unsigned size_reserve) :
+ GlobalNestedNameSpecifier(0), CFConstantStringTypeDecl(0),
+ ObjCFastEnumerationStateTypeDecl(0), FILEDecl(0), jmp_bufDecl(0),
+ sigjmp_bufDecl(0), SourceMgr(SM), LangOpts(LOpts),
+ LoadedExternalComments(false), FreeMemory(FreeMem), Target(t),
Idents(idents), Selectors(sels),
- BuiltinInfo(builtins), ExternalSource(0), PrintingPolicy(LOpts) {
- if (size_reserve > 0) Types.reserve(size_reserve);
- InitBuiltinTypes();
+ BuiltinInfo(builtins), ExternalSource(0), PrintingPolicy(LOpts) {
+ ObjCIdRedefinitionType = QualType();
+ ObjCClassRedefinitionType = QualType();
+ if (size_reserve > 0) Types.reserve(size_reserve);
TUDecl = TranslationUnitDecl::Create(*this);
+ InitBuiltinTypes();
}
ASTContext::~ASTContext() {
@@ -53,6 +59,13 @@ ASTContext::~ASTContext() {
}
{
+ llvm::FoldingSet<ExtQuals>::iterator
+ I = ExtQualNodes.begin(), E = ExtQualNodes.end();
+ while (I != E)
+ Deallocate(&*I++);
+ }
+
+ {
llvm::DenseMap<const RecordDecl*, const ASTRecordLayout*>::iterator
I = ASTRecordLayouts.begin(), E = ASTRecordLayouts.end();
while (I != E) {
@@ -73,8 +86,8 @@ ASTContext::~ASTContext() {
// Destroy nested-name-specifiers.
for (llvm::FoldingSet<NestedNameSpecifier>::iterator
NNS = NestedNameSpecifiers.begin(),
- NNSEnd = NestedNameSpecifiers.end();
- NNS != NNSEnd;
+ NNSEnd = NestedNameSpecifiers.end();
+ NNS != NNSEnd;
/* Increment in loop */)
(*NNS++).Destroy(*this);
@@ -84,7 +97,7 @@ ASTContext::~ASTContext() {
TUDecl->Destroy(*this);
}
-void
+void
ASTContext::setExternalSource(llvm::OwningPtr<ExternalASTSource> &Source) {
ExternalSource.reset(Source.take());
}
@@ -94,7 +107,7 @@ void ASTContext::PrintStats() const {
fprintf(stderr, " %d types total.\n", (int)Types.size());
unsigned counts[] = {
-#define TYPE(Name, Parent) 0,
+#define TYPE(Name, Parent) 0,
#define ABSTRACT_TYPE(Name, Parent)
#include "clang/AST/TypeNodes.def"
0 // Extra
@@ -114,7 +127,7 @@ void ASTContext::PrintStats() const {
++Idx;
#define ABSTRACT_TYPE(Name, Parent)
#include "clang/AST/TypeNodes.def"
-
+
fprintf(stderr, "Total bytes = %d\n", int(TotalBytes));
if (ExternalSource.get()) {
@@ -125,15 +138,17 @@ void ASTContext::PrintStats() const {
void ASTContext::InitBuiltinType(QualType &R, BuiltinType::Kind K) {
- Types.push_back((R = QualType(new (*this,8) BuiltinType(K),0)).getTypePtr());
+ BuiltinType *Ty = new (*this, TypeAlignment) BuiltinType(K);
+ R = QualType(Ty, 0);
+ Types.push_back(Ty);
}
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.
@@ -147,14 +162,14 @@ void ASTContext::InitBuiltinTypes() {
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);
@@ -169,6 +184,16 @@ void ASTContext::InitBuiltinTypes() {
else // C99
WCharTy = getFromTargetType(Target.getWCharType());
+ if (LangOpts.CPlusPlus) // C++0x 3.9.1p5, extension for C++
+ InitBuiltinType(Char16Ty, BuiltinType::Char16);
+ else // C99
+ Char16Ty = getFromTargetType(Target.getChar16Type());
+
+ if (LangOpts.CPlusPlus) // C++0x 3.9.1p5, extension for C++
+ InitBuiltinType(Char32Ty, BuiltinType::Char32);
+ else // C99
+ Char32Ty = getFromTargetType(Target.getChar32Type());
+
// Placeholder type for functions.
InitBuiltinType(OverloadTy, BuiltinType::Overload);
@@ -179,23 +204,27 @@ void ASTContext::InitBuiltinTypes() {
// expressions.
InitBuiltinType(DependentTy, BuiltinType::Dependent);
- // Placeholder type for C++0x auto declarations whose real type has
+ // Placeholder type for C++0x auto declarations whose real type has
// not yet been deduced.
InitBuiltinType(UndeducedAutoTy, BuiltinType::UndeducedAuto);
-
+
// C99 6.2.5p11.
FloatComplexTy = getComplexType(FloatTy);
DoubleComplexTy = getComplexType(DoubleTy);
LongDoubleComplexTy = getComplexType(LongDoubleTy);
BuiltinVaListType = QualType();
- ObjCIdType = QualType();
- IdStructType = 0;
- ObjCClassType = QualType();
- ClassStructType = 0;
-
+
+ // "Builtin" typedefs set by Sema::ActOnTranslationUnitScope().
+ ObjCIdTypedefType = QualType();
+ ObjCClassTypedefType = QualType();
+
+ // Builtin types for 'id' and 'Class'.
+ InitBuiltinType(ObjCBuiltinIdTy, BuiltinType::ObjCId);
+ InitBuiltinType(ObjCBuiltinClassTy, BuiltinType::ObjCClass);
+
ObjCConstantStringType = QualType();
-
+
// void * type
VoidPtrTy = getPointerType(VoidTy);
@@ -203,14 +232,73 @@ void ASTContext::InitBuiltinTypes() {
InitBuiltinType(NullPtrTy, BuiltinType::NullPtr);
}
+MemberSpecializationInfo *
+ASTContext::getInstantiatedFromStaticDataMember(VarDecl *Var) {
+ assert(Var->isStaticDataMember() && "Not a static data member");
+ llvm::DenseMap<VarDecl *, MemberSpecializationInfo *>::iterator Pos
+ = InstantiatedFromStaticDataMember.find(Var);
+ if (Pos == InstantiatedFromStaticDataMember.end())
+ return 0;
+
+ return Pos->second;
+}
+
+void
+ASTContext::setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl,
+ TemplateSpecializationKind TSK) {
+ assert(Inst->isStaticDataMember() && "Not a static data member");
+ assert(Tmpl->isStaticDataMember() && "Not a static data member");
+ assert(!InstantiatedFromStaticDataMember[Inst] &&
+ "Already noted what static data member was instantiated from");
+ InstantiatedFromStaticDataMember[Inst]
+ = new (*this) MemberSpecializationInfo(Tmpl, TSK);
+}
+
+UnresolvedUsingDecl *
+ASTContext::getInstantiatedFromUnresolvedUsingDecl(UsingDecl *UUD) {
+ llvm::DenseMap<UsingDecl *, UnresolvedUsingDecl *>::iterator Pos
+ = InstantiatedFromUnresolvedUsingDecl.find(UUD);
+ if (Pos == InstantiatedFromUnresolvedUsingDecl.end())
+ return 0;
+
+ return Pos->second;
+}
+
+void
+ASTContext::setInstantiatedFromUnresolvedUsingDecl(UsingDecl *UD,
+ UnresolvedUsingDecl *UUD) {
+ assert(!InstantiatedFromUnresolvedUsingDecl[UD] &&
+ "Already noted what using decl what instantiated from");
+ InstantiatedFromUnresolvedUsingDecl[UD] = UUD;
+}
+
+FieldDecl *ASTContext::getInstantiatedFromUnnamedFieldDecl(FieldDecl *Field) {
+ llvm::DenseMap<FieldDecl *, FieldDecl *>::iterator Pos
+ = InstantiatedFromUnnamedFieldDecl.find(Field);
+ if (Pos == InstantiatedFromUnnamedFieldDecl.end())
+ return 0;
+
+ return Pos->second;
+}
+
+void ASTContext::setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst,
+ FieldDecl *Tmpl) {
+ assert(!Inst->getDeclName() && "Instantiated field decl is not unnamed");
+ assert(!Tmpl->getDeclName() && "Template field decl is not unnamed");
+ assert(!InstantiatedFromUnnamedFieldDecl[Inst] &&
+ "Already noted what unnamed field was instantiated from");
+
+ InstantiatedFromUnnamedFieldDecl[Inst] = Tmpl;
+}
+
namespace {
- class BeforeInTranslationUnit
+ class BeforeInTranslationUnit
: std::binary_function<SourceRange, SourceRange, bool> {
SourceManager *SourceMgr;
-
+
public:
explicit BeforeInTranslationUnit(SourceManager *SM) : SourceMgr(SM) { }
-
+
bool operator()(SourceRange X, SourceRange Y) {
return SourceMgr->isBeforeInTranslationUnit(X.getBegin(), Y.getBegin());
}
@@ -226,14 +314,14 @@ namespace {
/// \param Member whether we want to check whether this is a member comment
/// (which requires a < after the Doxygen-comment delimiter). Otherwise,
/// we only return true when we find a non-member comment.
-static bool
-isDoxygenComment(SourceManager &SourceMgr, SourceRange Comment,
+static bool
+isDoxygenComment(SourceManager &SourceMgr, SourceRange Comment,
bool Member = false) {
- const char *BufferStart
+ const char *BufferStart
= SourceMgr.getBufferData(SourceMgr.getFileID(Comment.getBegin())).first;
const char *Start = BufferStart + SourceMgr.getFileOffset(Comment.getBegin());
const char* End = BufferStart + SourceMgr.getFileOffset(Comment.getEnd());
-
+
if (End - Start < 4)
return false;
@@ -247,32 +335,32 @@ isDoxygenComment(SourceManager &SourceMgr, SourceRange Comment,
}
/// \brief Retrieve the comment associated with the given declaration, if
-/// it has one.
+/// it has one.
const char *ASTContext::getCommentForDecl(const Decl *D) {
if (!D)
return 0;
-
+
// Check whether we have cached a comment string for this declaration
// already.
- llvm::DenseMap<const Decl *, std::string>::iterator Pos
+ llvm::DenseMap<const Decl *, std::string>::iterator Pos
= DeclComments.find(D);
if (Pos != DeclComments.end())
return Pos->second.c_str();
- // If we have an external AST source and have not yet loaded comments from
+ // If we have an external AST source and have not yet loaded comments from
// that source, do so now.
if (ExternalSource && !LoadedExternalComments) {
std::vector<SourceRange> LoadedComments;
ExternalSource->ReadComments(LoadedComments);
-
+
if (!LoadedComments.empty())
Comments.insert(Comments.begin(), LoadedComments.begin(),
LoadedComments.end());
-
+
LoadedExternalComments = true;
}
-
- // If there are no comments anywhere, we won't find anything.
+
+ // If there are no comments anywhere, we won't find anything.
if (Comments.empty())
return 0;
@@ -284,17 +372,17 @@ const char *ASTContext::getCommentForDecl(const Decl *D) {
// Find the comment that occurs just before this declaration.
std::vector<SourceRange>::iterator LastComment
- = std::lower_bound(Comments.begin(), Comments.end(),
+ = std::lower_bound(Comments.begin(), Comments.end(),
SourceRange(DeclStartLoc),
BeforeInTranslationUnit(&SourceMgr));
-
+
// Decompose the location for the start of the declaration and find the
// beginning of the file buffer.
- std::pair<FileID, unsigned> DeclStartDecomp
+ std::pair<FileID, unsigned> DeclStartDecomp
= SourceMgr.getDecomposedLoc(DeclStartLoc);
- const char *FileBufferStart
+ const char *FileBufferStart
= SourceMgr.getBufferData(DeclStartDecomp.first).first;
-
+
// First check whether we have a comment for a member.
if (LastComment != Comments.end() &&
!isa<TagDecl>(D) && !isa<NamespaceDecl>(D) &&
@@ -303,19 +391,19 @@ const char *ASTContext::getCommentForDecl(const Decl *D) {
= SourceMgr.getDecomposedLoc(LastComment->getEnd());
if (DeclStartDecomp.first == LastCommentEndDecomp.first &&
SourceMgr.getLineNumber(DeclStartDecomp.first, DeclStartDecomp.second)
- == SourceMgr.getLineNumber(LastCommentEndDecomp.first,
+ == SourceMgr.getLineNumber(LastCommentEndDecomp.first,
LastCommentEndDecomp.second)) {
// The Doxygen member comment comes after the declaration starts and
// is on the same line and in the same file as the declaration. This
// is the comment we want.
std::string &Result = DeclComments[D];
- Result.append(FileBufferStart +
- SourceMgr.getFileOffset(LastComment->getBegin()),
+ Result.append(FileBufferStart +
+ SourceMgr.getFileOffset(LastComment->getBegin()),
FileBufferStart + LastCommentEndDecomp.second + 1);
return Result.c_str();
}
}
-
+
if (LastComment == Comments.begin())
return 0;
--LastComment;
@@ -323,33 +411,33 @@ const char *ASTContext::getCommentForDecl(const Decl *D) {
// Decompose the end of the comment.
std::pair<FileID, unsigned> LastCommentEndDecomp
= SourceMgr.getDecomposedLoc(LastComment->getEnd());
-
+
// If the comment and the declaration aren't in the same file, then they
// aren't related.
if (DeclStartDecomp.first != LastCommentEndDecomp.first)
return 0;
-
+
// Check that we actually have a Doxygen comment.
if (!isDoxygenComment(SourceMgr, *LastComment))
return 0;
-
+
// Compute the starting line for the declaration and for the end of the
// comment (this is expensive).
- unsigned DeclStartLine
+ unsigned DeclStartLine
= SourceMgr.getLineNumber(DeclStartDecomp.first, DeclStartDecomp.second);
unsigned CommentEndLine
- = SourceMgr.getLineNumber(LastCommentEndDecomp.first,
+ = SourceMgr.getLineNumber(LastCommentEndDecomp.first,
LastCommentEndDecomp.second);
-
+
// If the comment does not end on the line prior to the declaration, then
// the comment is not associated with the declaration at all.
if (CommentEndLine + 1 != DeclStartLine)
return 0;
-
+
// We have a comment, but there may be more comments on the previous lines.
// Keep looking so long as the comments are still Doxygen comments and are
// still adjacent.
- unsigned ExpectedLine
+ unsigned ExpectedLine
= SourceMgr.getSpellingLineNumber(LastComment->getBegin()) - 1;
std::vector<SourceRange>::iterator FirstComment = LastComment;
while (FirstComment != Comments.begin()) {
@@ -357,31 +445,31 @@ const char *ASTContext::getCommentForDecl(const Decl *D) {
--FirstComment;
std::pair<FileID, unsigned> Decomp
= SourceMgr.getDecomposedLoc(FirstComment->getEnd());
-
+
// If this previous comment is in a different file, we're done.
if (Decomp.first != DeclStartDecomp.first) {
++FirstComment;
break;
}
-
+
// If this comment is not a Doxygen comment, we're done.
if (!isDoxygenComment(SourceMgr, *FirstComment)) {
++FirstComment;
break;
}
-
+
// If the line number is not what we expected, we're done.
unsigned Line = SourceMgr.getLineNumber(Decomp.first, Decomp.second);
if (Line != ExpectedLine) {
++FirstComment;
break;
}
-
+
// Set the next expected line number.
- ExpectedLine
+ ExpectedLine
= SourceMgr.getSpellingLineNumber(FirstComment->getBegin()) - 1;
}
-
+
// The iterator range [FirstComment, LastComment] contains all of the
// BCPL comments that, together, are associated with this declaration.
// Form a single comment block string for this declaration that concatenates
@@ -396,10 +484,10 @@ const char *ASTContext::getCommentForDecl(const Decl *D) {
FileBufferStart + DecompEnd.second + 1);
++FirstComment;
}
-
+
// Append the last comment line.
- Result.append(FileBufferStart +
- SourceMgr.getFileOffset(LastComment->getBegin()),
+ Result.append(FileBufferStart +
+ SourceMgr.getFileOffset(LastComment->getBegin()),
FileBufferStart + LastCommentEndDecomp.second + 1);
return Result.c_str();
}
@@ -411,7 +499,7 @@ const char *ASTContext::getCommentForDecl(const Decl *D) {
/// 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();
+ const BuiltinType *BT = T->getAs<BuiltinType>();
assert(BT && "Not a floating point type!");
switch (BT->getKind()) {
default: assert(0 && "Not a floating point type!");
@@ -421,7 +509,7 @@ const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const {
}
}
-/// getDeclAlign - Return a conservative estimate of the alignment of the
+/// getDeclAlignInBytes - 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) {
@@ -432,7 +520,7 @@ unsigned ASTContext::getDeclAlignInBytes(const Decl *D) {
if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
QualType T = VD->getType();
- if (const ReferenceType* RT = T->getAsReferenceType()) {
+ if (const ReferenceType* RT = T->getAs<ReferenceType>()) {
unsigned AS = RT->getPointeeType().getAddressSpace();
Align = Target.getPointerAlign(AS);
} else if (!T->isIncompleteType() && !T->isFunctionType()) {
@@ -449,6 +537,10 @@ unsigned ASTContext::getDeclAlignInBytes(const Decl *D) {
/// getTypeSize - Return the size of the specified type, in bits. This method
/// does not work on incomplete types.
+///
+/// FIXME: Pointers into different addr spaces could have different sizes and
+/// alignment requirements: getPointerInfo should take an AddrSpace, this
+/// should take a QualType, &c.
std::pair<uint64_t, unsigned>
ASTContext::getTypeInfo(const Type *T) {
uint64_t Width=0;
@@ -462,6 +554,10 @@ ASTContext::getTypeInfo(const Type *T) {
assert(false && "Should not see dependent types");
break;
+ case Type::ObjCProtocolList:
+ assert(false && "Should not see protocol list types");
+ break;
+
case Type::FunctionNoProto:
case Type::FunctionProto:
// GCC extension: alignof(function) = 32 bits
@@ -475,9 +571,11 @@ ASTContext::getTypeInfo(const Type *T) {
Align = getTypeAlign(cast<ArrayType>(T)->getElementType());
break;
+ case Type::ConstantArrayWithExpr:
+ case Type::ConstantArrayWithoutExpr:
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;
@@ -485,7 +583,7 @@ ASTContext::getTypeInfo(const Type *T) {
}
case Type::ExtVector:
case Type::Vector: {
- std::pair<uint64_t, unsigned> EltInfo =
+ std::pair<uint64_t, unsigned> EltInfo =
getTypeInfo(cast<VectorType>(T)->getElementType());
Width = EltInfo.first*cast<VectorType>(T)->getNumElements();
Align = Width;
@@ -520,6 +618,14 @@ ASTContext::getTypeInfo(const Type *T) {
Width = Target.getWCharWidth();
Align = Target.getWCharAlign();
break;
+ case BuiltinType::Char16:
+ Width = Target.getChar16Width();
+ Align = Target.getChar16Align();
+ break;
+ case BuiltinType::Char32:
+ Width = Target.getChar32Width();
+ Align = Target.getChar32Align();
+ break;
case BuiltinType::UShort:
case BuiltinType::Short:
Width = Target.getShortWidth();
@@ -570,12 +676,7 @@ ASTContext::getTypeInfo(const Type *T) {
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::ObjCObjectPointer:
- case Type::ObjCQualifiedInterface:
Width = Target.getPointerWidth(0);
Align = Target.getPointerAlign(0);
break;
@@ -604,7 +705,7 @@ ASTContext::getTypeInfo(const Type *T) {
// 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 =
+ std::pair<uint64_t, unsigned> PtrDiffInfo =
getTypeInfo(getPointerDiffType());
Width = PtrDiffInfo.first;
if (Pointee->isFunctionType())
@@ -615,7 +716,7 @@ ASTContext::getTypeInfo(const Type *T) {
case Type::Complex: {
// Complex types have the same alignment as their elements, but twice the
// size.
- std::pair<uint64_t, unsigned> EltInfo =
+ std::pair<uint64_t, unsigned> EltInfo =
getTypeInfo(cast<ComplexType>(T)->getElementType());
Width = EltInfo.first*2;
Align = EltInfo.second;
@@ -637,7 +738,7 @@ ASTContext::getTypeInfo(const Type *T) {
Align = 1;
break;
}
-
+
if (const EnumType *ET = dyn_cast<EnumType>(TT))
return getTypeInfo(ET->getDecl()->getIntegerType());
@@ -648,6 +749,10 @@ ASTContext::getTypeInfo(const Type *T) {
break;
}
+ case Type::Elaborated: {
+ return getTypeInfo(cast<ElaboratedType>(T)->getUnderlyingType().getTypePtr());
+ }
+
case Type::Typedef: {
const TypedefDecl *Typedef = cast<TypedefType>(T)->getDecl();
if (const AlignedAttr *Aligned = Typedef->getAttr<AlignedAttr>()) {
@@ -671,16 +776,16 @@ ASTContext::getTypeInfo(const Type *T) {
case Type::QualifiedName:
return getTypeInfo(cast<QualifiedNameType>(T)->getNamedType().getTypePtr());
-
+
case Type::TemplateSpecialization:
- assert(getCanonicalType(T) != T &&
+ 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);
}
@@ -693,7 +798,7 @@ 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())
+ if (const ComplexType* CT = T->getAs<ComplexType>())
T = CT->getElementType().getTypePtr();
if (T->isSpecificBuiltinType(BuiltinType::Double) ||
T->isSpecificBuiltinType(BuiltinType::LongLong))
@@ -702,102 +807,6 @@ unsigned ASTContext::getPreferredTypeAlign(const Type *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) {
@@ -836,7 +845,7 @@ void ASTContext::CollectProtocolSynthesizedIvars(const ObjCProtocolDecl *PD,
E = PD->prop_end(); 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)
@@ -876,8 +885,7 @@ unsigned ASTContext::CountProtocolSynthesizedIvars(const ObjCProtocolDecl *PD) {
return count;
}
-unsigned ASTContext::CountSynthesizedIvars(const ObjCInterfaceDecl *OI)
-{
+unsigned ASTContext::CountSynthesizedIvars(const ObjCInterfaceDecl *OI) {
unsigned count = 0;
for (ObjCInterfaceDecl::prop_iterator I = OI->prop_begin(),
E = OI->prop_end(); I != E; ++I) {
@@ -894,6 +902,52 @@ unsigned ASTContext::CountSynthesizedIvars(const ObjCInterfaceDecl *OI)
return count;
}
+/// \brief Get the implementation of ObjCInterfaceDecl,or NULL if none exists.
+ObjCImplementationDecl *ASTContext::getObjCImplementation(ObjCInterfaceDecl *D) {
+ llvm::DenseMap<ObjCContainerDecl*, ObjCImplDecl*>::iterator
+ I = ObjCImpls.find(D);
+ if (I != ObjCImpls.end())
+ return cast<ObjCImplementationDecl>(I->second);
+ return 0;
+}
+/// \brief Get the implementation of ObjCCategoryDecl, or NULL if none exists.
+ObjCCategoryImplDecl *ASTContext::getObjCImplementation(ObjCCategoryDecl *D) {
+ llvm::DenseMap<ObjCContainerDecl*, ObjCImplDecl*>::iterator
+ I = ObjCImpls.find(D);
+ if (I != ObjCImpls.end())
+ return cast<ObjCCategoryImplDecl>(I->second);
+ return 0;
+}
+
+/// \brief Set the implementation of ObjCInterfaceDecl.
+void ASTContext::setObjCImplementation(ObjCInterfaceDecl *IFaceD,
+ ObjCImplementationDecl *ImplD) {
+ assert(IFaceD && ImplD && "Passed null params");
+ ObjCImpls[IFaceD] = ImplD;
+}
+/// \brief Set the implementation of ObjCCategoryDecl.
+void ASTContext::setObjCImplementation(ObjCCategoryDecl *CatD,
+ ObjCCategoryImplDecl *ImplD) {
+ assert(CatD && ImplD && "Passed null params");
+ ObjCImpls[CatD] = ImplD;
+}
+
+/// \brief Allocate an uninitialized DeclaratorInfo.
+///
+/// The caller should initialize the memory held by DeclaratorInfo using
+/// the TypeLoc wrappers.
+///
+/// \param T the type that will be the basis for type source info. This type
+/// should refer to how the declarator was written in source code, not to
+/// what type semantic analysis resolved the declarator to.
+DeclaratorInfo *ASTContext::CreateDeclaratorInfo(QualType T) {
+ unsigned DataSize = TypeLoc::getFullDataSizeForType(T);
+ DeclaratorInfo *DInfo =
+ (DeclaratorInfo*)BumpAlloc.Allocate(sizeof(DeclaratorInfo) + DataSize, 8);
+ new (DInfo) DeclaratorInfo(T);
+ return DInfo;
+}
+
/// getInterfaceLayoutImpl - Get or compute information about the
/// layout of the given interface.
///
@@ -905,14 +959,14 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D,
assert(!D->isForwardDecl() && "Invalid interface decl!");
// Look up this layout, if already laid out, return what we have.
- ObjCContainerDecl *Key =
+ 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) {
+ unsigned FieldCount = D->ivar_size();
unsigned SynthCount = CountSynthesizedIvars(D);
FieldCount += SynthCount;
// If there aren't any sythesized ivars then reuse the interface
@@ -923,40 +977,10 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D,
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);
+ const ASTRecordLayout *NewEntry =
+ ASTRecordLayoutBuilder::ComputeLayout(*this, D, Impl);
+ ObjCLayouts[Key] = NewEntry;
- 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;
- llvm::SmallVector<ObjCIvarDecl*, 16> Ivars;
- ShallowCollectObjCIvars(D, Ivars, Impl);
- 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;
}
@@ -978,37 +1002,15 @@ const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) {
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];
+ // Note that we can't save a reference to the entry because this function
+ // is recursive.
+ 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(), D->field_end()));
- 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(),
- FieldEnd = D->field_end();
- 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);
+ const ASTRecordLayout *NewEntry =
+ ASTRecordLayoutBuilder::ComputeLayout(*this, D);
+ ASTRecordLayouts[D] = NewEntry;
+
return *NewEntry;
}
@@ -1016,102 +1018,111 @@ const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) {
// Type creation/memoization methods
//===----------------------------------------------------------------------===//
+QualType ASTContext::getExtQualType(const Type *TypeNode, Qualifiers Quals) {
+ unsigned Fast = Quals.getFastQualifiers();
+ Quals.removeFastQualifiers();
+
+ // Check if we've already instantiated this type.
+ llvm::FoldingSetNodeID ID;
+ ExtQuals::Profile(ID, TypeNode, Quals);
+ void *InsertPos = 0;
+ if (ExtQuals *EQ = ExtQualNodes.FindNodeOrInsertPos(ID, InsertPos)) {
+ assert(EQ->getQualifiers() == Quals);
+ QualType T = QualType(EQ, Fast);
+ return T;
+ }
+
+ ExtQuals *New = new (*this, TypeAlignment) ExtQuals(*this, TypeNode, Quals);
+ ExtQualNodes.InsertNode(New, InsertPos);
+ QualType T = QualType(New, Fast);
+ return T;
+}
+
+QualType ASTContext::getVolatileType(QualType T) {
+ QualType CanT = getCanonicalType(T);
+ if (CanT.isVolatileQualified()) return T;
+
+ QualifierCollector Quals;
+ const Type *TypeNode = Quals.strip(T);
+ Quals.addVolatile();
+
+ return getExtQualType(TypeNode, Quals);
+}
+
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 we are composing extended qualifiers together, merge together
+ // into one ExtQuals node.
+ QualifierCollector Quals;
+ const Type *TypeNode = Quals.strip(T);
- // 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);
+ // If this type already has an address space specified, it cannot get
+ // another one.
+ assert(!Quals.hasAddressSpace() &&
+ "Type cannot be in multiple addr spaces!");
+ Quals.addAddressSpace(AddressSpace);
+
+ return getExtQualType(TypeNode, Quals);
}
QualType ASTContext::getObjCGCQualType(QualType T,
- QualType::GCAttrTypes GCAttr) {
+ Qualifiers::GC GCAttr) {
QualType CanT = getCanonicalType(T);
if (CanT.getObjCGCAttr() == GCAttr)
return T;
-
+
if (T->isPointerType()) {
- QualType Pointee = T->getAsPointerType()->getPointeeType();
- if (Pointee->isPointerType()) {
+ QualType Pointee = T->getAs<PointerType>()->getPointeeType();
+ if (Pointee->isAnyPointerType()) {
QualType ResultType = getObjCGCQualType(Pointee, GCAttr);
return getPointerType(ResultType);
}
}
- // 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;
+
+ // If we are composing extended qualifiers together, merge together
+ // into one ExtQuals node.
+ QualifierCollector Quals;
+ const Type *TypeNode = Quals.strip(T);
+
+ // If this type already has an ObjCGC specified, it cannot get
+ // another one.
+ assert(!Quals.hasObjCGCAttr() &&
+ "Type cannot have multiple ObjCGCs!");
+ Quals.addObjCGCAttr(GCAttr);
+
+ return getExtQualType(TypeNode, Quals);
+}
+
+QualType ASTContext::getNoReturnType(QualType T) {
+ QualType ResultType;
+ if (T->isPointerType()) {
+ QualType Pointee = T->getAs<PointerType>()->getPointeeType();
+ ResultType = getNoReturnType(Pointee);
+ ResultType = getPointerType(ResultType);
+ } else if (T->isBlockPointerType()) {
+ QualType Pointee = T->getAs<BlockPointerType>()->getPointeeType();
+ ResultType = getNoReturnType(Pointee);
+ ResultType = getBlockPointerType(ResultType);
+ } else {
+ assert (T->isFunctionType()
+ && "can't noreturn qualify non-pointer to function or block type");
+
+ if (const FunctionNoProtoType *FNPT = T->getAs<FunctionNoProtoType>()) {
+ ResultType = getFunctionNoProtoType(FNPT->getResultType(), true);
+ } else {
+ const FunctionProtoType *F = T->getAs<FunctionProtoType>();
+ ResultType
+ = getFunctionType(F->getResultType(), F->arg_type_begin(),
+ F->getNumArgs(), F->isVariadic(), F->getTypeQuals(),
+ F->hasExceptionSpec(), F->hasAnyExceptionSpec(),
+ F->getNumExceptions(), F->exception_begin(), true);
+ }
}
- ExtQualType *New =
- new (*this, 8) ExtQualType(TypeNode, Canonical, AddressSpace, GCAttr);
- ExtQualTypes.InsertNode(New, InsertPos);
- Types.push_back(New);
- return QualType(New, CVRQuals);
+
+ return getQualifiedType(ResultType, T.getQualifiers());
}
/// getComplexType - Return the uniqued reference to the type for a complex
@@ -1121,22 +1132,22 @@ QualType ASTContext::getComplexType(QualType T) {
// 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);
+ ComplexType *New = new (*this, TypeAlignment) ComplexType(T, Canonical);
Types.push_back(New);
ComplexTypes.InsertNode(New, InsertPos);
return QualType(New, 0);
@@ -1158,28 +1169,28 @@ QualType ASTContext::getPointerType(QualType T) {
// 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);
+ PointerType *New = new (*this, TypeAlignment) PointerType(T, Canonical);
Types.push_back(New);
PointerTypes.InsertNode(New, InsertPos);
return QualType(New, 0);
}
-/// getBlockPointerType - Return the uniqued reference to the type for
+/// 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");
@@ -1187,24 +1198,25 @@ QualType ASTContext::getBlockPointerType(QualType T) {
// 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
+
+ // 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);
+ BlockPointerType *New
+ = new (*this, TypeAlignment) BlockPointerType(T, Canonical);
Types.push_back(New);
BlockPointerTypes.InsertNode(New, InsertPos);
return QualType(New, 0);
@@ -1235,7 +1247,8 @@ QualType ASTContext::getLValueReferenceType(QualType T) {
assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
}
- LValueReferenceType *New = new (*this,8) LValueReferenceType(T, Canonical);
+ LValueReferenceType *New
+ = new (*this, TypeAlignment) LValueReferenceType(T, Canonical);
Types.push_back(New);
LValueReferenceTypes.InsertNode(New, InsertPos);
return QualType(New, 0);
@@ -1266,7 +1279,8 @@ QualType ASTContext::getRValueReferenceType(QualType T) {
assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
}
- RValueReferenceType *New = new (*this,8) RValueReferenceType(T, Canonical);
+ RValueReferenceType *New
+ = new (*this, TypeAlignment) RValueReferenceType(T, Canonical);
Types.push_back(New);
RValueReferenceTypes.InsertNode(New, InsertPos);
return QualType(New, 0);
@@ -1274,8 +1288,7 @@ QualType ASTContext::getRValueReferenceType(QualType T) {
/// 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)
-{
+QualType ASTContext::getMemberPointerType(QualType T, const Type *Cls) {
// Unique pointers, to guarantee there is only one pointer of a particular
// structure.
llvm::FoldingSetNodeID ID;
@@ -1297,15 +1310,16 @@ QualType ASTContext::getMemberPointerType(QualType T, const Type *Cls)
MemberPointerTypes.FindNodeOrInsertPos(ID, InsertPos);
assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
}
- MemberPointerType *New = new (*this,8) MemberPointerType(T, Cls, Canonical);
+ MemberPointerType *New
+ = new (*this, TypeAlignment) 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
+/// getConstantArrayType - Return the unique reference to the type for an
/// array of the specified element type.
-QualType ASTContext::getConstantArrayType(QualType EltTy,
+QualType ASTContext::getConstantArrayType(QualType EltTy,
const llvm::APInt &ArySizeIn,
ArrayType::ArraySizeModifier ASM,
unsigned EltTypeQuals) {
@@ -1316,44 +1330,93 @@ QualType ASTContext::getConstantArrayType(QualType EltTy,
// 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 =
+ 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,
+ Canonical = getConstantArrayType(getCanonicalType(EltTy), ArySize,
ASM, EltTypeQuals);
// Get the new insert position for the node we care about.
- ConstantArrayType *NewIP =
+ 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);
+
+ ConstantArrayType *New = new(*this,TypeAlignment)
+ ConstantArrayType(EltTy, Canonical, ArySize, ASM, EltTypeQuals);
ConstantArrayTypes.InsertNode(New, InsertPos);
Types.push_back(New);
return QualType(New, 0);
}
+/// getConstantArrayWithExprType - Return a reference to the type for
+/// an array of the specified element type.
+QualType
+ASTContext::getConstantArrayWithExprType(QualType EltTy,
+ const llvm::APInt &ArySizeIn,
+ Expr *ArySizeExpr,
+ ArrayType::ArraySizeModifier ASM,
+ unsigned EltTypeQuals,
+ SourceRange Brackets) {
+ // 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()));
+
+ // Compute the canonical ConstantArrayType.
+ QualType Canonical = getConstantArrayType(getCanonicalType(EltTy),
+ ArySize, ASM, EltTypeQuals);
+ // Since we don't unique expressions, it isn't possible to unique VLA's
+ // that have an expression provided for their size.
+ ConstantArrayWithExprType *New = new(*this, TypeAlignment)
+ ConstantArrayWithExprType(EltTy, Canonical, ArySize, ArySizeExpr,
+ ASM, EltTypeQuals, Brackets);
+ Types.push_back(New);
+ return QualType(New, 0);
+}
+
+/// getConstantArrayWithoutExprType - Return a reference to the type for
+/// an array of the specified element type.
+QualType
+ASTContext::getConstantArrayWithoutExprType(QualType EltTy,
+ const llvm::APInt &ArySizeIn,
+ ArrayType::ArraySizeModifier ASM,
+ unsigned EltTypeQuals) {
+ // 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()));
+
+ // Compute the canonical ConstantArrayType.
+ QualType Canonical = getConstantArrayType(getCanonicalType(EltTy),
+ ArySize, ASM, EltTypeQuals);
+ ConstantArrayWithoutExprType *New = new(*this, TypeAlignment)
+ ConstantArrayWithoutExprType(EltTy, Canonical, ArySize, ASM, EltTypeQuals);
+ 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,
+QualType ASTContext::getVariableArrayType(QualType EltTy,
+ Expr *NumElts,
ArrayType::ArraySizeModifier ASM,
- unsigned EltTypeQuals) {
+ unsigned EltTypeQuals,
+ SourceRange Brackets) {
// 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);
+ VariableArrayType *New = new(*this, TypeAlignment)
+ VariableArrayType(EltTy, QualType(), NumElts, ASM, EltTypeQuals, Brackets);
VariableArrayTypes.push_back(New);
Types.push_back(New);
@@ -1362,22 +1425,46 @@ QualType ASTContext::getVariableArrayType(QualType EltTy, Expr *NumElts,
/// 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,
+/// type.
+QualType ASTContext::getDependentSizedArrayType(QualType EltTy,
+ Expr *NumElts,
ArrayType::ArraySizeModifier ASM,
- unsigned EltTypeQuals) {
- assert((NumElts->isTypeDependent() || NumElts->isValueDependent()) &&
+ unsigned EltTypeQuals,
+ SourceRange Brackets) {
+ 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.
+ llvm::FoldingSetNodeID ID;
+ DependentSizedArrayType::Profile(ID, *this, getCanonicalType(EltTy), ASM,
+ EltTypeQuals, NumElts);
- DependentSizedArrayType *New =
- new (*this,8) DependentSizedArrayType(EltTy, QualType(), NumElts,
- ASM, EltTypeQuals);
+ void *InsertPos = 0;
+ DependentSizedArrayType *Canon
+ = DependentSizedArrayTypes.FindNodeOrInsertPos(ID, InsertPos);
+ DependentSizedArrayType *New;
+ if (Canon) {
+ // We already have a canonical version of this array type; use it as
+ // the canonical type for a newly-built type.
+ New = new (*this, TypeAlignment)
+ DependentSizedArrayType(*this, EltTy, QualType(Canon, 0),
+ NumElts, ASM, EltTypeQuals, Brackets);
+ } else {
+ QualType CanonEltTy = getCanonicalType(EltTy);
+ if (CanonEltTy == EltTy) {
+ New = new (*this, TypeAlignment)
+ DependentSizedArrayType(*this, EltTy, QualType(),
+ NumElts, ASM, EltTypeQuals, Brackets);
+ DependentSizedArrayTypes.InsertNode(New, InsertPos);
+ } else {
+ QualType Canon = getDependentSizedArrayType(CanonEltTy, NumElts,
+ ASM, EltTypeQuals,
+ SourceRange());
+ New = new (*this, TypeAlignment)
+ DependentSizedArrayType(*this, EltTy, Canon,
+ NumElts, ASM, EltTypeQuals, Brackets);
+ }
+ }
- DependentSizedArrayTypes.push_back(New);
Types.push_back(New);
return QualType(New, 0);
}
@@ -1389,7 +1476,7 @@ QualType ASTContext::getIncompleteArrayType(QualType EltTy,
IncompleteArrayType::Profile(ID, EltTy, ASM, EltTypeQuals);
void *InsertPos = 0;
- if (IncompleteArrayType *ATP =
+ if (IncompleteArrayType *ATP =
IncompleteArrayTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(ATP, 0);
@@ -1407,8 +1494,8 @@ QualType ASTContext::getIncompleteArrayType(QualType EltTy,
assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
}
- IncompleteArrayType *New = new (*this,8) IncompleteArrayType(EltTy, Canonical,
- ASM, EltTypeQuals);
+ IncompleteArrayType *New = new (*this, TypeAlignment)
+ IncompleteArrayType(EltTy, Canonical, ASM, EltTypeQuals);
IncompleteArrayTypes.InsertNode(New, InsertPos);
Types.push_back(New);
@@ -1419,13 +1506,13 @@ QualType ASTContext::getIncompleteArrayType(QualType EltTy,
/// 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);
+ VectorType::Profile(ID, vecType, NumElts, Type::Vector);
void *InsertPos = 0;
if (VectorType *VTP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(VTP, 0);
@@ -1435,12 +1522,13 @@ QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts) {
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);
+ VectorType *New = new (*this, TypeAlignment)
+ VectorType(vecType, NumElts, Canonical);
VectorTypes.InsertNode(New, InsertPos);
Types.push_back(New);
return QualType(New, 0);
@@ -1450,13 +1538,13 @@ QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts) {
/// 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);
+ VectorType::Profile(ID, vecType, NumElts, Type::ExtVector);
void *InsertPos = 0;
if (VectorType *VTP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(VTP, 0);
@@ -1466,53 +1554,79 @@ QualType ASTContext::getExtVectorType(QualType vecType, unsigned NumElts) {
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);
+ ExtVectorType *New = new (*this, TypeAlignment)
+ ExtVectorType(vecType, NumElts, Canonical);
VectorTypes.InsertNode(New, InsertPos);
Types.push_back(New);
return QualType(New, 0);
}
-QualType ASTContext::getDependentSizedExtVectorType(QualType vecType,
+QualType ASTContext::getDependentSizedExtVectorType(QualType vecType,
Expr *SizeExpr,
SourceLocation AttrLoc) {
- DependentSizedExtVectorType *New =
- new (*this,8) DependentSizedExtVectorType(vecType, QualType(),
- SizeExpr, AttrLoc);
+ llvm::FoldingSetNodeID ID;
+ DependentSizedExtVectorType::Profile(ID, *this, getCanonicalType(vecType),
+ SizeExpr);
+
+ void *InsertPos = 0;
+ DependentSizedExtVectorType *Canon
+ = DependentSizedExtVectorTypes.FindNodeOrInsertPos(ID, InsertPos);
+ DependentSizedExtVectorType *New;
+ if (Canon) {
+ // We already have a canonical version of this array type; use it as
+ // the canonical type for a newly-built type.
+ New = new (*this, TypeAlignment)
+ DependentSizedExtVectorType(*this, vecType, QualType(Canon, 0),
+ SizeExpr, AttrLoc);
+ } else {
+ QualType CanonVecTy = getCanonicalType(vecType);
+ if (CanonVecTy == vecType) {
+ New = new (*this, TypeAlignment)
+ DependentSizedExtVectorType(*this, vecType, QualType(), SizeExpr,
+ AttrLoc);
+ DependentSizedExtVectorTypes.InsertNode(New, InsertPos);
+ } else {
+ QualType Canon = getDependentSizedExtVectorType(CanonVecTy, SizeExpr,
+ SourceLocation());
+ New = new (*this, TypeAlignment)
+ DependentSizedExtVectorType(*this, vecType, Canon, SizeExpr, AttrLoc);
+ }
+ }
- DependentSizedExtVectorTypes.push_back(New);
Types.push_back(New);
return QualType(New, 0);
}
/// getFunctionNoProtoType - Return a K&R style C function type like 'int()'.
///
-QualType ASTContext::getFunctionNoProtoType(QualType ResultTy) {
+QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn) {
// Unique functions, to guarantee there is only one function of a particular
// structure.
llvm::FoldingSetNodeID ID;
- FunctionNoProtoType::Profile(ID, ResultTy);
-
+ FunctionNoProtoType::Profile(ID, ResultTy, NoReturn);
+
void *InsertPos = 0;
- if (FunctionNoProtoType *FT =
+ if (FunctionNoProtoType *FT =
FunctionNoProtoTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(FT, 0);
-
+
QualType Canonical;
if (!ResultTy->isCanonical()) {
- Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy));
-
+ Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy), NoReturn);
+
// 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);
+
+ FunctionNoProtoType *New = new (*this, TypeAlignment)
+ FunctionNoProtoType(ResultTy, Canonical, NoReturn);
Types.push_back(New);
FunctionNoProtoTypes.InsertNode(New, InsertPos);
return QualType(New, 0);
@@ -1524,16 +1638,22 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,
unsigned NumArgs, bool isVariadic,
unsigned TypeQuals, bool hasExceptionSpec,
bool hasAnyExceptionSpec, unsigned NumExs,
- const QualType *ExArray) {
+ const QualType *ExArray, bool NoReturn) {
+ if (LangOpts.CPlusPlus) {
+ for (unsigned i = 0; i != NumArgs; ++i)
+ assert(!ArgArray[i].hasQualifiers() &&
+ "C++ arguments can't have toplevel qualifiers!");
+ }
+
// 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);
+ NumExs, ExArray, NoReturn);
void *InsertPos = 0;
- if (FunctionProtoType *FTP =
+ if (FunctionProtoType *FTP =
FunctionProtoTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(FTP, 0);
@@ -1556,7 +1676,8 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,
Canonical = getFunctionType(getCanonicalType(ResultTy),
CanonicalArgs.data(), NumArgs,
- isVariadic, TypeQuals);
+ isVariadic, TypeQuals, false,
+ false, 0, 0, NoReturn);
// Get the new insert position for the node we care about.
FunctionProtoType *NewIP =
@@ -1567,13 +1688,13 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,
// 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 *FTP =
(FunctionProtoType*)Allocate(sizeof(FunctionProtoType) +
NumArgs*sizeof(QualType) +
- NumExs*sizeof(QualType), 8);
+ NumExs*sizeof(QualType), TypeAlignment);
new (FTP) FunctionProtoType(ResultTy, ArgArray, NumArgs, isVariadic,
TypeQuals, hasExceptionSpec, hasAnyExceptionSpec,
- ExArray, NumExs, Canonical);
+ ExArray, NumExs, Canonical, NoReturn);
Types.push_back(FTP);
FunctionProtoTypes.InsertNode(FTP, InsertPos);
return QualType(FTP, 0);
@@ -1584,27 +1705,26 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,
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))
+ } 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)) {
+ Decl->TypeForDecl = new (*this, TypeAlignment) 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
+ Decl->TypeForDecl = new (*this, TypeAlignment) EnumType(Enum);
+ } else
assert(false && "TypeDecl without a type?");
if (!PrevDecl) Types.push_back(Decl->TypeForDecl);
@@ -1615,45 +1735,36 @@ QualType ASTContext::getTypeDeclType(TypeDecl *Decl, TypeDecl* PrevDecl) {
/// 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);
+ QualType Canonical = getCanonicalType(Decl->getUnderlyingType());
+ Decl->TypeForDecl = new(*this, TypeAlignment)
+ TypedefType(Type::Typedef, Decl, Canonical);
Types.push_back(Decl->TypeForDecl);
return QualType(Decl->TypeForDecl, 0);
}
/// \brief Retrieve the template type parameter type for a template
-/// parameter or parameter pack with the given depth, index, and (optionally)
+/// parameter or parameter pack with the given depth, index, and (optionally)
/// name.
-QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index,
+QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index,
bool ParameterPack,
IdentifierInfo *Name) {
llvm::FoldingSetNodeID ID;
TemplateTypeParmType::Profile(ID, Depth, Index, ParameterPack, Name);
void *InsertPos = 0;
- TemplateTypeParmType *TypeParm
+ TemplateTypeParmType *TypeParm
= TemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos);
if (TypeParm)
return QualType(TypeParm, 0);
-
+
if (Name) {
QualType Canon = getTemplateTypeParmType(Depth, Index, ParameterPack);
- TypeParm = new (*this, 8) TemplateTypeParmType(Depth, Index, ParameterPack,
- Name, Canon);
+ TypeParm = new (*this, TypeAlignment)
+ TemplateTypeParmType(Depth, Index, ParameterPack, Name, Canon);
} else
- TypeParm = new (*this, 8) TemplateTypeParmType(Depth, Index, ParameterPack);
+ TypeParm = new (*this, TypeAlignment)
+ TemplateTypeParmType(Depth, Index, ParameterPack);
Types.push_back(TypeParm);
TemplateTypeParmTypes.InsertNode(TypeParm, InsertPos);
@@ -1661,54 +1772,83 @@ QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index,
return QualType(TypeParm, 0);
}
-QualType
+QualType
ASTContext::getTemplateSpecializationType(TemplateName Template,
const TemplateArgument *Args,
unsigned NumArgs,
QualType Canon) {
if (!Canon.isNull())
Canon = getCanonicalType(Canon);
+ else {
+ // Build the canonical template specialization type.
+ TemplateName CanonTemplate = getCanonicalTemplateName(Template);
+ llvm::SmallVector<TemplateArgument, 4> CanonArgs;
+ CanonArgs.reserve(NumArgs);
+ for (unsigned I = 0; I != NumArgs; ++I)
+ CanonArgs.push_back(getCanonicalTemplateArgument(Args[I]));
+
+ // Determine whether this canonical template specialization type already
+ // exists.
+ llvm::FoldingSetNodeID ID;
+ TemplateSpecializationType::Profile(ID, CanonTemplate,
+ CanonArgs.data(), NumArgs, *this);
+
+ void *InsertPos = 0;
+ TemplateSpecializationType *Spec
+ = TemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos);
+
+ if (!Spec) {
+ // Allocate a new canonical template specialization type.
+ void *Mem = Allocate((sizeof(TemplateSpecializationType) +
+ sizeof(TemplateArgument) * NumArgs),
+ TypeAlignment);
+ Spec = new (Mem) TemplateSpecializationType(*this, CanonTemplate,
+ CanonArgs.data(), NumArgs,
+ Canon);
+ Types.push_back(Spec);
+ TemplateSpecializationTypes.InsertNode(Spec, InsertPos);
+ }
- llvm::FoldingSetNodeID ID;
- TemplateSpecializationType::Profile(ID, Template, Args, NumArgs);
+ if (Canon.isNull())
+ Canon = QualType(Spec, 0);
+ assert(Canon->isDependentType() &&
+ "Non-dependent template-id type must have a canonical type");
+ }
- void *InsertPos = 0;
+ // Allocate the (non-canonical) template specialization type, but don't
+ // try to unique it: these types typically have location information that
+ // we don't unique and don't want to lose.
+ void *Mem = Allocate((sizeof(TemplateSpecializationType) +
+ sizeof(TemplateArgument) * NumArgs),
+ TypeAlignment);
TemplateSpecializationType *Spec
- = TemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos);
+ = new (Mem) TemplateSpecializationType(*this, Template, Args, NumArgs,
+ Canon);
- 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);
+ return QualType(Spec, 0);
}
-QualType
+QualType
ASTContext::getQualifiedNameType(NestedNameSpecifier *NNS,
QualType NamedType) {
llvm::FoldingSetNodeID ID;
QualifiedNameType::Profile(ID, NNS, NamedType);
void *InsertPos = 0;
- QualifiedNameType *T
+ QualifiedNameType *T
= QualifiedNameTypes.FindNodeOrInsertPos(ID, InsertPos);
if (T)
return QualType(T, 0);
- T = new (*this) QualifiedNameType(NNS, NamedType,
+ 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,
+QualType ASTContext::getTypenameType(NestedNameSpecifier *NNS,
const IdentifierInfo *Name,
QualType Canon) {
assert(NNS->isDependent() && "nested-name-specifier must be dependent");
@@ -1723,7 +1863,7 @@ QualType ASTContext::getTypenameType(NestedNameSpecifier *NNS,
TypenameType::Profile(ID, NNS, Name);
void *InsertPos = 0;
- TypenameType *T
+ TypenameType *T
= TypenameTypes.FindNodeOrInsertPos(ID, InsertPos);
if (T)
return QualType(T, 0);
@@ -1731,11 +1871,11 @@ QualType ASTContext::getTypenameType(NestedNameSpecifier *NNS,
T = new (*this) TypenameType(NNS, Name, Canon);
Types.push_back(T);
TypenameTypes.InsertNode(T, InsertPos);
- return QualType(T, 0);
+ return QualType(T, 0);
}
-QualType
-ASTContext::getTypenameType(NestedNameSpecifier *NNS,
+QualType
+ASTContext::getTypenameType(NestedNameSpecifier *NNS,
const TemplateSpecializationType *TemplateId,
QualType Canon) {
assert(NNS->isDependent() && "nested-name-specifier must be dependent");
@@ -1745,7 +1885,7 @@ ASTContext::getTypenameType(NestedNameSpecifier *NNS,
QualType CanonType = getCanonicalType(QualType(TemplateId, 0));
if (CanonNNS != NNS || CanonType != QualType(TemplateId, 0)) {
const TemplateSpecializationType *CanonTemplateId
- = CanonType->getAsTemplateSpecializationType();
+ = CanonType->getAs<TemplateSpecializationType>();
assert(CanonTemplateId &&
"Canonical type must also be a template specialization type");
Canon = getTypenameType(CanonNNS, CanonTemplateId);
@@ -1756,7 +1896,7 @@ ASTContext::getTypenameType(NestedNameSpecifier *NNS,
TypenameType::Profile(ID, NNS, TemplateId);
void *InsertPos = 0;
- TypenameType *T
+ TypenameType *T
= TypenameTypes.FindNodeOrInsertPos(ID, InsertPos);
if (T)
return QualType(T, 0);
@@ -1764,7 +1904,26 @@ ASTContext::getTypenameType(NestedNameSpecifier *NNS,
T = new (*this) TypenameType(NNS, TemplateId, Canon);
Types.push_back(T);
TypenameTypes.InsertNode(T, InsertPos);
- return QualType(T, 0);
+ return QualType(T, 0);
+}
+
+QualType
+ASTContext::getElaboratedType(QualType UnderlyingType,
+ ElaboratedType::TagKind Tag) {
+ llvm::FoldingSetNodeID ID;
+ ElaboratedType::Profile(ID, UnderlyingType, Tag);
+
+ void *InsertPos = 0;
+ ElaboratedType *T = ElaboratedTypes.FindNodeOrInsertPos(ID, InsertPos);
+ if (T)
+ return QualType(T, 0);
+
+ QualType Canon = getCanonicalType(UnderlyingType);
+
+ T = new (*this) ElaboratedType(UnderlyingType, Tag, Canon);
+ Types.push_back(T);
+ ElaboratedTypes.InsertNode(T, InsertPos);
+ return QualType(T, 0);
}
/// CmpProtocolNames - Comparison predicate for sorting protocols
@@ -1777,7 +1936,7 @@ static bool CmpProtocolNames(const ObjCProtocolDecl *LHS,
static void SortAndUniqueProtocols(ObjCProtocolDecl **&Protocols,
unsigned &NumProtocols) {
ObjCProtocolDecl **ProtocolsEnd = Protocols+NumProtocols;
-
+
// Sort protocols, keyed by name.
std::sort(Protocols, Protocols+NumProtocols, CmpProtocolNames);
@@ -1788,15 +1947,15 @@ static void SortAndUniqueProtocols(ObjCProtocolDecl **&Protocols,
/// getObjCObjectPointerType - Return a ObjCObjectPointerType type for
/// the given interface decl and the conforming protocol list.
-QualType ASTContext::getObjCObjectPointerType(ObjCInterfaceDecl *Decl,
- ObjCProtocolDecl **Protocols,
+QualType ASTContext::getObjCObjectPointerType(QualType InterfaceT,
+ ObjCProtocolDecl **Protocols,
unsigned NumProtocols) {
// Sort the protocol list alphabetically to canonicalize it.
if (NumProtocols)
SortAndUniqueProtocols(Protocols, NumProtocols);
llvm::FoldingSetNodeID ID;
- ObjCObjectPointerType::Profile(ID, Decl, Protocols, NumProtocols);
+ ObjCObjectPointerType::Profile(ID, InterfaceT, Protocols, NumProtocols);
void *InsertPos = 0;
if (ObjCObjectPointerType *QT =
@@ -1804,46 +1963,89 @@ QualType ASTContext::getObjCObjectPointerType(ObjCInterfaceDecl *Decl,
return QualType(QT, 0);
// No Match;
- ObjCObjectPointerType *QType =
- new (*this,8) ObjCObjectPointerType(Decl, Protocols, NumProtocols);
-
+ ObjCObjectPointerType *QType = new (*this, TypeAlignment)
+ ObjCObjectPointerType(InterfaceT, Protocols, NumProtocols);
+
Types.push_back(QType);
ObjCObjectPointerTypes.InsertNode(QType, InsertPos);
return QualType(QType, 0);
}
-/// getObjCQualifiedInterfaceType - Return a ObjCQualifiedInterfaceType type for
-/// the given interface decl and the conforming protocol list.
-QualType ASTContext::getObjCQualifiedInterfaceType(ObjCInterfaceDecl *Decl,
+/// getObjCInterfaceType - Return the unique reference to the type for the
+/// specified ObjC interface decl. The list of protocols is optional.
+QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl,
ObjCProtocolDecl **Protocols, unsigned NumProtocols) {
- // Sort the protocol list alphabetically to canonicalize it.
- SortAndUniqueProtocols(Protocols, NumProtocols);
-
+ if (NumProtocols)
+ // Sort the protocol list alphabetically to canonicalize it.
+ SortAndUniqueProtocols(Protocols, NumProtocols);
+
llvm::FoldingSetNodeID ID;
- ObjCQualifiedInterfaceType::Profile(ID, Decl, Protocols, NumProtocols);
-
+ ObjCInterfaceType::Profile(ID, Decl, Protocols, NumProtocols);
+
void *InsertPos = 0;
- if (ObjCQualifiedInterfaceType *QT =
- ObjCQualifiedInterfaceTypes.FindNodeOrInsertPos(ID, InsertPos))
+ if (ObjCInterfaceType *QT =
+ ObjCInterfaceTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(QT, 0);
-
+
// No Match;
- ObjCQualifiedInterfaceType *QType =
- new (*this,8) ObjCQualifiedInterfaceType(Decl, Protocols, NumProtocols);
+ ObjCInterfaceType *QType = new (*this, TypeAlignment)
+ ObjCInterfaceType(const_cast<ObjCInterfaceDecl*>(Decl),
+ Protocols, NumProtocols);
+ Types.push_back(QType);
+ ObjCInterfaceTypes.InsertNode(QType, InsertPos);
+ return QualType(QType, 0);
+}
+
+QualType ASTContext::getObjCProtocolListType(QualType T,
+ ObjCProtocolDecl **Protocols,
+ unsigned NumProtocols) {
+ llvm::FoldingSetNodeID ID;
+ ObjCProtocolListType::Profile(ID, T, Protocols, NumProtocols);
+
+ void *InsertPos = 0;
+ if (ObjCProtocolListType *QT =
+ ObjCProtocolListTypes.FindNodeOrInsertPos(ID, InsertPos))
+ return QualType(QT, 0);
+ // No Match;
+ ObjCProtocolListType *QType = new (*this, TypeAlignment)
+ ObjCProtocolListType(T, Protocols, NumProtocols);
Types.push_back(QType);
- ObjCQualifiedInterfaceTypes.InsertNode(QType, InsertPos);
+ ObjCProtocolListTypes.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
+/// 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);
+ TypeOfExprType *toe;
+ if (tofExpr->isTypeDependent()) {
+ llvm::FoldingSetNodeID ID;
+ DependentTypeOfExprType::Profile(ID, *this, tofExpr);
+
+ void *InsertPos = 0;
+ DependentTypeOfExprType *Canon
+ = DependentTypeOfExprTypes.FindNodeOrInsertPos(ID, InsertPos);
+ if (Canon) {
+ // We already have a "canonical" version of an identical, dependent
+ // typeof(expr) type. Use that as our canonical type.
+ toe = new (*this, TypeAlignment) TypeOfExprType(tofExpr,
+ QualType((TypeOfExprType*)Canon, 0));
+ }
+ else {
+ // Build a new, canonical typeof(expr) type.
+ Canon
+ = new (*this, TypeAlignment) DependentTypeOfExprType(*this, tofExpr);
+ DependentTypeOfExprTypes.InsertNode(Canon, InsertPos);
+ toe = Canon;
+ }
+ } else {
+ QualType Canonical = getCanonicalType(tofExpr->getType());
+ toe = new (*this, TypeAlignment) TypeOfExprType(tofExpr, Canonical);
+ }
Types.push_back(toe);
return QualType(toe, 0);
}
@@ -1851,11 +2053,11 @@ QualType ASTContext::getTypeOfExprType(Expr *tofExpr) {
/// 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
+/// 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);
+ TypeOfType *tot = new (*this, TypeAlignment) TypeOfType(tofType, Canonical);
Types.push_back(tot);
return QualType(tot, 0);
}
@@ -1865,7 +2067,7 @@ QualType ASTContext::getTypeOfType(QualType tofType) {
static QualType getDecltypeForExpr(const Expr *e, ASTContext &Context) {
if (e->isTypeDependent())
return Context.DependentTy;
-
+
// If e is an id expression or a class member access, decltype(e) is defined
// as the type of the entity named by e.
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(e)) {
@@ -1881,39 +2083,63 @@ static QualType getDecltypeForExpr(const Expr *e, ASTContext &Context) {
// return type of that function.
if (const CallExpr *CE = dyn_cast<CallExpr>(e->IgnoreParens()))
return CE->getCallReturnType();
-
+
QualType T = e->getType();
-
- // Otherwise, where T is the type of e, if e is an lvalue, decltype(e) is
+
+ // Otherwise, where T is the type of e, if e is an lvalue, decltype(e) is
// defined as T&, otherwise decltype(e) is defined as T.
if (e->isLvalue(Context) == Expr::LV_Valid)
T = Context.getLValueReferenceType(T);
-
+
return T;
}
/// getDecltypeType - Unlike many "get<Type>" functions, we don't unique
/// DecltypeType AST's. The only motivation to unique these nodes would be
/// memory savings. Since decltype(t) is fairly uncommon, space shouldn't be
-/// an issue. This doesn't effect the type checker, since it operates
+/// an issue. This doesn't effect the type checker, since it operates
/// on canonical type's (which are always unique).
QualType ASTContext::getDecltypeType(Expr *e) {
- QualType T = getDecltypeForExpr(e, *this);
- DecltypeType *dt = new (*this, 8) DecltypeType(e, getCanonicalType(T));
+ DecltypeType *dt;
+ if (e->isTypeDependent()) {
+ llvm::FoldingSetNodeID ID;
+ DependentDecltypeType::Profile(ID, *this, e);
+
+ void *InsertPos = 0;
+ DependentDecltypeType *Canon
+ = DependentDecltypeTypes.FindNodeOrInsertPos(ID, InsertPos);
+ if (Canon) {
+ // We already have a "canonical" version of an equivalent, dependent
+ // decltype type. Use that as our canonical type.
+ dt = new (*this, TypeAlignment) DecltypeType(e, DependentTy,
+ QualType((DecltypeType*)Canon, 0));
+ }
+ else {
+ // Build a new, canonical typeof(expr) type.
+ Canon = new (*this, TypeAlignment) DependentDecltypeType(*this, e);
+ DependentDecltypeTypes.InsertNode(Canon, InsertPos);
+ dt = Canon;
+ }
+ } else {
+ QualType T = getDecltypeForExpr(e, *this);
+ dt = new (*this, TypeAlignment) DecltypeType(e, T, getCanonicalType(T));
+ }
Types.push_back(dt);
return QualType(dt, 0);
}
/// getTagDeclType - Return the unique reference to the type for the
/// specified TagDecl (struct/union/class/enum) decl.
-QualType ASTContext::getTagDeclType(TagDecl *Decl) {
+QualType ASTContext::getTagDeclType(const TagDecl *Decl) {
assert (Decl);
- return getTypeDeclType(Decl);
+ // FIXME: What is the design on getTagDeclType when it requires casting
+ // away const? mutable?
+ return getTypeDeclType(const_cast<TagDecl*>(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>.
+/// 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());
}
@@ -1948,99 +2174,143 @@ QualType ASTContext::getPointerDiffType() const {
/// 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;
+CanQualType ASTContext::getCanonicalType(QualType T) {
+ QualifierCollector Quals;
+ const Type *Ptr = Quals.strip(T);
+ QualType CanType = Ptr->getCanonicalTypeInternal();
+
+ // The canonical internal type will be the canonical type *except*
+ // that we push type qualifiers down through array types.
- // If the type qualifiers are on an array type, get the canonical type of the
- // array with the qualifiers applied to the element type.
+ // If there are no new qualifiers to push down, stop here.
+ if (!Quals.hasQualifiers())
+ return CanQualType::CreateUnsafe(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);
-
+ return CanQualType::CreateUnsafe(getQualifiedType(CanType, Quals));
+
// 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);
+ QualType NewEltTy = getQualifiedType(AT->getElementType(), Quals);
NewEltTy = getCanonicalType(NewEltTy);
-
+
if (ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT))
- return getConstantArrayType(NewEltTy, CAT->getSize(),CAT->getSizeModifier(),
- CAT->getIndexTypeQualifier());
+ return CanQualType::CreateUnsafe(
+ getConstantArrayType(NewEltTy, CAT->getSize(),
+ CAT->getSizeModifier(),
+ CAT->getIndexTypeCVRQualifiers()));
if (IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(AT))
- return getIncompleteArrayType(NewEltTy, IAT->getSizeModifier(),
- IAT->getIndexTypeQualifier());
-
+ return CanQualType::CreateUnsafe(
+ getIncompleteArrayType(NewEltTy, IAT->getSizeModifier(),
+ IAT->getIndexTypeCVRQualifiers()));
+
if (DependentSizedArrayType *DSAT = dyn_cast<DependentSizedArrayType>(AT))
- return getDependentSizedArrayType(NewEltTy, DSAT->getSizeExpr(),
- DSAT->getSizeModifier(),
- DSAT->getIndexTypeQualifier());
+ return CanQualType::CreateUnsafe(
+ getDependentSizedArrayType(NewEltTy,
+ DSAT->getSizeExpr() ?
+ DSAT->getSizeExpr()->Retain() : 0,
+ DSAT->getSizeModifier(),
+ DSAT->getIndexTypeCVRQualifiers(),
+ DSAT->getBracketsRange()));
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 (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D)) {
- while (FunTmpl->getPreviousDeclaration())
- FunTmpl = FunTmpl->getPreviousDeclaration();
- return FunTmpl;
- }
-
- if (const VarDecl *Var = dyn_cast<VarDecl>(D)) {
- while (Var->getPreviousDeclaration())
- Var = Var->getPreviousDeclaration();
- return const_cast<VarDecl *>(Var);
- }
-
- return D;
+ return CanQualType::CreateUnsafe(getVariableArrayType(NewEltTy,
+ VAT->getSizeExpr() ?
+ VAT->getSizeExpr()->Retain() : 0,
+ VAT->getSizeModifier(),
+ VAT->getIndexTypeCVRQualifiers(),
+ VAT->getBracketsRange()));
}
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)));
+ return TemplateName(cast<TemplateDecl>(Template->getCanonicalDecl()));
+
+ // If this template name refers to a set of overloaded function templates,
+ /// the canonical template name merely stores the set of function templates.
+ if (OverloadedFunctionDecl *Ovl = Name.getAsOverloadedFunctionDecl()) {
+ OverloadedFunctionDecl *CanonOvl = 0;
+ for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
+ FEnd = Ovl->function_end();
+ F != FEnd; ++F) {
+ Decl *Canon = F->get()->getCanonicalDecl();
+ if (CanonOvl || Canon != F->get()) {
+ if (!CanonOvl)
+ CanonOvl = OverloadedFunctionDecl::Create(*this,
+ Ovl->getDeclContext(),
+ Ovl->getDeclName());
+
+ CanonOvl->addOverload(
+ AnyFunctionDecl::getFromNamedDecl(cast<NamedDecl>(Canon)));
+ }
+ }
+
+ return TemplateName(CanonOvl? CanonOvl : Ovl);
+ }
DependentTemplateName *DTN = Name.getAsDependentTemplateName();
assert(DTN && "Non-dependent template names must refer to template decls.");
return DTN->CanonicalTemplateName;
}
+TemplateArgument
+ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) {
+ switch (Arg.getKind()) {
+ case TemplateArgument::Null:
+ return Arg;
+
+ case TemplateArgument::Expression:
+ // FIXME: Build canonical expression?
+ return Arg;
+
+ case TemplateArgument::Declaration:
+ return TemplateArgument(SourceLocation(),
+ Arg.getAsDecl()->getCanonicalDecl());
+
+ case TemplateArgument::Integral:
+ return TemplateArgument(SourceLocation(),
+ *Arg.getAsIntegral(),
+ getCanonicalType(Arg.getIntegralType()));
+
+ case TemplateArgument::Type:
+ return TemplateArgument(SourceLocation(),
+ getCanonicalType(Arg.getAsType()));
+
+ case TemplateArgument::Pack: {
+ // FIXME: Allocate in ASTContext
+ TemplateArgument *CanonArgs = new TemplateArgument[Arg.pack_size()];
+ unsigned Idx = 0;
+ for (TemplateArgument::pack_iterator A = Arg.pack_begin(),
+ AEnd = Arg.pack_end();
+ A != AEnd; (void)++A, ++Idx)
+ CanonArgs[Idx] = getCanonicalTemplateArgument(*A);
+
+ TemplateArgument Result;
+ Result.setArgumentPack(CanonArgs, Arg.pack_size(), false);
+ return Result;
+ }
+ }
+
+ // Silence GCC warning
+ assert(false && "Unhandled template argument kind");
+ return TemplateArgument();
+}
+
NestedNameSpecifier *
ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) {
- if (!NNS)
+ if (!NNS)
return 0;
switch (NNS->getKind()) {
case NestedNameSpecifier::Identifier:
// Canonicalize the prefix but keep the identifier the same.
- return NestedNameSpecifier::Create(*this,
+ return NestedNameSpecifier::Create(*this,
getCanonicalNestedNameSpecifier(NNS->getPrefix()),
NNS->getAsIdentifier());
@@ -2052,14 +2322,8 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) {
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,
+ return NestedNameSpecifier::Create(*this, 0,
+ NNS->getKind() == NestedNameSpecifier::TypeSpecWithTemplate,
T.getTypePtr());
}
@@ -2075,81 +2339,65 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) {
const ArrayType *ASTContext::getAsArrayType(QualType T) {
// Handle the non-qualified case efficiently.
- if (T.getCVRQualifiers() == 0) {
+ if (!T.hasQualifiers()) {
// 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.
+
+ // Handle the common negative case fast.
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()))
+ if (!isa<ArrayType>(CType))
return 0;
-
- // Apply any CVR qualifiers from the array type to the element type. This
+
+ // Apply any 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();
- }
- }
-
+ // we must propagate them down into the element type.
+
+ QualifierCollector Qs;
+ const Type *Ty = Qs.strip(T.getDesugaredType());
+
// If we have a simple case, just return now.
const ArrayType *ATy = dyn_cast<ArrayType>(Ty);
- if (ATy == 0 || (AddrSpace == 0 && CVRQuals == 0))
+ if (ATy == 0 || Qs.empty())
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);
-
+ QualType NewEltTy = getQualifiedType(ATy->getElementType(), Qs);
+
if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(ATy))
return cast<ArrayType>(getConstantArrayType(NewEltTy, CAT->getSize(),
CAT->getSizeModifier(),
- CAT->getIndexTypeQualifier()));
+ CAT->getIndexTypeCVRQualifiers()));
if (const IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(ATy))
return cast<ArrayType>(getIncompleteArrayType(NewEltTy,
IAT->getSizeModifier(),
- IAT->getIndexTypeQualifier()));
+ IAT->getIndexTypeCVRQualifiers()));
- if (const DependentSizedArrayType *DSAT
+ if (const DependentSizedArrayType *DSAT
= dyn_cast<DependentSizedArrayType>(ATy))
return cast<ArrayType>(
- getDependentSizedArrayType(NewEltTy,
- DSAT->getSizeExpr(),
+ getDependentSizedArrayType(NewEltTy,
+ DSAT->getSizeExpr() ?
+ DSAT->getSizeExpr()->Retain() : 0,
DSAT->getSizeModifier(),
- DSAT->getIndexTypeQualifier()));
-
+ DSAT->getIndexTypeCVRQualifiers(),
+ DSAT->getBracketsRange()));
+
const VariableArrayType *VAT = cast<VariableArrayType>(ATy);
- return cast<ArrayType>(getVariableArrayType(NewEltTy, VAT->getSizeExpr(),
+ return cast<ArrayType>(getVariableArrayType(NewEltTy,
+ VAT->getSizeExpr() ?
+ VAT->getSizeExpr()->Retain() : 0,
VAT->getSizeModifier(),
- VAT->getIndexTypeQualifier()));
+ VAT->getIndexTypeCVRQualifiers(),
+ VAT->getBracketsRange()));
}
@@ -2166,30 +2414,53 @@ QualType ASTContext::getArrayDecayedType(QualType Ty) {
// (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());
+ return getQualifiedType(PtrTy, PrettyArrayType->getIndexTypeQualifiers());
}
-QualType ASTContext::getBaseElementType(const VariableArrayType *VAT) {
- QualType ElemTy = VAT->getElementType();
-
- if (const VariableArrayType *VAT = getAsVariableArrayType(ElemTy))
- return getBaseElementType(VAT);
-
+QualType ASTContext::getBaseElementType(QualType QT) {
+ QualifierCollector Qs;
+ while (true) {
+ const Type *UT = Qs.strip(QT);
+ if (const ArrayType *AT = getAsArrayType(QualType(UT,0))) {
+ QT = AT->getElementType();
+ } else {
+ return Qs.apply(QT);
+ }
+ }
+}
+
+QualType ASTContext::getBaseElementType(const ArrayType *AT) {
+ QualType ElemTy = AT->getElementType();
+
+ if (const ArrayType *AT = getAsArrayType(ElemTy))
+ return getBaseElementType(AT);
+
return ElemTy;
}
+/// getConstantArrayElementCount - Returns number of constant array elements.
+uint64_t
+ASTContext::getConstantArrayElementCount(const ConstantArrayType *CA) const {
+ uint64_t ElementCount = 1;
+ do {
+ ElementCount *= CA->getSize().getZExtValue();
+ CA = dyn_cast<ConstantArrayType>(CA->getElementType());
+ } while (CA);
+ return ElementCount;
+}
+
/// 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())
+ if (const ComplexType *CT = T->getAs<ComplexType>())
return getFloatingRank(CT->getElementType());
- assert(T->getAsBuiltinType() && "getFloatingRank(): not a floating type");
- switch (T->getAsBuiltinType()->getKind()) {
+ assert(T->getAs<BuiltinType>() && "getFloatingRank(): not a floating type");
+ switch (T->getAs<BuiltinType>()->getKind()) {
default: assert(0 && "getFloatingRank(): not a floating type");
case BuiltinType::Float: return FloatRank;
case BuiltinType::Double: return DoubleRank;
@@ -2197,8 +2468,8 @@ static FloatingRank getFloatingRank(QualType T) {
}
}
-/// getFloatingTypeOfSizeWithinDomain - Returns a real floating
-/// point or a complex type (based on typeDomain/typeSize).
+/// 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,
@@ -2225,11 +2496,11 @@ QualType ASTContext::getFloatingTypeOfSizeWithinDomain(QualType Size,
/// 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.
+/// 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)
@@ -2245,6 +2516,15 @@ unsigned ASTContext::getIntegerRank(Type *T) {
if (EnumType* ET = dyn_cast<EnumType>(T))
T = ET->getDecl()->getIntegerType().getTypePtr();
+ if (T->isSpecificBuiltinType(BuiltinType::WChar))
+ T = getFromTargetType(Target.getWCharType()).getTypePtr();
+
+ if (T->isSpecificBuiltinType(BuiltinType::Char16))
+ T = getFromTargetType(Target.getChar16Type()).getTypePtr();
+
+ if (T->isSpecificBuiltinType(BuiltinType::Char32))
+ T = getFromTargetType(Target.getChar32Type()).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.
@@ -2278,117 +2558,163 @@ unsigned ASTContext::getIntegerRank(Type *T) {
}
}
-/// getIntegerTypeOrder - Returns the highest ranked integer type:
+/// \brief Whether this is a promotable bitfield reference according
+/// to C99 6.3.1.1p2, bullet 2 (and GCC extensions).
+///
+/// \returns the type this bit-field will promote to, or NULL if no
+/// promotion occurs.
+QualType ASTContext::isPromotableBitField(Expr *E) {
+ FieldDecl *Field = E->getBitField();
+ if (!Field)
+ return QualType();
+
+ QualType FT = Field->getType();
+
+ llvm::APSInt BitWidthAP = Field->getBitWidth()->EvaluateAsInt(*this);
+ uint64_t BitWidth = BitWidthAP.getZExtValue();
+ uint64_t IntSize = getTypeSize(IntTy);
+ // GCC extension compatibility: if the bit-field size is less than or equal
+ // to the size of int, it gets promoted no matter what its type is.
+ // For instance, unsigned long bf : 4 gets promoted to signed int.
+ if (BitWidth < IntSize)
+ return IntTy;
+
+ if (BitWidth == IntSize)
+ return FT->isSignedIntegerType() ? IntTy : UnsignedIntTy;
+
+ // Types bigger than int are not subject to promotions, and therefore act
+ // like the base type.
+ // FIXME: This doesn't quite match what gcc does, but what gcc does here
+ // is ridiculous.
+ return QualType();
+}
+
+/// getPromotedIntegerType - Returns the type that Promotable will
+/// promote to: C99 6.3.1.1p2, assuming that Promotable is a promotable
+/// integer type.
+QualType ASTContext::getPromotedIntegerType(QualType Promotable) {
+ assert(!Promotable.isNull());
+ assert(Promotable->isPromotableIntegerType());
+ if (Promotable->isSignedIntegerType())
+ return IntTy;
+ uint64_t PromotableSize = getTypeSize(Promotable);
+ uint64_t IntSize = getTypeSize(IntTy);
+ assert(Promotable->isUnsignedIntegerType() && PromotableSize <= IntSize);
+ return (PromotableSize != IntSize) ? IntTy : UnsignedIntTy;
+}
+
+/// 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.
+/// 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.
+ // 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.
+ // powers of two larger than each other, this is always safe.
return 1;
}
-// getCFConstantStringType - Return the type used for constant CFStrings.
+// getCFConstantStringType - Return the type used for constant CFStrings.
QualType ASTContext::getCFConstantStringType() {
if (!CFConstantStringTypeDecl) {
- CFConstantStringTypeDecl =
- RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
+ 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));
+ FieldTypes[0] = getPointerType(IntTy.withConst());
// int flags;
FieldTypes[1] = IntTy;
// const char *str;
- FieldTypes[2] = getPointerType(CharTy.getQualifiedType(QualType::Const));
+ FieldTypes[2] = getPointerType(CharTy.withConst());
// long length;
- FieldTypes[3] = LongTy;
-
+ FieldTypes[3] = LongTy;
+
// Create fields
for (unsigned i = 0; i < 4; ++i) {
- FieldDecl *Field = FieldDecl::Create(*this, CFConstantStringTypeDecl,
+ FieldDecl *Field = FieldDecl::Create(*this, CFConstantStringTypeDecl,
SourceLocation(), 0,
- FieldTypes[i], /*BitWidth=*/0,
+ FieldTypes[i], /*DInfo=*/0,
+ /*BitWidth=*/0,
/*Mutable=*/false);
CFConstantStringTypeDecl->addDecl(Field);
}
CFConstantStringTypeDecl->completeDefinition(*this);
}
-
+
return getTagDeclType(CFConstantStringTypeDecl);
}
void ASTContext::setCFConstantStringType(QualType T) {
- const RecordType *Rec = T->getAsRecordType();
+ const RecordType *Rec = T->getAs<RecordType>();
assert(Rec && "Invalid CFConstantStringType");
CFConstantStringTypeDecl = Rec->getDecl();
}
-QualType ASTContext::getObjCFastEnumerationStateType()
-{
+QualType ASTContext::getObjCFastEnumerationStateType() {
if (!ObjCFastEnumerationStateTypeDecl) {
ObjCFastEnumerationStateTypeDecl =
RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
&Idents.get("__objcFastEnumerationState"));
-
+
QualType FieldTypes[] = {
UnsignedLongTy,
- getPointerType(ObjCIdType),
+ getPointerType(ObjCIdTypedefType),
getPointerType(UnsignedLongTy),
getConstantArrayType(UnsignedLongTy,
llvm::APInt(32, 5), ArrayType::Normal, 0)
};
-
+
for (size_t i = 0; i < 4; ++i) {
- FieldDecl *Field = FieldDecl::Create(*this,
- ObjCFastEnumerationStateTypeDecl,
- SourceLocation(), 0,
- FieldTypes[i], /*BitWidth=*/0,
+ FieldDecl *Field = FieldDecl::Create(*this,
+ ObjCFastEnumerationStateTypeDecl,
+ SourceLocation(), 0,
+ FieldTypes[i], /*DInfo=*/0,
+ /*BitWidth=*/0,
/*Mutable=*/false);
ObjCFastEnumerationStateTypeDecl->addDecl(Field);
}
-
+
ObjCFastEnumerationStateTypeDecl->completeDefinition(*this);
}
-
+
return getTagDeclType(ObjCFastEnumerationStateTypeDecl);
}
void ASTContext::setObjCFastEnumerationStateType(QualType T) {
- const RecordType *Rec = T->getAsRecordType();
+ const RecordType *Rec = T->getAs<RecordType>();
assert(Rec && "Invalid ObjCFAstEnumerationStateType");
ObjCFastEnumerationStateTypeDecl = Rec->getDecl();
}
@@ -2399,7 +2725,7 @@ 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;
}
@@ -2407,7 +2733,7 @@ static bool isTypeTypedefedAsBOOL(QualType T) {
/// 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));
@@ -2419,7 +2745,7 @@ int ASTContext::getObjCEncodingTypeSize(QualType type) {
/// getObjCEncodingForMethodDecl - Return the encoded type for this method
/// declaration.
-void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl,
+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.
@@ -2444,13 +2770,13 @@ void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl,
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();
+ 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
@@ -2472,11 +2798,11 @@ void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl,
/// 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
+/// 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 {
@@ -2493,7 +2819,7 @@ void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl,
/// kPropertyNonAtomic = 'N' // property non-atomic
/// };
/// @endcode
-void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD,
+void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD,
const Decl *Container,
std::string& S) {
// Collect information from the property implementation decl(s).
@@ -2502,7 +2828,7 @@ void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD,
// FIXME: Duplicated code due to poor abstraction.
if (Container) {
- if (const ObjCCategoryImplDecl *CID =
+ if (const ObjCCategoryImplDecl *CID =
dyn_cast<ObjCCategoryImplDecl>(Container)) {
for (ObjCCategoryImplDecl::propimpl_iterator
i = CID->propimpl_begin(), e = CID->propimpl_end();
@@ -2529,7 +2855,7 @@ void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD,
SynthesizePID = PID;
}
}
- }
+ }
}
}
@@ -2539,7 +2865,7 @@ void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD,
// 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,
+ getObjCEncodingForTypeImpl(PD->getType(), S, true, true, 0,
true /* outermost type */,
true /* encoding for property */);
@@ -2549,7 +2875,7 @@ void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD,
switch (PD->getSetterKind()) {
case ObjCPropertyDecl::Assign: break;
case ObjCPropertyDecl::Copy: S += ",C"; break;
- case ObjCPropertyDecl::Retain: S += ",&"; break;
+ case ObjCPropertyDecl::Retain: S += ",&"; break;
}
}
@@ -2560,7 +2886,7 @@ void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD,
if (PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic)
S += ",N";
-
+
if (PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_getter) {
S += ",G";
S += PD->getGetterName().getAsString();
@@ -2581,17 +2907,17 @@ void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD,
}
/// getLegacyIntegralTypeEncoding -
-/// Another legacy compatibility encoding: 32-bit longs are encoded as
-/// 'l' or 'L' , but not always. For typedefs, we need to use
+/// 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 (isa<TypedefType>(PointeeTy.getTypePtr())) {
+ if (const BuiltinType *BT = PointeeTy->getAs<BuiltinType>()) {
if (BT->getKind() == BuiltinType::ULong &&
((const_cast<ASTContext *>(this))->getIntWidth(PointeeTy) == 32))
PointeeTy = UnsignedIntTy;
- else
+ else
if (BT->getKind() == BuiltinType::Long &&
((const_cast<ASTContext *>(this))->getIntWidth(PointeeTy) == 32))
PointeeTy = IntTy;
@@ -2605,11 +2931,11 @@ void ASTContext::getObjCEncodingForType(QualType T, std::string& S,
// 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,
+ getObjCEncodingForTypeImpl(T, S, true, true, Field,
true /* outermost type */);
}
-static void EncodeBitField(const ASTContext *Context, std::string& S,
+static void EncodeBitField(const ASTContext *Context, std::string& S,
const FieldDecl *FD) {
const Expr *E = FD->getBitWidth();
assert(E && "bitfield width not there - getObjCEncodingForTypeImpl");
@@ -2625,83 +2951,66 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
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';
+ if (const BuiltinType *BT = T->getAs<BuiltinType>()) {
+ if (FD && FD->isBitField())
+ return EncodeBitField(this, S, FD);
+ 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::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;
+ 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;
}
- } else if (const ComplexType *CT = T->getAsComplexType()) {
+
+ S += encoding;
+ return;
+ }
+
+ if (const ComplexType *CT = T->getAs<ComplexType>()) {
S += 'j';
- getObjCEncodingForTypeImpl(CT->getElementType(), S, false, false, 0, false,
+ 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 ObjCObjectPointerType *QIDT = T->getAsObjCQualifiedIdType();
- S += '"';
- for (ObjCObjectPointerType::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()) {
+
+ if (const PointerType *PT = T->getAs<PointerType>()) {
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())) {
+ // Also, do not emit the 'r' for anything but the outermost type!
+ if (isa<TypedefType>(T.getTypePtr())) {
if (OutermostType && T.isConstQualified()) {
isReadOnly = true;
S += 'r';
}
- }
- else if (OutermostType) {
+ } else if (OutermostType) {
QualType P = PointeeTy;
- while (P->getAsPointerType())
- P = P->getAsPointerType()->getPointeeType();
+ while (P->getAs<PointerType>())
+ P = P->getAs<PointerType>()->getPointeeType();
if (P.isConstQualified()) {
isReadOnly = true;
S += 'r';
@@ -2718,46 +3027,11 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
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)) {
+ 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'.
@@ -2765,26 +3039,39 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
S += '*';
return;
}
+ } else if (const RecordType *RTy = PointeeTy->getAs<RecordType>()) {
+ // GCC binary compat: Need to convert "struct objc_class *" to "#".
+ if (RTy->getDecl()->getIdentifier() == &Idents.get("objc_class")) {
+ S += '#';
+ return;
+ }
+ // GCC binary compat: Need to convert "struct objc_object *" to "@".
+ if (RTy->getDecl()->getIdentifier() == &Idents.get("objc_object")) {
+ S += '@';
+ return;
+ }
+ // fall through...
}
-
S += '^';
getLegacyIntegralTypeEncoding(PointeeTy);
- getObjCEncodingForTypeImpl(PointeeTy, S,
- false, ExpandPointedToStructures,
+ getObjCEncodingForTypeImpl(PointeeTy, S, false, ExpandPointedToStructures,
NULL);
- } else if (const ArrayType *AT =
- // Ignore type qualifiers etc.
- dyn_cast<ArrayType>(T->getCanonicalTypeInternal())) {
+ return;
+ }
+
+ 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,
+ getObjCEncodingForTypeImpl(AT->getElementType(), S,
false, ExpandStructures, FD);
} else {
S += '[';
-
+
if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT))
S += llvm::utostr(CAT->getSize().getZExtValue());
else {
@@ -2792,14 +3079,20 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
assert(isa<VariableArrayType>(AT) && "Unknown array type!");
S += '0';
}
-
- getObjCEncodingForTypeImpl(AT->getElementType(), S,
+
+ getObjCEncodingForTypeImpl(AT->getElementType(), S,
false, ExpandStructures, FD);
S += ']';
}
- } else if (T->getAsFunctionType()) {
+ return;
+ }
+
+ if (T->getAs<FunctionType>()) {
S += '?';
- } else if (const RecordType *RTy = T->getAsRecordType()) {
+ return;
+ }
+
+ if (const RecordType *RTy = T->getAs<RecordType>()) {
RecordDecl *RDecl = RTy->getDecl();
S += RDecl->isUnion() ? '(' : '{';
// Anonymous structures print as '?'
@@ -2818,30 +3111,39 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
S += Field->getNameAsString();
S += '"';
}
-
+
// Special case bit-fields.
if (Field->isBitField()) {
- getObjCEncodingForTypeImpl(Field->getType(), S, false, true,
+ getObjCEncodingForTypeImpl(Field->getType(), S, false, true,
(*Field));
} else {
QualType qt = Field->getType();
getLegacyIntegralTypeEncoding(qt);
- getObjCEncodingForTypeImpl(qt, S, false, true,
+ getObjCEncodingForTypeImpl(qt, S, false, true,
FD);
}
}
}
S += RDecl->isUnion() ? ')' : '}';
- } else if (T->isEnumeralType()) {
+ return;
+ }
+
+ if (T->isEnumeralType()) {
if (FD && FD->isBitField())
EncodeBitField(this, S, FD);
else
S += 'i';
- } else if (T->isBlockPointerType()) {
+ return;
+ }
+
+ if (T->isBlockPointerType()) {
S += "@?"; // Unlike a pointer-to-function, which is "^?".
- } else if (T->isObjCInterfaceType()) {
+ return;
+ }
+
+ if (const ObjCInterfaceType *OIT = T->getAs<ObjCInterfaceType>()) {
// @encode(class_name)
- ObjCInterfaceDecl *OI = T->getAsObjCInterfaceType()->getDecl();
+ ObjCInterfaceDecl *OI = OIT->getDecl();
S += '{';
const IdentifierInfo *II = OI->getIdentifier();
S += II->getName();
@@ -2850,19 +3152,78 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
CollectObjCIvars(OI, RecFields);
for (unsigned i = 0, e = RecFields.size(); i != e; ++i) {
if (RecFields[i]->isBitField())
- getObjCEncodingForTypeImpl(RecFields[i]->getType(), S, false, true,
+ getObjCEncodingForTypeImpl(RecFields[i]->getType(), S, false, true,
RecFields[i]);
else
- getObjCEncodingForTypeImpl(RecFields[i]->getType(), S, false, true,
+ getObjCEncodingForTypeImpl(RecFields[i]->getType(), S, false, true,
FD);
}
S += '}';
+ return;
}
- else
- assert(0 && "@encode for type not implemented!");
+
+ if (const ObjCObjectPointerType *OPT = T->getAs<ObjCObjectPointerType>()) {
+ if (OPT->isObjCIdType()) {
+ S += '@';
+ return;
+ }
+
+ if (OPT->isObjCClassType()) {
+ S += '#';
+ return;
+ }
+
+ if (OPT->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.
+ S += '"';
+ for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(),
+ E = OPT->qual_end(); I != E; ++I) {
+ S += '<';
+ S += (*I)->getNameAsString();
+ S += '>';
+ }
+ S += '"';
+ }
+ return;
+ }
+
+ QualType PointeeTy = OPT->getPointeeType();
+ 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) {
+ S += '"';
+ S += OPT->getInterfaceDecl()->getNameAsCString();
+ for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(),
+ E = OPT->qual_end(); I != E; ++I) {
+ S += '<';
+ S += (*I)->getNameAsString();
+ S += '>';
+ }
+ S += '"';
+ }
+ return;
+ }
+
+ assert(0 && "@encode for type not implemented!");
}
-void ASTContext::getObjCEncodingForTypeQualifier(Decl::ObjCDeclQualifier QT,
+void ASTContext::getObjCEncodingForTypeQualifier(Decl::ObjCDeclQualifier QT,
std::string& S) const {
if (QT & Decl::OBJC_TQ_In)
S += 'n';
@@ -2878,46 +3239,26 @@ void ASTContext::getObjCEncodingForTypeQualifier(Decl::ObjCDeclQualifier QT,
S += 'V';
}
-void ASTContext::setBuiltinVaListType(QualType T)
-{
+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::setObjCIdType(QualType T) {
+ ObjCIdTypedefType = T;
}
-void ASTContext::setObjCSelType(QualType T)
-{
+void ASTContext::setObjCSelType(QualType T) {
ObjCSelType = T;
- const TypedefType *TT = T->getAsTypedefType();
+ const TypedefType *TT = T->getAs<TypedefType>();
if (!TT)
return;
TypedefDecl *TD = TT->getDecl();
// typedef struct objc_selector *SEL;
- const PointerType *ptr = TD->getUnderlyingType()->getAsPointerType();
+ const PointerType *ptr = TD->getUnderlyingType()->getAs<PointerType>();
if (!ptr)
return;
const RecordType *rec = ptr->getPointeeType()->getAsStructureType();
@@ -2926,38 +3267,24 @@ void ASTContext::setObjCSelType(QualType T)
SelStructType = rec;
}
-void ASTContext::setObjCProtoType(QualType QT)
-{
+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::setObjCClassType(QualType T) {
+ ObjCClassTypedefType = T;
}
void ASTContext::setObjCConstantStringInterface(ObjCInterfaceDecl *Decl) {
- assert(ObjCConstantStringType.isNull() &&
+ 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,
+TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS,
bool TemplateKeyword,
TemplateDecl *Template) {
llvm::FoldingSetNodeID ID;
@@ -2974,11 +3301,31 @@ TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS,
return TemplateName(QTN);
}
+/// \brief Retrieve the template name that represents a qualified
+/// template name such as \c std::vector.
+TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS,
+ bool TemplateKeyword,
+ OverloadedFunctionDecl *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,
+TemplateName ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS,
const IdentifierInfo *Name) {
- assert(NNS->isDependent() && "Nested name specifier must be dependent");
+ assert((!NNS || NNS->isDependent()) &&
+ "Nested name specifier must be dependent");
llvm::FoldingSetNodeID ID;
DependentTemplateName::Profile(ID, NNS, Name);
@@ -3007,7 +3354,7 @@ TemplateName ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS,
/// is actually a value of type @c TargetInfo::IntType.
QualType ASTContext::getFromTargetType(unsigned Type) const {
switch (Type) {
- case TargetInfo::NoInt: return QualType();
+ case TargetInfo::NoInt: return QualType();
case TargetInfo::SignedShort: return ShortTy;
case TargetInfo::UnsignedShort: return UnsignedShortTy;
case TargetInfo::SignedInt: return IntTy;
@@ -3029,6 +3376,7 @@ QualType ASTContext::getFromTargetType(unsigned Type) const {
/// 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.
+/// FIXME: Move to Type.
///
bool ASTContext::isObjCNSObjectType(QualType Ty) const {
if (TypedefType *TDT = dyn_cast<TypedefType>(Ty)) {
@@ -3036,68 +3384,30 @@ bool ASTContext::isObjCNSObjectType(QualType Ty) const {
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;
+Qualifiers::GC ASTContext::getObjCGCAttrKind(const QualType &Ty) const {
+ Qualifiers::GC GCAttrs = Qualifiers::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
+ // (or pointers to them) be treated as though they were declared
// as __strong.
- if (GCAttrs == QualType::GCNone) {
- if (isObjCObjectPointerType(Ty))
- GCAttrs = QualType::Strong;
+ if (GCAttrs == Qualifiers::GCNone) {
+ if (Ty->isObjCObjectPointerType() || Ty->isBlockPointerType())
+ GCAttrs = Qualifiers::Strong;
else if (Ty->isPointerType())
- return getObjCGCAttrKind(Ty->getAsPointerType()->getPointeeType());
+ return getObjCGCAttrKind(Ty->getAs<PointerType>()->getPointeeType());
}
// Non-pointers have none gc'able attribute regardless of the attribute
// set on them.
- else if (!Ty->isPointerType() && !isObjCObjectPointerType(Ty))
- return QualType::GCNone;
+ else if (!Ty->isAnyPointerType() && !Ty->isBlockPointerType())
+ return Qualifiers::GCNone;
}
return GCAttrs;
}
@@ -3106,7 +3416,7 @@ QualType::GCAttrTypes ASTContext::getObjCGCAttrKind(const QualType &Ty) const {
// Type Compatibility Testing
//===----------------------------------------------------------------------===//
-/// areCompatVectorTypes - Return true if the two specified vector types are
+/// areCompatVectorTypes - Return true if the two specified vector types are
/// compatible.
static bool areCompatVectorTypes(const VectorType *LHS,
const VectorType *RHS) {
@@ -3115,46 +3425,207 @@ static bool areCompatVectorTypes(const VectorType *LHS,
LHS->getNumElements() == RHS->getNumElements();
}
+//===----------------------------------------------------------------------===//
+// ObjCQualifiedIdTypesAreCompatible - Compatibility testing for qualified id's.
+//===----------------------------------------------------------------------===//
+
+/// ProtocolCompatibleWithProtocol - return 'true' if 'lProto' is in the
+/// inheritance hierarchy of 'rProto'.
+bool ASTContext::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;
+}
+
+/// QualifiedIdConformsQualifiedId - compare id<p,...> with id<p1,...>
+/// return true if lhs's protocols conform to rhs's protocol; false
+/// otherwise.
+bool ASTContext::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.
+bool ASTContext::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs,
+ bool compare) {
+ // Allow id<P..> and an 'id' or void* type in all cases.
+ if (lhs->isVoidPointerType() ||
+ lhs->isObjCIdType() || lhs->isObjCClassType())
+ return true;
+ else if (rhs->isVoidPointerType() ||
+ rhs->isObjCIdType() || rhs->isObjCClassType())
+ return true;
+
+ if (const ObjCObjectPointerType *lhsQID = lhs->getAsObjCQualifiedIdType()) {
+ const ObjCObjectPointerType *rhsOPT = rhs->getAs<ObjCObjectPointerType>();
+
+ if (!rhsOPT) return false;
+
+ if (rhsOPT->qual_empty()) {
+ // If the RHS is a unqualified interface pointer "NSString*",
+ // make sure we check the class hierarchy.
+ if (ObjCInterfaceDecl *rhsID = rhsOPT->getInterfaceDecl()) {
+ for (ObjCObjectPointerType::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 (!rhsID->ClassImplementsProtocol(*I, true))
+ return false;
+ }
+ }
+ // If there are no qualifiers and no interface, we have an 'id'.
+ return true;
+ }
+ // Both the right and left sides have qualifiers.
+ for (ObjCObjectPointerType::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 (ObjCObjectPointerType::qual_iterator J = rhsOPT->qual_begin(),
+ E = rhsOPT->qual_end(); J != E; ++J) {
+ ObjCProtocolDecl *rhsProto = *J;
+ if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) ||
+ (compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) {
+ match = true;
+ break;
+ }
+ }
+ // If the RHS is a qualified interface pointer "NSString<P>*",
+ // make sure we check the class hierarchy.
+ if (ObjCInterfaceDecl *rhsID = rhsOPT->getInterfaceDecl()) {
+ for (ObjCObjectPointerType::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 (rhsID->ClassImplementsProtocol(*I, true)) {
+ match = true;
+ break;
+ }
+ }
+ }
+ if (!match)
+ return false;
+ }
+
+ return true;
+ }
+
+ const ObjCObjectPointerType *rhsQID = rhs->getAsObjCQualifiedIdType();
+ assert(rhsQID && "One of the LHS/RHS should be id<x>");
+
+ if (const ObjCObjectPointerType *lhsOPT =
+ lhs->getAsObjCInterfacePointerType()) {
+ if (lhsOPT->qual_empty()) {
+ bool match = false;
+ if (ObjCInterfaceDecl *lhsID = lhsOPT->getInterfaceDecl()) {
+ for (ObjCObjectPointerType::qual_iterator I = rhsQID->qual_begin(),
+ E = rhsQID->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 (lhsID->ClassImplementsProtocol(*I, true)) {
+ match = true;
+ break;
+ }
+ }
+ if (!match)
+ return false;
+ }
+ return true;
+ }
+ // Both the right and left sides have qualifiers.
+ for (ObjCObjectPointerType::qual_iterator I = lhsOPT->qual_begin(),
+ E = lhsOPT->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 (ObjCObjectPointerType::qual_iterator J = rhsQID->qual_begin(),
+ E = rhsQID->qual_end(); J != E; ++J) {
+ ObjCProtocolDecl *rhsProto = *J;
+ if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) ||
+ (compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) {
+ match = true;
+ break;
+ }
+ }
+ if (!match)
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
/// 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 ObjCObjectPointerType *LHSOPT,
+ const ObjCObjectPointerType *RHSOPT) {
+ // If either type represents the built-in 'id' or 'Class' types, return true.
+ if (LHSOPT->isObjCBuiltinType() || RHSOPT->isObjCBuiltinType())
+ return true;
+
+ if (LHSOPT->isObjCQualifiedIdType() || RHSOPT->isObjCQualifiedIdType())
+ return ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0),
+ QualType(RHSOPT,0),
+ false);
+
+ const ObjCInterfaceType* LHS = LHSOPT->getInterfaceType();
+ const ObjCInterfaceType* RHS = RHSOPT->getInterfaceType();
+ if (LHS && RHS) // We have 2 user-defined types.
+ return canAssignObjCInterfaces(LHS, RHS);
+
+ return false;
+}
+
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))
+ if (LHS->getNumProtocols() == 0)
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))
+ if (RHS->getNumProtocols() == 0)
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();
+
+ for (ObjCInterfaceType::qual_iterator LHSPI = LHS->qual_begin(),
+ LHSPE = LHS->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()))
+ for (ObjCInterfaceType::qual_iterator RHSPI = RHS->qual_begin(),
+ RHSPE = RHS->qual_end();
+ RHSPI != RHSPE; RHSPI++) {
+ if ((*RHSPI)->lookupProtocolNamed((*LHSPI)->getIdentifier())) {
RHSImplementsProtocol = true;
+ break;
+ }
}
// FIXME: For better diagnostics, consider passing back the protocol name.
if (!RHSImplementsProtocol)
@@ -3166,38 +3637,27 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCInterfaceType *LHS,
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)
+ const ObjCObjectPointerType *LHSOPT = LHS->getAs<ObjCObjectPointerType>();
+ const ObjCObjectPointerType *RHSOPT = RHS->getAs<ObjCObjectPointerType>();
+
+ if (!LHSOPT || !RHSOPT)
return false;
- return canAssignObjCInterfaces(LHSIface, RHSIface) ||
- canAssignObjCInterfaces(RHSIface, LHSIface);
+
+ return canAssignObjCInterfaces(LHSOPT, RHSOPT) ||
+ canAssignObjCInterfaces(RHSOPT, LHSOPT);
}
-/// typesAreCompatible - C99 6.7.3p9: For two qualified types to be compatible,
+/// 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
+/// 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 FunctionType *lbase = lhs->getAs<FunctionType>();
+ const FunctionType *rbase = rhs->getAs<FunctionType>();
const FunctionProtoType *lproto = dyn_cast<FunctionProtoType>(lbase);
const FunctionProtoType *rproto = dyn_cast<FunctionProtoType>(rbase);
bool allLTypes = true;
@@ -3210,6 +3670,12 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) {
allLTypes = false;
if (getCanonicalType(retType) != getCanonicalType(rbase->getResultType()))
allRTypes = false;
+ // FIXME: double check this
+ bool NoReturn = lbase->getNoReturnAttr() || rbase->getNoReturnAttr();
+ if (NoReturn != lbase->getNoReturnAttr())
+ allLTypes = false;
+ if (NoReturn != rbase->getNoReturnAttr())
+ allRTypes = false;
if (lproto && rproto) { // two C99 style function prototypes
assert(!lproto->hasExceptionSpec() && !rproto->hasExceptionSpec() &&
@@ -3244,7 +3710,8 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) {
if (allLTypes) return lhs;
if (allRTypes) return rhs;
return getFunctionType(retType, types.begin(), types.size(),
- lproto->isVariadic(), lproto->getTypeQuals());
+ lproto->isVariadic(), lproto->getTypeQuals(),
+ NoReturn);
}
if (lproto) allRTypes = false;
@@ -3270,13 +3737,13 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) {
if (allLTypes) return lhs;
if (allRTypes) return rhs;
return getFunctionType(retType, proto->arg_type_begin(),
- proto->getNumArgs(), lproto->isVariadic(),
- lproto->getTypeQuals());
+ proto->getNumArgs(), proto->isVariadic(),
+ proto->getTypeQuals(), NoReturn);
}
if (allLTypes) return lhs;
if (allRTypes) return rhs;
- return getFunctionNoProtoType(retType);
+ return getFunctionNoProtoType(retType, NoReturn);
}
QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
@@ -3289,9 +3756,9 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
// 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())
+ if (const ReferenceType *RT = LHS->getAs<ReferenceType>())
LHS = RT->getPointeeType();
- if (const ReferenceType *RT = RHS->getAsReferenceType())
+ if (const ReferenceType *RT = RHS->getAs<ReferenceType>())
RHS = RT->getPointeeType();
QualType LHSCan = getCanonicalType(LHS),
@@ -3301,11 +3768,38 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
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())
+ // If the qualifiers are different, the types aren't compatible... mostly.
+ Qualifiers LQuals = LHSCan.getQualifiers();
+ Qualifiers RQuals = RHSCan.getQualifiers();
+ if (LQuals != RQuals) {
+ // If any of these qualifiers are different, we have a type
+ // mismatch.
+ if (LQuals.getCVRQualifiers() != RQuals.getCVRQualifiers() ||
+ LQuals.getAddressSpace() != RQuals.getAddressSpace())
+ return QualType();
+
+ // Exactly one GC qualifier difference is allowed: __strong is
+ // okay if the other type has no GC qualifier but is an Objective
+ // C object pointer (i.e. implicitly strong by default). We fix
+ // this by pretending that the unqualified type was actually
+ // qualified __strong.
+ Qualifiers::GC GC_L = LQuals.getObjCGCAttr();
+ Qualifiers::GC GC_R = RQuals.getObjCGCAttr();
+ assert((GC_L != GC_R) && "unequal qualifier sets had only equal elements");
+
+ if (GC_L == Qualifiers::Weak || GC_R == Qualifiers::Weak)
+ return QualType();
+
+ if (GC_L == Qualifiers::Strong && RHSCan->isObjCObjectPointerType()) {
+ return mergeTypes(LHS, getObjCGCQualType(RHS, Qualifiers::Strong));
+ }
+ if (GC_R == Qualifiers::Strong && LHSCan->isObjCObjectPointerType()) {
+ return mergeTypes(getObjCGCQualType(LHS, Qualifiers::Strong), RHS);
+ }
return QualType();
+ }
+
+ // Okay, qualifiers are equal.
Type::TypeClass LHSClass = LHSCan->getTypeClass();
Type::TypeClass RHSClass = RHSCan->getTypeClass();
@@ -3315,120 +3809,25 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
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) {
- QualType::GCAttrTypes GCLHSAttr = LHSCan.getObjCGCAttr();
- // __weak attribute must appear on both declarations.
- // __strong attribue is redundant if other decl is an objective-c
- // object pointer (or decorated with __strong attribute); otherwise
- // issue error.
- if ((GCAttr == QualType::Weak && GCLHSAttr != GCAttr) ||
- (GCAttr == QualType::Strong && GCLHSAttr != GCAttr &&
- LHSCan->isPointerType() && !isObjCObjectPointerType(LHSCan) &&
- !isObjCIdStructType(LHSCan->getAsPointerType()->getPointeeType())))
- return QualType();
-
- RHS = QualType(cast<ExtQualType>(RHS.getDesugaredType())->getBaseType(),
- RHS.getCVRQualifiers());
- QualType Result = mergeTypes(LHS, RHS);
- if (!Result.isNull()) {
- 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) {
- QualType::GCAttrTypes GCRHSAttr = RHSCan.getObjCGCAttr();
- // __weak attribute must appear on both declarations. __strong
- // __strong attribue is redundant if other decl is an objective-c
- // object pointer (or decorated with __strong attribute); otherwise
- // issue error.
- if ((GCAttr == QualType::Weak && GCRHSAttr != GCAttr) ||
- (GCAttr == QualType::Strong && GCRHSAttr != GCAttr &&
- RHSCan->isPointerType() && !isObjCObjectPointerType(RHSCan) &&
- !isObjCIdStructType(RHSCan->getAsPointerType()->getPointeeType())))
- return QualType();
-
- LHS = QualType(cast<ExtQualType>(LHS.getDesugaredType())->getBaseType(),
- LHS.getCVRQualifiers());
- QualType Result = mergeTypes(LHS, RHS);
- if (!Result.isNull()) {
- 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()) {
+ // a signed integer type, or an unsigned integer type.
+ if (const EnumType* ETy = LHS->getAs<EnumType>()) {
if (ETy->getDecl()->getIntegerType() == RHSCan.getUnqualifiedType())
return RHS;
}
- if (const EnumType* ETy = RHS->getAsEnumType()) {
+ if (const EnumType* ETy = RHS->getAs<EnumType>()) {
if (ETy->getDecl()->getIntegerType() == LHSCan.getUnqualifiedType())
return LHS;
}
@@ -3456,15 +3855,14 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
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 LHSPointee = LHS->getAs<PointerType>()->getPointeeType();
+ QualType RHSPointee = RHS->getAs<PointerType>()->getPointeeType();
QualType ResultType = mergeTypes(LHSPointee, RHSPointee);
if (ResultType.isNull()) return QualType();
if (getCanonicalType(LHSPointee) == getCanonicalType(ResultType))
@@ -3476,8 +3874,8 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
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 LHSPointee = LHS->getAs<BlockPointerType>()->getPointeeType();
+ QualType RHSPointee = RHS->getAs<BlockPointerType>()->getPointeeType();
QualType ResultType = mergeTypes(LHSPointee, RHSPointee);
if (ResultType.isNull()) return QualType();
if (getCanonicalType(LHSPointee) == getCanonicalType(ResultType))
@@ -3525,15 +3923,13 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
}
if (getCanonicalType(LHSElem) == getCanonicalType(ResultType)) return LHS;
if (getCanonicalType(RHSElem) == getCanonicalType(ResultType)) return RHS;
- return getIncompleteArrayType(ResultType, ArrayType::ArraySizeModifier(),0);
+ 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.
@@ -3543,56 +3939,31 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
return QualType();
case Type::Vector:
// FIXME: The merged type should be an ExtVector!
- if (areCompatVectorTypes(LHS->getAsVectorType(), RHS->getAsVectorType()))
+ if (areCompatVectorTypes(LHS->getAs<VectorType>(), RHS->getAs<VectorType>()))
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();
+ const ObjCInterfaceType* LHSIface = LHS->getAs<ObjCInterfaceType>();
+ const ObjCInterfaceType* RHSIface = RHS->getAs<ObjCInterfaceType>();
if (LHSIface && RHSIface &&
canAssignObjCInterfaces(LHSIface, RHSIface))
return LHS;
return QualType();
}
- case Type::ObjCObjectPointer:
- // FIXME: finish
- // Distinct qualified id's are not compatible.
+ case Type::ObjCObjectPointer: {
+ if (canAssignObjCInterfaces(LHS->getAs<ObjCObjectPointerType>(),
+ RHS->getAs<ObjCObjectPointerType>()))
+ return LHS;
+
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;
@@ -3617,9 +3988,9 @@ unsigned ASTContext::getIntWidth(QualType T) {
QualType ASTContext::getCorrespondingUnsignedType(QualType T) {
assert(T->isSignedIntegerType() && "Unexpected type");
- if (const EnumType* ETy = T->getAsEnumType())
+ if (const EnumType* ETy = T->getAs<EnumType>())
T = ETy->getDecl()->getIntegerType();
- const BuiltinType* BTy = T->getAsBuiltinType();
+ const BuiltinType* BTy = T->getAs<BuiltinType>();
assert (BTy && "Unexpected signed integer type");
switch (BTy->getKind()) {
case BuiltinType::Char_S:
@@ -3652,18 +4023,18 @@ void ExternalASTSource::PrintStats() { }
/// 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,
+static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context,
ASTContext::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;
+ 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!");
@@ -3682,7 +4053,7 @@ static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context,
}
QualType Type;
-
+
// Read the base type.
switch (*Str++) {
default: assert(0 && "Unknown builtin type letter!");
@@ -3764,34 +4135,43 @@ static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context,
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(II);
- if (Lookup.first != Lookup.second && isa<TypeDecl>(*Lookup.first)) {
- Type = Context.getTypeDeclType(cast<TypeDecl>(*Lookup.first));
- break;
+ case 'X': {
+ QualType ElementType = DecodeTypeFromStr(Str, Context, Error, false);
+ Type = Context.getComplexType(ElementType);
+ break;
+ }
+ case 'P':
+ Type = Context.getFILEType();
+ if (Type.isNull()) {
+ Error = ASTContext::GE_Missing_stdio;
+ return QualType();
}
- else {
- Error = ASTContext::GE_Missing_FILE;
+ break;
+ case 'J':
+ if (Signed)
+ Type = Context.getsigjmp_bufType();
+ else
+ Type = Context.getjmp_bufType();
+
+ if (Type.isNull()) {
+ Error = ASTContext::GE_Missing_setjmp;
return QualType();
}
+ break;
}
- }
-
+
if (!AllowTypeModifiers)
return Type;
-
+
Done = false;
while (!Done) {
switch (*Str++) {
@@ -3804,11 +4184,11 @@ static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context,
break;
// FIXME: There's no way to have a built-in with an rvalue ref arg.
case 'C':
- Type = Type.getQualifiedType(QualType::Const);
+ Type = Type.withConst();
break;
}
}
-
+
return Type;
}
@@ -3816,9 +4196,9 @@ static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context,
QualType ASTContext::GetBuiltinType(unsigned id,
GetBuiltinTypeError &Error) {
const char *TypeStr = BuiltinInfo.GetTypeString(id);
-
+
llvm::SmallVector<QualType, 8> ArgTypes;
-
+
Error = GE_None;
QualType ResType = DecodeTypeFromStr(TypeStr, *this, Error);
if (Error != GE_None)
@@ -3831,7 +4211,7 @@ QualType ASTContext::GetBuiltinType(unsigned id,
// Do array -> pointer decay. The builtin should use the decayed type.
if (Ty->isArrayType())
Ty = getArrayDecayedType(Ty);
-
+
ArgTypes.push_back(Ty);
}
@@ -3844,3 +4224,143 @@ QualType ASTContext::GetBuiltinType(unsigned id,
return getFunctionType(ResType, ArgTypes.data(), ArgTypes.size(),
TypeStr[0] == '.', 0);
}
+
+QualType
+ASTContext::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 = getPromotedIntegerType(lhs);
+ else
+ lhs = lhs.getUnqualifiedType();
+ if (rhs->isPromotableIntegerType())
+ rhs = getPromotedIntegerType(rhs);
+ 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 = getFloatingTypeOrder(lhs, rhs);
+
+ if (result > 0) { // The left side is bigger, convert rhs.
+ rhs = getFloatingTypeOfSizeWithinDomain(lhs, rhs);
+ } else if (result < 0) { // The right side is bigger, convert lhs.
+ lhs = 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 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 getComplexType(rhs);
+ }
+ // We have two real floating types, float/complex combos were handled above.
+ // Convert the smaller operand to the bigger result.
+ int result = 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 (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 = 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 (getIntWidth(lhs) != 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 = getCorrespondingUnsignedType(lhsSigned ? lhs : rhs);
+ }
+ return destType;
+}
diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt
index ac4cbb2..20e1150 100644
--- a/lib/AST/CMakeLists.txt
+++ b/lib/AST/CMakeLists.txt
@@ -4,28 +4,31 @@ add_clang_library(clangAST
APValue.cpp
ASTConsumer.cpp
ASTContext.cpp
- CFG.cpp
- DeclarationName.cpp
- DeclBase.cpp
+ CXXInheritance.cpp
Decl.cpp
+ DeclBase.cpp
DeclCXX.cpp
DeclGroup.cpp
DeclObjC.cpp
DeclPrinter.cpp
DeclTemplate.cpp
- ExprConstant.cpp
+ DeclarationName.cpp
Expr.cpp
ExprCXX.cpp
+ ExprConstant.cpp
InheritViz.cpp
NestedNameSpecifier.cpp
ParentMap.cpp
+ RecordLayoutBuilder.cpp
Stmt.cpp
StmtDumper.cpp
StmtIterator.cpp
StmtPrinter.cpp
+ StmtProfile.cpp
StmtViz.cpp
TemplateName.cpp
Type.cpp
+ TypeLoc.cpp
)
add_dependencies(clangAST ClangDiagnosticAST)
diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp
new file mode 100644
index 0000000..4a46eab
--- /dev/null
+++ b/lib/AST/CXXInheritance.cpp
@@ -0,0 +1,244 @@
+//===------ CXXInheritance.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 routines that help analyzing C++ inheritance hierarchies.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/DeclCXX.h"
+#include <algorithm>
+#include <set>
+
+using namespace clang;
+
+/// \brief Computes the set of declarations referenced by these base
+/// paths.
+void CXXBasePaths::ComputeDeclsFound() {
+ assert(NumDeclsFound == 0 && !DeclsFound &&
+ "Already computed the set of declarations");
+
+ std::set<NamedDecl *> Decls;
+ for (CXXBasePaths::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);
+}
+
+CXXBasePaths::decl_iterator CXXBasePaths::found_decls_begin() {
+ if (NumDeclsFound == 0)
+ ComputeDeclsFound();
+ return DeclsFound;
+}
+
+CXXBasePaths::decl_iterator CXXBasePaths::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 CXXBasePaths::isAmbiguous(QualType BaseType) {
+ assert(BaseType->isCanonical() && "Base type must be the canonical type");
+ assert(BaseType.hasQualifiers() == 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 CXXBasePaths::clear() {
+ Paths.clear();
+ ClassSubobjects.clear();
+ ScratchPath.clear();
+ DetectedVirtual = 0;
+}
+
+/// @brief Swaps the contents of this CXXBasePaths structure with the
+/// contents of Other.
+void CXXBasePaths::swap(CXXBasePaths &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);
+}
+
+bool CXXRecordDecl::isDerivedFrom(CXXRecordDecl *Base) {
+ CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/false,
+ /*DetectVirtual=*/false);
+ return isDerivedFrom(Base, Paths);
+}
+
+bool CXXRecordDecl::isDerivedFrom(CXXRecordDecl *Base, CXXBasePaths &Paths) {
+ if (getCanonicalDecl() == Base->getCanonicalDecl())
+ return false;
+
+ Paths.setOrigin(this);
+ return lookupInBases(&FindBaseClass, Base->getCanonicalDecl(), Paths);
+}
+
+bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches,
+ void *UserData,
+ CXXBasePaths &Paths) {
+ bool FoundPath = false;
+
+ ASTContext &Context = getASTContext();
+ for (base_class_iterator BaseSpec = bases_begin(), BaseSpecEnd = 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();
+
+ // C++ [temp.dep]p3:
+ // In the definition of a class template or a member of a class template,
+ // if a base class of the class template depends on a template-parameter,
+ // the base class scope is not examined during unqualified name lookup
+ // either at the point of definition of the class template or member or
+ // during an instantiation of the class tem- plate or member.
+ if (BaseType->isDependentType())
+ continue;
+
+ // 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->getAs<RecordType>();
+ SetVirtual = true;
+ }
+ } else
+ ++Subobjects.second;
+
+ if (Paths.isRecordingPaths()) {
+ // Add this base specifier to the current path.
+ CXXBasePathElement Element;
+ Element.Base = &*BaseSpec;
+ Element.Class = this;
+ if (BaseSpec->isVirtual())
+ Element.SubobjectNumber = 0;
+ else
+ Element.SubobjectNumber = Subobjects.second;
+ Paths.ScratchPath.push_back(Element);
+ }
+
+ if (BaseMatches(BaseSpec, Paths.ScratchPath, UserData)) {
+ // 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;
+ }
+ } else if (VisitBase) {
+ CXXRecordDecl *BaseRecord
+ = cast<CXXRecordDecl>(BaseSpec->getType()->getAs<RecordType>()
+ ->getDecl());
+ if (BaseRecord->lookupInBases(BaseMatches, UserData, Paths)) {
+ // 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.
+
+ // 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;
+}
+
+bool CXXRecordDecl::FindBaseClass(CXXBaseSpecifier *Specifier,
+ CXXBasePath &Path,
+ void *BaseRecord) {
+ assert(((Decl *)BaseRecord)->getCanonicalDecl() == BaseRecord &&
+ "User data for FindBaseClass is not canonical!");
+ return Specifier->getType()->getAs<RecordType>()->getDecl()
+ ->getCanonicalDecl() == BaseRecord;
+}
+
+bool CXXRecordDecl::FindTagMember(CXXBaseSpecifier *Specifier,
+ CXXBasePath &Path,
+ void *Name) {
+ RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl();
+
+ DeclarationName N = DeclarationName::getFromOpaquePtr(Name);
+ for (Path.Decls = BaseRecord->lookup(N);
+ Path.Decls.first != Path.Decls.second;
+ ++Path.Decls.first) {
+ if ((*Path.Decls.first)->isInIdentifierNamespace(IDNS_Tag))
+ return true;
+ }
+
+ return false;
+}
+
+bool CXXRecordDecl::FindOrdinaryMember(CXXBaseSpecifier *Specifier,
+ CXXBasePath &Path,
+ void *Name) {
+ RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl();
+
+ const unsigned IDNS = IDNS_Ordinary | IDNS_Tag | IDNS_Member;
+ DeclarationName N = DeclarationName::getFromOpaquePtr(Name);
+ for (Path.Decls = BaseRecord->lookup(N);
+ Path.Decls.first != Path.Decls.second;
+ ++Path.Decls.first) {
+ if ((*Path.Decls.first)->isInIdentifierNamespace(IDNS))
+ return true;
+ }
+
+ return false;
+}
+
+bool CXXRecordDecl::FindNestedNameSpecifierMember(CXXBaseSpecifier *Specifier,
+ CXXBasePath &Path,
+ void *Name) {
+ RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl();
+
+ DeclarationName N = DeclarationName::getFromOpaquePtr(Name);
+ for (Path.Decls = BaseRecord->lookup(N);
+ Path.Decls.first != Path.Decls.second;
+ ++Path.Decls.first) {
+ // FIXME: Refactor the "is it a nested-name-specifier?" check
+ if (isa<TypedefDecl>(*Path.Decls.first) ||
+ (*Path.Decls.first)->isInIdentifierNamespace(IDNS_Tag))
+ return true;
+ }
+
+ return false;
+}
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 3d02150..429729e 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -16,11 +16,14 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/TypeLoc.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/Expr.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/IdentifierTable.h"
+#include "clang/Parse/DeclSpec.h"
+#include "llvm/Support/ErrorHandling.h"
#include <vector>
using namespace clang;
@@ -34,11 +37,15 @@ void Attr::Destroy(ASTContext &C) {
C.Deallocate((void*)this);
}
+/// \brief Return the TypeLoc wrapper for the type source info.
+TypeLoc DeclaratorInfo::getTypeLoc() const {
+ return TypeLoc(Ty, (void*)(this + 1));
+}
//===----------------------------------------------------------------------===//
// Decl Allocation/Deallocation Method Implementations
//===----------------------------------------------------------------------===//
-
+
TranslationUnitDecl *TranslationUnitDecl::Create(ASTContext &C) {
return new (C) TranslationUnitDecl(C);
@@ -52,7 +59,7 @@ NamespaceDecl *NamespaceDecl::Create(ASTContext &C, DeclContext *DC,
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);
}
@@ -68,9 +75,9 @@ const char *VarDecl::getStorageClassSpecifierString(StorageClass 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::PrivateExtern: return "__private_extern__"; break;
case VarDecl::Register: return "register"; break;
- case VarDecl::Static: return "static"; break;
+ case VarDecl::Static: return "static"; break;
}
assert(0 && "Invalid storage class");
@@ -79,34 +86,45 @@ const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) {
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 T, DeclaratorInfo *DInfo,
+ StorageClass S, Expr *DefArg) {
+ return new (C) ParmVarDecl(ParmVar, DC, L, Id, T, DInfo, S, DefArg);
}
QualType ParmVarDecl::getOriginalType() const {
- if (const OriginalParmVarDecl *PVD =
+ 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);
- }
+SourceRange ParmVarDecl::getDefaultArgRange() const {
+ if (const Expr *E = getInit())
+ return E->getSourceRange();
+
+ if (const Expr *E = getUninstantiatedDefaultArg())
+ return E->getSourceRange();
+
+ return SourceRange();
+}
- Init = I;
+void VarDecl::setInit(ASTContext &C, Expr *I) {
+ if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>()) {
+ Eval->~EvaluatedStmt();
+ C.Deallocate(Eval);
}
-bool VarDecl::isExternC(ASTContext &Context) const {
+ Init = I;
+}
+
+bool VarDecl::isExternC() const {
+ ASTContext &Context = getASTContext();
if (!Context.getLangOptions().CPlusPlus)
- return (getDeclContext()->isTranslationUnit() &&
+ return (getDeclContext()->isTranslationUnit() &&
getStorageClass() != Static) ||
(getDeclContext()->isFunctionOrMethod() && hasExternalStorage());
- for (const DeclContext *DC = getDeclContext(); !DC->isTranslationUnit();
+ for (const DeclContext *DC = getDeclContext(); !DC->isTranslationUnit();
DC = DC->getParent()) {
if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC)) {
if (Linkage->getLanguage() == LinkageSpecDecl::lang_c)
@@ -125,20 +143,19 @@ bool VarDecl::isExternC(ASTContext &Context) const {
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);
+ QualType T, DeclaratorInfo *DInfo,
+ QualType OT, StorageClass S, Expr *DefArg) {
+ return new (C) OriginalParmVarDecl(DC, L, Id, T, DInfo, 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);
+ SourceLocation L,
+ DeclarationName N, QualType T,
+ DeclaratorInfo *DInfo,
+ StorageClass S, bool isInline,
+ bool hasWrittenPrototype) {
+ FunctionDecl *New
+ = new (C) FunctionDecl(Function, DC, L, N, T, DInfo, S, isInline);
New->HasWrittenPrototype = hasWrittenPrototype;
return New;
}
@@ -148,16 +165,16 @@ BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation 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);
+ IdentifierInfo *Id, QualType T,
+ DeclaratorInfo *DInfo, Expr *BW, bool Mutable) {
+ return new (C) FieldDecl(Decl::Field, DC, L, Id, T, DInfo, BW, Mutable);
}
bool FieldDecl::isAnonymousStructOrUnion() const {
if (!isImplicit() || getDeclName())
return false;
-
- if (const RecordType *Record = getType()->getAsRecordType())
+
+ if (const RecordType *Record = getType()->getAs<RecordType>())
return Record->getDecl()->isAnonymousStructOrUnion();
return false;
@@ -182,9 +199,9 @@ TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC,
}
EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
- IdentifierInfo *Id,
+ IdentifierInfo *Id, SourceLocation TKL,
EnumDecl *PrevDecl) {
- EnumDecl *Enum = new (C) EnumDecl(DC, L, Id);
+ EnumDecl *Enum = new (C) EnumDecl(DC, L, Id, PrevDecl, TKL);
C.getTypeDeclType(Enum, PrevDecl);
return Enum;
}
@@ -210,6 +227,10 @@ FileScopeAsmDecl *FileScopeAsmDecl::Create(ASTContext &C, DeclContext *DC,
//===----------------------------------------------------------------------===//
std::string NamedDecl::getQualifiedNameAsString() const {
+ return getQualifiedNameAsString(getASTContext().getLangOptions());
+}
+
+std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const {
std::vector<std::string> Names;
std::string QualName;
const DeclContext *Ctx = getDeclContext();
@@ -223,15 +244,14 @@ std::string NamedDecl::getQualifiedNameAsString() const {
// scope class/struct/union. How do we handle this case?
break;
- if (const ClassTemplateSpecializationDecl *Spec
+ if (const ClassTemplateSpecializationDecl *Spec
= dyn_cast<ClassTemplateSpecializationDecl>(Ctx)) {
const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
- PrintingPolicy Policy(getASTContext().getLangOptions());
std::string TemplateArgsStr
= TemplateSpecializationType::PrintTemplateArgumentList(
TemplateArgs.getFlatArgumentList(),
TemplateArgs.flat_size(),
- Policy);
+ P);
Names.push_back(Spec->getIdentifier()->getName() + TemplateArgsStr);
} else if (const NamedDecl *ND = dyn_cast<NamedDecl>(Ctx))
Names.push_back(ND->getNameAsString());
@@ -253,7 +273,6 @@ std::string NamedDecl::getQualifiedNameAsString() const {
return QualName;
}
-
bool NamedDecl::declarationReplaces(NamedDecl *OldD) const {
assert(getDeclName() == OldD->getDeclName() && "Declaration name mismatch");
@@ -263,7 +282,7 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD) const {
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;
@@ -275,11 +294,14 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD) const {
= dyn_cast<FunctionTemplateDecl>(OldD))
return FunctionTemplate->getTemplatedDecl()
->declarationReplaces(OldFunctionTemplate->getTemplatedDecl());
-
+
// For method declarations, we keep track of redeclarations.
if (isa<ObjCMethodDecl>(this))
return false;
-
+
+ if (isa<ObjCInterfaceDecl>(this) && isa<ObjCCompatibleAliasDecl>(OldD))
+ return true;
+
// 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.
@@ -310,13 +332,23 @@ NamedDecl *NamedDecl::getUnderlyingDecl() {
}
//===----------------------------------------------------------------------===//
+// DeclaratorDecl Implementation
+//===----------------------------------------------------------------------===//
+
+SourceLocation DeclaratorDecl::getTypeSpecStartLoc() const {
+ if (DeclInfo)
+ return DeclInfo->getTypeLoc().getTypeSpecRange().getBegin();
+ return SourceLocation();
+}
+
+//===----------------------------------------------------------------------===//
// 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);
+ IdentifierInfo *Id, QualType T, DeclaratorInfo *DInfo,
+ StorageClass S) {
+ return new (C) VarDecl(Var, DC, L, Id, T, DInfo, S);
}
void VarDecl::Destroy(ASTContext& C) {
@@ -341,6 +373,31 @@ SourceRange VarDecl::getSourceRange() const {
return SourceRange(getLocation(), getLocation());
}
+VarDecl *VarDecl::getInstantiatedFromStaticDataMember() {
+ if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo())
+ return cast<VarDecl>(MSI->getInstantiatedFrom());
+
+ return 0;
+}
+
+TemplateSpecializationKind VarDecl::getTemplateSpecializationKind() {
+ if (MemberSpecializationInfo *MSI
+ = getASTContext().getInstantiatedFromStaticDataMember(this))
+ return MSI->getTemplateSpecializationKind();
+
+ return TSK_Undeclared;
+}
+
+MemberSpecializationInfo *VarDecl::getMemberSpecializationInfo() {
+ return getASTContext().getInstantiatedFromStaticDataMember(this);
+}
+
+void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) {
+ MemberSpecializationInfo *MSI = getMemberSpecializationInfo();
+ assert(MSI && "Not an instantiated static data member?");
+ MSI->setTemplateSpecializationKind(TSK);
+}
+
bool VarDecl::isTentativeDefinition(ASTContext &Context) const {
if (!isFileVarDecl() || Context.getLangOptions().CPlusPlus)
return false;
@@ -351,11 +408,19 @@ bool VarDecl::isTentativeDefinition(ASTContext &Context) const {
}
const Expr *VarDecl::getDefinition(const VarDecl *&Def) const {
- Def = this;
- while (Def && !Def->getInit())
- Def = Def->getPreviousDeclaration();
+ redecl_iterator I = redecls_begin(), E = redecls_end();
+ while (I != E && !I->getInit())
+ ++I;
- return Def? Def->getInit() : 0;
+ if (I != E) {
+ Def = *I;
+ return I->getInit();
+ }
+ return 0;
+}
+
+VarDecl *VarDecl::getCanonicalDecl() {
+ return getFirstDeclaration();
}
//===----------------------------------------------------------------------===//
@@ -369,27 +434,39 @@ void FunctionDecl::Destroy(ASTContext& C) {
for (param_iterator I=param_begin(), E=param_end(); I!=E; ++I)
(*I)->Destroy(C);
+ FunctionTemplateSpecializationInfo *FTSInfo
+ = TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>();
+ if (FTSInfo)
+ C.Deallocate(FTSInfo);
+
+ MemberSpecializationInfo *MSInfo
+ = TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>();
+ if (MSInfo)
+ C.Deallocate(MSInfo);
+
C.Deallocate(ParamInfo);
Decl::Destroy(C);
}
-
-Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const {
- for (const FunctionDecl *FD = this; FD != 0; FD = FD->PreviousDeclaration) {
- if (FD->Body) {
- Definition = FD;
- return FD->Body.get(getASTContext().getExternalSource());
- }
- }
-
- return 0;
+void FunctionDecl::getNameForDiagnostic(std::string &S,
+ const PrintingPolicy &Policy,
+ bool Qualified) const {
+ NamedDecl::getNameForDiagnostic(S, Policy, Qualified);
+ const TemplateArgumentList *TemplateArgs = getTemplateSpecializationArgs();
+ if (TemplateArgs)
+ S += TemplateSpecializationType::PrintTemplateArgumentList(
+ TemplateArgs->getFlatArgumentList(),
+ TemplateArgs->flat_size(),
+ Policy);
+
}
-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);
+Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const {
+ for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
+ if (I->Body) {
+ Definition = *I;
+ return I->Body.get(getASTContext().getExternalSource());
}
}
@@ -403,21 +480,24 @@ void FunctionDecl::setBody(Stmt *B) {
}
bool FunctionDecl::isMain() const {
- return getDeclContext()->getLookupContext()->isTranslationUnit() &&
+ ASTContext &Context = getASTContext();
+ return !Context.getLangOptions().Freestanding &&
+ getDeclContext()->getLookupContext()->isTranslationUnit() &&
getIdentifier() && getIdentifier()->isStr("main");
}
-bool FunctionDecl::isExternC(ASTContext &Context) const {
+bool FunctionDecl::isExternC() const {
+ ASTContext &Context = getASTContext();
// 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();
+ 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 &&
+ return getStorageClass() != Static &&
!getAttr<OverloadableAttr>();
break;
@@ -434,7 +514,7 @@ bool FunctionDecl::isGlobal() const {
if (getStorageClass() == Static)
return false;
- for (const DeclContext *DC = getDeclContext();
+ for (const DeclContext *DC = getDeclContext();
DC->isNamespace();
DC = DC->getParent()) {
if (const NamespaceDecl *Namespace = cast<NamespaceDecl>(DC)) {
@@ -454,9 +534,10 @@ bool FunctionDecl::isGlobal() const {
/// 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
+/// 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 {
+unsigned FunctionDecl::getBuiltinID() const {
+ ASTContext &Context = getASTContext();
if (!getIdentifier() || !getIdentifier()->getBuiltinID())
return 0;
@@ -481,7 +562,7 @@ unsigned FunctionDecl::getBuiltinID(ASTContext &Context) const {
// 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()
+ cast<LinkageSpecDecl>(getDeclContext())->getLanguage()
== LinkageSpecDecl::lang_c &&
!getAttr<OverloadableAttr>())
return BuiltinID;
@@ -495,18 +576,18 @@ unsigned FunctionDecl::getBuiltinID(ASTContext &Context) const {
/// 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();
+ const FunctionType *FT = getType()->getAs<FunctionType>();
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);
@@ -533,42 +614,87 @@ unsigned FunctionDecl::getMinRequiredArguments() const {
return NumRequiredArgs;
}
-bool FunctionDecl::hasActiveGNUInlineAttribute(ASTContext &Context) const {
- if (!isInline() || !hasAttr<GNUInlineAttr>())
+/// \brief For an inline function definition in C, determine whether the
+/// definition will be externally visible.
+///
+/// Inline function definitions are always available for inlining optimizations.
+/// However, depending on the language dialect, declaration specifiers, and
+/// attributes, the definition of an inline function may or may not be
+/// "externally" visible to other translation units in the program.
+///
+/// In C99, inline definitions are not externally visible by default. However,
+/// if even one of the globa-scope declarations is marked "extern inline", the
+/// inline definition becomes externally visible (C99 6.7.4p6).
+///
+/// In GNU89 mode, or if the gnu_inline attribute is attached to the function
+/// definition, we use the GNU semantics for inline, which are nearly the
+/// opposite of C99 semantics. In particular, "inline" by itself will create
+/// an externally visible symbol, but "extern inline" will not create an
+/// externally visible symbol.
+bool FunctionDecl::isInlineDefinitionExternallyVisible() const {
+ assert(isThisDeclarationADefinition() && "Must have the function definition");
+ assert(isInline() && "Function must be inline");
+
+ if (!getASTContext().getLangOptions().C99 || hasAttr<GNUInlineAttr>()) {
+ // GNU inline semantics. Based on a number of examples, we came up with the
+ // following heuristic: if the "inline" keyword is present on a
+ // declaration of the function but "extern" is not present on that
+ // declaration, then the symbol is externally visible. Otherwise, the GNU
+ // "extern inline" semantics applies and the symbol is not externally
+ // visible.
+ for (redecl_iterator Redecl = redecls_begin(), RedeclEnd = redecls_end();
+ Redecl != RedeclEnd;
+ ++Redecl) {
+ if (Redecl->isInline() && Redecl->getStorageClass() != Extern)
+ return true;
+ }
+
+ // GNU "extern inline" semantics; no externally visible symbol.
return false;
-
- for (const FunctionDecl *FD = getPreviousDeclaration(); FD;
- FD = FD->getPreviousDeclaration()) {
- if (FD->isInline() && !FD->hasAttr<GNUInlineAttr>())
- return false;
}
-
- return true;
-}
-
-bool FunctionDecl::isExternGNUInline(ASTContext &Context) const {
- if (!hasActiveGNUInlineAttribute(Context))
- return false;
-
- for (const FunctionDecl *FD = this; FD; FD = FD->getPreviousDeclaration())
- if (FD->getStorageClass() == Extern && FD->hasAttr<GNUInlineAttr>())
- return true;
-
+
+ // C99 6.7.4p6:
+ // [...] If all of the file scope declarations for a function in a
+ // translation unit include the inline function specifier without extern,
+ // then the definition in that translation unit is an inline definition.
+ for (redecl_iterator Redecl = redecls_begin(), RedeclEnd = redecls_end();
+ Redecl != RedeclEnd;
+ ++Redecl) {
+ // Only consider file-scope declarations in this test.
+ if (!Redecl->getLexicalDeclContext()->isTranslationUnit())
+ continue;
+
+ if (!Redecl->isInline() || Redecl->getStorageClass() == Extern)
+ return true; // Not an inline definition
+ }
+
+ // C99 6.7.4p6:
+ // An inline definition does not provide an external definition for the
+ // function, and does not forbid an external definition in another
+ // translation unit.
return false;
}
-void
+void
FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) {
- PreviousDeclaration = PrevDecl;
-
+ redeclarable_base::setPreviousDeclaration(PrevDecl);
+
if (FunctionTemplateDecl *FunTmpl = getDescribedFunctionTemplate()) {
- FunctionTemplateDecl *PrevFunTmpl
+ FunctionTemplateDecl *PrevFunTmpl
= PrevDecl? PrevDecl->getDescribedFunctionTemplate() : 0;
assert((!PrevDecl || PrevFunTmpl) && "Function/function template mismatch");
FunTmpl->setPreviousDeclaration(PrevFunTmpl);
}
}
+const FunctionDecl *FunctionDecl::getCanonicalDecl() const {
+ return getFirstDeclaration();
+}
+
+FunctionDecl *FunctionDecl::getCanonicalDecl() {
+ return getFirstDeclaration();
+}
+
/// getOverloadedOperator - Which C++ overloaded operator this
/// function represents, if any.
OverloadedOperatorKind FunctionDecl::getOverloadedOperator() const {
@@ -578,8 +704,29 @@ OverloadedOperatorKind FunctionDecl::getOverloadedOperator() const {
return OO_None;
}
+FunctionDecl *FunctionDecl::getInstantiatedFromMemberFunction() const {
+ if (MemberSpecializationInfo *Info = getMemberSpecializationInfo())
+ return cast<FunctionDecl>(Info->getInstantiatedFrom());
+
+ return 0;
+}
+
+MemberSpecializationInfo *FunctionDecl::getMemberSpecializationInfo() const {
+ return TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>();
+}
+
+void
+FunctionDecl::setInstantiationOfMemberFunction(FunctionDecl *FD,
+ TemplateSpecializationKind TSK) {
+ assert(TemplateOrSpecialization.isNull() &&
+ "Member function is already a specialization");
+ MemberSpecializationInfo *Info
+ = new (getASTContext()) MemberSpecializationInfo(FD, TSK);
+ TemplateOrSpecialization = Info;
+}
+
FunctionTemplateDecl *FunctionDecl::getPrimaryTemplate() const {
- if (FunctionTemplateSpecializationInfo *Info
+ if (FunctionTemplateSpecializationInfo *Info
= TemplateOrSpecialization
.dyn_cast<FunctionTemplateSpecializationInfo*>()) {
return Info->Template.getPointer();
@@ -589,79 +736,151 @@ FunctionTemplateDecl *FunctionDecl::getPrimaryTemplate() const {
const TemplateArgumentList *
FunctionDecl::getTemplateSpecializationArgs() const {
- if (FunctionTemplateSpecializationInfo *Info
- = TemplateOrSpecialization
- .dyn_cast<FunctionTemplateSpecializationInfo*>()) {
+ if (FunctionTemplateSpecializationInfo *Info
+ = TemplateOrSpecialization
+ .dyn_cast<FunctionTemplateSpecializationInfo*>()) {
return Info->TemplateArguments;
}
return 0;
}
-void
+void
FunctionDecl::setFunctionTemplateSpecialization(ASTContext &Context,
FunctionTemplateDecl *Template,
const TemplateArgumentList *TemplateArgs,
- void *InsertPos) {
- FunctionTemplateSpecializationInfo *Info
+ void *InsertPos,
+ TemplateSpecializationKind TSK) {
+ assert(TSK != TSK_Undeclared &&
+ "Must specify the type of function template specialization");
+ FunctionTemplateSpecializationInfo *Info
= TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>();
if (!Info)
Info = new (Context) FunctionTemplateSpecializationInfo;
-
+
Info->Function = this;
Info->Template.setPointer(Template);
- Info->Template.setInt(0); // Implicit instantiation, unless told otherwise
+ Info->Template.setInt(TSK - 1);
Info->TemplateArguments = TemplateArgs;
TemplateOrSpecialization = Info;
-
+
// Insert this function template specialization into the set of known
- // function template specialiations.
- Template->getSpecializations().InsertNode(Info, InsertPos);
+ // function template specializations.
+ if (InsertPos)
+ Template->getSpecializations().InsertNode(Info, InsertPos);
+ else {
+ // Try to insert the new node. If there is an existing node, remove it
+ // first.
+ FunctionTemplateSpecializationInfo *Existing
+ = Template->getSpecializations().GetOrInsertNode(Info);
+ if (Existing) {
+ Template->getSpecializations().RemoveNode(Existing);
+ Template->getSpecializations().GetOrInsertNode(Info);
+ }
+ }
}
-bool FunctionDecl::isExplicitSpecialization() const {
- // FIXME: check this property for explicit specializations of member
- // functions of class templates.
- FunctionTemplateSpecializationInfo *Info
+TemplateSpecializationKind FunctionDecl::getTemplateSpecializationKind() const {
+ // For a function template specialization, query the specialization
+ // information object.
+ FunctionTemplateSpecializationInfo *FTSInfo
= TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>();
- if (!Info)
- return false;
+ if (FTSInfo)
+ return FTSInfo->getTemplateSpecializationKind();
+
+ MemberSpecializationInfo *MSInfo
+ = TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>();
+ if (MSInfo)
+ return MSInfo->getTemplateSpecializationKind();
- return Info->isExplicitSpecialization();
+ return TSK_Undeclared;
+}
+
+void
+FunctionDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) {
+ if (FunctionTemplateSpecializationInfo *FTSInfo
+ = TemplateOrSpecialization.dyn_cast<
+ FunctionTemplateSpecializationInfo*>())
+ FTSInfo->setTemplateSpecializationKind(TSK);
+ else if (MemberSpecializationInfo *MSInfo
+ = TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>())
+ MSInfo->setTemplateSpecializationKind(TSK);
+ else
+ assert(false && "Function cannot have a template specialization kind");
}
-void FunctionDecl::setExplicitSpecialization(bool ES) {
- // FIXME: set this property for explicit specializations of member functions
- // of class templates.
- FunctionTemplateSpecializationInfo *Info
- = TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>();
- if (Info)
- Info->setExplicitSpecialization(ES);
+bool FunctionDecl::isOutOfLine() const {
+ // FIXME: Should we restrict this to member functions?
+ if (Decl::isOutOfLine())
+ return true;
+
+ // If this function was instantiated from a member function of a
+ // class template, check whether that member function was defined out-of-line.
+ if (FunctionDecl *FD = getInstantiatedFromMemberFunction()) {
+ const FunctionDecl *Definition;
+ if (FD->getBody(Definition))
+ return Definition->isOutOfLine();
+ }
+
+ // If this function was instantiated from a function template,
+ // check whether that function template was defined out-of-line.
+ if (FunctionTemplateDecl *FunTmpl = getPrimaryTemplate()) {
+ const FunctionDecl *Definition;
+ if (FunTmpl->getTemplatedDecl()->getBody(Definition))
+ return Definition->isOutOfLine();
+ }
+
+ return false;
}
//===----------------------------------------------------------------------===//
// TagDecl Implementation
//===----------------------------------------------------------------------===//
+SourceRange TagDecl::getSourceRange() const {
+ SourceLocation E = RBraceLoc.isValid() ? RBraceLoc : getLocation();
+ return SourceRange(TagKeywordLoc, E);
+}
+
+TagDecl* TagDecl::getCanonicalDecl() {
+ return getFirstDeclaration();
+}
+
void TagDecl::startDefinition() {
- TagType *TagT = const_cast<TagType *>(TypeForDecl->getAsTagType());
- TagT->decl.setPointer(this);
- TagT->getAsTagType()->decl.setInt(1);
+ if (TagType *TagT = const_cast<TagType *>(TypeForDecl->getAs<TagType>())) {
+ TagT->decl.setPointer(this);
+ TagT->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);
+ if (TagType *TagT = const_cast<TagType *>(TypeForDecl->getAs<TagType>())) {
+ assert(TagT->decl.getPointer() == this &&
+ "Attempt to redefine a tag definition?");
+ 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;
+ if (isDefinition())
+ return const_cast<TagDecl *>(this);
+
+ for (redecl_iterator R = redecls_begin(), REnd = redecls_end();
+ R != REnd; ++R)
+ if (R->isDefinition())
+ return *R;
+
+ return 0;
+}
+
+TagDecl::TagKind TagDecl::getTagKindForTypeSpec(unsigned TypeSpec) {
+ switch (TypeSpec) {
+ default: llvm::llvm_unreachable("unexpected type specifier");
+ case DeclSpec::TST_struct: return TK_struct;
+ case DeclSpec::TST_class: return TK_class;
+ case DeclSpec::TST_union: return TK_union;
+ case DeclSpec::TST_enum: return TK_enum;
+ }
}
//===----------------------------------------------------------------------===//
@@ -669,18 +888,20 @@ TagDecl* TagDecl::getDefinition(ASTContext& C) const {
//===----------------------------------------------------------------------===//
RecordDecl::RecordDecl(Kind DK, TagKind TK, DeclContext *DC, SourceLocation L,
- IdentifierInfo *Id)
- : TagDecl(DK, TK, DC, L, Id) {
+ IdentifierInfo *Id, RecordDecl *PrevDecl,
+ SourceLocation TKL)
+ : TagDecl(DK, TK, DC, L, Id, PrevDecl, TKL) {
HasFlexibleArrayMember = false;
AnonymousStructOrUnion = false;
+ HasObjectMember = 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);
+ SourceLocation TKL, RecordDecl* PrevDecl) {
+
+ RecordDecl* R = new (C) RecordDecl(Record, TK, DC, L, Id, PrevDecl, TKL);
C.getTypeDeclType(R, PrevDecl);
return R;
}
@@ -693,7 +914,7 @@ void RecordDecl::Destroy(ASTContext& C) {
}
bool RecordDecl::isInjectedClassName() const {
- return isImplicit() && getDeclName() && getDeclContext()->isRecord() &&
+ return isImplicit() && getDeclName() && getDeclContext()->isRecord() &&
cast<RecordDecl>(getDeclContext())->getDeclName() == getDeclName();
}
@@ -717,15 +938,15 @@ void BlockDecl::Destroy(ASTContext& C) {
for (param_iterator I=param_begin(), E=param_end(); I!=E; ++I)
(*I)->Destroy(C);
-
- C.Deallocate(ParamInfo);
+
+ 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;
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 96ba19b..224bf87 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -62,12 +62,12 @@ bool Decl::CollectingStats(bool Enable) {
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) { \
@@ -77,7 +77,7 @@ void Decl::PrintStats() {
(int)(n##Derived##s * sizeof(Derived##Decl))); \
}
#include "clang/AST/DeclNodes.def"
-
+
fprintf(stderr, "Total bytes = %d\n", totalBytes);
}
@@ -92,26 +92,26 @@ void Decl::addDeclKind(Kind k) {
bool Decl::isTemplateParameterPack() const {
if (const TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(this))
return TTP->isParameterPack();
-
+
return false;
}
bool Decl::isFunctionOrFunctionTemplate() const {
if (const UsingDecl *UD = dyn_cast<UsingDecl>(this))
return UD->getTargetDecl()->isFunctionOrFunctionTemplate();
-
+
return isa<FunctionDecl>(this) || isa<FunctionTemplateDecl>(this);
}
//===----------------------------------------------------------------------===//
// 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 << ": ";
@@ -123,7 +123,7 @@ void PrettyStackTraceDecl::print(llvm::raw_ostream &OS) const {
OS << " '" << DN->getQualifiedNameAsString() << '\'';
OS << '\n';
}
-
+
//===----------------------------------------------------------------------===//
// Decl Implementation
//===----------------------------------------------------------------------===//
@@ -132,14 +132,14 @@ void PrettyStackTraceDecl::print(llvm::raw_ostream &OS) const {
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;
}
@@ -157,28 +157,39 @@ void Decl::setLexicalDeclContext(DeclContext *DC) {
}
}
+bool Decl::isInAnonymousNamespace() const {
+ const DeclContext *DC = getDeclContext();
+ do {
+ if (const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC))
+ if (ND->isAnonymousNamespace())
+ return true;
+ } while ((DC = DC->getParent()));
+
+ return false;
+}
+
TranslationUnitDecl *Decl::getTranslationUnitDecl() {
if (TranslationUnitDecl *TUD = dyn_cast<TranslationUnitDecl>(this))
return TUD;
DeclContext *DC = getDeclContext();
assert(DC && "This decl is not contained in a translation unit!");
-
+
while (!DC->isTranslationUnit()) {
DC = DC->getParent();
assert(DC && "This decl is not contained in a translation unit!");
}
-
+
return cast<TranslationUnitDecl>(DC);
}
ASTContext &Decl::getASTContext() const {
- return getTranslationUnitDecl()->getASTContext();
+ return getTranslationUnitDecl()->getASTContext();
}
unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
switch (DeclKind) {
- default:
+ default:
if (DeclKind >= FunctionFirst && DeclKind <= FunctionLast)
return IDNS_Ordinary;
assert(0 && "Unknown decl kind!");
@@ -191,6 +202,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case OriginalParmVar:
case NonTypeTemplateParm:
case Using:
+ case UnresolvedUsing:
case ObjCMethod:
case ObjCContainer:
case ObjCCategory:
@@ -198,10 +210,10 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case ObjCProperty:
case ObjCCompatibleAlias:
return IDNS_Ordinary;
-
+
case ObjCProtocol:
return IDNS_ObjCProtocol;
-
+
case ObjCImplementation:
return IDNS_ObjCImplementation;
@@ -212,13 +224,13 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case ObjCAtDefsField:
case ObjCIvar:
return IDNS_Member;
-
+
case Record:
case CXXRecord:
case Enum:
case TemplateTypeParm:
return IDNS_Tag;
-
+
case Namespace:
case Template:
case FunctionTemplate:
@@ -226,8 +238,10 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case TemplateTemplateParm:
case NamespaceAlias:
return IDNS_Tag | IDNS_Ordinary;
-
+
// Never have names.
+ case Friend:
+ case FriendTemplate:
case LinkageSpec:
case FileScopeAsm:
case StaticAssert:
@@ -250,41 +264,41 @@ void Decl::addAttr(Attr *NewAttr) {
NewAttr->setNext(ExistingAttr);
ExistingAttr = NewAttr;
-
+
HasAttrs = true;
}
void Decl::invalidateAttrs() {
if (!HasAttrs) return;
-
+
HasAttrs = false;
getASTContext().eraseDeclAttrs(this);
}
const Attr *Decl::getAttrsImpl() const {
- assert(HasAttrs && "getAttrs() should verify this!");
+ assert(HasAttrs && "getAttrs() should verify this!");
return getASTContext().getDeclAttrs(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);
-
+
ASTContext &Context = getASTContext();
-
+
// Handle the case when both decls have attrs.
if (HasRHSAttr) {
std::swap(Context.getDeclAttrs(this), Context.getDeclAttrs(RHS));
return;
}
-
+
// Otherwise, LHS has an attr and RHS doesn't.
Context.getDeclAttrs(RHS) = Context.getDeclAttrs(this);
Context.eraseDeclAttrs(this);
@@ -300,7 +314,7 @@ void Decl::Destroy(ASTContext &C) {
invalidateAttrs();
HasAttrs = false;
}
-
+
#if 0
// FIXME: Once ownership is fully understood, we can enable this code
if (DeclContext *DC = dyn_cast<DeclContext>(this))
@@ -309,15 +323,15 @@ void Decl::Destroy(ASTContext &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);
@@ -377,8 +391,13 @@ SourceLocation Decl::getBodyRBrace() const {
#ifndef NDEBUG
void Decl::CheckAccessDeclContext() const {
- assert((Access != AS_none || isa<TranslationUnitDecl>(this) ||
- !isa<CXXRecordDecl>(getDeclContext())) &&
+ // If the decl is the toplevel translation unit or if we're not in a
+ // record decl context, we don't need to check anything.
+ if (isa<TranslationUnitDecl>(this) ||
+ !isa<CXXRecordDecl>(getDeclContext()))
+ return;
+
+ assert(Access != AS_none &&
"Access specifier is AS_none inside a record decl");
}
@@ -413,6 +432,22 @@ void DeclContext::DestroyDecls(ASTContext &C) {
(*D++)->Destroy(C);
}
+/// \brief Find the parent context of this context that will be
+/// used for unqualified name lookup.
+///
+/// Generally, the parent lookup context is the semantic context. However, for
+/// a friend function the parent lookup context is the lexical context, which
+/// is the class in which the friend is declared.
+DeclContext *DeclContext::getLookupParent() {
+ // FIXME: Find a better way to identify friends
+ if (isa<FunctionDecl>(this))
+ if (getParent()->getLookupContext()->isFileContext() &&
+ getLexicalParent()->getLookupContext()->isRecord())
+ return getLexicalParent();
+
+ return getParent();
+}
+
bool DeclContext::isDependentContext() const {
if (isFileContext())
return false;
@@ -427,7 +462,7 @@ bool DeclContext::isDependentContext() const {
if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(this))
if (Function->getDescribedFunctionTemplate())
return true;
-
+
return getParent() && getParent()->isDependentContext();
}
@@ -444,11 +479,21 @@ bool DeclContext::isTransparentContext() const {
return false;
}
+bool DeclContext::Encloses(DeclContext *DC) {
+ if (getPrimaryContext() != this)
+ return getPrimaryContext()->Encloses(DC);
+
+ for (; DC; DC = DC->getParent())
+ if (DC->getPrimaryContext() == this)
+ return true;
+ return false;
+}
+
DeclContext *DeclContext::getPrimaryContext() {
switch (DeclKind) {
case Decl::TranslationUnit:
case Decl::LinkageSpec:
- case Decl::Block:
+ case Decl::Block:
// There is only one DeclContext for these entities.
return this;
@@ -473,8 +518,8 @@ DeclContext *DeclContext::getPrimaryContext() {
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() ||
+ if (const TagType *TagT =cast<TagDecl>(this)->TypeForDecl->getAs<TagType>())
+ if (TagT->isBeingDefined() ||
(TagT->getDecl() && TagT->getDecl()->isDefinition()))
return TagT->getDecl();
return this;
@@ -499,13 +544,13 @@ DeclContext *DeclContext::getNextContext() {
/// \brief Load the declarations within this lexical storage from an
/// external source.
-void
+void
DeclContext::LoadLexicalDeclsFromExternalStorage() const {
ExternalASTSource *Source = getParentASTContext().getExternalSource();
assert(hasExternalLexicalStorage() && Source && "No external storage?");
llvm::SmallVector<uint32_t, 64> Decls;
- if (Source->ReadDeclsLexicallyInContext(const_cast<DeclContext *>(this),
+ if (Source->ReadDeclsLexicallyInContext(const_cast<DeclContext *>(this),
Decls))
return;
@@ -537,7 +582,7 @@ DeclContext::LoadLexicalDeclsFromExternalStorage() const {
LastDecl = PrevDecl;
}
-void
+void
DeclContext::LoadVisibleDeclsFromExternalStorage() const {
DeclContext *This = const_cast<DeclContext *>(this);
ExternalASTSource *Source = getParentASTContext().getExternalSource();
@@ -566,14 +611,14 @@ DeclContext::decl_iterator DeclContext::decls_begin() const {
// FIXME: Check whether we need to load some declarations from
// external storage.
- return decl_iterator(FirstDecl);
+ return decl_iterator(FirstDecl);
}
DeclContext::decl_iterator DeclContext::decls_end() const {
if (hasExternalLexicalStorage())
LoadLexicalDeclsFromExternalStorage();
- return decl_iterator();
+ return decl_iterator();
}
bool DeclContext::decls_empty() const {
@@ -583,10 +628,10 @@ bool DeclContext::decls_empty() const {
return !FirstDecl;
}
-void DeclContext::addDecl(Decl *D) {
+void DeclContext::addHiddenDecl(Decl *D) {
assert(D->getLexicalDeclContext() == this &&
"Decl inserted into wrong lexical context");
- assert(!D->getNextDeclInContext() && D != LastDecl &&
+ assert(!D->getNextDeclInContext() && D != LastDecl &&
"Decl already inserted into a DeclContext");
if (FirstDecl) {
@@ -595,6 +640,10 @@ void DeclContext::addDecl(Decl *D) {
} else {
FirstDecl = LastDecl = D;
}
+}
+
+void DeclContext::addDecl(Decl *D) {
+ addHiddenDecl(D);
if (NamedDecl *ND = dyn_cast<NamedDecl>(D))
ND->getDeclContext()->makeDeclVisibleInContext(ND);
@@ -605,12 +654,15 @@ void DeclContext::addDecl(Decl *D) {
/// transparent contexts nested within it).
void DeclContext::buildLookup(DeclContext *DCtx) {
for (; DCtx; DCtx = DCtx->getNextContext()) {
- for (decl_iterator D = DCtx->decls_begin(),
- DEnd = DCtx->decls_end();
+ for (decl_iterator D = DCtx->decls_begin(),
+ DEnd = DCtx->decls_end();
D != DEnd; ++D) {
- // Insert this declaration into the lookup structure
+ // Insert this declaration into the lookup structure, but only
+ // if it's semantically in its decl context. During non-lazy
+ // lookup building, this is implicitly enforced by addDecl.
if (NamedDecl *ND = dyn_cast<NamedDecl>(*D))
- makeDeclVisibleInContextImpl(ND);
+ if (D->getDeclContext() == DCtx)
+ makeDeclVisibleInContextImpl(ND);
// If this declaration is itself a transparent declaration context,
// add its members (recursively).
@@ -621,7 +673,7 @@ void DeclContext::buildLookup(DeclContext *DCtx) {
}
}
-DeclContext::lookup_result
+DeclContext::lookup_result
DeclContext::lookup(DeclarationName Name) {
DeclContext *PrimaryContext = getPrimaryContext();
if (PrimaryContext != this)
@@ -647,7 +699,7 @@ DeclContext::lookup(DeclarationName Name) {
return Pos->second.getLookupResult(getParentASTContext());
}
-DeclContext::lookup_const_result
+DeclContext::lookup_const_result
DeclContext::lookup(DeclarationName Name) const {
return const_cast<DeclContext*>(this)->lookup(Name);
}
@@ -668,7 +720,7 @@ DeclContext *DeclContext::getEnclosingNamespaceContext() {
return Ctx->getPrimaryContext();
}
-void DeclContext::makeDeclVisibleInContext(NamedDecl *D) {
+void DeclContext::makeDeclVisibleInContext(NamedDecl *D, bool Recoverable) {
// FIXME: This feels like a hack. Should DeclarationName support
// template-ids, or is there a better way to keep specializations
// from being visible?
@@ -677,20 +729,20 @@ void DeclContext::makeDeclVisibleInContext(NamedDecl *D) {
DeclContext *PrimaryContext = getPrimaryContext();
if (PrimaryContext != this) {
- PrimaryContext->makeDeclVisibleInContext(D);
+ PrimaryContext->makeDeclVisibleInContext(D, Recoverable);
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)
+ if (LookupPtr || !Recoverable)
makeDeclVisibleInContextImpl(D);
// If we are a transparent context, insert into our parent context,
// too. This operation is recursive.
if (isTransparentContext())
- getParent()->makeDeclVisibleInContext(D);
+ getParent()->makeDeclVisibleInContext(D, Recoverable);
}
void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) {
@@ -720,14 +772,14 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) {
// one, just replace it and return.
if (DeclNameEntries.HandleRedeclaration(getParentASTContext(), 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::udir_iterator_range
DeclContext::getUsingDirectives() const {
lookup_const_result Result = lookup(UsingDirectiveDecl::getName());
return udir_iterator_range(reinterpret_cast<udir_iterator>(Result.first),
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index b8b2952..457f4c8 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -17,6 +17,7 @@
#include "clang/AST/Expr.h"
#include "clang/Basic/IdentifierTable.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallPtrSet.h"
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -24,22 +25,32 @@ using namespace clang;
//===----------------------------------------------------------------------===//
CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id)
- : RecordDecl(K, TK, DC, L, Id),
+ SourceLocation L, IdentifierInfo *Id,
+ CXXRecordDecl *PrevDecl,
+ SourceLocation TKL)
+ : RecordDecl(K, TK, DC, L, Id, PrevDecl, TKL),
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()),
+ Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false),
+ Abstract(false), HasTrivialConstructor(true),
+ HasTrivialCopyConstructor(true), HasTrivialCopyAssignment(true),
+ HasTrivialDestructor(true), ComputedVisibleConversions(false),
+ Bases(0), NumBases(0), VBases(0), NumVBases(0),
+ Conversions(DC, DeclarationName()),
+ VisibleConversions(DC, DeclarationName()),
TemplateOrInstantiation() { }
CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id,
+ SourceLocation TKL,
CXXRecordDecl* PrevDecl,
bool DelayTypeCreation) {
- CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TK, DC, L, Id);
+ CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TK, DC, L, Id,
+ PrevDecl, TKL);
+
+ // FIXME: DelayTypeCreation seems like such a hack
if (!DelayTypeCreation)
- C.getTypeDeclType(R, PrevDecl);
+ C.getTypeDeclType(R, PrevDecl);
return R;
}
@@ -48,14 +59,15 @@ CXXRecordDecl::~CXXRecordDecl() {
void CXXRecordDecl::Destroy(ASTContext &C) {
C.Deallocate(Bases);
+ C.Deallocate(VBases);
this->RecordDecl::Destroy(C);
}
-void
+void
CXXRecordDecl::setBases(ASTContext &C,
- CXXBaseSpecifier const * const *Bases,
+ CXXBaseSpecifier const * const *Bases,
unsigned NumBases) {
- // C++ [dcl.init.aggr]p1:
+ // C++ [dcl.init.aggr]p1:
// An aggregate is an array or a class (clause 9) with [...]
// no base classes [...].
Aggregate = false;
@@ -63,39 +75,109 @@ CXXRecordDecl::setBases(ASTContext &C,
if (this->Bases)
C.Deallocate(this->Bases);
+ int vbaseCount = 0;
+ llvm::SmallVector<const CXXBaseSpecifier*, 8> UniqueVbases;
+ bool hasDirectVirtualBase = false;
+
this->Bases = new(C) CXXBaseSpecifier [NumBases];
this->NumBases = NumBases;
- for (unsigned i = 0; i < NumBases; ++i)
+ for (unsigned i = 0; i < NumBases; ++i) {
this->Bases[i] = *Bases[i];
+ // Keep track of inherited vbases for this base class.
+ const CXXBaseSpecifier *Base = Bases[i];
+ QualType BaseType = Base->getType();
+ // Skip template types.
+ // FIXME. This means that this list must be rebuilt during template
+ // instantiation.
+ if (BaseType->isDependentType())
+ continue;
+ CXXRecordDecl *BaseClassDecl
+ = cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl());
+ if (Base->isVirtual())
+ hasDirectVirtualBase = true;
+ for (CXXRecordDecl::base_class_iterator VBase =
+ BaseClassDecl->vbases_begin(),
+ E = BaseClassDecl->vbases_end(); VBase != E; ++VBase) {
+ // Add this vbase to the array of vbases for current class if it is
+ // not already in the list.
+ // FIXME. Note that we do a linear search as number of such classes are
+ // very few.
+ int i;
+ for (i = 0; i < vbaseCount; ++i)
+ if (UniqueVbases[i]->getType() == VBase->getType())
+ break;
+ if (i == vbaseCount) {
+ UniqueVbases.push_back(VBase);
+ ++vbaseCount;
+ }
+ }
+ }
+ if (hasDirectVirtualBase) {
+ // Iterate one more time through the direct bases and add the virtual
+ // base to the list of vritual bases for current class.
+ for (unsigned i = 0; i < NumBases; ++i) {
+ const CXXBaseSpecifier *VBase = Bases[i];
+ if (!VBase->isVirtual())
+ continue;
+ int j;
+ for (j = 0; j < vbaseCount; ++j)
+ if (UniqueVbases[j]->getType() == VBase->getType())
+ break;
+ if (j == vbaseCount) {
+ UniqueVbases.push_back(VBase);
+ ++vbaseCount;
+ }
+ }
+ }
+ if (vbaseCount > 0) {
+ // build AST for inhireted, direct or indirect, virtual bases.
+ this->VBases = new (C) CXXBaseSpecifier [vbaseCount];
+ this->NumVBases = vbaseCount;
+ for (int i = 0; i < vbaseCount; i++) {
+ QualType QT = UniqueVbases[i]->getType();
+ CXXRecordDecl *VBaseClassDecl
+ = cast<CXXRecordDecl>(QT->getAs<RecordType>()->getDecl());
+ this->VBases[i] =
+ CXXBaseSpecifier(VBaseClassDecl->getSourceRange(), true,
+ VBaseClassDecl->getTagKind() == RecordDecl::TK_class,
+ UniqueVbases[i]->getAccessSpecifier(), QT);
+ }
+ }
}
bool CXXRecordDecl::hasConstCopyConstructor(ASTContext &Context) const {
- return getCopyConstructor(Context, QualType::Const) != 0;
+ return getCopyConstructor(Context, Qualifiers::Const) != 0;
}
-CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(ASTContext &Context,
+CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(ASTContext &Context,
unsigned TypeQuals) const{
QualType ClassType
= Context.getTypeDeclType(const_cast<CXXRecordDecl*>(this));
- DeclarationName ConstructorName
+ DeclarationName ConstructorName
= Context.DeclarationNames.getCXXConstructorName(
Context.getCanonicalType(ClassType));
unsigned FoundTQs;
DeclContext::lookup_const_iterator Con, ConEnd;
for (llvm::tie(Con, ConEnd) = this->lookup(ConstructorName);
Con != ConEnd; ++Con) {
- if (cast<CXXConstructorDecl>(*Con)->isCopyConstructor(Context,
+ // C++ [class.copy]p2:
+ // A non-template constructor for class X is a copy constructor if [...]
+ if (isa<FunctionTemplateDecl>(*Con))
+ continue;
+
+ if (cast<CXXConstructorDecl>(*Con)->isCopyConstructor(Context,
FoundTQs)) {
- if (((TypeQuals & QualType::Const) == (FoundTQs & QualType::Const)) ||
- (!(TypeQuals & QualType::Const) && (FoundTQs & QualType::Const)))
+ if (((TypeQuals & Qualifiers::Const) == (FoundTQs & Qualifiers::Const)) ||
+ (!(TypeQuals & Qualifiers::Const) && (FoundTQs & Qualifiers::Const)))
return cast<CXXConstructorDecl>(*Con);
-
+
}
}
return 0;
}
-bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context) const {
+bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context,
+ const CXXMethodDecl *& MD) const {
QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(
const_cast<CXXRecordDecl*>(this)));
DeclarationName OpName =Context.DeclarationNames.getCXXOperatorName(OO_Equal);
@@ -110,16 +192,17 @@ bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context) const {
const CXXMethodDecl* Method = cast<CXXMethodDecl>(*Op);
if (Method->isStatic())
continue;
- // TODO: Skip templates? Or is this implicitly done due to parameter types?
+ if (Method->getPrimaryTemplate())
+ continue;
const FunctionProtoType *FnType =
- Method->getType()->getAsFunctionProtoType();
+ Method->getType()->getAs<FunctionProtoType>();
assert(FnType && "Overloaded operator has no prototype.");
// Don't assert on this; an invalid decl might have been left in the AST.
if (FnType->getNumArgs() != 1 || FnType->isVariadic())
continue;
bool AcceptsConst = true;
QualType ArgType = FnType->getArgType(0);
- if (const LValueReferenceType *Ref = ArgType->getAsLValueReferenceType()) {
+ if (const LValueReferenceType *Ref = ArgType->getAs<LValueReferenceType>()) {
ArgType = Ref->getPointeeType();
// Is it a non-const lvalue reference?
if (!ArgType.isConstQualified())
@@ -127,7 +210,7 @@ bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context) const {
}
if (Context.getCanonicalType(ArgType).getUnqualifiedType() != ClassType)
continue;
-
+ MD = Method;
// 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;
@@ -138,13 +221,13 @@ bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context) const {
}
void
-CXXRecordDecl::addedConstructor(ASTContext &Context,
+CXXRecordDecl::addedConstructor(ASTContext &Context,
CXXConstructorDecl *ConDecl) {
assert(!ConDecl->isImplicit() && "addedConstructor - not for implicit decl");
// Note that we have a user-declared constructor.
UserDeclaredConstructor = true;
- // C++ [dcl.init.aggr]p1:
+ // C++ [dcl.init.aggr]p1:
// An aggregate is an array or a class (clause 9) with no
// user-declared constructors (12.1) [...].
Aggregate = false;
@@ -156,22 +239,34 @@ CXXRecordDecl::addedConstructor(ASTContext &Context,
// C++ [class.ctor]p5:
// A constructor is trivial if it is an implicitly-declared default
// constructor.
+ // FIXME: C++0x: don't do this for "= default" default constructors.
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))
+ if (ConDecl->isCopyConstructor(Context)) {
UserDeclaredCopyConstructor = true;
+
+ // C++ [class.copy]p6:
+ // A copy constructor is trivial if it is implicitly declared.
+ // FIXME: C++0x: don't do this for "= default" copy constructors.
+ HasTrivialCopyConstructor = false;
+ }
}
void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context,
CXXMethodDecl *OpDecl) {
// We're interested specifically in copy assignment operators.
- const FunctionProtoType *FnType = OpDecl->getType()->getAsFunctionProtoType();
+ const FunctionProtoType *FnType = OpDecl->getType()->getAs<FunctionProtoType>();
assert(FnType && "Overloaded operator has no proto function type.");
assert(FnType->getNumArgs() == 1 && !FnType->isVariadic());
+
+ // Copy assignment operators must be non-templates.
+ if (OpDecl->getPrimaryTemplate() || OpDecl->getDescribedFunctionTemplate())
+ return;
+
QualType ArgType = FnType->getArgType(0);
- if (const LValueReferenceType *Ref = ArgType->getAsLValueReferenceType())
+ if (const LValueReferenceType *Ref = ArgType->getAs<LValueReferenceType>())
ArgType = Ref->getPointeeType();
ArgType = ArgType.getUnqualifiedType();
@@ -185,17 +280,212 @@ void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context,
// Suppress the implicit declaration of a copy constructor.
UserDeclaredCopyAssignment = true;
+ // C++ [class.copy]p11:
+ // A copy assignment operator is trivial if it is implicitly declared.
+ // FIXME: C++0x: don't do this for "= default" copy operators.
+ HasTrivialCopyAssignment = false;
+
// 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,
+void
+CXXRecordDecl::collectConversionFunctions(
+ llvm::SmallPtrSet<CanQualType, 8>& ConversionsTypeSet)
+{
+ OverloadedFunctionDecl *TopConversions = getConversionFunctions();
+ for (OverloadedFunctionDecl::function_iterator
+ TFunc = TopConversions->function_begin(),
+ TFuncEnd = TopConversions->function_end();
+ TFunc != TFuncEnd; ++TFunc) {
+ NamedDecl *TopConv = TFunc->get();
+ CanQualType TConvType;
+ if (FunctionTemplateDecl *TConversionTemplate =
+ dyn_cast<FunctionTemplateDecl>(TopConv))
+ TConvType =
+ getASTContext().getCanonicalType(
+ TConversionTemplate->getTemplatedDecl()->getResultType());
+ else
+ TConvType =
+ getASTContext().getCanonicalType(
+ cast<CXXConversionDecl>(TopConv)->getConversionType());
+ ConversionsTypeSet.insert(TConvType);
+ }
+}
+
+/// getNestedVisibleConversionFunctions - imports unique conversion
+/// functions from base classes into the visible conversion function
+/// list of the class 'RD'. This is a private helper method.
+/// TopConversionsTypeSet is the set of conversion functions of the class
+/// we are interested in. HiddenConversionTypes is set of conversion functions
+/// of the immediate derived class which hides the conversion functions found
+/// in current class.
+void
+CXXRecordDecl::getNestedVisibleConversionFunctions(CXXRecordDecl *RD,
+ const llvm::SmallPtrSet<CanQualType, 8> &TopConversionsTypeSet,
+ const llvm::SmallPtrSet<CanQualType, 8> &HiddenConversionTypes)
+{
+ bool inTopClass = (RD == this);
+ QualType ClassType = getASTContext().getTypeDeclType(this);
+ if (const RecordType *Record = ClassType->getAs<RecordType>()) {
+ OverloadedFunctionDecl *Conversions
+ = cast<CXXRecordDecl>(Record->getDecl())->getConversionFunctions();
+
+ for (OverloadedFunctionDecl::function_iterator
+ Func = Conversions->function_begin(),
+ FuncEnd = Conversions->function_end();
+ Func != FuncEnd; ++Func) {
+ NamedDecl *Conv = Func->get();
+ // Only those conversions not exact match of conversions in current
+ // class are candidateconversion routines.
+ CanQualType ConvType;
+ if (FunctionTemplateDecl *ConversionTemplate =
+ dyn_cast<FunctionTemplateDecl>(Conv))
+ ConvType =
+ getASTContext().getCanonicalType(
+ ConversionTemplate->getTemplatedDecl()->getResultType());
+ else
+ ConvType =
+ getASTContext().getCanonicalType(
+ cast<CXXConversionDecl>(Conv)->getConversionType());
+ // We only add conversion functions found in the base class if they
+ // are not hidden by those found in HiddenConversionTypes which are
+ // the conversion functions in its derived class.
+ if (inTopClass ||
+ (!TopConversionsTypeSet.count(ConvType) &&
+ !HiddenConversionTypes.count(ConvType)) ) {
+ if (FunctionTemplateDecl *ConversionTemplate =
+ dyn_cast<FunctionTemplateDecl>(Conv))
+ RD->addVisibleConversionFunction(ConversionTemplate);
+ else
+ RD->addVisibleConversionFunction(cast<CXXConversionDecl>(Conv));
+ }
+ }
+ }
+
+ if (getNumBases() == 0 && getNumVBases() == 0)
+ return;
+
+ llvm::SmallPtrSet<CanQualType, 8> ConversionFunctions;
+ if (!inTopClass)
+ collectConversionFunctions(ConversionFunctions);
+
+ for (CXXRecordDecl::base_class_iterator VBase = vbases_begin(),
+ E = vbases_end(); VBase != E; ++VBase) {
+ CXXRecordDecl *VBaseClassDecl
+ = cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl());
+ VBaseClassDecl->getNestedVisibleConversionFunctions(RD,
+ TopConversionsTypeSet,
+ (inTopClass ? TopConversionsTypeSet : ConversionFunctions));
+
+ }
+ for (CXXRecordDecl::base_class_iterator Base = bases_begin(),
+ E = bases_end(); Base != E; ++Base) {
+ if (Base->isVirtual())
+ continue;
+ CXXRecordDecl *BaseClassDecl
+ = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+
+ BaseClassDecl->getNestedVisibleConversionFunctions(RD,
+ TopConversionsTypeSet,
+ (inTopClass ? TopConversionsTypeSet : ConversionFunctions));
+
+ }
+}
+
+/// getVisibleConversionFunctions - get all conversion functions visible
+/// in current class; including conversion function templates.
+OverloadedFunctionDecl *
+CXXRecordDecl::getVisibleConversionFunctions() {
+ // If root class, all conversions are visible.
+ if (bases_begin() == bases_end())
+ return &Conversions;
+ // If visible conversion list is already evaluated, return it.
+ if (ComputedVisibleConversions)
+ return &VisibleConversions;
+ llvm::SmallPtrSet<CanQualType, 8> TopConversionsTypeSet;
+ collectConversionFunctions(TopConversionsTypeSet);
+ getNestedVisibleConversionFunctions(this, TopConversionsTypeSet,
+ TopConversionsTypeSet);
+ ComputedVisibleConversions = true;
+ return &VisibleConversions;
+}
+
+void CXXRecordDecl::addVisibleConversionFunction(
CXXConversionDecl *ConvDecl) {
+ assert(!ConvDecl->getDescribedFunctionTemplate() &&
+ "Conversion function templates should cast to FunctionTemplateDecl.");
+ VisibleConversions.addOverload(ConvDecl);
+}
+
+void CXXRecordDecl::addVisibleConversionFunction(
+ FunctionTemplateDecl *ConvDecl) {
+ assert(isa<CXXConversionDecl>(ConvDecl->getTemplatedDecl()) &&
+ "Function template is not a conversion function template");
+ VisibleConversions.addOverload(ConvDecl);
+}
+
+void CXXRecordDecl::addConversionFunction(CXXConversionDecl *ConvDecl) {
+ assert(!ConvDecl->getDescribedFunctionTemplate() &&
+ "Conversion function templates should cast to FunctionTemplateDecl.");
Conversions.addOverload(ConvDecl);
}
+void CXXRecordDecl::addConversionFunction(FunctionTemplateDecl *ConvDecl) {
+ assert(isa<CXXConversionDecl>(ConvDecl->getTemplatedDecl()) &&
+ "Function template is not a conversion function template");
+ Conversions.addOverload(ConvDecl);
+}
+
+CXXRecordDecl *CXXRecordDecl::getInstantiatedFromMemberClass() const {
+ if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo())
+ return cast<CXXRecordDecl>(MSInfo->getInstantiatedFrom());
+
+ return 0;
+}
+
+MemberSpecializationInfo *CXXRecordDecl::getMemberSpecializationInfo() const {
+ return TemplateOrInstantiation.dyn_cast<MemberSpecializationInfo *>();
+}
+
+void
+CXXRecordDecl::setInstantiationOfMemberClass(CXXRecordDecl *RD,
+ TemplateSpecializationKind TSK) {
+ assert(TemplateOrInstantiation.isNull() &&
+ "Previous template or instantiation?");
+ assert(!isa<ClassTemplateSpecializationDecl>(this));
+ TemplateOrInstantiation
+ = new (getASTContext()) MemberSpecializationInfo(RD, TSK);
+}
+
+TemplateSpecializationKind CXXRecordDecl::getTemplateSpecializationKind() {
+ if (ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(this))
+ return Spec->getSpecializationKind();
+
+ if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo())
+ return MSInfo->getTemplateSpecializationKind();
+
+ return TSK_Undeclared;
+}
+
+void
+CXXRecordDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) {
+ if (ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(this)) {
+ Spec->setSpecializationKind(TSK);
+ return;
+ }
+
+ if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) {
+ MSInfo->setTemplateSpecializationKind(TSK);
+ return;
+ }
+
+ assert(false && "Not a class template or member class specialization");
+}
CXXConstructorDecl *
CXXRecordDecl::getDefaultConstructor(ASTContext &Context) {
@@ -203,10 +493,14 @@ CXXRecordDecl::getDefaultConstructor(ASTContext &Context) {
DeclarationName ConstructorName
= Context.DeclarationNames.getCXXConstructorName(
Context.getCanonicalType(ClassType.getUnqualifiedType()));
-
+
DeclContext::lookup_const_iterator Con, ConEnd;
for (llvm::tie(Con, ConEnd) = lookup(ConstructorName);
Con != ConEnd; ++Con) {
+ // FIXME: In C++0x, a constructor template can be a default constructor.
+ if (isa<FunctionTemplateDecl>(*Con))
+ continue;
+
CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con);
if (Constructor->isDefaultConstructor())
return Constructor;
@@ -217,66 +511,105 @@ CXXRecordDecl::getDefaultConstructor(ASTContext &Context) {
const CXXDestructorDecl *
CXXRecordDecl::getDestructor(ASTContext &Context) {
QualType ClassType = Context.getTypeDeclType(this);
-
- DeclarationName Name
- = Context.DeclarationNames.getCXXDestructorName(ClassType);
+
+ DeclarationName Name
+ = Context.DeclarationNames.getCXXDestructorName(
+ Context.getCanonicalType(ClassType));
DeclContext::lookup_iterator I, E;
- llvm::tie(I, E) = lookup(Name);
+ llvm::tie(I, E) = lookup(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);
+ QualType T, DeclaratorInfo *DInfo,
+ bool isStatic, bool isInline) {
+ return new (C) CXXMethodDecl(CXXMethod, RD, L, N, T, DInfo,
+ isStatic, isInline);
}
+bool CXXMethodDecl::isUsualDeallocationFunction() const {
+ if (getOverloadedOperator() != OO_Delete &&
+ getOverloadedOperator() != OO_Array_Delete)
+ return false;
+
+ // C++ [basic.stc.dynamic.deallocation]p2:
+ // If a class T has a member deallocation function named operator delete
+ // with exactly one parameter, then that function is a usual (non-placement)
+ // deallocation function. [...]
+ if (getNumParams() == 1)
+ return true;
+
+ // C++ [basic.stc.dynamic.deallocation]p2:
+ // [...] If class T does not declare such an operator delete but does
+ // declare a member deallocation function named operator delete with
+ // exactly two parameters, the second of which has type std::size_t (18.1),
+ // then this function is a usual deallocation function.
+ ASTContext &Context = getASTContext();
+ if (getNumParams() != 2 ||
+ !Context.hasSameType(getParamDecl(1)->getType(), Context.getSizeType()))
+ return false;
+
+ // This function is a usual deallocation function if there are no
+ // single-parameter deallocation functions of the same kind.
+ for (DeclContext::lookup_const_result R = getDeclContext()->lookup(getDeclName());
+ R.first != R.second; ++R.first) {
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*R.first))
+ if (FD->getNumParams() == 1)
+ return false;
+ }
+
+ return true;
+}
-typedef llvm::DenseMap<const CXXMethodDecl*,
- std::vector<const CXXMethodDecl *> *>
+typedef llvm::DenseMap<const CXXMethodDecl*,
+ std::vector<const CXXMethodDecl *> *>
OverriddenMethodsMapTy;
+// FIXME: We hate static data. This doesn't survive PCH saving/loading, and
+// the vtable building code uses it at CG time.
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())
+ if (it == OverriddenMethods->end() || it->second->empty())
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())
+ if (it == OverriddenMethods->end() || it->second->empty())
return 0;
- return &(*it->second)[it->second->size()];
+ return &(*it->second)[0] + it->second->size();
}
QualType CXXMethodDecl::getThisType(ASTContext &C) const {
@@ -292,40 +625,46 @@ QualType CXXMethodDecl::getThisType(ASTContext &C) const {
if (ClassTemplateDecl *TD = getParent()->getDescribedClassTemplate())
ClassTy = TD->getInjectedClassNameType(C);
else
- ClassTy = C.getTagDeclType(const_cast<CXXRecordDecl*>(getParent()));
- ClassTy = ClassTy.getWithAdditionalQualifiers(getTypeQualifiers());
- return C.getPointerType(ClassTy).withConst();
+ ClassTy = C.getTagDeclType(getParent());
+ ClassTy = C.getQualifiedType(ClassTy,
+ Qualifiers::fromCVRMask(getTypeQualifiers()));
+ return C.getPointerType(ClassTy);
}
CXXBaseOrMemberInitializer::
CXXBaseOrMemberInitializer(QualType BaseType, Expr **Args, unsigned NumArgs,
- SourceLocation L)
- : Args(0), NumArgs(0), IdLoc(L) {
+ CXXConstructorDecl *C,
+ SourceLocation L, SourceLocation R)
+ : Args(0), NumArgs(0), CtorOrAnonUnion(), IdLoc(L), RParenLoc(R) {
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];
+ // FIXME. Allocation via Context
+ this->Args = new Stmt*[NumArgs];
for (unsigned Idx = 0; Idx < NumArgs; ++Idx)
this->Args[Idx] = Args[Idx];
}
+ CtorOrAnonUnion = C;
}
CXXBaseOrMemberInitializer::
CXXBaseOrMemberInitializer(FieldDecl *Member, Expr **Args, unsigned NumArgs,
- SourceLocation L)
- : Args(0), NumArgs(0), IdLoc(L) {
+ CXXConstructorDecl *C,
+ SourceLocation L, SourceLocation R)
+ : Args(0), NumArgs(0), CtorOrAnonUnion(), IdLoc(L), RParenLoc(R) {
BaseOrMember = reinterpret_cast<uintptr_t>(Member);
- assert((BaseOrMember & 0x01) == 0 && "Invalid member pointer");
+ assert((BaseOrMember & 0x01) == 0 && "Invalid member pointer");
if (NumArgs > 0) {
this->NumArgs = NumArgs;
- this->Args = new Expr*[NumArgs];
+ this->Args = new Stmt*[NumArgs];
for (unsigned Idx = 0; Idx < NumArgs; ++Idx)
this->Args[Idx] = Args[Idx];
}
+ CtorOrAnonUnion = C;
}
CXXBaseOrMemberInitializer::~CXXBaseOrMemberInitializer() {
@@ -335,11 +674,12 @@ CXXBaseOrMemberInitializer::~CXXBaseOrMemberInitializer() {
CXXConstructorDecl *
CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation L, DeclarationName N,
- QualType T, bool isExplicit,
+ QualType T, DeclaratorInfo *DInfo,
+ 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,
+ return new (C) CXXConstructorDecl(RD, L, N, T, DInfo, isExplicit, isInline,
isImplicitlyDeclared);
}
@@ -348,11 +688,11 @@ bool CXXConstructorDecl::isDefaultConstructor() const {
// 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);
+ (getNumParams() > 0 && getParamDecl(0)->hasDefaultArg());
}
-bool
-CXXConstructorDecl::isCopyConstructor(ASTContext &Context,
+bool
+CXXConstructorDecl::isCopyConstructor(ASTContext &Context,
unsigned &TypeQuals) const {
// C++ [class.copy]p2:
// A non-template constructor for class X is a copy constructor
@@ -360,42 +700,46 @@ CXXConstructorDecl::isCopyConstructor(ASTContext &Context,
// 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)->hasDefaultArg()))
+ (getNumParams() > 1 && !getParamDecl(1)->hasDefaultArg()) ||
+ (getPrimaryTemplate() != 0) ||
+ (getDescribedFunctionTemplate() != 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();
+ Param->getType()->getAs<LValueReferenceType>();
if (!ParamRefType)
return false;
// Is it a reference to our class type?
- QualType PointeeType
+ CanQualType PointeeType
= Context.getCanonicalType(ParamRefType->getPointeeType());
- QualType ClassTy
- = Context.getTagDeclType(const_cast<CXXRecordDecl*>(getParent()));
+ CanQualType ClassTy
+ = Context.getCanonicalType(Context.getTagDeclType(getParent()));
if (PointeeType.getUnqualifiedType() != ClassTy)
return false;
+ // FIXME: other qualifiers?
+
// We have a copy constructor.
TypeQuals = PointeeType.getCVRQualifiers();
return true;
}
-bool CXXConstructorDecl::isConvertingConstructor() const {
+bool CXXConstructorDecl::isConvertingConstructor(bool AllowExplicit) 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())
+ if (isExplicit() && !AllowExplicit)
return false;
- return (getNumParams() == 0 &&
- getType()->getAsFunctionProtoType()->isVariadic()) ||
+ return (getNumParams() == 0 &&
+ getType()->getAs<FunctionProtoType>()->isVariadic()) ||
(getNumParams() == 1) ||
(getNumParams() > 1 && getParamDecl(1)->hasDefaultArg());
}
@@ -403,42 +747,34 @@ bool CXXConstructorDecl::isConvertingConstructor() const {
CXXDestructorDecl *
CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation L, DeclarationName N,
- QualType T, bool isInline,
+ 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,
+ return new (C) CXXDestructorDecl(RD, L, N, T, isInline,
isImplicitlyDeclared);
}
void
-CXXConstructorDecl::setBaseOrMemberInitializers(
- ASTContext &C,
- CXXBaseOrMemberInitializer **Initializers,
- unsigned NumInitializers) {
- if (NumInitializers > 0) {
- NumBaseOrMemberInitializers = NumInitializers;
- BaseOrMemberInitializers =
- new (C, 8) CXXBaseOrMemberInitializer*[NumInitializers];
- for (unsigned Idx = 0; Idx < NumInitializers; ++Idx)
- BaseOrMemberInitializers[Idx] = Initializers[Idx];
- }
+CXXDestructorDecl::Destroy(ASTContext& C) {
+ C.Deallocate(BaseOrMemberDestructions);
+ CXXMethodDecl::Destroy(C);
}
void
CXXConstructorDecl::Destroy(ASTContext& C) {
C.Deallocate(BaseOrMemberInitializers);
- this->~CXXMethodDecl();
- C.Deallocate((void *)this);
+ CXXMethodDecl::Destroy(C);
}
CXXConversionDecl *
CXXConversionDecl::Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation L, DeclarationName N,
- QualType T, bool isInline, bool isExplicit) {
+ QualType T, DeclaratorInfo *DInfo,
+ 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);
+ return new (C) CXXConversionDecl(RD, L, N, T, DInfo, isInline, isExplicit);
}
OverloadedFunctionDecl *
@@ -447,13 +783,78 @@ OverloadedFunctionDecl::Create(ASTContext &C, DeclContext *DC,
return new (C) OverloadedFunctionDecl(DC, N);
}
+OverloadIterator::OverloadIterator(NamedDecl *ND) : D(0) {
+ if (!ND)
+ return;
+
+ if (isa<FunctionDecl>(ND) || isa<FunctionTemplateDecl>(ND))
+ D = ND;
+ else if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(ND)) {
+ if (Ovl->size() != 0) {
+ D = ND;
+ Iter = Ovl->function_begin();
+ }
+ }
+}
+
void OverloadedFunctionDecl::addOverload(AnyFunctionDecl F) {
Functions.push_back(F);
this->setLocation(F.get()->getLocation());
}
+OverloadIterator::reference OverloadIterator::operator*() const {
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ return FD;
+
+ if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(D))
+ return FTD;
+
+ assert(isa<OverloadedFunctionDecl>(D));
+ return *Iter;
+}
+
+OverloadIterator &OverloadIterator::operator++() {
+ if (isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D)) {
+ D = 0;
+ return *this;
+ }
+
+ if (++Iter == cast<OverloadedFunctionDecl>(D)->function_end())
+ D = 0;
+
+ return *this;
+}
+
+bool OverloadIterator::Equals(const OverloadIterator &Other) const {
+ if (!D || !Other.D)
+ return D == Other.D;
+
+ if (D != Other.D)
+ return false;
+
+ return !isa<OverloadedFunctionDecl>(D) || Iter == Other.Iter;
+}
+
+FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L,
+ FriendUnion Friend,
+ SourceLocation FriendL) {
+#ifndef NDEBUG
+ if (Friend.is<NamedDecl*>()) {
+ NamedDecl *D = Friend.get<NamedDecl*>();
+ assert(isa<FunctionDecl>(D) ||
+ isa<CXXRecordDecl>(D) ||
+ isa<FunctionTemplateDecl>(D) ||
+ isa<ClassTemplateDecl>(D));
+ assert(D->getFriendObjectKind());
+ }
+#endif
+
+ return new (C) FriendDecl(DC, L, Friend, FriendL);
+}
+
LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C,
- DeclContext *DC,
+ DeclContext *DC,
SourceLocation L,
LanguageIDs Lang, bool Braces) {
return new (C) LinkageSpecDecl(DC, L, Lang, Braces);
@@ -467,19 +868,19 @@ UsingDirectiveDecl *UsingDirectiveDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation IdentLoc,
NamespaceDecl *Used,
DeclContext *CommonAncestor) {
- return new (C) UsingDirectiveDecl(DC, L, NamespaceLoc, QualifierRange,
+ 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,
+NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L,
+ SourceLocation AliasLoc,
+ IdentifierInfo *Alias,
SourceRange QualifierRange,
NestedNameSpecifier *Qualifier,
- SourceLocation IdentLoc,
+ SourceLocation IdentLoc,
NamedDecl *Namespace) {
- return new (C) NamespaceAliasDecl(DC, L, AliasLoc, Alias, QualifierRange,
+ return new (C) NamespaceAliasDecl(DC, L, AliasLoc, Alias, QualifierRange,
Qualifier, IdentLoc, Namespace);
}
@@ -491,6 +892,17 @@ UsingDecl *UsingDecl::Create(ASTContext &C, DeclContext *DC,
TargetNNS, IsTypeNameArg);
}
+UnresolvedUsingDecl *UnresolvedUsingDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation UsingLoc,
+ SourceRange TargetNNR,
+ NestedNameSpecifier *TargetNNS,
+ SourceLocation TargetNameLoc,
+ DeclarationName TargetName,
+ bool IsTypeNameArg) {
+ return new (C) UnresolvedUsingDecl(DC, UsingLoc, TargetNNR, TargetNNS,
+ TargetNameLoc, TargetName, IsTypeNameArg);
+}
+
StaticAssertDecl *StaticAssertDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation L, Expr *AssertExpr,
StringLiteral *Message) {
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index 54f13e1..7f38ac1 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -30,8 +30,8 @@ void ObjCListBase::Destroy(ASTContext &Ctx) {
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);
@@ -54,29 +54,9 @@ ObjCContainerDecl::getIvarDecl(IdentifierInfo *Id) const {
return 0;
}
-// Get the local instance method declared in this interface.
-ObjCMethodDecl *
-ObjCContainerDecl::getInstanceMethod(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(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.
+// Get the local instance/class method declared in this interface.
ObjCMethodDecl *
-ObjCContainerDecl::getClassMethod(Selector Sel) const {
+ObjCContainerDecl::getMethod(Selector Sel, bool isInstance) const {
// Since instance & class methods can have the same name, the loop below
// ensures we get the correct method.
//
@@ -88,7 +68,7 @@ ObjCContainerDecl::getClassMethod(Selector Sel) const {
lookup_const_iterator Meth, MethEnd;
for (llvm::tie(Meth, MethEnd) = lookup(Sel); Meth != MethEnd; ++Meth) {
ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth);
- if (MD && MD->isClassMethod())
+ if (MD && MD->isInstanceMethod() == isInstance)
return MD;
}
return 0;
@@ -103,15 +83,15 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const {
for (prop_iterator I = prop_begin(), E = prop_end(); 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(),
+ for (ObjCProtocolDecl::protocol_iterator I = PID->protocol_begin(),
E = PID->protocol_end(); I != E; ++I)
if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId))
return P;
}
-
+
if (const ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(this)) {
// Look through categories.
for (ObjCCategoryDecl *Category = OID->getCategoryList();
@@ -138,6 +118,45 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const {
return 0;
}
+void ObjCInterfaceDecl::mergeClassExtensionProtocolList(
+ ObjCProtocolDecl *const* ExtList, unsigned ExtNum,
+ ASTContext &C)
+{
+ if (ReferencedProtocols.empty()) {
+ ReferencedProtocols.set(ExtList, ExtNum, C);
+ return;
+ }
+ // Check for duplicate protocol in class's protocol list.
+ // This is (O)2. But it is extremely rare and number of protocols in
+ // class or its extension are very few.
+ llvm::SmallVector<ObjCProtocolDecl*, 8> ProtocolRefs;
+ for (unsigned i = 0; i < ExtNum; i++) {
+ bool protocolExists = false;
+ ObjCProtocolDecl *ProtoInExtension = ExtList[i];
+ for (protocol_iterator p = protocol_begin(), e = protocol_end();
+ p != e; p++) {
+ ObjCProtocolDecl *Proto = (*p);
+ if (C.ProtocolCompatibleWithProtocol(ProtoInExtension, Proto)) {
+ protocolExists = true;
+ break;
+ }
+ }
+ // Do we want to warn on a protocol in extension class which
+ // already exist in the class? Probably not.
+ if (!protocolExists)
+ ProtocolRefs.push_back(ProtoInExtension);
+ }
+ if (ProtocolRefs.empty())
+ return;
+ // Merge ProtocolRefs into class's protocol list;
+ for (protocol_iterator p = protocol_begin(), e = protocol_end();
+ p != e; p++)
+ ProtocolRefs.push_back(*p);
+ ReferencedProtocols.Destroy(C);
+ unsigned NumProtoRefs = ProtocolRefs.size();
+ setProtocolList((ObjCProtocolDecl**)&ProtocolRefs[0], NumProtoRefs, C);
+}
+
ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable(IdentifierInfo *ID,
ObjCInterfaceDecl *&clsDeclared) {
ObjCInterfaceDecl* ClassDecl = this;
@@ -165,72 +184,37 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::lookupInheritedClass(
return NULL;
}
-/// lookupInstanceMethod - This method returns an instance method by looking in
+/// lookupMethod - This method returns an instance/class method by looking in
/// the class, its categories, and its super classes (using a linear search).
-ObjCMethodDecl *ObjCInterfaceDecl::lookupInstanceMethod(Selector Sel) {
- ObjCInterfaceDecl* ClassDecl = this;
+ObjCMethodDecl *ObjCInterfaceDecl::lookupMethod(Selector Sel,
+ bool isInstance) const {
+ const ObjCInterfaceDecl* ClassDecl = this;
ObjCMethodDecl *MethodDecl = 0;
-
+
while (ClassDecl != NULL) {
- if ((MethodDecl = ClassDecl->getInstanceMethod(Sel)))
+ if ((MethodDecl = ClassDecl->getMethod(Sel, isInstance)))
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(Sel)))
- return MethodDecl;
-
- // Didn't find one yet - now look through categories.
- ObjCCategoryDecl *CatDecl = ClassDecl->getCategoryList();
- while (CatDecl) {
- if ((MethodDecl = CatDecl->getInstanceMethod(Sel)))
+ if ((MethodDecl = (*I)->lookupMethod(Sel, isInstance)))
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(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(Selector Sel) {
- ObjCInterfaceDecl* ClassDecl = this;
- ObjCMethodDecl *MethodDecl = 0;
-
- while (ClassDecl != NULL) {
- if ((MethodDecl = ClassDecl->getClassMethod(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(Sel)))
- return MethodDecl;
-
// Didn't find one yet - now look through categories.
ObjCCategoryDecl *CatDecl = ClassDecl->getCategoryList();
while (CatDecl) {
- if ((MethodDecl = CatDecl->getClassMethod(Sel)))
+ if ((MethodDecl = CatDecl->getMethod(Sel, isInstance)))
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(Sel)))
+ if ((MethodDecl = (*I)->lookupMethod(Sel, isInstance)))
return MethodDecl;
CatDecl = CatDecl->getNextClassCategory();
}
@@ -239,14 +223,23 @@ ObjCMethodDecl *ObjCInterfaceDecl::lookupClassMethod(Selector Sel) {
return NULL;
}
-
+ObjCMethodDecl *ObjCInterfaceDecl::lookupPrivateInstanceMethod(
+ const Selector &Sel) {
+ ObjCMethodDecl *Method = 0;
+ if (ObjCImplementationDecl *ImpDecl = getImplementation())
+ Method = ImpDecl->getInstanceMethod(Sel);
+
+ if (!Method && getSuperClass())
+ return getSuperClass()->lookupPrivateInstanceMethod(Sel);
+ return Method;
+}
//===----------------------------------------------------------------------===//
// ObjCMethodDecl
//===----------------------------------------------------------------------===//
ObjCMethodDecl *ObjCMethodDecl::Create(ASTContext &C,
- SourceLocation beginLoc,
+ SourceLocation beginLoc,
SourceLocation endLoc,
Selector SelInfo, QualType T,
DeclContext *contextDecl,
@@ -256,14 +249,14 @@ ObjCMethodDecl *ObjCMethodDecl::Create(ASTContext &C,
ImplementationControl impControl) {
return new (C) ObjCMethodDecl(beginLoc, endLoc,
SelInfo, T, contextDecl,
- isInstance,
+ 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);
@@ -272,7 +265,57 @@ void ObjCMethodDecl::Destroy(ASTContext &C) {
Decl::Destroy(C);
}
-void ObjCMethodDecl::createImplicitParams(ASTContext &Context,
+/// \brief A definition will return its interface declaration.
+/// An interface declaration will return its definition.
+/// Otherwise it will return itself.
+ObjCMethodDecl *ObjCMethodDecl::getNextRedeclaration() {
+ ASTContext &Ctx = getASTContext();
+ ObjCMethodDecl *Redecl = 0;
+ Decl *CtxD = cast<Decl>(getDeclContext());
+
+ if (ObjCInterfaceDecl *IFD = dyn_cast<ObjCInterfaceDecl>(CtxD)) {
+ if (ObjCImplementationDecl *ImplD = Ctx.getObjCImplementation(IFD))
+ Redecl = ImplD->getMethod(getSelector(), isInstanceMethod());
+
+ } else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(CtxD)) {
+ if (ObjCCategoryImplDecl *ImplD = Ctx.getObjCImplementation(CD))
+ Redecl = ImplD->getMethod(getSelector(), isInstanceMethod());
+
+ } else if (ObjCImplementationDecl *ImplD =
+ dyn_cast<ObjCImplementationDecl>(CtxD)) {
+ if (ObjCInterfaceDecl *IFD = ImplD->getClassInterface())
+ Redecl = IFD->getMethod(getSelector(), isInstanceMethod());
+
+ } else if (ObjCCategoryImplDecl *CImplD =
+ dyn_cast<ObjCCategoryImplDecl>(CtxD)) {
+ if (ObjCCategoryDecl *CatD = CImplD->getCategoryClass())
+ Redecl = CatD->getMethod(getSelector(), isInstanceMethod());
+ }
+
+ return Redecl ? Redecl : this;
+}
+
+ObjCMethodDecl *ObjCMethodDecl::getCanonicalDecl() {
+ Decl *CtxD = cast<Decl>(getDeclContext());
+
+ if (ObjCImplementationDecl *ImplD = dyn_cast<ObjCImplementationDecl>(CtxD)) {
+ if (ObjCInterfaceDecl *IFD = ImplD->getClassInterface())
+ if (ObjCMethodDecl *MD = IFD->getMethod(getSelector(),
+ isInstanceMethod()))
+ return MD;
+
+ } else if (ObjCCategoryImplDecl *CImplD =
+ dyn_cast<ObjCCategoryImplDecl>(CtxD)) {
+ if (ObjCCategoryDecl *CatD = CImplD->getCategoryClass())
+ if (ObjCMethodDecl *MD = CatD->getMethod(getSelector(),
+ isInstanceMethod()))
+ return MD;
+ }
+
+ return this;
+}
+
+void ObjCMethodDecl::createImplicitParams(ASTContext &Context,
const ObjCInterfaceDecl *OID) {
QualType selfTy;
if (isInstanceMethod()) {
@@ -280,49 +323,30 @@ void ObjCMethodDecl::createImplicitParams(ASTContext &Context,
// of the interface (which has been reported). Recover gracefully.
if (OID) {
selfTy = Context.getObjCInterfaceType(OID);
- selfTy = Context.getPointerType(selfTy);
+ selfTy = Context.getObjCObjectPointerType(selfTy);
} else {
selfTy = Context.getObjCIdType();
}
} else // we have a factory method.
selfTy = Context.getObjCClassType();
- setSelfDecl(ImplicitParamDecl::Create(Context, this, SourceLocation(),
+ setSelfDecl(ImplicitParamDecl::Create(Context, this, SourceLocation(),
&Context.Idents.get("self"), selfTy));
- setCmdDecl(ImplicitParamDecl::Create(Context, this, SourceLocation(),
- &Context.Idents.get("_cmd"),
+ 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()))
+ if (ObjCImplDecl *IMD = dyn_cast<ObjCImplDecl>(getDeclContext()))
return IMD->getClassInterface();
- if (ObjCCategoryImplDecl *CID =
- dyn_cast<ObjCCategoryImplDecl>(getDeclContext()))
- return CID->getClassInterface();
+
+ assert(!isa<ObjCProtocolDecl>(getDeclContext()) && "It's a protocol method");
assert(false && "unknown method context");
return 0;
}
@@ -334,7 +358,7 @@ ObjCInterfaceDecl *ObjCMethodDecl::getClassInterface() {
ObjCInterfaceDecl *ObjCInterfaceDecl::Create(ASTContext &C,
DeclContext *DC,
SourceLocation atLoc,
- IdentifierInfo *Id,
+ IdentifierInfo *Id,
SourceLocation ClassLoc,
bool ForwardDecl, bool isInternal){
return new (C) ObjCInterfaceDecl(DC, atLoc, Id, ClassLoc, ForwardDecl,
@@ -350,19 +374,28 @@ ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id,
ClassLoc(CLoc) {
}
-void ObjCInterfaceDecl::Destroy(ASTContext &C) {
+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);
}
+ObjCImplementationDecl *ObjCInterfaceDecl::getImplementation() const {
+ return getASTContext().getObjCImplementation(
+ const_cast<ObjCInterfaceDecl*>(this));
+}
+
+void ObjCInterfaceDecl::setImplementation(ObjCImplementationDecl *ImplD) {
+ getASTContext().setObjCImplementation(this, ImplD);
+}
+
/// FindCategoryDeclaration - Finds category declaration in the list of
/// categories for this class and returns it. Name of the category is passed
@@ -377,14 +410,79 @@ ObjCInterfaceDecl::FindCategoryDeclaration(IdentifierInfo *CategoryId) const {
return 0;
}
+ObjCMethodDecl *
+ObjCInterfaceDecl::getCategoryInstanceMethod(Selector Sel) const {
+ for (ObjCCategoryDecl *Category = getCategoryList();
+ Category; Category = Category->getNextClassCategory())
+ if (ObjCCategoryImplDecl *Impl = Category->getImplementation())
+ if (ObjCMethodDecl *MD = Impl->getInstanceMethod(Sel))
+ return MD;
+ return 0;
+}
+
+ObjCMethodDecl *ObjCInterfaceDecl::getCategoryClassMethod(Selector Sel) const {
+ for (ObjCCategoryDecl *Category = getCategoryList();
+ Category; Category = Category->getNextClassCategory())
+ if (ObjCCategoryImplDecl *Impl = Category->getImplementation())
+ if (ObjCMethodDecl *MD = Impl->getClassMethod(Sel))
+ return MD;
+ return 0;
+}
+
+/// ClassImplementsProtocol - Checks that 'lProto' protocol
+/// has been implemented in IDecl class, its super class or categories (if
+/// lookupCategory is true).
+bool ObjCInterfaceDecl::ClassImplementsProtocol(ObjCProtocolDecl *lProto,
+ bool lookupCategory,
+ bool RHSIsQualifiedID) {
+ ObjCInterfaceDecl *IDecl = this;
+ // 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 (getASTContext().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 &&
+ getASTContext().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 (getASTContext().ProtocolCompatibleWithProtocol(lProto, *PI))
+ return true;
+ }
+
+ // 3rd, look up the super class(s)
+ if (IDecl->getSuperClass())
+ return
+ IDecl->getSuperClass()->ClassImplementsProtocol(lProto, lookupCategory,
+ RHSIsQualifiedID);
+
+ return false;
+}
+
//===----------------------------------------------------------------------===//
// 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);
+ QualType T, DeclaratorInfo *DInfo,
+ AccessControl ac, Expr *BW) {
+ return new (C) ObjCIvarDecl(DC, L, Id, T, DInfo, ac, BW);
}
@@ -401,7 +499,7 @@ ObjCAtDefsFieldDecl
void ObjCAtDefsFieldDecl::Destroy(ASTContext& C) {
this->~ObjCAtDefsFieldDecl();
- C.Deallocate((void *)this);
+ C.Deallocate((void *)this);
}
//===----------------------------------------------------------------------===//
@@ -409,7 +507,7 @@ void ObjCAtDefsFieldDecl::Destroy(ASTContext& C) {
//===----------------------------------------------------------------------===//
ObjCProtocolDecl *ObjCProtocolDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation L,
+ SourceLocation L,
IdentifierInfo *Id) {
return new (C) ObjCProtocolDecl(DC, L, Id);
}
@@ -428,34 +526,21 @@ ObjCProtocolDecl *ObjCProtocolDecl::lookupProtocolNamed(IdentifierInfo *Name) {
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(Selector Sel) {
- ObjCMethodDecl *MethodDecl = NULL;
-
- if ((MethodDecl = getInstanceMethod(Sel)))
- return MethodDecl;
-
- for (protocol_iterator I = protocol_begin(), E = protocol_end(); I != E; ++I)
- if ((MethodDecl = (*I)->lookupInstanceMethod(Sel)))
- return MethodDecl;
return NULL;
}
-// lookupInstanceMethod - Lookup a class method in the protocol and protocols
+// lookupMethod - Lookup a instance/class method in the protocol and protocols
// it inherited.
-ObjCMethodDecl *ObjCProtocolDecl::lookupClassMethod(Selector Sel) {
+ObjCMethodDecl *ObjCProtocolDecl::lookupMethod(Selector Sel,
+ bool isInstance) const {
ObjCMethodDecl *MethodDecl = NULL;
-
- if ((MethodDecl = getClassMethod(Sel)))
+
+ if ((MethodDecl = getMethod(Sel, isInstance)))
return MethodDecl;
-
+
for (protocol_iterator I = protocol_begin(), E = protocol_end(); I != E; ++I)
- if ((MethodDecl = (*I)->lookupClassMethod(Sel)))
+ if ((MethodDecl = (*I)->lookupMethod(Sel, isInstance)))
return MethodDecl;
return NULL;
}
@@ -464,7 +549,7 @@ ObjCMethodDecl *ObjCProtocolDecl::lookupClassMethod(Selector Sel) {
// ObjCClassDecl
//===----------------------------------------------------------------------===//
-ObjCClassDecl::ObjCClassDecl(DeclContext *DC, SourceLocation L,
+ObjCClassDecl::ObjCClassDecl(DeclContext *DC, SourceLocation L,
ObjCInterfaceDecl *const *Elts, unsigned nElts,
ASTContext &C)
: Decl(ObjCClass, DC, L) {
@@ -480,7 +565,7 @@ ObjCClassDecl *ObjCClassDecl::Create(ASTContext &C, DeclContext *DC,
}
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)
@@ -488,7 +573,7 @@ void ObjCClassDecl::Destroy(ASTContext &C) {
// 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);
}
@@ -501,14 +586,14 @@ ObjCForwardProtocolDecl::
ObjCForwardProtocolDecl(DeclContext *DC, SourceLocation L,
ObjCProtocolDecl *const *Elts, unsigned nElts,
ASTContext &C)
-: Decl(ObjCForwardProtocol, DC, L) {
+: Decl(ObjCForwardProtocol, DC, L) {
ReferencedProtocols.set(Elts, nElts, C);
}
ObjCForwardProtocolDecl *
ObjCForwardProtocolDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation L,
+ SourceLocation L,
ObjCProtocolDecl *const *Elts,
unsigned NumElts) {
return new (C) ObjCForwardProtocolDecl(DC, L, Elts, NumElts, C);
@@ -529,6 +614,16 @@ ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, DeclContext *DC,
return new (C) ObjCCategoryDecl(DC, L, Id);
}
+ObjCCategoryImplDecl *ObjCCategoryDecl::getImplementation() const {
+ return getASTContext().getObjCImplementation(
+ const_cast<ObjCCategoryDecl*>(this));
+}
+
+void ObjCCategoryDecl::setImplementation(ObjCCategoryImplDecl *ImplD) {
+ getASTContext().setObjCImplementation(this, ImplD);
+}
+
+
//===----------------------------------------------------------------------===//
// ObjCCategoryImplDecl
//===----------------------------------------------------------------------===//
@@ -540,6 +635,10 @@ ObjCCategoryImplDecl::Create(ASTContext &C, DeclContext *DC,
return new (C) ObjCCategoryImplDecl(DC, L, Id, ClassInterface);
}
+ObjCCategoryDecl *ObjCCategoryImplDecl::getCategoryClass() const {
+ return getClassInterface()->FindCategoryDeclaration(getIdentifier());
+}
+
void ObjCImplDecl::addPropertyImplementation(ObjCPropertyImplDecl *property) {
// FIXME: The context should be correct before we get here.
@@ -547,6 +646,23 @@ void ObjCImplDecl::addPropertyImplementation(ObjCPropertyImplDecl *property) {
addDecl(property);
}
+void ObjCImplDecl::setClassInterface(ObjCInterfaceDecl *IFace) {
+ ASTContext &Ctx = getASTContext();
+
+ if (ObjCImplementationDecl *ImplD
+ = dyn_cast_or_null<ObjCImplementationDecl>(this)) {
+ if (IFace)
+ Ctx.setObjCImplementation(IFace, ImplD);
+
+ } else if (ObjCCategoryImplDecl *ImplD =
+ dyn_cast_or_null<ObjCCategoryImplDecl>(this)) {
+ if (ObjCCategoryDecl *CD = IFace->FindCategoryDeclaration(getIdentifier()))
+ Ctx.setObjCImplementation(CD, ImplD);
+ }
+
+ ClassInterface = IFace;
+}
+
/// 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.
@@ -576,56 +692,12 @@ FindPropertyImplDecl(IdentifierInfo *Id) const {
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(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(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(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(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,
+ObjCImplementationDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
ObjCInterfaceDecl *ClassInterface,
ObjCInterfaceDecl *SuperDecl) {
@@ -639,7 +711,7 @@ ObjCImplementationDecl::Create(ASTContext &C, DeclContext *DC,
ObjCCompatibleAliasDecl *
ObjCCompatibleAliasDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
- IdentifierInfo *Id,
+ IdentifierInfo *Id,
ObjCInterfaceDecl* AliasedClass) {
return new (C) ObjCCompatibleAliasDecl(DC, L, Id, AliasedClass);
}
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index 12e89cd..9d0d836 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -19,7 +19,6 @@
#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;
@@ -34,8 +33,10 @@ namespace {
llvm::raw_ostream& Indent();
void ProcessDeclGroup(llvm::SmallVectorImpl<Decl*>& Decls);
+ void Print(AccessSpecifier AS);
+
public:
- DeclPrinter(llvm::raw_ostream &Out, ASTContext &Context,
+ DeclPrinter(llvm::raw_ostream &Out, ASTContext &Context,
const PrintingPolicy &Policy,
unsigned Indentation = 0)
: Out(Out), Context(Context), Policy(Policy), Indentation(Indentation) { }
@@ -71,17 +72,19 @@ namespace {
void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D);
void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
+ void VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D);
+ void VisitUsingDecl(UsingDecl *D);
};
}
-void Decl::print(llvm::raw_ostream &Out, unsigned Indentation) {
+void Decl::print(llvm::raw_ostream &Out, unsigned Indentation) const {
print(Out, getASTContext().PrintingPolicy, Indentation);
}
void Decl::print(llvm::raw_ostream &Out, const PrintingPolicy &Policy,
- unsigned Indentation) {
+ unsigned Indentation) const {
DeclPrinter Printer(Out, getASTContext(), Policy, Indentation);
- Printer.Visit(this);
+ Printer.Visit(const_cast<Decl*>(this));
}
static QualType GetBaseType(QualType T) {
@@ -90,13 +93,13 @@ static QualType GetBaseType(QualType T) {
while (!BaseType->isSpecifierType()) {
if (isa<TypedefType>(BaseType))
break;
- else if (const PointerType* PTy = BaseType->getAsPointerType())
+ else if (const PointerType* PTy = BaseType->getAs<PointerType>())
BaseType = PTy->getPointeeType();
else if (const ArrayType* ATy = dyn_cast<ArrayType>(BaseType))
BaseType = ATy->getElementType();
- else if (const FunctionType* FTy = BaseType->getAsFunctionType())
+ else if (const FunctionType* FTy = BaseType->getAs<FunctionType>())
BaseType = FTy->getResultType();
- else if (const VectorType *VTy = BaseType->getAsVectorType())
+ else if (const VectorType *VTy = BaseType->getAs<VectorType>())
BaseType = VTy->getElementType();
else
assert(0 && "Unknown declarator!");
@@ -146,7 +149,7 @@ void Decl::printGroup(Decl** Begin, unsigned NumDecls,
}
}
-void Decl::dump() {
+void Decl::dump() const {
print(llvm::errs());
}
@@ -164,6 +167,15 @@ void DeclPrinter::ProcessDeclGroup(llvm::SmallVectorImpl<Decl*>& Decls) {
}
+void DeclPrinter::Print(AccessSpecifier AS) {
+ switch(AS) {
+ case AS_none: assert(0 && "No access specifier!"); break;
+ case AS_public: Out << "public"; break;
+ case AS_protected: Out << "protected"; break;
+ case AS_private: Out << " private"; break;
+ }
+}
+
//----------------------------------------------------------------------------
// Common C declarations
//----------------------------------------------------------------------------
@@ -172,6 +184,9 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) {
if (Indent)
Indentation += Policy.Indentation;
+ bool PrintAccess = isa<CXXRecordDecl>(DC);
+ AccessSpecifier CurAS = AS_none;
+
llvm::SmallVector<Decl*, 2> Decls;
for (DeclContext::decl_iterator D = DC->decls_begin(), DEnd = DC->decls_end();
D != DEnd; ++D) {
@@ -185,6 +200,16 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) {
continue;
}
+ if (PrintAccess) {
+ AccessSpecifier AS = D->getAccess();
+
+ if (AS != CurAS) {
+ Print(AS);
+ Out << ":\n";
+ CurAS = AS;
+ }
+ }
+
// 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
@@ -215,16 +240,16 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) {
}
this->Indent();
Visit(*D);
-
- // FIXME: Need to be able to tell the DeclPrinter when
+
+ // FIXME: Need to be able to tell the DeclPrinter when
const char *Terminator = 0;
- if (isa<FunctionDecl>(*D) &&
+ 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<ObjCImplementationDecl>(*D) ||
isa<ObjCInterfaceDecl>(*D) ||
isa<ObjCProtocolDecl>(*D) ||
isa<ObjCCategoryImplDecl>(*D) ||
@@ -274,7 +299,7 @@ void DeclPrinter::VisitRecordDecl(RecordDecl *D) {
Out << " ";
Out << D->getNameAsString();
}
-
+
if (D->isDefinition()) {
Out << " {\n";
VisitDeclContext(D);
@@ -290,7 +315,7 @@ void DeclPrinter::VisitEnumConstantDecl(EnumConstantDecl *D) {
}
}
-void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
+void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
if (!Policy.SuppressSpecifiers) {
switch (D->getStorageClass()) {
case FunctionDecl::None: break;
@@ -307,7 +332,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
SubPolicy.SuppressSpecifiers = false;
std::string Proto = D->getNameAsString();
if (isa<FunctionType>(D->getType().getTypePtr())) {
- const FunctionType *AFT = D->getType()->getAsFunctionType();
+ const FunctionType *AFT = D->getType()->getAs<FunctionType>();
const FunctionProtoType *FT = 0;
if (D->hasWrittenPrototype())
@@ -321,7 +346,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
if (i) POut << ", ";
ParamPrinter.VisitParmVarDecl(D->getParamDecl(i));
}
-
+
if (FT->isVariadic()) {
if (D->getNumParams()) POut << ", ";
POut << "...";
@@ -335,7 +360,81 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
}
Proto += ")";
- AFT->getResultType().getAsStringInternal(Proto, Policy);
+ if (D->hasAttr<NoReturnAttr>())
+ Proto += " __attribute((noreturn))";
+ if (CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D)) {
+ if (CDecl->getNumBaseOrMemberInitializers() > 0) {
+ Proto += " : ";
+ Out << Proto;
+ Proto.clear();
+ for (CXXConstructorDecl::init_const_iterator B = CDecl->init_begin(),
+ E = CDecl->init_end();
+ B != E; ++B) {
+ CXXBaseOrMemberInitializer * BMInitializer = (*B);
+ if (B != CDecl->init_begin())
+ Out << ", ";
+ bool hasArguments = (BMInitializer->arg_begin() !=
+ BMInitializer->arg_end());
+ if (BMInitializer->isMemberInitializer()) {
+ FieldDecl *FD = BMInitializer->getMember();
+ Out << FD->getNameAsString();
+ }
+ else // FIXME. skip dependent types for now.
+ if (const RecordType *RT =
+ BMInitializer->getBaseClass()->getAs<RecordType>()) {
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(RT->getDecl());
+ Out << BaseDecl->getNameAsString();
+ }
+ if (hasArguments) {
+ Out << "(";
+ for (CXXBaseOrMemberInitializer::const_arg_iterator BE =
+ BMInitializer->const_arg_begin(),
+ EE = BMInitializer->const_arg_end(); BE != EE; ++BE) {
+ if (BE != BMInitializer->const_arg_begin())
+ Out<< ", ";
+ const Expr *Exp = (*BE);
+ Exp->printPretty(Out, Context, 0, Policy, Indentation);
+ }
+ Out << ")";
+ } else
+ Out << "()";
+ }
+ }
+ }
+ else if (CXXDestructorDecl *DDecl = dyn_cast<CXXDestructorDecl>(D)) {
+ if (DDecl->getNumBaseOrMemberDestructions() > 0) {
+ // List order of base/member destruction for visualization purposes.
+ assert (D->isThisDeclarationADefinition() && "Destructor with dtor-list");
+ Proto += "/* : ";
+ for (CXXDestructorDecl::destr_const_iterator *B = DDecl->destr_begin(),
+ *E = DDecl->destr_end();
+ B != E; ++B) {
+ uintptr_t BaseOrMember = (*B);
+ if (B != DDecl->destr_begin())
+ Proto += ", ";
+
+ if (DDecl->isMemberToDestroy(BaseOrMember)) {
+ FieldDecl *FD = DDecl->getMemberToDestroy(BaseOrMember);
+ Proto += "~";
+ Proto += FD->getNameAsString();
+ }
+ else // FIXME. skip dependent types for now.
+ if (const RecordType *RT =
+ DDecl->getAnyBaseClassToDestroy(BaseOrMember)
+ ->getAs<RecordType>()) {
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(RT->getDecl());
+ Proto += "~";
+ Proto += BaseDecl->getNameAsString();
+ }
+ Proto += "()";
+ }
+ Proto += " */";
+ }
+ }
+ else
+ AFT->getResultType().getAsStringInternal(Proto, Policy);
} else {
D->getType().getAsStringInternal(Proto, Policy);
}
@@ -423,7 +522,7 @@ void DeclPrinter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) {
// C++ declarations
//----------------------------------------------------------------------------
void DeclPrinter::VisitOverloadedFunctionDecl(OverloadedFunctionDecl *D) {
- assert(false &&
+ assert(false &&
"OverloadedFunctionDecls aren't really decls and are never printed");
}
@@ -453,28 +552,23 @@ void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) {
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) {
+ 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);
+ AccessSpecifier AS = Base->getAccessSpecifierAsWritten();
+ if (AS != AS_none)
+ Print(AS);
+ Out << " " << Base->getType().getAsString(Policy);
}
}
@@ -483,7 +577,7 @@ void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) {
Out << " {\n";
VisitDeclContext(D);
Indent() << "}";
- }
+ }
}
void DeclPrinter::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
@@ -507,17 +601,17 @@ void DeclPrinter::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
void DeclPrinter::VisitTemplateDecl(TemplateDecl *D) {
Out << "template <";
-
+
TemplateParameterList *Params = D->getTemplateParameters();
for (unsigned i = 0, e = Params->size(); i != e; ++i) {
if (i != 0)
Out << ", ";
-
+
const Decl *Param = Params->getParam(i);
- if (const TemplateTypeParmDecl *TTP =
+ if (const TemplateTypeParmDecl *TTP =
dyn_cast<TemplateTypeParmDecl>(Param)) {
-
- QualType ParamType =
+
+ QualType ParamType =
Context.getTypeDeclType(const_cast<TemplateTypeParmDecl*>(TTP));
if (TTP->wasDeclaredWithTypename())
@@ -527,14 +621,14 @@ void DeclPrinter::VisitTemplateDecl(TemplateDecl *D) {
if (TTP->isParameterPack())
Out << "... ";
-
+
Out << ParamType.getAsString(Policy);
if (TTP->hasDefaultArgument()) {
Out << " = ";
Out << TTP->getDefaultArgument().getAsString(Policy);
};
- } else if (const NonTypeTemplateParmDecl *NTTP =
+ } else if (const NonTypeTemplateParmDecl *NTTP =
dyn_cast<NonTypeTemplateParmDecl>(Param)) {
Out << NTTP->getType().getAsString(Policy);
@@ -542,15 +636,15 @@ void DeclPrinter::VisitTemplateDecl(TemplateDecl *D) {
Out << ' ';
Out << Name->getName();
}
-
+
if (NTTP->hasDefaultArgument()) {
Out << " = ";
- NTTP->getDefaultArgument()->printPretty(Out, Context, 0, Policy,
+ NTTP->getDefaultArgument()->printPretty(Out, Context, 0, Policy,
Indentation);
}
}
}
-
+
Out << "> ";
Visit(D->getTemplatedDecl());
@@ -572,29 +666,29 @@ void DeclPrinter::VisitObjCClassDecl(ObjCClassDecl *D) {
void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) {
if (OMD->isInstanceMethod())
Out << "- ";
- else
+ 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!
+ // FIXME: selector is missing here!
pos = name.find_first_of(":", lastPos);
Out << " " << name.substr(lastPos, pos - lastPos);
Out << ":(" << (*PI)->getType().getAsString(Policy) << ")"
- << (*PI)->getNameAsString();
+ << (*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);
@@ -623,7 +717,7 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
Out << "@interface " << I << " : " << SID->getNameAsString();
else
Out << "@interface " << I;
-
+
// Protocols?
const ObjCList<ObjCProtocolDecl> &Protocols = OID->getReferencedProtocols();
if (!Protocols.empty()) {
@@ -631,22 +725,22 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
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";
+ << ' ' << (*I)->getNameAsString() << ";\n";
}
Indentation -= Policy.Indentation;
Out << "}\n";
}
-
+
VisitDeclContext(OID, false);
Out << "@end";
// FIXME: implement the rest...
@@ -654,7 +748,7 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
void DeclPrinter::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) {
Out << "@protocol ";
- for (ObjCForwardProtocolDecl::protocol_iterator I = D->protocol_begin(),
+ for (ObjCForwardProtocolDecl::protocol_iterator I = D->protocol_begin(),
E = D->protocol_end();
I != E; ++I) {
if (I != D->protocol_begin()) Out << ", ";
@@ -671,7 +765,7 @@ void DeclPrinter::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) {
void DeclPrinter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) {
Out << "@implementation "
<< PID->getClassInterface()->getNameAsString()
- << '(' << PID->getNameAsString() << ")\n";
+ << '(' << PID->getNameAsString() << ")\n";
VisitDeclContext(PID, false);
Out << "@end";
@@ -679,18 +773,18 @@ void DeclPrinter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) {
}
void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) {
- Out << "@interface "
+ 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";
+ Out << "@compatibility_alias " << AID->getNameAsString()
+ << ' ' << AID->getClassInterface()->getNameAsString() << ";\n";
}
/// PrintObjCPropertyDecl - print a property declaration.
@@ -700,17 +794,17 @@ void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) {
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() &
+ 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();
@@ -721,29 +815,29 @@ void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) {
<< 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() &
+
+ if (PDecl->getPropertyAttributes() &
ObjCPropertyDecl::OBJC_PR_nonatomic) {
Out << (first ? ' ' : ',') << "nonatomic";
first = false;
@@ -763,3 +857,15 @@ void DeclPrinter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) {
if (PID->getPropertyIvarDecl())
Out << "=" << PID->getPropertyIvarDecl()->getNameAsString();
}
+
+void DeclPrinter::VisitUsingDecl(UsingDecl *D) {
+ Out << "using ";
+ D->getTargetNestedNameDecl()->print(Out, Policy);
+ Out << D->getTargetDecl()->getNameAsString();
+}
+
+void DeclPrinter::VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D) {
+ Out << "using ";
+ D->getTargetNestedNameSpecifier()->print(Out, Policy);
+ Out << D->getTargetName().getAsString();
+}
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index f1bd1b6..7836b3f 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -25,7 +25,7 @@ using namespace clang;
TemplateParameterList::TemplateParameterList(SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
- Decl **Params, unsigned NumParams,
+ NamedDecl **Params, unsigned NumParams,
SourceLocation RAngleLoc)
: TemplateLoc(TemplateLoc), LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc),
NumParams(NumParams) {
@@ -35,31 +35,32 @@ TemplateParameterList::TemplateParameterList(SourceLocation TemplateLoc,
TemplateParameterList *
TemplateParameterList::Create(ASTContext &C, SourceLocation TemplateLoc,
- SourceLocation LAngleLoc, Decl **Params,
+ SourceLocation LAngleLoc, NamedDecl **Params,
unsigned NumParams, SourceLocation RAngleLoc) {
- unsigned Size = sizeof(TemplateParameterList) + sizeof(Decl *) * NumParams;
+ unsigned Size = sizeof(TemplateParameterList)
+ + sizeof(NamedDecl *) * NumParams;
unsigned Align = llvm::AlignOf<TemplateParameterList>::Alignment;
void *Mem = C.Allocate(Size, Align);
- return new (Mem) TemplateParameterList(TemplateLoc, LAngleLoc, Params,
+ return new (Mem) TemplateParameterList(TemplateLoc, LAngleLoc, Params,
NumParams, RAngleLoc);
}
unsigned TemplateParameterList::getMinRequiredArguments() const {
unsigned NumRequiredArgs = size();
- iterator Param = const_cast<TemplateParameterList *>(this)->end(),
+ iterator Param = const_cast<TemplateParameterList *>(this)->end(),
ParamBegin = const_cast<TemplateParameterList *>(this)->begin();
while (Param != ParamBegin) {
--Param;
-
+
if (!(*Param)->isTemplateParameterPack() &&
- !(isa<TemplateTypeParmDecl>(*Param) &&
+ !(isa<TemplateTypeParmDecl>(*Param) &&
cast<TemplateTypeParmDecl>(*Param)->hasDefaultArgument()) &&
!(isa<NonTypeTemplateParmDecl>(*Param) &&
cast<NonTypeTemplateParmDecl>(*Param)->hasDefaultArgument()) &&
!(isa<TemplateTemplateParmDecl>(*Param) &&
cast<TemplateTemplateParmDecl>(*Param)->hasDefaultArgument()))
break;
-
+
--NumRequiredArgs;
}
@@ -94,16 +95,23 @@ void FunctionTemplateDecl::Destroy(ASTContext &C) {
Spec != SpecEnd; ++Spec)
C.Deallocate(&*Spec);
}
-
+
Decl::Destroy(C);
}
+FunctionTemplateDecl *FunctionTemplateDecl::getCanonicalDecl() {
+ FunctionTemplateDecl *FunTmpl = this;
+ while (FunTmpl->getPreviousDeclaration())
+ FunTmpl = FunTmpl->getPreviousDeclaration();
+ return FunTmpl;
+}
+
FunctionTemplateDecl::Common *FunctionTemplateDecl::getCommonPtr() {
// Find the first declaration of this function template.
FunctionTemplateDecl *First = this;
while (First->getPreviousDeclaration())
First = First->getPreviousDeclaration();
-
+
if (First->CommonOrPrev.isNull()) {
// FIXME: Allocate with the ASTContext
First->CommonOrPrev = new Common;
@@ -115,6 +123,13 @@ FunctionTemplateDecl::Common *FunctionTemplateDecl::getCommonPtr() {
// ClassTemplateDecl Implementation
//===----------------------------------------------------------------------===//
+ClassTemplateDecl *ClassTemplateDecl::getCanonicalDecl() {
+ ClassTemplateDecl *Template = this;
+ while (Template->getPreviousDeclaration())
+ Template = Template->getPreviousDeclaration();
+ return Template;
+}
+
ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C,
DeclContext *DC,
SourceLocation L,
@@ -128,7 +143,7 @@ ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C,
else
CommonPtr = new (C) Common;
- return new (C) ClassTemplateDecl(DC, L, Name, Params, Decl, PrevDecl,
+ return new (C) ClassTemplateDecl(DC, L, Name, Params, Decl, PrevDecl,
CommonPtr);
}
@@ -147,6 +162,21 @@ void ClassTemplateDecl::Destroy(ASTContext& C) {
C.Deallocate((void*)this);
}
+ClassTemplatePartialSpecializationDecl *
+ClassTemplateDecl::findPartialSpecialization(QualType T) {
+ ASTContext &Context = getASTContext();
+ typedef llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator
+ partial_spec_iterator;
+ for (partial_spec_iterator P = getPartialSpecializations().begin(),
+ PEnd = getPartialSpecializations().end();
+ P != PEnd; ++P) {
+ if (Context.hasSameType(Context.getTypeDeclType(&*P), T))
+ return &*P;
+ }
+
+ return 0;
+}
+
QualType ClassTemplateDecl::getInjectedClassNameType(ASTContext &Context) {
if (!CommonPtr->InjectedClassNameType.isNull())
return CommonPtr->InjectedClassNameType;
@@ -157,52 +187,32 @@ QualType ClassTemplateDecl::getInjectedClassNameType(ASTContext &Context) {
// 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();
+ 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(),
+ TemplateArgs.push_back(TemplateArgument((*Param)->getLocation(),
ParamType));
- CanonTemplateArgs.push_back(
- TemplateArgument((*Param)->getLocation(),
- Context.getCanonicalType(ParamType)));
- } else if (NonTypeTemplateParmDecl *NTTP =
+ } 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 {
+ } 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,
+ = Context.getTemplateSpecializationType(TemplateName(this),
&TemplateArgs[0],
- TemplateArgs.size(),
- CanonType);
+ TemplateArgs.size());
return CommonPtr->InjectedClassNameType;
}
@@ -227,14 +237,13 @@ 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);
+ DeclaratorInfo *DInfo) {
+ return new (C) NonTypeTemplateParmDecl(DC, L, D, P, Id, T, DInfo);
}
SourceLocation NonTypeTemplateParmDecl::getDefaultArgumentLoc() const {
return DefaultArgument? DefaultArgument->getSourceRange().getBegin()
- : SourceLocation();
+ : SourceLocation();
}
//===----------------------------------------------------------------------===//
@@ -251,7 +260,7 @@ TemplateTemplateParmDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation TemplateTemplateParmDecl::getDefaultArgumentLoc() const {
return DefaultArgument? DefaultArgument->getSourceRange().getBegin()
- : SourceLocation();
+ : SourceLocation();
}
//===----------------------------------------------------------------------===//
@@ -264,10 +273,10 @@ TemplateArgument::TemplateArgument(Expr *E) : Kind(Expression) {
}
/// \brief Construct a template argument pack.
-void TemplateArgument::setArgumentPack(TemplateArgument *args, unsigned NumArgs,
+void TemplateArgument::setArgumentPack(TemplateArgument *args, unsigned NumArgs,
bool CopyArgs) {
assert(isNull() && "Must call setArgumentPack on a null argument");
-
+
Kind = Pack;
Args.NumArgs = NumArgs;
Args.CopyArgs = CopyArgs;
@@ -275,7 +284,8 @@ void TemplateArgument::setArgumentPack(TemplateArgument *args, unsigned NumArgs,
Args.Args = args;
return;
}
-
+
+ // FIXME: Allocate in ASTContext
Args.Args = new TemplateArgument[NumArgs];
for (unsigned I = 0; I != Args.NumArgs; ++I)
Args.Args[I] = args[I];
@@ -292,21 +302,21 @@ void TemplateArgumentListBuilder::Append(const TemplateArgument& Arg) {
assert(Arg.getAsType()->isCanonical() && "Type must be canonical!");
break;
}
-
+
assert(NumFlatArgs < MaxFlatArgs && "Argument list builder is full!");
- assert(!StructuredArgs &&
+ assert(!StructuredArgs &&
"Can't append arguments when an argument pack has been added!");
-
+
if (!FlatArgs)
FlatArgs = new TemplateArgument[MaxFlatArgs];
-
+
FlatArgs[NumFlatArgs++] = Arg;
}
void TemplateArgumentListBuilder::BeginPack() {
assert(!AddingToPack && "Already adding to pack!");
assert(!StructuredArgs && "Argument list already contains a pack!");
-
+
AddingToPack = true;
PackBeginIndex = NumFlatArgs;
}
@@ -314,24 +324,24 @@ void TemplateArgumentListBuilder::BeginPack() {
void TemplateArgumentListBuilder::EndPack() {
assert(AddingToPack && "Not adding to pack!");
assert(!StructuredArgs && "Argument list already contains a pack!");
-
+
AddingToPack = false;
StructuredArgs = new TemplateArgument[MaxStructuredArgs];
-
+
// First copy the flat entries over to the list (if any)
for (unsigned I = 0; I != PackBeginIndex; ++I) {
NumStructuredArgs++;
StructuredArgs[I] = FlatArgs[I];
}
-
+
// Next, set the pack.
TemplateArgument *PackArgs = 0;
unsigned NumPackArgs = NumFlatArgs - PackBeginIndex;
if (NumPackArgs)
PackArgs = &FlatArgs[PackBeginIndex];
-
- StructuredArgs[NumStructuredArgs++].setArgumentPack(PackArgs, NumPackArgs,
+
+ StructuredArgs[NumStructuredArgs++].setArgumentPack(PackArgs, NumPackArgs,
/*CopyArgs=*/false);
}
@@ -350,19 +360,25 @@ void TemplateArgumentListBuilder::ReleaseArgs() {
TemplateArgumentList::TemplateArgumentList(ASTContext &Context,
TemplateArgumentListBuilder &Builder,
bool TakeArgs)
- : FlatArguments(Builder.getFlatArguments(), TakeArgs),
- NumFlatArguments(Builder.flatSize()),
+ : FlatArguments(Builder.getFlatArguments(), TakeArgs),
+ NumFlatArguments(Builder.flatSize()),
StructuredArguments(Builder.getStructuredArguments(), TakeArgs),
NumStructuredArguments(Builder.structuredSize()) {
-
+
if (!TakeArgs)
return;
-
+
if (Builder.getStructuredArguments() == Builder.getFlatArguments())
StructuredArguments.setInt(0);
Builder.ReleaseArgs();
}
+TemplateArgumentList::TemplateArgumentList(const TemplateArgumentList &Other)
+ : FlatArguments(Other.FlatArguments.getPointer(), 1),
+ NumFlatArguments(Other.flat_size()),
+ StructuredArguments(Other.StructuredArguments.getPointer(), 1),
+ NumStructuredArguments(Other.NumStructuredArguments) { }
+
TemplateArgumentList::~TemplateArgumentList() {
// FIXME: Deallocate template arguments
}
@@ -374,34 +390,66 @@ ClassTemplateSpecializationDecl::
ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK,
DeclContext *DC, SourceLocation L,
ClassTemplateDecl *SpecializedTemplate,
- TemplateArgumentListBuilder &Builder)
- : CXXRecordDecl(DK,
- SpecializedTemplate->getTemplatedDecl()->getTagKind(),
+ TemplateArgumentListBuilder &Builder,
+ ClassTemplateSpecializationDecl *PrevDecl)
+ : CXXRecordDecl(DK,
+ SpecializedTemplate->getTemplatedDecl()->getTagKind(),
DC, L,
// FIXME: Should we use DeclarationName for the name of
// class template specializations?
- SpecializedTemplate->getIdentifier()),
+ SpecializedTemplate->getIdentifier(),
+ PrevDecl),
SpecializedTemplate(SpecializedTemplate),
TemplateArgs(Context, Builder, /*TakeArgs=*/true),
SpecializationKind(TSK_Undeclared) {
}
-
+
ClassTemplateSpecializationDecl *
-ClassTemplateSpecializationDecl::Create(ASTContext &Context,
+ClassTemplateSpecializationDecl::Create(ASTContext &Context,
DeclContext *DC, SourceLocation L,
ClassTemplateDecl *SpecializedTemplate,
TemplateArgumentListBuilder &Builder,
ClassTemplateSpecializationDecl *PrevDecl) {
ClassTemplateSpecializationDecl *Result
- = new (Context)ClassTemplateSpecializationDecl(Context,
+ = new (Context)ClassTemplateSpecializationDecl(Context,
ClassTemplateSpecialization,
- DC, L,
+ DC, L,
SpecializedTemplate,
- Builder);
+ Builder,
+ PrevDecl);
Context.getTypeDeclType(Result, PrevDecl);
return Result;
}
+void ClassTemplateSpecializationDecl::Destroy(ASTContext &C) {
+ if (SpecializedPartialSpecialization *PartialSpec
+ = SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization*>())
+ C.Deallocate(PartialSpec);
+
+ CXXRecordDecl::Destroy(C);
+}
+
+void
+ClassTemplateSpecializationDecl::getNameForDiagnostic(std::string &S,
+ const PrintingPolicy &Policy,
+ bool Qualified) const {
+ NamedDecl::getNameForDiagnostic(S, Policy, Qualified);
+
+ const TemplateArgumentList &TemplateArgs = getTemplateArgs();
+ S += TemplateSpecializationType::PrintTemplateArgumentList(
+ TemplateArgs.getFlatArgumentList(),
+ TemplateArgs.flat_size(),
+ Policy);
+}
+
+ClassTemplateDecl *
+ClassTemplateSpecializationDecl::getSpecializedTemplate() const {
+ if (SpecializedPartialSpecialization *PartialSpec
+ = SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization*>())
+ return PartialSpec->PartialSpecialization->getSpecializedTemplate();
+ return SpecializedTemplate.get<ClassTemplateDecl*>();
+}
+
//===----------------------------------------------------------------------===//
// ClassTemplatePartialSpecializationDecl Implementation
//===----------------------------------------------------------------------===//
@@ -413,11 +461,27 @@ Create(ASTContext &Context, DeclContext *DC, SourceLocation L,
TemplateArgumentListBuilder &Builder,
ClassTemplatePartialSpecializationDecl *PrevDecl) {
ClassTemplatePartialSpecializationDecl *Result
- = new (Context)ClassTemplatePartialSpecializationDecl(Context,
+ = new (Context)ClassTemplatePartialSpecializationDecl(Context,
DC, L, Params,
SpecializedTemplate,
- Builder);
+ Builder, PrevDecl);
Result->setSpecializationKind(TSK_ExplicitSpecialization);
Context.getTypeDeclType(Result, PrevDecl);
return Result;
}
+
+//===----------------------------------------------------------------------===//
+// FriendTemplateDecl Implementation
+//===----------------------------------------------------------------------===//
+
+FriendTemplateDecl *FriendTemplateDecl::Create(ASTContext &Context,
+ DeclContext *DC,
+ SourceLocation L,
+ unsigned NParams,
+ TemplateParameterList **Params,
+ FriendUnion Friend,
+ SourceLocation FLoc) {
+ FriendTemplateDecl *Result
+ = new (Context) FriendTemplateDecl(DC, L, NParams, Params, Friend, FLoc);
+ return Result;
+}
diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp
index a17abde..101ddd2 100644
--- a/lib/AST/DeclarationName.cpp
+++ b/lib/AST/DeclarationName.cpp
@@ -23,7 +23,7 @@ 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
+class CXXSpecialName
: public DeclarationNameExtra, public llvm::FoldingSetNode {
public:
/// Type - The type associated with this declaration name.
@@ -40,7 +40,7 @@ public:
};
/// CXXOperatorIdName - Contains extra information for the name of an
-/// overloaded operator in C++, such as "operator+.
+/// overloaded operator in C++, such as "operator+.
class CXXOperatorIdName : public DeclarationNameExtra {
public:
/// FETokenInfo - Extra information associated with this operator
@@ -93,13 +93,13 @@ DeclarationName::NameKind DeclarationName::getNameKind() const {
case StoredDeclarationNameExtra:
switch (getExtra()->ExtraKindOrNumArgs) {
- case DeclarationNameExtra::CXXConstructor:
+ case DeclarationNameExtra::CXXConstructor:
return CXXConstructorName;
- case DeclarationNameExtra::CXXDestructor:
+ case DeclarationNameExtra::CXXDestructor:
return CXXDestructorName;
- case DeclarationNameExtra::CXXConversionFunction:
+ case DeclarationNameExtra::CXXConversionFunction:
return CXXConversionFunctionName;
case DeclarationNameExtra::CXXUsingDirective:
@@ -107,7 +107,7 @@ DeclarationName::NameKind DeclarationName::getNameKind() const {
default:
// Check if we have one of the CXXOperator* enumeration values.
- if (getExtra()->ExtraKindOrNumArgs <
+ if (getExtra()->ExtraKindOrNumArgs <
DeclarationNameExtra::CXXUsingDirective)
return CXXOperatorName;
@@ -135,7 +135,7 @@ std::string DeclarationName::getAsString() const {
case CXXConstructorName: {
QualType ClassType = getCXXNameType();
- if (const RecordType *ClassRec = ClassType->getAsRecordType())
+ if (const RecordType *ClassRec = ClassType->getAs<RecordType>())
return ClassRec->getDecl()->getNameAsString();
return ClassType.getAsString();
}
@@ -143,7 +143,7 @@ std::string DeclarationName::getAsString() const {
case CXXDestructorName: {
std::string Result = "~";
QualType Type = getCXXNameType();
- if (const RecordType *Rec = Type->getAsRecordType())
+ if (const RecordType *Rec = Type->getAs<RecordType>())
Result += Rec->getDecl()->getNameAsString();
else
Result += Type.getAsString();
@@ -159,7 +159,7 @@ std::string DeclarationName::getAsString() const {
};
const char *OpName = OperatorNames[getCXXOverloadedOperator()];
assert(OpName && "not an overloaded operator");
-
+
std::string Result = "operator";
if (OpName[0] >= 'a' && OpName[0] <= 'z')
Result += ' ';
@@ -170,7 +170,7 @@ std::string DeclarationName::getAsString() const {
case CXXConversionFunctionName: {
std::string Result = "operator ";
QualType Type = getCXXNameType();
- if (const RecordType *Rec = Type->getAsRecordType())
+ if (const RecordType *Rec = Type->getAs<RecordType>())
Result += Rec->getDecl()->getNameAsString();
else
Result += Type.getAsString();
@@ -193,7 +193,7 @@ QualType DeclarationName::getCXXNameType() const {
OverloadedOperatorKind DeclarationName::getCXXOverloadedOperator() const {
if (CXXOperatorIdName *CXXOp = getAsCXXOperatorIdName()) {
- unsigned value
+ unsigned value
= CXXOp->ExtraKindOrNumArgs - DeclarationNameExtra::CXXConversionFunction;
return static_cast<OverloadedOperatorKind>(value);
} else {
@@ -276,7 +276,7 @@ DeclarationNameTable::DeclarationNameTable() {
// Initialize the overloaded operator names.
CXXOperatorNames = new CXXOperatorIdName[NUM_OVERLOADED_OPERATORS];
for (unsigned Op = 0; Op < NUM_OVERLOADED_OPERATORS; ++Op) {
- CXXOperatorNames[Op].ExtraKindOrNumArgs
+ CXXOperatorNames[Op].ExtraKindOrNumArgs
= Op + DeclarationNameExtra::CXXConversionFunction;
CXXOperatorNames[Op].FETokenInfo = 0;
}
@@ -296,26 +296,24 @@ DeclarationNameTable::~DeclarationNameTable() {
delete [] CXXOperatorNames;
}
-DeclarationName
-DeclarationNameTable::getCXXSpecialName(DeclarationName::NameKind Kind,
- QualType Ty) {
+DeclarationName
+DeclarationNameTable::getCXXSpecialName(DeclarationName::NameKind Kind,
+ CanQualType 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
+ llvm::FoldingSet<CXXSpecialName> *SpecialNames
= static_cast<llvm::FoldingSet<CXXSpecialName>*>(CXXSpecialNamesImpl);
DeclarationNameExtra::ExtraKind EKind;
switch (Kind) {
- case DeclarationName::CXXConstructorName:
+ case DeclarationName::CXXConstructorName:
EKind = DeclarationNameExtra::CXXConstructor;
- assert(Ty.getCVRQualifiers() == 0 &&"Constructor type must be unqualified");
+ assert(!Ty.hasQualifiers() &&"Constructor type must be unqualified");
break;
case DeclarationName::CXXDestructorName:
EKind = DeclarationNameExtra::CXXDestructor;
- assert(Ty.getCVRQualifiers() == 0 && "Destructor type must be unqualified");
+ assert(!Ty.hasQualifiers() && "Destructor type must be unqualified");
break;
case DeclarationName::CXXConversionFunctionName:
EKind = DeclarationNameExtra::CXXConversionFunction;
@@ -342,12 +340,12 @@ DeclarationNameTable::getCXXSpecialName(DeclarationName::NameKind Kind,
return DeclarationName(SpecialName);
}
-DeclarationName
+DeclarationName
DeclarationNameTable::getCXXOperatorName(OverloadedOperatorKind Op) {
return DeclarationName(&CXXOperatorNames[(unsigned)Op]);
}
-unsigned
+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
index 482e106..0e4a29f 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/APValue.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
@@ -21,6 +22,7 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/TargetInfo.h"
+#include "llvm/Support/raw_ostream.h"
#include <algorithm>
using namespace clang;
@@ -28,34 +30,80 @@ using namespace clang;
// Primary Expressions.
//===----------------------------------------------------------------------===//
-PredefinedExpr* PredefinedExpr::Clone(ASTContext &C) const {
- return new (C) PredefinedExpr(Loc, getType(), Type);
-}
+// FIXME: Maybe this should use DeclPrinter with a special "print predefined
+// expr" policy instead.
+std::string PredefinedExpr::ComputeName(ASTContext &Context, IdentType IT,
+ const Decl *CurrentDecl) {
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurrentDecl)) {
+ if (IT != PrettyFunction)
+ return FD->getNameAsString();
-IntegerLiteral* IntegerLiteral::Clone(ASTContext &C) const {
- return new (C) IntegerLiteral(Value, getType(), Loc);
-}
+ llvm::SmallString<256> Name;
+ llvm::raw_svector_ostream Out(Name);
-CharacterLiteral* CharacterLiteral::Clone(ASTContext &C) const {
- return new (C) CharacterLiteral(Value, IsWide, getType(), Loc);
-}
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
+ if (MD->isVirtual())
+ Out << "virtual ";
+ }
-FloatingLiteral* FloatingLiteral::Clone(ASTContext &C) const {
- return new (C) FloatingLiteral(Value, IsExact, getType(), Loc);
-}
+ PrintingPolicy Policy(Context.getLangOptions());
+ Policy.SuppressTagKind = true;
-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());
-}
+ std::string Proto = FD->getQualifiedNameAsString(Policy);
+
+ const FunctionType *AFT = FD->getType()->getAs<FunctionType>();
+ const FunctionProtoType *FT = 0;
+ if (FD->hasWrittenPrototype())
+ FT = dyn_cast<FunctionProtoType>(AFT);
+
+ Proto += "(";
+ if (FT) {
+ llvm::raw_string_ostream POut(Proto);
+ for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i) {
+ if (i) POut << ", ";
+ std::string Param;
+ FD->getParamDecl(i)->getType().getAsStringInternal(Param, Policy);
+ POut << Param;
+ }
+
+ if (FT->isVariadic()) {
+ if (FD->getNumParams()) POut << ", ";
+ POut << "...";
+ }
+ }
+ Proto += ")";
+
+ AFT->getResultType().getAsStringInternal(Proto, Policy);
+
+ Out << Proto;
+
+ Out.flush();
+ return Name.str().str();
+ }
+ if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(CurrentDecl)) {
+ llvm::SmallString<256> Name;
+ llvm::raw_svector_ostream Out(Name);
+ Out << (MD->isInstanceMethod() ? '-' : '+');
+ Out << '[';
+ Out << MD->getClassInterface()->getNameAsString();
+ if (const ObjCCategoryImplDecl *CID =
+ dyn_cast<ObjCCategoryImplDecl>(MD->getDeclContext())) {
+ Out << '(';
+ Out << CID->getNameAsString();
+ Out << ')';
+ }
+ Out << ' ';
+ Out << MD->getSelector().getAsString();
+ Out << ']';
-GNUNullExpr* GNUNullExpr::Clone(ASTContext &C) const {
- return new (C) GNUNullExpr(getType(), TokenLoc);
+ Out.flush();
+ return Name.str().str();
+ }
+ if (isa<TranslationUnitDecl>(CurrentDecl) && IT == PrettyFunction) {
+ // __PRETTY_FUNCTION__ -> "top level", the others produce an empty string.
+ return "top level";
+ }
+ return "";
}
/// getValueAsApproximateDouble - This returns the value as an inaccurate
@@ -72,7 +120,7 @@ double FloatingLiteral::getValueAsApproximateDouble() const {
StringLiteral *StringLiteral::Create(ASTContext &C, const char *StrData,
unsigned ByteLength, bool Wide,
QualType Ty,
- const SourceLocation *Loc,
+ const SourceLocation *Loc,
unsigned NumStrs) {
// Allocate enough space for the StringLiteral plus an array of locations for
// any concatenated string tokens.
@@ -80,7 +128,7 @@ StringLiteral *StringLiteral::Create(ASTContext &C, const char *StrData,
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);
@@ -106,25 +154,19 @@ StringLiteral *StringLiteral::CreateEmpty(ASTContext &C, unsigned NumStrs) {
return SL;
}
-StringLiteral* StringLiteral::Clone(ASTContext &C) const {
- return Create(C, StrData, ByteLength, IsWide, getType(),
- TokLocs, NumConcatenated);
-}
-
-void StringLiteral::Destroy(ASTContext &C) {
+void StringLiteral::DoDestroy(ASTContext &C) {
C.Deallocate(const_cast<char*>(StrData));
- this->~StringLiteral();
- C.Deallocate(this);
+ Expr::DoDestroy(C);
}
-void StringLiteral::setStrData(ASTContext &C, const char *Str, unsigned Len) {
+void StringLiteral::setString(ASTContext &C, llvm::StringRef Str) {
if (StrData)
C.Deallocate(const_cast<char*>(StrData));
- char *AStrData = new (C, 1) char[Len];
- memcpy(AStrData, Str, Len);
+ char *AStrData = new (C, 1) char[Str.size()];
+ memcpy(AStrData, Str.data(), Str.size());
StrData = AStrData;
- ByteLength = Len;
+ ByteLength = Str.size();
}
/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it
@@ -149,7 +191,7 @@ const char *UnaryOperator::getOpcodeStr(Opcode Op) {
}
}
-UnaryOperator::Opcode
+UnaryOperator::Opcode
UnaryOperator::getOverloadedOpcode(OverloadedOperatorKind OO, bool Postfix) {
switch (OO) {
default: assert(false && "No unary operator for overloaded function");
@@ -185,11 +227,11 @@ OverloadedOperatorKind UnaryOperator::getOverloadedOperator(Opcode Opc) {
CallExpr::CallExpr(ASTContext& C, StmtClass SC, Expr *fn, Expr **args,
unsigned numargs, QualType t, SourceLocation rparenloc)
- : Expr(SC, t,
+ : 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)
@@ -213,25 +255,33 @@ CallExpr::CallExpr(ASTContext& C, Expr *fn, Expr **args, unsigned numargs,
RParenLoc = rparenloc;
}
-CallExpr::CallExpr(ASTContext &C, EmptyShell Empty)
- : Expr(CallExprClass, Empty), SubExprs(0), NumArgs(0) {
+CallExpr::CallExpr(ASTContext &C, StmtClass SC, EmptyShell Empty)
+ : Expr(SC, Empty), SubExprs(0), NumArgs(0) {
SubExprs = new (C) Stmt*[1];
}
-void CallExpr::Destroy(ASTContext& C) {
+void CallExpr::DoDestroy(ASTContext& C) {
DestroyChildren(C);
if (SubExprs) C.Deallocate(SubExprs);
this->~CallExpr();
C.Deallocate(this);
}
+FunctionDecl *CallExpr::getDirectCallee() {
+ Expr *CEE = getCallee()->IgnoreParenCasts();
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE))
+ return dyn_cast<FunctionDecl>(DRE->getDecl());
+
+ return 0;
+}
+
/// 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)
@@ -241,14 +291,14 @@ void CallExpr::setNumArgs(ASTContext& C, unsigned NumArgs) {
}
// Otherwise, we are growing the # arguments. New an bigger argument array.
- Stmt **NewSubExprs = new Stmt*[NumArgs+1];
+ Stmt **NewSubExprs = new (C) 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;
@@ -258,37 +308,130 @@ void CallExpr::setNumArgs(ASTContext& C, unsigned NumArgs) {
/// 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
+ // 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);
+ return FDecl->getBuiltinID();
}
QualType CallExpr::getCallReturnType() const {
QualType CalleeType = getCallee()->getType();
- if (const PointerType *FnTypePtr = CalleeType->getAsPointerType())
+ if (const PointerType *FnTypePtr = CalleeType->getAs<PointerType>())
CalleeType = FnTypePtr->getPointeeType();
- else if (const BlockPointerType *BPT = CalleeType->getAsBlockPointerType())
+ else if (const BlockPointerType *BPT = CalleeType->getAs<BlockPointerType>())
CalleeType = BPT->getPointeeType();
-
- const FunctionType *FnType = CalleeType->getAsFunctionType();
+
+ const FunctionType *FnType = CalleeType->getAs<FunctionType>();
return FnType->getResultType();
}
+MemberExpr::MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual,
+ SourceRange qualrange, NamedDecl *memberdecl,
+ SourceLocation l, bool has_explicit,
+ SourceLocation langle,
+ const TemplateArgument *targs, unsigned numtargs,
+ SourceLocation rangle, QualType ty)
+ : Expr(MemberExprClass, ty,
+ base->isTypeDependent() || (qual && qual->isDependent()),
+ base->isValueDependent() || (qual && qual->isDependent())),
+ Base(base), MemberDecl(memberdecl), MemberLoc(l), IsArrow(isarrow),
+ HasQualifier(qual != 0), HasExplicitTemplateArgumentList(has_explicit) {
+ // Initialize the qualifier, if any.
+ if (HasQualifier) {
+ NameQualifier *NQ = getMemberQualifier();
+ NQ->NNS = qual;
+ NQ->Range = qualrange;
+ }
+
+ // Initialize the explicit template argument list, if any.
+ if (HasExplicitTemplateArgumentList) {
+ ExplicitTemplateArgumentList *ETemplateArgs
+ = getExplicitTemplateArgumentList();
+ ETemplateArgs->LAngleLoc = langle;
+ ETemplateArgs->RAngleLoc = rangle;
+ ETemplateArgs->NumTemplateArgs = numtargs;
+
+ TemplateArgument *TemplateArgs = ETemplateArgs->getTemplateArgs();
+ for (unsigned I = 0; I < numtargs; ++I)
+ new (TemplateArgs + I) TemplateArgument(targs[I]);
+ }
+}
+
+MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow,
+ NestedNameSpecifier *qual,
+ SourceRange qualrange,
+ NamedDecl *memberdecl,
+ SourceLocation l,
+ bool has_explicit,
+ SourceLocation langle,
+ const TemplateArgument *targs,
+ unsigned numtargs,
+ SourceLocation rangle,
+ QualType ty) {
+ std::size_t Size = sizeof(MemberExpr);
+ if (qual != 0)
+ Size += sizeof(NameQualifier);
+
+ if (has_explicit)
+ Size += sizeof(ExplicitTemplateArgumentList) +
+ sizeof(TemplateArgument) * numtargs;
+
+ void *Mem = C.Allocate(Size, llvm::alignof<MemberExpr>());
+ return new (Mem) MemberExpr(base, isarrow, qual, qualrange, memberdecl, l,
+ has_explicit, langle, targs, numtargs, rangle,
+ ty);
+}
+
+const char *CastExpr::getCastKindName() const {
+ switch (getCastKind()) {
+ case CastExpr::CK_Unknown:
+ return "Unknown";
+ case CastExpr::CK_BitCast:
+ return "BitCast";
+ case CastExpr::CK_NoOp:
+ return "NoOp";
+ case CastExpr::CK_DerivedToBase:
+ return "DerivedToBase";
+ case CastExpr::CK_Dynamic:
+ return "Dynamic";
+ case CastExpr::CK_ToUnion:
+ return "ToUnion";
+ case CastExpr::CK_ArrayToPointerDecay:
+ return "ArrayToPointerDecay";
+ case CastExpr::CK_FunctionToPointerDecay:
+ return "FunctionToPointerDecay";
+ case CastExpr::CK_NullToMemberPointer:
+ return "NullToMemberPointer";
+ case CastExpr::CK_BaseToDerivedMemberPointer:
+ return "BaseToDerivedMemberPointer";
+ case CastExpr::CK_UserDefinedConversion:
+ return "UserDefinedConversion";
+ case CastExpr::CK_ConstructorConversion:
+ return "ConstructorConversion";
+ case CastExpr::CK_IntegralToPointer:
+ return "IntegralToPointer";
+ case CastExpr::CK_PointerToIntegral:
+ return "PointerToIntegral";
+ }
+
+ assert(0 && "Unhandled cast kind!");
+ return 0;
+}
+
/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it
/// corresponds to, e.g. "<<=".
const char *BinaryOperator::getOpcodeStr(Opcode Op) {
@@ -330,7 +473,7 @@ const char *BinaryOperator::getOpcodeStr(Opcode Op) {
return "";
}
-BinaryOperator::Opcode
+BinaryOperator::Opcode
BinaryOperator::getOverloadedOpcode(OverloadedOperatorKind OO) {
switch (OO) {
default: assert(false && "Not an overloadable binary operator");
@@ -392,13 +535,13 @@ OverloadedOperatorKind BinaryOperator::getOverloadedOperator(Opcode Opc) {
return OverOps[Opc];
}
-InitListExpr::InitListExpr(SourceLocation lbraceloc,
+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),
+ LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0),
UnionFieldInit(0), HadArrayRangeDesignator(false) {
InitExprs.insert(InitExprs.end(), initExprs, initExprs+numInits);
@@ -422,7 +565,7 @@ Expr *InitListExpr::updateInit(unsigned Init, Expr *expr) {
InitExprs.back() = expr;
return 0;
}
-
+
Expr *Result = cast_or_null<Expr>(InitExprs[Init]);
InitExprs[Init] = expr;
return Result;
@@ -431,18 +574,18 @@ Expr *InitListExpr::updateInit(unsigned Init, Expr *expr) {
/// getFunctionType - Return the underlying function type for this block.
///
const FunctionType *BlockExpr::getFunctionType() const {
- return getType()->getAsBlockPointerType()->
- getPointeeType()->getAsFunctionType();
+ return getType()->getAs<BlockPointerType>()->
+ getPointeeType()->getAs<FunctionType>();
}
-SourceLocation BlockExpr::getCaretLocation() const {
- return TheBlock->getCaretLocation();
+SourceLocation BlockExpr::getCaretLocation() const {
+ return TheBlock->getCaretLocation();
}
-const Stmt *BlockExpr::getBody() const {
+const Stmt *BlockExpr::getBody() const {
return TheBlock->getBody();
}
-Stmt *BlockExpr::getBody() {
- return TheBlock->getBody();
+Stmt *BlockExpr::getBody() {
+ return TheBlock->getBody();
}
@@ -460,7 +603,7 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
// instantiating to void.
if (isTypeDependent())
return false;
-
+
switch (getStmtClass()) {
default:
Loc = getExprLoc();
@@ -471,7 +614,7 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
isUnusedResultAWarning(Loc, R1, R2);
case UnaryOperatorClass: {
const UnaryOperator *UO = cast<UnaryOperator>(this);
-
+
switch (UO->getOpcode()) {
default: break;
case UnaryOperator::PostInc:
@@ -503,7 +646,7 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
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();
@@ -518,7 +661,7 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
// 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() &&
+ if (Exp->getLHS() &&
Exp->getLHS()->isUnusedResultAWarning(Loc, R1, R2))
return true;
return Exp->getRHS()->isUnusedResultAWarning(Loc, R1, R2);
@@ -533,7 +676,7 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
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.
@@ -549,26 +692,43 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
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 (const FunctionDecl *FD = CE->getDirectCallee()) {
// 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;
- }
+ //
+ // Note: If new cases are added here, DiagnoseUnusedExprResult should be
+ // updated to match for QoI.
+ 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 ObjCImplicitSetterGetterRefExprClass: { // Dot syntax for message send.
+#if 0
+ const ObjCImplicitSetterGetterRefExpr *Ref =
+ cast<ObjCImplicitSetterGetterRefExpr>(this);
+ // FIXME: We really want the location of the '.' here.
+ Loc = Ref->getLocation();
+ R1 = SourceRange(Ref->getLocation(), Ref->getLocation());
+ if (Ref->getBase())
+ R2 = Ref->getBase()->getSourceRange();
+#else
+ Loc = getExprLoc();
+ R1 = getSourceRange();
+#endif
+ return true;
+ }
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.
@@ -579,17 +739,16 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
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 this is an explicit cast to void, allow it. People do this when they
+ // think they know what they're doing :).
if (getType()->isVoidType())
- return cast<CastExpr>(this)->getSubExpr()
- ->isUnusedResultAWarning(Loc, R1, R2);
+ return false;
Loc = cast<CStyleCastExpr>(this)->getLParenLoc();
R1 = cast<CStyleCastExpr>(this)->getSubExpr()->getSourceRange();
return true;
@@ -602,7 +761,7 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
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)
@@ -617,6 +776,9 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
// effects (e.g. a placement new with an uninitialized POD).
case CXXDeleteExprClass:
return false;
+ case CXXBindTemporaryExprClass:
+ return cast<CXXBindTemporaryExpr>(this)
+ ->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2);
case CXXExprWithTemporariesClass:
return cast<CXXExprWithTemporaries>(this)
->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2);
@@ -628,14 +790,15 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
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
+ 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)));
+ (isa<FunctionDecl>(Decl) || isa<OverloadedFunctionDecl>(Decl) ||
+ isa<FunctionTemplateDecl>(Decl)));
}
/// isLvalue - C99 6.3.2.1: an lvalue is an expression with an object type or an
@@ -659,11 +822,11 @@ Expr::isLvalueResult Expr::isLvalue(ASTContext &Ctx) const {
// 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())
+ if (TR->isFunctionType() || TR == Ctx.OverloadTy)
return LV_NotObjectType;
// Allow qualified void which is an incomplete type other than void (yuck).
- if (TR->isVoidType() && !Ctx.getCanonicalType(TR).getCVRQualifiers())
+ if (TR->isVoidType() && !Ctx.getCanonicalType(TR).hasQualifiers())
return LV_IncompleteVoidType;
return LV_Valid;
@@ -680,7 +843,7 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const {
if (cast<ArraySubscriptExpr>(this)->getBase()->getType()->isVectorType())
return cast<ArraySubscriptExpr>(this)->getBase()->isLvalue(Ctx);
return LV_Valid;
- case DeclRefExprClass:
+ case DeclRefExprClass:
case QualifiedDeclRefExprClass: { // C99 6.5.1p2
const NamedDecl *RefdDecl = cast<DeclRefExpr>(this)->getDecl();
if (DeclCanBeLvalue(RefdDecl, Ctx))
@@ -693,7 +856,7 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const {
return LV_Valid;
break;
}
- case MemberExprClass: {
+ case MemberExprClass: {
const MemberExpr *m = cast<MemberExpr>(this);
if (Ctx.getLangOptions().CPlusPlus) { // C++ [expr.ref]p4:
NamedDecl *Member = m->getMemberDecl();
@@ -727,7 +890,7 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const {
// Not an lvalue.
return LV_InvalidExpression;
- }
+ }
// C99 6.5.2.3p4
return m->isArrow() ? LV_Valid : m->getBase()->isLvalue(Ctx);
@@ -747,7 +910,7 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const {
return LV_Valid;
break;
case ImplicitCastExprClass:
- return cast<ImplicitCastExpr>(this)->isLvalueCast()? LV_Valid
+ return cast<ImplicitCastExpr>(this)->isLvalueCast()? LV_Valid
: LV_InvalidExpression;
case ParenExprClass: // C99 6.5.1p5
return cast<ParenExpr>(this)->getSubExpr()->isLvalue(Ctx);
@@ -760,16 +923,26 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const {
return BinOp->getRHS()->isLvalue(Ctx);
// C++ [expr.mptr.oper]p6
- if ((BinOp->getOpcode() == BinaryOperator::PtrMemD ||
- BinOp->getOpcode() == BinaryOperator::PtrMemI) &&
+ // The result of a .* expression is an lvalue only if its first operand is
+ // an lvalue and its second operand is a pointer to data member.
+ if (BinOp->getOpcode() == BinaryOperator::PtrMemD &&
!BinOp->getType()->isFunctionType())
return BinOp->getLHS()->isLvalue(Ctx);
+ // The result of an ->* expression is an lvalue only if its second operand
+ // is a pointer to data member.
+ if (BinOp->getOpcode() == BinaryOperator::PtrMemI &&
+ !BinOp->getType()->isFunctionType()) {
+ QualType Ty = BinOp->getRHS()->getType();
+ if (Ty->isMemberPointerType() && !Ty->isMemberFunctionPointerType())
+ return LV_Valid;
+ }
+
if (!BinOp->isAssignmentOp())
return LV_InvalidExpression;
if (Ctx.getLangOptions().CPlusPlus)
- // C++ [expr.ass]p1:
+ // C++ [expr.ass]p1:
// The result of an assignment operation [...] is an lvalue.
return LV_Valid;
@@ -778,7 +951,7 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const {
// An assignment expression [...] is not an lvalue.
return LV_InvalidExpression;
}
- case CallExprClass:
+ case CallExprClass:
case CXXOperatorCallExprClass:
case CXXMemberCallExprClass: {
// C++0x [expr.call]p10
@@ -803,7 +976,7 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const {
return LV_Valid;
case ObjCPropertyRefExprClass: // FIXME: check if read-only property.
return LV_Valid;
- case ObjCKVCRefExprClass: // FIXME: check if read-only property.
+ case ObjCImplicitSetterGetterRefExprClass: // FIXME: check if read-only property.
return LV_Valid;
case PredefinedExprClass:
return LV_Valid;
@@ -828,6 +1001,9 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const {
case CXXTypeidExprClass:
// C++ 5.2.8p1: The result of a typeid expression is an lvalue of ...
return LV_Valid;
+ case CXXBindTemporaryExprClass:
+ return cast<CXXBindTemporaryExpr>(this)->getSubExpr()->
+ isLvalueInternal(Ctx);
case ConditionalOperatorClass: {
// Complicated handling is only for C++.
if (!Ctx.getLangOptions().CPlusPlus)
@@ -862,15 +1038,15 @@ Expr::isLvalueResult Expr::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,
+/// 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::isModifiableLvalueResult
Expr::isModifiableLvalue(ASTContext &Ctx, SourceLocation *Loc) const {
isLvalueResult lvalResult = isLvalue(Ctx);
-
+
switch (lvalResult) {
- case LV_Valid:
+ case LV_Valid:
// C++ 3.10p11: Functions cannot be modified, but pointers to
// functions can be modifiable.
if (Ctx.getLangOptions().CPlusPlus && TR->isFunctionType())
@@ -900,74 +1076,37 @@ Expr::isModifiableLvalue(ASTContext &Ctx, SourceLocation *Loc) const {
// void takeclosure(void (^C)(void));
// void func() { int x = 1; takeclosure(^{ x = 7; }); }
//
- if (isa<BlockDeclRefExpr>(this)) {
- const BlockDeclRefExpr *BDR = cast<BlockDeclRefExpr>(this);
+ if (const BlockDeclRefExpr *BDR = dyn_cast<BlockDeclRefExpr>(this)) {
if (!BDR->isByRef() && isa<VarDecl>(BDR->getDecl()))
return MLV_NotBlockQualified;
}
+ // Assigning to an 'implicit' property?
+ if (const ObjCImplicitSetterGetterRefExpr* Expr =
+ dyn_cast<ObjCImplicitSetterGetterRefExpr>(this)) {
+ if (Expr->getSetterMethod() == 0)
+ return MLV_NoSetterProperty;
+ }
+
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())
+
+ if (const RecordType *r = CT->getAs<RecordType>()) {
+ 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();
- }
+ return MLV_Valid;
}
/// isOBJCGCCandidate - Check if an expression is objc gc'able.
-///
+/// returns true, if it is; false otherwise.
bool Expr::isOBJCGCCandidate(ASTContext &Ctx) const {
switch (getStmtClass()) {
default:
@@ -989,11 +1128,10 @@ bool Expr::isOBJCGCCandidate(ASTContext &Ctx) const {
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;
-
+ // dereferencing to a pointer is always a gc'able candidate,
+ // unless it is __weak.
+ return T->isPointerType() &&
+ (Ctx.getObjCGCAttrKind(T) != Qualifiers::Weak);
}
return false;
}
@@ -1009,7 +1147,7 @@ Expr* Expr::IgnoreParens() {
Expr* E = this;
while (ParenExpr* P = dyn_cast<ParenExpr>(E))
E = P->getSubExpr();
-
+
return E;
}
@@ -1037,17 +1175,17 @@ Expr *Expr::IgnoreParenNoopCasts(ASTContext &Ctx) {
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())) {
@@ -1055,7 +1193,7 @@ Expr *Expr::IgnoreParenNoopCasts(ASTContext &Ctx) {
continue;
}
}
-
+
return E;
}
}
@@ -1094,6 +1232,7 @@ bool Expr::isConstantInitializer(ASTContext &Ctx) const {
switch (getStmtClass()) {
default: break;
case StringLiteralClass:
+ case ObjCStringLiteralClass:
case ObjCEncodeExprClass:
return true;
case CompoundLiteralExprClass: {
@@ -1110,22 +1249,31 @@ bool Expr::isConstantInitializer(ASTContext &Ctx) const {
const InitListExpr *Exp = cast<InitListExpr>(this);
unsigned numInits = Exp->getNumInits();
for (unsigned i = 0; i < numInits; i++) {
- if (!Exp->getInit(i)->isConstantInitializer(Ctx))
+ if (!Exp->getInit(i)->isConstantInitializer(Ctx))
return false;
}
return true;
}
case ImplicitValueInitExprClass:
return true;
- case ParenExprClass: {
+ 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 BinaryOperatorClass: {
+ // Special case &&foo - &&bar. It would be nice to generalize this somehow
+ // but this handles the common case.
+ const BinaryOperator *Exp = cast<BinaryOperator>(this);
+ if (Exp->getOpcode() == BinaryOperator::Sub &&
+ isa<AddrLabelExpr>(Exp->getLHS()->IgnoreParenNoopCasts(Ctx)) &&
+ isa<AddrLabelExpr>(Exp->getRHS()->IgnoreParenNoopCasts(Ctx)))
+ return true;
+ break;
+ }
case ImplicitCastExprClass:
case CStyleCastExprClass:
// Handle casts with a destination that's a struct or union; this
@@ -1133,9 +1281,15 @@ bool Expr::isConstantInitializer(ASTContext &Ctx) const {
// cast-to-union extension.
if (getType()->isRecordType())
return cast<CastExpr>(this)->getSubExpr()->isConstantInitializer(Ctx);
+
+ // Integer->integer casts can be handled here, which is important for
+ // things like (int)(&&x-&&y). Scary but true.
+ if (getType()->isIntegerType() &&
+ cast<CastExpr>(this)->getSubExpr()->getType()->isIntegerType())
+ return cast<CastExpr>(this)->getSubExpr()->isConstantInitializer(Ctx);
+
break;
}
-
return isEvaluatable(Ctx);
}
@@ -1152,9 +1306,9 @@ bool Expr::isConstantInitializer(ASTContext &Ctx) const {
// 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
+// 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.
+// value, it calls into Evalute.
//
// Meanings of Val:
// 0: This expression is an ICE if it can be evaluated by Evaluate.
@@ -1190,8 +1344,65 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
}
switch (E->getStmtClass()) {
- default:
+#define STMT(Node, Base) case Expr::Node##Class:
+#define EXPR(Node, Base)
+#include "clang/AST/StmtNodes.def"
+ case Expr::PredefinedExprClass:
+ case Expr::FloatingLiteralClass:
+ case Expr::ImaginaryLiteralClass:
+ case Expr::StringLiteralClass:
+ case Expr::ArraySubscriptExprClass:
+ case Expr::MemberExprClass:
+ case Expr::CompoundAssignOperatorClass:
+ case Expr::CompoundLiteralExprClass:
+ case Expr::ExtVectorElementExprClass:
+ case Expr::InitListExprClass:
+ case Expr::DesignatedInitExprClass:
+ case Expr::ImplicitValueInitExprClass:
+ case Expr::ParenListExprClass:
+ case Expr::VAArgExprClass:
+ case Expr::AddrLabelExprClass:
+ case Expr::StmtExprClass:
+ case Expr::CXXMemberCallExprClass:
+ case Expr::CXXDynamicCastExprClass:
+ case Expr::CXXTypeidExprClass:
+ case Expr::CXXNullPtrLiteralExprClass:
+ case Expr::CXXThisExprClass:
+ case Expr::CXXThrowExprClass:
+ case Expr::CXXConditionDeclExprClass: // FIXME: is this correct?
+ case Expr::CXXNewExprClass:
+ case Expr::CXXDeleteExprClass:
+ case Expr::CXXPseudoDestructorExprClass:
+ case Expr::UnresolvedFunctionNameExprClass:
+ case Expr::UnresolvedDeclRefExprClass:
+ case Expr::TemplateIdRefExprClass:
+ case Expr::CXXConstructExprClass:
+ case Expr::CXXBindTemporaryExprClass:
+ case Expr::CXXExprWithTemporariesClass:
+ case Expr::CXXTemporaryObjectExprClass:
+ case Expr::CXXUnresolvedConstructExprClass:
+ case Expr::CXXUnresolvedMemberExprClass:
+ case Expr::ObjCStringLiteralClass:
+ case Expr::ObjCEncodeExprClass:
+ case Expr::ObjCMessageExprClass:
+ case Expr::ObjCSelectorExprClass:
+ case Expr::ObjCProtocolExprClass:
+ case Expr::ObjCIvarRefExprClass:
+ case Expr::ObjCPropertyRefExprClass:
+ case Expr::ObjCImplicitSetterGetterRefExprClass:
+ case Expr::ObjCSuperExprClass:
+ case Expr::ObjCIsaExprClass:
+ case Expr::ShuffleVectorExprClass:
+ case Expr::BlockExprClass:
+ case Expr::BlockDeclRefExprClass:
+ case Expr::NoStmtClass:
+ case Expr::ExprClass:
return ICEDiag(2, E->getLocStart());
+
+ case Expr::GNUNullExprClass:
+ // GCC considers the GNU __null value to be an integral constant expression.
+ return NoDiag();
+
case Expr::ParenExprClass:
return CheckICE(cast<ParenExpr>(E)->getSubExpr(), Ctx);
case Expr::IntegerLiteralClass:
@@ -1201,7 +1412,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::TypesCompatibleExprClass:
case Expr::UnaryTypeTraitExprClass:
return NoDiag();
- case Expr::CallExprClass:
+ case Expr::CallExprClass:
case Expr::CXXOperatorCallExprClass: {
const CallExpr *CE = cast<CallExpr>(E);
if (CE->isBuiltinCall(Ctx))
@@ -1213,7 +1424,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
if (isa<EnumConstantDecl>(cast<DeclRefExpr>(E)->getDecl()))
return NoDiag();
if (Ctx.getLangOptions().CPlusPlus &&
- E->getType().getCVRQualifiers() == QualType::Const) {
+ E->getType().getCVRQualifiers() == Qualifiers::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.
@@ -1240,8 +1451,14 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::UnaryOperatorClass: {
const UnaryOperator *Exp = cast<UnaryOperator>(E);
switch (Exp->getOpcode()) {
- default:
+ case UnaryOperator::PostInc:
+ case UnaryOperator::PostDec:
+ case UnaryOperator::PreInc:
+ case UnaryOperator::PreDec:
+ case UnaryOperator::AddrOf:
+ case UnaryOperator::Deref:
return ICEDiag(2, E->getLocStart());
+
case UnaryOperator::Extension:
case UnaryOperator::LNot:
case UnaryOperator::Plus:
@@ -1269,8 +1486,21 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::BinaryOperatorClass: {
const BinaryOperator *Exp = cast<BinaryOperator>(E);
switch (Exp->getOpcode()) {
- default:
+ case BinaryOperator::PtrMemD:
+ case BinaryOperator::PtrMemI:
+ case BinaryOperator::Assign:
+ case BinaryOperator::MulAssign:
+ case BinaryOperator::DivAssign:
+ case BinaryOperator::RemAssign:
+ case BinaryOperator::AddAssign:
+ case BinaryOperator::SubAssign:
+ case BinaryOperator::ShlAssign:
+ case BinaryOperator::ShrAssign:
+ case BinaryOperator::AndAssign:
+ case BinaryOperator::XorAssign:
+ case BinaryOperator::OrAssign:
return ICEDiag(2, E->getLocStart());
+
case BinaryOperator::Mul:
case BinaryOperator::Div:
case BinaryOperator::Rem:
@@ -1340,9 +1570,15 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
}
}
}
+ case Expr::CastExprClass:
case Expr::ImplicitCastExprClass:
+ case Expr::ExplicitCastExprClass:
case Expr::CStyleCastExprClass:
- case Expr::CXXFunctionalCastExprClass: {
+ case Expr::CXXFunctionalCastExprClass:
+ case Expr::CXXNamedCastExprClass:
+ case Expr::CXXStaticCastExprClass:
+ case Expr::CXXReinterpretCastExprClass:
+ case Expr::CXXConstCastExprClass: {
const Expr *SubExpr = cast<CastExpr>(E)->getSubExpr();
if (SubExpr->getType()->isIntegralType())
return CheckICE(SubExpr, Ctx);
@@ -1352,7 +1588,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
}
case Expr::ConditionalOperatorClass: {
const ConditionalOperator *Exp = cast<ConditionalOperator>(E);
- // If the condition (ignoring parens) is a __builtin_constant_p call,
+ // 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.
@@ -1392,6 +1628,9 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
return CheckICE(cast<ChooseExpr>(E)->getChosenSubExpr(Ctx), Ctx);
}
}
+
+ // Silence a GCC warning
+ return ICEDiag(2, E->getLocStart());
}
bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx,
@@ -1413,31 +1652,45 @@ bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx,
/// 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
-{
+bool Expr::isNullPointerConstant(ASTContext &Ctx,
+ NullPointerConstantValueDependence NPC) const {
+ if (isValueDependent()) {
+ switch (NPC) {
+ case NPC_NeverValueDependent:
+ assert(false && "Unexpected value dependent expression!");
+ // If the unthinkable happens, fall through to the safest alternative.
+
+ case NPC_ValueDependentIsNull:
+ return isTypeDependent() || getType()->isIntegralType();
+
+ case NPC_ValueDependentIsNotNull:
+ return false;
+ }
+ }
+
// 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()) {
+ if (const PointerType *PT = CE->getType()->getAs<PointerType>()) {
QualType Pointee = PT->getPointeeType();
- if (Pointee.getCVRQualifiers() == 0 &&
+ if (!Pointee.hasQualifiers() &&
Pointee->isVoidType() && // to void*
CE->getSubExpr()->getType()->isIntegerType()) // from int.
- return CE->getSubExpr()->isNullPointerConstant(Ctx);
+ return CE->getSubExpr()->isNullPointerConstant(Ctx, NPC);
}
}
} else if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(this)) {
// Ignore the ImplicitCastExpr type entirely.
- return ICE->getSubExpr()->isNullPointerConstant(Ctx);
+ return ICE->getSubExpr()->isNullPointerConstant(Ctx, NPC);
} 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
+ return PE->getSubExpr()->isNullPointerConstant(Ctx, NPC);
+ } else if (const CXXDefaultArgExpr *DefaultArg
= dyn_cast<CXXDefaultArgExpr>(this)) {
// See through default argument expressions
- return DefaultArg->getExpr()->isNullPointerConstant(Ctx);
+ return DefaultArg->getExpr()->isNullPointerConstant(Ctx, NPC);
} else if (isa<GNUNullExpr>(this)) {
// The GNU __null extension is always a null pointer constant.
return true;
@@ -1448,9 +1701,10 @@ bool Expr::isNullPointerConstant(ASTContext &Ctx) const
return true;
// This expression must be an integer type.
- if (!getType()->isIntegerType())
+ if (!getType()->isIntegerType() ||
+ (Ctx.getLangOptions().CPlusPlus && getType()->isEnumeralType()))
return false;
-
+
// If we have an integer constant expression, we need to *evaluate* it and
// test for the value 0.
llvm::APSInt Result;
@@ -1458,7 +1712,7 @@ bool Expr::isNullPointerConstant(ASTContext &Ctx) const
}
FieldDecl *Expr::getBitField() {
- Expr *E = this->IgnoreParenCasts();
+ Expr *E = this->IgnoreParens();
if (MemberExpr *MemRef = dyn_cast<MemberExpr>(E))
if (FieldDecl *Field = dyn_cast<FieldDecl>(MemRef->getMemberDecl()))
@@ -1479,7 +1733,7 @@ bool ExtVectorElementExpr::isArrow() const {
}
unsigned ExtVectorElementExpr::getNumElements() const {
- if (const VectorType *VT = getType()->getAsVectorType())
+ if (const VectorType *VT = getType()->getAs<VectorType>())
return VT->getNumElements();
return 1;
}
@@ -1490,20 +1744,20 @@ bool ExtVectorElementExpr::containsDuplicateElements() const {
unsigned length = Accessor->getLength();
// Halving swizzles do not contain duplicate elements.
- if (!strcmp(compStr, "hi") || !strcmp(compStr, "lo") ||
+ 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 == '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)
+ if (c == *s)
return true;
}
return false;
@@ -1515,15 +1769,15 @@ void ExtVectorElementExpr::getEncodedElementAccess(
const char *compStr = Accessor->getName();
if (*compStr == 's' || *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)
@@ -1544,7 +1798,7 @@ ObjCMessageExpr::ObjCMessageExpr(Expr *receiver, Selector selInfo,
QualType retType, ObjCMethodDecl *mproto,
SourceLocation LBrac, SourceLocation RBrac,
Expr **ArgExprs, unsigned nargs)
- : Expr(ObjCMessageExprClass, retType), SelName(selInfo),
+ : Expr(ObjCMessageExprClass, retType), SelName(selInfo),
MethodProto(mproto) {
NumArgs = nargs;
SubExprs = new Stmt*[NumArgs+1];
@@ -1557,29 +1811,13 @@ ObjCMessageExpr::ObjCMessageExpr(Expr *receiver, Selector selInfo,
RBracloc = RBrac;
}
-ObjCStringLiteral* ObjCStringLiteral::Clone(ASTContext &C) const {
- // Clone the string literal.
- StringLiteral *NewString =
- String ? cast<StringLiteral>(String)->Clone(C) : 0;
-
- return new (C) ObjCStringLiteral(NewString, getType(), AtLoc);
-}
-
-ObjCSelectorExpr *ObjCSelectorExpr::Clone(ASTContext &C) const {
- return new (C) ObjCSelectorExpr(getType(), SelName, AtLoc, RParenLoc);
-}
-
-ObjCProtocolExpr *ObjCProtocolExpr::Clone(ASTContext &C) const {
- return new (C) ObjCProtocolExpr(getType(), TheProtocol, AtLoc, RParenLoc);
-}
-
-// constructor for class messages.
+// 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),
+ : Expr(ObjCMessageExprClass, retType), SelName(selInfo),
MethodProto(mproto) {
NumArgs = nargs;
SubExprs = new Stmt*[NumArgs+1];
@@ -1592,12 +1830,12 @@ ObjCMessageExpr::ObjCMessageExpr(IdentifierInfo *clsName, Selector selInfo,
RBracloc = RBrac;
}
-// constructor for class messages.
+// 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),
+: Expr(ObjCMessageExprClass, retType), SelName(selInfo),
MethodProto(mproto) {
NumArgs = nargs;
SubExprs = new Stmt*[NumArgs+1];
@@ -1640,16 +1878,23 @@ 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];
+void ShuffleVectorExpr::setExprs(ASTContext &C, Expr ** Exprs,
+ unsigned NumExprs) {
+ if (SubExprs) C.Deallocate(SubExprs);
+
+ SubExprs = new (C) Stmt* [NumExprs];
this->NumExprs = NumExprs;
memcpy(SubExprs, Exprs, sizeof(Expr *) * NumExprs);
}
-void SizeOfAlignOfExpr::Destroy(ASTContext& C) {
+void ShuffleVectorExpr::DoDestroy(ASTContext& C) {
+ DestroyChildren(C);
+ if (SubExprs) C.Deallocate(SubExprs);
+ this->~ShuffleVectorExpr();
+ C.Deallocate(this);
+}
+
+void SizeOfAlignOfExpr::DoDestroy(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
@@ -1660,7 +1905,7 @@ void SizeOfAlignOfExpr::Destroy(ASTContext& C) {
C.Deallocate(this);
}
else
- Expr::Destroy(C);
+ Expr::DoDestroy(C);
}
//===----------------------------------------------------------------------===//
@@ -1675,17 +1920,17 @@ IdentifierInfo *DesignatedInitExpr::Designator::getFieldName() {
return getField()->getIdentifier();
}
-DesignatedInitExpr::DesignatedInitExpr(QualType Ty, unsigned NumDesignators,
+DesignatedInitExpr::DesignatedInitExpr(QualType Ty, unsigned NumDesignators,
const Designator *Designators,
- SourceLocation EqualOrColonLoc,
+ SourceLocation EqualOrColonLoc,
bool GNUSyntax,
- Expr **IndexExprs,
+ Expr **IndexExprs,
unsigned NumIndexExprs,
Expr *Init)
- : Expr(DesignatedInitExprClass, Ty,
+ : Expr(DesignatedInitExprClass, Ty,
Init->isTypeDependent(), Init->isValueDependent()),
- EqualOrColonLoc(EqualOrColonLoc), GNUSyntax(GNUSyntax),
- NumDesignators(NumDesignators), NumSubExprs(NumIndexExprs + 1) {
+ EqualOrColonLoc(EqualOrColonLoc), GNUSyntax(GNUSyntax),
+ NumDesignators(NumDesignators), NumSubExprs(NumIndexExprs + 1) {
this->Designators = new Designator[NumDesignators];
// Record the initializer itself.
@@ -1701,7 +1946,7 @@ DesignatedInitExpr::DesignatedInitExpr(QualType Ty, unsigned NumDesignators,
if (this->Designators[I].isArrayDesignator()) {
// Compute type- and value-dependence.
Expr *Index = IndexExprs[IndexIdx];
- ValueDependent = ValueDependent ||
+ ValueDependent = ValueDependent ||
Index->isTypeDependent() || Index->isValueDependent();
// Copy the index expressions into permanent storage.
@@ -1710,7 +1955,7 @@ DesignatedInitExpr::DesignatedInitExpr(QualType Ty, unsigned NumDesignators,
// Compute type- and value-dependence.
Expr *Start = IndexExprs[IndexIdx];
Expr *End = IndexExprs[IndexIdx + 1];
- ValueDependent = ValueDependent ||
+ ValueDependent = ValueDependent ||
Start->isTypeDependent() || Start->isValueDependent() ||
End->isTypeDependent() || End->isValueDependent();
@@ -1724,7 +1969,7 @@ DesignatedInitExpr::DesignatedInitExpr(QualType Ty, unsigned NumDesignators,
}
DesignatedInitExpr *
-DesignatedInitExpr::Create(ASTContext &C, Designator *Designators,
+DesignatedInitExpr::Create(ASTContext &C, Designator *Designators,
unsigned NumDesignators,
Expr **IndexExprs, unsigned NumIndexExprs,
SourceLocation ColonOrEqualLoc,
@@ -1736,14 +1981,14 @@ DesignatedInitExpr::Create(ASTContext &C, Designator *Designators,
IndexExprs, NumIndexExprs, Init);
}
-DesignatedInitExpr *DesignatedInitExpr::CreateEmpty(ASTContext &C,
+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,
+void DesignatedInitExpr::setDesignators(const Designator *Desigs,
unsigned NumDesigs) {
if (Designators)
delete [] Designators;
@@ -1778,7 +2023,7 @@ Expr *DesignatedInitExpr::getArrayIndex(const Designator& D) {
}
Expr *DesignatedInitExpr::getArrayRangeStart(const Designator& D) {
- assert(D.Kind == Designator::ArrayRangeDesignator &&
+ assert(D.Kind == Designator::ArrayRangeDesignator &&
"Requires array range designator");
char* Ptr = static_cast<char*>(static_cast<void *>(this));
Ptr += sizeof(DesignatedInitExpr);
@@ -1787,7 +2032,7 @@ Expr *DesignatedInitExpr::getArrayRangeStart(const Designator& D) {
}
Expr *DesignatedInitExpr::getArrayRangeEnd(const Designator& D) {
- assert(D.Kind == Designator::ArrayRangeDesignator &&
+ assert(D.Kind == Designator::ArrayRangeDesignator &&
"Requires array range designator");
char* Ptr = static_cast<char*>(static_cast<void *>(this));
Ptr += sizeof(DesignatedInitExpr);
@@ -1797,8 +2042,8 @@ Expr *DesignatedInitExpr::getArrayRangeEnd(const Designator& D) {
/// \brief Replaces the designator at index @p Idx with the series
/// of designators in [First, Last).
-void DesignatedInitExpr::ExpandDesignator(unsigned Idx,
- const Designator *First,
+void DesignatedInitExpr::ExpandDesignator(unsigned Idx,
+ const Designator *First,
const Designator *Last) {
unsigned NumNewDesignators = Last - First;
if (NumNewDesignators == 0) {
@@ -1812,7 +2057,7 @@ void DesignatedInitExpr::ExpandDesignator(unsigned Idx,
return;
}
- Designator *NewDesignators
+ Designator *NewDesignators
= new Designator[NumDesignators - 1 + NumNewDesignators];
std::copy(Designators, Designators + Idx, NewDesignators);
std::copy(First, Last, NewDesignators + Idx);
@@ -1823,13 +2068,29 @@ void DesignatedInitExpr::ExpandDesignator(unsigned Idx,
NumDesignators = NumDesignators - 1 + NumNewDesignators;
}
-void DesignatedInitExpr::Destroy(ASTContext &C) {
+void DesignatedInitExpr::DoDestroy(ASTContext &C) {
delete [] Designators;
- Expr::Destroy(C);
+ Expr::DoDestroy(C);
}
-ImplicitValueInitExpr *ImplicitValueInitExpr::Clone(ASTContext &C) const {
- return new (C) ImplicitValueInitExpr(getType());
+ParenListExpr::ParenListExpr(ASTContext& C, SourceLocation lparenloc,
+ Expr **exprs, unsigned nexprs,
+ SourceLocation rparenloc)
+: Expr(ParenListExprClass, QualType(),
+ hasAnyTypeDependentArguments(exprs, nexprs),
+ hasAnyValueDependentArguments(exprs, nexprs)),
+ NumExprs(nexprs), LParenLoc(lparenloc), RParenLoc(rparenloc) {
+
+ Exprs = new (C) Stmt*[nexprs];
+ for (unsigned i = 0; i != nexprs; ++i)
+ Exprs[i] = exprs[i];
+}
+
+void ParenListExpr::DoDestroy(ASTContext& C) {
+ DestroyChildren(C);
+ if (Exprs) C.Deallocate(Exprs);
+ this->~ParenListExpr();
+ C.Deallocate(this);
}
//===----------------------------------------------------------------------===//
@@ -1861,14 +2122,22 @@ Stmt::child_iterator ObjCIvarRefExpr::child_end() { return &Base+1; }
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; }
+// ObjCImplicitSetterGetterRefExpr
+Stmt::child_iterator ObjCImplicitSetterGetterRefExpr::child_begin() {
+ return &Base;
+}
+Stmt::child_iterator ObjCImplicitSetterGetterRefExpr::child_end() {
+ return &Base+1;
+}
// ObjCSuperExpr
Stmt::child_iterator ObjCSuperExpr::child_begin() { return child_iterator(); }
Stmt::child_iterator ObjCSuperExpr::child_end() { return child_iterator(); }
+// ObjCIsaExpr
+Stmt::child_iterator ObjCIsaExpr::child_begin() { return &Base; }
+Stmt::child_iterator ObjCIsaExpr::child_end() { return &Base+1; }
+
// PredefinedExpr
Stmt::child_iterator PredefinedExpr::child_begin() { return child_iterator(); }
Stmt::child_iterator PredefinedExpr::child_end() { return child_iterator(); }
@@ -1902,7 +2171,7 @@ Stmt::child_iterator UnaryOperator::child_begin() { return &Val; }
Stmt::child_iterator UnaryOperator::child_end() { return &Val+1; }
// SizeOfAlignOfExpr
-Stmt::child_iterator SizeOfAlignOfExpr::child_begin() {
+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?
@@ -2024,16 +2293,24 @@ Stmt::child_iterator DesignatedInitExpr::child_end() {
}
// ImplicitValueInitExpr
-Stmt::child_iterator ImplicitValueInitExpr::child_begin() {
- return child_iterator();
+Stmt::child_iterator ImplicitValueInitExpr::child_begin() {
+ return child_iterator();
}
-Stmt::child_iterator ImplicitValueInitExpr::child_end() {
- return child_iterator();
+Stmt::child_iterator ImplicitValueInitExpr::child_end() {
+ return child_iterator();
+}
+
+// ParenListExpr
+Stmt::child_iterator ParenListExpr::child_begin() {
+ return &Exprs[0];
+}
+Stmt::child_iterator ParenListExpr::child_end() {
+ return &Exprs[0]+NumExprs;
}
// ObjCStringLiteral
-Stmt::child_iterator ObjCStringLiteral::child_begin() {
+Stmt::child_iterator ObjCStringLiteral::child_begin() {
return &String;
}
Stmt::child_iterator ObjCStringLiteral::child_end() {
@@ -2045,7 +2322,7 @@ 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() {
+Stmt::child_iterator ObjCSelectorExpr::child_begin() {
return child_iterator();
}
Stmt::child_iterator ObjCSelectorExpr::child_end() {
@@ -2061,7 +2338,7 @@ Stmt::child_iterator ObjCProtocolExpr::child_end() {
}
// ObjCMessageExpr
-Stmt::child_iterator ObjCMessageExpr::child_begin() {
+Stmt::child_iterator ObjCMessageExpr::child_begin() {
return getReceiver() ? &SubExprs[0] : &SubExprs[0] + ARGS_START;
}
Stmt::child_iterator ObjCMessageExpr::child_end() {
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index 399c302..cba0e22 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -17,14 +17,6 @@
#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
//===----------------------------------------------------------------------===//
@@ -38,7 +30,7 @@ Stmt::child_iterator CXXTypeidExpr::child_end() {
}
// CXXBoolLiteralExpr
-Stmt::child_iterator CXXBoolLiteralExpr::child_begin() {
+Stmt::child_iterator CXXBoolLiteralExpr::child_begin() {
return child_iterator();
}
Stmt::child_iterator CXXBoolLiteralExpr::child_end() {
@@ -46,7 +38,7 @@ Stmt::child_iterator CXXBoolLiteralExpr::child_end() {
}
// CXXNullPtrLiteralExpr
-Stmt::child_iterator CXXNullPtrLiteralExpr::child_begin() {
+Stmt::child_iterator CXXNullPtrLiteralExpr::child_begin() {
return child_iterator();
}
Stmt::child_iterator CXXNullPtrLiteralExpr::child_end() {
@@ -73,7 +65,7 @@ Stmt::child_iterator CXXDefaultArgExpr::child_end() {
}
// CXXZeroInitValueExpr
-Stmt::child_iterator CXXZeroInitValueExpr::child_begin() {
+Stmt::child_iterator CXXZeroInitValueExpr::child_begin() {
return child_iterator();
}
Stmt::child_iterator CXXZeroInitValueExpr::child_end() {
@@ -101,8 +93,7 @@ CXXNewExpr::CXXNewExpr(bool globalNew, FunctionDecl *operatorNew,
Initializer(initializer), Array(arraySize), NumPlacementArgs(numPlaceArgs),
NumConstructorArgs(numConsArgs), OperatorNew(operatorNew),
OperatorDelete(operatorDelete), Constructor(constructor),
- StartLoc(startLoc), EndLoc(endLoc)
-{
+ StartLoc(startLoc), EndLoc(endLoc) {
unsigned TotalSize = Array + NumPlacementArgs + NumConstructorArgs;
SubExprs = new Stmt*[TotalSize];
unsigned i = 0;
@@ -124,19 +115,19 @@ Stmt::child_iterator CXXNewExpr::child_end() {
Stmt::child_iterator CXXDeleteExpr::child_begin() { return &Argument; }
Stmt::child_iterator CXXDeleteExpr::child_end() { return &Argument+1; }
+// CXXPseudoDestructorExpr
+Stmt::child_iterator CXXPseudoDestructorExpr::child_begin() { return &Base; }
+Stmt::child_iterator CXXPseudoDestructorExpr::child_end() {
+ return &Base + 1;
+}
+
// UnresolvedFunctionNameExpr
-Stmt::child_iterator UnresolvedFunctionNameExpr::child_begin() {
- return child_iterator();
+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();
@@ -155,16 +146,16 @@ StmtIterator UnresolvedDeclRefExpr::child_end() {
}
TemplateIdRefExpr::TemplateIdRefExpr(QualType T,
- NestedNameSpecifier *Qualifier,
+ NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
- TemplateName Template,
+ TemplateName Template,
SourceLocation TemplateNameLoc,
- SourceLocation LAngleLoc,
+ SourceLocation LAngleLoc,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs,
SourceLocation RAngleLoc)
: Expr(TemplateIdRefExprClass, T,
- (Template.isDependent() ||
+ (Template.isDependent() ||
TemplateSpecializationType::anyDependentTemplateArguments(
TemplateArgs, NumTemplateArgs)),
(Template.isDependent() ||
@@ -172,10 +163,8 @@ TemplateIdRefExpr::TemplateIdRefExpr(QualType T,
TemplateArgs, NumTemplateArgs))),
Qualifier(Qualifier), QualifierRange(QualifierRange), Template(Template),
TemplateNameLoc(TemplateNameLoc), LAngleLoc(LAngleLoc),
- RAngleLoc(RAngleLoc), NumTemplateArgs(NumTemplateArgs)
-
-{
- TemplateArgument *StoredTemplateArgs
+ RAngleLoc(RAngleLoc), NumTemplateArgs(NumTemplateArgs) {
+ TemplateArgument *StoredTemplateArgs
= reinterpret_cast<TemplateArgument *> (this+1);
for (unsigned I = 0; I != NumTemplateArgs; ++I)
new (StoredTemplateArgs + I) TemplateArgument(TemplateArgs[I]);
@@ -183,10 +172,10 @@ TemplateIdRefExpr::TemplateIdRefExpr(QualType T,
TemplateIdRefExpr *
TemplateIdRefExpr::Create(ASTContext &Context, QualType T,
- NestedNameSpecifier *Qualifier,
+ NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
TemplateName Template, SourceLocation TemplateNameLoc,
- SourceLocation LAngleLoc,
+ SourceLocation LAngleLoc,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs, SourceLocation RAngleLoc) {
void *Mem = Context.Allocate(sizeof(TemplateIdRefExpr) +
@@ -196,11 +185,13 @@ TemplateIdRefExpr::Create(ASTContext &Context, QualType T,
NumTemplateArgs, RAngleLoc);
}
-void TemplateIdRefExpr::Destroy(ASTContext &Context) {
+void TemplateIdRefExpr::DoDestroy(ASTContext &Context) {
const TemplateArgument *TemplateArgs = getTemplateArgs();
for (unsigned I = 0; I != NumTemplateArgs; ++I)
if (Expr *E = TemplateArgs[I].getAsExpr())
E->Destroy(Context);
+ this->~TemplateIdRefExpr();
+ Context.Deallocate(this);
}
Stmt::child_iterator TemplateIdRefExpr::child_begin() {
@@ -213,34 +204,87 @@ Stmt::child_iterator TemplateIdRefExpr::child_end() {
return Stmt::child_iterator();
}
-bool UnaryTypeTraitExpr::EvaluateTrait() const {
+bool UnaryTypeTraitExpr::EvaluateTrait(ASTContext& C) 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()) {
+ if (const RecordType *Record = QueriedType->getAs<RecordType>()) {
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()) {
+ if (const RecordType *Record = QueriedType->getAs<RecordType>()) {
// 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())
+ if (const RecordType *RT = QueriedType->getAs<RecordType>())
return cast<CXXRecordDecl>(RT->getDecl())->isAbstract();
return false;
+ case UTT_IsEmpty:
+ if (const RecordType *Record = QueriedType->getAs<RecordType>()) {
+ return !Record->getDecl()->isUnion()
+ && cast<CXXRecordDecl>(Record->getDecl())->isEmpty();
+ }
+ return false;
case UTT_HasTrivialConstructor:
- if (const RecordType *RT = QueriedType->getAsRecordType())
+ // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
+ // If __is_pod (type) is true then the trait is true, else if type is
+ // a cv class or union type (or array thereof) with a trivial default
+ // constructor ([class.ctor]) then the trait is true, else it is false.
+ if (QueriedType->isPODType())
+ return true;
+ if (const RecordType *RT =
+ C.getBaseElementType(QueriedType)->getAs<RecordType>())
return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialConstructor();
return false;
+ case UTT_HasTrivialCopy:
+ // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
+ // If __is_pod (type) is true or type is a reference type then
+ // the trait is true, else if type is a cv class or union type
+ // with a trivial copy constructor ([class.copy]) then the trait
+ // is true, else it is false.
+ if (QueriedType->isPODType() || QueriedType->isReferenceType())
+ return true;
+ if (const RecordType *RT = QueriedType->getAs<RecordType>())
+ return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialCopyConstructor();
+ return false;
+ case UTT_HasTrivialAssign:
+ // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
+ // If type is const qualified or is a reference type then the
+ // trait is false. Otherwise if __is_pod (type) is true then the
+ // trait is true, else if type is a cv class or union type with
+ // a trivial copy assignment ([class.copy]) then the trait is
+ // true, else it is false.
+ // Note: the const and reference restrictions are interesting,
+ // given that const and reference members don't prevent a class
+ // from having a trivial copy assignment operator (but do cause
+ // errors if the copy assignment operator is actually used, q.v.
+ // [class.copy]p12).
+
+ if (C.getBaseElementType(QueriedType).isConstQualified())
+ return false;
+ if (QueriedType->isPODType())
+ return true;
+ if (const RecordType *RT = QueriedType->getAs<RecordType>())
+ return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialCopyAssignment();
+ return false;
case UTT_HasTrivialDestructor:
- if (const RecordType *RT = QueriedType->getAsRecordType())
+ // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
+ // If __is_pod (type) is true or type is a reference type
+ // then the trait is true, else if type is a cv class or union
+ // type (or array thereof) with a trivial destructor
+ // ([class.dtor]) then the trait is true, else it is
+ // false.
+ if (QueriedType->isPODType() || QueriedType->isReferenceType())
+ return true;
+ if (const RecordType *RT =
+ C.getBaseElementType(QueriedType)->getAs<RecordType>())
return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDestructor();
return false;
}
@@ -251,7 +295,7 @@ SourceRange CXXOperatorCallExpr::getSourceRange() const {
if (Kind == OO_PlusPlus || Kind == OO_MinusMinus) {
if (getNumArgs() == 1)
// Prefix operator
- return SourceRange(getOperatorLoc(),
+ return SourceRange(getOperatorLoc(),
getArg(0)->getSourceRange().getEnd());
else
// Postfix operator
@@ -296,26 +340,26 @@ const char *CXXNamedCastExpr::getCastName() const {
}
}
-CXXTemporary *CXXTemporary::Create(ASTContext &C,
+CXXTemporary *CXXTemporary::Create(ASTContext &C,
const CXXDestructorDecl *Destructor) {
return new (C) CXXTemporary(Destructor);
}
-void CXXTemporary::Destroy(ASTContext &C) {
+void CXXTemporary::Destroy(ASTContext &Ctx) {
this->~CXXTemporary();
- C.Deallocate(this);
+ Ctx.Deallocate(this);
}
-CXXBindTemporaryExpr *CXXBindTemporaryExpr::Create(ASTContext &C,
+CXXBindTemporaryExpr *CXXBindTemporaryExpr::Create(ASTContext &C,
CXXTemporary *Temp,
Expr* SubExpr) {
- assert(SubExpr->getType()->isRecordType() &&
+ assert(SubExpr->getType()->isRecordType() &&
"Expression bound to a temporary must have record type!");
return new (C) CXXBindTemporaryExpr(Temp, SubExpr);
}
-void CXXBindTemporaryExpr::Destroy(ASTContext &C) {
+void CXXBindTemporaryExpr::DoDestroy(ASTContext &C) {
Temp->Destroy(C);
this->~CXXBindTemporaryExpr();
C.Deallocate(this);
@@ -324,38 +368,49 @@ void CXXBindTemporaryExpr::Destroy(ASTContext &C) {
CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C,
CXXConstructorDecl *Cons,
QualType writtenTy,
- SourceLocation tyBeginLoc,
+ SourceLocation tyBeginLoc,
Expr **Args,
- unsigned NumArgs,
+ unsigned NumArgs,
SourceLocation rParenLoc)
- : CXXConstructExpr(C, CXXTemporaryObjectExprClass, writtenTy, Cons,
- false, Args, NumArgs),
+ : CXXConstructExpr(C, CXXTemporaryObjectExprClass, writtenTy, Cons,
+ false, Args, NumArgs),
TyBeginLoc(tyBeginLoc), RParenLoc(rParenLoc) {
}
-CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T,
+CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T,
CXXConstructorDecl *D, bool Elidable,
Expr **Args, unsigned NumArgs) {
- return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, D, Elidable,
+ return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, D, Elidable,
Args, NumArgs);
}
-CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T,
+CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T,
CXXConstructorDecl *D, bool elidable,
- Expr **args, unsigned numargs)
+ 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) {
+ if (NumArgs) {
Args = new (C) Stmt*[NumArgs];
- for (unsigned i = 0; i < NumArgs; ++i)
+
+ for (unsigned i = 0; i != NumArgs; ++i) {
+ assert(args[i] && "NULL argument in CXXConstructExpr");
Args[i] = args[i];
+ }
}
}
-void CXXConstructExpr::Destroy(ASTContext &C) {
+CXXConstructExpr::CXXConstructExpr(EmptyShell Empty, ASTContext &C,
+ unsigned numargs)
+ : Expr(CXXConstructExprClass, Empty), Args(0), NumArgs(numargs)
+{
+ if (NumArgs)
+ Args = new (C) Stmt*[NumArgs];
+}
+
+void CXXConstructExpr::DoDestroy(ASTContext &C) {
DestroyChildren(C);
if (Args)
C.Deallocate(Args);
@@ -363,13 +418,13 @@ void CXXConstructExpr::Destroy(ASTContext &C) {
C.Deallocate(this);
}
-CXXExprWithTemporaries::CXXExprWithTemporaries(Expr *subexpr,
- CXXTemporary **temps,
+CXXExprWithTemporaries::CXXExprWithTemporaries(Expr *subexpr,
+ CXXTemporary **temps,
unsigned numtemps,
bool shoulddestroytemps)
: Expr(CXXExprWithTemporariesClass, subexpr->getType(),
- subexpr->isTypeDependent(), subexpr->isValueDependent()),
- SubExpr(subexpr), Temps(0), NumTemps(numtemps),
+ subexpr->isTypeDependent(), subexpr->isValueDependent()),
+ SubExpr(subexpr), Temps(0), NumTemps(numtemps),
ShouldDestroyTemps(shoulddestroytemps) {
if (NumTemps > 0) {
Temps = new CXXTemporary*[NumTemps];
@@ -378,16 +433,16 @@ CXXExprWithTemporaries::CXXExprWithTemporaries(Expr *subexpr,
}
}
-CXXExprWithTemporaries *CXXExprWithTemporaries::Create(ASTContext &C,
+CXXExprWithTemporaries *CXXExprWithTemporaries::Create(ASTContext &C,
Expr *SubExpr,
- CXXTemporary **Temps,
+ CXXTemporary **Temps,
unsigned NumTemps,
bool ShouldDestroyTemps){
- return new (C) CXXExprWithTemporaries(SubExpr, Temps, NumTemps,
+ return new (C) CXXExprWithTemporaries(SubExpr, Temps, NumTemps,
ShouldDestroyTemps);
}
-void CXXExprWithTemporaries::Destroy(ASTContext &C) {
+void CXXExprWithTemporaries::DoDestroy(ASTContext &C) {
DestroyChildren(C);
this->~CXXExprWithTemporaries();
C.Deallocate(this);
@@ -402,7 +457,7 @@ Stmt::child_iterator CXXBindTemporaryExpr::child_begin() {
return &SubExpr;
}
-Stmt::child_iterator CXXBindTemporaryExpr::child_end() {
+Stmt::child_iterator CXXBindTemporaryExpr::child_end() {
return &SubExpr + 1;
}
@@ -419,7 +474,7 @@ Stmt::child_iterator CXXExprWithTemporaries::child_begin() {
return &SubExpr;
}
-Stmt::child_iterator CXXExprWithTemporaries::child_end() {
+Stmt::child_iterator CXXExprWithTemporaries::child_end() {
return &SubExpr + 1;
}
@@ -442,7 +497,7 @@ CXXUnresolvedConstructExpr::CXXUnresolvedConstructExpr(
}
CXXUnresolvedConstructExpr *
-CXXUnresolvedConstructExpr::Create(ASTContext &C,
+CXXUnresolvedConstructExpr::Create(ASTContext &C,
SourceLocation TyBegin,
QualType T,
SourceLocation LParenLoc,
@@ -463,26 +518,79 @@ 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);
+CXXUnresolvedMemberExpr::CXXUnresolvedMemberExpr(ASTContext &C,
+ Expr *Base, bool IsArrow,
+ SourceLocation OperatorLoc,
+ NestedNameSpecifier *Qualifier,
+ SourceRange QualifierRange,
+ NamedDecl *FirstQualifierFoundInScope,
+ DeclarationName Member,
+ SourceLocation MemberLoc,
+ bool HasExplicitTemplateArgs,
+ SourceLocation LAngleLoc,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ SourceLocation RAngleLoc)
+ : Expr(CXXUnresolvedMemberExprClass, C.DependentTy, true, true),
+ Base(Base), IsArrow(IsArrow),
+ HasExplicitTemplateArgumentList(HasExplicitTemplateArgs),
+ OperatorLoc(OperatorLoc),
+ Qualifier(Qualifier), QualifierRange(QualifierRange),
+ FirstQualifierFoundInScope(FirstQualifierFoundInScope),
+ Member(Member), MemberLoc(MemberLoc) {
+ if (HasExplicitTemplateArgumentList) {
+ ExplicitTemplateArgumentList *ETemplateArgs
+ = getExplicitTemplateArgumentList();
+ ETemplateArgs->LAngleLoc = LAngleLoc;
+ ETemplateArgs->RAngleLoc = RAngleLoc;
+ ETemplateArgs->NumTemplateArgs = NumTemplateArgs;
+
+ TemplateArgument *SavedTemplateArgs = ETemplateArgs->getTemplateArgs();
+ for (unsigned I = 0; I < NumTemplateArgs; ++I)
+ new (SavedTemplateArgs + I) TemplateArgument(TemplateArgs[I]);
+ }
}
-//===----------------------------------------------------------------------===//
-// Cloners
-//===----------------------------------------------------------------------===//
-
-CXXBoolLiteralExpr* CXXBoolLiteralExpr::Clone(ASTContext &C) const {
- return new (C) CXXBoolLiteralExpr(Value, getType(), Loc);
+CXXUnresolvedMemberExpr *
+CXXUnresolvedMemberExpr::Create(ASTContext &C,
+ Expr *Base, bool IsArrow,
+ SourceLocation OperatorLoc,
+ NestedNameSpecifier *Qualifier,
+ SourceRange QualifierRange,
+ NamedDecl *FirstQualifierFoundInScope,
+ DeclarationName Member,
+ SourceLocation MemberLoc,
+ bool HasExplicitTemplateArgs,
+ SourceLocation LAngleLoc,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ SourceLocation RAngleLoc) {
+ if (!HasExplicitTemplateArgs)
+ return new (C) CXXUnresolvedMemberExpr(C, Base, IsArrow, OperatorLoc,
+ Qualifier, QualifierRange,
+ FirstQualifierFoundInScope,
+ Member, MemberLoc);
+
+ void *Mem = C.Allocate(sizeof(CXXUnresolvedMemberExpr) +
+ sizeof(ExplicitTemplateArgumentList) +
+ sizeof(TemplateArgument) * NumTemplateArgs,
+ llvm::alignof<CXXUnresolvedMemberExpr>());
+ return new (Mem) CXXUnresolvedMemberExpr(C, Base, IsArrow, OperatorLoc,
+ Qualifier, QualifierRange,
+ FirstQualifierFoundInScope,
+ Member,
+ MemberLoc,
+ HasExplicitTemplateArgs,
+ LAngleLoc,
+ TemplateArgs,
+ NumTemplateArgs,
+ RAngleLoc);
}
-CXXNullPtrLiteralExpr* CXXNullPtrLiteralExpr::Clone(ASTContext &C) const {
- return new (C) CXXNullPtrLiteralExpr(getType(), Loc);
+Stmt::child_iterator CXXUnresolvedMemberExpr::child_begin() {
+ return child_iterator(&Base);
}
-CXXZeroInitValueExpr* CXXZeroInitValueExpr::Clone(ASTContext &C) const {
- return new (C) CXXZeroInitValueExpr(getType(), TyBeginLoc, RParenLoc);
+Stmt::child_iterator CXXUnresolvedMemberExpr::child_end() {
+ return child_iterator(&Base + 1);
}
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index eb6b5b7..94d2299 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -42,12 +42,16 @@ using llvm::APFloat;
/// 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) {}
+ /// AnyLValue - Stack based LValue results are not discarded.
+ bool AnyLValue;
+
+ EvalInfo(ASTContext &ctx, Expr::EvalResult& evalresult,
+ bool anylvalue = false)
+ : Ctx(ctx), EvalResult(evalresult), AnyLValue(anylvalue) {}
};
@@ -104,12 +108,12 @@ static bool HandleConversionToBool(Expr* E, bool& Result, EvalInfo &Info) {
return false;
}
-static APSInt HandleFloatToIntCast(QualType DestType, QualType SrcType,
+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;
@@ -118,16 +122,16 @@ static APSInt HandleFloatToIntCast(QualType DestType, QualType SrcType,
return APSInt(llvm::APInt(DestWidth, 4, Space), !DestSigned);
}
-static APFloat HandleFloatToFloatCast(QualType DestType, QualType SrcType,
+static APFloat HandleFloatToFloatCast(QualType DestType, QualType SrcType,
APFloat &Value, ASTContext &Ctx) {
bool ignored;
APFloat Result = Value;
- Result.convert(Ctx.getFloatTypeSemantics(DestType),
+ Result.convert(Ctx.getFloatTypeSemantics(DestType),
APFloat::rmNearestTiesToEven, &ignored);
return Result;
}
-static APSInt HandleIntToIntCast(QualType DestType, QualType SrcType,
+static APSInt HandleIntToIntCast(QualType DestType, QualType SrcType,
APSInt &Value, ASTContext &Ctx) {
unsigned DestWidth = Ctx.getIntWidth(DestType);
APSInt Result = Value;
@@ -138,7 +142,7 @@ static APSInt HandleIntToIntCast(QualType DestType, QualType SrcType,
return Result;
}
-static APFloat HandleIntToFloatCast(QualType DestType, QualType SrcType,
+static APFloat HandleIntToFloatCast(QualType DestType, QualType SrcType,
APSInt &Value, ASTContext &Ctx) {
APFloat Result(Ctx.getFloatTypeSemantics(DestType), 1);
@@ -155,7 +159,7 @@ class VISIBILITY_HIDDEN LValueExprEvaluator
: public StmtVisitor<LValueExprEvaluator, APValue> {
EvalInfo &Info;
public:
-
+
LValueExprEvaluator(EvalInfo &info) : Info(info) {}
APValue VisitStmt(Stmt *S) {
@@ -176,6 +180,16 @@ public:
{ return Visit(E->getSubExpr()); }
APValue VisitChooseExpr(const ChooseExpr *E)
{ return Visit(E->getChosenSubExpr(Info.Ctx)); }
+
+ APValue VisitCastExpr(CastExpr *E) {
+ switch (E->getCastKind()) {
+ default:
+ return APValue();
+
+ case CastExpr::CK_NoOp:
+ return Visit(E->getSubExpr());
+ }
+ }
// FIXME: Missing: __real__, __imag__
};
} // end anonymous namespace
@@ -185,16 +199,15 @@ static bool EvaluateLValue(const Expr* E, APValue& Result, EvalInfo &Info) {
return Result.isLValue();
}
-APValue LValueExprEvaluator::VisitDeclRefExpr(DeclRefExpr *E)
-{
- if (!E->hasGlobalStorage())
- return APValue();
-
+APValue LValueExprEvaluator::VisitDeclRefExpr(DeclRefExpr *E) {
if (isa<FunctionDecl>(E->getDecl())) {
return APValue(E, 0);
} else if (VarDecl* VD = dyn_cast<VarDecl>(E->getDecl())) {
+ if (!Info.AnyLValue && !VD->hasGlobalStorage())
+ return APValue();
if (!VD->getType()->isReferenceType())
return APValue(E, 0);
+ // FIXME: Check whether VD might be overridden!
if (VD->getInit())
return Visit(VD->getInit());
}
@@ -202,18 +215,17 @@ APValue LValueExprEvaluator::VisitDeclRefExpr(DeclRefExpr *E)
return APValue();
}
-APValue LValueExprEvaluator::VisitBlockExpr(BlockExpr *E)
-{
+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();
+ if (!Info.AnyLValue && !E->isFileScope())
+ return APValue();
+ return APValue(E, 0);
}
APValue LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) {
@@ -222,7 +234,7 @@ APValue LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) {
if (E->isArrow()) {
if (!EvaluatePointer(E->getBase(), result, Info))
return APValue();
- Ty = E->getBase()->getType()->getAsPointerType()->getPointeeType();
+ Ty = E->getBase()->getType()->getAs<PointerType>()->getPointeeType();
} else {
result = Visit(E->getBase());
if (result.isUninit())
@@ -230,7 +242,7 @@ APValue LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) {
Ty = E->getBase()->getType();
}
- RecordDecl *RD = Ty->getAsRecordType()->getDecl();
+ RecordDecl *RD = Ty->getAs<RecordType>()->getDecl();
const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD);
FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl());
@@ -255,13 +267,12 @@ APValue LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) {
return result;
}
-APValue LValueExprEvaluator::VisitArraySubscriptExpr(ArraySubscriptExpr *E)
-{
+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();
@@ -269,13 +280,12 @@ APValue LValueExprEvaluator::VisitArraySubscriptExpr(ArraySubscriptExpr *E)
uint64_t ElementSize = Info.Ctx.getTypeSize(E->getType()) / 8;
uint64_t Offset = Index.getSExtValue() * ElementSize;
- Result.setLValue(Result.getLValueBase(),
+ Result.setLValue(Result.getLValueBase(),
Result.getLValueOffset() + Offset);
return Result;
}
-APValue LValueExprEvaluator::VisitUnaryDeref(UnaryOperator *E)
-{
+APValue LValueExprEvaluator::VisitUnaryDeref(UnaryOperator *E) {
APValue Result;
if (!EvaluatePointer(E->getSubExpr(), Result, Info))
return APValue();
@@ -291,7 +301,7 @@ class VISIBILITY_HIDDEN PointerExprEvaluator
: public StmtVisitor<PointerExprEvaluator, APValue> {
EvalInfo &Info;
public:
-
+
PointerExprEvaluator(EvalInfo &info) : Info(info) {}
APValue VisitStmt(Stmt *S) {
@@ -337,23 +347,23 @@ 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();
+ QualType PointeeType = PExp->getType()->getAs<PointerType>()->getPointeeType();
uint64_t SizeOfPointee;
-
+
// Explicitly handle GNU void* and function pointer arithmetic extensions.
if (PointeeType->isVoidType() || PointeeType->isFunctionType())
SizeOfPointee = 1;
@@ -376,19 +386,21 @@ APValue PointerExprEvaluator::VisitUnaryAddrOf(const UnaryOperator *E) {
return result;
return APValue();
}
-
+
APValue PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
const Expr* SubExpr = E->getSubExpr();
// Check for pointer->pointer cast
- if (SubExpr->getType()->isPointerType()) {
+ if (SubExpr->getType()->isPointerType() ||
+ SubExpr->getType()->isObjCObjectPointerType() ||
+ SubExpr->getType()->isNullPtrType()) {
APValue Result;
if (EvaluatePointer(SubExpr, Result, Info))
return Result;
return APValue();
}
-
+
if (SubExpr->getType()->isIntegralType()) {
APValue Result;
if (!EvaluateIntegerOrLValue(SubExpr, Result, Info))
@@ -398,7 +410,7 @@ APValue PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
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;
}
@@ -413,10 +425,10 @@ APValue PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
}
return APValue();
-}
+}
APValue PointerExprEvaluator::VisitCallExpr(CallExpr *E) {
- if (E->isBuiltinCall(Info.Ctx) ==
+ if (E->isBuiltinCall(Info.Ctx) ==
Builtin::BI__builtin___CFStringMakeConstantString)
return APValue(E, 0);
return APValue();
@@ -445,13 +457,13 @@ namespace {
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)
@@ -485,11 +497,11 @@ static bool EvaluateVector(const Expr* E, APValue& Result, EvalInfo &Info) {
}
APValue VectorExprEvaluator::VisitCastExpr(const CastExpr* E) {
- const VectorType *VTy = E->getType()->getAsVectorType();
+ const VectorType *VTy = E->getType()->getAs<VectorType>();
QualType EltTy = VTy->getElementType();
unsigned NElts = VTy->getNumElements();
unsigned EltWidth = Info.Ctx.getTypeSize(EltTy);
-
+
const Expr* SE = E->getSubExpr();
QualType SETy = SE->getType();
APValue Result = APValue();
@@ -539,12 +551,12 @@ APValue VectorExprEvaluator::VisitCastExpr(const CastExpr* E) {
// element.
APSInt Init;
Init = Result.isInt() ? Result.getInt() : Result.getFloat().bitcastToAPInt();
-
+
llvm::SmallVector<APValue, 4> Elts;
for (unsigned i = 0; i != NElts; ++i) {
APSInt Tmp = Init;
Tmp.extOrTrunc(EltWidth);
-
+
if (EltTy->isIntegerType())
Elts.push_back(APValue(Tmp));
else if (EltTy->isRealFloatingType())
@@ -557,17 +569,17 @@ APValue VectorExprEvaluator::VisitCastExpr(const CastExpr* E) {
return APValue(&Elts[0], Elts.size());
}
-APValue
+APValue
VectorExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
return this->Visit(const_cast<Expr*>(E->getInitializer()));
}
-APValue
+APValue
VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
- const VectorType *VT = E->getType()->getAsVectorType();
+ const VectorType *VT = E->getType()->getAs<VectorType>();
unsigned NumInits = E->getNumInits();
unsigned NumElements = VT->getNumElements();
-
+
QualType EltTy = VT->getElementType();
llvm::SmallVector<APValue, 4> Elements;
@@ -595,9 +607,9 @@ VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
return APValue(&Elements[0], Elements.size());
}
-APValue
+APValue
VectorExprEvaluator::GetZeroVector(QualType T) {
- const VectorType *VT = T->getAsVectorType();
+ const VectorType *VT = T->getAs<VectorType>();
QualType EltTy = VT->getElementType();
APValue ZeroElement;
if (EltTy->isIntegerType())
@@ -676,20 +688,20 @@ public:
}
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) {
@@ -704,7 +716,7 @@ public:
// 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(),
+ return Success(Info.Ctx.typesAreCompatible(T0.getUnqualifiedType(),
T1.getUnqualifiedType()),
E);
}
@@ -720,11 +732,11 @@ public:
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);
}
@@ -734,7 +746,7 @@ public:
}
bool VisitUnaryTypeTraitExpr(const UnaryTypeTraitExpr *E) {
- return Success(E->EvaluateTrait(), E);
+ return Success(E->EvaluateTrait(Info.Ctx), E);
}
bool VisitChooseExpr(const ChooseExpr *E) {
@@ -754,7 +766,7 @@ private:
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));
}
@@ -781,7 +793,7 @@ bool IntExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *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 (E->getType().getCVRQualifiers() == Qualifiers::Const) {
if (const VarDecl *D = dyn_cast<VarDecl>(E->getDecl())) {
if (APValue *V = D->getEvaluatedValue())
return Success(V->getInt(), E);
@@ -817,12 +829,12 @@ static int EvaluateBuiltinClassifyType(const CallExpr *E) {
array_type_class, string_type_class,
lang_type_class
};
-
- // If no argument was supplied, default to "no_type_class". This isn't
+
+ // 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;
@@ -863,11 +875,17 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
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);
+
+ case Builtin::BI__builtin_eh_return_data_regno: {
+ int Operand = E->getArg(0)->EvaluateAsInt(Info.Ctx).getZExtValue();
+ Operand = Info.Ctx.Target.getEHDataRegisterNumber(Operand);
+ return Success(Operand, E);
+ }
}
}
@@ -888,7 +906,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
// 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
@@ -905,7 +923,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
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) ||
+ 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.
@@ -933,9 +951,9 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
return false;
if (LHS.isComplexFloat()) {
- APFloat::cmpResult CR_r =
+ APFloat::cmpResult CR_r =
LHS.getComplexFloatReal().compare(RHS.getComplexFloatReal());
- APFloat::cmpResult CR_i =
+ APFloat::cmpResult CR_i =
LHS.getComplexFloatImag().compare(RHS.getComplexFloatImag());
if (E->getOpcode() == BinaryOperator::EQ)
@@ -944,9 +962,9 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
else {
assert(E->getOpcode() == BinaryOperator::NE &&
"Invalid complex comparison.");
- return Success(((CR_r == APFloat::cmpGreaterThan ||
+ return Success(((CR_r == APFloat::cmpGreaterThan ||
CR_r == APFloat::cmpLessThan) &&
- (CR_i == APFloat::cmpGreaterThan ||
+ (CR_i == APFloat::cmpGreaterThan ||
CR_i == APFloat::cmpLessThan)), E);
}
} else {
@@ -961,17 +979,17 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *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()) {
@@ -984,16 +1002,16 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
case BinaryOperator::LE:
return Success(CR == APFloat::cmpLessThan || CR == APFloat::cmpEqual, E);
case BinaryOperator::GE:
- return Success(CR == APFloat::cmpGreaterThan || CR == APFloat::cmpEqual,
+ 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
+ return Success(CR == APFloat::cmpGreaterThan
|| CR == APFloat::cmpLessThan, E);
}
}
-
+
if (LHSTy->isPointerType() && RHSTy->isPointerType()) {
if (E->getOpcode() == BinaryOperator::Sub || E->isEqualityOp()) {
APValue LHSValue;
@@ -1028,7 +1046,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
if (E->getOpcode() == BinaryOperator::Sub) {
const QualType Type = E->getLHS()->getType();
- const QualType ElementType = Type->getAsPointerType()->getPointeeType();
+ const QualType ElementType = Type->getAs<PointerType>()->getPointeeType();
uint64_t D = LHSValue.getLValueOffset() - RHSValue.getLValueOffset();
if (!ElementType->isVoidType() && !ElementType->isFunctionType())
@@ -1105,16 +1123,16 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
return Success(Result.getInt() % RHS, E);
case BinaryOperator::Shl: {
// FIXME: Warn about out of range shift amounts!
- unsigned SA =
+ unsigned SA =
(unsigned) RHS.getLimitedValue(Result.getInt().getBitWidth()-1);
return Success(Result.getInt() << SA, E);
}
case BinaryOperator::Shr: {
- unsigned SA =
+ 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);
@@ -1144,7 +1162,7 @@ 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.
+ // to 1 in those cases.
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
return Info.Ctx.getDeclAlignInBytes(DRE->getDecl());
@@ -1224,7 +1242,7 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
// If so, we could clear the diagnostic ID.
return true;
case UnaryOperator::Plus:
- // The result is always just the subexpr.
+ // The result is always just the subexpr.
return true;
case UnaryOperator::Minus:
if (!Result.isInt()) return false;
@@ -1234,7 +1252,7 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
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) {
@@ -1262,7 +1280,7 @@ bool IntExprEvaluator::VisitCastExpr(CastExpr *E) {
return Success(HandleIntToIntCast(DestType, SrcType,
Result.getInt(), Info.Ctx), E);
}
-
+
// FIXME: Clean this up!
if (SrcType->isPointerType()) {
APValue LV;
@@ -1316,7 +1334,7 @@ bool IntExprEvaluator::VisitCastExpr(CastExpr *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);
}
@@ -1399,13 +1417,13 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
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 =
+ if (const StringLiteral *S =
dyn_cast<StringLiteral>(E->getArg(0)->IgnoreParenCasts())) {
if (!S->isWide()) {
const llvm::fltSemantics &Sem =
@@ -1430,13 +1448,13 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
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_copysign:
+ case Builtin::BI__builtin_copysignf:
case Builtin::BI__builtin_copysignl: {
APFloat RHS(0.);
if (!EvaluateFloat(E->getArg(0), Result, Info) ||
@@ -1457,7 +1475,7 @@ bool FloatExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
switch (E->getOpcode()) {
default: return false;
- case UnaryOperator::Plus:
+ case UnaryOperator::Plus:
return true;
case UnaryOperator::Minus:
Result.changeSign();
@@ -1498,12 +1516,12 @@ bool FloatExprEvaluator::VisitFloatingLiteral(const FloatingLiteral *E) {
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(),
+ Result = HandleIntToFloatCast(E->getType(), SubExpr->getType(),
IntResult, Info.Ctx);
return true;
}
@@ -1532,10 +1550,10 @@ namespace {
class VISIBILITY_HIDDEN ComplexExprEvaluator
: public StmtVisitor<ComplexExprEvaluator, APValue> {
EvalInfo &Info;
-
+
public:
ComplexExprEvaluator(EvalInfo &info) : Info(info) {}
-
+
//===--------------------------------------------------------------------===//
// Visitor Methods
//===--------------------------------------------------------------------===//
@@ -1543,7 +1561,7 @@ public:
APValue VisitStmt(Stmt *S) {
return APValue();
}
-
+
APValue VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
APValue VisitImaginaryLiteral(ImaginaryLiteral *E) {
@@ -1554,17 +1572,17 @@ public:
if (!EvaluateFloat(SubExpr, Result, Info))
return APValue();
-
- return APValue(APFloat(Result.getSemantics(), APFloat::fcZero, false),
+
+ return APValue(APFloat(Result.getSemantics(), APFloat::fcZero, false),
Result);
} else {
- assert(SubExpr->getType()->isIntegerType() &&
+ 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);
@@ -1573,7 +1591,7 @@ public:
APValue VisitCastExpr(CastExpr *E) {
Expr* SubExpr = E->getSubExpr();
- QualType EltType = E->getType()->getAsComplexType()->getElementType();
+ QualType EltType = E->getType()->getAs<ComplexType>()->getElementType();
QualType SubType = SubExpr->getType();
if (SubType->isRealFloatingType()) {
@@ -1584,7 +1602,7 @@ public:
if (EltType->isRealFloatingType()) {
Result = HandleFloatToFloatCast(EltType, SubType, Result, Info.Ctx);
- return APValue(Result,
+ return APValue(Result,
APFloat(Result.getSemantics(), APFloat::fcZero, false));
} else {
llvm::APSInt IResult;
@@ -1602,7 +1620,7 @@ public:
if (EltType->isRealFloatingType()) {
APFloat FResult =
HandleIntToFloatCast(EltType, SubType, Result, Info.Ctx);
- return APValue(FResult,
+ return APValue(FResult,
APFloat(FResult.getSemantics(), APFloat::fcZero, false));
} else {
Result = HandleIntToIntCast(EltType, SubType, Result, Info.Ctx);
@@ -1610,7 +1628,7 @@ public:
Zero = 0;
return APValue(Result, Zero);
}
- } else if (const ComplexType *CT = SubType->getAsComplexType()) {
+ } else if (const ComplexType *CT = SubType->getAs<ComplexType>()) {
APValue Src;
if (!EvaluateComplex(SubExpr, Src, Info))
@@ -1620,36 +1638,36 @@ public:
if (Src.isComplexFloat()) {
if (EltType->isRealFloatingType()) {
- return APValue(HandleFloatToFloatCast(EltType, SrcType,
+ return APValue(HandleFloatToFloatCast(EltType, SrcType,
Src.getComplexFloatReal(),
Info.Ctx),
- HandleFloatToFloatCast(EltType, SrcType,
+ HandleFloatToFloatCast(EltType, SrcType,
Src.getComplexFloatImag(),
Info.Ctx));
} else {
return APValue(HandleFloatToIntCast(EltType, SrcType,
Src.getComplexFloatReal(),
Info.Ctx),
- HandleFloatToIntCast(EltType, SrcType,
+ HandleFloatToIntCast(EltType, SrcType,
Src.getComplexFloatImag(),
- Info.Ctx));
+ Info.Ctx));
}
} else {
assert(Src.isComplexInt() && "Invalid evaluate result.");
if (EltType->isRealFloatingType()) {
- return APValue(HandleIntToFloatCast(EltType, SrcType,
+ return APValue(HandleIntToFloatCast(EltType, SrcType,
Src.getComplexIntReal(),
Info.Ctx),
- HandleIntToFloatCast(EltType, SrcType,
+ HandleIntToFloatCast(EltType, SrcType,
Src.getComplexIntImag(),
Info.Ctx));
} else {
return APValue(HandleIntToIntCast(EltType, SrcType,
Src.getComplexIntReal(),
Info.Ctx),
- HandleIntToIntCast(EltType, SrcType,
+ HandleIntToIntCast(EltType, SrcType,
Src.getComplexIntImag(),
- Info.Ctx));
+ Info.Ctx));
}
}
}
@@ -1657,7 +1675,7 @@ public:
// FIXME: Handle more casts.
return APValue();
}
-
+
APValue VisitBinaryOperator(const BinaryOperator *E);
APValue VisitChooseExpr(const ChooseExpr *E)
{ return Visit(E->getChosenSubExpr(Info.Ctx)); }
@@ -1668,23 +1686,21 @@ public:
};
} // end anonymous namespace
-static bool EvaluateComplex(const Expr *E, APValue &Result, EvalInfo &Info)
-{
+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())) &&
+ (&Result.getComplexFloatReal().getSemantics() ==
+ &Result.getComplexFloatImag().getSemantics())) &&
"Invalid complex evaluation.");
return Result.isComplexFloat() || Result.isComplexInt();
}
-APValue ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E)
-{
+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();
@@ -1721,7 +1737,7 @@ APValue ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E)
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;
@@ -1737,10 +1753,10 @@ APValue ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E)
Result.getComplexFloatImag().add(Tmp, APFloat::rmNearestTiesToEven);
} else {
APValue LHS = Result;
- Result.getComplexIntReal() =
+ Result.getComplexIntReal() =
(LHS.getComplexIntReal() * RHS.getComplexIntReal() -
LHS.getComplexIntImag() * RHS.getComplexIntImag());
- Result.getComplexIntImag() =
+ Result.getComplexIntImag() =
(LHS.getComplexIntReal() * RHS.getComplexIntImag() +
LHS.getComplexIntImag() * RHS.getComplexIntReal());
}
@@ -1774,7 +1790,7 @@ bool Expr::Evaluate(EvalResult &Result, ASTContext &Ctx) const {
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))
@@ -1791,6 +1807,12 @@ bool Expr::EvaluateAsLValue(EvalResult &Result, ASTContext &Ctx) const {
return EvaluateLValue(this, Result.Val, Info) && !Result.HasSideEffects;
}
+bool Expr::EvaluateAsAnyLValue(EvalResult &Result, ASTContext &Ctx) const {
+ EvalInfo Info(Ctx, Result, true);
+
+ 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 {
diff --git a/lib/AST/InheritViz.cpp b/lib/AST/InheritViz.cpp
index dd2fc14..c47a9da 100644
--- a/lib/AST/InheritViz.cpp
+++ b/lib/AST/InheritViz.cpp
@@ -89,8 +89,8 @@ void InheritanceHierarchyWriter::WriteNode(QualType Type, bool FromVirtual) {
Out << " \"];\n";
// Display the base classes.
- const CXXRecordDecl *Decl
- = static_cast<const CXXRecordDecl *>(Type->getAsRecordType()->getDecl());
+ const CXXRecordDecl *Decl
+ = static_cast<const CXXRecordDecl *>(Type->getAs<RecordType>()->getDecl());
for (CXXRecordDecl::base_class_const_iterator Base = Decl->bases_begin();
Base != Decl->bases_end(); ++Base) {
QualType CanonBaseType = Context.getCanonicalType(Base->getType());
@@ -120,8 +120,8 @@ void InheritanceHierarchyWriter::WriteNode(QualType Type, bool FromVirtual) {
/// WriteNodeReference - Write out a reference to the given node,
/// using a unique identifier for each direct base and for the
/// (only) virtual base.
-llvm::raw_ostream&
-InheritanceHierarchyWriter::WriteNodeReference(QualType Type,
+llvm::raw_ostream&
+InheritanceHierarchyWriter::WriteNodeReference(QualType Type,
bool FromVirtual) {
QualType CanonType = Context.getCanonicalType(Type);
@@ -149,7 +149,7 @@ void CXXRecordDecl::viewInheritance(ASTContext& Context) const {
llvm::errs() << "Writing '" << Filename.c_str() << "'... ";
- llvm::raw_fd_ostream O(Filename.c_str(), false, ErrMsg);
+ llvm::raw_fd_ostream O(Filename.c_str(), ErrMsg);
if (ErrMsg.empty()) {
InheritanceHierarchyWriter Writer(Context, O);
diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp
index 90ec4d3..d969776 100644
--- a/lib/AST/NestedNameSpecifier.cpp
+++ b/lib/AST/NestedNameSpecifier.cpp
@@ -22,13 +22,13 @@
using namespace clang;
NestedNameSpecifier *
-NestedNameSpecifier::FindOrInsert(ASTContext &Context,
+NestedNameSpecifier::FindOrInsert(ASTContext &Context,
const NestedNameSpecifier &Mockup) {
llvm::FoldingSetNodeID ID;
Mockup.Profile(ID);
void *InsertPos = 0;
- NestedNameSpecifier *NNS
+ NestedNameSpecifier *NNS
= Context.NestedNameSpecifiers.FindNodeOrInsertPos(ID, InsertPos);
if (!NNS) {
NNS = new (Context, 4) NestedNameSpecifier(Mockup);
@@ -39,10 +39,10 @@ NestedNameSpecifier::FindOrInsert(ASTContext &Context,
}
NestedNameSpecifier *
-NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix,
+NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix,
IdentifierInfo *II) {
assert(II && "Identifier cannot be NULL");
- assert(Prefix && Prefix->isDependent() && "Prefix must be dependent");
+ assert((!Prefix || Prefix->isDependent()) && "Prefix must be dependent");
NestedNameSpecifier Mockup;
Mockup.Prefix.setPointer(Prefix);
@@ -52,10 +52,10 @@ NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix,
}
NestedNameSpecifier *
-NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix,
+NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix,
NamespaceDecl *NS) {
assert(NS && "Namespace cannot be NULL");
- assert((!Prefix ||
+ assert((!Prefix ||
(Prefix->getAsType() == 0 && Prefix->getAsIdentifier() == 0)) &&
"Broken nested name specifier");
NestedNameSpecifier Mockup;
@@ -75,7 +75,17 @@ NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix,
Mockup.Specifier = T;
return FindOrInsert(Context, Mockup);
}
-
+
+NestedNameSpecifier *
+NestedNameSpecifier::Create(ASTContext &Context, IdentifierInfo *II) {
+ assert(II && "Identifier cannot be NULL");
+ NestedNameSpecifier Mockup;
+ Mockup.Prefix.setPointer(0);
+ Mockup.Prefix.setInt(Identifier);
+ Mockup.Specifier = II;
+ return FindOrInsert(Context, Mockup);
+}
+
NestedNameSpecifier *NestedNameSpecifier::GlobalSpecifier(ASTContext &Context) {
if (!Context.GlobalNestedNameSpecifier)
Context.GlobalNestedNameSpecifier = new (Context, 4) NestedNameSpecifier();
@@ -105,8 +115,8 @@ bool NestedNameSpecifier::isDependent() const {
/// \brief Print this nested name specifier to the given output
/// stream.
-void
-NestedNameSpecifier::print(llvm::raw_ostream &OS,
+void
+NestedNameSpecifier::print(llvm::raw_ostream &OS,
const PrintingPolicy &Policy) const {
if (getPrefix())
getPrefix()->print(OS, Policy);
@@ -131,15 +141,34 @@ NestedNameSpecifier::print(llvm::raw_ostream &OS,
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);
+ InnerPolicy.SuppressScope = true;
+
+ // Nested-name-specifiers are intended to contain minimally-qualified
+ // types. An actual QualifiedNameType will not occur, since we'll store
+ // just the type that is referred to in the nested-name-specifier (e.g.,
+ // a TypedefType, TagType, etc.). However, when we are dealing with
+ // dependent template-id types (e.g., Outer<T>::template Inner<U>),
+ // the type requires its own nested-name-specifier for uniqueness, so we
+ // suppress that nested-name-specifier during printing.
+ assert(!isa<QualifiedNameType>(T) &&
+ "Qualified name type in nested-name-specifier");
+ if (const TemplateSpecializationType *SpecType
+ = dyn_cast<TemplateSpecializationType>(T)) {
+ // Print the template name without its corresponding
+ // nested-name-specifier.
+ SpecType->getTemplateName().print(OS, InnerPolicy, true);
+
+ // Print the template argument list.
+ TypeStr = TemplateSpecializationType::PrintTemplateArgumentList(
+ SpecType->getArgs(),
+ SpecType->getNumArgs(),
+ InnerPolicy);
+ } else {
+ // Print the type normally
+ T->getAsStringInternal(TypeStr, InnerPolicy);
+ }
OS << TypeStr;
break;
}
diff --git a/lib/AST/ParentMap.cpp b/lib/AST/ParentMap.cpp
index 9d87daa..48251d5 100644
--- a/lib/AST/ParentMap.cpp
+++ b/lib/AST/ParentMap.cpp
@@ -32,7 +32,7 @@ ParentMap::ParentMap(Stmt* S) : Impl(0) {
if (S) {
MapTy *M = new MapTy();
BuildParentMap(*M, S);
- Impl = M;
+ Impl = M;
}
}
@@ -54,16 +54,16 @@ Stmt *ParentMap::getParentIgnoreParens(Stmt *S) const {
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);
@@ -78,7 +78,7 @@ bool ParentMap::isConsumedExpr(Expr* E) const {
case Stmt::ForStmtClass:
return DirectChild == cast<ForStmt>(P)->getCond();
case Stmt::WhileStmtClass:
- return DirectChild == cast<WhileStmt>(P)->getCond();
+ return DirectChild == cast<WhileStmt>(P)->getCond();
case Stmt::DoStmtClass:
return DirectChild == cast<DoStmt>(P)->getCond();
case Stmt::IfStmtClass:
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
new file mode 100644
index 0000000..c79cc3c
--- /dev/null
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -0,0 +1,674 @@
+//=== ASTRecordLayoutBuilder.cpp - Helper class for building record layouts ==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RecordLayoutBuilder.h"
+
+#include "clang/AST/Attr.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/Basic/TargetInfo.h"
+#include <llvm/ADT/SmallSet.h>
+#include <llvm/Support/MathExtras.h>
+
+using namespace clang;
+
+ASTRecordLayoutBuilder::ASTRecordLayoutBuilder(ASTContext &Ctx)
+ : Ctx(Ctx), Size(0), Alignment(8), Packed(false), MaxFieldAlignment(0),
+ DataSize(0), IsUnion(false), NonVirtualSize(0), NonVirtualAlignment(8),
+ PrimaryBase(0), PrimaryBaseWasVirtual(false) {}
+
+/// LayoutVtable - Lay out the vtable and set PrimaryBase.
+void ASTRecordLayoutBuilder::LayoutVtable(const CXXRecordDecl *RD) {
+ if (!RD->isDynamicClass()) {
+ // There is no primary base in this case.
+ return;
+ }
+
+ SelectPrimaryBase(RD);
+ if (PrimaryBase == 0) {
+ int AS = 0;
+ UpdateAlignment(Ctx.Target.getPointerAlign(AS));
+ Size += Ctx.Target.getPointerWidth(AS);
+ DataSize = Size;
+ }
+}
+
+void
+ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
+ for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
+ e = RD->bases_end(); i != e; ++i) {
+ if (!i->isVirtual()) {
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+ // Skip the PrimaryBase here, as it is laid down first.
+ if (Base != PrimaryBase || PrimaryBaseWasVirtual)
+ LayoutBaseNonVirtually(Base, false);
+ }
+ }
+}
+
+// Helper routines related to the abi definition from:
+// http://www.codesourcery.com/public/cxx-abi/abi.html
+//
+/// IsNearlyEmpty - Indicates when a class has a vtable pointer, but
+/// no other data.
+bool ASTRecordLayoutBuilder::IsNearlyEmpty(const CXXRecordDecl *RD) const {
+ // FIXME: Audit the corners
+ if (!RD->isDynamicClass())
+ return false;
+ const ASTRecordLayout &BaseInfo = Ctx.getASTRecordLayout(RD);
+ if (BaseInfo.getNonVirtualSize() == Ctx.Target.getPointerWidth(0))
+ return true;
+ return false;
+}
+
+void ASTRecordLayoutBuilder::IdentifyPrimaryBases(const CXXRecordDecl *RD) {
+ const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
+
+ // If the record has a primary base class that is virtual, add it to the set
+ // of primary bases.
+ if (Layout.getPrimaryBaseWasVirtual())
+ IndirectPrimaryBases.insert(Layout.getPrimaryBase());
+
+ // Now traverse all bases and find primary bases for them.
+ for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
+ e = RD->bases_end(); i != e; ++i) {
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+
+ // Only bases with virtual bases participate in computing the
+ // indirect primary virtual base classes.
+ if (Base->getNumVBases())
+ IdentifyPrimaryBases(Base);
+ }
+}
+
+void
+ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD,
+ const CXXRecordDecl *&FirstPrimary) {
+ for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
+ e = RD->bases_end(); i != e; ++i) {
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+ if (!i->isVirtual()) {
+ SelectPrimaryVBase(Base, FirstPrimary);
+ if (PrimaryBase)
+ return;
+ continue;
+ }
+ if (IsNearlyEmpty(Base)) {
+ if (FirstPrimary==0)
+ FirstPrimary = Base;
+ if (!IndirectPrimaryBases.count(Base)) {
+ setPrimaryBase(Base, true);
+ return;
+ }
+ }
+ }
+}
+
+/// SelectPrimaryBase - Selects the primary base for the given class and
+/// record that with setPrimaryBase. We also calculate the IndirectPrimaries.
+void ASTRecordLayoutBuilder::SelectPrimaryBase(const CXXRecordDecl *RD) {
+ // Compute all the primary virtual bases for all of our direct and
+ // indirect bases, and record all their primary virtual base classes.
+ for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
+ e = RD->bases_end(); i != e; ++i) {
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+ IdentifyPrimaryBases(Base);
+ }
+
+ // If the record has a dynamic base class, attempt to choose a primary base
+ // class. It is the first (in direct base class order) non-virtual dynamic
+ // base class, if one exists.
+ for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
+ e = RD->bases_end(); i != e; ++i) {
+ if (!i->isVirtual()) {
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+ if (Base->isDynamicClass()) {
+ // We found it.
+ setPrimaryBase(Base, false);
+ return;
+ }
+ }
+ }
+
+ // Otherwise, it is the first nearly empty virtual base that is not an
+ // indirect primary virtual base class, if one exists.
+
+ // If we have no virtual bases at this point, bail out as the searching below
+ // is expensive.
+ if (RD->getNumVBases() == 0)
+ return;
+
+ // Then we can search for the first nearly empty virtual base itself.
+ const CXXRecordDecl *FirstPrimary = 0;
+ SelectPrimaryVBase(RD, FirstPrimary);
+
+ // Otherwise if is the first nearly empty virtual base, if one exists,
+ // otherwise there is no primary base class.
+ if (!PrimaryBase)
+ setPrimaryBase(FirstPrimary, true);
+}
+
+void ASTRecordLayoutBuilder::LayoutVirtualBase(const CXXRecordDecl *RD) {
+ LayoutBaseNonVirtually(RD, true);
+}
+
+void ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD,
+ const CXXRecordDecl *PB,
+ int64_t Offset,
+ llvm::SmallSet<const CXXRecordDecl*, 32> &mark,
+ llvm::SmallSet<const CXXRecordDecl*, 32> &IndirectPrimary) {
+ for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
+ e = RD->bases_end(); i != e; ++i) {
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+#if 0
+ const ASTRecordLayout &L = Ctx.getASTRecordLayout(Base);
+ const CXXRecordDecl *PB = L.getPrimaryBase();
+ if (PB && L.getPrimaryBaseWasVirtual()
+ && IndirectPrimary.count(PB)) {
+ int64_t BaseOffset;
+ // FIXME: calculate this.
+ BaseOffset = (1<<63) | (1<<31);
+ VBases.push_back(PB);
+ VBaseOffsets.push_back(BaseOffset);
+ }
+#endif
+ int64_t BaseOffset = Offset;;
+ // FIXME: Calculate BaseOffset.
+ if (i->isVirtual()) {
+ if (Base == PB) {
+ // Only lay things out once.
+ if (mark.count(Base))
+ continue;
+ // Mark it so we don't lay it out twice.
+ mark.insert(Base);
+ assert (IndirectPrimary.count(Base) && "IndirectPrimary was wrong");
+ VBases.push_back(std::make_pair(Base, Offset));
+ } else if (IndirectPrimary.count(Base)) {
+ // Someone else will eventually lay this out.
+ ;
+ } else {
+ // Only lay things out once.
+ if (mark.count(Base))
+ continue;
+ // Mark it so we don't lay it out twice.
+ mark.insert(Base);
+ LayoutVirtualBase(Base);
+ BaseOffset = VBases.back().second;
+ }
+ }
+ if (Base->getNumVBases()) {
+ const ASTRecordLayout &L = Ctx.getASTRecordLayout(Base);
+ const CXXRecordDecl *PB = L.getPrimaryBase();
+ LayoutVirtualBases(Base, PB, BaseOffset, mark, IndirectPrimary);
+ }
+ }
+}
+
+bool ASTRecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD,
+ uint64_t Offset) const {
+ // Look for an empty class with the same type at the same offset.
+ for (EmptyClassOffsetsTy::const_iterator I =
+ EmptyClassOffsets.lower_bound(Offset),
+ E = EmptyClassOffsets.upper_bound(Offset); I != E; ++I) {
+
+ if (I->second == RD)
+ return false;
+ }
+
+ const ASTRecordLayout &Info = Ctx.getASTRecordLayout(RD);
+
+ // Check bases.
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ if (I->isVirtual())
+ continue;
+
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ uint64_t BaseClassOffset = Info.getBaseClassOffset(Base);
+
+ if (!canPlaceRecordAtOffset(Base, Offset + BaseClassOffset))
+ return false;
+ }
+
+ // Check fields.
+ unsigned FieldNo = 0;
+ for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
+ I != E; ++I, ++FieldNo) {
+ const FieldDecl *FD = *I;
+
+ uint64_t FieldOffset = Info.getFieldOffset(FieldNo);
+
+ if (!canPlaceFieldAtOffset(FD, Offset + FieldOffset))
+ return false;
+ }
+
+ // FIXME: virtual bases.
+ return true;
+}
+
+bool ASTRecordLayoutBuilder::canPlaceFieldAtOffset(const FieldDecl *FD,
+ uint64_t Offset) const {
+ QualType T = FD->getType();
+ if (const RecordType *RT = T->getAs<RecordType>()) {
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()))
+ return canPlaceRecordAtOffset(RD, Offset);
+ }
+
+ if (const ConstantArrayType *AT = Ctx.getAsConstantArrayType(T)) {
+ QualType ElemTy = Ctx.getBaseElementType(AT);
+ const RecordType *RT = ElemTy->getAs<RecordType>();
+ if (!RT)
+ return true;
+ const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
+ if (!RD)
+ return true;
+
+ const ASTRecordLayout &Info = Ctx.getASTRecordLayout(RD);
+
+ uint64_t NumElements = Ctx.getConstantArrayElementCount(AT);
+ unsigned ElementOffset = Offset;
+ for (uint64_t I = 0; I != NumElements; ++I) {
+ if (!canPlaceRecordAtOffset(RD, ElementOffset))
+ return false;
+
+ ElementOffset += Info.getSize();
+ }
+ }
+
+ return true;
+}
+
+void ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const CXXRecordDecl *RD,
+ uint64_t Offset) {
+ if (RD->isEmpty())
+ EmptyClassOffsets.insert(std::make_pair(Offset, RD));
+
+ const ASTRecordLayout &Info = Ctx.getASTRecordLayout(RD);
+
+ // Update bases.
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ if (I->isVirtual())
+ continue;
+
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ uint64_t BaseClassOffset = Info.getBaseClassOffset(Base);
+ UpdateEmptyClassOffsets(Base, Offset + BaseClassOffset);
+ }
+
+ // Update fields.
+ unsigned FieldNo = 0;
+ for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
+ I != E; ++I, ++FieldNo) {
+ const FieldDecl *FD = *I;
+
+ uint64_t FieldOffset = Info.getFieldOffset(FieldNo);
+ UpdateEmptyClassOffsets(FD, Offset + FieldOffset);
+ }
+
+ // FIXME: Update virtual bases.
+}
+
+void
+ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const FieldDecl *FD,
+ uint64_t Offset) {
+ QualType T = FD->getType();
+
+ if (const RecordType *RT = T->getAs<RecordType>()) {
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
+ UpdateEmptyClassOffsets(RD, Offset);
+ return;
+ }
+ }
+
+ if (const ConstantArrayType *AT = Ctx.getAsConstantArrayType(T)) {
+ QualType ElemTy = Ctx.getBaseElementType(AT);
+ const RecordType *RT = ElemTy->getAs<RecordType>();
+ if (!RT)
+ return;
+ const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
+ if (!RD)
+ return;
+
+ const ASTRecordLayout &Info = Ctx.getASTRecordLayout(RD);
+
+ uint64_t NumElements = Ctx.getConstantArrayElementCount(AT);
+ unsigned ElementOffset = Offset;
+
+ for (uint64_t I = 0; I != NumElements; ++I) {
+ UpdateEmptyClassOffsets(RD, ElementOffset);
+ ElementOffset += Info.getSize();
+ }
+ }
+}
+
+uint64_t ASTRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *RD) {
+ const ASTRecordLayout &BaseInfo = Ctx.getASTRecordLayout(RD);
+
+ // If we have an empty base class, try to place it at offset 0.
+ if (RD->isEmpty() && canPlaceRecordAtOffset(RD, 0)) {
+ // We were able to place the class at offset 0.
+ UpdateEmptyClassOffsets(RD, 0);
+
+ Size = std::max(Size, BaseInfo.getSize());
+
+ return 0;
+ }
+
+ unsigned BaseAlign = BaseInfo.getNonVirtualAlign();
+
+ // Round up the current record size to the base's alignment boundary.
+ uint64_t Offset = llvm::RoundUpToAlignment(DataSize, BaseAlign);
+
+ // Try to place the base.
+ while (true) {
+ if (canPlaceRecordAtOffset(RD, Offset))
+ break;
+
+ Offset += BaseAlign;
+ }
+
+ if (!RD->isEmpty()) {
+ // Update the data size.
+ DataSize = Offset + BaseInfo.getNonVirtualSize();
+
+ Size = std::max(Size, DataSize);
+ } else
+ Size = std::max(Size, Offset + BaseInfo.getSize());
+
+ // Remember max struct/class alignment.
+ UpdateAlignment(BaseAlign);
+
+ UpdateEmptyClassOffsets(RD, Offset);
+ return Offset;
+}
+
+void ASTRecordLayoutBuilder::LayoutBaseNonVirtually(const CXXRecordDecl *RD,
+ bool IsVirtualBase) {
+ // Layout the base.
+ unsigned Offset = LayoutBase(RD);
+
+ // Add base class offsets.
+ if (IsVirtualBase)
+ VBases.push_back(std::make_pair(RD, Offset));
+ else
+ Bases.push_back(std::make_pair(RD, Offset));
+
+#if 0
+ // And now add offsets for all our primary virtual bases as well, so
+ // they all have offsets.
+ const ASTRecordLayout *L = &BaseInfo;
+ const CXXRecordDecl *PB = L->getPrimaryBase();
+ while (PB) {
+ if (L->getPrimaryBaseWasVirtual()) {
+ VBases.push_back(PB);
+ VBaseOffsets.push_back(Size);
+ }
+ PB = L->getPrimaryBase();
+ if (PB)
+ L = &Ctx.getASTRecordLayout(PB);
+ }
+#endif
+}
+
+void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) {
+ IsUnion = D->isUnion();
+
+ Packed = D->hasAttr<PackedAttr>();
+
+ // The #pragma pack attribute specifies the maximum field alignment.
+ if (const PragmaPackAttr *PPA = D->getAttr<PragmaPackAttr>())
+ MaxFieldAlignment = PPA->getAlignment();
+
+ if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
+ UpdateAlignment(AA->getAlignment());
+
+ // If this is a C++ class, lay out the vtable and the non-virtual bases.
+ const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D);
+ if (RD) {
+ LayoutVtable(RD);
+ // PrimaryBase goes first.
+ if (PrimaryBase) {
+ if (PrimaryBaseWasVirtual)
+ IndirectPrimaryBases.insert(PrimaryBase);
+ LayoutBaseNonVirtually(PrimaryBase, PrimaryBaseWasVirtual);
+ }
+ LayoutNonVirtualBases(RD);
+ }
+
+ LayoutFields(D);
+
+ NonVirtualSize = Size;
+ NonVirtualAlignment = Alignment;
+
+ if (RD) {
+ llvm::SmallSet<const CXXRecordDecl*, 32> mark;
+ LayoutVirtualBases(RD, PrimaryBase, 0, mark, IndirectPrimaryBases);
+ }
+
+ // Finally, round the size of the total struct up to the alignment of the
+ // struct itself.
+ FinishLayout();
+}
+
+void ASTRecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D,
+ const ObjCImplementationDecl *Impl) {
+ if (ObjCInterfaceDecl *SD = D->getSuperClass()) {
+ const ASTRecordLayout &SL = Ctx.getASTObjCInterfaceLayout(SD);
+
+ UpdateAlignment(SL.getAlignment());
+
+ // We start laying out ivars not at the end of the superclass
+ // structure, but at the next byte following the last field.
+ Size = llvm::RoundUpToAlignment(SL.getDataSize(), 8);
+ DataSize = Size;
+ }
+
+ Packed = D->hasAttr<PackedAttr>();
+
+ // The #pragma pack attribute specifies the maximum field alignment.
+ if (const PragmaPackAttr *PPA = D->getAttr<PragmaPackAttr>())
+ MaxFieldAlignment = PPA->getAlignment();
+
+ if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
+ UpdateAlignment(AA->getAlignment());
+
+ // Layout each ivar sequentially.
+ llvm::SmallVector<ObjCIvarDecl*, 16> Ivars;
+ Ctx.ShallowCollectObjCIvars(D, Ivars, Impl);
+ for (unsigned i = 0, e = Ivars.size(); i != e; ++i)
+ LayoutField(Ivars[i]);
+
+ // Finally, round the size of the total struct up to the alignment of the
+ // struct itself.
+ FinishLayout();
+}
+
+void ASTRecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
+ // Layout each field, for now, just sequentially, respecting alignment. In
+ // the future, this will need to be tweakable by targets.
+ for (RecordDecl::field_iterator Field = D->field_begin(),
+ FieldEnd = D->field_end(); Field != FieldEnd; ++Field)
+ LayoutField(*Field);
+}
+
+void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) {
+ bool FieldPacked = Packed;
+ uint64_t FieldOffset = IsUnion ? 0 : DataSize;
+ uint64_t FieldSize;
+ unsigned FieldAlign;
+
+ FieldPacked |= D->hasAttr<PackedAttr>();
+
+ if (const Expr *BitWidthExpr = D->getBitWidth()) {
+ // TODO: Need to check this algorithm on other targets!
+ // (tested on Linux-X86)
+ FieldSize = BitWidthExpr->EvaluateAsInt(Ctx).getZExtValue();
+
+ std::pair<uint64_t, unsigned> FieldInfo = Ctx.getTypeInfo(D->getType());
+ uint64_t TypeSize = FieldInfo.first;
+
+ FieldAlign = FieldInfo.second;
+
+ if (FieldPacked)
+ FieldAlign = 1;
+ if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
+ FieldAlign = std::max(FieldAlign, AA->getAlignment());
+ // The maximum field alignment overrides the aligned attribute.
+ if (MaxFieldAlignment)
+ FieldAlign = std::min(FieldAlign, MaxFieldAlignment);
+
+ // 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 (!D->getIdentifier())
+ FieldAlign = 1;
+ } else {
+ if (D->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 = Ctx.getAsArrayType(D->getType());
+ FieldAlign = Ctx.getTypeAlign(ATy->getElementType());
+ } else if (const ReferenceType *RT = D->getType()->getAs<ReferenceType>()) {
+ unsigned AS = RT->getPointeeType().getAddressSpace();
+ FieldSize = Ctx.Target.getPointerWidth(AS);
+ FieldAlign = Ctx.Target.getPointerAlign(AS);
+ } else {
+ std::pair<uint64_t, unsigned> FieldInfo = Ctx.getTypeInfo(D->getType());
+ FieldSize = FieldInfo.first;
+ FieldAlign = FieldInfo.second;
+ }
+
+ if (FieldPacked)
+ FieldAlign = 8;
+ if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
+ FieldAlign = std::max(FieldAlign, AA->getAlignment());
+ // The maximum field alignment overrides the aligned attribute.
+ if (MaxFieldAlignment)
+ FieldAlign = std::min(FieldAlign, MaxFieldAlignment);
+
+ // Round up the current record size to the field's alignment boundary.
+ FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign);
+
+ if (!IsUnion) {
+ while (true) {
+ // Check if we can place the field at this offset.
+ if (canPlaceFieldAtOffset(D, FieldOffset))
+ break;
+
+ // We couldn't place the field at the offset. Try again at a new offset.
+ FieldOffset += FieldAlign;
+ }
+
+ UpdateEmptyClassOffsets(D, FieldOffset);
+ }
+ }
+
+ // Place this field at the current location.
+ FieldOffsets.push_back(FieldOffset);
+
+ // Reserve space for this field.
+ if (IsUnion)
+ Size = std::max(Size, FieldSize);
+ else
+ Size = FieldOffset + FieldSize;
+
+ // Update the data size.
+ DataSize = Size;
+
+ // Remember max struct/class alignment.
+ UpdateAlignment(FieldAlign);
+}
+
+void ASTRecordLayoutBuilder::FinishLayout() {
+ // In C++, records cannot be of size 0.
+ if (Ctx.getLangOptions().CPlusPlus && 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 ASTRecordLayoutBuilder::UpdateAlignment(unsigned NewAlignment) {
+ if (NewAlignment <= Alignment)
+ return;
+
+ assert(llvm::isPowerOf2_32(NewAlignment && "Alignment not a power of 2"));
+
+ Alignment = NewAlignment;
+}
+
+const ASTRecordLayout *
+ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx,
+ const RecordDecl *D) {
+ ASTRecordLayoutBuilder Builder(Ctx);
+
+ Builder.Layout(D);
+
+ if (!isa<CXXRecordDecl>(D))
+ return new ASTRecordLayout(Builder.Size, Builder.Alignment, Builder.Size,
+ Builder.FieldOffsets.data(),
+ Builder.FieldOffsets.size());
+
+ // FIXME: This is not always correct. See the part about bitfields at
+ // http://www.codesourcery.com/public/cxx-abi/abi.html#POD for more info.
+ // FIXME: IsPODForThePurposeOfLayout should be stored in the record layout.
+ bool IsPODForThePurposeOfLayout = cast<CXXRecordDecl>(D)->isPOD();
+
+ // FIXME: This should be done in FinalizeLayout.
+ uint64_t DataSize =
+ IsPODForThePurposeOfLayout ? Builder.Size : Builder.DataSize;
+ uint64_t NonVirtualSize =
+ IsPODForThePurposeOfLayout ? DataSize : Builder.NonVirtualSize;
+
+ return new ASTRecordLayout(Builder.Size, Builder.Alignment, DataSize,
+ Builder.FieldOffsets.data(),
+ Builder.FieldOffsets.size(),
+ NonVirtualSize,
+ Builder.NonVirtualAlignment,
+ Builder.PrimaryBase,
+ Builder.PrimaryBaseWasVirtual,
+ Builder.Bases.data(),
+ Builder.Bases.size(),
+ Builder.VBases.data(),
+ Builder.VBases.size());
+}
+
+const ASTRecordLayout *
+ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx,
+ const ObjCInterfaceDecl *D,
+ const ObjCImplementationDecl *Impl) {
+ ASTRecordLayoutBuilder Builder(Ctx);
+
+ Builder.Layout(D, Impl);
+
+ return new ASTRecordLayout(Builder.Size, Builder.Alignment,
+ Builder.DataSize,
+ Builder.FieldOffsets.data(),
+ Builder.FieldOffsets.size());
+}
diff --git a/lib/AST/RecordLayoutBuilder.h b/lib/AST/RecordLayoutBuilder.h
new file mode 100644
index 0000000..6e4cdd2
--- /dev/null
+++ b/lib/AST/RecordLayoutBuilder.h
@@ -0,0 +1,146 @@
+//===- ASTRecordLayoutBuilder.h - Helper class for building record layouts ===//
+//
+// 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_RECORDLAYOUTBUILDER_H
+#define LLVM_CLANG_AST_RECORDLAYOUTBUILDER_H
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/Support/DataTypes.h"
+#include <map>
+
+namespace clang {
+ class ASTContext;
+ class ASTRecordLayout;
+ class CXXRecordDecl;
+ class FieldDecl;
+ class ObjCImplementationDecl;
+ class ObjCInterfaceDecl;
+ class RecordDecl;
+
+class ASTRecordLayoutBuilder {
+ ASTContext &Ctx;
+
+ uint64_t Size;
+ unsigned Alignment;
+ llvm::SmallVector<uint64_t, 16> FieldOffsets;
+
+ /// Packed - Whether the record is packed or not.
+ bool Packed;
+
+ /// MaxFieldAlignment - The maximum allowed field alignment. This is set by
+ /// #pragma pack.
+ unsigned MaxFieldAlignment;
+
+ /// DataSize - The data size of the record being laid out.
+ uint64_t DataSize;
+
+ bool IsUnion;
+
+ uint64_t NonVirtualSize;
+ unsigned NonVirtualAlignment;
+ const CXXRecordDecl *PrimaryBase;
+ bool PrimaryBaseWasVirtual;
+
+ typedef llvm::SmallVector<std::pair<const CXXRecordDecl *,
+ uint64_t>, 4> BaseOffsetsTy;
+
+ /// Bases - base classes and their offsets from the record.
+ BaseOffsetsTy Bases;
+
+ // VBases - virtual base classes and their offsets from the record.
+ BaseOffsetsTy VBases;
+
+ /// IndirectPrimaryBases - Virtual base classes, direct or indirect, that are
+ /// primary base classes for some other direct or indirect base class.
+ llvm::SmallSet<const CXXRecordDecl*, 32> IndirectPrimaryBases;
+
+ /// EmptyClassOffsets - A map from offsets to empty record decls.
+ typedef std::multimap<uint64_t, const CXXRecordDecl *> EmptyClassOffsetsTy;
+ EmptyClassOffsetsTy EmptyClassOffsets;
+
+ ASTRecordLayoutBuilder(ASTContext &Ctx);
+
+ void Layout(const RecordDecl *D);
+ void Layout(const CXXRecordDecl *D);
+ void Layout(const ObjCInterfaceDecl *D,
+ const ObjCImplementationDecl *Impl);
+
+ void LayoutFields(const RecordDecl *D);
+ void LayoutField(const FieldDecl *D);
+
+ void SelectPrimaryBase(const CXXRecordDecl *RD);
+ void SelectPrimaryVBase(const CXXRecordDecl *RD,
+ const CXXRecordDecl *&FirstPrimary);
+
+ /// IdentifyPrimaryBases - Identify all virtual base classes, direct or
+ /// indirect, that are primary base classes for some other direct or indirect
+ /// base class.
+ void IdentifyPrimaryBases(const CXXRecordDecl *RD);
+
+ void setPrimaryBase(const CXXRecordDecl *PB, bool Virtual) {
+ PrimaryBase = PB;
+ PrimaryBaseWasVirtual = Virtual;
+ }
+
+ bool IsNearlyEmpty(const CXXRecordDecl *RD) const;
+
+ /// LayoutBase - Will lay out a base and return the offset where it was
+ /// placed, in bits.
+ uint64_t LayoutBase(const CXXRecordDecl *RD);
+
+ void LayoutVtable(const CXXRecordDecl *RD);
+ void LayoutNonVirtualBases(const CXXRecordDecl *RD);
+ void LayoutBaseNonVirtually(const CXXRecordDecl *RD, bool IsVBase);
+ void LayoutVirtualBase(const CXXRecordDecl *RD);
+ void LayoutVirtualBases(const CXXRecordDecl *RD, const CXXRecordDecl *PB,
+ int64_t Offset,
+ llvm::SmallSet<const CXXRecordDecl*, 32> &mark,
+ llvm::SmallSet<const CXXRecordDecl*, 32> &IndirectPrimary);
+
+ /// canPlaceRecordAtOffset - Return whether a record (either a base class
+ /// or a field) can be placed at the given offset.
+ /// Returns false if placing the record will result in two components
+ /// (direct or indirect) of the same type having the same offset.
+ bool canPlaceRecordAtOffset(const CXXRecordDecl *RD, uint64_t Offset) const;
+
+ /// canPlaceFieldAtOffset - Return whether a field can be placed at the given
+ /// offset.
+ bool canPlaceFieldAtOffset(const FieldDecl *FD, uint64_t Offset) const;
+
+ /// UpdateEmptyClassOffsets - Called after a record (either a base class
+ /// or a field) has been placed at the given offset. Will update the
+ /// EmptyClassOffsets map if the class is empty or has any empty bases or
+ /// fields.
+ void UpdateEmptyClassOffsets(const CXXRecordDecl *RD, uint64_t Offset);
+
+ /// UpdateEmptyClassOffsets - Called after a field has been placed at the
+ /// given offset.
+ void UpdateEmptyClassOffsets(const FieldDecl *FD, uint64_t Offset);
+
+ /// FinishLayout - Finalize record layout. Adjust record size based on the
+ /// alignment.
+ void FinishLayout();
+
+ void UpdateAlignment(unsigned NewAlignment);
+
+ ASTRecordLayoutBuilder(const ASTRecordLayoutBuilder&); // DO NOT IMPLEMENT
+ void operator=(const ASTRecordLayoutBuilder&); // DO NOT IMPLEMENT
+public:
+ static const ASTRecordLayout *ComputeLayout(ASTContext &Ctx,
+ const RecordDecl *RD);
+ static const ASTRecordLayout *ComputeLayout(ASTContext &Ctx,
+ const ObjCInterfaceDecl *D,
+ const ObjCImplementationDecl *Impl);
+};
+
+} // end namespace clang
+
+#endif
+
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index 1757791..3a838fa 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -19,6 +19,7 @@
#include "clang/AST/Type.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTDiagnostic.h"
+#include <cstdio>
using namespace clang;
static struct StmtClassNameTable {
@@ -43,7 +44,7 @@ static StmtClassNameTable &getStmtInfoTableEntry(Stmt::StmtClass E) {
}
const char *Stmt::getStmtClassName() const {
- return getStmtInfoTableEntry(sClass).Name;
+ return getStmtInfoTableEntry((StmtClass)sClass).Name;
}
void Stmt::DestroyChildren(ASTContext &C) {
@@ -51,19 +52,12 @@ void Stmt::DestroyChildren(ASTContext &C) {
if (Stmt* Child = *I++) Child->Destroy(C);
}
-void Stmt::Destroy(ASTContext &C) {
+void Stmt::DoDestroy(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);
@@ -99,16 +93,18 @@ bool Stmt::CollectingStats(bool enable) {
return StatSwitch;
}
-NullStmt* NullStmt::Clone(ASTContext &C) const {
- return new (C) NullStmt(SemiLoc);
-}
-
-ContinueStmt* ContinueStmt::Clone(ASTContext &C) const {
- return new (C) ContinueStmt(ContinueLoc);
-}
+void SwitchStmt::DoDestroy(ASTContext &Ctx) {
+ // Destroy the SwitchCase statements in this switch. In the normal
+ // case, this loop will merely decrement the reference counts from
+ // the Retain() calls in addSwitchCase();
+ SwitchCase *SC = FirstCase;
+ while (SC) {
+ SwitchCase *Next = SC->getNextSwitchCase();
+ SC->Destroy(Ctx);
+ SC = Next;
+ }
-BreakStmt* BreakStmt::Clone(ASTContext &C) const {
- return new (C) BreakStmt(BreakLoc);
+ Stmt::DoDestroy(Ctx);
}
void CompoundStmt::setStmts(ASTContext &C, Stmt **Stmts, unsigned NumStmts) {
@@ -191,7 +187,7 @@ std::string AsmStmt::getInputConstraint(unsigned i) const {
void AsmStmt::setOutputsAndInputs(unsigned NumOutputs,
- unsigned NumInputs,
+ unsigned NumInputs,
const std::string *Names,
StringLiteral **Constraints,
Stmt **Exprs) {
@@ -200,7 +196,7 @@ void AsmStmt::setOutputsAndInputs(unsigned NumOutputs,
this->Names.clear();
this->Names.insert(this->Names.end(), Names, Names + NumOutputs + NumInputs);
this->Constraints.clear();
- this->Constraints.insert(this->Constraints.end(),
+ this->Constraints.insert(this->Constraints.end(),
Constraints, Constraints + NumOutputs + NumInputs);
this->Exprs.clear();
this->Exprs.insert(this->Exprs.end(), Exprs, Exprs + NumOutputs + NumInputs);
@@ -211,13 +207,13 @@ void AsmStmt::setOutputsAndInputs(unsigned NumOutputs,
/// 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;
@@ -239,7 +235,7 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces,
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()) {
@@ -261,7 +257,7 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces,
// 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) {
@@ -269,7 +265,7 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces,
Pieces.push_back(AsmStringPiece(CurStringPiece));
return 0;
}
-
+
char CurChar = *CurPtr++;
if (CurChar == '$') {
CurStringPiece += "$$";
@@ -278,48 +274,48 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces,
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) {
@@ -330,20 +326,20 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces,
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.
@@ -351,11 +347,11 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces,
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;
}
@@ -513,7 +509,7 @@ Stmt::child_iterator ReturnStmt::child_end() {
}
// AsmStmt
-Stmt::child_iterator AsmStmt::child_begin() {
+Stmt::child_iterator AsmStmt::child_begin() {
return Exprs.empty() ? 0 : &Exprs[0];
}
Stmt::child_iterator AsmStmt::child_end() {
@@ -569,10 +565,10 @@ QualType CXXCatchStmt::getCaughtType() {
return QualType();
}
-void CXXCatchStmt::Destroy(ASTContext& C) {
+void CXXCatchStmt::DoDestroy(ASTContext& C) {
if (ExceptionDecl)
ExceptionDecl->Destroy(C);
- Stmt::Destroy(C);
+ Stmt::DoDestroy(C);
}
// CXXTryStmt
diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp
index bc096bf..0465999 100644
--- a/lib/AST/StmtDumper.cpp
+++ b/lib/AST/StmtDumper.cpp
@@ -30,12 +30,12 @@ namespace {
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;
@@ -47,18 +47,18 @@ namespace {
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 {
+ else {
Visit(S);
-
+
// Print out children.
Stmt::child_iterator CI = S->child_begin(), CE = S->child_end();
if (CI != CE) {
@@ -75,25 +75,22 @@ namespace {
}
--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());
+ // If the type is sugared, also dump a (shallow) desugared type.
+ QualType Simplified = T.getDesugaredType();
+ if (Simplified != T)
fprintf(F, ":'%s'", Simplified.getAsString().c_str());
- }
}
}
void DumpStmt(const Stmt *Node) {
@@ -108,15 +105,16 @@ namespace {
}
void DumpSourceRange(const Stmt *Node);
void DumpLocation(SourceLocation Loc);
-
+
// Stmts.
void VisitStmt(Stmt *Node);
void VisitDeclStmt(DeclStmt *Node);
void VisitLabelStmt(LabelStmt *Node);
void VisitGotoStmt(GotoStmt *Node);
-
+
// Exprs
void VisitExpr(Expr *Node);
+ void VisitCastExpr(CastExpr *Node);
void VisitDeclRefExpr(DeclRefExpr *Node);
void VisitPredefinedExpr(PredefinedExpr *Node);
void VisitCharacterLiteral(CharacterLiteral *Node);
@@ -137,14 +135,19 @@ namespace {
void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node);
void VisitCXXThisExpr(CXXThisExpr *Node);
void VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node);
-
+ void VisitCXXConstructExpr(CXXConstructExpr *Node);
+ void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node);
+ void VisitCXXExprWithTemporaries(CXXExprWithTemporaries *Node);
+ void DumpCXXTemporary(CXXTemporary *Temporary);
+
// 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 VisitObjCImplicitSetterGetterRefExpr(
+ ObjCImplicitSetterGetterRefExpr *Node);
void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node);
void VisitObjCSuperExpr(ObjCSuperExpr *Node);
};
@@ -156,7 +159,7 @@ namespace {
void StmtDumper::DumpLocation(SourceLocation Loc) {
SourceLocation SpellingLoc = SM->getSpellingLoc(Loc);
-
+
if (SpellingLoc.isInvalid()) {
fprintf(stderr, "<invalid sloc>");
return;
@@ -182,11 +185,11 @@ void StmtDumper::DumpLocation(SourceLocation Loc) {
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()) {
@@ -194,7 +197,7 @@ void StmtDumper::DumpSourceRange(const Stmt *Node) {
DumpLocation(R.getEnd());
}
fprintf(stderr, ">");
-
+
// <t2.c:123:421[blah], t2.c:412:321>
}
@@ -220,15 +223,15 @@ void StmtDumper::DumpDeclarator(Decl *D) {
// Emit storage class for vardecls.
if (VarDecl *V = dyn_cast<VarDecl>(VD)) {
if (V->getStorageClass() != VarDecl::None)
- fprintf(F, "%s ",
+ fprintf(F, "%s ",
VarDecl::getStorageClassSpecifierString(V->getStorageClass()));
}
-
+
std::string Name = VD->getNameAsString();
- VD->getType().getAsStringInternal(Name,
+ VD->getType().getAsStringInternal(Name,
PrintingPolicy(VD->getASTContext().getLangOptions()));
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()) {
@@ -293,32 +296,37 @@ void StmtDumper::VisitExpr(Expr *Node) {
DumpExpr(Node);
}
+void StmtDumper::VisitCastExpr(CastExpr *Node) {
+ DumpExpr(Node);
+ fprintf(F, " <%s>", Node->getCastKindName());
+}
+
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;
+ default: fprintf(F,"Decl"); break;
+ 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;
}
-
- fprintf(F, "='%s' %p", Node->getDecl()->getNameAsString().c_str(),
+
+ 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(),
+ fprintf(F, " %sDecl='%s' %p", Node->getDecl()->getDeclKindName(),
Node->getDecl()->getNameAsString().c_str(), (void*)Node->getDecl());
if (Node->isFreeIvar())
fprintf(F, " isFreeIvar");
@@ -359,7 +367,7 @@ void StmtDumper::VisitStringLiteral(StringLiteral *Str) {
switch (char C = Str->getStrData()[i]) {
default:
if (isprint(C))
- fputc(C, F);
+ fputc(C, F);
else
fprintf(F, "\\%03o", C);
break;
@@ -390,7 +398,7 @@ void StmtDumper::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) {
void StmtDumper::VisitMemberExpr(MemberExpr *Node) {
DumpExpr(Node);
fprintf(F, " %s%s %p", Node->isArrow() ? "->" : ".",
- Node->getMemberDecl()->getNameAsString().c_str(),
+ Node->getMemberDecl()->getNameAsString().c_str(),
(void*)Node->getMemberDecl());
}
void StmtDumper::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) {
@@ -431,8 +439,9 @@ void StmtDumper::VisitTypesCompatibleExpr(TypesCompatibleExpr *Node) {
void StmtDumper::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) {
DumpExpr(Node);
- fprintf(F, " %s<%s>", Node->getCastName(),
- Node->getTypeAsWritten().getAsString().c_str());
+ fprintf(F, " %s<%s> <%s>", Node->getCastName(),
+ Node->getTypeAsWritten().getAsString().c_str(),
+ Node->getCastKindName());
}
void StmtDumper::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) {
@@ -447,10 +456,37 @@ void StmtDumper::VisitCXXThisExpr(CXXThisExpr *Node) {
void StmtDumper::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) {
DumpExpr(Node);
- fprintf(F, " functional cast to %s",
+ fprintf(F, " functional cast to %s",
Node->getTypeAsWritten().getAsString().c_str());
}
+void StmtDumper::VisitCXXConstructExpr(CXXConstructExpr *Node) {
+ DumpExpr(Node);
+ if (Node->isElidable())
+ fprintf(F, " elidable");
+}
+
+void StmtDumper::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node) {
+ DumpExpr(Node);
+ fprintf(F, " ");
+ DumpCXXTemporary(Node->getTemporary());
+}
+
+void StmtDumper::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *Node) {
+ DumpExpr(Node);
+ ++IndentLevel;
+ for (unsigned i = 0, e = Node->getNumTemporaries(); i != e; ++i) {
+ fprintf(F, "\n");
+ Indent();
+ DumpCXXTemporary(Node->getTemporary(i));
+ }
+ --IndentLevel;
+}
+
+void StmtDumper::DumpCXXTemporary(CXXTemporary *Temporary) {
+ fprintf(F, "(CXXTemporary %p)", (void *)Temporary);
+}
+
//===----------------------------------------------------------------------===//
// Obj-C Expressions
//===----------------------------------------------------------------------===//
@@ -464,21 +500,21 @@ void StmtDumper::VisitObjCMessageExpr(ObjCMessageExpr* Node) {
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());
}
@@ -486,16 +522,17 @@ void StmtDumper::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) {
void StmtDumper::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) {
DumpExpr(Node);
- fprintf(F, " Kind=PropertyRef Property=\"%s\"",
+ fprintf(F, " Kind=PropertyRef Property=\"%s\"",
Node->getProperty()->getNameAsString().c_str());
}
-void StmtDumper::VisitObjCKVCRefExpr(ObjCKVCRefExpr *Node) {
+void StmtDumper::VisitObjCImplicitSetterGetterRefExpr(
+ ObjCImplicitSetterGetterRefExpr *Node) {
DumpExpr(Node);
-
+
ObjCMethodDecl *Getter = Node->getGetterMethod();
ObjCMethodDecl *Setter = Node->getSetterMethod();
- fprintf(F, " Kind=MethodRef Getter=\"%s\" Setter=\"%s\"",
+ fprintf(F, " Kind=MethodRef Getter=\"%s\" Setter=\"%s\"",
Getter->getSelector().getAsString().c_str(),
Setter ? Setter->getSelector().getAsString().c_str() : "(null)");
}
diff --git a/lib/AST/StmtIterator.cpp b/lib/AST/StmtIterator.cpp
index 5c22e28..4f62b66 100644
--- a/lib/AST/StmtIterator.cpp
+++ b/lib/AST/StmtIterator.cpp
@@ -23,10 +23,10 @@ static inline VariableArrayType* FindVA(Type* t) {
if (VariableArrayType* vat = dyn_cast<VariableArrayType>(vt))
if (vat->getSizeExpr())
return vat;
-
+
t = vt->getElementType().getTypePtr();
}
-
+
return NULL;
}
@@ -39,20 +39,20 @@ void StmtIteratorBase::NextVA() {
if (p)
return;
-
+
if (inDecl()) {
- if (VarDecl* VD = dyn_cast<VarDecl>(decl))
+ if (VarDecl* VD = dyn_cast<VarDecl>(decl))
if (VD->Init)
return;
-
+
NextDecl();
}
else if (inDeclGroup()) {
- if (VarDecl* VD = dyn_cast<VarDecl>(*DGI))
+ if (VarDecl* VD = dyn_cast<VarDecl>(*DGI))
if (VD->Init)
return;
-
- NextDecl();
+
+ NextDecl();
}
else {
assert (inSizeOfTypeVA());
@@ -63,10 +63,10 @@ void StmtIteratorBase::NextVA() {
void StmtIteratorBase::NextDecl(bool ImmediateAdvance) {
assert (getVAPtr() == NULL);
-
+
if (inDecl()) {
assert (decl);
-
+
// FIXME: SIMPLIFY AWAY.
if (ImmediateAdvance)
decl = 0;
@@ -75,10 +75,10 @@ void StmtIteratorBase::NextDecl(bool ImmediateAdvance) {
}
else {
assert (inDeclGroup());
-
+
if (ImmediateAdvance)
++DGI;
-
+
for ( ; DGI != DGE; ++DGI)
if (HandleDecl(*DGI))
return;
@@ -88,18 +88,18 @@ void StmtIteratorBase::NextDecl(bool ImmediateAdvance) {
}
bool StmtIteratorBase::HandleDecl(Decl* D) {
-
- if (VarDecl* VD = dyn_cast<VarDecl>(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 =
+ if (VariableArrayType* VAPtr =
FindVA(TD->getUnderlyingType().getTypePtr())) {
setVAPtr(VAPtr);
return true;
@@ -110,7 +110,7 @@ bool StmtIteratorBase::HandleDecl(Decl* D) {
return true;
}
- return false;
+ return false;
}
StmtIteratorBase::StmtIteratorBase(Decl* d)
@@ -130,19 +130,19 @@ StmtIteratorBase::StmtIteratorBase(VariableArrayType* 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)) {
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index fec17fb..05d0c26 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -17,7 +17,6 @@
#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;
@@ -34,12 +33,12 @@ namespace {
PrintingPolicy Policy;
public:
- StmtPrinter(llvm::raw_ostream &os, ASTContext &C, PrinterHelper* helper,
+ StmtPrinter(llvm::raw_ostream &os, ASTContext &C, PrinterHelper* helper,
const PrintingPolicy &Policy,
unsigned Indentation = 0)
: OS(os), Context(C), IndentLevel(Indentation), Helper(helper),
Policy(Policy) {}
-
+
void PrintStmt(Stmt *S) {
PrintStmt(S, Policy.Indentation);
}
@@ -64,29 +63,29 @@ namespace {
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) {
+
+ 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);
@@ -109,7 +108,7 @@ void StmtPrinter::PrintRawCompoundStmt(CompoundStmt *Node) {
for (CompoundStmt::body_iterator I = Node->body_begin(), E = Node->body_end();
I != E; ++I)
PrintStmt(*I);
-
+
Indent() << "}";
}
@@ -120,7 +119,7 @@ void StmtPrinter::PrintRawDecl(Decl *D) {
void StmtPrinter::PrintRawDeclStmt(DeclStmt *S) {
DeclStmt::decl_iterator Begin = S->decl_begin(), End = S->decl_end();
llvm::SmallVector<Decl*, 2> Decls;
- for ( ; Begin != End; ++Begin)
+ for ( ; Begin != End; ++Begin)
Decls.push_back(*Begin);
Decl::printGroup(Decls.data(), Decls.size(), OS, Policy, IndentLevel);
@@ -150,7 +149,7 @@ void StmtPrinter::VisitCaseStmt(CaseStmt *Node) {
PrintExpr(Node->getRHS());
}
OS << ":\n";
-
+
PrintStmt(Node->getSubStmt(), 0);
}
@@ -168,7 +167,7 @@ void StmtPrinter::PrintRawIfStmt(IfStmt *If) {
OS << "if (";
PrintExpr(If->getCond());
OS << ')';
-
+
if (CompoundStmt *CS = dyn_cast<CompoundStmt>(If->getThen())) {
OS << ' ';
PrintRawCompoundStmt(CS);
@@ -178,10 +177,10 @@ void StmtPrinter::PrintRawIfStmt(IfStmt *If) {
PrintStmt(If->getThen());
if (If->getElse()) Indent();
}
-
+
if (Stmt *Else = If->getElse()) {
OS << "else";
-
+
if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Else)) {
OS << ' ';
PrintRawCompoundStmt(CS);
@@ -205,7 +204,7 @@ 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 << " ";
@@ -238,7 +237,7 @@ void StmtPrinter::VisitDoStmt(DoStmt *Node) {
PrintStmt(Node->getBody());
Indent();
}
-
+
OS << "while (";
PrintExpr(Node->getCond());
OS << ");\n";
@@ -263,7 +262,7 @@ void StmtPrinter::VisitForStmt(ForStmt *Node) {
PrintExpr(Node->getInc());
}
OS << ") ";
-
+
if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Node->getBody())) {
PrintRawCompoundStmt(CS);
OS << "\n";
@@ -282,7 +281,7 @@ void StmtPrinter::VisitObjCForCollectionStmt(ObjCForCollectionStmt *Node) {
OS << " in ";
PrintExpr(Node->getCollection());
OS << ") ";
-
+
if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Node->getBody())) {
PrintRawCompoundStmt(CS);
OS << "\n";
@@ -323,63 +322,63 @@ void StmtPrinter::VisitReturnStmt(ReturnStmt *Node) {
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";
}
@@ -389,11 +388,11 @@ void StmtPrinter::VisitObjCAtTryStmt(ObjCAtTryStmt *Node) {
PrintRawCompoundStmt(TS);
OS << "\n";
}
-
- for (ObjCAtCatchStmt *catchStmt =
+
+ for (ObjCAtCatchStmt *catchStmt =
static_cast<ObjCAtCatchStmt *>(Node->getCatchStmts());
- catchStmt;
- catchStmt =
+ catchStmt;
+ catchStmt =
static_cast<ObjCAtCatchStmt *>(catchStmt->getNextCatchStmt())) {
Indent() << "@catch(";
if (catchStmt->getCatchParamDecl()) {
@@ -401,19 +400,18 @@ void StmtPrinter::VisitObjCAtTryStmt(ObjCAtTryStmt *Node) {
PrintRawDecl(DS);
}
OS << ")";
- if (CompoundStmt *CS = dyn_cast<CompoundStmt>(catchStmt->getCatchBody()))
- {
- PrintRawCompoundStmt(CS);
- OS << "\n";
- }
+ if (CompoundStmt *CS = dyn_cast<CompoundStmt>(catchStmt->getCatchBody())) {
+ PrintRawCompoundStmt(CS);
+ OS << "\n";
+ }
}
-
- if (ObjCAtFinallyStmt *FS =static_cast<ObjCAtFinallyStmt *>(
- Node->getFinallyStmt())) {
+
+ if (ObjCAtFinallyStmt *FS = static_cast<ObjCAtFinallyStmt *>(
+ Node->getFinallyStmt())) {
Indent() << "@finally";
PrintRawCompoundStmt(dyn_cast<CompoundStmt>(FS->getFinallyBody()));
OS << "\n";
- }
+ }
}
void StmtPrinter::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *Node) {
@@ -459,7 +457,7 @@ void StmtPrinter::VisitCXXCatchStmt(CXXCatchStmt *Node) {
void StmtPrinter::VisitCXXTryStmt(CXXTryStmt *Node) {
Indent() << "try ";
PrintRawCompoundStmt(Node->getTryBlock());
- for(unsigned i = 0, e = Node->getNumHandlers(); i < e; ++i) {
+ for (unsigned i = 0, e = Node->getNumHandlers(); i < e; ++i) {
OS << " ";
PrintRawCXXCatchStmt(Node->getHandler(i));
}
@@ -478,14 +476,14 @@ void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) {
OS << Node->getDecl()->getNameAsString();
}
-void StmtPrinter::VisitQualifiedDeclRefExpr(QualifiedDeclRefExpr *Node) {
+void StmtPrinter::VisitQualifiedDeclRefExpr(QualifiedDeclRefExpr *Node) {
NamedDecl *D = Node->getDecl();
Node->getQualifier()->print(OS, Policy);
OS << D->getNameAsString();
}
-void StmtPrinter::VisitUnresolvedDeclRefExpr(UnresolvedDeclRefExpr *Node) {
+void StmtPrinter::VisitUnresolvedDeclRefExpr(UnresolvedDeclRefExpr *Node) {
Node->getQualifier()->print(OS, Policy);
OS << Node->getDeclName().getAsString();
}
@@ -494,12 +492,10 @@ void StmtPrinter::VisitTemplateIdRefExpr(TemplateIdRefExpr *Node) {
if (Node->getQualifier())
Node->getQualifier()->print(OS, Policy);
Node->getTemplateName().print(OS, Policy, true);
- OS << '<';
OS << TemplateSpecializationType::PrintTemplateArgumentList(
Node->getTemplateArgs(),
Node->getNumTemplateArgs(),
Policy);
- OS << '>';
}
void StmtPrinter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) {
@@ -518,12 +514,15 @@ void StmtPrinter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) {
OS << Node->getProperty()->getNameAsCString();
}
-void StmtPrinter::VisitObjCKVCRefExpr(ObjCKVCRefExpr *Node) {
+void StmtPrinter::VisitObjCImplicitSetterGetterRefExpr(
+ ObjCImplicitSetterGetterRefExpr *Node) {
if (Node->getBase()) {
PrintExpr(Node->getBase());
OS << ".";
}
- // FIXME: Setter/Getter names
+ if (Node->getGetterMethod())
+ OS << Node->getGetterMethod()->getNameAsString();
+
}
void StmtPrinter::VisitPredefinedExpr(PredefinedExpr *Node) {
@@ -594,9 +593,9 @@ void StmtPrinter::VisitCharacterLiteral(CharacterLiteral *Node) {
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()) {
+ switch (Node->getType()->getAs<BuiltinType>()->getKind()) {
default: assert(0 && "Unexpected type for integer literal!");
case BuiltinType::Int: break; // no suffix.
case BuiltinType::UInt: OS << 'U'; break;
@@ -623,7 +622,7 @@ void StmtPrinter::VisitStringLiteral(StringLiteral *Str) {
// 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))
@@ -653,7 +652,7 @@ void StmtPrinter::VisitParenExpr(ParenExpr *Node) {
void StmtPrinter::VisitUnaryOperator(UnaryOperator *Node) {
if (!Node->isPostfix()) {
OS << UnaryOperator::getOpcodeStr(Node->getOpcode());
-
+
// Print a space if this is an "identifier operator" like __real, or if
// it might be concatenated incorrectly like '+'.
switch (Node->getOpcode()) {
@@ -671,7 +670,7 @@ void StmtPrinter::VisitUnaryOperator(UnaryOperator *Node) {
}
}
PrintExpr(Node->getSubExpr());
-
+
if (Node->isPostfix())
OS << UnaryOperator::getOpcodeStr(Node->getOpcode());
}
@@ -737,8 +736,22 @@ void StmtPrinter::VisitMemberExpr(MemberExpr *Node) {
OS << (Node->isArrow() ? "->" : ".");
// FIXME: Suppress printing references to unnamed objects
// representing anonymous unions/structs
+ if (NestedNameSpecifier *Qualifier = Node->getQualifier())
+ Qualifier->print(OS, Policy);
+
OS << Node->getMemberDecl()->getNameAsString();
+
+ if (Node->hasExplicitTemplateArgumentList())
+ OS << TemplateSpecializationType::PrintTemplateArgumentList(
+ Node->getTemplateArgs(),
+ Node->getNumTemplateArgs(),
+ Policy);
}
+void StmtPrinter::VisitObjCIsaExpr(ObjCIsaExpr *Node) {
+ PrintExpr(Node->getBase());
+ OS << (Node->isArrow() ? "->isa" : ".isa");
+}
+
void StmtPrinter::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) {
PrintExpr(Node->getBase());
OS << ".";
@@ -774,7 +787,7 @@ void StmtPrinter::VisitCompoundAssignOperator(CompoundAssignOperator *Node) {
}
void StmtPrinter::VisitConditionalOperator(ConditionalOperator *Node) {
PrintExpr(Node->getCond());
-
+
if (Node->getLHS()) {
OS << " ? ";
PrintExpr(Node->getLHS());
@@ -783,7 +796,7 @@ void StmtPrinter::VisitConditionalOperator(ConditionalOperator *Node) {
else { // Handle GCC extension where LHS can be NULL.
OS << " ?: ";
}
-
+
PrintExpr(Node->getRHS());
}
@@ -845,6 +858,15 @@ void StmtPrinter::VisitInitListExpr(InitListExpr* Node) {
OS << " }";
}
+void StmtPrinter::VisitParenListExpr(ParenListExpr* Node) {
+ OS << "( ";
+ for (unsigned i = 0, e = Node->getNumExprs(); i != e; ++i) {
+ if (i) OS << ", ";
+ PrintExpr(Node->getExpr(i));
+ }
+ OS << " )";
+}
+
void StmtPrinter::VisitDesignatedInitExpr(DesignatedInitExpr *Node) {
for (DesignatedInitExpr::designators_iterator D = Node->designators_begin(),
DEnd = Node->designators_end();
@@ -861,7 +883,7 @@ void StmtPrinter::VisitDesignatedInitExpr(DesignatedInitExpr *Node) {
} else {
PrintExpr(Node->getArrayRangeStart(*D));
OS << " ... ";
- PrintExpr(Node->getArrayRangeEnd(*D));
+ PrintExpr(Node->getArrayRangeEnd(*D));
}
OS << "]";
}
@@ -1013,7 +1035,7 @@ void StmtPrinter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *Node) {
OS << Node->getType().getAsString();
OS << "(";
for (CXXTemporaryObjectExpr::arg_iterator Arg = Node->arg_begin(),
- ArgEnd = Node->arg_end();
+ ArgEnd = Node->arg_end();
Arg != ArgEnd; ++Arg) {
if (Arg != Node->arg_begin())
OS << ", ";
@@ -1082,6 +1104,20 @@ void StmtPrinter::VisitCXXDeleteExpr(CXXDeleteExpr *E) {
PrintExpr(E->getArgument());
}
+void StmtPrinter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
+ PrintExpr(E->getBase());
+ if (E->isArrow())
+ OS << "->";
+ else
+ OS << '.';
+ if (E->getQualifier())
+ E->getQualifier()->print(OS, Policy);
+
+ std::string TypeS;
+ E->getDestroyedType().getAsStringInternal(TypeS, Policy);
+ OS << TypeS;
+}
+
void StmtPrinter::VisitUnresolvedFunctionNameExpr(UnresolvedFunctionNameExpr *E) {
OS << E->getName().getAsString();
}
@@ -1095,13 +1131,13 @@ void StmtPrinter::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E) {
PrintExpr(E->getSubExpr());
}
-void
+void
StmtPrinter::VisitCXXUnresolvedConstructExpr(
CXXUnresolvedConstructExpr *Node) {
OS << Node->getTypeAsWritten().getAsString();
OS << "(";
for (CXXUnresolvedConstructExpr::arg_iterator Arg = Node->arg_begin(),
- ArgEnd = Node->arg_end();
+ ArgEnd = Node->arg_end();
Arg != ArgEnd; ++Arg) {
if (Arg != Node->arg_begin())
OS << ", ";
@@ -1113,7 +1149,20 @@ StmtPrinter::VisitCXXUnresolvedConstructExpr(
void StmtPrinter::VisitCXXUnresolvedMemberExpr(CXXUnresolvedMemberExpr *Node) {
PrintExpr(Node->getBase());
OS << (Node->isArrow() ? "->" : ".");
+ if (NestedNameSpecifier *Qualifier = Node->getQualifier())
+ Qualifier->print(OS, Policy);
+ else if (Node->hasExplicitTemplateArgumentList())
+ // FIXME: Track use of "template" keyword explicitly?
+ OS << "template ";
+
OS << Node->getMember().getAsString();
+
+ if (Node->hasExplicitTemplateArgumentList()) {
+ OS << TemplateSpecializationType::PrintTemplateArgumentList(
+ Node->getTemplateArgs(),
+ Node->getNumTemplateArgs(),
+ Policy);
+ }
}
static const char *getTypeTraitName(UnaryTypeTrait UTT) {
@@ -1142,7 +1191,7 @@ void StmtPrinter::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) {
<< E->getQueriedType().getAsString() << ")";
}
-// Obj-C
+// Obj-C
void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) {
OS << "@";
@@ -1180,7 +1229,7 @@ void StmtPrinter::VisitObjCMessageExpr(ObjCMessageExpr *Mess) {
OS << ":";
}
else OS << ", "; // Handle variadic methods.
-
+
PrintExpr(Mess->getArg(i));
}
}
@@ -1194,9 +1243,9 @@ void StmtPrinter::VisitObjCSuperExpr(ObjCSuperExpr *) {
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()) {
@@ -1209,7 +1258,7 @@ void StmtPrinter::VisitBlockExpr(BlockExpr *Node) {
(*AI)->getType().getAsStringInternal(ParamStr, Policy);
OS << ParamStr;
}
-
+
const FunctionProtoType *FT = cast<FunctionProtoType>(AFT);
if (FT->isVariadic()) {
if (!BD->param_empty()) OS << ", ";
@@ -1241,10 +1290,10 @@ void Stmt::printPretty(llvm::raw_ostream &OS, ASTContext& Context,
}
if (Policy.Dump) {
- dump();
+ dump(Context.getSourceManager());
return;
}
-
+
StmtPrinter P(OS, Context, Helper, Policy, Indentation);
P.Visit(const_cast<Stmt*>(this));
}
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
new file mode 100644
index 0000000..c4d42f6
--- /dev/null
+++ b/lib/AST/StmtProfile.cpp
@@ -0,0 +1,720 @@
+//===---- StmtProfile.cpp - Profile 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::Profile method, which builds a unique bit
+// representation that identifies a statement/expression.
+//
+//===----------------------------------------------------------------------===//
+#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/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/AST/StmtVisitor.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/Support/Compiler.h"
+using namespace clang;
+
+namespace {
+ class VISIBILITY_HIDDEN StmtProfiler : public StmtVisitor<StmtProfiler> {
+ llvm::FoldingSetNodeID &ID;
+ ASTContext &Context;
+ bool Canonical;
+
+ public:
+ StmtProfiler(llvm::FoldingSetNodeID &ID, ASTContext &Context,
+ bool Canonical)
+ : ID(ID), Context(Context), Canonical(Canonical) { }
+
+ void VisitStmt(Stmt *S);
+
+#define STMT(Node, Base) void Visit##Node(Node *S);
+#include "clang/AST/StmtNodes.def"
+
+ /// \brief Visit a declaration that is referenced within an expression
+ /// or statement.
+ void VisitDecl(Decl *D);
+
+ /// \brief Visit a type that is referenced within an expression or
+ /// statement.
+ void VisitType(QualType T);
+
+ /// \brief Visit a name that occurs within an expression or statement.
+ void VisitName(DeclarationName Name);
+
+ /// \brief Visit a nested-name-specifier that occurs within an expression
+ /// or statement.
+ void VisitNestedNameSpecifier(NestedNameSpecifier *NNS);
+
+ /// \brief Visit a template name that occurs within an expression or
+ /// statement.
+ void VisitTemplateName(TemplateName Name);
+
+ /// \brief Visit template arguments that occur within an expression or
+ /// statement.
+ void VisitTemplateArguments(const TemplateArgument *Args, unsigned NumArgs);
+ };
+}
+
+void StmtProfiler::VisitStmt(Stmt *S) {
+ ID.AddInteger(S->getStmtClass());
+ for (Stmt::child_iterator C = S->child_begin(), CEnd = S->child_end();
+ C != CEnd; ++C)
+ Visit(*C);
+}
+
+void StmtProfiler::VisitDeclStmt(DeclStmt *S) {
+ VisitStmt(S);
+ for (DeclStmt::decl_iterator D = S->decl_begin(), DEnd = S->decl_end();
+ D != DEnd; ++D)
+ VisitDecl(*D);
+}
+
+void StmtProfiler::VisitNullStmt(NullStmt *S) {
+ VisitStmt(S);
+}
+
+void StmtProfiler::VisitCompoundStmt(CompoundStmt *S) {
+ VisitStmt(S);
+}
+
+void StmtProfiler::VisitSwitchCase(SwitchCase *S) {
+ VisitStmt(S);
+}
+
+void StmtProfiler::VisitCaseStmt(CaseStmt *S) {
+ VisitStmt(S);
+}
+
+void StmtProfiler::VisitDefaultStmt(DefaultStmt *S) {
+ VisitStmt(S);
+}
+
+void StmtProfiler::VisitLabelStmt(LabelStmt *S) {
+ VisitStmt(S);
+ VisitName(S->getID());
+}
+
+void StmtProfiler::VisitIfStmt(IfStmt *S) {
+ VisitStmt(S);
+}
+
+void StmtProfiler::VisitSwitchStmt(SwitchStmt *S) {
+ VisitStmt(S);
+}
+
+void StmtProfiler::VisitWhileStmt(WhileStmt *S) {
+ VisitStmt(S);
+}
+
+void StmtProfiler::VisitDoStmt(DoStmt *S) {
+ VisitStmt(S);
+}
+
+void StmtProfiler::VisitForStmt(ForStmt *S) {
+ VisitStmt(S);
+}
+
+void StmtProfiler::VisitGotoStmt(GotoStmt *S) {
+ VisitStmt(S);
+ VisitName(S->getLabel()->getID());
+}
+
+void StmtProfiler::VisitIndirectGotoStmt(IndirectGotoStmt *S) {
+ VisitStmt(S);
+}
+
+void StmtProfiler::VisitContinueStmt(ContinueStmt *S) {
+ VisitStmt(S);
+}
+
+void StmtProfiler::VisitBreakStmt(BreakStmt *S) {
+ VisitStmt(S);
+}
+
+void StmtProfiler::VisitReturnStmt(ReturnStmt *S) {
+ VisitStmt(S);
+}
+
+void StmtProfiler::VisitAsmStmt(AsmStmt *S) {
+ VisitStmt(S);
+ ID.AddBoolean(S->isVolatile());
+ ID.AddBoolean(S->isSimple());
+ VisitStringLiteral(S->getAsmString());
+ ID.AddInteger(S->getNumOutputs());
+ for (unsigned I = 0, N = S->getNumOutputs(); I != N; ++I) {
+ ID.AddString(S->getOutputName(I));
+ VisitStringLiteral(S->getOutputConstraintLiteral(I));
+ }
+ ID.AddInteger(S->getNumInputs());
+ for (unsigned I = 0, N = S->getNumInputs(); I != N; ++I) {
+ ID.AddString(S->getInputName(I));
+ VisitStringLiteral(S->getInputConstraintLiteral(I));
+ }
+ ID.AddInteger(S->getNumClobbers());
+ for (unsigned I = 0, N = S->getNumClobbers(); I != N; ++I)
+ VisitStringLiteral(S->getClobber(I));
+}
+
+void StmtProfiler::VisitCXXCatchStmt(CXXCatchStmt *S) {
+ VisitStmt(S);
+ VisitType(S->getCaughtType());
+}
+
+void StmtProfiler::VisitCXXTryStmt(CXXTryStmt *S) {
+ VisitStmt(S);
+}
+
+void StmtProfiler::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
+ VisitStmt(S);
+}
+
+void StmtProfiler::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) {
+ VisitStmt(S);
+ ID.AddBoolean(S->hasEllipsis());
+ if (S->getCatchParamDecl())
+ VisitType(S->getCatchParamDecl()->getType());
+}
+
+void StmtProfiler::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
+ VisitStmt(S);
+}
+
+void StmtProfiler::VisitObjCAtTryStmt(ObjCAtTryStmt *S) {
+ VisitStmt(S);
+}
+
+void StmtProfiler::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
+ VisitStmt(S);
+}
+
+void StmtProfiler::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) {
+ VisitStmt(S);
+}
+
+void StmtProfiler::VisitExpr(Expr *S) {
+ VisitStmt(S);
+}
+
+void StmtProfiler::VisitDeclRefExpr(DeclRefExpr *S) {
+ VisitExpr(S);
+ VisitDecl(S->getDecl());
+}
+
+void StmtProfiler::VisitPredefinedExpr(PredefinedExpr *S) {
+ VisitExpr(S);
+ ID.AddInteger(S->getIdentType());
+}
+
+void StmtProfiler::VisitIntegerLiteral(IntegerLiteral *S) {
+ VisitExpr(S);
+ S->getValue().Profile(ID);
+}
+
+void StmtProfiler::VisitCharacterLiteral(CharacterLiteral *S) {
+ VisitExpr(S);
+ ID.AddBoolean(S->isWide());
+ ID.AddInteger(S->getValue());
+}
+
+void StmtProfiler::VisitFloatingLiteral(FloatingLiteral *S) {
+ VisitExpr(S);
+ S->getValue().Profile(ID);
+ ID.AddBoolean(S->isExact());
+}
+
+void StmtProfiler::VisitImaginaryLiteral(ImaginaryLiteral *S) {
+ VisitExpr(S);
+}
+
+void StmtProfiler::VisitStringLiteral(StringLiteral *S) {
+ VisitExpr(S);
+ ID.AddString(S->getString());
+ ID.AddBoolean(S->isWide());
+}
+
+void StmtProfiler::VisitParenExpr(ParenExpr *S) {
+ VisitExpr(S);
+}
+
+void StmtProfiler::VisitParenListExpr(ParenListExpr *S) {
+ VisitExpr(S);
+}
+
+void StmtProfiler::VisitUnaryOperator(UnaryOperator *S) {
+ VisitExpr(S);
+ ID.AddInteger(S->getOpcode());
+}
+
+void StmtProfiler::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *S) {
+ VisitExpr(S);
+ ID.AddBoolean(S->isSizeOf());
+ if (S->isArgumentType())
+ VisitType(S->getArgumentType());
+}
+
+void StmtProfiler::VisitArraySubscriptExpr(ArraySubscriptExpr *S) {
+ VisitExpr(S);
+}
+
+void StmtProfiler::VisitCallExpr(CallExpr *S) {
+ VisitExpr(S);
+}
+
+void StmtProfiler::VisitMemberExpr(MemberExpr *S) {
+ VisitExpr(S);
+ VisitDecl(S->getMemberDecl());
+ VisitNestedNameSpecifier(S->getQualifier());
+ ID.AddBoolean(S->isArrow());
+}
+
+void StmtProfiler::VisitCompoundLiteralExpr(CompoundLiteralExpr *S) {
+ VisitExpr(S);
+ ID.AddBoolean(S->isFileScope());
+}
+
+void StmtProfiler::VisitCastExpr(CastExpr *S) {
+ VisitExpr(S);
+}
+
+void StmtProfiler::VisitImplicitCastExpr(ImplicitCastExpr *S) {
+ VisitCastExpr(S);
+ ID.AddBoolean(S->isLvalueCast());
+}
+
+void StmtProfiler::VisitExplicitCastExpr(ExplicitCastExpr *S) {
+ VisitCastExpr(S);
+ VisitType(S->getTypeAsWritten());
+}
+
+void StmtProfiler::VisitCStyleCastExpr(CStyleCastExpr *S) {
+ VisitExplicitCastExpr(S);
+}
+
+void StmtProfiler::VisitBinaryOperator(BinaryOperator *S) {
+ VisitExpr(S);
+ ID.AddInteger(S->getOpcode());
+}
+
+void StmtProfiler::VisitCompoundAssignOperator(CompoundAssignOperator *S) {
+ VisitBinaryOperator(S);
+}
+
+void StmtProfiler::VisitConditionalOperator(ConditionalOperator *S) {
+ VisitExpr(S);
+}
+
+void StmtProfiler::VisitAddrLabelExpr(AddrLabelExpr *S) {
+ VisitExpr(S);
+ VisitName(S->getLabel()->getID());
+}
+
+void StmtProfiler::VisitStmtExpr(StmtExpr *S) {
+ VisitExpr(S);
+}
+
+void StmtProfiler::VisitTypesCompatibleExpr(TypesCompatibleExpr *S) {
+ VisitExpr(S);
+ VisitType(S->getArgType1());
+ VisitType(S->getArgType2());
+}
+
+void StmtProfiler::VisitShuffleVectorExpr(ShuffleVectorExpr *S) {
+ VisitExpr(S);
+}
+
+void StmtProfiler::VisitChooseExpr(ChooseExpr *S) {
+ VisitExpr(S);
+}
+
+void StmtProfiler::VisitGNUNullExpr(GNUNullExpr *S) {
+ VisitExpr(S);
+}
+
+void StmtProfiler::VisitVAArgExpr(VAArgExpr *S) {
+ VisitExpr(S);
+}
+
+void StmtProfiler::VisitInitListExpr(InitListExpr *S) {
+ if (S->getSyntacticForm()) {
+ VisitInitListExpr(S->getSyntacticForm());
+ return;
+ }
+
+ VisitExpr(S);
+}
+
+void StmtProfiler::VisitDesignatedInitExpr(DesignatedInitExpr *S) {
+ VisitExpr(S);
+ ID.AddBoolean(S->usesGNUSyntax());
+ for (DesignatedInitExpr::designators_iterator D = S->designators_begin(),
+ DEnd = S->designators_end();
+ D != DEnd; ++D) {
+ if (D->isFieldDesignator()) {
+ ID.AddInteger(0);
+ VisitName(D->getFieldName());
+ continue;
+ }
+
+ if (D->isArrayDesignator()) {
+ ID.AddInteger(1);
+ } else {
+ assert(D->isArrayRangeDesignator());
+ ID.AddInteger(2);
+ }
+ ID.AddInteger(D->getFirstExprIndex());
+ }
+}
+
+void StmtProfiler::VisitImplicitValueInitExpr(ImplicitValueInitExpr *S) {
+ VisitExpr(S);
+}
+
+void StmtProfiler::VisitExtVectorElementExpr(ExtVectorElementExpr *S) {
+ VisitExpr(S);
+ VisitName(&S->getAccessor());
+}
+
+void StmtProfiler::VisitBlockExpr(BlockExpr *S) {
+ VisitExpr(S);
+ VisitDecl(S->getBlockDecl());
+}
+
+void StmtProfiler::VisitBlockDeclRefExpr(BlockDeclRefExpr *S) {
+ VisitExpr(S);
+ VisitDecl(S->getDecl());
+ ID.AddBoolean(S->isByRef());
+ ID.AddBoolean(S->isConstQualAdded());
+}
+
+void StmtProfiler::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *S) {
+ VisitCallExpr(S);
+ ID.AddInteger(S->getOperator());
+}
+
+void StmtProfiler::VisitCXXMemberCallExpr(CXXMemberCallExpr *S) {
+ VisitCallExpr(S);
+}
+
+void StmtProfiler::VisitCXXNamedCastExpr(CXXNamedCastExpr *S) {
+ VisitExplicitCastExpr(S);
+}
+
+void StmtProfiler::VisitCXXStaticCastExpr(CXXStaticCastExpr *S) {
+ VisitCXXNamedCastExpr(S);
+}
+
+void StmtProfiler::VisitCXXDynamicCastExpr(CXXDynamicCastExpr *S) {
+ VisitCXXNamedCastExpr(S);
+}
+
+void StmtProfiler::VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *S) {
+ VisitCXXNamedCastExpr(S);
+}
+
+void StmtProfiler::VisitCXXConstCastExpr(CXXConstCastExpr *S) {
+ VisitCXXNamedCastExpr(S);
+}
+
+void StmtProfiler::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *S) {
+ VisitExpr(S);
+ ID.AddBoolean(S->getValue());
+}
+
+void StmtProfiler::VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *S) {
+ VisitExpr(S);
+}
+
+void StmtProfiler::VisitCXXTypeidExpr(CXXTypeidExpr *S) {
+ VisitExpr(S);
+ if (S->isTypeOperand())
+ VisitType(S->getTypeOperand());
+}
+
+void StmtProfiler::VisitCXXThisExpr(CXXThisExpr *S) {
+ VisitExpr(S);
+}
+
+void StmtProfiler::VisitCXXThrowExpr(CXXThrowExpr *S) {
+ VisitExpr(S);
+}
+
+void StmtProfiler::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *S) {
+ VisitExpr(S);
+ VisitDecl(S->getParam());
+}
+
+void StmtProfiler::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *S) {
+ VisitExpr(S);
+ VisitDecl(
+ const_cast<CXXDestructorDecl *>(S->getTemporary()->getDestructor()));
+}
+
+void StmtProfiler::VisitCXXConstructExpr(CXXConstructExpr *S) {
+ VisitExpr(S);
+ VisitDecl(S->getConstructor());
+ ID.AddBoolean(S->isElidable());
+}
+
+void StmtProfiler::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *S) {
+ VisitExplicitCastExpr(S);
+}
+
+void StmtProfiler::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *S) {
+ VisitCXXConstructExpr(S);
+}
+
+void StmtProfiler::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *S) {
+ VisitExpr(S);
+}
+
+void StmtProfiler::VisitCXXConditionDeclExpr(CXXConditionDeclExpr *S) {
+ VisitDeclRefExpr(S);
+}
+
+void StmtProfiler::VisitCXXDeleteExpr(CXXDeleteExpr *S) {
+ VisitExpr(S);
+ ID.AddBoolean(S->isGlobalDelete());
+ ID.AddBoolean(S->isArrayForm());
+ VisitDecl(S->getOperatorDelete());
+}
+
+
+void StmtProfiler::VisitCXXNewExpr(CXXNewExpr *S) {
+ VisitExpr(S);
+ VisitType(S->getAllocatedType());
+ VisitDecl(S->getOperatorNew());
+ VisitDecl(S->getOperatorDelete());
+ VisitDecl(S->getConstructor());
+ ID.AddBoolean(S->isArray());
+ ID.AddInteger(S->getNumPlacementArgs());
+ ID.AddBoolean(S->isGlobalNew());
+ ID.AddBoolean(S->isParenTypeId());
+ ID.AddBoolean(S->hasInitializer());
+ ID.AddInteger(S->getNumConstructorArgs());
+}
+
+void StmtProfiler::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *S) {
+ VisitExpr(S);
+ ID.AddBoolean(S->isArrow());
+ VisitNestedNameSpecifier(S->getQualifier());
+ VisitType(S->getDestroyedType());
+}
+
+void
+StmtProfiler::VisitUnresolvedFunctionNameExpr(UnresolvedFunctionNameExpr *S) {
+ VisitExpr(S);
+ VisitName(S->getName());
+}
+
+void StmtProfiler::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *S) {
+ VisitExpr(S);
+ ID.AddInteger(S->getTrait());
+ VisitType(S->getQueriedType());
+}
+
+void StmtProfiler::VisitQualifiedDeclRefExpr(QualifiedDeclRefExpr *S) {
+ VisitDeclRefExpr(S);
+ VisitNestedNameSpecifier(S->getQualifier());
+}
+
+void StmtProfiler::VisitUnresolvedDeclRefExpr(UnresolvedDeclRefExpr *S) {
+ VisitExpr(S);
+ VisitName(S->getDeclName());
+ VisitNestedNameSpecifier(S->getQualifier());
+ ID.AddBoolean(S->isAddressOfOperand());
+}
+
+void StmtProfiler::VisitTemplateIdRefExpr(TemplateIdRefExpr *S) {
+ VisitExpr(S);
+ VisitNestedNameSpecifier(S->getQualifier());
+ VisitTemplateName(S->getTemplateName());
+ VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs());
+}
+
+void StmtProfiler::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *S) {
+ VisitExpr(S);
+ ID.AddBoolean(S->shouldDestroyTemporaries());
+ for (unsigned I = 0, N = S->getNumTemporaries(); I != N; ++I)
+ VisitDecl(
+ const_cast<CXXDestructorDecl *>(S->getTemporary(I)->getDestructor()));
+}
+
+void
+StmtProfiler::VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *S) {
+ VisitExpr(S);
+ VisitType(S->getTypeAsWritten());
+}
+
+void StmtProfiler::VisitCXXUnresolvedMemberExpr(CXXUnresolvedMemberExpr *S) {
+ VisitExpr(S);
+ ID.AddBoolean(S->isArrow());
+ VisitNestedNameSpecifier(S->getQualifier());
+ VisitName(S->getMember());
+}
+
+void StmtProfiler::VisitObjCStringLiteral(ObjCStringLiteral *S) {
+ VisitExpr(S);
+}
+
+void StmtProfiler::VisitObjCEncodeExpr(ObjCEncodeExpr *S) {
+ VisitExpr(S);
+ VisitType(S->getEncodedType());
+}
+
+void StmtProfiler::VisitObjCSelectorExpr(ObjCSelectorExpr *S) {
+ VisitExpr(S);
+ VisitName(S->getSelector());
+}
+
+void StmtProfiler::VisitObjCProtocolExpr(ObjCProtocolExpr *S) {
+ VisitExpr(S);
+ VisitDecl(S->getProtocol());
+}
+
+void StmtProfiler::VisitObjCIvarRefExpr(ObjCIvarRefExpr *S) {
+ VisitExpr(S);
+ VisitDecl(S->getDecl());
+ ID.AddBoolean(S->isArrow());
+ ID.AddBoolean(S->isFreeIvar());
+}
+
+void StmtProfiler::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *S) {
+ VisitExpr(S);
+ VisitDecl(S->getProperty());
+}
+
+void StmtProfiler::VisitObjCImplicitSetterGetterRefExpr(
+ ObjCImplicitSetterGetterRefExpr *S) {
+ VisitExpr(S);
+ VisitDecl(S->getGetterMethod());
+ VisitDecl(S->getSetterMethod());
+ VisitDecl(S->getInterfaceDecl());
+}
+
+void StmtProfiler::VisitObjCMessageExpr(ObjCMessageExpr *S) {
+ VisitExpr(S);
+ VisitName(S->getSelector());
+ VisitDecl(S->getMethodDecl());
+}
+
+void StmtProfiler::VisitObjCSuperExpr(ObjCSuperExpr *S) {
+ VisitExpr(S);
+}
+
+void StmtProfiler::VisitObjCIsaExpr(ObjCIsaExpr *S) {
+ VisitExpr(S);
+ ID.AddBoolean(S->isArrow());
+}
+
+void StmtProfiler::VisitDecl(Decl *D) {
+ ID.AddInteger(D? D->getKind() : 0);
+
+ if (Canonical && D) {
+ if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) {
+ ID.AddInteger(NTTP->getDepth());
+ ID.AddInteger(NTTP->getIndex());
+ VisitType(NTTP->getType());
+ return;
+ }
+
+ if (ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D)) {
+ // The Itanium C++ ABI uses the type of a parameter when mangling
+ // expressions that involve function parameters, so we will use the
+ // parameter's type for establishing function parameter identity. That
+ // way, our definition of "equivalent" (per C++ [temp.over.link])
+ // matches the definition of "equivalent" used for name mangling.
+ VisitType(Parm->getType());
+ return;
+ }
+
+ if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(D)) {
+ ID.AddInteger(TTP->getDepth());
+ ID.AddInteger(TTP->getIndex());
+ return;
+ }
+
+ if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(D)) {
+ // The Itanium C++ ABI mangles references to a set of overloaded
+ // functions using just the function name, so we do the same here.
+ VisitName(Ovl->getDeclName());
+ return;
+ }
+ }
+
+ ID.AddPointer(D? D->getCanonicalDecl() : 0);
+}
+
+void StmtProfiler::VisitType(QualType T) {
+ if (Canonical)
+ T = Context.getCanonicalType(T);
+
+ ID.AddPointer(T.getAsOpaquePtr());
+}
+
+void StmtProfiler::VisitName(DeclarationName Name) {
+ ID.AddPointer(Name.getAsOpaquePtr());
+}
+
+void StmtProfiler::VisitNestedNameSpecifier(NestedNameSpecifier *NNS) {
+ if (Canonical)
+ NNS = Context.getCanonicalNestedNameSpecifier(NNS);
+ ID.AddPointer(NNS);
+}
+
+void StmtProfiler::VisitTemplateName(TemplateName Name) {
+ if (Canonical)
+ Name = Context.getCanonicalTemplateName(Name);
+
+ Name.Profile(ID);
+}
+
+void StmtProfiler::VisitTemplateArguments(const TemplateArgument *Args,
+ unsigned NumArgs) {
+ ID.AddInteger(NumArgs);
+ for (unsigned I = 0; I != NumArgs; ++I) {
+ const TemplateArgument &Arg = Args[I];
+
+ // Mostly repetitive with TemplateArgument::Profile!
+ ID.AddInteger(Arg.getKind());
+ switch (Arg.getKind()) {
+ case TemplateArgument::Null:
+ break;
+
+ case TemplateArgument::Type:
+ VisitType(Arg.getAsType());
+ break;
+
+ case TemplateArgument::Declaration:
+ VisitDecl(Arg.getAsDecl());
+ break;
+
+ case TemplateArgument::Integral:
+ Arg.getAsIntegral()->Profile(ID);
+ VisitType(Arg.getIntegralType());
+ break;
+
+ case TemplateArgument::Expression:
+ Visit(Arg.getAsExpr());
+ break;
+
+ case TemplateArgument::Pack:
+ VisitTemplateArguments(Arg.pack_begin(), Arg.pack_size());
+ break;
+ }
+ }
+}
+
+void Stmt::Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context,
+ bool Canonical) {
+ StmtProfiler Profiler(ID, Context, Canonical);
+ Profiler.Visit(this);
+}
diff --git a/lib/AST/StmtViz.cpp b/lib/AST/StmtViz.cpp
index 96b5218..61fd750 100644
--- a/lib/AST/StmtViz.cpp
+++ b/lib/AST/StmtViz.cpp
@@ -15,7 +15,6 @@
#include "clang/AST/StmtGraphTraits.h"
#include "clang/AST/Decl.h"
#include "llvm/Support/GraphWriter.h"
-#include <sstream>
using namespace clang;
@@ -23,8 +22,8 @@ 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";
+ llvm::errs() << "Stmt::viewAST is only available in debug builds on "
+ << "systems with Graphviz or gv!\n";
#endif
}
@@ -33,26 +32,26 @@ template<>
struct DOTGraphTraits<const Stmt*> : public DefaultDOTGraphTraits {
static std::string getNodeLabel(const Stmt* Node, const Stmt* Graph,
bool ShortNames) {
-
+
#ifndef NDEBUG
std::string OutSStr;
llvm::raw_string_ostream Out(OutSStr);
-
+
if (Node)
Out << Node->getStmtClassName();
else
Out << "<NULL>";
-
- std::string OutStr = Out.str();
+
+ 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 "";
diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp
index 5b671c1..24588bc 100644
--- a/lib/AST/TemplateName.cpp
+++ b/lib/AST/TemplateName.cpp
@@ -22,39 +22,55 @@ 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;
}
+OverloadedFunctionDecl *TemplateName::getAsOverloadedFunctionDecl() const {
+ if (OverloadedFunctionDecl *Ovl
+ = Storage.dyn_cast<OverloadedFunctionDecl *>())
+ return Ovl;
+
+ if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName())
+ return QTN->getOverloadedFunctionDecl();
+
+ 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 isa<TemplateTemplateParmDecl>(Template) ||
+ Template->getDeclContext()->isDependentContext();
}
+ if (OverloadedFunctionDecl *Ovl = getAsOverloadedFunctionDecl())
+ return Ovl->getDeclContext()->isDependentContext();
+
return true;
}
-void
+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 (OverloadedFunctionDecl *Ovl
+ = Storage.dyn_cast<OverloadedFunctionDecl *>())
+ OS << Ovl->getNameAsString();
else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) {
if (!SuppressNNS)
QTN->getQualifier()->print(OS, Policy);
if (QTN->hasTemplateKeyword())
OS << "template ";
- OS << QTN->getTemplateDecl()->getIdentifier()->getName();
+ OS << QTN->getDecl()->getNameAsString();
} else if (DependentTemplateName *DTN = getAsDependentTemplateName()) {
- if (!SuppressNNS)
+ if (!SuppressNNS && DTN->getQualifier())
DTN->getQualifier()->print(OS, Policy);
OS << "template ";
+ // FIXME: Shouldn't we have a more general kind of name?
OS << DTN->getName()->getName();
}
}
@@ -65,3 +81,13 @@ void TemplateName::dump() const {
LO.Bool = true;
print(llvm::errs(), PrintingPolicy(LO));
}
+
+TemplateDecl *QualifiedTemplateName::getTemplateDecl() const {
+ return dyn_cast<TemplateDecl>(Template);
+}
+
+OverloadedFunctionDecl *
+QualifiedTemplateName::getOverloadedFunctionDecl() const {
+ return dyn_cast<OverloadedFunctionDecl>(Template);
+}
+
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 4e061a9..0293862 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -22,12 +22,12 @@
#include "llvm/Support/raw_ostream.h"
using namespace clang;
-bool QualType::isConstant(ASTContext &Ctx) const {
- if (isConstQualified())
+bool QualType::isConstant(QualType T, ASTContext &Ctx) {
+ if (T.isConstQualified())
return true;
- if (getTypePtr()->isArrayType())
- return Ctx.getAsArrayType(*this)->getElementType().isConstant(Ctx);
+ if (const ArrayType *AT = Ctx.getAsArrayType(T))
+ return AT->getElementType().isConstant(Ctx);
return false;
}
@@ -37,6 +37,18 @@ void Type::Destroy(ASTContext& C) {
C.Deallocate(this);
}
+void ConstantArrayWithExprType::Destroy(ASTContext& C) {
+ // FIXME: destruction of SizeExpr commented out due to resource contention.
+ // SizeExpr->Destroy(C);
+ // See FIXME in SemaDecl.cpp:1536: if we were able to either steal
+ // or clone the SizeExpr there, then here we could freely delete it.
+ // Since we do not know how to steal or clone, we keep a pointer to
+ // a shared resource, but we cannot free it.
+ // (There probably is a trivial solution ... for people knowing clang!).
+ this->~ConstantArrayWithExprType();
+ C.Deallocate(this);
+}
+
void VariableArrayType::Destroy(ASTContext& C) {
if (SizeExpr)
SizeExpr->Destroy(C);
@@ -45,14 +57,37 @@ void VariableArrayType::Destroy(ASTContext& C) {
}
void DependentSizedArrayType::Destroy(ASTContext& C) {
- SizeExpr->Destroy(C);
+ // FIXME: Resource contention like in ConstantArrayWithExprType ?
+ // May crash, depending on platform or a particular build.
+ // SizeExpr->Destroy(C);
this->~DependentSizedArrayType();
C.Deallocate(this);
}
+void DependentSizedArrayType::Profile(llvm::FoldingSetNodeID &ID,
+ ASTContext &Context,
+ QualType ET,
+ ArraySizeModifier SizeMod,
+ unsigned TypeQuals,
+ Expr *E) {
+ ID.AddPointer(ET.getAsOpaquePtr());
+ ID.AddInteger(SizeMod);
+ ID.AddInteger(TypeQuals);
+ E->Profile(ID, Context, true);
+}
+
+void
+DependentSizedExtVectorType::Profile(llvm::FoldingSetNodeID &ID,
+ ASTContext &Context,
+ QualType ElementType, Expr *SizeExpr) {
+ ID.AddPointer(ElementType.getAsOpaquePtr());
+ SizeExpr->Profile(ID, Context, true);
+}
+
void DependentSizedExtVectorType::Destroy(ASTContext& C) {
- if (SizeExpr)
- SizeExpr->Destroy(C);
+ // FIXME: Deallocate size expression, once we're cloning properly.
+// if (SizeExpr)
+// SizeExpr->Destroy(C);
this->~DependentSizedExtVectorType();
C.Deallocate(this);
}
@@ -64,18 +99,15 @@ 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();
+ if (!isa<ArrayType>(CanonicalType))
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();
+ return cast<ArrayType>(getUnqualifiedDesugaredType())
+ ->getElementType().getTypePtr();
}
/// getDesugaredType - Return the specified type with any "sugar" removed from
@@ -84,66 +116,52 @@ const Type *Type::getArrayElementTypeNoTypeQual() const {
/// 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());
+QualType QualType::getDesugaredType(QualType T) {
+ QualifierCollector Qs;
+
+ QualType Cur = T;
+ while (true) {
+ const Type *CurTy = Qs.strip(Cur);
+ switch (CurTy->getTypeClass()) {
+#define ABSTRACT_TYPE(Class, Parent)
+#define TYPE(Class, Parent) \
+ case Type::Class: { \
+ const Class##Type *Ty = cast<Class##Type>(CurTy); \
+ if (!Ty->isSugared()) \
+ return Qs.apply(Cur); \
+ Cur = Ty->desugar(); \
+ break; \
+ }
+#include "clang/AST/TypeNodes.def"
+ }
+ }
}
-/// 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 DecltypeType *DTT = dyn_cast<DecltypeType>(this))
- return DTT->getUnderlyingExpr()->getType().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();
+/// getUnqualifiedDesugaredType - Pull any qualifiers and syntactic
+/// sugar off the given type. This should produce an object of the
+/// same dynamic type as the canonical type.
+const Type *Type::getUnqualifiedDesugaredType() const {
+ const Type *Cur = this;
+
+ while (true) {
+ switch (Cur->getTypeClass()) {
+#define ABSTRACT_TYPE(Class, Parent)
+#define TYPE(Class, Parent) \
+ case Class: { \
+ const Class##Type *Ty = cast<Class##Type>(Cur); \
+ if (!Ty->isSugared()) return Cur; \
+ Cur = Ty->desugar().getTypePtr(); \
+ break; \
+ }
+#include "clang/AST/TypeNodes.def"
+ }
}
-
- 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;
}
@@ -151,18 +169,16 @@ 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 ConstantArrayWithExpr:
+ case ConstantArrayWithoutExpr:
case IncompleteArray:
case FunctionProto:
case FunctionNoProto:
@@ -176,23 +192,23 @@ bool Type::isDerivedType() const {
}
bool Type::isClassType() const {
- if (const RecordType *RT = getAsRecordType())
+ if (const RecordType *RT = getAs<RecordType>())
return RT->getDecl()->isClass();
return false;
}
bool Type::isStructureType() const {
- if (const RecordType *RT = getAsRecordType())
+ if (const RecordType *RT = getAs<RecordType>())
return RT->getDecl()->isStruct();
return false;
}
bool Type::isVoidPointerType() const {
- if (const PointerType *PT = getAsPointerType())
+ if (const PointerType *PT = getAs<PointerType>())
return PT->getPointeeType()->isVoidType();
return false;
}
bool Type::isUnionType() const {
- if (const RecordType *RT = getAsRecordType())
+ if (const RecordType *RT = getAs<RecordType>())
return RT->getDecl()->isUnion();
return false;
}
@@ -200,192 +216,29 @@ bool Type::isUnionType() const {
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;
+ return getAsComplexIntegerType();
}
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());
+ if (const ComplexType *Complex = getAs<ComplexType>())
+ if (Complex->getElementType()->isIntegerType())
+ return Complex;
+ return 0;
}
-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());
+QualType Type::getPointeeType() const {
+ if (const PointerType *PT = getAs<PointerType>())
+ return PT->getPointeeType();
+ if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>())
+ return OPT->getPointeeType();
+ if (const BlockPointerType *BPT = getAs<BlockPointerType>())
+ return BPT->getPointeeType();
+ return QualType();
}
/// isVariablyModifiedType (C99 6.7.5p3) - Return true for variable length
@@ -404,59 +257,23 @@ bool Type::isVariablyModifiedType() const {
// 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())
+ if (const PointerType *PT = getAs<PointerType>())
return PT->getPointeeType()->isVariablyModifiedType();
- if (const ReferenceType *RT = getAsReferenceType())
+ if (const ReferenceType *RT = getAs<ReferenceType>())
return RT->getPointeeType()->isVariablyModifiedType();
- if (const MemberPointerType *PT = getAsMemberPointerType())
+ if (const MemberPointerType *PT = getAs<MemberPointerType>())
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())
+ if (const FunctionType *FT = getAs<FunctionType>())
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)) {
@@ -468,24 +285,21 @@ const RecordType *Type::getAsStructureType() const {
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());
+ return cast<RecordType>(getUnqualifiedDesugaredType());
}
- // Look through type qualifiers
- if (isa<RecordType>(CanonicalType.getUnqualifiedType()))
- return CanonicalType.getUnqualifiedType()->getAsStructureType();
return 0;
}
-const RecordType *Type::getAsUnionType() const {
+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())
@@ -493,118 +307,49 @@ const RecordType *Type::getAsUnionType() const {
// 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;
+ return cast<RecordType>(getUnqualifiedDesugaredType());
}
- // 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());
+ return 0;
}
-const ObjCInterfaceType *Type::getAsObjCInterfaceType() const {
+const ObjCInterfaceType *Type::getAsObjCQualifiedInterfaceType() 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 ObjCObjectPointerType *Type::getAsObjCObjectPointerType() const {
- // There is no sugar for ObjCObjectPointerType's, just return the
- // canonical type pointer if it is the right class.
- return dyn_cast<ObjCObjectPointerType>(CanonicalType.getUnqualifiedType());
+ if (const ObjCInterfaceType *OIT = getAs<ObjCInterfaceType>())
+ if (OIT->getNumProtocols())
+ return OIT;
+ return 0;
}
-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());
+bool Type::isObjCQualifiedInterfaceType() const {
+ return getAsObjCQualifiedInterfaceType() != 0;
}
const ObjCObjectPointerType *Type::getAsObjCQualifiedIdType() const {
// There is no sugar for ObjCQualifiedIdType's, just return the canonical
// type pointer if it is the right class.
- if (const ObjCObjectPointerType *OPT = getAsObjCObjectPointerType()) {
+ if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) {
if (OPT->isObjCQualifiedIdType())
return OPT;
}
return 0;
}
-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 ObjCObjectPointerType *Type::getAsObjCInterfacePointerType() const {
+ if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) {
+ if (OPT->getInterfaceType())
+ return OPT;
+ }
+ return 0;
}
-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);
+const CXXRecordDecl *Type::getCXXRecordDeclForPointerType() const {
+ if (const PointerType *PT = getAs<PointerType>())
+ if (const RecordType *RT = PT->getPointeeType()->getAs<RecordType>())
+ return dyn_cast<CXXRecordDecl>(RT->getDecl());
+ return 0;
}
bool Type::isIntegerType() const {
@@ -620,8 +365,6 @@ bool Type::isIntegerType() const {
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;
}
@@ -635,24 +378,18 @@ bool Type::isIntegralType() const {
// 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;
}
@@ -662,16 +399,12 @@ bool Type::isCharType() const {
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;
}
@@ -684,18 +417,16 @@ bool Type::isSignedIntegerType() const {
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;
}
@@ -718,8 +449,6 @@ bool Type::isUnsignedIntegerType() const {
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;
}
@@ -731,8 +460,6 @@ bool Type::isFloatingType() const {
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;
}
@@ -742,8 +469,6 @@ bool Type::isRealFloatingType() const {
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;
}
@@ -757,8 +482,6 @@ bool Type::isRealType() const {
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;
}
@@ -772,8 +495,6 @@ bool Type::isArithmeticType() const {
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);
}
@@ -787,8 +508,6 @@ bool Type::isScalarType() const {
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) ||
@@ -815,8 +534,6 @@ bool Type::isAggregateType() const {
return true;
}
- if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
- return EXTQT->getBaseType()->isAggregateType();
return isa<ArrayType>(CanonicalType);
}
@@ -824,8 +541,6 @@ bool Type::isAggregateType() const {
/// 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.
@@ -835,11 +550,9 @@ bool Type::isConstantSizeType() const {
/// 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()) {
+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.
@@ -853,7 +566,6 @@ bool Type::isIncompleteType() const {
// 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();
}
@@ -869,8 +581,6 @@ bool Type::isPODType() const {
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.
@@ -889,7 +599,7 @@ bool Type::isPODType() const {
return true;
case Record:
- if (CXXRecordDecl *ClassDecl
+ if (CXXRecordDecl *ClassDecl
= dyn_cast<CXXRecordDecl>(cast<RecordType>(CanonicalType)->getDecl()))
return ClassDecl->isPOD();
@@ -899,7 +609,7 @@ bool Type::isPODType() const {
}
bool Type::isPromotableIntegerType() const {
- if (const BuiltinType *BT = getAsBuiltinType())
+ if (const BuiltinType *BT = getAs<BuiltinType>())
switch (BT->getKind()) {
case BuiltinType::Bool:
case BuiltinType::Char_S:
@@ -909,14 +619,14 @@ bool Type::isPromotableIntegerType() const {
case BuiltinType::Short:
case BuiltinType::UShort:
return true;
- default:
+ default:
return false;
}
return false;
}
bool Type::isNullPtrType() const {
- if (const BuiltinType *BT = getAsBuiltinType())
+ if (const BuiltinType *BT = getAs<BuiltinType>())
return BT->getKind() == BuiltinType::NullPtr;
return false;
}
@@ -936,7 +646,6 @@ bool Type::isSpecifierType() const {
case QualifiedName:
case Typename:
case ObjCInterface:
- case ObjCQualifiedInterface:
case ObjCObjectPointer:
return true;
default:
@@ -944,6 +653,15 @@ bool Type::isSpecifierType() const {
}
}
+const char *Type::getTypeClassName() const {
+ switch (TC) {
+ default: assert(0 && "Type class not in TypeNodes.def!");
+#define ABSTRACT_TYPE(Derived, Base)
+#define TYPE(Derived, Base) case Derived: return #Derived;
+#include "clang/AST/TypeNodes.def"
+ }
+}
+
const char *BuiltinType::getName(const LangOptions &LO) const {
switch (getKind()) {
default: assert(0 && "Unknown builtin type!");
@@ -967,10 +685,14 @@ const char *BuiltinType::getName(const LangOptions &LO) const {
case Double: return "double";
case LongDouble: return "long double";
case WChar: return "wchar_t";
+ case Char16: return "char16_t";
+ case Char32: return "char32_t";
case NullPtr: return "nullptr_t";
case Overload: return "<overloaded function type>";
case Dependent: return "<dependent type>";
- case UndeducedAuto: return "<undeduced auto type>";
+ case UndeducedAuto: return "auto";
+ case ObjCId: return "id";
+ case ObjCClass: return "Class";
}
}
@@ -979,7 +701,7 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
unsigned NumArgs, bool isVariadic,
unsigned TypeQuals, bool hasExceptionSpec,
bool anyExceptionSpec, unsigned NumExceptions,
- exception_iterator Exs) {
+ exception_iterator Exs, bool NoReturn) {
ID.AddPointer(Result.getAsOpaquePtr());
for (unsigned i = 0; i != NumArgs; ++i)
ID.AddPointer(ArgTys[i].getAsOpaquePtr());
@@ -988,41 +710,43 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
ID.AddInteger(hasExceptionSpec);
if (hasExceptionSpec) {
ID.AddInteger(anyExceptionSpec);
- for(unsigned i = 0; i != NumExceptions; ++i)
+ for (unsigned i = 0; i != NumExceptions; ++i)
ID.AddPointer(Exs[i].getAsOpaquePtr());
}
+ ID.AddInteger(NoReturn);
}
void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, getResultType(), arg_type_begin(), NumArgs, isVariadic(),
getTypeQuals(), hasExceptionSpec(), hasAnyExceptionSpec(),
- getNumExceptions(), exception_begin());
+ getNumExceptions(), exception_begin(), getNoReturnAttr());
}
void ObjCObjectPointerType::Profile(llvm::FoldingSetNodeID &ID,
- const ObjCInterfaceDecl *Decl,
- ObjCProtocolDecl **protocols,
+ QualType OIT, ObjCProtocolDecl **protocols,
unsigned NumProtocols) {
- ID.AddPointer(Decl);
+ ID.AddPointer(OIT.getAsOpaquePtr());
for (unsigned i = 0; i != NumProtocols; i++)
ID.AddPointer(protocols[i]);
}
void ObjCObjectPointerType::Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getDecl(), &Protocols[0], getNumProtocols());
+ if (getNumProtocols())
+ Profile(ID, getPointeeType(), &Protocols[0], getNumProtocols());
+ else
+ Profile(ID, getPointeeType(), 0, 0);
}
-void ObjCQualifiedInterfaceType::Profile(llvm::FoldingSetNodeID &ID,
- const ObjCInterfaceDecl *Decl,
- ObjCProtocolDecl **protocols,
- unsigned NumProtocols) {
- ID.AddPointer(Decl);
+void ObjCProtocolListType::Profile(llvm::FoldingSetNodeID &ID,
+ QualType OIT, ObjCProtocolDecl **protocols,
+ unsigned NumProtocols) {
+ ID.AddPointer(OIT.getAsOpaquePtr());
for (unsigned i = 0; i != NumProtocols; i++)
ID.AddPointer(protocols[i]);
}
-void ObjCQualifiedInterfaceType::Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getDecl(), &Protocols[0], getNumProtocols());
+void ObjCProtocolListType::Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getBaseType(), &Protocols[0], getNumProtocols());
}
/// LookThroughTypedefs - Return the ultimate type this typedef corresponds to
@@ -1037,38 +761,51 @@ QualType TypedefType::LookThroughTypedefs() const {
QualType FirstType = getDecl()->getUnderlyingType();
if (!isa<TypedefType>(FirstType))
return FirstType;
-
+
// Otherwise, do the fully general loop.
- unsigned TypeQuals = 0;
+ QualifierCollector Qs;
+
+ QualType CurType;
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);
- }
+ do {
+ CurType = TDT->getDecl()->getUnderlyingType();
+ TDT = dyn_cast<TypedefType>(Qs.strip(CurType));
+ } while (TDT);
+
+ return Qs.apply(CurType);
+}
+
+QualType TypedefType::desugar() const {
+ return getDecl()->getUnderlyingType();
}
TypeOfExprType::TypeOfExprType(Expr *E, QualType can)
: Type(TypeOfExpr, can, E->isTypeDependent()), TOExpr(E) {
- assert(!isa<TypedefType>(can) && "Invalid canonical type");
}
-DecltypeType::DecltypeType(Expr *E, QualType can)
- : Type(Decltype, can, E->isTypeDependent()), E(E) {
- assert(can->isDependentType() == E->isTypeDependent() &&
- "type dependency mismatch!");
- assert(!isa<TypedefType>(can) && "Invalid canonical type");
+QualType TypeOfExprType::desugar() const {
+ return getUnderlyingExpr()->getType();
+}
+
+void DependentTypeOfExprType::Profile(llvm::FoldingSetNodeID &ID,
+ ASTContext &Context, Expr *E) {
+ E->Profile(ID, Context, true);
}
-TagType::TagType(TypeClass TC, TagDecl *D, QualType can)
+DecltypeType::DecltypeType(Expr *E, QualType underlyingType, QualType can)
+ : Type(Decltype, can, E->isTypeDependent()), E(E),
+ UnderlyingType(underlyingType) {
+}
+
+DependentDecltypeType::DependentDecltypeType(ASTContext &Context, Expr *E)
+ : DecltypeType(E, Context.DependentTy), Context(Context) { }
+
+void DependentDecltypeType::Profile(llvm::FoldingSetNodeID &ID,
+ ASTContext &Context, Expr *E) {
+ E->Profile(ID, Context, true);
+}
+
+TagType::TagType(TypeClass TC, TagDecl *D, QualType can)
: Type(TC, can, D->isDependentType()), decl(D, 0) {}
bool RecordType::classof(const TagType *TT) {
@@ -1079,7 +816,7 @@ bool EnumType::classof(const TagType *TT) {
return isa<EnumDecl>(TT->getDecl());
}
-bool
+bool
TemplateSpecializationType::
anyDependentTemplateArguments(const TemplateArgument *Args, unsigned NumArgs) {
for (unsigned Idx = 0; Idx < NumArgs; ++Idx) {
@@ -1087,12 +824,12 @@ anyDependentTemplateArguments(const TemplateArgument *Args, unsigned NumArgs) {
case TemplateArgument::Null:
assert(false && "Should not have a NULL template argument");
break;
-
+
case TemplateArgument::Type:
if (Args[Idx].getAsType()->isDependentType())
return true;
break;
-
+
case TemplateArgument::Declaration:
case TemplateArgument::Integral:
// Never dependent
@@ -1103,7 +840,7 @@ anyDependentTemplateArguments(const TemplateArgument *Args, unsigned NumArgs) {
Args[Idx].getAsExpr()->isValueDependent())
return true;
break;
-
+
case TemplateArgument::Pack:
assert(0 && "FIXME: Implement!");
break;
@@ -1114,18 +851,19 @@ anyDependentTemplateArguments(const TemplateArgument *Args, unsigned NumArgs) {
}
TemplateSpecializationType::
-TemplateSpecializationType(TemplateName T, const TemplateArgument *Args,
+TemplateSpecializationType(ASTContext &Context, TemplateName T,
+ const TemplateArgument *Args,
unsigned NumArgs, QualType Canon)
- : Type(TemplateSpecialization,
+ : Type(TemplateSpecialization,
Canon.isNull()? QualType(this, 0) : Canon,
T.isDependent() || anyDependentTemplateArguments(Args, NumArgs)),
- Template(T), NumArgs(NumArgs)
-{
- assert((!Canon.isNull() ||
+ Context(Context),
+ Template(T), NumArgs(NumArgs) {
+ assert((!Canon.isNull() ||
T.isDependent() || anyDependentTemplateArguments(Args, NumArgs)) &&
"No canonical type for non-dependent class template specialization");
- TemplateArgument *TemplateArgs
+ TemplateArgument *TemplateArgs
= reinterpret_cast<TemplateArgument *>(this + 1);
for (unsigned Arg = 0; Arg < NumArgs; ++Arg)
new (&TemplateArgs[Arg]) TemplateArgument(Args[Arg]);
@@ -1151,16 +889,34 @@ TemplateSpecializationType::getArg(unsigned Idx) const {
return getArgs()[Idx];
}
-void
-TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID,
- TemplateName T,
- const TemplateArgument *Args,
- unsigned NumArgs) {
+void
+TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID,
+ TemplateName T,
+ const TemplateArgument *Args,
+ unsigned NumArgs,
+ ASTContext &Context) {
T.Profile(ID);
for (unsigned Idx = 0; Idx < NumArgs; ++Idx)
- Args[Idx].Profile(ID);
+ Args[Idx].Profile(ID, Context);
+}
+
+QualType QualifierCollector::apply(QualType QT) const {
+ if (!hasNonFastQualifiers())
+ return QT.withFastQualifiers(getFastQualifiers());
+
+ assert(Context && "extended qualifiers but no context!");
+ return Context->getQualifiedType(QT, *this);
+}
+
+QualType QualifierCollector::apply(const Type *T) const {
+ if (!hasNonFastQualifiers())
+ return QualType(T, getFastQualifiers());
+
+ assert(Context && "extended qualifiers but no context!");
+ return Context->getQualifiedType(T, *this);
}
+
//===----------------------------------------------------------------------===//
// Type Printing
//===----------------------------------------------------------------------===//
@@ -1188,14 +944,46 @@ void Type::dump() const {
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;
+ if (TypeQuals & Qualifiers::Const) {
+ if (!S.empty()) S += ' ';
+ S += "const";
+ }
+ if (TypeQuals & Qualifiers::Volatile) {
+ if (!S.empty()) S += ' ';
+ S += "volatile";
+ }
+ if (TypeQuals & Qualifiers::Restrict) {
+ if (!S.empty()) S += ' ';
+ S += "restrict";
+ }
+}
+
+std::string Qualifiers::getAsString() const {
+ LangOptions LO;
+ return getAsString(PrintingPolicy(LO));
+}
+
+// Appends qualifiers to the given string, separated by spaces. Will
+// prefix a space if the string is non-empty. Will not append a final
+// space.
+void Qualifiers::getAsStringInternal(std::string &S,
+ const PrintingPolicy&) const {
+ AppendTypeQualList(S, getCVRQualifiers());
+ if (unsigned AddressSpace = getAddressSpace()) {
+ if (!S.empty()) S += ' ';
+ S += "__attribute__((address_space(";
+ S += llvm::utostr_32(AddressSpace);
+ S += ")))";
+ }
+ if (Qualifiers::GC GCAttrType = getObjCGCAttr()) {
+ if (!S.empty()) S += ' ';
+ S += "__attribute__((objc_gc(";
+ if (GCAttrType == Qualifiers::Weak)
+ S += "weak";
+ else
+ S += "strong";
+ S += ")))";
+ }
}
std::string QualType::getAsString() const {
@@ -1205,8 +993,8 @@ std::string QualType::getAsString() const {
return S;
}
-void
-QualType::getAsStringInternal(std::string &S,
+void
+QualType::getAsStringInternal(std::string &S,
const PrintingPolicy &Policy) const {
if (isNull()) {
S += "NULL TYPE";
@@ -1217,19 +1005,22 @@ QualType::getAsStringInternal(std::string &S,
return;
// Print qualifiers as appropriate.
- if (unsigned Tq = getCVRQualifiers()) {
+ Qualifiers Quals = getQualifiers();
+ if (!Quals.empty()) {
std::string TQS;
- AppendTypeQualList(TQS, Tq);
- if (!S.empty())
- S = TQS + ' ' + S;
- else
- S = TQS;
+ Quals.getAsStringInternal(TQS, Policy);
+
+ if (!S.empty()) {
+ TQS += ' ';
+ TQS += S;
+ }
+ std::swap(S, TQS);
}
getTypePtr()->getAsStringInternal(S, Policy);
}
-void BuiltinType::getAsStringInternal(std::string &S,
+void BuiltinType::getAsStringInternal(std::string &S,
const PrintingPolicy &Policy) const {
if (S.empty()) {
S = getName(Policy.LangOpts);
@@ -1260,33 +1051,14 @@ void ComplexType::getAsStringInternal(std::string &S, const PrintingPolicy &Poli
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);
}
@@ -1335,10 +1107,33 @@ void ConstantArrayType::getAsStringInternal(std::string &S, const PrintingPolicy
S += '[';
S += llvm::utostr(getSize().getZExtValue());
S += ']';
-
+
getElementType().getAsStringInternal(S, Policy);
}
+void ConstantArrayWithExprType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
+ if (Policy.ConstantArraySizeAsWritten) {
+ std::string SStr;
+ llvm::raw_string_ostream s(SStr);
+ getSizeExpr()->printPretty(s, 0, Policy);
+ S += '[';
+ S += s.str();
+ S += ']';
+ getElementType().getAsStringInternal(S, Policy);
+ }
+ else
+ ConstantArrayType::getAsStringInternal(S, Policy);
+}
+
+void ConstantArrayWithoutExprType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
+ if (Policy.ConstantArraySizeAsWritten) {
+ S += "[]";
+ getElementType().getAsStringInternal(S, Policy);
+ }
+ else
+ ConstantArrayType::getAsStringInternal(S, Policy);
+}
+
void IncompleteArrayType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
S += "[]";
@@ -1347,17 +1142,17 @@ void IncompleteArrayType::getAsStringInternal(std::string &S, const PrintingPoli
void VariableArrayType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
S += '[';
-
- if (getIndexTypeQualifier()) {
- AppendTypeQualList(S, getIndexTypeQualifier());
+
+ if (getIndexTypeQualifiers().hasQualifiers()) {
+ AppendTypeQualList(S, getIndexTypeCVRQualifiers());
S += ' ';
}
-
+
if (getSizeModifier() == Static)
S += "static";
else if (getSizeModifier() == Star)
S += '*';
-
+
if (getSizeExpr()) {
std::string SStr;
llvm::raw_string_ostream s(SStr);
@@ -1365,23 +1160,23 @@ void VariableArrayType::getAsStringInternal(std::string &S, const PrintingPolicy
S += s.str();
}
S += ']';
-
+
getElementType().getAsStringInternal(S, Policy);
}
void DependentSizedArrayType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
S += '[';
-
- if (getIndexTypeQualifier()) {
- AppendTypeQualList(S, getIndexTypeQualifier());
+
+ if (getIndexTypeQualifiers().hasQualifiers()) {
+ AppendTypeQualList(S, getIndexTypeCVRQualifiers());
S += ' ';
}
-
+
if (getSizeModifier() == Static)
S += "static";
else if (getSizeModifier() == Star)
S += '*';
-
+
if (getSizeExpr()) {
std::string SStr;
llvm::raw_string_ostream s(SStr);
@@ -1389,7 +1184,7 @@ void DependentSizedArrayType::getAsStringInternal(std::string &S, const Printing
S += s.str();
}
S += ']';
-
+
getElementType().getAsStringInternal(S, Policy);
}
@@ -1439,7 +1234,7 @@ void TypeOfType::getAsStringInternal(std::string &InnerString, const PrintingPol
InnerString = "typeof(" + Tmp + ")" + InnerString;
}
-void DecltypeType::getAsStringInternal(std::string &InnerString,
+void DecltypeType::getAsStringInternal(std::string &InnerString,
const PrintingPolicy &Policy) const {
if (!InnerString.empty()) // Prefix the basic type, e.g. 'decltype(t) X'.
InnerString = ' ' + InnerString;
@@ -1453,8 +1248,10 @@ void FunctionNoProtoType::getAsStringInternal(std::string &S, const PrintingPoli
// If needed for precedence reasons, wrap the inner part in grouping parens.
if (!S.empty())
S = "(" + S + ")";
-
+
S += "()";
+ if (getNoReturnAttr())
+ S += " __attribute__((noreturn))";
getResultType().getAsStringInternal(S, Policy);
}
@@ -1462,7 +1259,7 @@ void FunctionProtoType::getAsStringInternal(std::string &S, const PrintingPolicy
// If needed for precedence reasons, wrap the inner part in grouping parens.
if (!S.empty())
S = "(" + S + ")";
-
+
S += "(";
std::string Tmp;
PrintingPolicy ParamPolicy(Policy);
@@ -1473,7 +1270,7 @@ void FunctionProtoType::getAsStringInternal(std::string &S, const PrintingPolicy
S += Tmp;
Tmp.clear();
}
-
+
if (isVariadic()) {
if (getNumArgs())
S += ", ";
@@ -1482,8 +1279,10 @@ void FunctionProtoType::getAsStringInternal(std::string &S, const PrintingPolicy
// Do not emit int() if we have a proto, emit 'int(void)'.
S += "void";
}
-
+
S += ")";
+ if (getNoReturnAttr())
+ S += " __attribute__((noreturn))";
getResultType().getAsStringInternal(S, Policy);
}
@@ -1499,13 +1298,13 @@ void TemplateTypeParmType::getAsStringInternal(std::string &InnerString, const P
InnerString = ' ' + InnerString;
if (!Name)
- InnerString = "type-parameter-" + llvm::utostr_32(Depth) + '-' +
+ InnerString = "type-parameter-" + llvm::utostr_32(Depth) + '-' +
llvm::utostr_32(Index) + InnerString;
else
InnerString = Name->getName() + InnerString;
}
-std::string
+std::string
TemplateSpecializationType::PrintTemplateArgumentList(
const TemplateArgument *Args,
unsigned NumArgs,
@@ -1515,7 +1314,7 @@ TemplateSpecializationType::PrintTemplateArgumentList(
for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
if (Arg)
SpecString += ", ";
-
+
// Print the argument into a string.
std::string ArgString;
switch (Args[Arg].getKind()) {
@@ -1565,7 +1364,7 @@ TemplateSpecializationType::PrintTemplateArgumentList(
return SpecString;
}
-void
+void
TemplateSpecializationType::
getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
std::string SpecString;
@@ -1589,10 +1388,11 @@ void QualifiedNameType::getAsStringInternal(std::string &InnerString, const Prin
llvm::raw_string_ostream OS(MyString);
NNS->print(OS, Policy);
}
-
+
std::string TypeStr;
PrintingPolicy InnerPolicy(Policy);
InnerPolicy.SuppressTagKind = true;
+ InnerPolicy.SuppressScope = true;
NamedType.getAsStringInternal(TypeStr, InnerPolicy);
MyString += TypeStr;
@@ -1615,35 +1415,65 @@ void TypenameType::getAsStringInternal(std::string &InnerString, const PrintingP
else if (const TemplateSpecializationType *Spec = getTemplateId()) {
Spec->getTemplateName().print(OS, Policy, true);
OS << TemplateSpecializationType::PrintTemplateArgumentList(
- Spec->getArgs(),
+ 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 ObjCInterfaceType::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 ObjCObjectPointerType::getAsStringInternal(std::string &InnerString,
- const PrintingPolicy &Policy) const {
+void ObjCInterfaceType::Profile(llvm::FoldingSetNodeID &ID) {
+ if (getNumProtocols())
+ Profile(ID, getDecl(), &Protocols[0], getNumProtocols());
+ else
+ Profile(ID, getDecl(), 0, 0);
+}
+
+void ObjCInterfaceType::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();
+ if (getNumProtocols()) {
+ 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 ObjCObjectPointerType::getAsStringInternal(std::string &InnerString,
+ const PrintingPolicy &Policy) const {
std::string ObjCQIString;
-
- if (getDecl())
- ObjCQIString = getDecl()->getNameAsString();
- else
+
+ if (isObjCIdType() || isObjCQualifiedIdType())
ObjCQIString = "id";
+ else if (isObjCClassType() || isObjCQualifiedClassType())
+ ObjCQIString = "Class";
+ else
+ ObjCQIString = getInterfaceDecl()->getNameAsString();
if (!qual_empty()) {
ObjCQIString += '<';
@@ -1654,15 +1484,23 @@ void ObjCObjectPointerType::getAsStringInternal(std::string &InnerString,
}
ObjCQIString += '>';
}
+
+ PointeeType.getQualifiers().getAsStringInternal(ObjCQIString, Policy);
+
+ if (!isObjCIdType() && !isObjCQualifiedIdType())
+ ObjCQIString += " *"; // Don't forget the implicit pointer.
+ else if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
+ InnerString = ' ' + InnerString;
+
InnerString = ObjCQIString + InnerString;
}
-void
-ObjCQualifiedInterfaceType::getAsStringInternal(std::string &InnerString,
+void ObjCProtocolListType::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();
+
+ std::string ObjCQIString = getBaseType().getAsString(Policy);
ObjCQIString += '<';
bool isFirst = true;
for (qual_iterator I = qual_begin(), E = qual_end(); I != E; ++I) {
@@ -1676,13 +1514,23 @@ ObjCQualifiedInterfaceType::getAsStringInternal(std::string &InnerString,
InnerString = ObjCQIString + InnerString;
}
+void ElaboratedType::getAsStringInternal(std::string &InnerString,
+ const PrintingPolicy &Policy) const {
+ std::string TypeStr;
+ PrintingPolicy InnerPolicy(Policy);
+ InnerPolicy.SuppressTagKind = true;
+ UnderlyingType.getAsStringInternal(InnerString, InnerPolicy);
+
+ InnerString = std::string(getNameForTagKind(getTagKind())) + ' ' + 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())
@@ -1696,10 +1544,10 @@ void TagType::getAsStringInternal(std::string &InnerString, const PrintingPolicy
// If this is a class template specialization, print the template
// arguments.
- if (ClassTemplateSpecializationDecl *Spec
+ if (ClassTemplateSpecializationDecl *Spec
= dyn_cast<ClassTemplateSpecializationDecl>(getDecl())) {
const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
- std::string TemplateArgsStr
+ std::string TemplateArgsStr
= TemplateSpecializationType::PrintTemplateArgumentList(
TemplateArgs.getFlatArgumentList(),
TemplateArgs.flat_size(),
@@ -1707,17 +1555,17 @@ void TagType::getAsStringInternal(std::string &InnerString, const PrintingPolicy
InnerString = TemplateArgsStr + InnerString;
}
- if (Kind) {
+ if (!Policy.SuppressScope) {
// Compute the full nested-name-specifier for this type. In C,
// this will always be empty.
std::string ContextStr;
- for (DeclContext *DC = getDecl()->getDeclContext();
+ 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
+ } else if (ClassTemplateSpecializationDecl *Spec
= dyn_cast<ClassTemplateSpecializationDecl>(DC)) {
const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
std::string TemplateArgsStr
@@ -1737,7 +1585,10 @@ void TagType::getAsStringInternal(std::string &InnerString, const PrintingPolicy
ContextStr = MyPart + "::" + ContextStr;
}
- InnerString = std::string(Kind) + " " + ContextStr + ID + InnerString;
+ if (Kind)
+ InnerString = std::string(Kind) + ' ' + ContextStr + ID + InnerString;
+ else
+ InnerString = ContextStr + ID + InnerString;
} else
InnerString = ID + InnerString;
}
diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp
new file mode 100644
index 0000000..c24477a
--- /dev/null
+++ b/lib/AST/TypeLoc.cpp
@@ -0,0 +1,370 @@
+//===--- TypeLoc.cpp - Type Source Info Wrapper -----------------*- 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 TypeLoc subclasses implementations.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/TypeLocVisitor.h"
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// TypeLoc Implementation
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+/// \brief Return the source range for the visited TypeSpecLoc.
+class TypeLocRanger : public TypeLocVisitor<TypeLocRanger, SourceRange> {
+public:
+#define ABSTRACT_TYPELOC(CLASS)
+#define TYPELOC(CLASS, PARENT, TYPE) \
+ SourceRange Visit##CLASS(CLASS TyLoc) { return TyLoc.getSourceRange(); }
+#include "clang/AST/TypeLocNodes.def"
+
+ SourceRange VisitTypeLoc(TypeLoc TyLoc) {
+ assert(0 && "A typeloc wrapper was not handled!");
+ return SourceRange();
+ }
+};
+
+}
+
+SourceRange TypeLoc::getSourceRange() const {
+ if (isNull())
+ return SourceRange();
+ return TypeLocRanger().Visit(*this);
+}
+
+/// \brief Returns the size of type source info data block for the given type.
+unsigned TypeLoc::getFullDataSizeForType(QualType Ty) {
+ return TypeLoc(Ty, 0).getFullDataSize();
+}
+
+/// \brief Find the TypeSpecLoc that is part of this TypeLoc.
+TypeSpecLoc TypeLoc::getTypeSpecLoc() const {
+ if (isNull())
+ return TypeSpecLoc();
+
+ if (const DeclaratorLoc *DL = dyn_cast<DeclaratorLoc>(this))
+ return DL->getTypeSpecLoc();
+ return cast<TypeSpecLoc>(*this);
+}
+
+/// \brief Find the TypeSpecLoc that is part of this TypeLoc and return its
+/// SourceRange.
+SourceRange TypeLoc::getTypeSpecRange() const {
+ return getTypeSpecLoc().getSourceRange();
+}
+
+namespace {
+
+/// \brief Report the full source info data size for the visited TypeLoc.
+class TypeSizer : public TypeLocVisitor<TypeSizer, unsigned> {
+public:
+#define ABSTRACT_TYPELOC(CLASS)
+#define TYPELOC(CLASS, PARENT, TYPE) \
+ unsigned Visit##CLASS(CLASS TyLoc) { return TyLoc.getFullDataSize(); }
+#include "clang/AST/TypeLocNodes.def"
+
+ unsigned VisitTypeLoc(TypeLoc TyLoc) {
+ assert(0 && "A type loc wrapper was not handled!");
+ return 0;
+ }
+};
+
+}
+
+/// \brief Returns the size of the type source info data block.
+unsigned TypeLoc::getFullDataSize() const {
+ if (isNull()) return 0;
+ return TypeSizer().Visit(*this);
+}
+
+namespace {
+
+/// \brief Return the "next" TypeLoc for the visited TypeLoc, e.g for "int*" the
+/// TypeLoc is a PointerLoc and next TypeLoc is for "int".
+class NextLoc : public TypeLocVisitor<NextLoc, TypeLoc> {
+public:
+#define TYPELOC(CLASS, PARENT, TYPE)
+#define DECLARATOR_TYPELOC(CLASS, TYPE) \
+ TypeLoc Visit##CLASS(CLASS TyLoc);
+#include "clang/AST/TypeLocNodes.def"
+
+ TypeLoc VisitTypeSpecLoc(TypeLoc TyLoc) { return TypeLoc(); }
+ TypeLoc VisitObjCProtocolListLoc(ObjCProtocolListLoc TL);
+
+ TypeLoc VisitTypeLoc(TypeLoc TyLoc) {
+ assert(0 && "A declarator loc wrapper was not handled!");
+ return TypeLoc();
+ }
+};
+
+}
+
+TypeLoc NextLoc::VisitObjCProtocolListLoc(ObjCProtocolListLoc TL) {
+ return TL.getBaseTypeLoc();
+}
+
+TypeLoc NextLoc::VisitPointerLoc(PointerLoc TL) {
+ return TL.getPointeeLoc();
+}
+TypeLoc NextLoc::VisitMemberPointerLoc(MemberPointerLoc TL) {
+ return TL.getPointeeLoc();
+}
+TypeLoc NextLoc::VisitBlockPointerLoc(BlockPointerLoc TL) {
+ return TL.getPointeeLoc();
+}
+TypeLoc NextLoc::VisitReferenceLoc(ReferenceLoc TL) {
+ return TL.getPointeeLoc();
+}
+TypeLoc NextLoc::VisitFunctionLoc(FunctionLoc TL) {
+ return TL.getResultLoc();
+}
+TypeLoc NextLoc::VisitArrayLoc(ArrayLoc TL) {
+ return TL.getElementLoc();
+}
+
+/// \brief Get the next TypeLoc pointed by this TypeLoc, e.g for "int*" the
+/// TypeLoc is a PointerLoc and next TypeLoc is for "int".
+TypeLoc TypeLoc::getNextTypeLoc() const {
+ return NextLoc().Visit(*this);
+}
+
+//===----------------------------------------------------------------------===//
+// TypeSpecLoc Implementation
+//===----------------------------------------------------------------------===//
+
+namespace {
+class TypeSpecChecker : public TypeLocVisitor<TypeSpecChecker, bool> {
+public:
+ bool VisitTypeSpecLoc(TypeSpecLoc TyLoc) { return true; }
+};
+
+}
+
+bool TypeSpecLoc::classof(const TypeLoc *TL) {
+ return TypeSpecChecker().Visit(*TL);
+}
+
+//===----------------------------------------------------------------------===//
+// DeclaratorLoc Implementation
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+/// \brief Return the TypeSpecLoc for the visited DeclaratorLoc.
+class TypeSpecGetter : public TypeLocVisitor<TypeSpecGetter, TypeSpecLoc> {
+public:
+#define TYPELOC(CLASS, PARENT, TYPE)
+#define DECLARATOR_TYPELOC(CLASS, TYPE) \
+ TypeSpecLoc Visit##CLASS(CLASS TyLoc) { return TyLoc.getTypeSpecLoc(); }
+#include "clang/AST/TypeLocNodes.def"
+
+ TypeSpecLoc VisitTypeLoc(TypeLoc TyLoc) {
+ assert(0 && "A declarator loc wrapper was not handled!");
+ return TypeSpecLoc();
+ }
+};
+
+}
+
+/// \brief Find the TypeSpecLoc that is part of this DeclaratorLoc.
+TypeSpecLoc DeclaratorLoc::getTypeSpecLoc() const {
+ return TypeSpecGetter().Visit(*this);
+}
+
+namespace {
+
+class DeclaratorLocChecker : public TypeLocVisitor<DeclaratorLocChecker, bool> {
+public:
+ bool VisitDeclaratorLoc(DeclaratorLoc TyLoc) { return true; }
+};
+
+}
+
+bool DeclaratorLoc::classof(const TypeLoc *TL) {
+ return DeclaratorLocChecker().Visit(*TL);
+}
+
+//===----------------------------------------------------------------------===//
+// DefaultTypeSpecLoc Implementation
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class DefaultTypeSpecLocChecker :
+ public TypeLocVisitor<DefaultTypeSpecLocChecker, bool> {
+public:
+ bool VisitDefaultTypeSpecLoc(DefaultTypeSpecLoc TyLoc) { return true; }
+};
+
+}
+
+bool DefaultTypeSpecLoc::classof(const TypeLoc *TL) {
+ return DefaultTypeSpecLocChecker().Visit(*TL);
+}
+
+//===----------------------------------------------------------------------===//
+// TypedefLoc Implementation
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class TypedefLocChecker : public TypeLocVisitor<TypedefLocChecker, bool> {
+public:
+ bool VisitTypedefLoc(TypedefLoc TyLoc) { return true; }
+};
+
+}
+
+bool TypedefLoc::classof(const TypeLoc *TL) {
+ return TypedefLocChecker().Visit(*TL);
+}
+
+//===----------------------------------------------------------------------===//
+// ObjCInterfaceLoc Implementation
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class ObjCInterfaceLocChecker :
+ public TypeLocVisitor<ObjCInterfaceLocChecker, bool> {
+public:
+ bool VisitObjCInterfaceLoc(ObjCInterfaceLoc TyLoc) { return true; }
+};
+
+}
+
+bool ObjCInterfaceLoc::classof(const TypeLoc *TL) {
+ return ObjCInterfaceLocChecker().Visit(*TL);
+}
+
+//===----------------------------------------------------------------------===//
+// ObjCProtocolListLoc Implementation
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class ObjCProtocolListLocChecker :
+ public TypeLocVisitor<ObjCProtocolListLocChecker, bool> {
+public:
+ bool VisitObjCProtocolListLoc(ObjCProtocolListLoc TyLoc) { return true; }
+};
+
+}
+
+bool ObjCProtocolListLoc::classof(const TypeLoc *TL) {
+ return ObjCProtocolListLocChecker().Visit(*TL);
+}
+
+//===----------------------------------------------------------------------===//
+// PointerLoc Implementation
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class PointerLocChecker : public TypeLocVisitor<PointerLocChecker, bool> {
+public:
+ bool VisitPointerLoc(PointerLoc TyLoc) { return true; }
+};
+
+}
+
+bool PointerLoc::classof(const TypeLoc *TL) {
+ return PointerLocChecker().Visit(*TL);
+}
+
+//===----------------------------------------------------------------------===//
+// BlockPointerLoc Implementation
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class BlockPointerLocChecker :
+ public TypeLocVisitor<BlockPointerLocChecker, bool> {
+public:
+ bool VisitBlockPointerLoc(BlockPointerLoc TyLoc) { return true; }
+};
+
+}
+
+bool BlockPointerLoc::classof(const TypeLoc *TL) {
+ return BlockPointerLocChecker().Visit(*TL);
+}
+
+//===----------------------------------------------------------------------===//
+// MemberPointerLoc Implementation
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class MemberPointerLocChecker :
+ public TypeLocVisitor<MemberPointerLocChecker, bool> {
+public:
+ bool VisitMemberPointerLoc(MemberPointerLoc TyLoc) { return true; }
+};
+
+}
+
+bool MemberPointerLoc::classof(const TypeLoc *TL) {
+ return MemberPointerLocChecker().Visit(*TL);
+}
+
+//===----------------------------------------------------------------------===//
+// ReferenceLoc Implementation
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class ReferenceLocChecker : public TypeLocVisitor<ReferenceLocChecker, bool> {
+public:
+ bool VisitReferenceLoc(ReferenceLoc TyLoc) { return true; }
+};
+
+}
+
+bool ReferenceLoc::classof(const TypeLoc *TL) {
+ return ReferenceLocChecker().Visit(*TL);
+}
+
+//===----------------------------------------------------------------------===//
+// FunctionLoc Implementation
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class FunctionLocChecker : public TypeLocVisitor<FunctionLocChecker, bool> {
+public:
+ bool VisitFunctionLoc(FunctionLoc TyLoc) { return true; }
+};
+
+}
+
+bool FunctionLoc::classof(const TypeLoc *TL) {
+ return FunctionLocChecker().Visit(*TL);
+}
+
+//===----------------------------------------------------------------------===//
+// ArrayLoc Implementation
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class ArrayLocChecker : public TypeLocVisitor<ArrayLocChecker, bool> {
+public:
+ bool VisitArrayLoc(ArrayLoc TyLoc) { return true; }
+};
+
+}
+
+bool ArrayLoc::classof(const TypeLoc *TL) {
+ return ArrayLocChecker().Visit(*TL);
+}
diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp
new file mode 100644
index 0000000..a4cb66b
--- /dev/null
+++ b/lib/Analysis/AnalysisContext.cpp
@@ -0,0 +1,138 @@
+//== AnalysisContext.cpp - Analysis context 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 AnalysisContext, a class that manages the analysis context
+// data for path sensitive analysis.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/AnalysisContext.h"
+#include "clang/Analysis/Analyses/LiveVariables.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/ParentMap.h"
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace clang;
+
+AnalysisContext::~AnalysisContext() {
+ delete cfg;
+ delete liveness;
+ delete PM;
+}
+
+AnalysisContextManager::~AnalysisContextManager() {
+ for (ContextMap::iterator I = Contexts.begin(), E = Contexts.end(); I!=E; ++I)
+ delete I->second;
+}
+
+Stmt *AnalysisContext::getBody() {
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ return FD->getBody();
+ else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
+ return MD->getBody();
+
+ llvm::llvm_unreachable("unknown code decl");
+}
+
+const ImplicitParamDecl *AnalysisContext::getSelfDecl() const {
+ if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
+ return MD->getSelfDecl();
+
+ return NULL;
+}
+
+CFG *AnalysisContext::getCFG() {
+ if (!cfg)
+ cfg = CFG::buildCFG(getBody(), &D->getASTContext());
+ return cfg;
+}
+
+ParentMap &AnalysisContext::getParentMap() {
+ if (!PM)
+ PM = new ParentMap(getBody());
+ return *PM;
+}
+
+LiveVariables *AnalysisContext::getLiveVariables() {
+ if (!liveness) {
+ CFG *c = getCFG();
+ if (!c)
+ return 0;
+
+ liveness = new LiveVariables(D->getASTContext(), *c);
+ liveness->runOnCFG(*c);
+ liveness->runOnAllBlocks(*c, 0, true);
+ }
+
+ return liveness;
+}
+
+AnalysisContext *AnalysisContextManager::getContext(const Decl *D) {
+ AnalysisContext *&AC = Contexts[D];
+ if (!AC)
+ AC = new AnalysisContext(D);
+
+ return AC;
+}
+
+void LocationContext::Profile(llvm::FoldingSetNodeID &ID, ContextKind k,
+ AnalysisContext *ctx,
+ const LocationContext *parent) {
+ ID.AddInteger(k);
+ ID.AddPointer(ctx);
+ ID.AddPointer(parent);
+}
+
+void StackFrameContext::Profile(llvm::FoldingSetNodeID &ID,AnalysisContext *ctx,
+ const LocationContext *parent, const Stmt *s) {
+ LocationContext::Profile(ID, StackFrame, ctx, parent);
+ ID.AddPointer(s);
+}
+
+void ScopeContext::Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx,
+ const LocationContext *parent, const Stmt *s) {
+ LocationContext::Profile(ID, Scope, ctx, parent);
+ ID.AddPointer(s);
+}
+
+StackFrameContext*
+LocationContextManager::getStackFrame(AnalysisContext *ctx,
+ const LocationContext *parent,
+ const Stmt *s) {
+ llvm::FoldingSetNodeID ID;
+ StackFrameContext::Profile(ID, ctx, parent, s);
+ void *InsertPos;
+
+ StackFrameContext *f =
+ cast_or_null<StackFrameContext>(Contexts.FindNodeOrInsertPos(ID, InsertPos));
+ if (!f) {
+ f = new StackFrameContext(ctx, parent, s);
+ Contexts.InsertNode(f, InsertPos);
+ }
+ return f;
+}
+
+ScopeContext *LocationContextManager::getScope(AnalysisContext *ctx,
+ const LocationContext *parent,
+ const Stmt *s) {
+ llvm::FoldingSetNodeID ID;
+ ScopeContext::Profile(ID, ctx, parent, s);
+ void *InsertPos;
+
+ ScopeContext *scope =
+ cast_or_null<ScopeContext>(Contexts.FindNodeOrInsertPos(ID, InsertPos));
+
+ if (!scope) {
+ scope = new ScopeContext(ctx, parent, s);
+ Contexts.InsertNode(scope, InsertPos);
+ }
+ return scope;
+}
diff --git a/lib/Analysis/AnalysisManager.cpp b/lib/Analysis/AnalysisManager.cpp
new file mode 100644
index 0000000..c2733fa
--- /dev/null
+++ b/lib/Analysis/AnalysisManager.cpp
@@ -0,0 +1,35 @@
+//== AnalysisManager.cpp - Path sensitive analysis data manager ----*- C++ -*-//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the AnalysisManager class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/AnalysisManager.h"
+#include "clang/Basic/SourceManager.h"
+
+using namespace clang;
+
+void AnalysisManager::DisplayFunction(Decl *D) {
+
+ if (DisplayedFunction)
+ return;
+
+ DisplayedFunction = true;
+
+ // FIXME: Is getCodeDecl() always a named decl?
+ if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
+ const NamedDecl *ND = cast<NamedDecl>(D);
+ SourceManager &SM = getASTContext().getSourceManager();
+ (llvm::errs() << "ANALYZE: "
+ << SM.getPresumedLoc(ND->getLocation()).getFilename()
+ << ' ' << ND->getNameAsString() << '\n').flush();
+ }
+}
+
diff --git a/lib/Analysis/BasicConstraintManager.cpp b/lib/Analysis/BasicConstraintManager.cpp
index cb89d30..d0b8289 100644
--- a/lib/Analysis/BasicConstraintManager.cpp
+++ b/lib/Analysis/BasicConstraintManager.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This file defines BasicConstraintManager, a class that tracks simple
+// This file defines BasicConstraintManager, a class that tracks simple
// equality and inequality constraints on symbolic values of GRState.
//
//===----------------------------------------------------------------------===//
@@ -27,22 +27,22 @@ 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; }
+ static inline void* GDMIndex() { return &ConstNotEqIndex; }
};
template<>
struct GRStateTrait<ConstEq> : public GRStatePartialTrait<ConstEqTy> {
- static inline void* GDMIndex() { return &ConstEqIndex; }
+ static inline void* GDMIndex() { return &ConstEqIndex; }
};
-}
-
+}
+
namespace {
// BasicConstraintManager only tracks equality and inequality constraints of
// constants and integer variables.
@@ -50,7 +50,7 @@ class VISIBILITY_HIDDEN BasicConstraintManager
: public SimpleConstraintManager {
GRState::IntSetTy::Factory ISetFactory;
public:
- BasicConstraintManager(GRStateManager& statemgr)
+ BasicConstraintManager(GRStateManager& statemgr)
: ISetFactory(statemgr.getAllocator()) {}
const GRState* AssumeSymNE(const GRState* state, SymbolRef sym,
@@ -83,7 +83,7 @@ public:
const GRState* RemoveDeadBindings(const GRState* state, SymbolReaper& SymReaper);
- void print(const GRState* state, llvm::raw_ostream& Out,
+ void print(const GRState* state, llvm::raw_ostream& Out,
const char* nl, const char *sep);
};
@@ -133,7 +133,7 @@ const GRState *BasicConstraintManager::AssumeSymEQ(const GRState *state,
// These logic will be handled in another ConstraintManager.
const GRState *BasicConstraintManager::AssumeSymLT(const GRState *state,
SymbolRef sym,
- const llvm::APSInt& V) {
+ const llvm::APSInt& V) {
// 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.
@@ -167,14 +167,14 @@ const GRState *BasicConstraintManager::AssumeSymGE(const GRState *state,
bool isFeasible = *X >= V;
return isFeasible ? state : NULL;
}
-
+
// 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.
+ // there is no other value greater than V.
bool isFeasible = !isNotEqual(state, 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.
@@ -193,20 +193,20 @@ BasicConstraintManager::AssumeSymLE(const GRState* state, SymbolRef sym,
bool isFeasible = *X <= V;
return isFeasible ? state : NULL;
}
-
+
// 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.
+ // there is no other value less than V.
bool isFeasible = !isNotEqual(state, 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.
return isFeasible ? AddEQ(state, sym, V) : NULL;
}
-
+
return state;
}
@@ -222,10 +222,10 @@ const GRState* BasicConstraintManager::AddNE(const GRState* state, SymbolRef sym
// 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);
}
@@ -236,7 +236,7 @@ const llvm::APSInt* BasicConstraintManager::getSymVal(const GRState* state,
return T ? *T : NULL;
}
-bool BasicConstraintManager::isNotEqual(const GRState* state, SymbolRef sym,
+bool BasicConstraintManager::isNotEqual(const GRState* state, SymbolRef sym,
const llvm::APSInt& V) const {
// Retrieve the NE-set associated with the given symbol.
@@ -273,14 +273,14 @@ BasicConstraintManager::RemoveDeadBindings(const GRState* state,
ConstNotEqTy::Factory& CNEFactory = state->get_context<ConstNotEq>();
for (ConstNotEqTy::iterator I = CNE.begin(), E = CNE.end(); I != E; ++I) {
- SymbolRef sym = I.getKey();
+ SymbolRef sym = I.getKey();
if (SymReaper.maybeDead(sym)) CNE = CNEFactory.Remove(CNE, sym);
}
-
+
return state->set<ConstNotEq>(CNE);
}
-void BasicConstraintManager::print(const GRState* state, llvm::raw_ostream& Out,
+void BasicConstraintManager::print(const GRState* state, llvm::raw_ostream& Out,
const char* nl, const char *sep) {
// Print equality constraints.
@@ -293,23 +293,23 @@ void BasicConstraintManager::print(const GRState* state, llvm::raw_ostream& Out,
}
// Print != constraints.
-
+
ConstNotEqTy CNE = state->get<ConstNotEq>();
-
+
if (!CNE.isEmpty()) {
Out << nl << sep << "'!=' constraints:";
-
+
for (ConstNotEqTy::iterator I = CNE.begin(), EI = CNE.end(); I!=EI; ++I) {
Out << nl << " $" << I.getKey() << " : ";
bool isFirst = true;
-
- GRState::IntSetTy::iterator J = I.getData().begin(),
- EJ = I.getData().end();
-
- for ( ; J != EJ; ++J) {
+
+ 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
index aa85769..af300f3 100644
--- a/lib/Analysis/BasicObjCFoundationChecks.cpp
+++ b/lib/Analysis/BasicObjCFoundationChecks.cpp
@@ -31,26 +31,21 @@
using namespace clang;
-static ObjCInterfaceType* GetReceiverType(ObjCMessageExpr* ME) {
- Expr* Receiver = ME->getReceiver();
-
+static const ObjCInterfaceType* GetReceiverType(const ObjCMessageExpr* ME) {
+ const 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?
+ if (const ObjCObjectPointerType *PT =
+ Receiver->getType()->getAs<ObjCObjectPointerType>())
+ return PT->getInterfaceType();
+
return NULL;
}
-static const char* GetReceiverNameType(ObjCMessageExpr* ME) {
- ObjCInterfaceType* ReceiverType = GetReceiverType(ME);
+static const char* GetReceiverNameType(const ObjCMessageExpr* ME) {
+ const ObjCInterfaceType *ReceiverType = GetReceiverType(ME);
return ReceiverType ? ReceiverType->getDecl()->getIdentifier()->getName()
: NULL;
}
@@ -61,76 +56,75 @@ 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;
-
- 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);
+
+ bool isNSString(const ObjCInterfaceType *T, const char* suffix);
+ bool AuditNSString(ExplodedNode* N, const ObjCMessageExpr* ME);
+
+ void Warn(ExplodedNode* N, const Expr* E, const std::string& s);
+ void WarnNilArg(ExplodedNode* N, const Expr* E);
+
+ bool CheckNilArg(ExplodedNode* N, unsigned Arg);
public:
- BasicObjCFoundationChecks(ASTContext& ctx, BugReporter& br)
+ BasicObjCFoundationChecks(ASTContext& ctx, BugReporter& br)
: BT(0), BR(br), Ctx(ctx) {}
-
- bool Audit(ExplodedNode<GRState>* N, GRStateManager&);
-
-private:
- void WarnNilArg(NodeTy* N, ObjCMessageExpr* ME, unsigned Arg) {
+
+ bool Audit(ExplodedNode* N, GRStateManager&);
+
+private:
+ void WarnNilArg(ExplodedNode* N, const 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, BugReporter& BR) {
- return new BasicObjCFoundationChecks(Ctx, BR);
+ return new BasicObjCFoundationChecks(Ctx, BR);
}
-bool BasicObjCFoundationChecks::Audit(ExplodedNode<GRState>* N,
+bool BasicObjCFoundationChecks::Audit(ExplodedNode* N,
GRStateManager&) {
-
- ObjCMessageExpr* ME =
+
+ const ObjCMessageExpr* ME =
cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());
- ObjCInterfaceType* ReceiverType = GetReceiverType(ME);
-
+ const 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);
@@ -138,24 +132,24 @@ bool BasicObjCFoundationChecks::Audit(ExplodedNode<GRState>* N,
}
static inline bool isNil(SVal X) {
- return isa<loc::ConcreteInt>(X);
+ return isa<loc::ConcreteInt>(X);
}
//===----------------------------------------------------------------------===//
// Error reporting.
//===----------------------------------------------------------------------===//
-bool BasicObjCFoundationChecks::CheckNilArg(NodeTy* N, unsigned Arg) {
- ObjCMessageExpr* ME =
+bool BasicObjCFoundationChecks::CheckNilArg(ExplodedNode* N, unsigned Arg) {
+ const ObjCMessageExpr* ME =
cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());
-
- Expr * E = ME->getArg(Arg);
-
+
+ const Expr * E = ME->getArg(Arg);
+
if (isNil(N->getState()->getSVal(E))) {
WarnNilArg(N, ME, Arg);
return true;
}
-
+
return false;
}
@@ -163,37 +157,36 @@ bool BasicObjCFoundationChecks::CheckNilArg(NodeTy* N, unsigned Arg) {
// NSString checking.
//===----------------------------------------------------------------------===//
-bool BasicObjCFoundationChecks::isNSString(ObjCInterfaceType* T,
+bool BasicObjCFoundationChecks::isNSString(const ObjCInterfaceType *T,
const char* suffix) {
-
return !strcmp("String", suffix) || !strcmp("MutableString", suffix);
}
-bool BasicObjCFoundationChecks::AuditNSString(NodeTy* N,
- ObjCMessageExpr* ME) {
-
+bool BasicObjCFoundationChecks::AuditNSString(ExplodedNode* N,
+ const 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:
+ 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
@@ -201,41 +194,41 @@ bool BasicObjCFoundationChecks::AuditNSString(NodeTy* N,
// 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;
-
+
+ break;
+
case 37:
if (!strcmp(cstr, "componentsSeparatedByCharactersInSet:"))
return CheckNilArg(N, 0);
-
- break;
+
+ break;
}
-
+
return false;
}
@@ -247,7 +240,7 @@ 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.
@@ -256,16 +249,16 @@ class VISIBILITY_HIDDEN AuditCFNumberCreate : public GRSimpleAPICheck {
BugReporter& BR;
public:
- AuditCFNumberCreate(ASTContext& ctx, BugReporter& br)
+ AuditCFNumberCreate(ASTContext& ctx, BugReporter& br)
: BT(0), Ctx(ctx), II(&Ctx.Idents.get("CFNumberCreate")), BR(br){}
-
+
~AuditCFNumberCreate() {}
-
- bool Audit(ExplodedNode<GRState>* N, GRStateManager&);
-
+
+ bool Audit(ExplodedNode* N, GRStateManager&);
+
private:
- void AddError(const TypedRegion* R, Expr* Ex, ExplodedNode<GRState> *N,
- uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
+ void AddError(const TypedRegion* R, const Expr* Ex, ExplodedNode *N,
+ uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
};
} // end anonymous namespace
@@ -296,7 +289,7 @@ namespace {
public:
Optional() : IsKnown(false), Val(0) {}
Optional(const T& val) : IsKnown(true), Val(val) {}
-
+
bool isKnown() const { return IsKnown; }
const T& getValue() const {
@@ -312,12 +305,12 @@ namespace {
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;
@@ -329,11 +322,11 @@ static Optional<uint64_t> GetCFNumberSize(ASTContext& Ctx, uint64_t i) {
case kCFNumberCFIndexType:
case kCFNumberNSIntegerType:
case kCFNumberCGFloatType:
- // FIXME: We need a way to map from names to Type*.
+ // FIXME: We need a way to map from names to Type*.
default:
return Optional<uint64_t>();
}
-
+
return Ctx.getTypeSize(T);
}
@@ -357,100 +350,98 @@ static const char* GetCFNumberTypeStr(uint64_t i) {
"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 = N->getState()->getSVal(Callee);
+bool AuditCFNumberCreate::Audit(ExplodedNode* N,GRStateManager&){
+ const CallExpr* CE =
+ cast<CallExpr>(cast<PostStmt>(N->getLocation()).getStmt());
+ const Expr* Callee = CE->getCallee();
+ SVal CallV = N->getState()->getSVal(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 = N->getState()->getSVal(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 = N->getState()->getSVal(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;
- }
-
+
+ const TypedRegion* R = dyn_cast<TypedRegion>(LV->getBaseRegion());
+
+ 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())
+
+ 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,
+void AuditCFNumberCreate::AddError(const TypedRegion* R, const Expr* Ex,
+ ExplodedNode *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. ";
+ << TargetSize << " bit integer. ";
if (SourceSize < TargetSize)
os << (TargetSize - SourceSize)
- << " bits of the CFNumber value will be garbage." ;
+ << " 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");
@@ -460,22 +451,98 @@ void AuditCFNumberCreate::AddError(const TypedRegion* R, Expr* Ex,
}
GRSimpleAPICheck*
-clang::CreateAuditCFNumberCreate(ASTContext& Ctx, BugReporter& BR) {
+clang::CreateAuditCFNumberCreate(ASTContext& Ctx, BugReporter& BR) {
return new AuditCFNumberCreate(Ctx, BR);
}
//===----------------------------------------------------------------------===//
+// CFRetain/CFRelease auditing for null arguments.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class VISIBILITY_HIDDEN AuditCFRetainRelease : 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 *Retain, *Release;
+ BugReporter& BR;
+
+public:
+ AuditCFRetainRelease(ASTContext& ctx, BugReporter& br)
+ : BT(0), Ctx(ctx),
+ Retain(&Ctx.Idents.get("CFRetain")), Release(&Ctx.Idents.get("CFRelease")),
+ BR(br){}
+
+ ~AuditCFRetainRelease() {}
+
+ bool Audit(ExplodedNode* N, GRStateManager&);
+};
+} // end anonymous namespace
+
+
+bool AuditCFRetainRelease::Audit(ExplodedNode* N, GRStateManager&) {
+ const CallExpr* CE = cast<CallExpr>(cast<PostStmt>(N->getLocation()).getStmt());
+
+ // If the CallExpr doesn't have exactly 1 argument just give up checking.
+ if (CE->getNumArgs() != 1)
+ return false;
+
+ // Check if we called CFRetain/CFRelease.
+ const GRState* state = N->getState();
+ SVal X = state->getSVal(CE->getCallee());
+ const FunctionDecl* FD = X.getAsFunctionDecl();
+
+ if (!FD)
+ return false;
+
+ const IdentifierInfo *FuncII = FD->getIdentifier();
+ if (!(FuncII == Retain || FuncII == Release))
+ return false;
+
+ // Finally, check if the argument is NULL.
+ // FIXME: We should be able to bifurcate the state here, as a successful
+ // check will result in the value not being NULL afterwards.
+ // FIXME: Need a way to register vistors for the BugReporter. Would like
+ // to benefit from the same diagnostics that regular null dereference
+ // reporting has.
+ if (state->getStateManager().isEqual(state, CE->getArg(0), 0)) {
+ if (!BT)
+ BT = new APIMisuse("null passed to CFRetain/CFRelease");
+
+ const char *description = (FuncII == Retain)
+ ? "Null pointer argument in call to CFRetain"
+ : "Null pointer argument in call to CFRelease";
+
+ RangedBugReport *report = new RangedBugReport(*BT, description, N);
+ report->addRange(CE->getArg(0)->getSourceRange());
+ BR.EmitReport(report);
+ return true;
+ }
+
+ return false;
+}
+
+
+GRSimpleAPICheck*
+clang::CreateAuditCFRetainRelease(ASTContext& Ctx, BugReporter& BR) {
+ return new AuditCFRetainRelease(Ctx, BR);
+}
+
+//===----------------------------------------------------------------------===//
// Check registration.
+//===----------------------------------------------------------------------===//
-void clang::RegisterAppleChecks(GRExprEngine& Eng) {
+void clang::RegisterAppleChecks(GRExprEngine& Eng, const Decl &D) {
ASTContext& Ctx = Eng.getContext();
BugReporter &BR = Eng.getBugReporter();
Eng.AddCheck(CreateBasicObjCFoundationChecks(Ctx, BR),
Stmt::ObjCMessageExprClass);
+ Eng.AddCheck(CreateAuditCFNumberCreate(Ctx, BR), Stmt::CallExprClass);
+ Eng.AddCheck(CreateAuditCFRetainRelease(Ctx, BR), Stmt::CallExprClass);
- Eng.AddCheck(CreateAuditCFNumberCreate(Ctx, BR),
- Stmt::CallExprClass);
-
- RegisterNSErrorChecks(BR, Eng);
+ RegisterNSErrorChecks(BR, Eng, D);
}
diff --git a/lib/Analysis/BasicObjCFoundationChecks.h b/lib/Analysis/BasicObjCFoundationChecks.h
index 5c9701e..1271ae4 100644
--- a/lib/Analysis/BasicObjCFoundationChecks.h
+++ b/lib/Analysis/BasicObjCFoundationChecks.h
@@ -25,21 +25,24 @@
#define LLVM_CLANG_ANALYSIS_BASICOBJCFOUNDATIONCHECKS
namespace clang {
-
+
class GRSimpleAPICheck;
class ASTContext;
-class GRStateManager;
+class GRStateManager;
class BugReporter;
class GRExprEngine;
-
-GRSimpleAPICheck* CreateBasicObjCFoundationChecks(ASTContext& Ctx,
+
+GRSimpleAPICheck *CreateBasicObjCFoundationChecks(ASTContext& Ctx,
BugReporter& BR);
-
-GRSimpleAPICheck* CreateAuditCFNumberCreate(ASTContext& Ctx,
+
+GRSimpleAPICheck *CreateAuditCFNumberCreate(ASTContext& Ctx,
BugReporter& BR);
-
-void RegisterNSErrorChecks(BugReporter& BR, GRExprEngine &Eng);
-
+
+GRSimpleAPICheck *CreateAuditCFRetainRelease(ASTContext& Ctx,
+ BugReporter& BR);
+
+void RegisterNSErrorChecks(BugReporter& BR, GRExprEngine &Eng, const Decl &D);
+
} // end clang namespace
#endif
diff --git a/lib/Analysis/BasicStore.cpp b/lib/Analysis/BasicStore.cpp
index 19d641e..a4f451f 100644
--- a/lib/Analysis/BasicStore.cpp
+++ b/lib/Analysis/BasicStore.cpp
@@ -13,17 +13,17 @@
#include "clang/AST/ExprObjC.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
+#include "clang/Analysis/PathSensitive/AnalysisContext.h"
#include "clang/Analysis/PathSensitive/GRState.h"
-#include "llvm/ADT/ImmutableMap.h"
#include "llvm/Support/Compiler.h"
-#include "llvm/Support/Streams.h"
+#include "llvm/ADT/ImmutableMap.h"
using namespace clang;
-typedef llvm::ImmutableMap<const MemRegion*,SVal> BindingsTy;
+typedef llvm::ImmutableMap<const MemRegion*,SVal> BindingsTy;
namespace {
-
+
class VISIBILITY_HIDDEN BasicStoreSubRegionMap : public SubRegionMap {
public:
BasicStoreSubRegionMap() {}
@@ -32,81 +32,78 @@ public:
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) {}
-
+ : StoreManager(mgr), VBFactory(mgr.getAllocator()) {}
+
~BasicStoreManager() {}
SubRegionMap *getSubRegionMap(const GRState *state) {
return new BasicStoreSubRegionMap();
}
- SVal Retrieve(const GRState *state, Loc loc, QualType T = QualType());
+ SValuator::CastResult Retrieve(const GRState *state, Loc loc,
+ QualType T = QualType());
+
+ const GRState *InvalidateRegion(const GRState *state, const MemRegion *R,
+ const Expr *E, unsigned Count);
const GRState *Bind(const GRState *state, Loc L, SVal V) {
return state->makeWithStore(BindInternal(state->getStore(), L, V));
}
- Store scanForIvars(Stmt *B, const Decl* SelfDecl, Store St);
-
- Store BindInternal(Store St, Loc loc, SVal V);
+ Store scanForIvars(Stmt *B, const Decl* SelfDecl,
+ const MemRegion *SelfRegion, Store St);
+
+ Store BindInternal(Store St, Loc loc, SVal V);
Store Remove(Store St, Loc loc);
- Store getInitialStore();
+ Store getInitialStore(const LocationContext *InitLoc);
// FIXME: Investigate what is using this. This method should be removed.
- virtual Loc getLoc(const VarDecl* VD) {
- return ValMgr.makeLoc(MRMgr.getVarRegion(VD));
+ virtual Loc getLoc(const VarDecl* VD, const LocationContext *LC) {
+ return ValMgr.makeLoc(MRMgr.getVarRegion(VD, LC));
}
-
+
const GRState *BindCompoundLiteral(const GRState *state,
const CompoundLiteralExpr* cl,
SVal val) {
return state;
}
-
- SVal getLValueVar(const GRState *state, const VarDecl* VD);
- SVal getLValueString(const GRState *state, const StringLiteral* S);
- SVal getLValueCompoundLiteral(const GRState *state,
- const CompoundLiteralExpr* CL);
- SVal getLValueIvar(const GRState *state, const ObjCIvarDecl* D, SVal Base);
- SVal getLValueField(const GRState *state, SVal Base, const FieldDecl* D);
- SVal getLValueElement(const GRState *state, QualType elementType,
- SVal Base, SVal Offset);
+
+ SVal getLValueVar(const VarDecl *VD, const LocationContext *LC);
+ SVal getLValueString(const StringLiteral *S);
+ SVal getLValueCompoundLiteral(const CompoundLiteralExpr *CL);
+ SVal getLValueIvar(const ObjCIvarDecl* D, SVal Base);
+ SVal getLValueField(const FieldDecl *D, SVal Base);
+ SVal getLValueElement(QualType elementType, SVal Offset, SVal Base);
/// 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.
- Store RemoveDeadBindings(const GRState *state, Stmt* Loc,
- SymbolReaper& SymReaper,
- llvm::SmallVectorImpl<const MemRegion*>& RegionRoots);
+ /// It updatees the GRState object in place with the values removed.
+ void RemoveDeadBindings(GRState &state, Stmt* Loc, SymbolReaper& SymReaper,
+ llvm::SmallVectorImpl<const MemRegion*>& RegionRoots);
void iterBindings(Store store, BindingsHandler& f);
- const GRState *BindDecl(const GRState *state, const VarDecl* VD, SVal InitVal) {
- return state->makeWithStore(BindDeclInternal(state->getStore(),VD, &InitVal));
+ const GRState *BindDecl(const GRState *state, const VarDecl *VD,
+ const LocationContext *LC, SVal InitVal) {
+ return state->makeWithStore(BindDeclInternal(state->getStore(),VD, LC,
+ &InitVal));
}
- const GRState *BindDeclWithNoInit(const GRState *state, const VarDecl* VD) {
- return state->makeWithStore(BindDeclInternal(state->getStore(), VD, 0));
+ const GRState *BindDeclWithNoInit(const GRState *state, const VarDecl *VD,
+ const LocationContext *LC) {
+ return state->makeWithStore(BindDeclInternal(state->getStore(), VD, LC, 0));
}
- Store BindDeclInternal(Store store, const VarDecl* VD, SVal* InitVal);
+ Store BindDeclInternal(Store store, const VarDecl *VD,
+ const LocationContext *LC, SVal *InitVal);
static inline BindingsTy GetBindings(Store store) {
return BindingsTy(static_cast<const BindingsTy::TreeTy*>(store));
@@ -118,7 +115,7 @@ public:
private:
ASTContext& getContext() { return StateMgr.getContext(); }
};
-
+
} // end anonymous namespace
@@ -126,23 +123,21 @@ StoreManager* clang::CreateBasicStoreManager(GRStateManager& StMgr) {
return new BasicStoreManager(StMgr);
}
-SVal BasicStoreManager::getLValueVar(const GRState *state, const VarDecl* VD) {
- return ValMgr.makeLoc(MRMgr.getVarRegion(VD));
+SVal BasicStoreManager::getLValueVar(const VarDecl* VD,
+ const LocationContext *LC) {
+ return ValMgr.makeLoc(MRMgr.getVarRegion(VD, LC));
}
-SVal BasicStoreManager::getLValueString(const GRState *state,
- const StringLiteral* S) {
+SVal BasicStoreManager::getLValueString(const StringLiteral* S) {
return ValMgr.makeLoc(MRMgr.getStringRegion(S));
}
-SVal BasicStoreManager::getLValueCompoundLiteral(const GRState *state,
- const CompoundLiteralExpr* CL){
+SVal BasicStoreManager::getLValueCompoundLiteral(const CompoundLiteralExpr* CL){
return ValMgr.makeLoc(MRMgr.getCompoundLiteralRegion(CL));
}
-SVal BasicStoreManager::getLValueIvar(const GRState *state, const ObjCIvarDecl* D,
- SVal Base) {
-
+SVal BasicStoreManager::getLValueIvar(const ObjCIvarDecl* D, SVal Base) {
+
if (Base.isUnknownOrUndef())
return Base;
@@ -150,23 +145,20 @@ SVal BasicStoreManager::getLValueIvar(const GRState *state, const ObjCIvarDecl*
if (isa<loc::MemRegionVal>(BaseL)) {
const MemRegion *BaseR = cast<loc::MemRegionVal>(BaseL).getRegion();
-
- if (BaseR == SelfRegion)
- return ValMgr.makeLoc(MRMgr.getObjCIvarRegion(D, BaseR));
+ return ValMgr.makeLoc(MRMgr.getObjCIvarRegion(D, BaseR));
}
-
+
return UnknownVal();
}
-SVal BasicStoreManager::getLValueField(const GRState *state, SVal Base,
- const FieldDecl* D) {
+SVal BasicStoreManager::getLValueField(const FieldDecl* D, SVal Base) {
if (Base.isUnknownOrUndef())
return Base;
-
- Loc BaseL = cast<Loc>(Base);
+
+ Loc BaseL = cast<Loc>(Base);
const MemRegion* BaseR = 0;
-
+
switch(BaseL.getSubKind()) {
case loc::GotoLabelKind:
return UndefinedVal();
@@ -174,7 +166,7 @@ SVal BasicStoreManager::getLValueField(const GRState *state, SVal Base,
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,
@@ -186,28 +178,27 @@ SVal BasicStoreManager::getLValueField(const GRState *state, SVal Base,
assert ("Unhandled Base.");
return Base;
}
-
+
return ValMgr.makeLoc(MRMgr.getFieldRegion(D, BaseR));
}
-SVal BasicStoreManager::getLValueElement(const GRState *state,
- QualType elementType,
- SVal Base, SVal Offset) {
+SVal BasicStoreManager::getLValueElement(QualType elementType,
+ SVal Offset, SVal Base) {
if (Base.isUnknownOrUndef())
return Base;
-
- Loc BaseL = cast<Loc>(Base);
+
+ Loc BaseL = cast<Loc>(Base);
const MemRegion* 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;
@@ -215,12 +206,12 @@ SVal BasicStoreManager::getLValueElement(const GRState *state,
// y[0] = 'a';
return Base;
}
-
+
if (isa<TypedRegion>(R) || isa<SymbolicRegion>(R)) {
BaseR = R;
break;
}
-
+
break;
}
@@ -230,13 +221,13 @@ SVal BasicStoreManager::getLValueElement(const GRState *state,
// 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) {
+
+ if (BaseR) {
return ValMgr.makeLoc(MRMgr.getElementRegion(elementType, UnknownVal(),
BaseR, getContext()));
}
@@ -246,37 +237,38 @@ SVal BasicStoreManager::getLValueElement(const GRState *state,
static bool isHigherOrderRawPtr(QualType T, ASTContext &C) {
bool foundPointer = false;
- while (1) {
- const PointerType *PT = T->getAsPointerType();
+ while (1) {
+ const PointerType *PT = T->getAs<PointerType>();
if (!PT) {
if (!foundPointer)
return false;
-
+
// intptr_t* or intptr_t**, etc?
if (T->isIntegerType() && C.getTypeSize(T) == C.getTypeSize(C.VoidPtrTy))
return true;
-
+
QualType X = C.getCanonicalType(T).getUnqualifiedType();
return X == C.VoidTy;
}
-
+
foundPointer = true;
T = PT->getPointeeType();
- }
+ }
}
-
-SVal BasicStoreManager::Retrieve(const GRState *state, Loc loc, QualType T) {
-
+
+SValuator::CastResult BasicStoreManager::Retrieve(const GRState *state,
+ Loc loc, QualType T) {
+
if (isa<UnknownVal>(loc))
- return UnknownVal();
-
- assert (!isa<UndefinedVal>(loc));
-
+ return SValuator::CastResult(state, 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.
@@ -284,42 +276,46 @@ SVal BasicStoreManager::Retrieve(const GRState *state, Loc loc, QualType T) {
QualType T = ER->getLocationType(Ctx);
if (!isHigherOrderRawPtr(T, Ctx))
- return UnknownVal();
-
+ return SValuator::CastResult(state, UnknownVal());
+
// FIXME: Should check for element 0.
// Otherwise, strip the element region.
R = ER->getSuperRegion();
}
-
+
if (!(isa<VarRegion>(R) || isa<ObjCIvarRegion>(R)))
- return UnknownVal();
-
+ return SValuator::CastResult(state, UnknownVal());
+
BindingsTy B = GetBindings(state->getStore());
- BindingsTy::data_type* T = B.lookup(R);
- return T ? *T : UnknownVal();
+ BindingsTy::data_type *Val = B.lookup(R);
+
+ if (!Val)
+ break;
+
+ return CastRetrievedVal(*Val, state, cast<TypedRegion>(R), T);
}
-
+
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();
-
+ return SValuator::CastResult(state, UndefinedVal());
+
default:
assert (false && "Invalid Loc.");
break;
}
-
- return UnknownVal();
+
+ return SValuator::CastResult(state, UnknownVal());
}
-
-Store BasicStoreManager::BindInternal(Store store, Loc loc, SVal V) {
+
+Store BasicStoreManager::BindInternal(Store store, Loc loc, SVal V) {
if (isa<loc::ConcreteInt>(loc))
return store;
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.
@@ -327,19 +323,21 @@ Store BasicStoreManager::BindInternal(Store store, Loc loc, SVal 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;
-
+
+ const TypedRegion *TyR = cast<TypedRegion>(R);
+
+ // Do not bind to arrays. We need to explicitly check for this so that
+ // we do not encounter any weirdness of trying to load/store from arrays.
+ if (TyR->isBoundable() && TyR->getValueType(C)->isArrayType())
+ 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.
@@ -347,11 +345,8 @@ Store BasicStoreManager::BindInternal(Store store, Loc loc, SVal V) {
// 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() &&
- Loc::IsLocType(TyR->getValueType(C)))
- V = X->getLoc();
- }
+ if (TyR->isBoundable() && Loc::IsLocType(TyR->getValueType(C)))
+ V = X->getLoc();
}
BindingsTy B = GetBindings(store);
@@ -364,10 +359,10 @@ 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:
@@ -376,16 +371,15 @@ Store BasicStoreManager::Remove(Store store, Loc loc) {
}
}
-Store
-BasicStoreManager::RemoveDeadBindings(const GRState *state, Stmt* Loc,
+void
+BasicStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
SymbolReaper& SymReaper,
- llvm::SmallVectorImpl<const MemRegion*>& RegionRoots)
+ llvm::SmallVectorImpl<const MemRegion*>& RegionRoots)
{
-
- Store store = state->getStore();
+ 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())) {
@@ -399,20 +393,20 @@ BasicStoreManager::RemoveDeadBindings(const GRState *state, Stmt* Loc,
}
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());
@@ -421,17 +415,17 @@ BasicStoreManager::RemoveDeadBindings(const GRState *state, Stmt* Loc,
else if (isa<VarRegion>(MR) || isa<ObjCIvarRegion>(MR)) {
if (Marked.count(MR))
break;
-
+
Marked.insert(MR);
- SVal X = Retrieve(state, loc::MemRegionVal(MR));
-
+ SVal X = Retrieve(&state, loc::MemRegionVal(MR)).getSVal();
+
// 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;
@@ -442,30 +436,32 @@ BasicStoreManager::RemoveDeadBindings(const GRState *state, Stmt* Loc,
break;
}
}
-
- // Remove dead variable bindings.
+
+ // 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, ValMgr.makeLoc(R));
SVal X = I.getData();
-
+
for (symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end(); SI!=SE; ++SI)
SymReaper.maybeDead(*SI);
}
}
- return store;
+ // Write the store back.
+ state.setStore(store);
}
-Store BasicStoreManager::scanForIvars(Stmt *B, const Decl* SelfDecl, Store St) {
+Store BasicStoreManager::scanForIvars(Stmt *B, const Decl* SelfDecl,
+ const MemRegion *SelfRegion, 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)) {
@@ -473,25 +469,25 @@ Store BasicStoreManager::scanForIvars(Stmt *B, const Decl* SelfDecl, Store St) {
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);
+ SelfRegion);
+ SVal X = ValMgr.getRegionValueSymbolVal(IVR);
St = BindInternal(St, ValMgr.makeLoc(IVR), X);
}
}
}
else
- St = scanForIvars(*CI, SelfDecl, St);
+ St = scanForIvars(*CI, SelfDecl, SelfRegion, St);
}
-
+
return St;
}
-Store BasicStoreManager::getInitialStore() {
+Store BasicStoreManager::getInitialStore(const LocationContext *InitLoc) {
// The LiveVariables information already has a compilation of all VarDecls
// used in the function. Iterate through this set, and "symbolicate"
// any VarDecl whose value originally comes from outside the function.
typedef LiveVariables::AnalysisDataTy LVDataTy;
- LVDataTy& D = StateMgr.getLiveVariables().getAnalysisData();
+ LVDataTy& D = InitLoc->getLiveVariables()->getAnalysisData();
Store St = VBFactory.GetEmptyMap().getRoot();
for (LVDataTy::decl_iterator I=D.begin_decl(), E=D.end_decl(); I != E; ++I) {
@@ -499,38 +495,35 @@ Store BasicStoreManager::getInitialStore() {
// Handle implicit parameters.
if (ImplicitParamDecl* PD = dyn_cast<ImplicitParamDecl>(ND)) {
- const Decl& CD = StateMgr.getCodeDecl();
+ const Decl& CD = *InitLoc->getDecl();
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, ValMgr.makeLoc(MRMgr.getVarRegion(PD)),
+ // FIXME: Just use a symbolic region, and remove ObjCObjectRegion
+ // entirely.
+ const ObjCObjectRegion *SelfRegion =
+ MRMgr.getObjCObjectRegion(MD->getClassInterface(),
+ MRMgr.getHeapRegion());
+
+ St = BindInternal(St, ValMgr.makeLoc(MRMgr.getVarRegion(PD, InitLoc)),
ValMgr.makeLoc(SelfRegion));
-
+
// Scan the method for ivar references. While this requires an
// entire AST scan, the cost should not be high in practice.
- St = scanForIvars(MD->getBody(), PD, St);
+ St = scanForIvars(MD->getBody(), PD, SelfRegion, 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 = ValMgr.getRegionManager().getVarRegion(VD);
- SVal X = R->hasGlobalsOrParametersStorage()
- ? ValMgr.getRegionValueSymbolVal(R)
- : UndefinedVal();
+ const MemRegion *R = ValMgr.getRegionManager().getVarRegion(VD, InitLoc);
+ SVal X = UndefinedVal();
+ if (R->hasGlobalsOrParametersStorage())
+ X = ValMgr.getRegionValueSymbolVal(R);
St = BindInternal(St, ValMgr.makeLoc(R), X);
}
@@ -539,10 +532,11 @@ Store BasicStoreManager::getInitialStore() {
}
Store BasicStoreManager::BindDeclInternal(Store store, const VarDecl* VD,
+ const LocationContext *LC,
SVal* InitVal) {
-
+
BasicValueFactory& BasicVals = StateMgr.getBasicVals();
-
+
// BasicStore does not model arrays and structs.
if (VD->getType()->isArrayType() || VD->getType()->isStructureType())
return store;
@@ -557,28 +551,28 @@ Store BasicStoreManager::BindDeclInternal(Store store, const VarDecl* VD,
// 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
+ // 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),
+ store = BindInternal(store, getLoc(VD, LC),
loc::ConcreteInt(BasicVals.getValue(0, T)));
else if (T->isIntegerType())
- store = BindInternal(store, getLoc(VD),
+ store = BindInternal(store, getLoc(VD, LC),
nonloc::ConcreteInt(BasicVals.getValue(0, T)));
else {
// assert(0 && "ignore other types of variables");
}
} else {
- store = BindInternal(store, getLoc(VD), *InitVal);
+ store = BindInternal(store, getLoc(VD, LC), *InitVal);
}
}
} else {
@@ -586,7 +580,7 @@ Store BasicStoreManager::BindDeclInternal(Store store, const VarDecl* VD,
QualType T = VD->getType();
if (ValMgr.getSymbolManager().canSymbolicate(T)) {
SVal V = InitVal ? *InitVal : UndefinedVal();
- store = BindInternal(store, getLoc(VD), V);
+ store = BindInternal(store, getLoc(VD, LC), V);
}
}
@@ -595,30 +589,48 @@ Store BasicStoreManager::BindDeclInternal(Store store, const VarDecl* VD,
void BasicStoreManager::print(Store store, llvm::raw_ostream& Out,
const char* nl, const char *sep) {
-
+
BindingsTy B = GetBindings(store);
Out << "Variables:" << nl;
-
+
bool isFirst = true;
-
+
for (BindingsTy::iterator I=B.begin(), E=B.end(); I != E; ++I) {
if (isFirst)
isFirst = false;
else
Out << nl;
-
- Out << ' ' << I.getKey() << " : ";
- I.getData().print(Out);
+
+ Out << ' ' << I.getKey() << " : " << I.getData();
}
}
void BasicStoreManager::iterBindings(Store store, BindingsHandler& f) {
BindingsTy B = GetBindings(store);
-
+
for (BindingsTy::iterator I=B.begin(), E=B.end(); I != E; ++I)
f.HandleBinding(*this, store, I.getKey(), I.getData());
}
StoreManager::BindingsHandler::~BindingsHandler() {}
+
+//===----------------------------------------------------------------------===//
+// Binding invalidation.
+//===----------------------------------------------------------------------===//
+
+const GRState *BasicStoreManager::InvalidateRegion(const GRState *state,
+ const MemRegion *R,
+ const Expr *E,
+ unsigned Count) {
+ R = R->getBaseRegion();
+
+ if (!(isa<VarRegion>(R) || isa<ObjCIvarRegion>(R)))
+ return state;
+
+ QualType T = cast<TypedRegion>(R)->getValueType(R->getContext());
+ SVal V = ValMgr.getConjuredSymbolVal(R, E, T, Count);
+ return Bind(state, loc::MemRegionVal(R), V);
+}
+
diff --git a/lib/Analysis/BasicValueFactory.cpp b/lib/Analysis/BasicValueFactory.cpp
index 72ad0a5..b33c277 100644
--- a/lib/Analysis/BasicValueFactory.cpp
+++ b/lib/Analysis/BasicValueFactory.cpp
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
//
// This file defines BasicValueFactory, a class that manages the lifetime
-// of APSInt objects and symbolic constraints used by GRExprEngine
+// of APSInt objects and symbolic constraints used by GRExprEngine
// and related classes.
//
//===----------------------------------------------------------------------===//
@@ -17,12 +17,19 @@
using namespace clang;
-void CompoundValData::Profile(llvm::FoldingSetNodeID& ID, QualType T,
+void CompoundValData::Profile(llvm::FoldingSetNodeID& ID, QualType T,
llvm::ImmutableList<SVal> L) {
T.Profile(ID);
ID.AddPointer(L.getInternalPointer());
}
+void LazyCompoundValData::Profile(llvm::FoldingSetNodeID& ID,
+ const GRState *state,
+ const TypedRegion *region) {
+ ID.AddPointer(state);
+ ID.AddPointer(region);
+}
+
typedef std::pair<SVal, uintptr_t> SValData;
typedef std::pair<SVal, SVal> SValPair;
@@ -33,7 +40,7 @@ template<> struct FoldingSetTrait<SValData> {
ID.AddPointer( (void*) X.second);
}
};
-
+
template<> struct FoldingSetTrait<SValPair> {
static inline void Profile(const SValPair& X, llvm::FoldingSetNodeID& ID) {
X.first.Profile(ID);
@@ -54,8 +61,8 @@ BasicValueFactory::~BasicValueFactory() {
// 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 (PersistentSValsTy*) PersistentSVals;
delete (PersistentSValPairsTy*) PersistentSValPairs;
}
@@ -63,16 +70,16 @@ 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) {
+
+ if (!P) {
P = (FoldNodeTy*) BPAlloc.Allocate<FoldNodeTy>();
new (P) FoldNodeTy(X);
APSIntSet.InsertNode(P, InsertPos);
}
-
+
return *P;
}
@@ -85,22 +92,22 @@ const llvm::APSInt& BasicValueFactory::getValue(const llvm::APInt& X,
const llvm::APSInt& BasicValueFactory::getValue(uint64_t X, unsigned BitWidth,
bool isUnsigned) {
llvm::APSInt V(BitWidth, isUnsigned);
- V = X;
+ 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*
+const CompoundValData*
BasicValueFactory::getCompoundValData(QualType T,
llvm::ImmutableList<SVal> Vals) {
-
+
llvm::FoldingSetNodeID ID;
CompoundValData::Profile(ID, T, Vals);
void* InsertPos;
@@ -116,91 +123,110 @@ BasicValueFactory::getCompoundValData(QualType T,
return D;
}
+const LazyCompoundValData*
+BasicValueFactory::getLazyCompoundValData(const GRState *state,
+ const TypedRegion *region) {
+ llvm::FoldingSetNodeID ID;
+ LazyCompoundValData::Profile(ID, state, region);
+ void* InsertPos;
+
+ LazyCompoundValData *D =
+ LazyCompoundValDataSet.FindNodeOrInsertPos(ID, InsertPos);
+
+ if (!D) {
+ D = (LazyCompoundValData*) BPAlloc.Allocate<LazyCompoundValData>();
+ new (D) LazyCompoundValData(state, region);
+ LazyCompoundValDataSet.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 );
}
@@ -209,21 +235,21 @@ BasicValueFactory::EvaluateAPSInt(BinaryOperator::Opcode Op,
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) {
+
+ if (!P) {
P = (FoldNodeTy*) BPAlloc.Allocate<FoldNodeTy>();
new (P) FoldNodeTy(std::make_pair(V, Data));
Map.InsertNode(P, InsertPos);
@@ -234,31 +260,31 @@ BasicValueFactory::getPersistentSValWithData(const SVal& V, uintptr_t Data) {
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) {
+
+ 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
index 3db96ca..8235f4a 100644
--- a/lib/Analysis/BugReporter.cpp
+++ b/lib/Analysis/BugReporter.cpp
@@ -15,7 +15,7 @@
#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/CFG.h"
+#include "clang/Analysis/CFG.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/StmtObjC.h"
@@ -40,36 +40,36 @@ BugReporterContext::~BugReporterContext() {
// 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();
+static inline const Stmt* GetStmt(ProgramPoint P) {
+ if (const StmtPoint* SP = dyn_cast<StmtPoint>(&P))
+ return SP->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) {
+static inline const ExplodedNode*
+GetPredecessorNode(const ExplodedNode* N) {
return N->pred_empty() ? NULL : *(N->pred_begin());
}
-static inline const ExplodedNode<GRState>*
-GetSuccessorNode(const ExplodedNode<GRState>* N) {
+static inline const ExplodedNode*
+GetSuccessorNode(const ExplodedNode* N) {
return N->succ_empty() ? NULL : *(N->succ_begin());
}
-static Stmt* GetPreviousStmt(const ExplodedNode<GRState>* N) {
+static const Stmt* GetPreviousStmt(const ExplodedNode* N) {
for (N = GetPredecessorNode(N); N; N = GetPredecessorNode(N))
- if (Stmt *S = GetStmt(N->getLocation()))
+ if (const Stmt *S = GetStmt(N->getLocation()))
return S;
-
+
return 0;
}
-static Stmt* GetNextStmt(const ExplodedNode<GRState>* N) {
+static const Stmt* GetNextStmt(const ExplodedNode* N) {
for (N = GetSuccessorNode(N); N; N = GetSuccessorNode(N))
- if (Stmt *S = GetStmt(N->getLocation())) {
+ if (const Stmt *S = GetStmt(N->getLocation())) {
// Check if the statement is '?' or '&&'/'||'. These are "merges",
// not actual statement points.
switch (S->getStmtClass()) {
@@ -84,23 +84,30 @@ static Stmt* GetNextStmt(const ExplodedNode<GRState>* N) {
default:
break;
}
+
+ // Some expressions don't have locations.
+ if (S->getLocStart().isInvalid())
+ continue;
+
return S;
}
-
+
return 0;
}
-static inline Stmt* GetCurrentOrPreviousStmt(const ExplodedNode<GRState>* N) {
- if (Stmt *S = GetStmt(N->getLocation()))
+static inline const Stmt*
+GetCurrentOrPreviousStmt(const ExplodedNode* N) {
+ if (const Stmt *S = GetStmt(N->getLocation()))
return S;
-
+
return GetPreviousStmt(N);
}
-
-static inline Stmt* GetCurrentOrNextStmt(const ExplodedNode<GRState>* N) {
- if (Stmt *S = GetStmt(N->getLocation()))
+
+static inline const Stmt*
+GetCurrentOrNextStmt(const ExplodedNode* N) {
+ if (const Stmt *S = GetStmt(N->getLocation()))
return S;
-
+
return GetNextStmt(N);
}
@@ -108,8 +115,8 @@ static inline Stmt* GetCurrentOrNextStmt(const ExplodedNode<GRState>* N) {
// PathDiagnosticBuilder and its associated routines and helper objects.
//===----------------------------------------------------------------------===//
-typedef llvm::DenseMap<const ExplodedNode<GRState>*,
-const ExplodedNode<GRState>*> NodeBackMap;
+typedef llvm::DenseMap<const ExplodedNode*,
+const ExplodedNode*> NodeBackMap;
namespace {
class VISIBILITY_HIDDEN NodeMapClosure : public BugReport::NodeResolver {
@@ -117,101 +124,100 @@ class VISIBILITY_HIDDEN NodeMapClosure : public BugReport::NodeResolver {
public:
NodeMapClosure(NodeBackMap *m) : M(*m) {}
~NodeMapClosure() {}
-
- const ExplodedNode<GRState>* getOriginalNode(const ExplodedNode<GRState>* N) {
+
+ const ExplodedNode* getOriginalNode(const ExplodedNode* 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:
+public:
PathDiagnosticBuilder(GRBugReporter &br,
- BugReport *r, NodeBackMap *Backmap,
+ BugReport *r, NodeBackMap *Backmap,
PathDiagnosticClient *pdc)
: BugReporterContext(br),
- R(r), PDC(pdc), NMC(Backmap)
- {
+ R(r), PDC(pdc), NMC(Backmap) {
addVisitor(R);
}
-
- PathDiagnosticLocation ExecutionContinues(const ExplodedNode<GRState>* N);
-
+
+ PathDiagnosticLocation ExecutionContinues(const ExplodedNode* N);
+
PathDiagnosticLocation ExecutionContinues(llvm::raw_string_ostream& os,
- const ExplodedNode<GRState>* N);
-
- ParentMap& getParentMap() {
- if (PM.get() == 0)
- PM.reset(new ParentMap(getCodeDecl().getBody()));
- return *PM.get();
- }
-
+ const ExplodedNode* N);
+
+ Decl const &getCodeDecl() { return R->getEndNode()->getCodeDecl(); }
+
+ ParentMap& getParentMap() { return R->getEndNode()->getParentMap(); }
+
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))
+PathDiagnosticBuilder::ExecutionContinues(const ExplodedNode* N) {
+ if (const Stmt *S = GetNextStmt(N))
return PathDiagnosticLocation(S, getSourceManager());
- return FullSourceLoc(getCodeDecl().getBodyRBrace(), getSourceManager());
+ return FullSourceLoc(N->getLocationContext()->getDecl()->getBodyRBrace(),
+ getSourceManager());
}
-
+
PathDiagnosticLocation
PathDiagnosticBuilder::ExecutionContinues(llvm::raw_string_ostream& os,
- const ExplodedNode<GRState>* N) {
+ const ExplodedNode* 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") << '.';
-
+ << (isa<ObjCMethodDecl>(N->getLocationContext()->getDecl()) ?
+ "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:
@@ -221,29 +227,29 @@ static bool IsNested(const Stmt *S, ParentMap &PM) {
default:
break;
}
-
- return false;
+
+ return false;
}
PathDiagnosticLocation
PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) {
assert(S && "Null Stmt* passed to getEnclosingStmtLocation");
- ParentMap &P = getParentMap();
+ 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);
@@ -253,20 +259,20 @@ PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) {
if (cast<ChooseExpr>(Parent)->getCond() == S)
return PathDiagnosticLocation(Parent, SMgr);
else
- return PathDiagnosticLocation(S, SMgr);
+ 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);
+ return PathDiagnosticLocation(S, SMgr);
case Stmt::DoStmtClass:
- return PathDiagnosticLocation(S, SMgr);
+ return PathDiagnosticLocation(S, SMgr);
case Stmt::ForStmtClass:
if (cast<ForStmt>(Parent)->getBody() == S)
- return PathDiagnosticLocation(S, SMgr);
- break;
+ return PathDiagnosticLocation(S, SMgr);
+ break;
case Stmt::IfStmtClass:
if (cast<IfStmt>(Parent)->getCond() != S)
return PathDiagnosticLocation(S, SMgr);
@@ -285,7 +291,7 @@ PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) {
S = Parent;
}
-
+
assert(S && "Cannot have null Stmt for PathDiagnosticLocation");
// Special case: DeclStmts can appear in for statement declarations, in which
@@ -298,8 +304,8 @@ PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) {
return PathDiagnosticLocation(Parent, SMgr);
default:
break;
- }
- }
+ }
+ }
}
else if (isa<BinaryOperator>(S)) {
// Special case: the binary operator represents the initialization
@@ -320,86 +326,86 @@ PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) {
//===----------------------------------------------------------------------===//
static const VarDecl*
-GetMostRecentVarDeclBinding(const ExplodedNode<GRState>* N,
+GetMostRecentVarDeclBinding(const ExplodedNode* 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());
-
+
+ const DeclRefExpr* DR = dyn_cast<DeclRefExpr>(cast<PostStmt>(P).getStmt());
+
if (!DR)
continue;
-
+
SVal Y = N->getState()->getSVal(DR);
-
+
if (X != Y)
continue;
-
- VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl());
-
+
+ const VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl());
+
if (!VD)
continue;
-
+
return VD;
}
-
+
return 0;
}
namespace {
-class VISIBILITY_HIDDEN NotableSymbolHandler
+class VISIBILITY_HIDDEN NotableSymbolHandler
: public StoreManager::BindingsHandler {
-
+
SymbolRef Sym;
const GRState* PrevSt;
const Stmt* S;
GRStateManager& VMgr;
- const ExplodedNode<GRState>* Pred;
- PathDiagnostic& PD;
+ const ExplodedNode* Pred;
+ PathDiagnostic& PD;
BugReporter& BR;
-
+
public:
-
+
NotableSymbolHandler(SymbolRef sym, const GRState* prevst, const Stmt* s,
- GRStateManager& vmgr, const ExplodedNode<GRState>* pred,
+ GRStateManager& vmgr, const ExplodedNode* pred,
PathDiagnostic& pd, BugReporter& br)
: Sym(sym), PrevSt(prevst), S(s), VMgr(vmgr), Pred(pred), PD(pd), BR(br) {}
-
+
bool HandleBinding(StoreManager& SMgr, Store store, const MemRegion* R,
SVal V) {
-
+
SymbolRef ScanSym = V.getAsSymbol();
-
+
if (ScanSym != Sym)
return true;
-
- // Check if the previous state has this binding.
+
+ // Check if the previous state has this binding.
SVal X = PrevSt->getSVal(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
+ // 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)) {
@@ -408,42 +414,42 @@ public:
// 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,
+static void HandleNotableSymbol(const ExplodedNode* N,
const Stmt* S,
SymbolRef Sym, BugReporter& BR,
PathDiagnostic& PD) {
-
- const ExplodedNode<GRState>* Pred = N->pred_empty() ? 0 : *N->pred_begin();
+
+ const ExplodedNode* 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();
@@ -454,34 +460,34 @@ static void HandleNotableSymbol(const ExplodedNode<GRState>* N,
namespace {
class VISIBILITY_HIDDEN ScanNotableSymbols
: public StoreManager::BindingsHandler {
-
+
llvm::SmallSet<SymbolRef, 10> AlreadyProcessed;
- const ExplodedNode<GRState>* N;
- Stmt* S;
+ const ExplodedNode* N;
+ const Stmt* S;
GRBugReporter& BR;
PathDiagnostic& PD;
-
+
public:
- ScanNotableSymbols(const ExplodedNode<GRState>* n, Stmt* s, GRBugReporter& br,
- PathDiagnostic& pd)
+ ScanNotableSymbols(const ExplodedNode* n, const 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;
}
@@ -496,57 +502,57 @@ static void CompactPathDiagnostic(PathDiagnostic &PD, const SourceManager& SM);
static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
PathDiagnosticBuilder &PDB,
- const ExplodedNode<GRState> *N) {
+ const ExplodedNode *N) {
SourceManager& SMgr = PDB.getSourceManager();
- const ExplodedNode<GRState>* NextNode = N->pred_empty()
+ const ExplodedNode* NextNode = N->pred_empty()
? NULL : *(N->pred_begin());
while (NextNode) {
- N = 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);
-
+ case Stmt::IndirectGotoStmtClass: {
+ const Stmt* S = GetNextStmt(N);
+
if (!S)
continue;
-
+
std::string sbuf;
- llvm::raw_string_ostream os(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: {
+
+ 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. "
@@ -557,21 +563,21 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
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);
+ os << "Control jumps to 'case ";
+ CaseStmt* Case = cast<CaseStmt>(S);
Expr* LHS = Case->getLHS()->IgnoreParenCasts();
-
- // Determine if it is an enum.
+
+ // 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();
@@ -591,14 +597,14 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
}
else {
os << "'Default' branch taken. ";
- const PathDiagnosticLocation &End = PDB.ExecutionContinues(os, N);
+ 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;
@@ -608,117 +614,117 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
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()));
+ os.str()));
}
else {
os << "true";
PathDiagnosticLocation End(B->getLHS(), SMgr);
PathDiagnosticLocation Start(B->getOperatorLoc(), SMgr);
PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
- os.str()));
+ os.str()));
}
}
-
+
break;
}
-
- case Stmt::DoStmtClass: {
+
+ 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: {
+ 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()));
}
@@ -726,32 +732,32 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
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
+ 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) {
@@ -759,15 +765,15 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
PD.push_front(p);
}
}
-
- if (const PostStmt* PS = dyn_cast<PostStmt>(&P)) {
+
+ if (const PostStmt* PS = dyn_cast<PostStmt>(&P)) {
// Scan the region bindings, and see if a "notable" symbol has a new
// lval binding.
ScanNotableSymbols SNS(N, PS->getStmt(), PDB.getBugReporter(), PD);
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());
@@ -779,20 +785,20 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
static bool IsControlFlowExpr(const Stmt *S) {
const Expr *E = dyn_cast<Expr>(S);
-
+
if (!E)
return false;
-
- E = E->IgnoreParenCasts();
-
+
+ E = E->IgnoreParenCasts();
+
if (isa<ConditionalOperator>(E))
return true;
-
+
if (const BinaryOperator *B = dyn_cast<BinaryOperator>(E))
if (B->isLogicalOp())
return true;
-
- return false;
+
+ return false;
}
namespace {
@@ -801,25 +807,25 @@ class VISIBILITY_HIDDEN ContextLocation : public PathDiagnosticLocation {
public:
ContextLocation(const PathDiagnosticLocation &L, bool isdead = false)
: PathDiagnosticLocation(L), IsDead(isdead) {}
-
- void markDead() { IsDead = true; }
+
+ 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()) {
@@ -847,20 +853,20 @@ class VISIBILITY_HIDDEN EdgeBuilder {
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.
@@ -868,18 +874,18 @@ class VISIBILITY_HIDDEN EdgeBuilder {
}
CLocs.pop_back();
}
-
- PathDiagnosticLocation IgnoreParens(const PathDiagnosticLocation &L);
+
+ 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());
}
@@ -887,7 +893,7 @@ public:
~EdgeBuilder() {
while (!CLocs.empty()) popLocation();
-
+
// Finally, add an initial edge from the start location of the first
// statement (if it doesn't already exist).
// FIXME: Should handle CXXTryStmt if analyser starts supporting C++.
@@ -897,20 +903,20 @@ public:
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
@@ -919,10 +925,10 @@ EdgeBuilder::getContextLocation(const PathDiagnosticLocation &L) {
if (const Stmt *S = L.asStmt()) {
if (IsControlFlowExpr(S))
return L;
-
- return PDB.getEnclosingStmtLocation(S);
+
+ return PDB.getEnclosingStmtLocation(S);
}
-
+
return L;
}
@@ -931,10 +937,10 @@ bool EdgeBuilder::containsLocation(const PathDiagnosticLocation &Container,
if (Container == Containee)
return true;
-
+
if (Container.asDecl())
return true;
-
+
if (const Stmt *S = Containee.asStmt())
if (const Stmt *ContainerS = Container.asStmt()) {
while (S) {
@@ -948,25 +954,25 @@ bool EdgeBuilder::containsLocation(const PathDiagnosticLocation &Container,
// 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);
-
+ assert(ContaineeBegLine <= ContaineeEndLine);
+
return (ContainerBegLine <= ContaineeBegLine &&
ContainerEndLine >= ContaineeEndLine &&
(ContainerBegLine != ContaineeBegLine ||
- SM.getInstantiationColumnNumber(ContainerRBeg) <=
+ SM.getInstantiationColumnNumber(ContainerRBeg) <=
SM.getInstantiationColumnNumber(ContaineeRBeg)) &&
(ContainerEndLine != ContaineeEndLine ||
SM.getInstantiationColumnNumber(ContainerREnd) >=
@@ -986,13 +992,13 @@ void EdgeBuilder::rawAddEdge(PathDiagnosticLocation NewLoc) {
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())
@@ -1003,15 +1009,15 @@ void EdgeBuilder::rawAddEdge(PathDiagnosticLocation 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) {
@@ -1028,21 +1034,21 @@ void EdgeBuilder::addEdge(PathDiagnosticLocation NewLoc, bool alwaysAdd) {
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;
+ 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);
}
@@ -1050,15 +1056,15 @@ void EdgeBuilder::addEdge(PathDiagnosticLocation NewLoc, bool alwaysAdd) {
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);
+
+ const Stmt *Parent = PDB.getParent(S);
while (Parent) {
if (isa<CompoundStmt>(Parent))
Parent = PDB.getParent(Parent);
@@ -1075,16 +1081,16 @@ void EdgeBuilder::addExtendedContext(const Stmt *S) {
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();
@@ -1094,7 +1100,7 @@ void EdgeBuilder::addContext(const Stmt *S) {
if (containsLocation(TopContextLoc, L)) {
CLocs.push_back(L);
- return;
+ return;
}
// Context does not contain the location. Flush it.
@@ -1106,12 +1112,12 @@ void EdgeBuilder::addContext(const Stmt *S) {
static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
PathDiagnosticBuilder &PDB,
- const ExplodedNode<GRState> *N) {
-
-
+ const ExplodedNode *N) {
+
+
EdgeBuilder EB(PD, PDB);
- const ExplodedNode<GRState>* NextNode = N->pred_empty()
+ const ExplodedNode* NextNode = N->pred_empty()
? NULL : *(N->pred_begin());
while (NextNode) {
N = NextNode;
@@ -1123,26 +1129,26 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
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());
+ 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());
@@ -1150,14 +1156,14 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
EB.addEdge(BL);
}
}
-
+
if (Term)
EB.addContext(Term);
-
+
break;
}
- if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) {
+ if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) {
if (const Stmt* S = BE->getFirstStmt()) {
if (IsControlFlowExpr(S)) {
// Add the proper context for '&&', '||', and '?'.
@@ -1170,10 +1176,10 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
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)) {
@@ -1181,16 +1187,25 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
EB.addEdge(Loc, true);
PD.push_front(p);
if (const Stmt *S = Loc.asStmt())
- EB.addExtendedContext(PDB.getEnclosingStmtLocation(S).asStmt());
+ EB.addExtendedContext(PDB.getEnclosingStmtLocation(S).asStmt());
}
- }
+ }
}
}
//===----------------------------------------------------------------------===//
// Methods for BugType and subclasses.
//===----------------------------------------------------------------------===//
-BugType::~BugType() {}
+BugType::~BugType() {
+ // Free up the equivalence class objects. Observe that we get a pointer to
+ // the object first before incrementing the iterator, as destroying the
+ // node before doing so means we will read from freed memory.
+ for (iterator I = begin(), E = end(); I !=E; ) {
+ BugReportEquivClass *EQ = &*I;
+ ++I;
+ delete EQ;
+ }
+}
void BugType::FlushReports(BugReporter &BR) {}
//===----------------------------------------------------------------------===//
@@ -1199,46 +1214,47 @@ void BugType::FlushReports(BugReporter &BR) {}
BugReport::~BugReport() {}
RangedBugReport::~RangedBugReport() {}
-Stmt* BugReport::getStmt(BugReporter& BR) const {
- ProgramPoint ProgP = EndNode->getLocation();
- Stmt *S = NULL;
-
+const Stmt* BugReport::getStmt() const {
+ ProgramPoint ProgP = EndNode->getLocation();
+ const Stmt *S = NULL;
+
if (BlockEntrance* BE = dyn_cast<BlockEntrance>(&ProgP)) {
- if (BE->getBlock() == &BR.getCFG()->getExit()) S = GetPreviousStmt(EndNode);
+ CFGBlock &Exit = ProgP.getLocationContext()->getCFG()->getExit();
+ if (BE->getBlock() == &Exit)
+ S = GetPreviousStmt(EndNode);
}
- if (!S) S = GetStmt(ProgP);
-
- return S;
+ if (!S)
+ S = GetStmt(ProgP);
+
+ return S;
}
PathDiagnosticPiece*
BugReport::getEndPath(BugReporterContext& BRC,
- const ExplodedNode<GRState>* EndPathNode) {
-
- Stmt* S = getStmt(BRC.getBugReporter());
-
+ const ExplodedNode* EndPathNode) {
+
+ const Stmt* S = getStmt();
+
if (!S)
return NULL;
const SourceRange *Beg, *End;
- getRanges(BRC.getBugReporter(), Beg, End);
+ getRanges(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))) {
+void BugReport::getRanges(const SourceRange*& beg, const SourceRange*& end) {
+ if (const Expr* E = dyn_cast_or_null<Expr>(getStmt())) {
R = E->getSourceRange();
assert(R.isValid());
beg = &R;
@@ -1248,12 +1264,15 @@ void BugReport::getRanges(BugReporter& BR, const SourceRange*& beg,
beg = end = 0;
}
-SourceLocation BugReport::getLocation() const {
+SourceLocation BugReport::getLocation() const {
if (EndNode)
- if (Stmt* S = GetCurrentOrPreviousStmt(EndNode)) {
+ if (const Stmt* S = GetCurrentOrPreviousStmt(EndNode)) {
// For member expressions, return the location of the '.' or '->'.
- if (MemberExpr* ME = dyn_cast<MemberExpr>(S))
+ if (const MemberExpr *ME = dyn_cast<MemberExpr>(S))
return ME->getMemberLoc();
+ // For binary operators, return the location of the operator.
+ if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S))
+ return B->getOperatorLoc();
return S->getLocStart();
}
@@ -1261,8 +1280,8 @@ SourceLocation BugReport::getLocation() const {
return FullSourceLoc();
}
-PathDiagnosticPiece* BugReport::VisitNode(const ExplodedNode<GRState>* N,
- const ExplodedNode<GRState>* PrevN,
+PathDiagnosticPiece* BugReport::VisitNode(const ExplodedNode* N,
+ const ExplodedNode* PrevN,
BugReporterContext &BRC) {
return NULL;
}
@@ -1275,11 +1294,10 @@ BugReportEquivClass::~BugReportEquivClass() {
for (iterator I=begin(), E=end(); I!=E; ++I) delete *I;
}
-GRBugReporter::~GRBugReporter() { FlushReports(); }
+GRBugReporter::~GRBugReporter() { }
BugReporterData::~BugReporterData() {}
-ExplodedGraph<GRState>&
-GRBugReporter::getGraph() { return Eng.getGraph(); }
+ExplodedGraph &GRBugReporter::getGraph() { return Eng.getGraph(); }
GRStateManager&
GRBugReporter::getStateManager() { return Eng.getStateManager(); }
@@ -1308,9 +1326,8 @@ void BugReporter::FlushReports() {
BugReportEquivClass& EQ = *EI;
FlushReport(EQ);
}
-
- // Delete the BugType object. This will also delete the equivalence
- // classes.
+
+ // Delete the BugType object.
delete BT;
}
@@ -1322,137 +1339,134 @@ void BugReporter::FlushReports() {
// 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) {
-
+static std::pair<std::pair<ExplodedGraph*, NodeBackMap*>,
+ std::pair<ExplodedNode*, unsigned> >
+MakeReportGraph(const ExplodedGraph* G,
+ const ExplodedNode** NStart,
+ const ExplodedNode** 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 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;
+ ExplodedGraph* GTrim;
+ InterExplodedGraphMap* 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);
-
+ llvm::OwningPtr<ExplodedGraph> AutoReleaseGTrim(GTrim);
+ llvm::OwningPtr<InterExplodedGraphMap> 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;
+ std::queue<const ExplodedNode*> WS;
+ typedef llvm::DenseMap<const ExplodedNode*, unsigned> IndexMapTy;
IndexMapTy IndexMap;
- for (const ExplodedNode<GRState>** I = NStart; I != NEnd; ++I)
- if (const ExplodedNode<GRState> *N = NMap->getMappedNode(*I)) {
+ for (const ExplodedNode** I = NStart; I != NEnd; ++I)
+ if (const ExplodedNode *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());
-
+ ExplodedGraph *GNew = new ExplodedGraph(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;
-
+ const ExplodedNode* Root = 0;
+
while (!WS.empty()) {
- const ExplodedNode<GRState>* Node = WS.front();
+ const ExplodedNode* 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(),
+
+ for (ExplodedNode::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;
+ ExplodedNode *Last = 0, *First = 0;
NodeBackMap *BM = new NodeBackMap();
unsigned NodeIndex = 0;
-
- for ( const ExplodedNode<GRState> *N = Root ;;) {
+
+ for ( const ExplodedNode *N = Root ;;) {
// Lookup the number associated with the current node.
llvm::DenseMap<const void*,unsigned>::iterator I = Visited.find(N);
assert(I != Visited.end());
-
+
// Create the equivalent node in the new graph with the same state
// and location.
- ExplodedNode<GRState>* NewN =
- GNew->getNode(N->getLocation(), N->getState());
-
+ ExplodedNode* NewN = GNew->getNode(N->getLocation(), N->getState());
+
// Store the mapping to the original node.
llvm::DenseMap<const void*, const void*>::iterator IMitr=InverseMap.find(N);
assert(IMitr != InverseMap.end() && "No mapping to original node.");
- (*BM)[NewN] = (const ExplodedNode<GRState>*) IMitr->second;
-
+ (*BM)[NewN] = (const ExplodedNode*) IMitr->second;
+
// Link up the new node with the previous node.
if (Last)
- NewN->addPredecessor(Last);
-
+ NewN->addPredecessor(Last, *GNew);
+
Last = NewN;
-
+
// Are we at the final node?
IndexMapTy::iterator IMI =
- IndexMap.find((const ExplodedNode<GRState>*)(IMitr->second));
+ IndexMap.find((const ExplodedNode*)(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();
+ ExplodedNode::const_succ_iterator SI = N->succ_begin();
+ ExplodedNode::const_succ_iterator SE = N->succ_end();
N = 0;
-
+
for (unsigned MinVal = 0; SI != SE; ++SI) {
-
+
I = Visited.find(*SI);
-
+
if (I == Visited.end())
continue;
-
+
if (!N || I->second < MinVal) {
N = *SI;
MinVal = I->second;
}
}
-
+
assert(N);
}
-
+
assert(First);
return std::make_pair(std::make_pair(GNew, BM),
@@ -1464,23 +1478,23 @@ MakeReportGraph(const ExplodedGraph<GRState>* G,
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();
-
+ const FullSourceLoc Loc = I->getLocation().asLocation();
+
// Determine the instantiation location, which is the location we group
// related PathDiagnosticPieces.
- SourceLocation InstantiationLoc = Loc.isMacroID() ?
+ SourceLocation InstantiationLoc = Loc.isMacroID() ?
SM.getInstantiationLoc(Loc) :
SourceLocation();
-
+
if (Loc.isFileID()) {
MacroStack.clear();
Pieces.push_back(&*I);
@@ -1488,7 +1502,7 @@ static void CompactPathDiagnostic(PathDiagnostic &PD, const SourceManager& SM) {
}
assert(Loc.isMacroID());
-
+
// Is the PathDiagnosticPiece within the same macro group?
if (!MacroStack.empty() && InstantiationLoc == MacroStack.back().second) {
MacroStack.back().first->push_back(&*I);
@@ -1502,22 +1516,22 @@ static void CompactPathDiagnostic(PathDiagnostic &PD, const SourceManager& SM) {
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);
@@ -1528,7 +1542,7 @@ static void CompactPathDiagnostic(PathDiagnostic &PD, const SourceManager& SM) {
assert(InstantiationLoc.isFileID());
Pieces.push_back(NewGroup);
}
-
+
MacroGroup = NewGroup;
MacroStack.push_back(std::make_pair(MacroGroup, InstantiationLoc));
}
@@ -1536,62 +1550,62 @@ static void CompactPathDiagnostic(PathDiagnostic &PD, const SourceManager& SM) {
// 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;
-
+
+ std::vector<const ExplodedNode*> Nodes;
+
for (BugReportEquivClass::iterator I=EQ.begin(), E=EQ.end(); I!=E; ++I) {
- const ExplodedNode<GRState>* N = I->getEndNode();
+ const ExplodedNode* 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> >&
+ // node to a root.
+ const std::pair<std::pair<ExplodedGraph*, NodeBackMap*>,
+ std::pair<ExplodedNode*, 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<ExplodedGraph> ReportGraph(GPair.first.first);
llvm::OwningPtr<NodeBackMap> BackMap(GPair.first.second);
- const ExplodedNode<GRState> *N = GPair.second.first;
-
- // Start building the path diagnostic...
+ const ExplodedNode *N = GPair.second.first;
+
+ // Start building the path diagnostic...
PathDiagnosticBuilder PDB(*this, R, BackMap.get(), getPathDiagnosticClient());
-
+
if (PathDiagnosticPiece* Piece = R->getEndPath(PDB, N))
PD.push_back(Piece);
else
return;
-
+
R->registerInitialVisitors(PDB, N);
-
+
switch (PDB.getGenerationScheme()) {
case PathDiagnosticClient::Extensive:
GenerateExtensivePathDiagnostic(PD, PDB, N);
@@ -1606,17 +1620,17 @@ void BugReporter::Register(BugType *BT) {
BugTypes = F.Add(BugTypes, BT);
}
-void BugReporter::EmitReport(BugReport* R) {
+void BugReporter::EmitReport(BugReport* R) {
// Compute the bug report's hash to determine its equivalence class.
llvm::FoldingSetNodeID ID;
R->Profile(ID);
-
- // Lookup the equivance class. If there isn't one, create it.
+
+ // 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);
-
+ BugReportEquivClass* EQ = BT.EQClasses.FindNodeOrInsertPos(ID, InsertPos);
+
if (!EQ) {
EQ = new BugReportEquivClass(R);
BT.EQClasses.InsertNode(EQ, InsertPos);
@@ -1625,34 +1639,178 @@ void BugReporter::EmitReport(BugReport* R) {
EQ->AddReport(R);
}
+
+//===----------------------------------------------------------------------===//
+// Emitting reports in equivalence classes.
+//===----------------------------------------------------------------------===//
+
+namespace {
+struct VISIBILITY_HIDDEN FRIEC_WLItem {
+ const ExplodedNode *N;
+ ExplodedNode::const_succ_iterator I, E;
+
+ FRIEC_WLItem(const ExplodedNode *n)
+ : N(n), I(N->succ_begin()), E(N->succ_end()) {}
+};
+}
+
+static BugReport *FindReportInEquivalenceClass(BugReportEquivClass& EQ) {
+ BugReportEquivClass::iterator I = EQ.begin(), E = EQ.end();
+ assert(I != E);
+ BugReport *R = *I;
+ BugType& BT = R->getBugType();
+
+ if (!BT.isSuppressOnSink())
+ return R;
+
+ // For bug reports that should be suppressed when all paths are post-dominated
+ // by a sink node, iterate through the reports in the equivalence class
+ // until we find one that isn't post-dominated (if one exists). We use a
+ // DFS traversal of the ExplodedGraph to find a non-sink node. We could write
+ // this as a recursive function, but we don't want to risk blowing out the
+ // stack for very long paths.
+ for (; I != E; ++I) {
+ R = *I;
+ const ExplodedNode *N = R->getEndNode();
+
+ if (!N)
+ continue;
+
+ if (N->isSink()) {
+ assert(false &&
+ "BugType::isSuppressSink() should not be 'true' for sink end nodes");
+ return R;
+ }
+
+ if (N->succ_empty())
+ return R;
+
+ // At this point we know that 'N' is not a sink and it has at least one
+ // successor. Use a DFS worklist to find a non-sink end-of-path node.
+ typedef FRIEC_WLItem WLItem;
+ typedef llvm::SmallVector<WLItem, 10> DFSWorkList;
+ llvm::DenseMap<const ExplodedNode *, unsigned> Visited;
+
+ DFSWorkList WL;
+ WL.push_back(N);
+ Visited[N] = 1;
+
+ while (!WL.empty()) {
+ WLItem &WI = WL.back();
+ assert(!WI.N->succ_empty());
+
+ for (; WI.I != WI.E; ++WI.I) {
+ const ExplodedNode *Succ = *WI.I;
+ // End-of-path node?
+ if (Succ->succ_empty()) {
+ // If we found an end-of-path node that is not a sink, then return
+ // this report.
+ if (!Succ->isSink())
+ return R;
+
+ // Found a sink? Continue on to the next successor.
+ continue;
+ }
+
+ // Mark the successor as visited. If it hasn't been explored,
+ // enqueue it to the DFS worklist.
+ unsigned &mark = Visited[Succ];
+ if (!mark) {
+ mark = 1;
+ WL.push_back(Succ);
+ break;
+ }
+ }
+
+ if (&WL.back() == &WI)
+ WL.pop_back();
+ }
+ }
+
+ // If we reach here, the end nodes for all reports in the equivalence
+ // class are post-dominated by a sink node.
+ return NULL;
+}
+
+
+//===----------------------------------------------------------------------===//
+// DiagnosticCache. This is a hack to cache analyzer diagnostics. It
+// uses global state, which eventually should go elsewhere.
+//===----------------------------------------------------------------------===//
+namespace {
+class VISIBILITY_HIDDEN DiagCacheItem : public llvm::FoldingSetNode {
+ llvm::FoldingSetNodeID ID;
+public:
+ DiagCacheItem(BugReport *R, PathDiagnostic *PD) {
+ ID.AddString(R->getBugType().getName());
+ ID.AddString(R->getBugType().getCategory());
+ ID.AddString(R->getDescription());
+ ID.AddInteger(R->getLocation().getRawEncoding());
+ PD->Profile(ID);
+ }
+
+ void Profile(llvm::FoldingSetNodeID &id) {
+ id = ID;
+ }
+
+ llvm::FoldingSetNodeID &getID() { return ID; }
+};
+}
+
+static bool IsCachedDiagnostic(BugReport *R, PathDiagnostic *PD) {
+ // FIXME: Eventually this diagnostic cache should reside in something
+ // like AnalysisManager instead of being a static variable. This is
+ // really unsafe in the long term.
+ typedef llvm::FoldingSet<DiagCacheItem> DiagnosticCache;
+ static DiagnosticCache DC;
+
+ void *InsertPos;
+ DiagCacheItem *Item = new DiagCacheItem(R, PD);
+
+ if (DC.FindNodeOrInsertPos(Item->getID(), InsertPos)) {
+ delete Item;
+ return true;
+ }
+
+ DC.InsertNode(Item, InsertPos);
+ return false;
+}
+
void BugReporter::FlushReport(BugReportEquivClass& EQ) {
- assert(!EQ.Reports.empty());
- BugReport &R = **EQ.begin();
- PathDiagnosticClient* PD = getPathDiagnosticClient();
+ BugReport *R = FindReportInEquivalenceClass(EQ);
+
+ if (!R)
+ return;
+ 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();
-
+ // Probably doesn't make a difference in practice.
+ BugType& BT = R->getBugType();
+
llvm::OwningPtr<PathDiagnostic>
- D(new PathDiagnostic(R.getBugType().getName(),
+ D(new PathDiagnostic(R->getBugType().getName(),
!PD || PD->useVerboseDescription()
- ? R.getDescription() : R.getShortDescription(),
+ ? R->getDescription() : R->getShortDescription(),
BT.getCategory()));
GeneratePathDiagnostic(*D.get(), EQ);
+
+ if (IsCachedDiagnostic(R, D.get()))
+ return;
// 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);
+ 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);
+ R->getRanges(Beg, End);
Diagnostic& Diag = getDiagnostic();
- FullSourceLoc L(R.getLocation(), getSourceManager());
+ FullSourceLoc L(R->getLocation(), getSourceManager());
unsigned ErrorDiag = Diag.getCustomDiagID(Diagnostic::Warning,
- R.getShortDescription().c_str());
+ R->getShortDescription().c_str());
switch (End-Beg) {
default: assert(0 && "Don't handle this many ranges yet!");
@@ -1665,15 +1823,15 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) {
// Emit a full diagnostic for the path if we have a PathDiagnosticClient.
if (!PD)
return;
-
- if (D->empty()) {
+
+ if (D->empty()) {
PathDiagnosticPiece* piece =
- new PathDiagnosticEventPiece(L, R.getDescription());
+ new PathDiagnosticEventPiece(L, R->getDescription());
for ( ; Beg != End; ++Beg) piece->addRange(*Beg);
D->push_back(piece);
}
-
+
PD->HandlePathDiagnostic(D.take());
}
@@ -1686,7 +1844,7 @@ void BugReporter::EmitBasicReport(const char* name, const char* str,
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);
diff --git a/lib/Analysis/BugReporterVisitors.cpp b/lib/Analysis/BugReporterVisitors.cpp
new file mode 100644
index 0000000..89c9ca1
--- /dev/null
+++ b/lib/Analysis/BugReporterVisitors.cpp
@@ -0,0 +1,349 @@
+// BugReporterVisitors.cpp - Helpers for reporting 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 a set of BugReporter "visitors" which can be used to
+// enhance the diagnostics reported for a bug.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Analysis/PathDiagnostic.h"
+#include "clang/Analysis/PathSensitive/GRState.h"
+
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Utility functions.
+//===----------------------------------------------------------------------===//
+
+const Stmt *clang::bugreporter::GetDerefExpr(const ExplodedNode *N) {
+ // Pattern match for a few useful cases (do something smarter later):
+ // a[0], p->f, *p
+ const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
+
+ 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;
+}
+
+const Stmt*
+clang::bugreporter::GetReceiverExpr(const ExplodedNode *N){
+ const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
+ if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S))
+ return ME->getReceiver();
+ return NULL;
+}
+
+const Stmt*
+clang::bugreporter::GetDenomExpr(const ExplodedNode *N) {
+ const Stmt *S = N->getLocationAs<PreStmt>()->getStmt();
+ if (const BinaryOperator *BE = dyn_cast<BinaryOperator>(S))
+ return BE->getRHS();
+ return NULL;
+}
+
+const Stmt*
+clang::bugreporter::GetCalleeExpr(const ExplodedNode *N) {
+ // Callee is checked as a PreVisit to the CallExpr.
+ const Stmt *S = N->getLocationAs<PreStmt>()->getStmt();
+ if (const CallExpr *CE = dyn_cast<CallExpr>(S))
+ return CE->getCallee();
+ return NULL;
+}
+
+const Stmt*
+clang::bugreporter::GetRetValExpr(const ExplodedNode *N) {
+ const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
+ if (const ReturnStmt *RS = dyn_cast<ReturnStmt>(S))
+ return RS->getRetValue();
+ return NULL;
+}
+
+//===----------------------------------------------------------------------===//
+// Definitions for bug reporter visitors.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class VISIBILITY_HIDDEN FindLastStoreBRVisitor : public BugReporterVisitor {
+ const MemRegion *R;
+ SVal V;
+ bool satisfied;
+ const ExplodedNode *StoreSite;
+public:
+ FindLastStoreBRVisitor(SVal v, const MemRegion *r)
+ : R(r), V(v), satisfied(false), StoreSite(0) {}
+
+ PathDiagnosticPiece* VisitNode(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext& BRC) {
+
+ if (satisfied)
+ return NULL;
+
+ if (!StoreSite) {
+ const ExplodedNode *Node = N, *Last = NULL;
+
+ for ( ; Node ; Last = Node, Node = Node->getFirstPred()) {
+
+ if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
+ if (const PostStmt *P = Node->getLocationAs<PostStmt>())
+ if (const DeclStmt *DS = P->getStmtAs<DeclStmt>())
+ if (DS->getSingleDecl() == VR->getDecl()) {
+ Last = Node;
+ break;
+ }
+ }
+
+ if (Node->getState()->getSVal(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()) {
+ if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) {
+ if (TR->getValueType(C)->isObjCObjectPointerType()) {
+ 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()) {
+ if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) {
+ if (TR->getValueType(C)->isObjCObjectPointerType()) {
+ 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 if (isa<nonloc::ConcreteInt>(V)) {
+ os << "The value " << cast<nonloc::ConcreteInt>(V).getValue()
+ << " is assigned to ";
+ }
+ else
+ return NULL;
+
+ if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
+ os << '\'' << VR->getDecl()->getNameAsString() << '\'';
+ }
+ else
+ return NULL;
+ }
+
+ // FIXME: Refactor this into BugReporterContext.
+ const 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 {
+ DefinedSVal Constraint;
+ const bool Assumption;
+ bool isSatisfied;
+public:
+ TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption)
+ : Constraint(constraint), Assumption(assumption), isSatisfied(false) {}
+
+ PathDiagnosticPiece* VisitNode(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext& BRC) {
+ if (isSatisfied)
+ return NULL;
+
+ // Check if in the previous state it was feasible for this constraint
+ // to *not* be true.
+ if (PrevN->getState()->Assume(Constraint, !Assumption)) {
+
+ isSatisfied = true;
+
+ // As a sanity check, make sure that the negation of the constraint
+ // was infeasible in the current state. If it is feasible, we somehow
+ // missed the transition point.
+ if (N->getState()->Assume(Constraint, !Assumption))
+ return NULL;
+
+ // We found the transition point for the constraint. We now need to
+ // pretty-print the constraint. (work-in-progress)
+ std::string sbuf;
+ llvm::raw_string_ostream os(sbuf);
+
+ 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.
+ const 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,
+ DefinedSVal Constraint,
+ bool Assumption) {
+ BRC.addVisitor(new TrackConstraintBRVisitor(Constraint, Assumption));
+}
+
+void clang::bugreporter::registerTrackNullOrUndefValue(BugReporterContext& BRC,
+ const void *data,
+ const ExplodedNode* N) {
+
+ const Stmt *S = static_cast<const Stmt*>(data);
+
+ 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, N->getLocationContext());
+
+ // What did we load?
+ SVal V = state->getSVal(S);
+
+ if (isa<loc::ConcreteInt>(V) || isa<nonloc::ConcreteInt>(V)
+ || V.isUndef()) {
+ registerFindLastStore(BRC, R, V);
+ }
+ }
+ }
+
+ SVal V = state->getSValAsScalarOrLoc(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);
+ }
+ }
+}
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
new file mode 100644
index 0000000..7b1d50c
--- /dev/null
+++ b/lib/Analysis/CFG.cpp
@@ -0,0 +1,2084 @@
+//===--- 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/Analysis/Support/SaveAndRestore.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/PrettyPrinter.h"
+#include "llvm/Support/GraphWriter.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Format.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallPtrSet.h"
+
+using namespace clang;
+
+namespace {
+
+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 {
+ ASTContext *Context;
+ 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(new CFG()), // crew a new CFG
+ Block(NULL), Succ(NULL),
+ ContinueTargetBlock(NULL), BreakTargetBlock(NULL),
+ SwitchTerminatedBlock(NULL), DefaultCaseBlock(NULL) {}
+
+ ~CFGBuilder() { delete cfg; }
+
+ // buildCFG - Used by external clients to construct the CFG.
+ CFG* buildCFG(Stmt *Statement, ASTContext *C);
+
+private:
+ // Visitors to walk an AST and construct the CFG.
+ CFGBlock *VisitAddrLabelExpr(AddrLabelExpr *A, bool alwaysAdd);
+ CFGBlock *VisitBinaryOperator(BinaryOperator *B, bool alwaysAdd);
+ CFGBlock *VisitBlockExpr(BlockExpr* E, bool alwaysAdd);
+ CFGBlock *VisitBlockDeclRefExpr(BlockDeclRefExpr* E, bool alwaysAdd);
+ CFGBlock *VisitBreakStmt(BreakStmt *B);
+ CFGBlock *VisitCallExpr(CallExpr *C, bool alwaysAdd);
+ CFGBlock *VisitCaseStmt(CaseStmt *C);
+ CFGBlock *VisitChooseExpr(ChooseExpr *C);
+ CFGBlock *VisitCompoundStmt(CompoundStmt *C);
+ CFGBlock *VisitConditionalOperator(ConditionalOperator *C);
+ CFGBlock *VisitContinueStmt(ContinueStmt *C);
+ CFGBlock *VisitCXXThrowExpr(CXXThrowExpr *T);
+ CFGBlock *VisitDeclStmt(DeclStmt *DS);
+ CFGBlock *VisitDeclSubExpr(Decl* D);
+ 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 *VisitObjCAtCatchStmt(ObjCAtCatchStmt *S);
+ CFGBlock *VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S);
+ CFGBlock *VisitObjCAtThrowStmt(ObjCAtThrowStmt *S);
+ CFGBlock *VisitObjCAtTryStmt(ObjCAtTryStmt *S);
+ CFGBlock *VisitObjCForCollectionStmt(ObjCForCollectionStmt *S);
+ CFGBlock *VisitReturnStmt(ReturnStmt* R);
+ CFGBlock *VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E, bool alwaysAdd);
+ CFGBlock *VisitStmtExpr(StmtExpr *S, bool alwaysAdd);
+ CFGBlock *VisitSwitchStmt(SwitchStmt *S);
+ CFGBlock *VisitWhileStmt(WhileStmt *W);
+
+ CFGBlock *Visit(Stmt *S, bool alwaysAdd = false);
+ CFGBlock *VisitStmt(Stmt *S, bool alwaysAdd);
+ CFGBlock *VisitChildren(Stmt* S);
+
+ // NYS == Not Yet Supported
+ CFGBlock* NYS() {
+ badCFG = true;
+ return Block;
+ }
+
+ void autoCreateBlock() { if (!Block) Block = createBlock(); }
+ CFGBlock *createBlock(bool add_successor = true);
+ bool FinishBlock(CFGBlock* B);
+ CFGBlock *addStmt(Stmt *S) { return Visit(S, true); }
+
+ void AppendStmt(CFGBlock *B, Stmt *S) {
+ B->appendStmt(S, cfg->getBumpVectorContext());
+ }
+
+ void AddSuccessor(CFGBlock *B, CFGBlock *S) {
+ B->addSuccessor(S, cfg->getBumpVectorContext());
+ }
+
+ /// TryResult - a class representing a variant over the values
+ /// 'true', 'false', or 'unknown'. This is returned by TryEvaluateBool,
+ /// and is used by the CFGBuilder to decide if a branch condition
+ /// can be decided up front during CFG construction.
+ class TryResult {
+ int X;
+ public:
+ TryResult(bool b) : X(b ? 1 : 0) {}
+ TryResult() : X(-1) {}
+
+ bool isTrue() const { return X == 1; }
+ bool isFalse() const { return X == 0; }
+ bool isKnown() const { return X >= 0; }
+ void negate() {
+ assert(isKnown());
+ X ^= 0x1;
+ }
+ };
+
+ /// TryEvaluateBool - Try and evaluate the Stmt and return 0 or 1
+ /// if we can evaluate to a known value, otherwise return -1.
+ TryResult TryEvaluateBool(Expr *S) {
+ Expr::EvalResult Result;
+ if (!S->isTypeDependent() && !S->isValueDependent() &&
+ S->Evaluate(Result, *Context) && Result.Val.isInt())
+ return Result.Val.getInt().getBoolValue();
+
+ return TryResult();
+ }
+
+ 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, ASTContext* C) {
+ Context = C;
+ 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 = addStmt(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;
+
+ AddSuccessor(B, 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;
+
+ AddSuccessor(B, 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)
+ AddSuccessor(B, Succ);
+ return B;
+}
+
+/// FinishBlock - "Finalize" the block by checking if we have a bad CFG.
+bool CFGBuilder::FinishBlock(CFGBlock* B) {
+ if (badCFG)
+ return false;
+
+ assert(B);
+ return true;
+}
+
+/// Visit - Walk the subtree of a statement and add extra
+/// blocks for ternary operators, &&, and ||. We also process "," and
+/// DeclStmts (which may contain nested control-flow).
+CFGBlock* CFGBuilder::Visit(Stmt * S, bool alwaysAdd) {
+tryAgain:
+ switch (S->getStmtClass()) {
+ default:
+ return VisitStmt(S, alwaysAdd);
+
+ case Stmt::AddrLabelExprClass:
+ return VisitAddrLabelExpr(cast<AddrLabelExpr>(S), alwaysAdd);
+
+ case Stmt::BinaryOperatorClass:
+ return VisitBinaryOperator(cast<BinaryOperator>(S), alwaysAdd);
+
+ case Stmt::BlockExprClass:
+ return VisitBlockExpr(cast<BlockExpr>(S), alwaysAdd);
+
+ case Stmt::BlockDeclRefExprClass:
+ return VisitBlockDeclRefExpr(cast<BlockDeclRefExpr>(S), alwaysAdd);
+
+ case Stmt::BreakStmtClass:
+ return VisitBreakStmt(cast<BreakStmt>(S));
+
+ case Stmt::CallExprClass:
+ return VisitCallExpr(cast<CallExpr>(S), alwaysAdd);
+
+ case Stmt::CaseStmtClass:
+ return VisitCaseStmt(cast<CaseStmt>(S));
+
+ case Stmt::ChooseExprClass:
+ return VisitChooseExpr(cast<ChooseExpr>(S));
+
+ case Stmt::CompoundStmtClass:
+ return VisitCompoundStmt(cast<CompoundStmt>(S));
+
+ case Stmt::ConditionalOperatorClass:
+ return VisitConditionalOperator(cast<ConditionalOperator>(S));
+
+ case Stmt::ContinueStmtClass:
+ return VisitContinueStmt(cast<ContinueStmt>(S));
+
+ case Stmt::DeclStmtClass:
+ return VisitDeclStmt(cast<DeclStmt>(S));
+
+ case Stmt::DefaultStmtClass:
+ return VisitDefaultStmt(cast<DefaultStmt>(S));
+
+ case Stmt::DoStmtClass:
+ return VisitDoStmt(cast<DoStmt>(S));
+
+ case Stmt::ForStmtClass:
+ return VisitForStmt(cast<ForStmt>(S));
+
+ case Stmt::GotoStmtClass:
+ return VisitGotoStmt(cast<GotoStmt>(S));
+
+ case Stmt::IfStmtClass:
+ return VisitIfStmt(cast<IfStmt>(S));
+
+ case Stmt::IndirectGotoStmtClass:
+ return VisitIndirectGotoStmt(cast<IndirectGotoStmt>(S));
+
+ case Stmt::LabelStmtClass:
+ return VisitLabelStmt(cast<LabelStmt>(S));
+
+ case Stmt::ObjCAtCatchStmtClass:
+ return VisitObjCAtCatchStmt(cast<ObjCAtCatchStmt>(S));
+
+ case Stmt::CXXThrowExprClass:
+ return VisitCXXThrowExpr(cast<CXXThrowExpr>(S));
+
+ case Stmt::ObjCAtSynchronizedStmtClass:
+ return VisitObjCAtSynchronizedStmt(cast<ObjCAtSynchronizedStmt>(S));
+
+ case Stmt::ObjCAtThrowStmtClass:
+ return VisitObjCAtThrowStmt(cast<ObjCAtThrowStmt>(S));
+
+ case Stmt::ObjCAtTryStmtClass:
+ return VisitObjCAtTryStmt(cast<ObjCAtTryStmt>(S));
+
+ case Stmt::ObjCForCollectionStmtClass:
+ return VisitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(S));
+
+ case Stmt::ParenExprClass:
+ S = cast<ParenExpr>(S)->getSubExpr();
+ goto tryAgain;
+
+ case Stmt::NullStmtClass:
+ return Block;
+
+ case Stmt::ReturnStmtClass:
+ return VisitReturnStmt(cast<ReturnStmt>(S));
+
+ case Stmt::SizeOfAlignOfExprClass:
+ return VisitSizeOfAlignOfExpr(cast<SizeOfAlignOfExpr>(S), alwaysAdd);
+
+ case Stmt::StmtExprClass:
+ return VisitStmtExpr(cast<StmtExpr>(S), alwaysAdd);
+
+ case Stmt::SwitchStmtClass:
+ return VisitSwitchStmt(cast<SwitchStmt>(S));
+
+ case Stmt::WhileStmtClass:
+ return VisitWhileStmt(cast<WhileStmt>(S));
+ }
+}
+
+CFGBlock *CFGBuilder::VisitStmt(Stmt *S, bool alwaysAdd) {
+ if (alwaysAdd) {
+ autoCreateBlock();
+ AppendStmt(Block, S);
+ }
+
+ return VisitChildren(S);
+}
+
+/// VisitChildren - Visit the children of a Stmt.
+CFGBlock *CFGBuilder::VisitChildren(Stmt* Terminator) {
+ CFGBlock *B = Block;
+ for (Stmt::child_iterator I = Terminator->child_begin(),
+ E = Terminator->child_end(); I != E; ++I) {
+ if (*I) B = Visit(*I);
+ }
+ return B;
+}
+
+CFGBlock *CFGBuilder::VisitAddrLabelExpr(AddrLabelExpr *A, bool alwaysAdd) {
+ AddressTakenLabels.insert(A->getLabel());
+
+ if (alwaysAdd) {
+ autoCreateBlock();
+ AppendStmt(Block, A);
+ }
+
+ return Block;
+}
+
+CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B, bool alwaysAdd) {
+ if (B->isLogicalOp()) { // && or ||
+ CFGBlock* ConfluenceBlock = Block ? Block : createBlock();
+ AppendStmt(ConfluenceBlock, 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 = addStmt(B->getRHS());
+ if (!FinishBlock(RHSBlock))
+ return 0;
+
+ // See if this is a known constant.
+ TryResult KnownVal = TryEvaluateBool(B->getLHS());
+ if (KnownVal.isKnown() && (B->getOpcode() == BinaryOperator::LOr))
+ KnownVal.negate();
+
+ // Now link the LHSBlock with RHSBlock.
+ if (B->getOpcode() == BinaryOperator::LOr) {
+ AddSuccessor(LHSBlock, KnownVal.isTrue() ? NULL : ConfluenceBlock);
+ AddSuccessor(LHSBlock, KnownVal.isFalse() ? NULL : RHSBlock);
+ } else {
+ assert (B->getOpcode() == BinaryOperator::LAnd);
+ AddSuccessor(LHSBlock, KnownVal.isFalse() ? NULL : RHSBlock);
+ AddSuccessor(LHSBlock, KnownVal.isTrue() ? NULL : ConfluenceBlock);
+ }
+
+ // Generate the blocks for evaluating the LHS.
+ Block = LHSBlock;
+ return addStmt(B->getLHS());
+ }
+ else if (B->getOpcode() == BinaryOperator::Comma) { // ,
+ autoCreateBlock();
+ AppendStmt(Block, B);
+ addStmt(B->getRHS());
+ return addStmt(B->getLHS());
+ }
+
+ return VisitStmt(B, alwaysAdd);
+}
+
+CFGBlock *CFGBuilder::VisitBlockExpr(BlockExpr* E, bool alwaysAdd) {
+ // FIXME
+ return NYS();
+}
+
+CFGBlock *CFGBuilder::VisitBlockDeclRefExpr(BlockDeclRefExpr* E,
+ bool alwaysAdd) {
+ // FIXME
+ return NYS();
+}
+
+CFGBlock *CFGBuilder::VisitBreakStmt(BreakStmt *B) {
+ // "break" is a control-flow statement. Thus we stop processing the current
+ // block.
+ if (Block && !FinishBlock(Block))
+ return 0;
+
+ // Now create a new block that ends with the break 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)
+ AddSuccessor(Block, BreakTargetBlock);
+ else
+ badCFG = true;
+
+
+ return Block;
+}
+
+CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, bool alwaysAdd) {
+ // If this is a call to a no-return function, this stops the block here.
+ bool NoReturn = false;
+ if (C->getCallee()->getType().getNoReturnAttr()) {
+ NoReturn = true;
+ }
+
+ if (FunctionDecl *FD = C->getDirectCallee())
+ if (FD->hasAttr<NoReturnAttr>())
+ NoReturn = true;
+
+ if (!NoReturn)
+ return VisitStmt(C, alwaysAdd);
+
+ if (Block && !FinishBlock(Block))
+ return 0;
+
+ // Create new block with no successor for the remaining pieces.
+ Block = createBlock(false);
+ AppendStmt(Block, C);
+
+ // Wire this to the exit block directly.
+ AddSuccessor(Block, &cfg->getExit());
+
+ return VisitChildren(C);
+}
+
+CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C) {
+ CFGBlock* ConfluenceBlock = Block ? Block : createBlock();
+ AppendStmt(ConfluenceBlock, C);
+ if (!FinishBlock(ConfluenceBlock))
+ return 0;
+
+ Succ = ConfluenceBlock;
+ Block = NULL;
+ CFGBlock* LHSBlock = addStmt(C->getLHS());
+ if (!FinishBlock(LHSBlock))
+ return 0;
+
+ Succ = ConfluenceBlock;
+ Block = NULL;
+ CFGBlock* RHSBlock = addStmt(C->getRHS());
+ if (!FinishBlock(RHSBlock))
+ return 0;
+
+ Block = createBlock(false);
+ // See if this is a known constant.
+ const TryResult& KnownVal = TryEvaluateBool(C->getCond());
+ AddSuccessor(Block, KnownVal.isFalse() ? NULL : LHSBlock);
+ AddSuccessor(Block, KnownVal.isTrue() ? NULL : RHSBlock);
+ Block->setTerminator(C);
+ return addStmt(C->getCond());
+}
+
+
+CFGBlock* CFGBuilder::VisitCompoundStmt(CompoundStmt* C) {
+ CFGBlock* LastBlock = Block;
+
+ for (CompoundStmt::reverse_body_iterator I=C->body_rbegin(), E=C->body_rend();
+ I != E; ++I ) {
+ LastBlock = addStmt(*I);
+
+ if (badCFG)
+ return NULL;
+ }
+ return LastBlock;
+}
+
+CFGBlock *CFGBuilder::VisitConditionalOperator(ConditionalOperator *C) {
+ // Create the confluence block that will "merge" the results of the ternary
+ // expression.
+ CFGBlock* ConfluenceBlock = Block ? Block : createBlock();
+ AppendStmt(ConfluenceBlock, 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 = addStmt(C->getLHS());
+ if (!FinishBlock(LHSBlock))
+ return 0;
+ Block = NULL;
+ }
+
+ // Create the block for the RHS expression.
+ Succ = ConfluenceBlock;
+ CFGBlock* RHSBlock = addStmt(C->getRHS());
+ if (!FinishBlock(RHSBlock))
+ return 0;
+
+ // Create the block that will contain the condition.
+ Block = createBlock(false);
+
+ // See if this is a known constant.
+ const TryResult& KnownVal = TryEvaluateBool(C->getCond());
+ if (LHSBlock) {
+ AddSuccessor(Block, KnownVal.isFalse() ? NULL : LHSBlock);
+ } else {
+ if (KnownVal.isFalse()) {
+ // If we know the condition is false, add NULL as the successor for
+ // the block containing the condition. In this case, the confluence
+ // block will have just one predecessor.
+ AddSuccessor(Block, 0);
+ assert(ConfluenceBlock->pred_size() == 1);
+ } 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.
+ AddSuccessor(Block, ConfluenceBlock);
+ assert(ConfluenceBlock->pred_size() == 2);
+ std::reverse(ConfluenceBlock->pred_begin(),
+ ConfluenceBlock->pred_end());
+ }
+ }
+
+ AddSuccessor(Block, KnownVal.isTrue() ? NULL : RHSBlock);
+ Block->setTerminator(C);
+ return addStmt(C->getCond());
+}
+
+CFGBlock *CFGBuilder::VisitDeclStmt(DeclStmt *DS) {
+ autoCreateBlock();
+
+ if (DS->isSingleDecl()) {
+ AppendStmt(Block, DS);
+ return 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 *DSNew = new (Mem) DeclStmt(DG, D->getLocation(), GetEndLoc(D));
+
+ // Append the fake DeclStmt to block.
+ AppendStmt(Block, DSNew);
+ B = VisitDeclSubExpr(D);
+ }
+
+ return B;
+}
+
+/// VisitDeclSubExpr - Utility method to add block-level expressions for
+/// initializers in Decls.
+CFGBlock *CFGBuilder::VisitDeclSubExpr(Decl* D) {
+ assert(Block);
+
+ 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;
+}
+
+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. 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.
+ 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 = addStmt(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.
+ CFGBlock* ThenBlock;
+ {
+ Stmt* Then = I->getThen();
+ assert (Then);
+ SaveAndRestore<CFGBlock*> sv(Succ);
+ Block = NULL;
+ ThenBlock = addStmt(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);
+ AddSuccessor(ThenBlock, 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);
+
+ // See if this is a known constant.
+ const TryResult &KnownVal = TryEvaluateBool(I->getCond());
+
+ // Now add the successors.
+ AddSuccessor(Block, KnownVal.isFalse() ? NULL : ThenBlock);
+ AddSuccessor(Block, KnownVal.isTrue()? NULL : 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());
+}
+
+
+CFGBlock* CFGBuilder::VisitReturnStmt(ReturnStmt* R) {
+ // If we were in the middle of a block we stop processing that block.
+ //
+ // NOTE: If a "return" appears in the middle of a block, this means that the
+ // 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.
+ AddSuccessor(Block, &cfg->getExit());
+
+ // Add the return statement to the block. This may create new blocks if R
+ // contains control-flow (short-circuit operations).
+ return VisitStmt(R, true);
+}
+
+CFGBlock* CFGBuilder::VisitLabelStmt(LabelStmt* L) {
+ // Get the block of the labeled statement. Add it to our map.
+ addStmt(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
+ AddSuccessor(Block, I->second);
+
+ return Block;
+}
+
+CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) {
+ CFGBlock* LoopSuccessor = NULL;
+
+ // "for" is a control-flow statement. Thus we stop processing the current
+ // block.
+ 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;
+
+ // See if this is a known constant.
+ TryResult KnownVal(true);
+
+ if (F->getCond())
+ KnownVal = TryEvaluateBool(F->getCond());
+
+ // 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 = addStmt(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 = addStmt(F->getBody());
+
+ if (!BodyBlock)
+ BodyBlock = ContinueTargetBlock; // can happen for "for (...;...;...) ;"
+ else if (Block && !FinishBlock(BodyBlock))
+ return 0;
+
+ // This new body block is a successor to our "exit" condition block.
+ AddSuccessor(ExitConditionBlock, KnownVal.isFalse() ? NULL : BodyBlock);
+ }
+
+ // Link up the condition block with the code that follows the loop. (the
+ // false branch).
+ AddSuccessor(ExitConditionBlock, KnownVal.isTrue() ? NULL : 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.
+ AppendStmt(ExitConditionBlock, 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 = Visit(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 = addStmt(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.
+ AddSuccessor(ExitConditionBlock, BodyBlock);
+ }
+
+ // Link up the condition block with the code that follows the loop.
+ // (the false branch).
+ AddSuccessor(ExitConditionBlock, 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 = addStmt(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 addStmt(S->getSynchExpr());
+}
+
+CFGBlock* CFGBuilder::VisitObjCAtTryStmt(ObjCAtTryStmt* S) {
+ // FIXME
+ return NYS();
+}
+
+CFGBlock* CFGBuilder::VisitWhileStmt(WhileStmt* W) {
+ CFGBlock* LoopSuccessor = NULL;
+
+ // "while" is a control-flow statement. Thus we stop processing the current
+ // block.
+ 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;
+
+ // See if this is a known constant.
+ const TryResult& KnownVal = TryEvaluateBool(W->getCond());
+
+ // 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 = addStmt(W->getBody());
+
+ if (!BodyBlock)
+ BodyBlock = ContinueTargetBlock; // can happen for "while(...) ;"
+ else if (Block) {
+ if (!FinishBlock(BodyBlock))
+ return 0;
+ }
+
+ // Add the loop body entry as a successor to the condition.
+ AddSuccessor(ExitConditionBlock, KnownVal.isFalse() ? NULL : BodyBlock);
+ }
+
+ // Link up the condition block with the code that follows the loop. (the
+ // false branch).
+ AddSuccessor(ExitConditionBlock, KnownVal.isTrue() ? NULL : 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::VisitObjCAtCatchStmt(ObjCAtCatchStmt* S) {
+ // FIXME: For now we pretend that @catch and the code it contains does not
+ // exit.
+ return Block;
+}
+
+CFGBlock* CFGBuilder::VisitObjCAtThrowStmt(ObjCAtThrowStmt* S) {
+ // 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.
+ if (Block && !FinishBlock(Block))
+ return 0;
+
+ // Create the new block.
+ Block = createBlock(false);
+
+ // The Exit block is the only successor.
+ AddSuccessor(Block, &cfg->getExit());
+
+ // Add the statement to the block. This may create new blocks if S contains
+ // control-flow (short-circuit operations).
+ return VisitStmt(S, true);
+}
+
+CFGBlock* CFGBuilder::VisitCXXThrowExpr(CXXThrowExpr* T) {
+ // If we were in the middle of a block we stop processing that block.
+ if (Block && !FinishBlock(Block))
+ return 0;
+
+ // Create the new block.
+ Block = createBlock(false);
+
+ // The Exit block is the only successor.
+ AddSuccessor(Block, &cfg->getExit());
+
+ // Add the statement to the block. This may create new blocks if S contains
+ // control-flow (short-circuit operations).
+ return VisitStmt(T, true);
+}
+
+CFGBlock *CFGBuilder::VisitDoStmt(DoStmt* D) {
+ CFGBlock* LoopSuccessor = NULL;
+
+ // "do...while" is a control-flow statement. Thus we stop processing the
+ // current block.
+ 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;
+
+ // See if this is a known constant.
+ const TryResult &KnownVal = TryEvaluateBool(D->getCond());
+
+ // 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 = addStmt(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.
+ AddSuccessor(ExitConditionBlock, KnownVal.isFalse() ? NULL : LoopBackBlock);
+ }
+
+ // Link up the condition block with the code that follows the loop.
+ // (the false branch).
+ AddSuccessor(ExitConditionBlock, KnownVal.isTrue() ? NULL : 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 && !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)
+ AddSuccessor(Block, ContinueTargetBlock);
+ else
+ badCFG = true;
+
+ return Block;
+}
+
+CFGBlock *CFGBuilder::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E,
+ bool alwaysAdd) {
+
+ if (alwaysAdd) {
+ autoCreateBlock();
+ AppendStmt(Block, E);
+ }
+
+ // 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());
+ }
+
+ return Block;
+}
+
+/// VisitStmtExpr - Utility method to handle (nested) statement
+/// expressions (a GCC extension).
+CFGBlock* CFGBuilder::VisitStmtExpr(StmtExpr *SE, bool alwaysAdd) {
+ if (alwaysAdd) {
+ autoCreateBlock();
+ AppendStmt(Block, SE);
+ }
+ return VisitCompoundStmt(SE->getSubStmt());
+}
+
+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 = addStmt(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.
+ AddSuccessor(SwitchTerminatedBlock, 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* CS) {
+ // CaseStmts are essentially labels, so they are the first statement in a
+ // block.
+
+ if (CS->getSubStmt())
+ addStmt(CS->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(CS);
+
+ if (!FinishBlock(CaseBlock))
+ return 0;
+
+ // Add this block to the list of successors for the block with the switch
+ // statement.
+ assert(SwitchTerminatedBlock);
+ AddSuccessor(SwitchTerminatedBlock, 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())
+ addStmt(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 && !FinishBlock(Block))
+ return 0;
+
+ Block = createBlock(false);
+ Block->setTerminator(I);
+ AddSuccessor(Block, 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.
+ CFGBlock *Mem = getAllocator().Allocate<CFGBlock>();
+ new (Mem) CFGBlock(NumBlockIDs++, BlkBVC);
+ Blocks.push_back(Mem, BlkBVC);
+
+ // If this is the first block, set it as the Entry and Exit.
+ if (first_block)
+ Entry = Exit = &back();
+
+ // Return the block.
+ return &back();
+}
+
+/// buildCFG - Constructs a CFG from an AST. Ownership of the returned
+/// CFG is returned to the caller.
+CFG* CFG::buildCFG(Stmt* Statement, ASTContext *C) {
+ CFGBuilder Builder;
+ return Builder.buildCFG(Statement, C);
+}
+
+//===----------------------------------------------------------------------===//
+// 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;
+ const LangOptions &LangOpts;
+public:
+
+ StmtPrinterHelper(const CFG* cfg, const LangOptions &LO)
+ : CurrentBlock(0), CurrentStmt(0), LangOpts(LO) {
+ 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() {}
+
+ const LangOptions &getLangOpts() const { return LangOpts; }
+ 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;
+ }
+};
+} // end anonymous namespace
+
+
+namespace {
+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)
+ : 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);
+ }
+};
+} // end anonymous namespace
+
+
+static 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, PrintingPolicy(Helper->getLangOpts()));
+
+ // Expressions need a newline.
+ if (isa<Expr>(Terminator)) OS << '\n';
+}
+
+static 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,
+ PrintingPolicy(Helper->getLangOpts()));
+ if (C->getRHS()) {
+ OS << " ... ";
+ C->getRHS()->printPretty(OS, Helper,
+ PrintingPolicy(Helper->getLangOpts()));
+ }
+ } 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,
+ PrintingPolicy(Helper->getLangOpts()));
+ 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 ";
+
+ if (*I)
+ OS << " B" << (*I)->getBlockID();
+ else
+ OS << " NULL";
+ }
+
+ OS << '\n';
+ }
+}
+
+
+/// dump - A simple pretty printer of a CFG that outputs to stderr.
+void CFG::dump(const LangOptions &LO) const { print(llvm::errs(), LO); }
+
+/// print - A simple pretty printer of a CFG that outputs to an ostream.
+void CFG::print(llvm::raw_ostream &OS, const LangOptions &LO) const {
+ StmtPrinterHelper Helper(this, LO);
+
+ // 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 LangOptions &LO) const {
+ print(llvm::errs(), cfg, LO);
+}
+
+/// 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 LangOptions &LO) const {
+ StmtPrinterHelper Helper(cfg, LO);
+ print_block(OS, cfg, *this, &Helper, true);
+}
+
+/// printTerminator - A simple pretty printer of the terminator of a CFGBlock.
+void CFGBlock::printTerminator(llvm::raw_ostream &OS,
+ const LangOptions &LO) const {
+ CFGBlockTerminatorPrint TPrinter(OS, NULL, PrintingPolicy(LO));
+ 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 LangOptions &LO) const {
+#ifndef NDEBUG
+ StmtPrinterHelper H(this, LO);
+ 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,
+ bool ShortNames) {
+
+#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/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp
index 3cca482..9b61257 100644
--- a/lib/Analysis/CFRefCount.cpp
+++ b/lib/Analysis/CFRefCount.cpp
@@ -22,7 +22,7 @@
#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/Analysis/PathSensitive/SymbolManager.h"
#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
-#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclObjC.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableMap.h"
@@ -44,7 +44,7 @@ using namespace clang;
// 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,
+// 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
@@ -62,8 +62,8 @@ static inline bool isWordEnd(char ch, char prev, char next) {
|| (isupper(prev) && isupper(ch) && islower(next)) // XXCreate
|| !isalpha(ch);
}
-
-static inline const char* parseWord(const char* s) {
+
+static inline const char* parseWord(const char* s) {
char ch = *s, prev = '\0';
assert(ch != '\0');
char next = *(s+1);
@@ -77,18 +77,18 @@ static inline const char* parseWord(const char* 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 == '_') {
@@ -103,24 +103,24 @@ static NamingConvention deriveNamingConvention(Selector S) {
++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;
+ C = CreateRule;
break;
case 4:
// Methods starting with 'alloc' or contain 'copy' follow the
@@ -136,7 +136,7 @@ static NamingConvention deriveNamingConvention(Selector S) {
C = CreateRule;
break;
}
-
+
// If we aren't in the prefix and have a derived convention then just
// return it now.
if (!InPossiblePrefix && C != NoConvention)
@@ -156,10 +156,10 @@ static bool followsFundamentalRule(Selector S) {
}
static const ObjCMethodDecl*
-ResolveToInterfaceMethodDecl(const ObjCMethodDecl *MD) {
+ResolveToInterfaceMethodDecl(const ObjCMethodDecl *MD) {
ObjCInterfaceDecl *ID =
const_cast<ObjCInterfaceDecl*>(MD->getClassInterface());
-
+
return MD->isInstanceMethod()
? ID->lookupInstanceMethod(MD->getSelector())
: ID->lookupClassMethod(MD->getSelector());
@@ -167,22 +167,23 @@ ResolveToInterfaceMethodDecl(const ObjCMethodDecl *MD) {
namespace {
class VISIBILITY_HIDDEN GenericNodeBuilder {
- GRStmtNodeBuilder<GRState> *SNB;
+ GRStmtNodeBuilder *SNB;
Stmt *S;
const void *tag;
- GREndPathNodeBuilder<GRState> *ENB;
+ GREndPathNodeBuilder *ENB;
public:
- GenericNodeBuilder(GRStmtNodeBuilder<GRState> &snb, Stmt *s,
+ GenericNodeBuilder(GRStmtNodeBuilder &snb, Stmt *s,
const void *t)
: SNB(&snb), S(s), tag(t), ENB(0) {}
- GenericNodeBuilder(GREndPathNodeBuilder<GRState> &enb)
+
+ GenericNodeBuilder(GREndPathNodeBuilder &enb)
: SNB(0), S(0), tag(0), ENB(&enb) {}
-
- ExplodedNode<GRState> *MakeNode(const GRState *state,
- ExplodedNode<GRState> *Pred) {
+
+ ExplodedNode *MakeNode(const GRState *state, ExplodedNode *Pred) {
if (SNB)
- return SNB->generateNode(PostStmt(S, tag), state, Pred);
-
+ return SNB->generateNode(PostStmt(S, Pred->getLocationContext(), tag),
+ state, Pred);
+
assert(ENB);
return ENB->generateNode(state, Pred);
}
@@ -210,16 +211,16 @@ static inline Selector GetUnarySelector(const char* name, ASTContext& Ctx) {
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';
}
@@ -230,14 +231,14 @@ static bool hasSuffix(const char* s, const char* suffix) {
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;
}
@@ -248,7 +249,7 @@ static bool isRefType(QualType RetTy, const char* prefix,
return false;
// Is the type void*?
- const PointerType* PT = RetTy->getAsPointerType();
+ const PointerType* PT = RetTy->getAs<PointerType>();
if (!(PT->getPointeeType().getUnqualifiedType() == Ctx->VoidTy))
return false;
@@ -281,14 +282,14 @@ typedef llvm::ImmutableMap<unsigned,ArgEffect> ArgEffects;
namespace {
/// RetEffect is used to summarize a function/method call's behavior with
-/// respect to its return value.
+/// 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 };
+
+ enum ObjKind { CF, ObjC, AnyObj };
private:
Kind K;
@@ -297,124 +298,124 @@ private:
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 {
+
+ 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) {}
-
+ 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) {
@@ -424,7 +425,7 @@ public:
ID.AddInteger((unsigned) ReceiverEff);
ID.AddInteger((unsigned) EndPath);
}
-
+
void Profile(llvm::FoldingSetNodeID& ID) const {
Profile(ID, Args, Ret, DefaultArgEffect, Receiver, EndPath);
}
@@ -439,7 +440,7 @@ namespace {
class VISIBILITY_HIDDEN ObjCSummaryKey {
IdentifierInfo* II;
Selector S;
-public:
+public:
ObjCSummaryKey(IdentifierInfo* ii, Selector s)
: II(ii), S(s) {}
@@ -448,10 +449,10 @@ public:
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; }
};
@@ -463,58 +464,56 @@ template <> struct DenseMapInfo<ObjCSummaryKey> {
return ObjCSummaryKey(DenseMapInfo<IdentifierInfo*>::getEmptyKey(),
DenseMapInfo<Selector>::getEmptyKey());
}
-
+
static inline ObjCSummaryKey getTombstoneKey() {
return ObjCSummaryKey(DenseMapInfo<IdentifierInfo*>::getTombstoneKey(),
- DenseMapInfo<Selector>::getTombstoneKey());
+ DenseMapInfo<Selector>::getTombstoneKey());
}
-
+
static unsigned getHashValue(const ObjCSummaryKey &V) {
return (DenseMapInfo<IdentifierInfo*>::getHashValue(V.getIdentifier())
- & 0x88888888)
+ & 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,
+
+ RetainSummary* find(const ObjCInterfaceDecl* D, IdentifierInfo *ClsName,
Selector S) {
// Lookup the method using the decl for the class @interface. If we
// have no decl, lookup using the class name.
return D ? find(D, S) : find(ClsName, S);
}
-
- iterator find(const ObjCInterfaceDecl* D, Selector S) {
+
+ RetainSummary* find(const ObjCInterfaceDecl* D, Selector S) {
// Do a lookup with the (D,S) pair. If we find a match return
// the iterator.
ObjCSummaryKey K(D, S);
MapTy::iterator I = M.find(K);
-
+
if (I != M.end() || !D)
- return I;
-
+ return I->second;
+
// 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
@@ -524,62 +523,62 @@ public:
for (ObjCInterfaceDecl* C=D->getSuperClass() ;; C=C->getSuperClass()) {
if ((I = M.find(ObjCSummaryKey(C, S))) != M.end())
break;
-
+
if (!C)
- return I;
+ return NULL;
}
-
- // Cache the summary with original key to make the next lookup faster
+
+ // Cache the summary with original key to make the next lookup faster
// and return the iterator.
- M[K] = I->second;
- return I;
+ RetainSummary *Summ = I->second;
+ M[K] = Summ;
+ return Summ;
}
-
- iterator find(Expr* Receiver, Selector S) {
+
+ RetainSummary* find(Expr* Receiver, Selector S) {
return find(getReceiverDecl(Receiver), S);
}
-
- iterator find(IdentifierInfo* II, Selector S) {
+
+ RetainSummary* find(IdentifierInfo* II, Selector S) {
// FIXME: Class method lookup. Right now we dont' have a good way
// of going between IdentifierInfo* and the class hierarchy.
- iterator I = M.find(ObjCSummaryKey(II, S));
- return I == M.end() ? M.find(ObjCSummaryKey(S)) : I;
+ MapTy::iterator I = M.find(ObjCSummaryKey(II, S));
+
+ if (I == M.end())
+ I = M.find(ObjCSummaryKey(S));
+
+ return I == M.end() ? NULL : I->second;
}
-
- 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;
+
+ const ObjCInterfaceDecl* getReceiverDecl(Expr* E) {
+ if (const ObjCObjectPointerType* PT =
+ E->getType()->getAs<ObjCObjectPointerType>())
+ return PT->getInterfaceDecl();
+
+ return NULL;
}
-
- iterator end() { return M.end(); }
-
+
RetainSummary*& operator[](ObjCMessageExpr* ME) {
-
+
Selector S = ME->getSelector();
-
+
if (Expr* Receiver = ME->getReceiver()) {
- ObjCInterfaceDecl* OD = getReceiverDecl(Receiver);
+ const 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
//===----------------------------------------------------------------------===//
@@ -592,29 +591,29 @@ 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;
-
+ FuncSummariesTy FuncSummaries;
+
/// ObjCClassMethodSummaries - A map from selectors (for instance methods)
/// to summaries.
ObjCMethodSummariesTy ObjCClassMethodSummaries;
@@ -625,34 +624,34 @@ class VISIBILITY_HIDDEN RetainSummaryManager {
/// 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;
-
+ ArgEffects::Factory AF;
+
/// ScratchArgs - A holding buffer for construct ArgEffects.
ArgEffects ScratchArgs;
-
+
/// ObjCAllocRetE - Default return effect for methods returning Objective-C
/// objects.
RetEffect ObjCAllocRetE;
- /// ObjCInitRetE - Default return effect for init methods returning Objective-C
- /// objects.
+ /// ObjCInitRetE - Default return effect for init methods returning
+ /// Objective-C objects.
RetEffect ObjCInitRetE;
-
+
RetainSummary DefaultSummary;
RetainSummary* StopSummary;
-
+
//==-----------------------------------------------------------------==//
// Methods.
//==-----------------------------------------------------------------==//
-
+
/// getArgEffects - Returns a persistent ArgEffects object based on the
/// data in ScratchArgs.
ArgEffects getArgEffects();
- enum UnaryFuncKind { cfretain, cfrelease, cfmakecollectable };
-
+ enum UnaryFuncKind { cfretain, cfrelease, cfmakecollectable };
+
public:
RetEffect getObjAllocRetEffect() const { return ObjCAllocRetE; }
@@ -660,13 +659,13 @@ public:
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* getCFSummaryGetRule(FunctionDecl* FD);
RetainSummary* getCFCreateGetRuleSummary(FunctionDecl* FD, const char* FName);
-
+
RetainSummary* getPersistentSummary(ArgEffects AE, RetEffect RetEff,
ArgEffect ReceiverEff = DoNothing,
ArgEffect DefaultEff = MayEscape,
@@ -677,36 +676,36 @@ public:
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;
}
@@ -717,43 +716,43 @@ private:
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]);
+ 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);
+ 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);
@@ -770,9 +769,9 @@ private:
addMethodSummary(&Ctx.Idents.get(Cls), ObjCMethodSummaries, Summ, argp);
va_end(argp);
}
-
+
public:
-
+
RetainSummaryManager(ASTContext& ctx, bool gcenabled)
: Ctx(ctx),
CFDictionaryCreateII(&ctx.Idents.get("CFDictionaryCreate")),
@@ -790,17 +789,17 @@ public:
InitializeClassMethodSummaries();
InitializeMethodSummaries();
}
-
+
~RetainSummaryManager();
-
- RetainSummary* getSummary(FunctionDecl* FD);
-
+
+ RetainSummary* getSummary(FunctionDecl* FD);
+
RetainSummary* getInstanceMethodSummary(ObjCMessageExpr* ME,
const ObjCInterfaceDecl* ID) {
return getInstanceMethodSummary(ME->getSelector(), ME->getClassName(),
- ID, ME->getMethodDecl(), ME->getType());
+ ID, ME->getMethodDecl(), ME->getType());
}
-
+
RetainSummary* getInstanceMethodSummary(Selector S, IdentifierInfo *ClsName,
const ObjCInterfaceDecl* ID,
const ObjCMethodDecl *MD,
@@ -810,7 +809,7 @@ public:
const ObjCInterfaceDecl *ID,
const ObjCMethodDecl *MD,
QualType RetTy);
-
+
RetainSummary *getClassMethodSummary(ObjCMessageExpr *ME) {
return getClassMethodSummary(ME->getSelector(), ME->getClassName(),
ME->getClassInfo().first,
@@ -825,17 +824,17 @@ public:
Selector S = MD->getSelector();
IdentifierInfo *ClsName = ID->getIdentifier();
QualType ResultTy = MD->getResultType();
-
- // Resolve the method decl last.
+
+ // Resolve the method decl last.
if (const ObjCMethodDecl *InterfaceMD = ResolveToInterfaceMethodDecl(MD))
MD = InterfaceMD;
-
+
if (MD->isInstanceMethod())
return getInstanceMethodSummary(S, ClsName, ID, MD, ResultTy);
else
return getClassMethodSummary(S, ClsName, ID, MD, ResultTy);
}
-
+
RetainSummary* getCommonMethodSummary(const ObjCMethodDecl* MD,
Selector S, QualType RetTy);
@@ -846,14 +845,14 @@ public:
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
//===----------------------------------------------------------------------===//
@@ -872,7 +871,7 @@ RetainSummary*
RetainSummaryManager::getPersistentSummary(ArgEffects AE, RetEffect RetEff,
ArgEffect ReceiverEff,
ArgEffect DefaultEff,
- bool isEndPath) {
+ bool isEndPath) {
// Create the summary and return it.
RetainSummary *Summ = (RetainSummary*) BPAlloc.Allocate<RetainSummary>();
new (Summ) RetainSummary(AE, RetEff, DefaultEff, ReceiverEff, isEndPath);
@@ -884,36 +883,35 @@ RetainSummaryManager::getPersistentSummary(ArgEffects AE, RetEffect RetEff,
//===----------------------------------------------------------------------===//
bool RetainSummaryManager::isTrackedObjCObjectType(QualType Ty) {
- if (!Ctx.isObjCObjectPointerType(Ty))
+ if (!Ty->isObjCObjectPointerType())
return false;
- // We assume that id<..>, id, and "Class" all represent tracked objects.
- const PointerType *PT = Ty->getAsPointerType();
- if (PT == 0)
+ const ObjCObjectPointerType *PT = Ty->getAs<ObjCObjectPointerType>();
+
+ // Can be true for objects with the 'NSObject' attribute.
+ if (!PT)
return true;
-
- const ObjCInterfaceType *OT = PT->getPointeeType()->getAsObjCInterfaceType();
// We assume that id<..>, id, and "Class" all represent tracked objects.
- if (!OT)
+ if (PT->isObjCIdType() || PT->isObjCQualifiedIdType() ||
+ PT->isObjCClassType())
return true;
-
- // Does the interface subclass NSObject?
- // FIXME: We can memoize here if this gets too expensive.
- ObjCInterfaceDecl* ID = OT->getDecl();
+
+ // Does the interface subclass NSObject?
+ // FIXME: We can memoize here if this gets too expensive.
+ const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
// Assume that anything declared with a forward declaration and no
// @interface subclasses NSObject.
if (ID->isForwardDecl())
return true;
-
- IdentifierInfo* NSObjectII = &Ctx.Idents.get("NSObject");
+ IdentifierInfo* NSObjectII = &Ctx.Idents.get("NSObject");
for ( ; ID ; ID = ID->getSuperClass())
if (ID->getIdentifier() == NSObjectII)
return true;
-
+
return false;
}
@@ -947,38 +945,44 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) {
// 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
+
+ // [PR 3337] Use 'getAs<FunctionType>' to strip away any typedefs on the
// function's type.
- const FunctionType* FT = FD->getType()->getAsFunctionType();
+ const FunctionType* FT = FD->getType()->getAs<FunctionType>();
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.
- assert (ScratchArgs.isEmpty());
+ assert(ScratchArgs.isEmpty());
switch (strlen(FName)) {
default: break;
-
+ case 14:
+ if (!memcmp(FName, "pthread_create", 14)) {
+ // Part of: <rdar://problem/7299394>. This will be addressed
+ // better with IPA.
+ S = getPersistentStopSummary();
+ }
+ break;
case 17:
// Handle: id NSMakeCollectable(CFTypeRef)
if (!memcmp(FName, "NSMakeCollectable", 17)) {
- S = (RetTy == Ctx.getObjCIdType())
+ S = (RetTy->isObjCIdType())
? getUnarySummary(FT, cfmakecollectable)
: getPersistentStopSummary();
}
@@ -1005,10 +1009,10 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) {
// Part of <rdar://problem/6961230>. (IOKit)
// This should be addressed using a API table.
ScratchArgs = AF.Add(ScratchArgs, 2, DecRef);
- S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
+ S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
}
break;
-
+
case 25:
if (!memcmp(FName, "IORegistryEntryIDMatching", 25)) {
// Part of <rdar://problem/6961230>. (IOKit)
@@ -1017,13 +1021,13 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) {
DoNothing, DoNothing);
}
break;
-
+
case 26:
if (!memcmp(FName, "IOOpenFirmwarePathMatching", 26)) {
// Part of <rdar://problem/6961230>. (IOKit)
// This should be addressed using a API table.
S = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true),
- DoNothing, DoNothing);
+ DoNothing, DoNothing);
}
break;
@@ -1032,7 +1036,7 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) {
// Part of <rdar://problem/6961230>.
// This should be addressed using a API table.
ScratchArgs = AF.Add(ScratchArgs, 1, DecRef);
- S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
+ S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
}
break;
@@ -1042,20 +1046,43 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) {
// This should be addressed using a API table. This strcmp is also
// a little gross, but there is no need to super optimize here.
ScratchArgs = AF.Add(ScratchArgs, 1, DecRef);
- S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
+ S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing,
+ DoNothing);
+ }
+ else if (!memcmp(FName, "CVPixelBufferCreateWithBytes", 28)) {
+ // FIXES: <rdar://problem/7283567>
+ // Eventually this can be improved by recognizing that the pixel
+ // buffer passed to CVPixelBufferCreateWithBytes is released via
+ // a callback and doing full IPA to make sure this is done correctly.
+ ScratchArgs = AF.Add(ScratchArgs, 7, StopTracking);
+ S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing,
+ DoNothing);
}
break;
-
+
case 32:
if (!memcmp(FName, "IOServiceAddMatchingNotification", 32)) {
// Part of <rdar://problem/6961230>.
// This should be addressed using a API table.
ScratchArgs = AF.Add(ScratchArgs, 2, DecRef);
- S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
+ S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
+ }
+ break;
+
+ case 34:
+ if (!memcmp(FName, "CVPixelBufferCreateWithPlanarBytes", 34)) {
+ // FIXES: <rdar://problem/7283567>
+ // Eventually this can be improved by recognizing that the pixel
+ // buffer passed to CVPixelBufferCreateWithPlanarBytes is released
+ // via a callback and doing full IPA to make sure this is done
+ // correctly.
+ ScratchArgs = AF.Add(ScratchArgs, 12, StopTracking);
+ S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing,
+ DoNothing);
}
break;
}
-
+
// Did we get a summary?
if (S)
break;
@@ -1065,7 +1092,7 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) {
#if 0
// Handle: NSDeallocateObject(id anObject);
// This method does allow 'nil' (although we don't check it now).
- if (strcmp(FName, "NSDeallocateObject") == 0) {
+ if (strcmp(FName, "NSDeallocateObject") == 0) {
return RetTy == Ctx.VoidTy
? getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, Dealloc)
: getPersistentStopSummary();
@@ -1079,7 +1106,7 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) {
S = getUnarySummary(FT, cfretain);
else if (strstr(FName, "MakeCollectable"))
S = getUnarySummary(FT, cfmakecollectable);
- else
+ else
S = getCFCreateGetRuleSummary(FD, FName);
break;
@@ -1102,7 +1129,7 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) {
S = getCFCreateGetRuleSummary(FD, FName);
break;
}
-
+
break;
}
@@ -1114,7 +1141,7 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) {
FName += 4;
else
FName += 2;
-
+
if (isRelease(FD, FName))
S = getUnarySummary(FT, cfrelease);
else {
@@ -1124,48 +1151,50 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) {
// and that ownership cannot be transferred. While this is technically
// correct, many methods allow a tracked object to escape. For example:
//
- // CFMutableDictionaryRef x = CFDictionaryCreateMutable(...);
+ // CFMutableDictionaryRef x = CFDictionaryCreateMutable(...);
// CFDictionaryAddValue(y, key, x);
- // CFRelease(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."
- //
+ // function name contains "InsertValue", "SetValue", "AddValue",
+ // "AppendValue", or "SetAttribute", then we assume that arguments may
+ // "escape." This means that something else holds on to the object,
+ // allowing it be used even after its local retain count drops to 0.
ArgEffect E = (CStrInCStrNoCase(FName, "InsertValue") ||
CStrInCStrNoCase(FName, "AddValue") ||
CStrInCStrNoCase(FName, "SetValue") ||
- CStrInCStrNoCase(FName, "AppendValue"))
+ CStrInCStrNoCase(FName, "AppendValue") ||
+ CStrInCStrNoCase(FName, "SetAttribute"))
? 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;
+ 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();
}
@@ -1178,27 +1207,27 @@ RetainSummaryManager::getUnarySummary(const FunctionType* FT,
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);
+ return getPersistentSummary(RetEffect::MakeAlias(0),DoNothing, DoNothing);
}
-
+
default:
assert (false && "Not a supported unary function.");
return getDefaultSummary();
@@ -1207,17 +1236,17 @@ RetainSummaryManager::getUnarySummary(const FunctionType* FT,
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());
+ assert (ScratchArgs.isEmpty());
return getPersistentSummary(RetEffect::MakeNotOwned(RetEffect::CF),
DoNothing, DoNothing);
}
@@ -1228,12 +1257,12 @@ RetainSummary* RetainSummaryManager::getCFSummaryGetRule(FunctionDecl* FD) {
RetainSummary*
RetainSummaryManager::getInitMethodSummary(QualType RetTy) {
- assert(ScratchArgs.isEmpty());
+ assert(ScratchArgs.isEmpty());
// 'init' methods conceptually return a newly allocated object and claim
- // the receiver.
+ // the receiver.
if (isTrackedObjCObjectType(RetTy) || isTrackedCFObjectType(RetTy))
return getPersistentSummary(ObjCInitRetE, DecRefMsg);
-
+
return getDefaultSummary();
}
@@ -1244,7 +1273,7 @@ RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ,
return;
QualType RetTy = FD->getResultType();
-
+
// Determine if there is a special return effect for this method.
if (isTrackedObjCObjectType(RetTy)) {
if (FD->getAttr<NSReturnsRetainedAttr>()) {
@@ -1254,7 +1283,7 @@ RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ,
Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true));
}
}
- else if (RetTy->getAsPointerType()) {
+ else if (RetTy->getAs<PointerType>()) {
if (FD->getAttr<CFReturnsRetainedAttr>()) {
Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true));
}
@@ -1267,15 +1296,23 @@ RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ,
if (!MD)
return;
+ bool isTrackedLoc = false;
+
// Determine if there is a special return effect for this method.
if (isTrackedObjCObjectType(MD->getResultType())) {
if (MD->getAttr<NSReturnsRetainedAttr>()) {
Summ.setRetEffect(ObjCAllocRetE);
+ return;
}
- else if (MD->getAttr<CFReturnsRetainedAttr>()) {
- Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true));
- }
+
+ isTrackedLoc = true;
}
+
+ if (!isTrackedLoc)
+ isTrackedLoc = MD->getResultType()->getAs<PointerType>() != NULL;
+
+ if (isTrackedLoc && MD->getAttr<CFReturnsRetainedAttr>())
+ Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true));
}
RetainSummary*
@@ -1296,10 +1333,10 @@ RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl* MD,
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
@@ -1309,29 +1346,29 @@ RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl* MD,
assert(!str.empty());
if (CStrInCStrNoCase(&str[0], "delegate:")) ReceiverEff = StopTracking;
}
-
+
// Look for methods that return an owned object.
- if (isTrackedObjCObjectType(RetTy)) {
+ 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);
+
+ 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);
}
@@ -1343,25 +1380,24 @@ RetainSummaryManager::getInstanceMethodSummary(Selector S,
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;
+ RetainSummary *Summ = ObjCMethodSummaries.find(ID, ClsName, S);
+
+ if (!Summ) {
+ assert(ScratchArgs.isEmpty());
+
+ // "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;
+ }
- 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;
}
@@ -1372,44 +1408,41 @@ RetainSummaryManager::getClassMethodSummary(Selector S, IdentifierInfo *ClsName,
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);
+ RetainSummary *Summ = ObjCClassMethodSummaries.find(ID, ClsName, S);
+
+ if (!Summ) {
+ Summ = getCommonMethodSummary(MD, S, RetTy);
+ // Annotations override defaults.
+ updateSummaryFromAnnotations(*Summ, MD);
+ // Memoize the summary.
+ ObjCClassMethodSummaries[ObjCSummaryKey(ID, ClsName, S)] = Summ;
+ }
- // Memoize the summary.
- ObjCClassMethodSummaries[ObjCSummaryKey(ID, ClsName, S)] = Summ;
return Summ;
}
-void RetainSummaryManager::InitializeClassMethodSummaries() {
+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.
+
+ // 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
@@ -1431,7 +1464,7 @@ void RetainSummaryManager::InitializeClassMethodSummaries() {
"withObject", "waitUntilDone", "modes", NULL);
addClsMethSummary(NSObjectII, Summ, "performSelectorInBackground",
"withObject", NULL);
-
+
// Specially handle NSData.
RetainSummary *dataWithBytesNoCopySumm =
getPersistentSummary(RetEffect::MakeNotOwned(RetEffect::ObjC), DoNothing,
@@ -1443,36 +1476,43 @@ void RetainSummaryManager::InitializeClassMethodSummaries() {
}
void RetainSummaryManager::InitializeMethodSummaries() {
-
- assert (ScratchArgs.isEmpty());
-
+
+ assert (ScratchArgs.isEmpty());
+
// Create the "init" selector. It just acts as a pass-through for the
// receiver.
- addNSObjectMethSummary(GetNullarySelector("init", Ctx),
- getPersistentSummary(ObjCInitRetE, DecRefMsg));
-
+ RetainSummary *InitSumm = getPersistentSummary(ObjCInitRetE, DecRefMsg);
+ addNSObjectMethSummary(GetNullarySelector("init", Ctx), InitSumm);
+
+ // awakeAfterUsingCoder: behaves basically like an 'init' method. It
+ // claims the receiver and returns a retained object.
+ addNSObjectMethSummary(GetUnarySelector("awakeAfterUsingCoder", Ctx),
+ InitSumm);
+
// The next methods are allocators.
- RetainSummary *AllocSumm = getPersistentSummary(ObjCAllocRetE);
-
- // Create the "copy" selector.
- addNSObjectMethSummary(GetNullarySelector("copy", Ctx), AllocSumm);
+ RetainSummary *AllocSumm = getPersistentSummary(ObjCAllocRetE);
+ RetainSummary *CFAllocSumm =
+ getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true));
+
+ // 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);
@@ -1480,13 +1520,13 @@ void RetainSummaryManager::InitializeMethodSummaries() {
// 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.
+
+ // 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.
@@ -1495,42 +1535,42 @@ void RetainSummaryManager::InitializeMethodSummaries() {
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);
-
+ "lineNumber", "description", NULL);
+
addPanicSummary("NSAssertionHandler", "handleFailureInMethod", "object",
"file", "lineNumber", "description", NULL);
-
+
// Create summaries QCRenderer/QCView -createSnapShotImageOfType:
addInstMethSummary("QCRenderer", AllocSumm,
"createSnapshotImageOfType", NULL);
@@ -1538,12 +1578,13 @@ void RetainSummaryManager::InitializeMethodSummaries() {
"createSnapshotImageOfType", NULL);
// Create summaries for CIContext, 'createCGImage' and
- // 'createCGLayerWithSize'.
- addInstMethSummary("CIContext", AllocSumm,
+ // 'createCGLayerWithSize'. These objects are CF objects, and are not
+ // automatically garbage collected.
+ addInstMethSummary("CIContext", CFAllocSumm,
"createCGImage", "fromRect", NULL);
- addInstMethSummary("CIContext", AllocSumm,
- "createCGImage", "fromRect", "format", "colorSpace", NULL);
- addInstMethSummary("CIContext", AllocSumm, "createCGLayerWithSize",
+ addInstMethSummary("CIContext", CFAllocSumm,
+ "createCGImage", "fromRect", "format", "colorSpace", NULL);
+ addInstMethSummary("CIContext", CFAllocSumm, "createCGLayerWithSize",
"info", NULL);
}
@@ -1552,19 +1593,19 @@ void RetainSummaryManager::InitializeMethodSummaries() {
//===----------------------------------------------------------------------===//
namespace {
-
+
class VISIBILITY_HIDDEN RefVal {
-public:
+public:
enum Kind {
- Owned = 0, // Owning reference.
- NotOwned, // Reference is not owned by still valid (not freed).
+ 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.
+ 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.
@@ -1575,7 +1616,7 @@ public:
ErrorReturnedNotOwned
};
-private:
+private:
Kind kind;
RetEffect::ObjKind okind;
unsigned Cnt;
@@ -1588,9 +1629,9 @@ private:
RefVal(Kind k, unsigned cnt = 0)
: kind(k), okind(RetEffect::AnyObj), Cnt(cnt), ACnt(0) {}
-public:
+public:
Kind getKind() const { return kind; }
-
+
RetEffect::ObjKind getObjKind() const { return okind; }
unsigned getCount() const { return Cnt; }
@@ -1599,72 +1640,72 @@ public:
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);
@@ -1674,41 +1715,41 @@ public:
void print(llvm::raw_ostream& Out) const;
};
-
+
void RefVal::print(llvm::raw_ostream& Out) const {
if (!T.isNull())
Out << "Tracked Type:" << T.getAsString() << '\n';
-
+
switch (getKind()) {
default: assert(false);
- case Owned: {
+ 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: {
+
+ 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;
@@ -1716,19 +1757,19 @@ void RefVal::print(llvm::raw_ostream& Out) const {
case ErrorDeallocGC:
Out << "-dealloc (GC)";
break;
-
+
case ErrorDeallocNotOwned:
Out << "-dealloc (not-owned)";
break;
-
+
case ErrorLeak:
Out << "Leaked";
- break;
-
+ break;
+
case ErrorLeakReturned:
Out << "Leaked (Bad naming)";
break;
-
+
case ErrorGCLeakReturned:
Out << "Leaked (GC-ed at return)";
break;
@@ -1736,38 +1777,38 @@ void RefVal::print(llvm::raw_ostream& Out) const {
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; }
+ static inline void* GDMIndex() { return &RefBIndex; }
};
}
@@ -1788,12 +1829,12 @@ namespace { class VISIBILITY_HIDDEN AutoreleaseStack {}; }
namespace clang {
template<> struct GRStateTrait<AutoreleaseStack>
: public GRStatePartialTrait<ARStack> {
- static inline void* GDMIndex() { return &AutoRBIndex; }
+ static inline void* GDMIndex() { return &AutoRBIndex; }
};
template<> struct GRStateTrait<AutoreleasePoolContents>
: public GRStatePartialTrait<ARPoolContents> {
- static inline void* GDMIndex() { return &AutoRCIndex; }
+ static inline void* GDMIndex() { return &AutoRCIndex; }
};
} // end clang namespace
@@ -1808,14 +1849,14 @@ static const GRState * SendAutorelease(const GRState *state,
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);
}
@@ -1824,7 +1865,7 @@ static const GRState * SendAutorelease(const GRState *state,
//===----------------------------------------------------------------------===//
namespace {
-
+
class VISIBILITY_HIDDEN CFRefCount : public GRTransferFuncs {
public:
class BindingsPrinter : public GRState::Printer {
@@ -1834,10 +1875,10 @@ public:
};
private:
- typedef llvm::DenseMap<const GRExprEngine::NodeTy*, const RetainSummary*>
- SummaryLogTy;
+ typedef llvm::DenseMap<const ExplodedNode*, const RetainSummary*>
+ SummaryLogTy;
- RetainSummaryManager Summaries;
+ RetainSummaryManager Summaries;
SummaryLogTy SummaryLog;
const LangOptions& LOpts;
ARCounts::Factory ARCountFactory;
@@ -1848,106 +1889,106 @@ private:
BugType *overAutorelease;
BugType *returnNotOwnedForOwned;
BugReporter *BR;
-
+
const GRState * Update(const GRState * state, SymbolRef sym, RefVal V, ArgEffect E,
RefVal::Kind& hasErr);
- void ProcessNonLeakError(ExplodedNodeSet<GRState>& Dst,
- GRStmtNodeBuilder<GRState>& Builder,
+ void ProcessNonLeakError(ExplodedNodeSet& Dst,
+ GRStmtNodeBuilder& Builder,
Expr* NodeExpr, Expr* ErrorExpr,
- ExplodedNode<GRState>* Pred,
+ ExplodedNode* Pred,
const GRState* St,
RefVal::Kind hasErr, SymbolRef Sym);
-
+
const GRState * HandleSymbolDeath(const GRState * state, SymbolRef sid, RefVal V,
llvm::SmallVectorImpl<SymbolRef> &Leaked);
-
- ExplodedNode<GRState>* ProcessLeaks(const GRState * state,
+
+ ExplodedNode* ProcessLeaks(const GRState * state,
llvm::SmallVectorImpl<SymbolRef> &Leaked,
GenericNodeBuilder &Builder,
GRExprEngine &Eng,
- ExplodedNode<GRState> *Pred = 0);
-
-public:
+ ExplodedNode *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 {
+
+ const RetainSummary *getSummaryOfNode(const ExplodedNode *N) const {
SummaryLogTy::const_iterator I = SummaryLog.find(N);
return I == SummaryLog.end() ? 0 : I->second;
}
-
+
// Calls.
- void EvalSummary(ExplodedNodeSet<GRState>& Dst,
+ void EvalSummary(ExplodedNodeSet& Dst,
GRExprEngine& Eng,
- GRStmtNodeBuilder<GRState>& Builder,
+ GRStmtNodeBuilder& Builder,
Expr* Ex,
Expr* Receiver,
const RetainSummary& Summ,
ExprIterator arg_beg, ExprIterator arg_end,
- ExplodedNode<GRState>* Pred);
-
- virtual void EvalCall(ExplodedNodeSet<GRState>& Dst,
+ ExplodedNode* Pred);
+
+ virtual void EvalCall(ExplodedNodeSet& Dst,
GRExprEngine& Eng,
- GRStmtNodeBuilder<GRState>& Builder,
+ GRStmtNodeBuilder& Builder,
CallExpr* CE, SVal L,
- ExplodedNode<GRState>* Pred);
-
-
- virtual void EvalObjCMessageExpr(ExplodedNodeSet<GRState>& Dst,
+ ExplodedNode* Pred);
+
+
+ virtual void EvalObjCMessageExpr(ExplodedNodeSet& Dst,
GRExprEngine& Engine,
- GRStmtNodeBuilder<GRState>& Builder,
+ GRStmtNodeBuilder& Builder,
ObjCMessageExpr* ME,
- ExplodedNode<GRState>* Pred);
-
- bool EvalObjCMessageExprAux(ExplodedNodeSet<GRState>& Dst,
+ ExplodedNode* Pred);
+
+ bool EvalObjCMessageExprAux(ExplodedNodeSet& Dst,
GRExprEngine& Engine,
- GRStmtNodeBuilder<GRState>& Builder,
+ GRStmtNodeBuilder& Builder,
ObjCMessageExpr* ME,
- ExplodedNode<GRState>* Pred);
+ ExplodedNode* Pred);
- // Stores.
+ // 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,
+ GREndPathNodeBuilder& Builder);
+
+ virtual void EvalDeadSymbols(ExplodedNodeSet& Dst,
GRExprEngine& Engine,
- GRStmtNodeBuilder<GRState>& Builder,
- ExplodedNode<GRState>* Pred,
+ GRStmtNodeBuilder& Builder,
+ ExplodedNode* Pred,
Stmt* S, const GRState* state,
SymbolReaper& SymReaper);
-
- std::pair<ExplodedNode<GRState>*, const GRState *>
+
+ std::pair<ExplodedNode*, const GRState *>
HandleAutoreleaseCounts(const GRState * state, GenericNodeBuilder Bd,
- ExplodedNode<GRState>* Pred, GRExprEngine &Eng,
+ ExplodedNode* Pred, GRExprEngine &Eng,
SymbolRef Sym, RefVal V, bool &stop);
// Return statements.
-
- virtual void EvalReturn(ExplodedNodeSet<GRState>& Dst,
+
+ virtual void EvalReturn(ExplodedNodeSet& Dst,
GRExprEngine& Engine,
- GRStmtNodeBuilder<GRState>& Builder,
+ GRStmtNodeBuilder& Builder,
ReturnStmt* S,
- ExplodedNode<GRState>* Pred);
+ ExplodedNode* Pred);
// Assumptions.
@@ -1965,34 +2006,34 @@ static void PrintPool(llvm::raw_ostream &Out, SymbolRef Sym,
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 << '}';
+ Out << '}';
}
void CFRefCount::BindingsPrinter::Print(llvm::raw_ostream& Out,
const GRState* state,
const char* nl, const char* sep) {
-
+
RefBindings B = state->get<RefBindings>();
-
+
if (!B.isEmpty())
Out << sep << nl;
-
+
for (RefBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) {
Out << (*I).first << " : ";
(*I).second.print(Out);
Out << nl;
}
-
+
// Print the autorelease stack.
Out << sep << nl << "AR pool stack:";
ARStack stack = state->get<AutoreleaseStack>();
-
+
PrintPool(Out, SymbolRef(), state); // Print the caller's pool.
for (ARStack::iterator I=stack.begin(), E=stack.end(); I!=E; ++I)
PrintPool(Out, *I, state);
@@ -2005,157 +2046,155 @@ void CFRefCount::BindingsPrinter::Print(llvm::raw_ostream& Out,
//===----------------------------------------------------------------------===//
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) {}
+
+ 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";
+ return "Incorrect decrement of the reference count of an object that 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) :
+ 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)
+ ExplodedNode *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)
+ ExplodedNode *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) {
-
+
+ virtual void getRanges(const SourceRange*& beg, const SourceRange*& end) {
if (!getBugType().isLeak())
- RangedBugReport::getRanges(BR, beg, end);
+ RangedBugReport::getRanges(beg, end);
else
beg = end = 0;
}
-
+
SymbolRef getSymbol() const { return Sym; }
-
+
PathDiagnosticPiece* getEndPath(BugReporterContext& BRC,
- const ExplodedNode<GRState>* N);
-
+ const ExplodedNode* N);
+
std::pair<const char**,const char**> getExtraDescriptiveText();
-
- PathDiagnosticPiece* VisitNode(const ExplodedNode<GRState>* N,
- const ExplodedNode<GRState>* PrevN,
+
+ PathDiagnosticPiece* VisitNode(const ExplodedNode* N,
+ const ExplodedNode* PrevN,
BugReporterContext& BRC);
};
@@ -2164,38 +2203,38 @@ namespace {
const MemRegion* AllocBinding;
public:
CFRefLeakReport(CFRefBug& D, const CFRefCount &tf,
- ExplodedNode<GRState> *n, SymbolRef sym,
+ ExplodedNode *n, SymbolRef sym,
GRExprEngine& Eng);
-
+
PathDiagnosticPiece* getEndPath(BugReporterContext& BRC,
- const ExplodedNode<GRState>* N);
-
+ const ExplodedNode* 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)
@@ -2205,13 +2244,15 @@ void CFRefCount::RegisterChecks(BugReporter& BR) {
assert(getLangOptions().getGCMode() == LangOptions::NonGC);
name = "Leak of returned object";
}
-
+
+ // Leaks should not be reported if they are post-dominated by a sink.
leakAtReturn = new LeakAtReturn(this, name);
+ leakAtReturn->setSuppressOnSink(true);
BR.Register(leakAtReturn);
-
+
// Second, register leaks within a function/method.
if (isGCEnabled())
- name = "Leak of object when using garbage collection";
+ 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";
@@ -2219,22 +2260,24 @@ void CFRefCount::RegisterChecks(BugReporter& BR) {
assert(getLangOptions().getGCMode() == LangOptions::NonGC);
name = "Leak";
}
-
+
+ // Leaks should not be reported if they are post-dominated by sinks.
leakWithinFunction = new LeakWithinFunction(this, name);
+ leakWithinFunction->setSuppressOnSink(true);
BR.Register(leakWithinFunction);
-
+
// Save the reference to the BugReporter.
this->BR = &BR;
}
static const char* Msgs[] = {
// GC only
- "Code is compiled to only use garbage collection",
+ "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",
+ " (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"
@@ -2242,19 +2285,19 @@ static const char* Msgs[] = {
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);
-
+ 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);
@@ -2268,50 +2311,50 @@ static inline bool contains(const llvm::SmallVectorImpl<ArgEffect>& V,
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,
+PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N,
+ const ExplodedNode* PrevN,
BugReporterContext& BRC) {
-
+
if (!isa<PostStmt>(N->getLocation()))
return NULL;
-
+
// Check if the type state has changed.
const GRState *PrevSt = PrevN->getState();
const GRState *CurrSt = N->getState();
-
- const RefVal* CurrT = CurrSt->get<RefBindings>(Sym);
+
+ 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)) {
+ const Stmt* S = cast<PostStmt>(N->getLocation()).getStmt();
+
+ if (const CallExpr *CE = dyn_cast<CallExpr>(S)) {
// Get the name of the callee (if it is available).
SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee());
if (const FunctionDecl* FD = X.getAsFunctionDecl())
os << "Call to function '" << FD->getNameAsString() <<'\'';
else
- os << "function call";
- }
+ os << "function call";
+ }
else {
assert (isa<ObjCMessageExpr>(S));
os << "Method";
}
-
+
if (CurrV.getObjKind() == RetEffect::CF) {
os << " returns a Core Foundation object with a ";
}
@@ -2319,10 +2362,10 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode<GRState>* N,
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 << " "
@@ -2333,51 +2376,51 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode<GRState>* N,
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)) {
+ const Stmt* S = cast<PostStmt>(N->getLocation()).getStmt();
+
+ if (const 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();
+
+ for (CallExpr::const_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())
+ else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S)) {
+ if (const 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.
@@ -2390,23 +2433,23 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode<GRState>* N,
break;
}
}
-
+
// Specially handle CFMakeCollectable and friends.
if (contains(AEffects, MakeCollectable)) {
// Get the name of the function.
- Stmt* S = cast<PostStmt>(N->getLocation()).getStmt();
+ const 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 "
@@ -2417,67 +2460,67 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode<GRState>* N,
"After this call its retain count is +" << CurrV.getCount()
<< '.';
}
- else
+ 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.
+
+ // 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) {
@@ -2493,24 +2536,25 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode<GRState>* N,
continue;
}
}
- } while(0);
-
+ } while (0);
+
if (os.str().empty())
return 0; // We have nothing to say!
- Stmt* S = cast<PostStmt>(N->getLocation()).getStmt();
+ const 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))
+ for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end();
+ I!=E; ++I)
+ if (const Expr* Exp = dyn_cast_or_null<Expr>(*I))
if (CurrSt->getSValAsScalarOrLoc(Exp).getAsLocSymbol() == Sym) {
P->addRange(Exp->getSourceRange());
break;
}
-
+
return P;
}
@@ -2520,62 +2564,62 @@ namespace {
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();
+
+ SymbolRef SymV = val.getAsSymbol();
if (!SymV || SymV != Sym)
return true;
-
+
if (Binding) {
First = false;
return false;
}
else
Binding = R;
-
- return true;
+
+ 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,
+static std::pair<const ExplodedNode*,const MemRegion*>
+GetAllocationSite(GRStateManager& StateMgr, const ExplodedNode* N,
SymbolRef Sym) {
-
+
// Find both first node that referred to the tracked symbol and the
// memory location that value was store to.
- const ExplodedNode<GRState>* Last = N;
- const MemRegion* FirstBinding = 0;
-
+ const ExplodedNode* 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();
-
+ StateMgr.iterBindings(St, FB);
+ if (FB) FirstBinding = FB.getRegion();
+
Last = N;
- N = N->pred_empty() ? NULL : *(N->pred_begin());
+ N = N->pred_empty() ? NULL : *(N->pred_begin());
}
-
+
return std::make_pair(Last, FirstBinding);
}
PathDiagnosticPiece*
CFRefReport::getEndPath(BugReporterContext& BRC,
- const ExplodedNode<GRState>* EndN) {
+ const ExplodedNode* EndN) {
// Tell the BugReporterContext to report cases when the tracked symbol is
// assigned to different variables, etc.
BRC.addNotableSymbol(Sym);
@@ -2584,37 +2628,37 @@ CFRefReport::getEndPath(BugReporterContext& BRC,
PathDiagnosticPiece*
CFRefLeakReport::getEndPath(BugReporterContext& BRC,
- const ExplodedNode<GRState>* EndN){
-
+ const ExplodedNode* 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 ExplodedNode* AllocNode = 0;
const MemRegion* FirstBinding = 0;
-
+
llvm::tie(AllocNode, FirstBinding) =
GetAllocationSite(BRC.getStateManager(), EndN, Sym);
-
- // Get the allocate site.
+
+ // Get the allocate site.
assert(AllocNode);
- Stmt* FirstStmt = cast<PostStmt>(AllocNode->getLocation()).getStmt();
-
+ const 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;
+ const ExplodedNode* LeakN = EndN;
PathDiagnosticLocation L;
-
+
while (LeakN) {
ProgramPoint P = LeakN->getLocation();
-
+
if (const PostStmt *PS = dyn_cast<PostStmt>(&P)) {
L = PathDiagnosticLocation(PS->getStmt()->getLocStart(), SMgr);
break;
@@ -2625,31 +2669,31 @@ CFRefLeakReport::getEndPath(BugReporterContext& BRC,
break;
}
}
-
+
LeakN = LeakN->succ_empty() ? 0 : *(LeakN->succ_begin());
}
-
+
if (!L.isValid()) {
- const Decl &D = BRC.getCodeDecl();
+ const Decl &D = EndN->getCodeDecl();
L = PathDiagnosticLocation(D.getBodyRBrace(), SMgr);
}
-
+
std::string sbuf;
llvm::raw_string_ostream os(sbuf);
-
+
os << "Object allocated on line " << AllocLine;
-
+
if (FirstBinding)
- os << " and stored into '" << FirstBinding->getString() << '\'';
-
+ 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());
+ ObjCMethodDecl& MD = cast<ObjCMethodDecl>(EndN->getCodeDecl());
os << " is returned from a method whose name ('"
<< MD.getSelector().getAsString()
<< "') does not contain 'copy' or otherwise starts with"
@@ -2657,7 +2701,7 @@ CFRefLeakReport::getEndPath(BugReporterContext& BRC,
" in the Memory Management Guide for Cocoa (object leaked)";
}
else if (RV->getKind() == RefVal::ErrorGCLeakReturned) {
- ObjCMethodDecl& MD = cast<ObjCMethodDecl>(BRC.getCodeDecl());
+ ObjCMethodDecl& MD = cast<ObjCMethodDecl>(EndN->getCodeDecl());
os << " and returned from method '" << MD.getSelector().getAsString()
<< "' is potentially leaked when using garbage collection. Callers "
"of this method do not expect a returned object with a +1 retain "
@@ -2667,16 +2711,15 @@ CFRefLeakReport::getEndPath(BugReporterContext& BRC,
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,
+ ExplodedNode *n,
SymbolRef sym, GRExprEngine& Eng)
-: CFRefReport(D, tf, n, sym)
-{
-
+: 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
@@ -2685,15 +2728,15 @@ CFRefLeakReport::CFRefLeakReport(CFRefBug& D, const CFRefCount &tf,
// Note that this is *not* the trimmed graph; we are guaranteed, however,
// that all ancestor nodes that represent the allocation site have the
// same SourceLocation.
- const ExplodedNode<GRState>* AllocNode = 0;
-
+ const ExplodedNode* 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);
@@ -2702,9 +2745,9 @@ CFRefLeakReport::CFRefLeakReport(CFRefBug& D, const CFRefCount &tf,
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() << '\'';
@@ -2719,57 +2762,46 @@ CFRefLeakReport::CFRefLeakReport(CFRefBug& D, const CFRefCount &tf,
/// 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) {
-
+static QualType GetReturnType(const 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
+ // If RetE is not a message expression just return its type.
+ // If RetE 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));
-}
+ if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(RetE))
+ if (const ObjCObjectPointerType *PT = RetTy->getAs<ObjCObjectPointerType>())
+ if (PT->isObjCQualifiedIdType() || PT->isObjCIdType() ||
+ PT->isObjCClassType()) {
+ // At this point we know the return type of the message expression is
+ // id, id<...>, or Class. If we have an ObjCInterfaceDecl, we know this
+ // is a call to a class method whose type we can resolve. In such
+ // cases, promote the return type to XXX* (where XXX is the class).
+ const ObjCInterfaceDecl *D = ME->getClassInfo().first;
+ return !D ? RetTy : Ctx.getPointerType(Ctx.getObjCInterfaceType(D));
+ }
+ return RetTy;
+}
-void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst,
+void CFRefCount::EvalSummary(ExplodedNodeSet& Dst,
GRExprEngine& Eng,
- GRStmtNodeBuilder<GRState>& Builder,
+ GRStmtNodeBuilder& Builder,
Expr* Ex,
Expr* Receiver,
const RetainSummary& Summ,
ExprIterator arg_beg, ExprIterator arg_end,
- ExplodedNode<GRState>* Pred) {
-
+ ExplodedNode* Pred) {
+
// Get the state.
- GRStateManager& StateMgr = Eng.getStateManager();
const GRState *state = Builder.GetState(Pred);
- 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 ErrorSym = 0;
+
+ for (ExprIterator I = arg_beg; I != arg_end; ++I, ++idx) {
+ SVal V = state->getSValAsScalarOrLoc(*I);
SymbolRef Sym = V.getAsLocSymbol();
if (Sym)
@@ -2779,143 +2811,76 @@ void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst,
ErrorExpr = *I;
ErrorSym = Sym;
break;
- }
+ }
continue;
}
+ tryAgain:
if (isa<Loc>(V)) {
if (loc::MemRegionVal* MR = dyn_cast<loc::MemRegionVal>(&V)) {
if (Summ.getArg(idx) == DoNothingByRef)
continue;
-
- // Invalidate the value of the variable passed by reference.
-
+
+ // Invalidate the value of the variable passed by reference.
+
// 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.
+ // disambiguate conjured symbols.
unsigned Count = Builder.getCurrentBlockCount();
- 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?
+ StoreManager& StoreMgr = Eng.getStateManager().getStoreManager();
+
+ const MemRegion *R = MR->getRegion();
+ // Are we dealing with an ElementRegion? If the element type is
+ // a basic integer type (e.g., char, int) and the underying region
+ // is a variable region then strip off the ElementRegion.
+ // FIXME: We really need to think about this for the general case
+ // as sometimes we are reasoning about arrays and other times
+ // about (char*), etc., is just a form of passing raw bytes.
+ // e.g., void *p = alloca(); foo((char*)p);
+ if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
+ // Checking for 'integral type' is probably too promiscuous, but
+ // we'll leave it in for now until we have a systematic way of
+ // handling all of these cases. Eventually we need to come up
+ // with an interface to StoreManager so that this logic can be
+ // approriately delegated to the respective StoreManagers while
+ // still allowing us to do checker-specific logic (e.g.,
+ // invalidating reference counts), probably via callbacks.
+ if (ER->getElementType()->isIntegralType()) {
+ const MemRegion *superReg = ER->getSuperRegion();
+ if (isa<VarRegion>(superReg) || isa<FieldRegion>(superReg) ||
+ isa<ObjCIvarRegion>(superReg))
+ R = cast<TypedRegion>(superReg);
}
-
- // 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()) {
- // Set the value of the variable to be a conjured symbol.
-
- 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(ValMgr.makeLoc(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->getStateManager().getRegionManager();
-
- // Iterate through the fields and construct new symbols.
- for (RecordDecl::field_iterator FI=RD->field_begin(),
- FE=RD->field_end(); FI!=FE; ++FI) {
-
- // For now just handle scalar fields.
- FieldDecl *FD = *FI;
- QualType FT = FD->getType();
- const FieldRegion* FR = MRMgr.getFieldRegion(FD, R);
-
- if (Loc::IsLocType(FT) ||
- (FT->isIntegerType() && FT->isScalarType())) {
- SVal V = ValMgr.getConjuredSymbolVal(*I, FT, Count);
- state = state->bindLoc(ValMgr.makeLoc(FR), V);
- }
- else if (FT->isStructureType()) {
- // set the default value of the struct field to conjured
- // symbol. Note that the type of the symbol is irrelavant.
- // We cannot use the type of the struct otherwise ValMgr won't
- // give us the conjured symbol.
- StoreManager& StoreMgr =
- Eng.getStateManager().getStoreManager();
- SVal V = ValMgr.getConjuredSymbolVal(*I,
- Eng.getContext().IntTy,
- Count);
- state = StoreMgr.setDefaultValue(state, 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 = StoreMgr.setDefaultValue(state, R, V);
- } else {
- // Just blast away other values.
- state = state->bindLoc(*MR, UnknownVal());
- }
- }
- }
- else if (isa<AllocaRegion>(MR->getRegion())) {
- // Invalidate the alloca region by setting its default value to
- // conjured symbol. The type of the symbol is irrelavant.
- SVal V = ValMgr.getConjuredSymbolVal(*I, Eng.getContext().IntTy,
- Count);
- StoreManager& StoreMgr =
- Eng.getStateManager().getStoreManager();
- state = StoreMgr.setDefaultValue(state, MR->getRegion(), V);
+ // FIXME: What about layers of ElementRegions?
}
- else
- state = state->bindLoc(*MR, UnknownVal());
+
+ // 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);
+
+ state = StoreMgr.InvalidateRegion(state, R, *I, Count);
}
else {
// Nuke all other arguments passed by reference.
+ // FIXME: is this necessary or correct? This handles the non-Region
+ // cases. Is it ever valid to store to these?
state = state->unbindLoc(cast<Loc>(V));
}
}
- else if (isa<nonloc::LocAsInteger>(V))
- state = state->unbindLoc(cast<nonloc::LocAsInteger>(V).getLoc());
- }
-
- // Evaluate the effect on the message receiver.
+ else if (isa<nonloc::LocAsInteger>(V)) {
+ // If we are passing a location wrapped as an integer, unwrap it and
+ // invalidate the values referred by the location.
+ V = cast<nonloc::LocAsInteger>(V).getLoc();
+ goto tryAgain;
+ }
+ }
+
+ // Evaluate the effect on the message receiver.
if (!ErrorExpr && Receiver) {
SymbolRef Sym = state->getSValAsScalarOrLoc(Receiver).getAsLocSymbol();
if (Sym) {
@@ -2928,17 +2893,17 @@ void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst,
}
}
}
-
- // Process any errors.
+
+ // Process any errors.
if (hasErr) {
ProcessNonLeakError(Dst, Builder, Ex, ErrorExpr, Pred, state,
hasErr, ErrorSym);
return;
}
-
- // Consult the summary for the return value.
+
+ // Consult the summary for the return value.
RetEffect RE = Summ.getRetEffect();
-
+
if (RE.getKind() == RetEffect::OwnedWhenTrackedReceiver) {
assert(Receiver);
SVal V = state->getSValAsScalarOrLoc(Receiver);
@@ -2951,57 +2916,57 @@ void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst,
if (!found)
RE = RetEffect::MakeNoRet();
- }
-
+ }
+
switch (RE.getKind()) {
default:
assert (false && "Unhandled RetEffect."); break;
-
- case RetEffect::NoRet: {
+
+ case RetEffect::NoRet: {
// Make up a symbol for the return value (not reference counted).
// FIXME: Most of this logic is not specific to the retain/release
// checker.
-
+
// FIXME: We eventually should handle structs and other compound types
// that are returned by value.
-
+
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);
- }
-
+ SVal X = ValMgr.getConjuredSymbolVal(NULL, 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);
+ state = state->BindExpr(Ex, V, false);
break;
}
-
+
case RetEffect::ReceiverAlias: {
assert (Receiver);
SVal V = state->getSValAsScalarOrLoc(Receiver);
- state = state->bindExpr(Ex, V, false);
+ state = state->BindExpr(Ex, V, false);
break;
}
-
+
case RetEffect::OwnedAllocatedSymbol:
case RetEffect::OwnedSymbol: {
unsigned Count = Builder.getCurrentBlockCount();
- ValueManager &ValMgr = Eng.getValueManager();
+ ValueManager &ValMgr = Eng.getValueManager();
SymbolRef Sym = ValMgr.getConjuredSymbol(Ex, Count);
- QualType RetT = GetReturnType(Ex, ValMgr.getContext());
+ QualType RetT = GetReturnType(Ex, ValMgr.getContext());
state = state->set<RefBindings>(Sym, RefVal::makeOwned(RE.getObjKind(),
RetT));
- state = state->bindExpr(Ex, ValMgr.makeLoc(Sym), false);
+ state = state->BindExpr(Ex, ValMgr.makeLoc(Sym), false);
// FIXME: Add a flag to the checker where allocations are assumed to
// *not fail.
@@ -3009,57 +2974,57 @@ void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst,
if (RE.getKind() == RetEffect::OwnedAllocatedSymbol) {
bool isFeasible;
state = state.Assume(loc::SymbolVal(Sym), true, isFeasible);
- assert(isFeasible && "Cannot assume fresh symbol is non-null.");
+ 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());
+ QualType RetT = GetReturnType(Ex, ValMgr.getContext());
state = state->set<RefBindings>(Sym, RefVal::makeNotOwned(RE.getObjKind(),
RetT));
- state = state->bindExpr(Ex, ValMgr.makeLoc(Sym), false);
+ state = state->BindExpr(Ex, ValMgr.makeLoc(Sym), false);
break;
}
}
-
+
// Generate a sink node if we are at the end of a path.
- GRExprEngine::NodeTy *NewNode =
+ ExplodedNode *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,
+void CFRefCount::EvalCall(ExplodedNodeSet& Dst,
GRExprEngine& Eng,
- GRStmtNodeBuilder<GRState>& Builder,
+ GRStmtNodeBuilder& Builder,
CallExpr* CE, SVal L,
- ExplodedNode<GRState>* Pred) {
+ ExplodedNode* Pred) {
const FunctionDecl* FD = L.getAsFunctionDecl();
- RetainSummary* Summ = !FD ? Summaries.getDefaultSummary()
+ 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,
+void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst,
GRExprEngine& Eng,
- GRStmtNodeBuilder<GRState>& Builder,
+ GRStmtNodeBuilder& Builder,
ObjCMessageExpr* ME,
- ExplodedNode<GRState>* Pred) {
+ ExplodedNode* Pred) {
RetainSummary* Summ = 0;
-
+
if (Expr* Receiver = ME->getReceiver()) {
// We need the type-information of the tracked receiver object
// Retrieve it from the state.
@@ -3073,26 +3038,21 @@ void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet<GRState>& Dst,
SVal V = St->getSValAsScalarOrLoc(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();
- }
+ if (const ObjCObjectPointerType* PT =
+ T->getType()->getAs<ObjCObjectPointerType>())
+ ID = PT->getInterfaceDecl();
}
}
// 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();
+ if (const ObjCObjectPointerType *PT =
+ Receiver->getType()->getAs<ObjCObjectPointerType>())
+ ID = PT->getInterfaceDecl();
}
// FIXME: The receiver could be a reference to a class, meaning that
@@ -3101,16 +3061,22 @@ void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet<GRState>& Dst,
// 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 (isa<ObjCMethodDecl>(Pred->getLocationContext()->getDecl())) {
if (Expr* Receiver = ME->getReceiver()) {
SVal X = St->getSValAsScalarOrLoc(Receiver);
- if (loc::MemRegionVal* L = dyn_cast<loc::MemRegionVal>(&X))
- if (L->getRegion() == St->getSelfRegion()) {
- // Update the summary to make the default argument effect
- // 'StopTracking'.
- Summ = Summaries.copySummary(Summ);
- Summ->setDefaultArgEffect(StopTracking);
+ if (loc::MemRegionVal* L = dyn_cast<loc::MemRegionVal>(&X)) {
+ // Get the region associated with 'self'.
+ const LocationContext *LC = Pred->getLocationContext();
+ if (const ImplicitParamDecl *SelfDecl = LC->getSelfDecl()) {
+ SVal SelfVal = St->getSVal(St->getRegion(SelfDecl, LC));
+ if (L->getBaseRegion() == SelfVal.getAsRegion()) {
+ // Update the summary to make the default argument effect
+ // 'StopTracking'.
+ Summ = Summaries.copySummary(Summ);
+ Summ->setDefaultArgEffect(StopTracking);
+ }
}
+ }
}
}
}
@@ -3137,18 +3103,18 @@ public:
}
};
} // end anonymous namespace
-
-void CFRefCount::EvalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val) {
- // Are we storing to something that causes the value to "escape"?
+
+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.
+ // does not understand.
const GRState *state = B.getState();
if (!isa<loc::MemRegionVal>(location))
@@ -3156,7 +3122,7 @@ void CFRefCount::EvalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val) {
else {
const MemRegion* R = cast<loc::MemRegionVal>(location).getRegion();
escapes = !R->hasStackStorage();
-
+
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
@@ -3178,40 +3144,40 @@ void CFRefCount::EvalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val) {
// Return statements.
-void CFRefCount::EvalReturn(ExplodedNodeSet<GRState>& Dst,
+void CFRefCount::EvalReturn(ExplodedNodeSet& Dst,
GRExprEngine& Eng,
- GRStmtNodeBuilder<GRState>& Builder,
+ GRStmtNodeBuilder& Builder,
ReturnStmt* S,
- ExplodedNode<GRState>* Pred) {
-
+ ExplodedNode* Pred) {
+
Expr* RetE = S->getRetValue();
if (!RetE)
return;
-
+
const GRState *state = Builder.GetState(Pred);
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: {
+
+ // 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) {
@@ -3223,39 +3189,39 @@ void CFRefCount::EvalReturn(ExplodedNodeSet<GRState>& Dst,
}
break;
}
-
- default:
+
+ 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)) {
+ Decl const *CD = &Pred->getCodeDecl();
+ if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(CD)) {
const RetainSummary &Summ = *Summaries.getMethodSummary(MD);
RetEffect RE = Summ.getRetEffect();
bool hasError = false;
@@ -3267,25 +3233,26 @@ void CFRefCount::EvalReturn(ExplodedNodeSet<GRState>& Dst,
// 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.
+ // enclosing method is expected to return ownership.
hasError = true;
X = X ^ RefVal::ErrorLeakReturned;
}
}
-
- if (hasError) {
+
+ 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);
+ ExplodedNode *N =
+ Builder.generateNode(PostStmt(S, Pred->getLocationContext(),
+ &ReturnOwnLeakTag), state, Pred);
if (N) {
CFRefReport *report =
new CFRefLeakReport(*static_cast<CFRefBug*>(leakAtReturn), *this,
@@ -3293,21 +3260,22 @@ void CFRefCount::EvalReturn(ExplodedNodeSet<GRState>& Dst,
BR->EmitReport(report);
}
}
- }
+ }
}
else if (X.isReturnedNotOwned()) {
- const Decl *CD = &Eng.getStateManager().getCodeDecl();
+ Decl const *CD = &Pred->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)) {
+ if (ExplodedNode *N =
+ Builder.generateNode(PostStmt(S, Pred->getLocationContext(),
+ &ReturnNotOwnedForOwnedTag),
+ state, Pred)) {
CFRefReport *report =
new CFRefReport(*static_cast<CFRefBug*>(returnNotOwnedForOwned),
*this, N, Sym);
@@ -3326,18 +3294,18 @@ const GRState* CFRefCount::EvalAssume(const GRState *state,
// 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
+ // too bad since the number of symbols we will track in practice are
// probably small and EvalAssume is only called at branches and a few
// other places.
RefBindings B = state->get<RefBindings>();
-
+
if (B.isEmpty())
return state;
-
- bool changed = false;
+
+ bool changed = false;
RefBindings::Factory& RefBFactory = state->get_context<RefBindings>();
- for (RefBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) {
+ for (RefBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) {
// Check if the symbol is null (or equal to any constant).
// If this is the case, stop tracking the symbol.
if (state->getSymVal(I.getKey())) {
@@ -3345,10 +3313,10 @@ const GRState* CFRefCount::EvalAssume(const GRState *state,
B = RefBFactory.Remove(B, I.getKey());
}
}
-
+
if (changed)
state = state->set<RefBindings>(B);
-
+
return state;
}
@@ -3362,21 +3330,21 @@ const GRState * CFRefCount::Update(const GRState * state, SymbolRef sym,
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 :
+ 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()) {
@@ -3384,7 +3352,7 @@ const GRState * CFRefCount::Update(const GRState * state, SymbolRef sym,
hasErr = V.getKind();
break;
}
-
+
switch (V.getKind()) {
default:
assert(false && "Invalid case.");
@@ -3397,13 +3365,13 @@ const GRState * CFRefCount::Update(const GRState * state, SymbolRef sym,
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;
@@ -3411,7 +3379,7 @@ const GRState * CFRefCount::Update(const GRState * state, SymbolRef sym,
}
// Fall-through.
-
+
case DoNothingByRef:
case DoNothing:
return state;
@@ -3419,7 +3387,7 @@ const GRState * CFRefCount::Update(const GRState * state, SymbolRef sym,
case Autorelease:
if (isGCEnabled())
return state;
-
+
// Update the autorelease counts.
state = SendAutorelease(state, ARCountFactory, sym);
V = V.autorelease();
@@ -3428,7 +3396,7 @@ const GRState * CFRefCount::Update(const GRState * state, SymbolRef sym,
case StopTracking:
return state->remove<RefBindings>(sym);
- case IncRef:
+ case IncRef:
switch (V.getKind()) {
default:
assert(false);
@@ -3436,15 +3404,15 @@ const GRState * CFRefCount::Update(const GRState * state, SymbolRef sym,
case RefVal::Owned:
case RefVal::NotOwned:
V = V + 1;
- break;
+ 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.
@@ -3459,23 +3427,23 @@ const GRState * CFRefCount::Update(const GRState * state, SymbolRef sym,
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;
+ }
break;
}
return state->set<RefBindings>(sym, V);
@@ -3485,27 +3453,27 @@ const GRState * CFRefCount::Update(const GRState * state, SymbolRef sym,
// Handle dead symbols and end-of-path.
//===----------------------------------------------------------------------===//
-std::pair<ExplodedNode<GRState>*, const GRState *>
+std::pair<ExplodedNode*, const GRState *>
CFRefCount::HandleAutoreleaseCounts(const GRState * state, GenericNodeBuilder Bd,
- ExplodedNode<GRState>* Pred,
+ ExplodedNode* 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?");
+
+ 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();
@@ -3519,10 +3487,10 @@ CFRefCount::HandleAutoreleaseCounts(const GRState * state, GenericNodeBuilder Bd
V.setAutoreleaseCount(0);
}
state = state->set<RefBindings>(Sym, V);
- ExplodedNode<GRState> *N = Bd.MakeNode(state, Pred);
+ ExplodedNode *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.
@@ -3530,9 +3498,9 @@ CFRefCount::HandleAutoreleaseCounts(const GRState * state, GenericNodeBuilder Bd
V = V ^ RefVal::ErrorOverAutorelease;
state = state->set<RefBindings>(Sym, V);
- if (ExplodedNode<GRState> *N = Bd.MakeNode(state, Pred)) {
+ if (ExplodedNode *N = Bd.MakeNode(state, Pred)) {
N->markAsSink();
-
+
std::string sbuf;
llvm::raw_string_ostream os(sbuf);
os << "Object over-autoreleased: object was sent -autorelease";
@@ -3544,95 +3512,95 @@ CFRefCount::HandleAutoreleaseCounts(const GRState * state, GenericNodeBuilder Bd
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);
+
+ return std::make_pair((ExplodedNode*)0, state);
}
const GRState *
CFRefCount::HandleSymbolDeath(const GRState * state, SymbolRef sid, RefVal V,
llvm::SmallVectorImpl<SymbolRef> &Leaked) {
-
- bool hasLeak = V.isOwned() ||
+
+ 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>*
+ExplodedNode*
CFRefCount::ProcessLeaks(const GRState * state,
llvm::SmallVectorImpl<SymbolRef> &Leaked,
GenericNodeBuilder &Builder,
GRExprEngine& Eng,
- ExplodedNode<GRState> *Pred) {
-
+ ExplodedNode *Pred) {
+
if (Leaked.empty())
return Pred;
-
+
// Generate an intermediate node representing the leak point.
- ExplodedNode<GRState> *N = Builder.MakeNode(state, Pred);
-
+ ExplodedNode *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
+
+ 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) {
-
+ GREndPathNodeBuilder& Builder) {
+
const GRState *state = Builder.getState();
GenericNodeBuilder Bd(Builder);
- RefBindings B = state->get<RefBindings>();
- ExplodedNode<GRState> *Pred = 0;
+ RefBindings B = state->get<RefBindings>();
+ ExplodedNode *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);
+ (*I).second, stop);
if (stop)
return;
}
-
- B = state->get<RefBindings>();
- llvm::SmallVector<SymbolRef, 10> Leaked;
-
+
+ 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,
+void CFRefCount::EvalDeadSymbols(ExplodedNodeSet& Dst,
GRExprEngine& Eng,
- GRStmtNodeBuilder<GRState>& Builder,
- ExplodedNode<GRState>* Pred,
+ GRStmtNodeBuilder& Builder,
+ ExplodedNode* Pred,
Stmt* S,
const GRState* state,
SymbolReaper& SymReaper) {
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) {
@@ -3648,57 +3616,57 @@ void CFRefCount::EvalDeadSymbols(ExplodedNodeSet<GRState>& Dst,
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) {
+ 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,
+void CFRefCount::ProcessNonLeakError(ExplodedNodeSet& Dst,
+ GRStmtNodeBuilder& Builder,
+ Expr* NodeExpr, Expr* ErrorExpr,
+ ExplodedNode* Pred,
const GRState* St,
RefVal::Kind hasErr, SymbolRef Sym) {
Builder.BuildSinks = true;
- GRExprEngine::NodeTy* N = Builder.MakeNode(Dst, NodeExpr, Pred, St);
-
+ ExplodedNode *N = Builder.MakeNode(Dst, NodeExpr, Pred, St);
+
if (!N)
return;
-
+
CFRefBug *BT = 0;
-
+
switch (hasErr) {
default:
assert(false && "Unhandled error.");
return;
case RefVal::ErrorUseAfterRelease:
BT = static_cast<CFRefBug*>(useAfterRelease);
- break;
+ break;
case RefVal::ErrorReleaseNotOwned:
BT = static_cast<CFRefBug*>(releaseNotOwned);
break;
@@ -3709,7 +3677,7 @@ void CFRefCount::ProcessNonLeakError(ExplodedNodeSet<GRState>& Dst,
BT = static_cast<CFRefBug*>(deallocNotOwned);
break;
}
-
+
CFRefReport *report = new CFRefReport(*BT, *this, N, Sym);
report->addRange(ErrorExpr->getSourceRange());
BR->EmitReport(report);
@@ -3722,4 +3690,4 @@ void CFRefCount::ProcessNonLeakError(ExplodedNodeSet<GRState>& Dst,
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
index 7d6a619..89c1783 100644
--- a/lib/Analysis/CMakeLists.txt
+++ b/lib/Analysis/CMakeLists.txt
@@ -1,17 +1,24 @@
set(LLVM_NO_RTTI 1)
add_clang_library(clangAnalysis
+ AnalysisContext.cpp
+ AnalysisManager.cpp
BasicConstraintManager.cpp
BasicObjCFoundationChecks.cpp
BasicStore.cpp
BasicValueFactory.cpp
BugReporter.cpp
+ BugReporterVisitors.cpp
+ CFG.cpp
CFRefCount.cpp
+ CallGraph.cpp
+ CallInliner.cpp
CheckDeadStores.cpp
CheckNSError.cpp
CheckObjCDealloc.cpp
CheckObjCInstMethSignature.cpp
CheckObjCUnusedIVars.cpp
+ CheckSecuritySyntaxOnly.cpp
Environment.cpp
ExplodedGraph.cpp
GRBlockCounter.cpp
@@ -24,10 +31,11 @@ add_clang_library(clangAnalysis
PathDiagnostic.cpp
RangeConstraintManager.cpp
RegionStore.cpp
+ SVals.cpp
+ SValuator.cpp
SimpleConstraintManager.cpp
SimpleSValuator.cpp
Store.cpp
- SVals.cpp
SymbolManager.cpp
UninitializedValues.cpp
ValueManager.cpp
diff --git a/lib/Analysis/CallGraph.cpp b/lib/Analysis/CallGraph.cpp
new file mode 100644
index 0000000..ae8845d
--- /dev/null
+++ b/lib/Analysis/CallGraph.cpp
@@ -0,0 +1,150 @@
+//== CallGraph.cpp - Call graph 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 defined the CallGraph and CGBuilder classes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/CallGraph.h"
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/StmtVisitor.h"
+
+#include "llvm/Support/GraphWriter.h"
+
+using namespace clang;
+using namespace idx;
+
+namespace {
+class CGBuilder : public StmtVisitor<CGBuilder> {
+
+ CallGraph &G;
+ FunctionDecl *FD;
+
+ Entity CallerEnt;
+
+ CallGraphNode *CallerNode;
+
+public:
+ CGBuilder(CallGraph &g, FunctionDecl *fd, Entity E, CallGraphNode *N)
+ : G(g), FD(fd), CallerEnt(E), CallerNode(N) {}
+
+ void VisitStmt(Stmt *S) { VisitChildren(S); }
+
+ void VisitCallExpr(CallExpr *CE);
+
+ void VisitChildren(Stmt *S) {
+ for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I != E;++I)
+ if (*I)
+ static_cast<CGBuilder*>(this)->Visit(*I);
+ }
+};
+}
+
+void CGBuilder::VisitCallExpr(CallExpr *CE) {
+ if (FunctionDecl *CalleeDecl = CE->getDirectCallee()) {
+ Entity Ent = Entity::get(CalleeDecl, G.getProgram());
+ CallGraphNode *CalleeNode = G.getOrInsertFunction(Ent);
+ CallerNode->addCallee(ASTLocation(FD, CE), CalleeNode);
+ }
+}
+
+CallGraph::CallGraph() : Root(0) {
+ ExternalCallingNode = getOrInsertFunction(Entity());
+}
+
+CallGraph::~CallGraph() {
+ if (!FunctionMap.empty()) {
+ for (FunctionMapTy::iterator I = FunctionMap.begin(), E = FunctionMap.end();
+ I != E; ++I)
+ delete I->second;
+ FunctionMap.clear();
+ }
+}
+
+void CallGraph::addTU(ASTUnit &AST) {
+ ASTContext &Ctx = AST.getASTContext();
+ DeclContext *DC = Ctx.getTranslationUnitDecl();
+
+ for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end();
+ I != E; ++I) {
+
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) {
+ if (FD->isThisDeclarationADefinition()) {
+ // Set caller's ASTContext.
+ Entity Ent = Entity::get(FD, Prog);
+ CallGraphNode *Node = getOrInsertFunction(Ent);
+ CallerCtx[Node] = &Ctx;
+
+ // If this function has external linkage, anything could call it.
+ if (FD->isGlobal())
+ ExternalCallingNode->addCallee(idx::ASTLocation(), Node);
+
+ // Set root node to 'main' function.
+ if (FD->getNameAsString() == "main")
+ Root = Node;
+
+ CGBuilder builder(*this, FD, Ent, Node);
+ builder.Visit(FD->getBody());
+ }
+ }
+ }
+}
+
+CallGraphNode *CallGraph::getOrInsertFunction(Entity F) {
+ CallGraphNode *&Node = FunctionMap[F];
+ if (Node)
+ return Node;
+
+ return Node = new CallGraphNode(F);
+}
+
+Decl *CallGraph::getDecl(CallGraphNode *Node) {
+ // Get the function's context.
+ ASTContext *Ctx = CallerCtx[Node];
+
+ return Node->getDecl(*Ctx);
+}
+
+void CallGraph::print(llvm::raw_ostream &os) {
+ for (iterator I = begin(), E = end(); I != E; ++I) {
+ if (I->second->hasCallee()) {
+ os << "function: " << I->first.getPrintableName()
+ << " calls:\n";
+ for (CallGraphNode::iterator CI = I->second->begin(),
+ CE = I->second->end(); CI != CE; ++CI) {
+ os << " " << CI->second->getName().c_str();
+ }
+ os << '\n';
+ }
+ }
+}
+
+void CallGraph::dump() {
+ print(llvm::errs());
+}
+
+void CallGraph::ViewCallGraph() const {
+ llvm::ViewGraph(*this, "CallGraph");
+}
+
+namespace llvm {
+
+template <>
+struct DOTGraphTraits<CallGraph> : public DefaultDOTGraphTraits {
+
+ static std::string getNodeLabel(const CallGraphNode *Node,
+ const CallGraph &CG, bool ShortNames) {
+ return Node->getName();
+
+ }
+
+};
+
+}
diff --git a/lib/Analysis/CallInliner.cpp b/lib/Analysis/CallInliner.cpp
new file mode 100644
index 0000000..cca8584
--- /dev/null
+++ b/lib/Analysis/CallInliner.cpp
@@ -0,0 +1,75 @@
+//===--- CallInliner.cpp - Transfer function that inlines callee ----------===//
+//
+// 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 callee inlining transfer function.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
+
+using namespace clang;
+
+namespace {
+
+class VISIBILITY_HIDDEN CallInliner : public GRTransferFuncs {
+ ASTContext &Ctx;
+public:
+ CallInliner(ASTContext &ctx) : Ctx(ctx) {}
+
+ void EvalCall(ExplodedNodeSet& Dst, GRExprEngine& Engine,
+ GRStmtNodeBuilder& Builder, CallExpr* CE, SVal L,
+ ExplodedNode* Pred);
+
+};
+
+}
+
+void CallInliner::EvalCall(ExplodedNodeSet& Dst, GRExprEngine& Engine,
+ GRStmtNodeBuilder& Builder, CallExpr* CE, SVal L,
+ ExplodedNode* Pred) {
+ FunctionDecl const *FD = L.getAsFunctionDecl();
+ if (!FD)
+ return; // GRExprEngine is responsible for the autotransition.
+
+ // Make a new LocationContext.
+ StackFrameContext const *LocCtx =
+ Engine.getAnalysisManager().getStackFrame(FD, Pred->getLocationContext(), CE);
+
+ CFGBlock const *Entry = &(LocCtx->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 const *SuccB = *(Entry->succ_begin());
+
+ // Construct an edge representing the starting location in the function.
+ BlockEdge Loc(Entry, SuccB, LocCtx);
+
+ GRState const *state = Builder.GetState(Pred);
+ state = Engine.getStoreManager().EnterStackFrame(state, LocCtx);
+
+ bool isNew;
+ ExplodedNode *SuccN = Engine.getGraph().getNode(Loc, state, &isNew);
+ SuccN->addPredecessor(Pred, Engine.getGraph());
+
+ Builder.Deferred.erase(Pred);
+
+ // This is a hack. We really should not use the GRStmtNodeBuilder.
+ if (isNew)
+ Builder.getWorkList()->Enqueue(SuccN);
+
+ Builder.HasGeneratedNode = true;
+}
+
+GRTransferFuncs *clang::CreateCallInliner(ASTContext &ctx) {
+ return new CallInliner(ctx);
+}
diff --git a/lib/Analysis/CheckDeadStores.cpp b/lib/Analysis/CheckDeadStores.cpp
index 69433d6..d5cb7ca 100644
--- a/lib/Analysis/CheckDeadStores.cpp
+++ b/lib/Analysis/CheckDeadStores.cpp
@@ -33,14 +33,14 @@ class VISIBILITY_HIDDEN DeadStoreObs : public LiveVariables::ObserverTy {
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) {
@@ -48,27 +48,27 @@ public:
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 +
@@ -76,10 +76,10 @@ public:
" read from '" + name + "'";
break;
}
-
- BR.EmitBasicReport(BugType, "Dead store", msg.c_str(), L, R);
+
+ BR.EmitBasicReport(BugType, "Dead store", msg.c_str(), L, R);
}
-
+
void CheckVarDecl(VarDecl* VD, Expr* Ex, Expr* Val,
DeadStoreKind dsk,
const LiveVariables::AnalysisDataTy& AD,
@@ -87,60 +87,60 @@ public:
if (VD->hasLocalStorage() && !Live(VD, AD) && !VD->getAttr<UnusedAttr>())
Report(VD, dsk, Ex->getSourceRange().getBegin(),
- Val->getSourceRange());
+ 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 (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.
+ // 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.
+ // FIXME: Probably should have an Expr::isNullPointerConstant.
if (L->getValue() == 0)
return;
}
@@ -149,19 +149,19 @@ public:
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
+ ? 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);"
@@ -170,21 +170,21 @@ public:
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
@@ -200,7 +200,7 @@ public:
// due to defensive programming.
if (E->isConstantInitializer(Ctx))
return;
-
+
// Special case: check for initializations from constant
// variables.
//
@@ -211,14 +211,14 @@ public:
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
//===----------------------------------------------------------------------===//
@@ -230,9 +230,9 @@ 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) {
@@ -249,11 +249,12 @@ public:
}
};
} // 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);
+
+void clang::CheckDeadStores(CFG &cfg, LiveVariables &L, ParentMap &pmap,
+ BugReporter& BR) {
+ FindEscaped FS(&cfg);
+ FS.getCFG().VisitBlockStmts(FS);
+ DeadStoreObs A(BR.getContext(), BR, pmap, FS.Escaped);
+ L.runOnAllBlocks(cfg, &A);
}
diff --git a/lib/Analysis/CheckNSError.cpp b/lib/Analysis/CheckNSError.cpp
index c91442b..8086da5 100644
--- a/lib/Analysis/CheckNSError.cpp
+++ b/lib/Analysis/CheckNSError.cpp
@@ -28,91 +28,91 @@ using namespace clang;
namespace {
class VISIBILITY_HIDDEN NSErrorCheck : public BugType {
+ const Decl &CodeDecl;
const bool isNSErrorWarning;
IdentifierInfo * const II;
GRExprEngine &Eng;
-
- void CheckSignature(ObjCMethodDecl& MD, QualType& ResultTy,
+
+ void CheckSignature(const ObjCMethodDecl& MD, QualType& ResultTy,
llvm::SmallVectorImpl<VarDecl*>& ErrorParams);
-
- void CheckSignature(FunctionDecl& MD, QualType& ResultTy,
+
+ void CheckSignature(const FunctionDecl& MD, QualType& ResultTy,
llvm::SmallVectorImpl<VarDecl*>& ErrorParams);
bool CheckNSErrorArgument(QualType ArgTy);
bool CheckCFErrorArgument(QualType ArgTy);
-
- void CheckParamDeref(VarDecl* V, const GRState *state, BugReporter& BR);
-
- void EmitRetTyWarning(BugReporter& BR, Decl& CodeDecl);
-
+
+ void CheckParamDeref(const VarDecl *V, const LocationContext *LC,
+ const GRState *state, BugReporter& BR);
+
+ void EmitRetTyWarning(BugReporter& BR, const Decl& CodeDecl);
+
public:
- NSErrorCheck(bool isNSError, GRExprEngine& eng)
- : BugType(isNSError ? "NSError** null dereference"
- : "CFErrorRef* null dereference",
- "Coding Conventions (Apple)"),
- isNSErrorWarning(isNSError),
+ NSErrorCheck(const Decl &D, bool isNSError, GRExprEngine& eng)
+ : BugType(isNSError ? "NSError** null dereference"
+ : "CFErrorRef* null dereference",
+ "Coding conventions (Apple)"),
+ CodeDecl(D),
+ 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 clang::RegisterNSErrorChecks(BugReporter& BR, GRExprEngine &Eng,
+ const Decl &D) {
+ BR.Register(new NSErrorCheck(D, true, Eng));
+ BR.Register(new NSErrorCheck(D, 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();
-
+ ExplodedGraph& G = Eng.getGraph();
+
// 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))
+ if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(&CodeDecl))
CheckSignature(*MD, ResultTy, ErrorParams);
- else if (FunctionDecl* FD = dyn_cast<FunctionDecl>(&CodeDecl))
+ else if (const 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) {
+
+ for (ExplodedGraph::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, (*RI)->getState(), BR);
-
+ E=ErrorParams.end(); I!=E; ++I)
+ CheckParamDeref(*I, (*RI)->getLocationContext(), (*RI)->getState(), BR);
}
}
-void NSErrorCheck::EmitRetTyWarning(BugReporter& BR, Decl& CodeDecl) {
+void NSErrorCheck::EmitRetTyWarning(BugReporter& BR, const Decl& CodeDecl) {
std::string sbuf;
llvm::raw_string_ostream os(sbuf);
-
+
if (isa<ObjCMethodDecl>(CodeDecl))
os << "Method";
else
- os << "Function";
-
+ os << "Function";
+
os << " accepting ";
os << (isNSErrorWarning ? "NSError**" : "CFErrorRef*");
os << " should have a non-void return value to indicate whether or not an "
- "error occured.";
-
+ "error occurred";
+
BR.EmitBasicReport(isNSErrorWarning
? "Bad return type when passing NSError**"
: "Bad return type when passing CFError*",
@@ -121,15 +121,15 @@ void NSErrorCheck::EmitRetTyWarning(BugReporter& BR, Decl& CodeDecl) {
}
void
-NSErrorCheck::CheckSignature(ObjCMethodDecl& M, QualType& ResultTy,
+NSErrorCheck::CheckSignature(const ObjCMethodDecl& M, QualType& ResultTy,
llvm::SmallVectorImpl<VarDecl*>& ErrorParams) {
ResultTy = M.getResultType();
-
- for (ObjCMethodDecl::param_iterator I=M.param_begin(),
+
+ for (ObjCMethodDecl::param_iterator I=M.param_begin(),
E=M.param_end(); I!=E; ++I) {
- QualType T = (*I)->getType();
+ QualType T = (*I)->getType();
if (isNSErrorWarning) {
if (CheckNSErrorArgument(T)) ErrorParams.push_back(*I);
@@ -140,16 +140,16 @@ NSErrorCheck::CheckSignature(ObjCMethodDecl& M, QualType& ResultTy,
}
void
-NSErrorCheck::CheckSignature(FunctionDecl& F, QualType& ResultTy,
+NSErrorCheck::CheckSignature(const 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();
-
+
+ for (FunctionDecl::param_const_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);
}
@@ -160,51 +160,59 @@ NSErrorCheck::CheckSignature(FunctionDecl& F, QualType& ResultTy,
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;
+
+ const PointerType* PPT = ArgTy->getAs<PointerType>();
+ if (!PPT)
+ return false;
+
+ const ObjCObjectPointerType* PT =
+ PPT->getPointeeType()->getAs<ObjCObjectPointerType>();
+
+ if (!PT)
+ return false;
+
+ const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
+
+ // FIXME: Can ID ever be NULL?
+ if (ID)
+ return II == ID->getIdentifier();
+
+ return false;
}
bool NSErrorCheck::CheckCFErrorArgument(QualType ArgTy) {
-
- const PointerType* PPT = ArgTy->getAsPointerType();
+
+ const PointerType* PPT = ArgTy->getAs<PointerType>();
if (!PPT) return false;
-
- const TypedefType* TT = PPT->getPointeeType()->getAsTypedefType();
+
+ const TypedefType* TT = PPT->getPointeeType()->getAs<TypedefType>();
if (!TT) return false;
return TT->getDecl()->getIdentifier() == II;
}
-void NSErrorCheck::CheckParamDeref(VarDecl* Param, const GRState *rootState,
+void NSErrorCheck::CheckParamDeref(const VarDecl *Param,
+ const LocationContext *LC,
+ const GRState *rootState,
BugReporter& BR) {
-
- SVal ParamL = rootState->getLValue(Param);
+
+ SVal ParamL = rootState->getLValue(Param, LC);
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) {
-
+
const GRState *state = (*I)->getState();
- const SVal* X = state->get<GRState::NullDerefTag>();
+ const SVal* X = state->get<GRState::NullDerefTag>();
if (!X || X->getAsSymbol() != ParamSym)
continue;
@@ -213,14 +221,14 @@ void NSErrorCheck::CheckParamDeref(VarDecl* Param, const GRState *rootState,
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.
diff --git a/lib/Analysis/CheckObjCDealloc.cpp b/lib/Analysis/CheckObjCDealloc.cpp
index a14ae26..92e3e11 100644
--- a/lib/Analysis/CheckObjCDealloc.cpp
+++ b/lib/Analysis/CheckObjCDealloc.cpp
@@ -24,11 +24,11 @@
using namespace clang;
-static bool scan_dealloc(Stmt* S, Selector Dealloc) {
-
+static bool scan_dealloc(Stmt* S, Selector Dealloc) {
+
if (ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(S))
if (ME->getSelector() == Dealloc)
- if(ME->getReceiver())
+ if (ME->getReceiver())
if (Expr* Receiver = ME->getReceiver()->IgnoreParenCasts())
return isa<ObjCSuperExpr>(Receiver);
@@ -37,20 +37,20 @@ static bool scan_dealloc(Stmt* S, Selector Dealloc) {
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,
+static bool scan_ivar_release(Stmt* S, ObjCIvarDecl* ID,
+ const ObjCPropertyDecl* PD,
+ Selector Release,
IdentifierInfo* SelfII,
- ASTContext& Ctx) {
-
+ ASTContext& Ctx) {
+
// [mMyIvar release]
if (ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(S))
if (ME->getSelector() == Release)
- if(ME->getReceiver())
+ if (ME->getReceiver())
if (Expr* Receiver = ME->getReceiver()->IgnoreParenCasts())
if (ObjCIvarRefExpr* E = dyn_cast<ObjCIvarRefExpr>(Receiver))
if (E->getDecl() == ID)
@@ -58,27 +58,29 @@ static bool scan_ivar_release(Stmt* S, ObjCIvarDecl* ID,
// [self setMyIvar:nil];
if (ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(S))
- if(ME->getReceiver())
+ 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))
+ ME->getArg(0)->isNullPointerConstant(Ctx,
+ Expr::NPC_ValueDependentIsNull))
return true;
-
+
// self.myIvar = nil;
if (BinaryOperator* BO = dyn_cast<BinaryOperator>(S))
if (BO->isAssignmentOp())
- if(ObjCPropertyRefExpr* PRE =
+ if (ObjCPropertyRefExpr* PRE =
dyn_cast<ObjCPropertyRefExpr>(BO->getLHS()->IgnoreParenCasts()))
- if(PRE->getProperty() == PD)
- if(BO->getRHS()->isNullPointerConstant(Ctx)) {
+ if (PRE->getProperty() == PD)
+ if (BO->getRHS()->isNullPointerConstant(Ctx,
+ Expr::NPC_ValueDependentIsNull)) {
// 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))
@@ -87,43 +89,43 @@ static bool scan_ivar_release(Stmt* S, ObjCIvarDecl* ID,
return false;
}
-void clang::CheckObjCDealloc(ObjCImplementationDecl* D,
+void clang::CheckObjCDealloc(const ObjCImplementationDecl* D,
const LangOptions& LOpts, BugReporter& BR) {
assert (LOpts.getGCMode() != LangOptions::GCOnly);
-
+
ASTContext& Ctx = BR.getContext();
- ObjCInterfaceDecl* ID = D->getClassInterface();
-
+ const 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) ||
+
+ if (!T->isObjCObjectPointerType() ||
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();
@@ -137,118 +139,118 @@ void clang::CheckObjCDealloc(ObjCImplementationDecl* D,
if (II == SenTestCaseII)
return;
}
-
+
if (!ID)
return;
-
+
// Get the "dealloc" selector.
IdentifierInfo* II = &Ctx.Idents.get("dealloc");
- Selector S = Ctx.Selectors.getSelector(0, &II);
+ Selector S = Ctx.Selectors.getSelector(0, &II);
ObjCMethodDecl* MD = 0;
-
+
// Scan the instance methods for "dealloc".
for (ObjCImplementationDecl::instmeth_iterator I = D->instmeth_begin(),
E = D->instmeth_end(); I!=E; ++I) {
-
+
if ((*I)->getSelector() == S) {
MD = *I;
break;
- }
+ }
}
-
+
if (!MD) { // No dealloc found.
-
- const char* name = LOpts.getGCMode() == LangOptions::NonGC
- ? "missing -dealloc"
+
+ 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() && !scan_dealloc(MD->getBody(), 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);
-
+ 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(),
E = D->propimpl_end(); I!=E; ++I) {
// We can only check the synthesized properties
- if((*I)->getPropertyImplementation() != ObjCPropertyImplDecl::Synthesize)
+ 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
+ if (!T->isObjCObjectPointerType()) // Skip non-pointer ivars
continue;
const ObjCPropertyDecl* PD = (*I)->getPropertyDecl();
- if(!PD)
+ if (!PD)
continue;
-
+
// ivars cannot be set via read-only properties, so we'll skip them
- if(PD->isReadOnly())
+ 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(), ID, PD, RS, SelfII, Ctx)
+ if (scan_ivar_release(MD->getBody(), 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) {
+ 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'";
+ "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
index 2881486..8c0d396 100644
--- a/lib/Analysis/CheckObjCInstMethSignature.cpp
+++ b/lib/Analysis/CheckObjCInstMethSignature.cpp
@@ -30,25 +30,24 @@ static bool AreTypesCompatible(QualType Derived, QualType Ancestor,
// 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()))
+ if (Derived->isAnyPointerType() && Ancestor->isAnyPointerType())
return true;
return C.typesAreCompatible(Derived, Ancestor);
}
-static void CompareReturnTypes(ObjCMethodDecl* MethDerived,
- ObjCMethodDecl* MethAncestor,
- BugReporter& BR, ASTContext& Ctx,
- ObjCImplementationDecl* ID) {
-
+static void CompareReturnTypes(const ObjCMethodDecl *MethDerived,
+ const ObjCMethodDecl *MethAncestor,
+ BugReporter &BR, ASTContext &Ctx,
+ const ObjCImplementationDecl *ID) {
+
QualType ResDerived = MethDerived->getResultType();
- QualType ResAncestor = MethAncestor->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 '"
@@ -64,31 +63,31 @@ static void CompareReturnTypes(ObjCMethodDecl* MethDerived,
<< 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,
+void clang::CheckObjCInstMethSignature(const ObjCImplementationDecl* ID,
BugReporter& BR) {
-
- ObjCInterfaceDecl* D = ID->getClassInterface();
- ObjCInterfaceDecl* C = D->getSuperClass();
+
+ const ObjCInterfaceDecl* D = ID->getClassInterface();
+ const 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(),
- E=ID->instmeth_end(); I!=E; ++I) {
-
+ E=ID->instmeth_end(); I!=E; ++I) {
+
ObjCMethodDecl* M = *I;
IMeths[M->getSelector()] = M;
++NumMethods;
@@ -102,19 +101,19 @@ void clang::CheckObjCInstMethSignature(ObjCImplementationDecl* ID,
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
index 0063c40..1a900f8 100644
--- a/lib/Analysis/CheckObjCUnusedIVars.cpp
+++ b/lib/Analysis/CheckObjCUnusedIVars.cpp
@@ -24,47 +24,56 @@
using namespace clang;
enum IVarState { Unused, Used };
-typedef llvm::DenseMap<ObjCIvarDecl*,IVarState> IvarUsageMap;
+typedef llvm::DenseMap<const ObjCIvarDecl*,IVarState> IvarUsageMap;
-static void Scan(IvarUsageMap& M, Stmt* S) {
+static void Scan(IvarUsageMap& M, const Stmt* S) {
if (!S)
return;
-
- if (ObjCIvarRefExpr* Ex = dyn_cast<ObjCIvarRefExpr>(S)) {
- ObjCIvarDecl* D = Ex->getDecl();
+
+ if (const ObjCIvarRefExpr *Ex = dyn_cast<ObjCIvarRefExpr>(S)) {
+ const ObjCIvarDecl *D = Ex->getDecl();
IvarUsageMap::iterator I = M.find(D);
- if (I != M.end()) I->second = Used;
+ if (I != M.end())
+ I->second = Used;
+ return;
+ }
+
+ // Blocks can reference an instance variable of a class.
+ if (const BlockExpr *BE = dyn_cast<BlockExpr>(S)) {
+ Scan(M, BE->getBody());
return;
}
-
- for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I!=E;++I)
+
+ for (Stmt::const_child_iterator I=S->child_begin(),E=S->child_end(); I!=E;++I)
Scan(M, *I);
}
-static void Scan(IvarUsageMap& M, ObjCPropertyImplDecl* D) {
+static void Scan(IvarUsageMap& M, const ObjCPropertyImplDecl* D) {
if (!D)
return;
-
- ObjCIvarDecl* ID = D->getPropertyIvarDecl();
+
+ const ObjCIvarDecl* ID = D->getPropertyIvarDecl();
if (!ID)
return;
-
+
IvarUsageMap::iterator I = M.find(ID);
- if (I != M.end()) I->second = Used;
+ if (I != M.end())
+ I->second = Used;
}
-void clang::CheckObjCUnusedIvar(ObjCImplementationDecl* D, BugReporter& BR) {
+void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D,
+ BugReporter &BR) {
- ObjCInterfaceDecl* ID = D->getClassInterface();
+ const ObjCInterfaceDecl* ID = D->getClassInterface();
IvarUsageMap M;
// Iterate over the ivars.
- for (ObjCInterfaceDecl::ivar_iterator I=ID->ivar_begin(), E=ID->ivar_end();
- I!=E; ++I) {
-
- ObjCIvarDecl* ID = *I;
-
+ for (ObjCInterfaceDecl::ivar_iterator I=ID->ivar_begin(),
+ E=ID->ivar_end(); I!=E; ++I) {
+
+ const ObjCIvarDecl* ID = *I;
+
// Ignore ivars that aren't private.
if (ID->getAccessControl() != ObjCIvarDecl::Private)
continue;
@@ -72,31 +81,31 @@ void clang::CheckObjCUnusedIvar(ObjCImplementationDecl* D, BugReporter& BR) {
// 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(),
- E = D->instmeth_end(); I!=E; ++I)
+ E = D->instmeth_end(); I!=E; ++I)
Scan(M, (*I)->getBody());
-
+
// Scan for @synthesized property methods that act as setters/getters
// to an ivar.
for (ObjCImplementationDecl::propimpl_iterator I = D->propimpl_begin(),
E = D->propimpl_end(); I!=E; ++I)
- Scan(M, *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::string sbuf;
llvm::raw_string_ostream os(sbuf);
os << "Instance variable '" << I->first->getNameAsString()
- << "' in class '" << ID->getNameAsString()
+ << "' in class '" << ID->getNameAsString()
<< "' is never used by the methods in its @implementation "
"(although it may be used by category methods).";
@@ -104,4 +113,3 @@ void clang::CheckObjCUnusedIvar(ObjCImplementationDecl* D, BugReporter& BR) {
os.str().c_str(), I->first->getLocation());
}
}
-
diff --git a/lib/Analysis/CheckSecuritySyntaxOnly.cpp b/lib/Analysis/CheckSecuritySyntaxOnly.cpp
new file mode 100644
index 0000000..9f0d059
--- /dev/null
+++ b/lib/Analysis/CheckSecuritySyntaxOnly.cpp
@@ -0,0 +1,409 @@
+//==- CheckSecuritySyntaxOnly.cpp - Basic security 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 a set of flow-insensitive security checks.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Analysis/LocalCheckers.h"
+#include "clang/AST/StmtVisitor.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+
+namespace {
+class VISIBILITY_HIDDEN WalkAST : public StmtVisitor<WalkAST> {
+ BugReporter &BR;
+ IdentifierInfo *II_gets;
+ enum { num_rands = 9 };
+ IdentifierInfo *II_rand[num_rands];
+ IdentifierInfo *II_random;
+ enum { num_setids = 6 };
+ IdentifierInfo *II_setid[num_setids];
+
+public:
+ WalkAST(BugReporter &br) : BR(br),
+ II_gets(0), II_rand(), II_random(0), II_setid() {}
+
+ // Statement visitor methods.
+ void VisitCallExpr(CallExpr *CE);
+ void VisitForStmt(ForStmt *S);
+ void VisitCompoundStmt (CompoundStmt *S);
+ void VisitStmt(Stmt *S) { VisitChildren(S); }
+
+ void VisitChildren(Stmt *S);
+
+ // Helpers.
+ IdentifierInfo *GetIdentifier(IdentifierInfo *& II, const char *str);
+
+ // Checker-specific methods.
+ void CheckLoopConditionForFloat(const ForStmt *FS);
+ void CheckCall_gets(const CallExpr *CE, const FunctionDecl *FD);
+ void CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD);
+ void CheckCall_random(const CallExpr *CE, const FunctionDecl *FD);
+ void CheckUncheckedReturnValue(CallExpr *CE);
+};
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// Helper methods.
+//===----------------------------------------------------------------------===//
+
+IdentifierInfo *WalkAST::GetIdentifier(IdentifierInfo *& II, const char *str) {
+ if (!II)
+ II = &BR.getContext().Idents.get(str);
+
+ return II;
+}
+
+//===----------------------------------------------------------------------===//
+// AST walking.
+//===----------------------------------------------------------------------===//
+
+void WalkAST::VisitChildren(Stmt *S) {
+ for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I)
+ if (Stmt *child = *I)
+ Visit(child);
+}
+
+void WalkAST::VisitCallExpr(CallExpr *CE) {
+ if (const FunctionDecl *FD = CE->getDirectCallee()) {
+ CheckCall_gets(CE, FD);
+ CheckCall_rand(CE, FD);
+ CheckCall_random(CE, FD);
+ }
+
+ // Recurse and check children.
+ VisitChildren(CE);
+}
+
+void WalkAST::VisitCompoundStmt(CompoundStmt *S) {
+ for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I)
+ if (Stmt *child = *I) {
+ if (CallExpr *CE = dyn_cast<CallExpr>(child))
+ CheckUncheckedReturnValue(CE);
+ Visit(child);
+ }
+}
+
+void WalkAST::VisitForStmt(ForStmt *FS) {
+ CheckLoopConditionForFloat(FS);
+
+ // Recurse and check children.
+ VisitChildren(FS);
+}
+
+//===----------------------------------------------------------------------===//
+// Check: floating poing variable used as loop counter.
+// Originally: <rdar://problem/6336718>
+// Implements: CERT security coding advisory FLP-30.
+//===----------------------------------------------------------------------===//
+
+static const DeclRefExpr*
+GetIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) {
+ expr = expr->IgnoreParenCasts();
+
+ if (const BinaryOperator *B = dyn_cast<BinaryOperator>(expr)) {
+ if (!(B->isAssignmentOp() || B->isCompoundAssignmentOp() ||
+ B->getOpcode() == BinaryOperator::Comma))
+ return NULL;
+
+ if (const DeclRefExpr *lhs = GetIncrementedVar(B->getLHS(), x, y))
+ return lhs;
+
+ if (const DeclRefExpr *rhs = GetIncrementedVar(B->getRHS(), x, y))
+ return rhs;
+
+ return NULL;
+ }
+
+ if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(expr)) {
+ const NamedDecl *ND = DR->getDecl();
+ return ND == x || ND == y ? DR : NULL;
+ }
+
+ if (const UnaryOperator *U = dyn_cast<UnaryOperator>(expr))
+ return U->isIncrementDecrementOp()
+ ? GetIncrementedVar(U->getSubExpr(), x, y) : NULL;
+
+ return NULL;
+}
+
+/// CheckLoopConditionForFloat - This check looks for 'for' statements that
+/// use a floating point variable as a loop counter.
+/// CERT: FLP30-C, FLP30-CPP.
+///
+void WalkAST::CheckLoopConditionForFloat(const ForStmt *FS) {
+ // Does the loop have a condition?
+ const Expr *condition = FS->getCond();
+
+ if (!condition)
+ return;
+
+ // Does the loop have an increment?
+ const Expr *increment = FS->getInc();
+
+ if (!increment)
+ return;
+
+ // Strip away '()' and casts.
+ condition = condition->IgnoreParenCasts();
+ increment = increment->IgnoreParenCasts();
+
+ // Is the loop condition a comparison?
+ const BinaryOperator *B = dyn_cast<BinaryOperator>(condition);
+
+ if (!B)
+ return;
+
+ // Is this a comparison?
+ if (!(B->isRelationalOp() || B->isEqualityOp()))
+ return;
+
+ // Are we comparing variables?
+ const DeclRefExpr *drLHS = dyn_cast<DeclRefExpr>(B->getLHS()->IgnoreParens());
+ const DeclRefExpr *drRHS = dyn_cast<DeclRefExpr>(B->getRHS()->IgnoreParens());
+
+ // Does at least one of the variables have a floating point type?
+ drLHS = drLHS && drLHS->getType()->isFloatingType() ? drLHS : NULL;
+ drRHS = drRHS && drRHS->getType()->isFloatingType() ? drRHS : NULL;
+
+ if (!drLHS && !drRHS)
+ return;
+
+ const VarDecl *vdLHS = drLHS ? dyn_cast<VarDecl>(drLHS->getDecl()) : NULL;
+ const VarDecl *vdRHS = drRHS ? dyn_cast<VarDecl>(drRHS->getDecl()) : NULL;
+
+ if (!vdLHS && !vdRHS)
+ return;
+
+ // Does either variable appear in increment?
+ const DeclRefExpr *drInc = GetIncrementedVar(increment, vdLHS, vdRHS);
+
+ if (!drInc)
+ return;
+
+ // Emit the error. First figure out which DeclRefExpr in the condition
+ // referenced the compared variable.
+ const DeclRefExpr *drCond = vdLHS == drInc->getDecl() ? drLHS : drRHS;
+
+ llvm::SmallVector<SourceRange, 2> ranges;
+ std::string sbuf;
+ llvm::raw_string_ostream os(sbuf);
+
+ os << "Variable '" << drCond->getDecl()->getNameAsCString()
+ << "' with floating point type '" << drCond->getType().getAsString()
+ << "' should not be used as a loop counter";
+
+ ranges.push_back(drCond->getSourceRange());
+ ranges.push_back(drInc->getSourceRange());
+
+ const char *bugType = "Floating point variable used as loop counter";
+ BR.EmitBasicReport(bugType, "Security", os.str().c_str(),
+ FS->getLocStart(), ranges.data(), ranges.size());
+}
+
+//===----------------------------------------------------------------------===//
+// Check: Any use of 'gets' is insecure.
+// Originally: <rdar://problem/6335715>
+// Implements (part of): 300-BSI (buildsecurityin.us-cert.gov)
+//===----------------------------------------------------------------------===//
+
+void WalkAST::CheckCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
+ if (FD->getIdentifier() != GetIdentifier(II_gets, "gets"))
+ return;
+
+ const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FD->getType());
+ if (!FTP)
+ return;
+
+ // Verify that the function takes a single argument.
+ if (FTP->getNumArgs() != 1)
+ return;
+
+ // Is the argument a 'char*'?
+ const PointerType *PT = dyn_cast<PointerType>(FTP->getArgType(0));
+ if (!PT)
+ return;
+
+ if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
+ return;
+
+ // Issue a warning.
+ SourceRange R = CE->getCallee()->getSourceRange();
+ BR.EmitBasicReport("Potential buffer overflow in call to 'gets'",
+ "Security",
+ "Call to function 'gets' is extremely insecure as it can "
+ "always result in a buffer overflow",
+ CE->getLocStart(), &R, 1);
+}
+
+//===----------------------------------------------------------------------===//
+// Check: Linear congruent random number generators should not be used
+// Originally: <rdar://problem/63371000>
+// CWE-338: Use of cryptographically weak prng
+//===----------------------------------------------------------------------===//
+
+void WalkAST::CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
+ if (II_rand[0] == NULL) {
+ // This check applies to these functions
+ static const char * const identifiers[num_rands] = {
+ "drand48", "erand48", "jrand48", "lrand48", "mrand48", "nrand48",
+ "lcong48",
+ "rand", "rand_r"
+ };
+
+ for (size_t i = 0; i < num_rands; i++)
+ II_rand[i] = &BR.getContext().Idents.get(identifiers[i]);
+ }
+
+ const IdentifierInfo *id = FD->getIdentifier();
+ size_t identifierid;
+
+ for (identifierid = 0; identifierid < num_rands; identifierid++)
+ if (id == II_rand[identifierid])
+ break;
+
+ if (identifierid >= num_rands)
+ return;
+
+ const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FD->getType());
+ if (!FTP)
+ return;
+
+ if (FTP->getNumArgs() == 1) {
+ // Is the argument an 'unsigned short *'?
+ // (Actually any integer type is allowed.)
+ const PointerType *PT = dyn_cast<PointerType>(FTP->getArgType(0));
+ if (!PT)
+ return;
+
+ if (! PT->getPointeeType()->isIntegerType())
+ return;
+ }
+ else if (FTP->getNumArgs() != 0)
+ return;
+
+ // Issue a warning.
+ std::string buf1;
+ llvm::raw_string_ostream os1(buf1);
+ os1 << "'" << FD->getNameAsString() << "' is a poor random number generator";
+
+ std::string buf2;
+ llvm::raw_string_ostream os2(buf2);
+ os2 << "Function '" << FD->getNameAsString()
+ << "' is obsolete because it implements a poor random number generator."
+ << " Use 'arc4random' instead";
+
+ SourceRange R = CE->getCallee()->getSourceRange();
+
+ BR.EmitBasicReport(os1.str().c_str(), "Security", os2.str().c_str(),
+ CE->getLocStart(), &R, 1);
+}
+
+//===----------------------------------------------------------------------===//
+// Check: 'random' should not be used
+// Originally: <rdar://problem/63371000>
+//===----------------------------------------------------------------------===//
+
+void WalkAST::CheckCall_random(const CallExpr *CE, const FunctionDecl *FD) {
+ if (FD->getIdentifier() != GetIdentifier(II_random, "random"))
+ return;
+
+ const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FD->getType());
+ if (!FTP)
+ return;
+
+ // Verify that the function takes no argument.
+ if (FTP->getNumArgs() != 0)
+ return;
+
+ // Issue a warning.
+ SourceRange R = CE->getCallee()->getSourceRange();
+ BR.EmitBasicReport("'random' is not a secure random number generator",
+ "Security",
+ "The 'random' function produces a sequence of values that "
+ "an adversary may be able to predict. Use 'arc4random' "
+ "instead",
+ CE->getLocStart(), &R, 1);
+}
+
+//===----------------------------------------------------------------------===//
+// Check: Should check whether privileges are dropped successfully.
+// Originally: <rdar://problem/6337132>
+//===----------------------------------------------------------------------===//
+
+void WalkAST::CheckUncheckedReturnValue(CallExpr *CE) {
+ const FunctionDecl *FD = CE->getDirectCallee();
+ if (!FD)
+ return;
+
+ if (II_setid[0] == NULL) {
+ static const char * const identifiers[num_setids] = {
+ "setuid", "setgid", "seteuid", "setegid",
+ "setreuid", "setregid"
+ };
+
+ for (size_t i = 0; i < num_setids; i++)
+ II_setid[i] = &BR.getContext().Idents.get(identifiers[i]);
+ }
+
+ const IdentifierInfo *id = FD->getIdentifier();
+ size_t identifierid;
+
+ for (identifierid = 0; identifierid < num_setids; identifierid++)
+ if (id == II_setid[identifierid])
+ break;
+
+ if (identifierid >= num_setids)
+ return;
+
+ const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FD->getType());
+ if (!FTP)
+ return;
+
+ // Verify that the function takes one or two arguments (depending on
+ // the function).
+ if (FTP->getNumArgs() != (identifierid < 4 ? 1 : 2))
+ return;
+
+ // The arguments must be integers.
+ for (unsigned i = 0; i < FTP->getNumArgs(); i++)
+ if (! FTP->getArgType(i)->isIntegerType())
+ return;
+
+ // Issue a warning.
+ std::string buf1;
+ llvm::raw_string_ostream os1(buf1);
+ os1 << "Return value is not checked in call to '" << FD->getNameAsString()
+ << "'";
+
+ std::string buf2;
+ llvm::raw_string_ostream os2(buf2);
+ os2 << "The return value from the call to '" << FD->getNameAsString()
+ << "' is not checked. If an error occurs in '"
+ << FD->getNameAsString()
+ << "', the following code may execute with unexpected privileges";
+
+ SourceRange R = CE->getCallee()->getSourceRange();
+
+ BR.EmitBasicReport(os1.str().c_str(), "Security", os2.str().c_str(),
+ CE->getLocStart(), &R, 1);
+}
+
+//===----------------------------------------------------------------------===//
+// Entry point for check.
+//===----------------------------------------------------------------------===//
+
+void clang::CheckSecuritySyntaxOnly(const Decl *D, BugReporter &BR) {
+ WalkAST walker(BR);
+ walker.Visit(D->getBody());
+}
diff --git a/lib/Analysis/Environment.cpp b/lib/Analysis/Environment.cpp
index 3f8f14d..1610ad4 100644
--- a/lib/Analysis/Environment.cpp
+++ b/lib/Analysis/Environment.cpp
@@ -12,106 +12,81 @@
//===----------------------------------------------------------------------===//
#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"
+#include "llvm/ADT/ImmutableMap.h"
using namespace clang;
SVal Environment::GetSVal(const Stmt *E, ValueManager& ValMgr) const {
-
+
for (;;) {
-
+
switch (E->getStmtClass()) {
-
- case Stmt::AddrLabelExprClass:
+
+ case Stmt::AddrLabelExprClass:
return ValMgr.makeLoc(cast<AddrLabelExpr>(E));
-
+
// ParenExprs are no-ops.
-
- case Stmt::ParenExprClass:
+
+ case Stmt::ParenExprClass:
E = cast<ParenExpr>(E)->getSubExpr();
continue;
-
+
case Stmt::CharacterLiteralClass: {
const CharacterLiteral* C = cast<CharacterLiteral>(E);
return ValMgr.makeIntVal(C->getValue(), C->getType());
}
-
+
case Stmt::IntegerLiteralClass: {
return ValMgr.makeIntVal(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: {
const 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(const Stmt *E, ValueManager& ValMgr) const {
-
- while (1) {
- switch (E->getStmtClass()) {
- case Stmt::ParenExprClass:
- E = cast<ParenExpr>(E)->getSubExpr();
- continue;
-
- case Stmt::CharacterLiteralClass: {
- const CharacterLiteral* C = cast<CharacterLiteral>(E);
- return ValMgr.makeIntVal(C->getValue(), C->getType());
- }
-
- case Stmt::IntegerLiteralClass: {
- return ValMgr.makeIntVal(cast<IntegerLiteral>(E));
- }
-
- default:
- return LookupBlkExpr(E);
- }
- }
-}
+Environment EnvironmentManager::BindExpr(Environment Env, const Stmt *S,
+ SVal V, bool Invalidate) {
+ assert(S);
-Environment EnvironmentManager::BindExpr(const Environment& Env, const Stmt* E,
- SVal V, bool isBlkExpr,
- bool Invalidate) {
- assert (E);
-
- if (V.isUnknown()) {
+ if (V.isUnknown()) {
if (Invalidate)
- return isBlkExpr ? RemoveBlkExpr(Env, E) : RemoveSubExpr(Env, E);
+ return Environment(F.Remove(Env.ExprBindings, S), Env.ACtx);
else
return Env;
}
- return isBlkExpr ? AddBlkExpr(Env, E, V) : AddSubExpr(Env, E, V);
+ return Environment(F.Add(Env.ExprBindings, S, V), Env.ACtx);
}
namespace {
class VISIBILITY_HIDDEN MarkLiveCallback : public SymbolVisitor {
SymbolReaper &SymReaper;
public:
- MarkLiveCallback(SymbolReaper &symreaper) : SymReaper(symreaper) {}
+ MarkLiveCallback(SymbolReaper &symreaper) : SymReaper(symreaper) {}
bool VisitSymbol(SymbolRef sym) { SymReaper.markLive(sym); return true; }
};
} // end anonymous namespace
@@ -120,60 +95,66 @@ public:
// - Remove subexpression bindings.
// - Remove dead block expression bindings.
// - Keep live block expression bindings:
-// - Mark their reachable symbols live in SymbolReaper,
+// - 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);
+Environment
+EnvironmentManager::RemoveDeadBindings(Environment Env, const Stmt *S,
+ SymbolReaper &SymReaper,
+ const GRState *ST,
+ llvm::SmallVectorImpl<const MemRegion*> &DRoots) {
+
+ CFG &C = *Env.getAnalysisContext().getCFG();
+
+ // We construct a new Environment object entirely, as this is cheaper than
+ // individually removing all the subexpression bindings (which will greatly
+ // outnumber block-level expression bindings).
+ Environment NewEnv = getInitialEnvironment(&Env.getAnalysisContext());
// Iterate over the block-expr bindings.
- for (Environment::beb_iterator I = Env.beb_begin(), E = Env.beb_end();
+ for (Environment::iterator I = Env.begin(), E = Env.end();
I != E; ++I) {
+
const Stmt *BlkExpr = I.getKey();
- if (SymReaper.isLive(Loc, BlkExpr)) {
- SVal X = I.getData();
+ // Not a block-level expression?
+ if (!C.isBlkExpr(BlkExpr))
+ continue;
+
+ const SVal &X = I.getData();
+
+ if (SymReaper.isLive(S, BlkExpr)) {
+ // Copy the binding to the new map.
+ NewEnv.ExprBindings = F.Add(NewEnv.ExprBindings, BlkExpr, X);
// If the block expr's value is a memory region, then mark that region.
if (isa<loc::MemRegionVal>(X)) {
const MemRegion* R = cast<loc::MemRegionVal>(X).getRegion();
DRoots.push_back(R);
// Mark the super region of the RX as live.
- // e.g.: int x; char *y = (char*) &x; if (*y) ...
+ // e.g.: int x; char *y = (char*) &x; if (*y) ...
// 'y' => element region. 'x' is its super region.
// We only add one level super region for now.
// FIXME: maybe multiple level of super regions should be added.
- if (const SubRegion *SR = dyn_cast<SubRegion>(R)) {
+ if (const SubRegion *SR = dyn_cast<SubRegion>(R))
DRoots.push_back(SR->getSuperRegion());
- }
}
// Mark all symbols in the block expr's value live.
MarkLiveCallback cb(SymReaper);
- state->scanReachableSymbols(X, 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);
+ ST->scanReachableSymbols(X, cb);
+ continue;
}
+
+ // Otherwise the expression is dead with a couple exceptions.
+ // 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())
+ NewEnv.ExprBindings = F.Add(NewEnv.ExprBindings, BlkExpr, X);
}
- return Env;
+ return NewEnv;
}
diff --git a/lib/Analysis/ExplodedGraph.cpp b/lib/Analysis/ExplodedGraph.cpp
index 20de6c4..0dc81a4 100644
--- a/lib/Analysis/ExplodedGraph.cpp
+++ b/lib/Analysis/ExplodedGraph.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
+#include "clang/Analysis/PathSensitive/GRState.h"
#include "clang/AST/Stmt.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/DenseMap.h"
@@ -26,193 +27,234 @@ using namespace clang;
//===----------------------------------------------------------------------===//
// An out of line virtual method to provide a home for the class vtable.
-ExplodedNodeImpl::Auditor::~Auditor() {}
+ExplodedNode::Auditor::~Auditor() {}
#ifndef NDEBUG
-static ExplodedNodeImpl::Auditor* NodeAuditor = 0;
+static ExplodedNode::Auditor* NodeAuditor = 0;
#endif
-void ExplodedNodeImpl::SetAuditor(ExplodedNodeImpl::Auditor* A) {
+void ExplodedNode::SetAuditor(ExplodedNode::Auditor* A) {
#ifndef NDEBUG
NodeAuditor = A;
#endif
}
//===----------------------------------------------------------------------===//
-// ExplodedNodeImpl.
+// ExplodedNode.
//===----------------------------------------------------------------------===//
-static inline std::vector<ExplodedNodeImpl*>& getVector(void* P) {
- return *reinterpret_cast<std::vector<ExplodedNodeImpl*>*>(P);
+static inline BumpVector<ExplodedNode*>& getVector(void* P) {
+ return *reinterpret_cast<BumpVector<ExplodedNode*>*>(P);
}
-void ExplodedNodeImpl::addPredecessor(ExplodedNodeImpl* V) {
+void ExplodedNode::addPredecessor(ExplodedNode* V, ExplodedGraph &G) {
assert (!V->isSink());
- Preds.addNode(V);
- V->Succs.addNode(this);
+ Preds.addNode(V, G);
+ V->Succs.addNode(this, G);
#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());
-
+void ExplodedNode::NodeGroup::addNode(ExplodedNode* N, ExplodedGraph &G) {
+ 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);
+ if (ExplodedNode* NOld = getNode()) {
+ BumpVectorContext &Ctx = G.getNodeAllocator();
+ BumpVector<ExplodedNode*> *V =
+ G.getAllocator().Allocate<BumpVector<ExplodedNode*> >();
+ new (V) BumpVector<ExplodedNode*>(Ctx, 4);
+
+ assert((reinterpret_cast<uintptr_t>(V) & Mask) == 0x0);
+ V->push_back(NOld, Ctx);
+ V->push_back(N, Ctx);
P = reinterpret_cast<uintptr_t>(V) | SizeOther;
- assert (getPtr() == (void*) V);
- assert (getKind() == SizeOther);
+ assert(getPtr() == (void*) V);
+ assert(getKind() == SizeOther);
}
else {
P = reinterpret_cast<uintptr_t>(N);
- assert (getKind() == Size1);
+ assert(getKind() == Size1);
}
}
else {
- assert (getKind() == SizeOther);
- getVector(getPtr()).push_back(N);
+ assert(getKind() == SizeOther);
+ getVector(getPtr()).push_back(N, G.getNodeAllocator());
}
}
-
-unsigned ExplodedNodeImpl::NodeGroup::size() const {
+unsigned ExplodedNode::NodeGroup::size() const {
if (getFlag())
return 0;
-
+
if (getKind() == Size1)
return getNode() ? 1 : 0;
else
return getVector(getPtr()).size();
}
-ExplodedNodeImpl** ExplodedNodeImpl::NodeGroup::begin() const {
+ExplodedNode **ExplodedNode::NodeGroup::begin() const {
if (getFlag())
return NULL;
-
+
if (getKind() == Size1)
- return (ExplodedNodeImpl**) (getPtr() ? &P : NULL);
+ return (ExplodedNode**) (getPtr() ? &P : NULL);
else
- return const_cast<ExplodedNodeImpl**>(&*(getVector(getPtr()).begin()));
+ return const_cast<ExplodedNode**>(&*(getVector(getPtr()).begin()));
}
-ExplodedNodeImpl** ExplodedNodeImpl::NodeGroup::end() const {
+ExplodedNode** ExplodedNode::NodeGroup::end() const {
if (getFlag())
return NULL;
-
+
if (getKind() == Size1)
- return (ExplodedNodeImpl**) (getPtr() ? &P+1 : NULL);
+ return (ExplodedNode**) (getPtr() ? &P+1 : NULL);
else {
// Dereferencing end() is undefined behaviour. The vector is not empty, so
// we can dereference the last elem and then add 1 to the result.
- return const_cast<ExplodedNodeImpl**>(&getVector(getPtr()).back()) + 1;
+ return const_cast<ExplodedNode**>(getVector(getPtr()).end());
}
}
-ExplodedNodeImpl::NodeGroup::~NodeGroup() {
- if (getKind() == SizeOther) delete &getVector(getPtr());
+ExplodedNode *ExplodedGraph::getNode(const ProgramPoint& L,
+ const GRState* State, bool* IsNew) {
+ // 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*) getAllocator().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;
+}
+
+std::pair<ExplodedGraph*, InterExplodedGraphMap*>
+ExplodedGraph::Trim(const NodeTy* const* NBeg, const NodeTy* const* NEnd,
+ llvm::DenseMap<const void*, const void*> *InverseMap) const {
+
+ if (NBeg == NEnd)
+ return std::make_pair((ExplodedGraph*) 0,
+ (InterExplodedGraphMap*) 0);
+
+ assert (NBeg < NEnd);
+
+ llvm::OwningPtr<InterExplodedGraphMap> M(new InterExplodedGraphMap());
+
+ ExplodedGraph* G = TrimInternal(NBeg, NEnd, M.get(), InverseMap);
+
+ return std::make_pair(static_cast<ExplodedGraph*>(G), M.take());
}
-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;
+ExplodedGraph*
+ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources,
+ const ExplodedNode* const* EndSources,
+ InterExplodedGraphMap* M,
+ llvm::DenseMap<const void*, const void*> *InverseMap) const {
+
+ typedef llvm::DenseSet<const ExplodedNode*> Pass1Ty;
Pass1Ty Pass1;
-
- typedef llvm::DenseMap<const ExplodedNodeImpl*, ExplodedNodeImpl*> Pass2Ty;
+
+ typedef llvm::DenseMap<const ExplodedNode*, ExplodedNode*> Pass2Ty;
Pass2Ty& Pass2 = M->M;
-
- llvm::SmallVector<const ExplodedNodeImpl*, 10> WL1, WL2;
+
+ llvm::SmallVector<const ExplodedNode*, 10> WL1, WL2;
// ===- Pass 1 (reverse DFS) -===
- for (const ExplodedNodeImpl* const* I = BeginSources; I != EndSources; ++I) {
+ for (const ExplodedNode* 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();
+ const ExplodedNode *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)
+ for (ExplodedNode** 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) -===
+ ExplodedGraph* G = MakeEmptyGraph();
+
+ // ===- Pass 2 (forward DFS to construct the new graph) -===
while (!WL2.empty()) {
- const ExplodedNodeImpl* N = WL2.back();
+ const ExplodedNode* 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);
+ ExplodedNode* NewN = G->getNode(N->getLocation(), N->State, NULL);
Pass2[N] = NewN;
-
+
// Also record the reverse mapping from the new node to the old node.
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) {
+ for (ExplodedNode **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);
+
+ NewN->addPredecessor(PI->second, *G);
}
// 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);
+ for (ExplodedNode **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);
+ PI->second->addPredecessor(NewN, *G);
continue;
}
@@ -220,22 +262,20 @@ const {
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 =
+ExplodedNode*
+InterExplodedGraphMap::getMappedNode(const ExplodedNode* N) const {
+ llvm::DenseMap<const ExplodedNode*, ExplodedNode*>::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
index f69a16d..4f4103a 100644
--- a/lib/Analysis/GRBlockCounter.cpp
+++ b/lib/Analysis/GRBlockCounter.cpp
@@ -1,5 +1,5 @@
//==- GRBlockCounter.h - ADT for counting block visits -------------*- C++ -*-//
-//
+//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
diff --git a/lib/Analysis/GRCoreEngine.cpp b/lib/Analysis/GRCoreEngine.cpp
index ff7b548..8747247 100644
--- a/lib/Analysis/GRCoreEngine.cpp
+++ b/lib/Analysis/GRCoreEngine.cpp
@@ -1,5 +1,5 @@
//==- GRCoreEngine.cpp - Path-Sensitive Dataflow Engine ------------*- C++ -*-//
-//
+//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Analysis/PathSensitive/GRCoreEngine.h"
+#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "clang/AST/Expr.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Casting.h"
@@ -29,7 +30,7 @@ using namespace clang;
//===----------------------------------------------------------------------===//
namespace {
- class VISIBILITY_HIDDEN DFS : public GRWorkList {
+class VISIBILITY_HIDDEN DFS : public GRWorkList {
llvm::SmallVector<GRWorkListUnit,20> Stack;
public:
virtual bool hasWork() const {
@@ -47,27 +48,27 @@ public:
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();
+ GRWorkListUnit U = Queue.front();
Queue.pop();
return U;
}
};
-
+
} // end anonymous namespace
// Place the dstor for GRWorkList here because it contains virtual member
@@ -85,14 +86,14 @@ namespace {
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()) {
@@ -100,13 +101,13 @@ namespace {
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();
+ GRWorkListUnit U = Queue.front();
Queue.pop();
- return U;
+ return U;
}
};
} // end anonymous namespace
@@ -118,55 +119,80 @@ GRWorkList* GRWorkList::MakeBFSBlockDFSContents() {
//===----------------------------------------------------------------------===//
// Core analysis engine.
//===----------------------------------------------------------------------===//
+void GRCoreEngine::ProcessEndPath(GREndPathNodeBuilder& Builder) {
+ SubEngine.ProcessEndPath(Builder);
+}
+
+void GRCoreEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& Builder) {
+ SubEngine.ProcessStmt(S, Builder);
+}
+
+bool GRCoreEngine::ProcessBlockEntrance(CFGBlock* Blk, const GRState* State,
+ GRBlockCounter BC) {
+ return SubEngine.ProcessBlockEntrance(Blk, State, BC);
+}
+
+void GRCoreEngine::ProcessBranch(Stmt* Condition, Stmt* Terminator,
+ GRBranchNodeBuilder& Builder) {
+ SubEngine.ProcessBranch(Condition, Terminator, Builder);
+}
+
+void GRCoreEngine::ProcessIndirectGoto(GRIndirectGotoNodeBuilder& Builder) {
+ SubEngine.ProcessIndirectGoto(Builder);
+}
+
+void GRCoreEngine::ProcessSwitch(GRSwitchNodeBuilder& Builder) {
+ SubEngine.ProcessSwitch(Builder);
+}
/// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps.
-bool GRCoreEngineImpl::ExecuteWorkList(unsigned Steps) {
-
+bool GRCoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps) {
+
if (G->num_roots() == 0) { // Initialize the analysis by constructing
// the root if none exists.
-
- CFGBlock* Entry = &getCFG().getEntry();
-
- assert (Entry->empty() &&
+
+ CFGBlock* Entry = &(L->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());
-
+ CFGBlock* Succ = *(Entry->succ_begin());
+
// Construct an edge representing the
// starting location in the function.
- BlockEdge StartLoc(Entry, Succ);
-
+ BlockEdge StartLoc(Entry, Succ, L);
+
// Set the current block counter to being empty.
WList->setBlockCounter(BCounterFactory.GetEmptyCounter());
-
+
// Generate the root.
- GenerateNode(StartLoc, getInitialState(), 0);
+ GenerateNode(StartLoc, getInitialState(L), 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();
-
+ ExplodedNode* 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;
@@ -175,26 +201,26 @@ bool GRCoreEngineImpl::ExecuteWorkList(unsigned Steps) {
assert(isa<PostStmt>(Node->getLocation()));
HandlePostStmt(cast<PostStmt>(Node->getLocation()), WU.getBlock(),
WU.getIndex(), Node);
- break;
+ break;
}
}
-
+
return WList->hasWork();
}
-void GRCoreEngineImpl::HandleBlockEdge(const BlockEdge& L,
- ExplodedNodeImpl* Pred) {
-
+
+void GRCoreEngine::HandleBlockEdge(const BlockEdge& L, ExplodedNode* Pred) {
+
CFGBlock* Blk = L.getDst();
-
- // Check if we are entering the EXIT block.
- if (Blk == &getCFG().getExit()) {
-
- assert (getCFG().getExit().size() == 0
+
+ // Check if we are entering the EXIT block.
+ if (Blk == &(Pred->getLocationContext()->getCFG()->getExit())) {
+
+ assert (Pred->getLocationContext()->getCFG()->getExit().size() == 0
&& "EXIT block cannot contain Stmts.");
// Process the final state transition.
- GREndPathNodeBuilderImpl Builder(Blk, Pred, this);
+ GREndPathNodeBuilder Builder(Blk, Pred, this);
ProcessEndPath(Builder);
// This path is done. Don't enqueue any more nodes.
@@ -202,84 +228,81 @@ void GRCoreEngineImpl::HandleBlockEdge(const BlockEdge& L,
}
// FIXME: Should we allow ProcessBlockEntrance to also manipulate state?
-
+
if (ProcessBlockEntrance(Blk, Pred->State, WList->getBlockCounter()))
- GenerateNode(BlockEntrance(Blk), Pred->State, Pred);
+ GenerateNode(BlockEntrance(Blk, Pred->getLocationContext()), Pred->State, Pred);
}
-void GRCoreEngineImpl::HandleBlockEntrance(const BlockEntrance& L,
- ExplodedNodeImpl* Pred) {
-
+void GRCoreEngine::HandleBlockEntrance(const BlockEntrance& L,
+ ExplodedNode* 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.
+
+ // Process the entrance of the block.
if (Stmt* S = L.getFirstStmt()) {
- GRStmtNodeBuilderImpl Builder(L.getBlock(), 0, Pred, this);
+ GRStmtNodeBuilder Builder(L.getBlock(), 0, Pred, this,
+ SubEngine.getStateManager());
ProcessStmt(S, Builder);
}
- else
+ else
HandleBlockExit(L.getBlock(), Pred);
}
-GRCoreEngineImpl::~GRCoreEngineImpl() {
- delete WList;
-}
+void GRCoreEngine::HandleBlockExit(CFGBlock * B, ExplodedNode* Pred) {
-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:
+ 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
+
+ GRIndirectGotoNodeBuilder
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:
//
@@ -294,16 +317,15 @@ void GRCoreEngineImpl::HandleBlockExit(CFGBlock * B, ExplodedNodeImpl* Pred) {
HandleBranch(Term, Term, B, Pred);
return;
}
-
+
case Stmt::SwitchStmtClass: {
- GRSwitchNodeBuilderImpl builder(Pred, B,
- cast<SwitchStmt>(Term)->getCond(),
- this);
-
+ GRSwitchNodeBuilder builder(Pred, B, cast<SwitchStmt>(Term)->getCond(),
+ this);
+
ProcessSwitch(builder);
return;
}
-
+
case Stmt::WhileStmtClass:
HandleBranch(cast<WhileStmt>(Term)->getCond(), Term, B, Pred);
return;
@@ -312,265 +334,280 @@ void GRCoreEngineImpl::HandleBlockExit(CFGBlock * B, ExplodedNodeImpl* Pred) {
assert (B->succ_size() == 1 &&
"Blocks with no terminator should have at most 1 successor.");
-
- GenerateNode(BlockEdge(B, *(B->succ_begin())), Pred->State, Pred);
+
+ GenerateNode(BlockEdge(B, *(B->succ_begin()), Pred->getLocationContext()),
+ Pred->State, Pred);
}
-void GRCoreEngineImpl::HandleBranch(Stmt* Cond, Stmt* Term, CFGBlock * B,
- ExplodedNodeImpl* Pred) {
+void GRCoreEngine::HandleBranch(Stmt* Cond, Stmt* Term, CFGBlock * B,
+ ExplodedNode* Pred) {
assert (B->succ_size() == 2);
- GRBranchNodeBuilderImpl Builder(B, *(B->succ_begin()), *(B->succ_begin()+1),
- Pred, this);
-
+ GRBranchNodeBuilder 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) {
-
+void GRCoreEngine::HandlePostStmt(const PostStmt& L, CFGBlock* B,
+ unsigned StmtIdx, ExplodedNode* Pred) {
+
assert (!B->empty());
if (StmtIdx == B->size())
HandleBlockExit(B, Pred);
else {
- GRStmtNodeBuilderImpl Builder(B, StmtIdx, Pred, this);
+ GRStmtNodeBuilder Builder(B, StmtIdx, Pred, this,
+ SubEngine.getStateManager());
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) {
-
+void GRCoreEngine::GenerateNode(const ProgramPoint& Loc,
+ const GRState* State, ExplodedNode* Pred) {
+
bool IsNew;
- ExplodedNodeImpl* Node = G->getNodeImpl(Loc, State, &IsNew);
-
- if (Pred)
- Node->addPredecessor(Pred); // Link 'Node' with its predecessor.
+ ExplodedNode* Node = G->getNode(Loc, State, &IsNew);
+
+ if (Pred)
+ Node->addPredecessor(Pred, *G); // 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) {
+GRStmtNodeBuilder::GRStmtNodeBuilder(CFGBlock* b, unsigned idx,
+ ExplodedNode* N, GRCoreEngine* e,
+ GRStateManager &mgr)
+ : Eng(*e), B(*b), Idx(idx), Pred(N), LastNode(N), Mgr(mgr), Auditor(0),
+ PurgingDeadSymbols(false), BuildSinks(false), HasGeneratedNode(false),
+ PointKind(ProgramPoint::PostStmtKind), Tag(0) {
Deferred.insert(N);
+ CleanedState = getLastNode()->getState();
}
-GRStmtNodeBuilderImpl::~GRStmtNodeBuilderImpl() {
+GRStmtNodeBuilder::~GRStmtNodeBuilder() {
for (DeferredTy::iterator I=Deferred.begin(), E=Deferred.end(); I!=E; ++I)
if (!(*I)->isSink())
GenerateAutoTransition(*I);
}
-void GRStmtNodeBuilderImpl::GenerateAutoTransition(ExplodedNodeImpl* N) {
+void GRStmtNodeBuilder::GenerateAutoTransition(ExplodedNode* N) {
assert (!N->isSink());
-
- PostStmt Loc(getStmt());
-
+
+ PostStmt Loc(getStmt(), N->getLocationContext());
+
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);
+ ExplodedNode* Succ = Eng.G->getNode(Loc, N->State, &IsNew);
+ Succ->addPredecessor(N, *Eng.G);
if (IsNew)
Eng.WList->Enqueue(Succ, B, Idx+1);
}
-static inline PostStmt GetPostLoc(Stmt* S, ProgramPoint::Kind K,
- const void *tag) {
+static inline PostStmt GetPostLoc(const Stmt* S, ProgramPoint::Kind K,
+ const LocationContext *L, const void *tag) {
switch (K) {
default:
assert(false && "Invalid PostXXXKind.");
-
+
case ProgramPoint::PostStmtKind:
- return PostStmt(S, tag);
-
+ return PostStmt(S, L, tag);
+
case ProgramPoint::PostLoadKind:
- return PostLoad(S, tag);
+ return PostLoad(S, L, tag);
case ProgramPoint::PostUndefLocationCheckFailedKind:
- return PostUndefLocationCheckFailed(S, tag);
+ return PostUndefLocationCheckFailed(S, L, tag);
case ProgramPoint::PostLocationChecksSucceedKind:
- return PostLocationChecksSucceed(S, tag);
-
+ return PostLocationChecksSucceed(S, L, tag);
+
case ProgramPoint::PostOutOfBoundsCheckFailedKind:
- return PostOutOfBoundsCheckFailed(S, tag);
-
+ return PostOutOfBoundsCheckFailed(S, L, tag);
+
case ProgramPoint::PostNullCheckFailedKind:
- return PostNullCheckFailed(S, tag);
-
+ return PostNullCheckFailed(S, L, tag);
+
case ProgramPoint::PostStoreKind:
- return PostStore(S, tag);
-
+ return PostStore(S, L, tag);
+
case ProgramPoint::PostLValueKind:
- return PostLValue(S, tag);
-
+ return PostLValue(S, L, tag);
+
case ProgramPoint::PostPurgeDeadSymbolsKind:
- return PostPurgeDeadSymbols(S, tag);
+ return PostPurgeDeadSymbols(S, L, tag);
}
}
-ExplodedNodeImpl*
-GRStmtNodeBuilderImpl::generateNodeImpl(Stmt* S, const void* State,
- ExplodedNodeImpl* Pred,
+ExplodedNode*
+GRStmtNodeBuilder::generateNodeInternal(const Stmt* S, const GRState* State,
+ ExplodedNode* Pred,
ProgramPoint::Kind K,
const void *tag) {
- return generateNodeImpl(GetPostLoc(S, K, tag), State, Pred);
+ return K == ProgramPoint::PreStmtKind
+ ? generateNodeInternal(PreStmt(S, Pred->getLocationContext(),tag),
+ State, Pred)
+ : generateNodeInternal(GetPostLoc(S, K, Pred->getLocationContext(), tag),
+ State, Pred);
}
-ExplodedNodeImpl*
-GRStmtNodeBuilderImpl::generateNodeImpl(PostStmt Loc, const void* State,
- ExplodedNodeImpl* Pred) {
+ExplodedNode*
+GRStmtNodeBuilder::generateNodeInternal(const ProgramPoint &Loc,
+ const GRState* State,
+ ExplodedNode* Pred) {
bool IsNew;
- ExplodedNodeImpl* N = Eng.G->getNodeImpl(Loc, State, &IsNew);
- N->addPredecessor(Pred);
+ ExplodedNode* N = Eng.G->getNode(Loc, State, &IsNew);
+ N->addPredecessor(Pred, *Eng.G);
Deferred.erase(Pred);
-
+
if (IsNew) {
Deferred.insert(N);
LastNode = N;
return N;
}
-
+
LastNode = NULL;
- return NULL;
+ return NULL;
}
-ExplodedNodeImpl* GRBranchNodeBuilderImpl::generateNodeImpl(const void* State,
- bool branch) {
+ExplodedNode* GRBranchNodeBuilder::generateNode(const GRState* State,
+ bool branch) {
+
+ // If the branch has been marked infeasible we should not generate a node.
+ if (!isFeasible(branch))
+ return NULL;
+
bool IsNew;
-
- ExplodedNodeImpl* Succ =
- Eng.G->getNodeImpl(BlockEdge(Src, branch ? DstT : DstF), State, &IsNew);
-
- Succ->addPredecessor(Pred);
-
- if (branch) GeneratedTrue = true;
- else GeneratedFalse = true;
-
+
+ ExplodedNode* Succ =
+ Eng.G->getNode(BlockEdge(Src,branch ? DstT:DstF,Pred->getLocationContext()),
+ State, &IsNew);
+
+ Succ->addPredecessor(Pred, *Eng.G);
+
+ 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);
-
+GRBranchNodeBuilder::~GRBranchNodeBuilder() {
+ if (!GeneratedTrue) generateNode(Pred->State, true);
+ if (!GeneratedFalse) generateNode(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) {
+ExplodedNode*
+GRIndirectGotoNodeBuilder::generateNode(const iterator& I, const GRState* St,
+ bool isSink) {
bool IsNew;
-
- ExplodedNodeImpl* Succ =
- Eng.G->getNodeImpl(BlockEdge(Src, I.getBlock()), St, &IsNew);
-
- Succ->addPredecessor(Pred);
-
+
+ ExplodedNode* Succ = Eng.G->getNode(BlockEdge(Src, I.getBlock(),
+ Pred->getLocationContext()), St, &IsNew);
+
+ Succ->addPredecessor(Pred, *Eng.G);
+
if (IsNew) {
-
+
if (isSink)
Succ->markAsSink();
else
Eng.WList->Enqueue(Succ);
-
+
return Succ;
}
-
+
return NULL;
}
-ExplodedNodeImpl*
-GRSwitchNodeBuilderImpl::generateCaseStmtNodeImpl(const Iterator& I,
- const void* St) {
+ExplodedNode*
+GRSwitchNodeBuilder::generateCaseStmtNode(const iterator& I, const GRState* St){
bool IsNew;
-
- ExplodedNodeImpl* Succ = Eng.G->getNodeImpl(BlockEdge(Src, I.getBlock()),
- St, &IsNew);
- Succ->addPredecessor(Pred);
-
+
+ ExplodedNode* Succ = Eng.G->getNode(BlockEdge(Src, I.getBlock(),
+ Pred->getLocationContext()), St, &IsNew);
+ Succ->addPredecessor(Pred, *Eng.G);
+
if (IsNew) {
Eng.WList->Enqueue(Succ);
return Succ;
}
-
+
return NULL;
}
-ExplodedNodeImpl*
-GRSwitchNodeBuilderImpl::generateDefaultCaseNodeImpl(const void* St,
- bool isSink) {
-
+ExplodedNode*
+GRSwitchNodeBuilder::generateDefaultCaseNode(const GRState* 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);
-
+
+ ExplodedNode* Succ = Eng.G->getNode(BlockEdge(Src, DefaultBlock,
+ Pred->getLocationContext()), St, &IsNew);
+ Succ->addPredecessor(Pred, *Eng.G);
+
if (IsNew) {
if (isSink)
Succ->markAsSink();
else
Eng.WList->Enqueue(Succ);
-
+
return Succ;
}
-
+
return NULL;
}
-GREndPathNodeBuilderImpl::~GREndPathNodeBuilderImpl() {
+GREndPathNodeBuilder::~GREndPathNodeBuilder() {
// Auto-generate an EOP node if one has not been generated.
- if (!HasGeneratedNode) generateNodeImpl(Pred->State);
+ if (!HasGeneratedNode) generateNode(Pred->State);
}
-ExplodedNodeImpl*
-GREndPathNodeBuilderImpl::generateNodeImpl(const void* State,
- const void *tag,
- ExplodedNodeImpl* P) {
- HasGeneratedNode = true;
+ExplodedNode*
+GREndPathNodeBuilder::generateNode(const GRState* State, const void *tag,
+ ExplodedNode* P) {
+ HasGeneratedNode = true;
bool IsNew;
-
- ExplodedNodeImpl* Node =
- Eng.G->getNodeImpl(BlockEntrance(&B, tag), State, &IsNew);
-
- Node->addPredecessor(P ? P : Pred);
-
+
+ ExplodedNode* Node = Eng.G->getNode(BlockEntrance(&B,
+ Pred->getLocationContext(), tag), State, &IsNew);
+
+ Node->addPredecessor(P ? P : Pred, *Eng.G);
+
if (IsNew) {
Eng.G->addEndOfPath(Node);
return Node;
}
-
+
return NULL;
}
diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp
index d9117f5..5079ace 100644
--- a/lib/Analysis/GRExprEngine.cpp
+++ b/lib/Analysis/GRExprEngine.cpp
@@ -15,16 +15,16 @@
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "clang/Analysis/PathSensitive/GRExprEngineBuilders.h"
+#include "clang/Analysis/PathSensitive/Checker.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/StmtObjC.h"
#include "clang/Basic/Builtins.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"
+#include "llvm/ADT/ImmutableList.h"
#ifndef NDEBUG
#include "llvm/Support/GraphWriter.h"
@@ -36,7 +36,7 @@ using llvm::cast;
using llvm::APSInt;
//===----------------------------------------------------------------------===//
-// Engine construction and deletion.
+// Batch auditor. DEPRECATED.
//===----------------------------------------------------------------------===//
namespace {
@@ -44,7 +44,7 @@ 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;
@@ -52,18 +52,18 @@ class VISIBILITY_HIDDEN MappedBatchAuditor : public GRSimpleAPICheck {
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;
}
@@ -75,34 +75,69 @@ public:
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);
+ AllStmts = F.Concat(A, AllStmts);
}
- virtual bool Audit(NodeTy* N, GRStateManager& VMgr) {
+ virtual bool Audit(ExplodedNode* 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();
+ const 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()) {
+ 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;
+
+ return isSink;
}
};
} // end anonymous namespace
//===----------------------------------------------------------------------===//
+// Checker worklist routines.
+//===----------------------------------------------------------------------===//
+
+void GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst,
+ ExplodedNodeSet &Src, bool isPrevisit) {
+
+ if (Checkers.empty()) {
+ Dst = Src;
+ return;
+ }
+
+ ExplodedNodeSet Tmp;
+ ExplodedNodeSet *PrevSet = &Src;
+
+ for (std::vector<Checker*>::iterator I = Checkers.begin(), E = Checkers.end();
+ I != E; ++I) {
+
+ ExplodedNodeSet *CurrSet = (I+1 == E) ? &Dst
+ : (PrevSet == &Tmp) ? &Src : &Tmp;
+ CurrSet->clear();
+ Checker *checker = *I;
+
+ for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
+ NI != NE; ++NI)
+ checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, isPrevisit);
+
+ // Update which NodeSet is the current one.
+ PrevSet = CurrSet;
+ }
+
+ // Don't autotransition. The CheckerContext objects should do this
+ // automatically.
+}
+
+//===----------------------------------------------------------------------===//
// Engine construction and deletion.
//===----------------------------------------------------------------------===//
@@ -112,29 +147,27 @@ static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) {
}
-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),
+GRExprEngine::GRExprEngine(AnalysisManager &mgr)
+ : AMgr(mgr),
+ CoreEngine(mgr.getASTContext(), *this),
G(CoreEngine.getGraph()),
- Liveness(L),
Builder(NULL),
- StateMgr(G.getContext(), SMC, CMC, G.getAllocator(), cfg, CD, L),
+ StateMgr(G.getContext(), mgr.getStoreManagerCreator(),
+ mgr.getConstraintManagerCreator(), G.getAllocator()),
SymMgr(StateMgr.getSymbolManager()),
ValMgr(StateMgr.getValueManager()),
- SVator(clang::CreateSimpleSValuator(ValMgr)), // FIXME: Generalize later.
+ SVator(ValMgr.getSValuator()),
CurrentStmt(NULL),
NSExceptionII(NULL), NSExceptionInstanceRaiseSelectors(NULL),
- RaiseSel(GetNullarySelector("raise", G.getContext())),
- PurgeDead(purgeDead),
- BR(BRD, *this),
- EagerlyAssume(eagerlyAssume) {}
+ RaiseSel(GetNullarySelector("raise", G.getContext())),
+ BR(mgr, *this) {}
-GRExprEngine::~GRExprEngine() {
+GRExprEngine::~GRExprEngine() {
BR.FlushReports();
delete [] NSExceptionInstanceRaiseSelectors;
+ for (std::vector<Checker*>::iterator I=Checkers.begin(), E=Checkers.end();
+ I!=E; ++I)
+ delete *I;
}
//===----------------------------------------------------------------------===//
@@ -151,7 +184,7 @@ void GRExprEngine::setTransferFunctions(GRTransferFuncs* tf) {
void GRExprEngine::AddCheck(GRSimpleAPICheck* A, Stmt::StmtClass C) {
if (!BatchAuditor)
BatchAuditor.reset(new MappedBatchAuditor(getGraph().getAllocator()));
-
+
((MappedBatchAuditor*) BatchAuditor.get())->AddCheck(A, C);
}
@@ -162,29 +195,50 @@ void GRExprEngine::AddCheck(GRSimpleAPICheck *A) {
((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.
+const GRState* GRExprEngine::getInitialState(const LocationContext *InitLoc) {
+ const GRState *state = StateMgr.getInitialState(InitLoc);
+
+ // Preconditions.
+
// 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()))
+ const Decl *D = InitLoc->getDecl();
+
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ // Precondition: the first argument of 'main' is an integer guaranteed
+ // to be > 0.
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 = state->getRegion(PD)) {
+ if (const MemRegion *R = state->getRegion(PD, InitLoc)) {
SVal V = state->getSVal(loc::MemRegionVal(R));
- SVal Constraint = EvalBinOp(state, BinaryOperator::GT, V,
- ValMgr.makeZeroVal(T),
- getContext().IntTy);
-
- if (const GRState *newState = state->assume(Constraint, true))
- state = newState;
+ SVal Constraint_untested = EvalBinOp(state, BinaryOperator::GT, V,
+ ValMgr.makeZeroVal(T),
+ getContext().IntTy);
+
+ if (DefinedOrUnknownSVal *Constraint =
+ dyn_cast<DefinedOrUnknownSVal>(&Constraint_untested)) {
+ if (const GRState *newState = state->Assume(*Constraint, true))
+ state = newState;
+ }
}
}
+ }
+ else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ // Precondition: 'self' is always non-null upon entry to an Objective-C
+ // method.
+ const ImplicitParamDecl *SelfD = MD->getSelfDecl();
+ const MemRegion *R = state->getRegion(SelfD, InitLoc);
+ SVal V = state->getSVal(loc::MemRegionVal(R));
+
+ if (const Loc *LV = dyn_cast<Loc>(&V)) {
+ // Assume that the pointer value in 'self' is non-null.
+ state = state->Assume(*LV, true);
+ assert(state && "'self' cannot be null");
+ }
+ }
return state;
}
@@ -193,32 +247,33 @@ const GRState* GRExprEngine::getInitialState() {
// Top-level transfer function logic (Dispatcher).
//===----------------------------------------------------------------------===//
-void GRExprEngine::ProcessStmt(Stmt* S, StmtNodeBuilder& builder) {
-
+void GRExprEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& 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();
+
+ // Create the cleaned state.
+ SymbolReaper SymReaper(Builder->getBasePredecessor()->getLiveVariables(),
+ SymMgr);
+ CleanedState = AMgr.shouldPurgeDead()
+ ? StateMgr.RemoveDeadBindings(EntryNode->getState(), CurrentStmt, SymReaper)
+ : EntryNode->getState();
// Process any special transfer function for dead symbols.
- NodeSet Tmp;
-
+ ExplodedNodeSet Tmp;
+
if (!SymReaper.hasDeadSymbols())
Tmp.Add(EntryNode);
else {
@@ -227,36 +282,36 @@ void GRExprEngine::ProcessStmt(Stmt* S, StmtNodeBuilder& builder) {
SaveAndRestore<bool> OldPurgeDeadSymbols(Builder->PurgingDeadSymbols);
Builder->PurgingDeadSymbols = true;
-
- getTF().EvalDeadSymbols(Tmp, *this, *Builder, EntryNode, S,
+
+ 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) {
+ for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
- NodeSet Dst;
-
- // Set the cleaned state.
+ ExplodedNodeSet Dst;
+
+ // Set the cleaned state.
Builder->SetCleanedState(*I == EntryNode ? CleanedState : GetState(*I));
-
- // Visit the statement.
+
+ // 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.
+ // 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;
@@ -264,11 +319,11 @@ void GRExprEngine::ProcessStmt(Stmt* S, StmtNodeBuilder& builder) {
// FIXME: Consolidate.
StateMgr.CurrentStmt = 0;
CurrentStmt = 0;
-
+
Builder = NULL;
}
-void GRExprEngine::Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst) {
+void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
S->getLocStart(),
"Error evaluating statement");
@@ -276,46 +331,46 @@ void GRExprEngine::Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst) {
// 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)) {
+
+ if (S != CurrentStmt && Pred->getLocationContext()->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, state->bindExpr(B, state->getSVal(B->getRHS())));
+ MakeNode(Dst, B, Pred, state->BindExpr(B, state->getSVal(B->getRHS())));
break;
}
- if (EagerlyAssume && (B->isRelationalOp() || B->isEqualityOp())) {
- NodeSet Tmp;
+ if (AMgr.shouldEagerlyAssume() && (B->isRelationalOp() || B->isEqualityOp())) {
+ ExplodedNodeSet Tmp;
VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Tmp);
- EvalEagerlyAssume(Dst, Tmp, cast<Expr>(S));
+ EvalEagerlyAssume(Dst, Tmp, cast<Expr>(S));
}
else
VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst);
@@ -332,13 +387,13 @@ void GRExprEngine::Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst) {
// 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;
@@ -346,22 +401,22 @@ void GRExprEngine::Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst) {
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);
@@ -372,11 +427,11 @@ void GRExprEngine::Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst) {
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;
@@ -384,12 +439,12 @@ void GRExprEngine::Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst) {
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.
@@ -398,19 +453,19 @@ void GRExprEngine::Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst) {
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);
@@ -421,25 +476,25 @@ void GRExprEngine::Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst) {
Dst.Add(Pred);
break;
}
-
+
if (Expr* LastExpr = dyn_cast<Expr>(*SE->getSubStmt()->body_rbegin())) {
const GRState* state = GetState(Pred);
- MakeNode(Dst, SE, Pred, state->bindExpr(SE, state->getSVal(LastExpr)));
+ MakeNode(Dst, SE, Pred, state->BindExpr(SE, state->getSVal(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;
+ if (AMgr.shouldEagerlyAssume() && (U->getOpcode() == UnaryOperator::LNot)) {
+ ExplodedNodeSet Tmp;
VisitUnaryOperator(U, Pred, Tmp, false);
EvalEagerlyAssume(Dst, Tmp, U);
}
@@ -450,44 +505,45 @@ void GRExprEngine::Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst) {
}
}
-void GRExprEngine::VisitLValue(Expr* Ex, NodeTy* Pred, NodeSet& Dst) {
-
+void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
+ ExplodedNodeSet& Dst) {
+
Ex = Ex->IgnoreParens();
-
- if (Ex != CurrentStmt && getCFG().isBlkExpr(Ex)) {
+
+ if (Ex != CurrentStmt && Pred->getLocationContext()->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:
+ case Stmt::ObjCImplicitSetterGetterRefExprClass:
// 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
@@ -505,10 +561,10 @@ void GRExprEngine::VisitLValue(Expr* Ex, NodeTy* Pred, NodeSet& Dst) {
case Stmt::StringLiteralClass: {
const GRState* state = GetState(Pred);
SVal V = state->getLValue(cast<StringLiteral>(Ex));
- MakeNode(Dst, Ex, Pred, state->bindExpr(Ex, V));
+ MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V));
return;
}
-
+
default:
// Arbitrary subexpressions can return aggregate temporaries that
// can be used in a lvalue context. We need to enhance our support
@@ -517,7 +573,7 @@ void GRExprEngine::VisitLValue(Expr* Ex, NodeTy* Pred, NodeSet& Dst) {
assert ((Ex->getType()->isAggregateType()) &&
"Other kinds of expressions with non-aggregate/union types do"
" not have lvalues.");
-
+
Visit(Ex, Pred, Dst);
}
}
@@ -528,7 +584,7 @@ void GRExprEngine::VisitLValue(Expr* Ex, NodeTy* Pred, NodeSet& Dst) {
bool GRExprEngine::ProcessBlockEntrance(CFGBlock* B, const GRState*,
GRBlockCounter BC) {
-
+
return BC.getNumVisited(B->getBlockID()) < 3;
}
@@ -536,12 +592,9 @@ bool GRExprEngine::ProcessBlockEntrance(CFGBlock* B, const GRState*,
// Generic node creation.
//===----------------------------------------------------------------------===//
-GRExprEngine::NodeTy* GRExprEngine::MakeNode(NodeSet& Dst, Stmt* S,
- NodeTy* Pred,
- const GRState* St,
- ProgramPoint::Kind K,
- const void *tag) {
-
+ExplodedNode* GRExprEngine::MakeNode(ExplodedNodeSet& Dst, Stmt* S,
+ ExplodedNode* Pred, const GRState* St,
+ ProgramPoint::Kind K, const void *tag) {
assert (Builder && "GRStmtNodeBuilder not present.");
SaveAndRestore<const void*> OldTag(Builder->Tag);
Builder->Tag = tag;
@@ -555,54 +608,54 @@ GRExprEngine::NodeTy* GRExprEngine::MakeNode(NodeSet& Dst, Stmt* S,
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)
+ (Op == BinaryOperator::LOr && !branchTaken)
? B->getRHS() : B->getLHS();
-
- return state->bindBlkExpr(B, UndefinedVal(Ex));
+
+ return state->BindExpr(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;
-
+
+ Expr* Ex;
+
if (branchTaken)
- Ex = C->getLHS() ? C->getLHS() : C->getCond();
+ Ex = C->getLHS() ? C->getLHS() : C->getCond();
else
Ex = C->getRHS();
-
- return state->bindBlkExpr(C, UndefinedVal(Ex));
+
+ return state->BindExpr(C, UndefinedVal(Ex));
}
-
+
case Stmt::ChooseExprClass: { // ?:
-
+
ChooseExpr* C = cast<ChooseExpr>(Terminator);
-
- Expr* Ex = branchTaken ? C->getLHS() : C->getRHS();
- return state->bindBlkExpr(C, UndefinedVal(Ex));
+
+ Expr* Ex = branchTaken ? C->getLHS() : C->getRHS();
+ return state->BindExpr(C, UndefinedVal(Ex));
}
}
}
@@ -621,19 +674,19 @@ static SVal RecoverCastedSymbol(GRStateManager& StateMgr, const GRState* state,
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();
}
@@ -642,211 +695,215 @@ static SVal RecoverCastedSymbol(GRStateManager& StateMgr, const GRState* state,
if (!bitsInit || !T->isIntegerType() || Ctx.getTypeSize(T) > bits)
return UnknownVal();
-
+
return state->getSVal(Ex);
}
void GRExprEngine::ProcessBranch(Stmt* Condition, Stmt* Term,
- BranchNodeBuilder& builder) {
-
- // Remove old bindings for subexpressions.
- const GRState* PrevState =
- StateMgr.RemoveSubExprBindings(builder.getState());
-
+ GRBranchNodeBuilder& builder) {
+
// Check for NULL conditions; e.g. "for(;;)"
- if (!Condition) {
+ if (!Condition) {
builder.markInfeasible(false);
return;
}
-
+
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
Condition->getLocStart(),
"Error evaluating branch");
+
+ const GRState* PrevState = builder.getState();
+ SVal X = PrevState->getSVal(Condition);
+ DefinedSVal *V = NULL;
- SVal V = PrevState->getSVal(Condition);
-
- switch (V.getBaseKind()) {
- default:
- break;
+ while (true) {
+ V = dyn_cast<DefinedSVal>(&X);
- case SVal::UnknownKind: {
- if (Expr *Ex = dyn_cast<Expr>(Condition)) {
+ if (!V) {
+ if (X.isUnknown()) {
+ if (const 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;
+ // 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()) {
+ X = recovered;
+ continue;
+ }
}
- }
+ }
+
+ builder.generateNode(MarkBranch(PrevState, Term, true), true);
+ builder.generateNode(MarkBranch(PrevState, Term, false), false);
+ return;
}
-
- builder.generateNode(MarkBranch(PrevState, Term, true), true);
- builder.generateNode(MarkBranch(PrevState, Term, false), false);
- return;
- }
-
- case SVal::UndefinedKind: {
- NodeTy* N = builder.generateNode(PrevState, true);
+
+ assert(X.isUndef());
+ ExplodedNode *N = builder.generateNode(PrevState, true);
if (N) {
N->markAsSink();
UndefBranches.insert(N);
}
-
+
builder.markInfeasible(false);
return;
- }
- }
+ }
+ break;
+ }
+
// Process the true branch.
- if (const GRState *state = PrevState->assume(V, true))
- builder.generateNode(MarkBranch(state, Term, true), true);
- else
- builder.markInfeasible(true);
-
- // Process the false branch.
- if (const GRState *state = PrevState->assume(V, false))
- builder.generateNode(MarkBranch(state, Term, false), false);
- else
- builder.markInfeasible(false);
+ if (builder.isFeasible(true)) {
+ if (const GRState *state = PrevState->Assume(*V, true))
+ builder.generateNode(MarkBranch(state, Term, true), true);
+ else
+ builder.markInfeasible(true);
+ }
+
+ // Process the false branch.
+ if (builder.isFeasible(false)) {
+ if (const GRState *state = PrevState->Assume(*V, false))
+ 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) {
+void GRExprEngine::ProcessIndirectGoto(GRIndirectGotoNodeBuilder& builder) {
- const GRState *state = builder.getState();
+ const GRState *state = builder.getState();
SVal V = state->getSVal(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;
+
+ typedef GRIndirectGotoNodeBuilder::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);
+ ExplodedNode* 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));
-
+ ExplodedNode* Pred, ExplodedNodeSet& Dst) {
+
+ assert (Ex == CurrentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(Ex));
+
const GRState* state = GetState(Pred);
- SVal X = state->getBlkExprSVal(Ex);
-
+ SVal X = state->getSVal(Ex);
+
assert (X.isUndef());
-
+
Expr *SE = (Expr*) cast<UndefinedVal>(X).getData();
- assert(SE);
- X = state->getBlkExprSVal(SE);
-
+ assert(SE);
+ X = state->getSVal(SE);
+
// Make sure that we invalidate the previous binding.
- MakeNode(Dst, Ex, Pred, state->bindExpr(Ex, X, true, true));
+ MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, X, 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();
+void GRExprEngine::ProcessSwitch(GRSwitchNodeBuilder& builder) {
+ typedef GRSwitchNodeBuilder::iterator iterator;
+ const GRState* state = builder.getState();
Expr* CondE = builder.getCondition();
- SVal CondV = state->getSVal(CondE);
+ SVal CondV_untested = state->getSVal(CondE);
- if (CondV.isUndef()) {
- NodeTy* N = builder.generateDefaultCaseNode(state, true);
+ if (CondV_untested.isUndef()) {
+ ExplodedNode* N = builder.generateDefaultCaseNode(state, true);
UndefBranches.insert(N);
return;
}
+ DefinedOrUnknownSVal CondV = cast<DefinedOrUnknownSVal>(CondV_untested);
- const GRState* DefaultSt = state;
+ const GRState *DefaultSt = state;
bool defaultIsFeasible = 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());
-
+ bool b = Case->getLHS()->Evaluate(V1, getContext());
+
// Sanity checks. These go away in Release builds.
- assert(b && V1.Val.isInt() && !V1.HasSideEffects
+ 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() ==
+ 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
+ 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.
- if (const GRState* stateNew = state->assume(Res, true)) {
+ nonloc::ConcreteInt CaseVal(getBasicVals().getValue(V1.Val.getInt()));
+ DefinedOrUnknownSVal Res = SVator.EvalEQ(DefaultSt, CondV, CaseVal);
+
+ // Now "assume" that the case matches.
+ if (const GRState* stateNew = state->Assume(Res, true)) {
builder.generateCaseStmtNode(I, stateNew);
-
+
// 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).
- if (const GRState *stateNew = DefaultSt->assume(Res, false)) {
+ if (const GRState *stateNew = DefaultSt->Assume(Res, false)) {
defaultIsFeasible = true;
DefaultSt = stateNew;
}
@@ -854,15 +911,15 @@ void GRExprEngine::ProcessSwitch(SwitchNodeBuilder& builder) {
// 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.
+ // possible.
if (defaultIsFeasible) builder.generateDefaultCaseNode(DefaultSt);
}
@@ -870,74 +927,72 @@ void GRExprEngine::ProcessSwitch(SwitchNodeBuilder& builder) {
// Transfer functions: logical operations ('&&', '||').
//===----------------------------------------------------------------------===//
-void GRExprEngine::VisitLogicalExpr(BinaryOperator* B, NodeTy* Pred,
- NodeSet& Dst) {
-
+void GRExprEngine::VisitLogicalExpr(BinaryOperator* B, ExplodedNode* Pred,
+ ExplodedNodeSet& Dst) {
+
assert(B->getOpcode() == BinaryOperator::LAnd ||
B->getOpcode() == BinaryOperator::LOr);
-
- assert(B == CurrentStmt && getCFG().isBlkExpr(B));
-
+
+ assert(B == CurrentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(B));
+
const GRState* state = GetState(Pred);
- SVal X = state->getBlkExprSVal(B);
+ SVal X = state->getSVal(B);
assert(X.isUndef());
-
- Expr* Ex = (Expr*) cast<UndefinedVal>(X).getData();
-
+
+ const Expr *Ex = (const Expr*) cast<UndefinedVal>(X).getData();
assert(Ex);
-
+
if (Ex == B->getRHS()) {
-
- X = state->getBlkExprSVal(Ex);
-
+ X = state->getSVal(Ex);
+
// Handle undefined values.
-
if (X.isUndef()) {
- MakeNode(Dst, B, Pred, state->bindBlkExpr(B, X));
+ MakeNode(Dst, B, Pred, state->BindExpr(B, X));
return;
}
+ DefinedOrUnknownSVal XD = cast<DefinedOrUnknownSVal>(X);
+
// We took the RHS. Because the value of the '&&' or '||' expression must
// evaluate to 0 or 1, we must assume the value of the RHS evaluates to 0
// or 1. Alternatively, we could take a lazy approach, and calculate this
// value later when necessary. We don't have the machinery in place for
// this right now, and since most logical expressions are used for branches,
- // the payoff is not likely to be large. Instead, we do eager evaluation.
- if (const GRState *newState = state->assume(X, true))
- MakeNode(Dst, B, Pred,
- newState->bindBlkExpr(B, ValMgr.makeIntVal(1U, B->getType())));
-
- if (const GRState *newState = state->assume(X, false))
- MakeNode(Dst, B, Pred,
- newState->bindBlkExpr(B, ValMgr.makeIntVal(0U, B->getType())));
+ // the payoff is not likely to be large. Instead, we do eager evaluation.
+ if (const GRState *newState = state->Assume(XD, true))
+ MakeNode(Dst, B, Pred,
+ newState->BindExpr(B, ValMgr.makeIntVal(1U, B->getType())));
+
+ if (const GRState *newState = state->Assume(XD, false))
+ MakeNode(Dst, B, Pred,
+ newState->BindExpr(B, ValMgr.makeIntVal(0U, B->getType())));
}
else {
// We took the LHS expression. Depending on whether we are '&&' or
// '||' we know what the value of the expression is via properties of
// the short-circuiting.
- X = ValMgr.makeIntVal(B->getOpcode() == BinaryOperator::LAnd ? 0U : 1U,
+ X = ValMgr.makeIntVal(B->getOpcode() == BinaryOperator::LAnd ? 0U : 1U,
B->getType());
- MakeNode(Dst, B, Pred, state->bindBlkExpr(B, X));
+ MakeNode(Dst, B, Pred, state->BindExpr(B, X));
}
}
-
+
//===----------------------------------------------------------------------===//
// Transfer functions: Loads and stores.
//===----------------------------------------------------------------------===//
-void GRExprEngine::VisitDeclRefExpr(DeclRefExpr* Ex, NodeTy* Pred, NodeSet& Dst,
- bool asLValue) {
-
- const GRState* state = GetState(Pred);
+void GRExprEngine::VisitDeclRefExpr(DeclRefExpr *Ex, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst, bool asLValue) {
- const NamedDecl* D = Ex->getDecl();
+ const GRState *state = GetState(Pred);
+ const NamedDecl *D = Ex->getDecl();
if (const VarDecl* VD = dyn_cast<VarDecl>(D)) {
- SVal V = state->getLValue(VD);
+ SVal V = state->getLValue(VD, Pred->getLocationContext());
if (asLValue)
- MakeNode(Dst, Ex, Pred, state->bindExpr(Ex, V),
+ MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V),
ProgramPoint::PostLValueKind);
else
EvalLoad(Dst, Ex, Pred, state, V);
@@ -947,29 +1002,30 @@ void GRExprEngine::VisitDeclRefExpr(DeclRefExpr* Ex, NodeTy* Pred, NodeSet& Dst,
assert(!asLValue && "EnumConstantDecl does not have lvalue.");
SVal V = ValMgr.makeIntVal(ED->getInitVal());
- MakeNode(Dst, Ex, Pred, state->bindExpr(Ex, V));
+ MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V));
return;
} else if (const FunctionDecl* FD = dyn_cast<FunctionDecl>(D)) {
- assert(asLValue);
+ // This code is valid regardless of the value of 'isLValue'.
SVal V = ValMgr.getFunctionPointer(FD);
- MakeNode(Dst, Ex, Pred, state->bindExpr(Ex, V),
+ MakeNode(Dst, Ex, Pred, state->BindExpr(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) {
-
+void GRExprEngine::VisitArraySubscriptExpr(ArraySubscriptExpr* A,
+ ExplodedNode* Pred,
+ ExplodedNodeSet& Dst, bool asLValue){
+
Expr* Base = A->getBase()->IgnoreParens();
Expr* Idx = A->getIdx()->IgnoreParens();
- NodeSet Tmp;
-
+ ExplodedNodeSet 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?
@@ -977,20 +1033,20 @@ void GRExprEngine::VisitArraySubscriptExpr(ArraySubscriptExpr* A, NodeTy* Pred,
// semantics.
VisitLValue(Base, Pred, Tmp);
}
- else
+ 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;
+
+ for (ExplodedNodeSet::iterator I1=Tmp.begin(), E1=Tmp.end(); I1!=E1; ++I1) {
+ ExplodedNodeSet Tmp2;
Visit(Idx, *I1, Tmp2); // Evaluate the index.
-
- for (NodeSet::iterator I2=Tmp2.begin(), E2=Tmp2.end(); I2!=E2; ++I2) {
+
+ for (ExplodedNodeSet::iterator I2=Tmp2.begin(),E2=Tmp2.end();I2!=E2; ++I2) {
const GRState* state = GetState(*I2);
- SVal V = state->getLValue(A->getType(), state->getSVal(Base),
- state->getSVal(Idx));
+ SVal V = state->getLValue(A->getType(), state->getSVal(Idx),
+ state->getSVal(Base));
if (asLValue)
- MakeNode(Dst, A, *I2, state->bindExpr(A, V),
+ MakeNode(Dst, A, *I2, state->BindExpr(A, V),
ProgramPoint::PostLValueKind);
else
EvalLoad(Dst, A, *I2, state, V);
@@ -999,30 +1055,30 @@ void GRExprEngine::VisitArraySubscriptExpr(ArraySubscriptExpr* A, NodeTy* Pred,
}
/// VisitMemberExpr - Transfer function for member expressions.
-void GRExprEngine::VisitMemberExpr(MemberExpr* M, NodeTy* Pred,
- NodeSet& Dst, bool asLValue) {
-
+void GRExprEngine::VisitMemberExpr(MemberExpr* M, ExplodedNode* Pred,
+ ExplodedNodeSet& Dst, bool asLValue) {
+
Expr* Base = M->getBase()->IgnoreParens();
- NodeSet Tmp;
-
- if (M->isArrow())
+ ExplodedNodeSet 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) {
+ for (ExplodedNodeSet::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 = state->getLValue(state->getSVal(Base), Field);
+ SVal L = state->getLValue(Field, state->getSVal(Base));
if (asLValue)
- MakeNode(Dst, M, *I, state->bindExpr(M, L),
+ MakeNode(Dst, M, *I, state->BindExpr(M, L),
ProgramPoint::PostLValueKind);
else
EvalLoad(Dst, M, *I, state, L);
@@ -1031,11 +1087,11 @@ void GRExprEngine::VisitMemberExpr(MemberExpr* M, NodeTy* Pred,
/// 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) {
+void GRExprEngine::EvalBind(ExplodedNodeSet& Dst, Expr* Ex, ExplodedNode* 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
@@ -1053,7 +1109,7 @@ void GRExprEngine::EvalBind(NodeSet& Dst, Expr* Ex, NodeTy* Pred,
// 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);
}
@@ -1063,22 +1119,22 @@ void GRExprEngine::EvalBind(NodeSet& Dst, Expr* Ex, NodeTy* Pred,
/// @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,
+void GRExprEngine::EvalStore(ExplodedNodeSet& Dst, Expr* Ex, ExplodedNode* 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.
+ // Proceed with the store.
SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind);
SaveAndRestore<const void*> OldTag(Builder->Tag);
Builder->PointKind = ProgramPoint::PostStoreKind;
@@ -1086,18 +1142,18 @@ void GRExprEngine::EvalStore(NodeSet& Dst, Expr* Ex, NodeTy* Pred,
EvalBind(Dst, Ex, Pred, state, location, Val);
}
-void GRExprEngine::EvalLoad(NodeSet& Dst, Expr* Ex, NodeTy* Pred,
+void GRExprEngine::EvalLoad(ExplodedNodeSet& Dst, Expr* Ex, ExplodedNode* Pred,
const GRState* state, SVal location,
const void *tag) {
- // Evaluate the location (checks for bad dereferences).
+ // 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;
@@ -1106,86 +1162,89 @@ void GRExprEngine::EvalLoad(NodeSet& Dst, Expr* Ex, NodeTy* Pred,
if (location.isUnknown()) {
// This is important. We must nuke the old binding.
- MakeNode(Dst, Ex, Pred, state->bindExpr(Ex, UnknownVal()), K, tag);
+ MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, UnknownVal()),
+ K, tag);
}
else {
SVal V = state->getSVal(cast<Loc>(location), Ex->getType());
- MakeNode(Dst, Ex, Pred, state->bindExpr(Ex, V), K, tag);
+ MakeNode(Dst, Ex, Pred, state->BindExpr(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;
+void GRExprEngine::EvalStore(ExplodedNodeSet& Dst, Expr* Ex, Expr* StoreE,
+ ExplodedNode* Pred, const GRState* state,
+ SVal location, SVal Val, const void *tag) {
+
+ ExplodedNodeSet TmpDst;
EvalStore(TmpDst, StoreE, Pred, state, location, Val, tag);
- for (NodeSet::iterator I=TmpDst.begin(), E=TmpDst.end(); I!=E; ++I)
+ for (ExplodedNodeSet::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) {
-
+ExplodedNode* GRExprEngine::EvalLocation(Stmt* Ex, ExplodedNode* 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.
+
+ // Check for loads/stores from/to undefined values.
if (location.isUndef()) {
- NodeTy* N =
+ ExplodedNode* 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);
-
+
+ Loc LV = cast<Loc>(location);
+
// "Assume" that the pointer is not NULL.
- const GRState *StNotNull = state->assume(LV, true);
-
+ const GRState *StNotNull = state->Assume(LV, true);
+
// "Assume" that the pointer is NULL.
- const GRState *StNull = state->assume(LV, false);
+ const GRState *StNull = state->Assume(LV, false);
- if (StNull) {
+ if (StNull) {
// 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,
+ ExplodedNode* NullNode =
+ Builder->generateNode(Ex, StNull, Pred,
ProgramPoint::PostNullCheckFailedKind);
- if (NullNode) {
- NullNode->markAsSink();
+ if (NullNode) {
+ NullNode->markAsSink();
if (StNotNull) ImplicitNullDeref.insert(NullNode);
else ExplicitNullDeref.insert(NullNode);
}
}
-
+
if (!StNotNull)
return NULL;
+ // FIXME: Temporarily disable out-of-bounds checking until we make
+ // the logic reflect recent changes to CastRegion and friends.
+#if 0
// Check for out-of-bound array access.
if (isa<loc::MemRegionVal>(LV)) {
const MemRegion* R = cast<loc::MemRegionVal>(LV).getRegion();
@@ -1196,14 +1255,14 @@ GRExprEngine::NodeTy* GRExprEngine::EvalLocation(Stmt* Ex, NodeTy* Pred,
SVal NumElements = getStoreManager().getSizeInElements(StNotNull,
ER->getSuperRegion());
- const GRState * StInBound = StNotNull->assumeInBound(Idx, NumElements,
+ const GRState * StInBound = StNotNull->AssumeInBound(Idx, NumElements,
true);
- const GRState* StOutBound = StNotNull->assumeInBound(Idx, NumElements,
+ const GRState* StOutBound = StNotNull->AssumeInBound(Idx, NumElements,
false);
if (StOutBound) {
// Report warning. Make sink node manually.
- NodeTy* OOBNode =
+ ExplodedNode* OOBNode =
Builder->generateNode(Ex, StOutBound, Pred,
ProgramPoint::PostOutOfBoundsCheckFailedKind);
@@ -1223,7 +1282,8 @@ GRExprEngine::NodeTy* GRExprEngine::EvalLocation(Stmt* Ex, NodeTy* Pred,
StNotNull = StInBound;
}
}
-
+#endif
+
// Generate a new node indicating the checks succeed.
return Builder->generateNode(Ex, StNotNull, Pred,
ProgramPoint::PostLocationChecksSucceedKind);
@@ -1239,105 +1299,127 @@ GRExprEngine::NodeTy* GRExprEngine::EvalLocation(Stmt* Ex, NodeTy* Pred,
// http://developer.apple.com/documentation/Darwin/Reference/Manpages/man3
// atomic.3.html
//
-static bool EvalOSAtomicCompareAndSwap(ExplodedNodeSet<GRState>& Dst,
+static bool EvalOSAtomicCompareAndSwap(ExplodedNodeSet& Dst,
GRExprEngine& Engine,
- GRStmtNodeBuilder<GRState>& Builder,
- CallExpr* CE, SVal L,
- ExplodedNode<GRState>* Pred) {
+ GRStmtNodeBuilder& Builder,
+ CallExpr* CE, SVal L,
+ ExplodedNode* 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();
-
+ const PointerType *theValueType =
+ theValueExpr->getType()->getAs<PointerType>();
+
// 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'.
const GRState *state = Pred->getState();
- ExplodedNodeSet<GRState> Tmp;
+ ExplodedNodeSet Tmp;
SVal location = state->getSVal(theValueExpr);
Engine.EvalLoad(Tmp, theValueExpr, Pred, state, location, OSAtomicLoadTag);
- for (ExplodedNodeSet<GRState>::iterator I = Tmp.begin(), E = Tmp.end();
+ for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end();
I != E; ++I) {
-
- ExplodedNode<GRState> *N = *I;
+
+ ExplodedNode *N = *I;
const GRState *stateLoad = N->getState();
- SVal theValueVal = stateLoad->getSVal(theValueExpr);
- SVal oldValueVal = stateLoad->getSVal(oldValueExpr);
-
- // Perform the comparison.
- SVal Cmp = Engine.EvalBinOp(stateLoad, BinaryOperator::EQ, theValueVal,
- oldValueVal, Engine.getContext().IntTy);
+ SVal theValueVal_untested = stateLoad->getSVal(theValueExpr);
+ SVal oldValueVal_untested = stateLoad->getSVal(oldValueExpr);
- const GRState *stateEqual = stateLoad->assume(Cmp, true);
+ // FIXME: Issue an error.
+ if (theValueVal_untested.isUndef() || oldValueVal_untested.isUndef()) {
+ return false;
+ }
+ DefinedOrUnknownSVal theValueVal =
+ cast<DefinedOrUnknownSVal>(theValueVal_untested);
+ DefinedOrUnknownSVal oldValueVal =
+ cast<DefinedOrUnknownSVal>(oldValueVal_untested);
+
+ SValuator &SVator = Engine.getSValuator();
+
+ // Perform the comparison.
+ DefinedOrUnknownSVal Cmp = SVator.EvalEQ(stateLoad, theValueVal,
+ oldValueVal);
+
+ const GRState *stateEqual = stateLoad->Assume(Cmp, true);
+
// Were they equal?
if (stateEqual) {
// Perform the store.
- ExplodedNodeSet<GRState> TmpStore;
- Engine.EvalStore(TmpStore, theValueExpr, N, stateEqual, location,
- stateEqual->getSVal(newValueExpr), OSAtomicStoreTag);
-
+ ExplodedNodeSet TmpStore;
+ SVal val = stateEqual->getSVal(newValueExpr);
+
+ // Handle implicit value casts.
+ if (const TypedRegion *R =
+ dyn_cast_or_null<TypedRegion>(location.getAsRegion())) {
+ llvm::tie(state, val) = SVator.EvalCast(val, state, R->getValueType(C),
+ newValueExpr->getType());
+ }
+
+ Engine.EvalStore(TmpStore, theValueExpr, N, stateEqual, location,
+ val, OSAtomicStoreTag);
+
// Now bind the result of the comparison.
- for (ExplodedNodeSet<GRState>::iterator I2 = TmpStore.begin(),
+ for (ExplodedNodeSet::iterator I2 = TmpStore.begin(),
E2 = TmpStore.end(); I2 != E2; ++I2) {
- ExplodedNode<GRState> *predNew = *I2;
+ ExplodedNode *predNew = *I2;
const GRState *stateNew = predNew->getState();
SVal Res = Engine.getValueManager().makeTruthVal(true, CE->getType());
- Engine.MakeNode(Dst, CE, predNew, stateNew->bindExpr(CE, Res));
+ Engine.MakeNode(Dst, CE, predNew, stateNew->BindExpr(CE, Res));
}
}
-
+
// Were they not equal?
- if (const GRState *stateNotEqual = stateLoad->assume(Cmp, false)) {
+ if (const GRState *stateNotEqual = stateLoad->Assume(Cmp, false)) {
SVal Res = Engine.getValueManager().makeTruthVal(false, CE->getType());
- Engine.MakeNode(Dst, CE, N, stateNotEqual->bindExpr(CE, Res));
+ Engine.MakeNode(Dst, CE, N, stateNotEqual->BindExpr(CE, Res));
}
}
-
+
return true;
}
-static bool EvalOSAtomic(ExplodedNodeSet<GRState>& Dst,
+static bool EvalOSAtomic(ExplodedNodeSet& Dst,
GRExprEngine& Engine,
- GRStmtNodeBuilder<GRState>& Builder,
+ GRStmtNodeBuilder& Builder,
CallExpr* CE, SVal L,
- ExplodedNode<GRState>* Pred) {
+ ExplodedNode* 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)
@@ -1350,37 +1432,163 @@ static bool EvalOSAtomic(ExplodedNodeSet<GRState>& Dst,
//===----------------------------------------------------------------------===//
// Transfer function: Function calls.
//===----------------------------------------------------------------------===//
+static void MarkNoReturnFunction(const FunctionDecl *FD, CallExpr *CE,
+ const GRState *state,
+ GRStmtNodeBuilder *Builder) {
+ if (!FD)
+ return;
+
+ 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;
-void GRExprEngine::EvalCall(NodeSet& Dst, CallExpr* CE, SVal L, NodeTy* Pred) {
+ 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 = state->getSVal(*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;
+ }
+
+ }
+}
+
+bool GRExprEngine::EvalBuiltinFunction(const FunctionDecl *FD, CallExpr *CE,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ if (!FD)
+ return false;
+
+ unsigned id = FD->getBuiltinID();
+ if (!id)
+ return false;
+
+ const GRState *state = Pred->getState();
+
+ 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 = state->getSVal(*(CE->arg_begin()));
+ MakeNode(Dst, CE, Pred, state->BindExpr(CE, X));
+ return true;
+ }
+
+ 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 = state->getSVal(*(CE->arg_begin()));
+ state = getStoreManager().setExtent(state, R, Extent);
+ MakeNode(Dst, CE, Pred, state->BindExpr(CE, loc::MemRegionVal(R)));
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void GRExprEngine::EvalCall(ExplodedNodeSet& Dst, CallExpr* CE, SVal L,
+ ExplodedNode* 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,
+void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred,
CallExpr::arg_iterator AI,
CallExpr::arg_iterator AE,
- NodeSet& Dst)
-{
+ ExplodedNodeSet& Dst) {
// Determine the type of function we're calling (if available).
const FunctionProtoType *Proto = NULL;
QualType FnType = CE->getCallee()->IgnoreParens()->getType();
- if (const PointerType *FnTypePtr = FnType->getAsPointerType())
- Proto = FnTypePtr->getPointeeType()->getAsFunctionProtoType();
+ if (const PointerType *FnTypePtr = FnType->getAs<PointerType>())
+ Proto = FnTypePtr->getPointeeType()->getAs<FunctionProtoType>();
VisitCallRec(CE, Pred, AI, AE, Dst, Proto, /*ParamIdx=*/0);
}
-void GRExprEngine::VisitCallRec(CallExpr* CE, NodeTy* Pred,
+void GRExprEngine::VisitCallRec(CallExpr* CE, ExplodedNode* Pred,
CallExpr::arg_iterator AI,
CallExpr::arg_iterator AE,
- NodeSet& Dst, const FunctionProtoType *Proto,
+ ExplodedNodeSet& Dst,
+ const FunctionProtoType *Proto,
unsigned ParamIdx) {
-
+
// Process the arguments.
if (AI != AE) {
// If the call argument is being bound to a reference parameter,
@@ -1389,201 +1597,63 @@ void GRExprEngine::VisitCallRec(CallExpr* CE, NodeTy* Pred,
if (Proto && ParamIdx < Proto->getNumArgs())
VisitAsLvalue = Proto->getArgType(ParamIdx)->isReferenceType();
- NodeSet DstTmp;
+ ExplodedNodeSet DstTmp;
if (VisitAsLvalue)
- VisitLValue(*AI, Pred, DstTmp);
+ VisitLValue(*AI, Pred, DstTmp);
else
- Visit(*AI, Pred, DstTmp);
+ Visit(*AI, Pred, DstTmp);
++AI;
-
- for (NodeSet::iterator DI=DstTmp.begin(), DE=DstTmp.end(); DI != DE; ++DI)
+
+ for (ExplodedNodeSet::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;
+ ExplodedNodeSet DstTmp;
Expr* Callee = CE->getCallee()->IgnoreParens();
- Visit(Callee, Pred, DstTmp);
-
+ { // Enter new scope to make the lifetime of 'DstTmp2' bounded.
+ ExplodedNodeSet DstTmp2;
+ Visit(Callee, Pred, DstTmp2);
+
+ // Perform the previsit of the CallExpr, storing the results in DstTmp.
+ CheckerVisit(CE, DstTmp, DstTmp2, true);
+ }
+
// Finally, evaluate the function call.
- for (NodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end(); DI!=DE; ++DI) {
+ for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end();
+ DI != DE; ++DI) {
const GRState* state = GetState(*DI);
SVal L = state->getSVal(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 = state->getSVal(*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;
+ MarkNoReturnFunction(FD, CE, state, Builder);
- break;
- }
-
- }
- }
-
// Evaluate the call.
+ if (EvalBuiltinFunction(FD, CE, *DI, Dst))
+ continue;
- 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 = state->getSVal(*(CE->arg_begin()));
- MakeNode(Dst, CE, *DI, state->bindExpr(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 = state->getSVal(*(CE->arg_begin()));
- state = getStoreManager().setExtent(state, R, Extent);
-
- MakeNode(Dst, CE, *DI, state->bindExpr(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) {
+ // Dispatch to the plug-in transfer function.
- if (GetState(*DI)->getSVal(*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);
@@ -1597,35 +1667,38 @@ void GRExprEngine::VisitCallRec(CallExpr* CE, NodeTy* Pred,
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;
-
+void GRExprEngine::EvalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
+ Expr *Ex) {
+ for (ExplodedNodeSet::iterator I=Src.begin(), E=Src.end(); I!=E; ++I) {
+ ExplodedNode *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();
+ ProgramPoint P = Pred->getLocation();
if (!isa<PostStmt>(P) || cast<PostStmt>(P).getStmt() != Ex) {
- Dst.Add(Pred);
+ Dst.Add(Pred);
continue;
- }
+ }
- const GRState* state = Pred->getState();
- SVal V = state->getSVal(Ex);
- if (isa<nonloc::SymExprVal>(V)) {
+ const GRState* state = Pred->getState();
+ SVal V = state->getSVal(Ex);
+ if (nonloc::SymExprVal *SEV = dyn_cast<nonloc::SymExprVal>(&V)) {
// First assume that the condition is true.
- if (const GRState *stateTrue = state->assume(V, true)) {
- stateTrue = stateTrue->bindExpr(Ex,
+ if (const GRState *stateTrue = state->Assume(*SEV, true)) {
+ stateTrue = stateTrue->BindExpr(Ex,
ValMgr.makeIntVal(1U, Ex->getType()));
- Dst.Add(Builder->generateNode(PostStmtCustom(Ex, &EagerlyAssumeTag),
+ Dst.Add(Builder->generateNode(PostStmtCustom(Ex,
+ &EagerlyAssumeTag, Pred->getLocationContext()),
stateTrue, Pred));
}
-
+
// Next, assume that the condition is false.
- if (const GRState *stateFalse = state->assume(V, false)) {
- stateFalse = stateFalse->bindExpr(Ex,
+ if (const GRState *stateFalse = state->Assume(*SEV, false)) {
+ stateFalse = stateFalse->BindExpr(Ex,
ValMgr.makeIntVal(0U, Ex->getType()));
- Dst.Add(Builder->generateNode(PostStmtCustom(Ex, &EagerlyAssumeTag),
+ Dst.Add(Builder->generateNode(PostStmtCustom(Ex, &EagerlyAssumeTag,
+ Pred->getLocationContext()),
stateFalse, Pred));
}
}
@@ -1638,21 +1711,20 @@ void GRExprEngine::EvalEagerlyAssume(NodeSet &Dst, NodeSet &Src, Expr *Ex) {
// Transfer function: Objective-C ivar references.
//===----------------------------------------------------------------------===//
-void GRExprEngine::VisitObjCIvarRefExpr(ObjCIvarRefExpr* Ex,
- NodeTy* Pred, NodeSet& Dst,
- bool asLValue) {
-
+void GRExprEngine::VisitObjCIvarRefExpr(ObjCIvarRefExpr* Ex, ExplodedNode* Pred,
+ ExplodedNodeSet& Dst, bool asLValue) {
+
Expr* Base = cast<Expr>(Ex->getBase());
- NodeSet Tmp;
+ ExplodedNodeSet Tmp;
Visit(Base, Pred, Tmp);
-
- for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
+
+ for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
const GRState* state = GetState(*I);
SVal BaseVal = state->getSVal(Base);
SVal location = state->getLValue(Ex->getDecl(), BaseVal);
-
+
if (asLValue)
- MakeNode(Dst, Ex, *I, state->bindExpr(Ex, location));
+ MakeNode(Dst, Ex, *I, state->BindExpr(Ex, location));
else
EvalLoad(Dst, Ex, *I, state, location);
}
@@ -1663,8 +1735,8 @@ void GRExprEngine::VisitObjCIvarRefExpr(ObjCIvarRefExpr* Ex,
//===----------------------------------------------------------------------===//
void GRExprEngine::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S,
- NodeTy* Pred, NodeSet& Dst) {
-
+ ExplodedNode* Pred, ExplodedNodeSet& Dst) {
+
// ObjCForCollectionStmts are processed in two places. This method
// handles the case where an ObjCForCollectionStmt* occurs as one of the
// statements within a basic block. This transfer function does two things:
@@ -1676,7 +1748,7 @@ void GRExprEngine::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S,
// 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
@@ -1689,51 +1761,51 @@ void GRExprEngine::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S,
// 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 = GetState(Pred)->getLValue(ElemD);
+ ElementV = GetState(Pred)->getLValue(ElemD, Pred->getLocationContext());
VisitObjCForCollectionStmtAux(S, Pred, Dst, ElementV);
return;
}
- NodeSet Tmp;
+ ExplodedNodeSet Tmp;
VisitLValue(cast<Expr>(elem), Pred, Tmp);
-
- for (NodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I!=E; ++I) {
+
+ for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I!=E; ++I) {
const GRState* state = GetState(*I);
VisitObjCForCollectionStmtAux(S, *I, Dst, state->getSVal(elem));
}
}
void GRExprEngine::VisitObjCForCollectionStmtAux(ObjCForCollectionStmt* S,
- NodeTy* Pred, NodeSet& Dst,
+ ExplodedNode* Pred, ExplodedNodeSet& 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;
-
+
const GRState *state = GetState(Pred);
// Handle the case where the container still has elements.
SVal TrueV = ValMgr.makeTruthVal(1);
- const GRState *hasElems = state->bindExpr(S, TrueV);
-
+ const GRState *hasElems = state->BindExpr(S, TrueV);
+
// Handle the case where the container has no elements.
SVal FalseV = ValMgr.makeTruthVal(0);
- const GRState *noElems = state->bindExpr(S, FalseV);
-
+ const GRState *noElems = state->BindExpr(S, FalseV);
+
if (loc::MemRegionVal* MV = dyn_cast<loc::MemRegionVal>(&ElementV))
if (const TypedRegion* R = dyn_cast<TypedRegion>(MV->getRegion())) {
// FIXME: The proper thing to do is to really iterate over the
@@ -1747,10 +1819,10 @@ void GRExprEngine::VisitObjCForCollectionStmtAux(ObjCForCollectionStmt* S,
hasElems = hasElems->bindLoc(ElementV, V);
// Bind the location to 'nil' on the false branch.
- SVal nilV = ValMgr.makeIntVal(0, T);
- noElems = noElems->bindLoc(ElementV, nilV);
+ SVal nilV = ValMgr.makeIntVal(0, T);
+ noElems = noElems->bindLoc(ElementV, nilV);
}
-
+
// Create the new nodes.
MakeNode(Dst, S, Pred, hasElems);
MakeNode(Dst, S, Pred, noElems);
@@ -1760,113 +1832,115 @@ void GRExprEngine::VisitObjCForCollectionStmtAux(ObjCForCollectionStmt* S,
// Transfer function: Objective-C message expressions.
//===----------------------------------------------------------------------===//
-void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, NodeTy* Pred,
- NodeSet& Dst){
-
+void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred,
+ ExplodedNodeSet& 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) {
+ ExplodedNode* Pred, ExplodedNodeSet& Dst) {
if (AI == AE) {
-
+
// Process the receiver.
-
+
if (Expr* Receiver = ME->getReceiver()) {
- NodeSet Tmp;
+ ExplodedNodeSet Tmp;
Visit(Receiver, Pred, Tmp);
-
- for (NodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI != NE; ++NI)
+
+ for (ExplodedNodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI != NE;
+ ++NI)
VisitObjCMessageExprDispatchHelper(ME, *NI, Dst);
-
+
return;
}
-
+
VisitObjCMessageExprDispatchHelper(ME, Pred, Dst);
return;
}
-
- NodeSet Tmp;
+
+ ExplodedNodeSet Tmp;
Visit(*AI, Pred, Tmp);
-
+
++AI;
-
- for (NodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI != NE; ++NI)
+
+ for (ExplodedNodeSet::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.
-
+ ExplodedNode* Pred,
+ ExplodedNodeSet& 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 = state->getSVal(Receiver);
-
- // Check for undefined control-flow.
- if (L.isUndef()) {
- NodeTy* N = Builder->generateNode(ME, state, Pred);
-
+
+ SVal L_untested = state->getSVal(Receiver);
+
+ // Check for undefined control-flow.
+ if (L_untested.isUndef()) {
+ ExplodedNode* N = Builder->generateNode(ME, state, Pred);
+
if (N) {
N->markAsSink();
UndefReceivers.insert(N);
}
-
+
return;
}
-
- // "Assume" that the receiver is not NULL.
- const GRState *StNotNull = state->assume(L, true);
-
- // "Assume" that the receiver is NULL.
- const GRState *StNull = state->assume(L, false);
-
+
+ // "Assume" that the receiver is not NULL.
+ DefinedOrUnknownSVal L = cast<DefinedOrUnknownSVal>(L_untested);
+ const GRState *StNotNull = state->Assume(L, true);
+
+ // "Assume" that the receiver is NULL.
+ const GRState *StNull = state->Assume(L, false);
+
if (StNull) {
QualType RetTy = ME->getType();
-
+
// Check if the receiver was nil and the return value a struct.
- if(RetTy->isRecordType()) {
- if (BR.getParentMap().isConsumedExpr(ME)) {
+ if (RetTy->isRecordType()) {
+ if (Pred->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)) {
+ // garbage.
+ if (ExplodedNode* N = Builder->generateNode(ME, StNull, Pred)) {
N->markAsSink();
if (StNotNull)
NilReceiverStructRetImplicit.insert(N);
else
- NilReceiverStructRetExplicit.insert(N);
+ NilReceiverStructRetExplicit.insert(N);
}
}
}
else {
ASTContext& Ctx = getContext();
if (RetTy != Ctx.VoidTy) {
- if (BR.getParentMap().isConsumedExpr(ME)) {
+ if (Pred->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)) {
+ if (voidPtrSize < returnTypeSize) {
+ if (ExplodedNode* N = Builder->generateNode(ME, StNull, Pred)) {
N->markAsSink();
- if(StNotNull)
+ if (StNotNull)
NilReceiverLargerThanVoidPtrRetImplicit.insert(N);
else
- NilReceiverLargerThanVoidPtrRetExplicit.insert(N);
+ NilReceiverLargerThanVoidPtrRetExplicit.insert(N);
}
}
else if (!StNotNull) {
@@ -1884,7 +1958,7 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
// of this case unless we have *a lot* more knowledge.
//
SVal V = ValMgr.makeZeroVal(ME->getType());
- MakeNode(Dst, ME, Pred, StNull->bindExpr(ME, V));
+ MakeNode(Dst, ME, Pred, StNull->BindExpr(ME, V));
return;
}
}
@@ -1894,99 +1968,99 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
// 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) {
+
+ 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:
+
+ // raise:format:
II.push_back(&Ctx.Idents.get("raise"));
- II.push_back(&Ctx.Idents.get("format"));
+ II.push_back(&Ctx.Idents.get("format"));
NSExceptionInstanceRaiseSelectors[idx++] =
- Ctx.Selectors.getSelector(II.size(), &II[0]);
-
- // raise:format::arguments:
+ 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 (state->getSVal(*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);
-
+ ExplodedNode* 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);
}
@@ -1995,24 +2069,8 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
// 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, state->bindExpr(CastE, EvalCast(cast<Loc>(V),
- CastE->getType())));
- }
- else
- MakeNode(Dst, CastE, Pred, state->bindExpr(CastE, V));
-}
-
-
-void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, NodeTy* Pred, NodeSet& Dst){
- NodeSet S1;
+void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred, ExplodedNodeSet& Dst){
+ ExplodedNodeSet S1;
QualType T = CastE->getType();
QualType ExTy = Ex->getType();
@@ -2023,180 +2081,67 @@ void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, NodeTy* Pred, NodeSet& Dst){
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)
+ if (T->isVoidType()) {
+ for (ExplodedNodeSet::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;
+
+ for (ExplodedNodeSet::iterator I1 = S1.begin(), E1 = S1.end(); I1 != E1; ++I1) {
+ ExplodedNode* N = *I1;
const GRState* state = GetState(N);
SVal V = state->getSVal(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, state->bindExpr(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, Res.getState()->bindExpr(CastE, V));
- continue;
- }
- // All other cases.
- DispatchCast: {
- MakeNode(Dst, CastE, N, state->bindExpr(CastE,
- EvalCast(V, CastE->getType())));
- continue;
- }
-
- PassThrough: {
- MakeNode(Dst, CastE, N, state->bindExpr(CastE, V));
- }
+ const SValuator::CastResult &Res = SVator.EvalCast(V, state, T, ExTy);
+ state = Res.getState()->BindExpr(CastE, Res.getSVal());
+ MakeNode(Dst, CastE, N, state);
}
}
void GRExprEngine::VisitCompoundLiteralExpr(CompoundLiteralExpr* CL,
- NodeTy* Pred, NodeSet& Dst,
+ ExplodedNode* Pred,
+ ExplodedNodeSet& Dst,
bool asLValue) {
InitListExpr* ILE = cast<InitListExpr>(CL->getInitializer()->IgnoreParens());
- NodeSet Tmp;
+ ExplodedNodeSet Tmp;
Visit(ILE, Pred, Tmp);
-
- for (NodeSet::iterator I = Tmp.begin(), EI = Tmp.end(); I!=EI; ++I) {
+
+ for (ExplodedNodeSet::iterator I = Tmp.begin(), EI = Tmp.end(); I!=EI; ++I) {
const GRState* state = GetState(*I);
SVal ILV = state->getSVal(ILE);
state = state->bindCompoundLiteral(CL, ILV);
if (asLValue)
- MakeNode(Dst, CL, *I, state->bindExpr(CL, state->getLValue(CL)));
+ MakeNode(Dst, CL, *I, state->BindExpr(CL, state->getLValue(CL)));
else
- MakeNode(Dst, CL, *I, state->bindExpr(CL, ILV));
+ MakeNode(Dst, CL, *I, state->BindExpr(CL, ILV));
}
}
-void GRExprEngine::VisitDeclStmt(DeclStmt* DS, NodeTy* Pred, NodeSet& Dst) {
+void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred,
+ ExplodedNodeSet& Dst) {
- // The CFG has one DeclStmt per Decl.
+ // 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);
+
+ 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;
+ ExplodedNodeSet Tmp;
if (InitEx)
Visit(InitEx, Pred, Tmp);
-
- if (Tmp.empty())
+ else
Tmp.Add(Pred);
-
- for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
+
+ for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
const GRState* state = GetState(*I);
unsigned Count = Builder->getCurrentBlockCount();
@@ -2204,58 +2149,61 @@ void GRExprEngine::VisitDeclStmt(DeclStmt* DS, NodeTy* Pred, NodeSet& Dst) {
QualType T = getContext().getCanonicalType(VD->getType());
if (VariableArrayType* VLA = dyn_cast<VariableArrayType>(T)) {
// FIXME: Handle multi-dimensional VLAs.
-
+
Expr* SE = VLA->getSizeExpr();
- SVal Size = state->getSVal(SE);
-
- if (Size.isUndef()) {
- if (NodeTy* N = Builder->generateNode(DS, state, Pred)) {
- N->markAsSink();
+ SVal Size_untested = state->getSVal(SE);
+
+ if (Size_untested.isUndef()) {
+ if (ExplodedNode* N = Builder->generateNode(DS, state, Pred)) {
+ N->markAsSink();
ExplicitBadSizedVLA.insert(N);
}
continue;
}
-
- const GRState* zeroState = state->assume(Size, false);
- state = state->assume(Size, true);
-
+
+ DefinedOrUnknownSVal Size = cast<DefinedOrUnknownSVal>(Size_untested);
+ const GRState *zeroState = state->Assume(Size, false);
+ state = state->Assume(Size, true);
+
if (zeroState) {
- if (NodeTy* N = Builder->generateNode(DS, zeroState, Pred)) {
- N->markAsSink();
+ if (ExplodedNode* N = Builder->generateNode(DS, zeroState, Pred)) {
+ N->markAsSink();
if (state)
ImplicitBadSizedVLA.insert(N);
else
ExplicitBadSizedVLA.insert(N);
}
}
-
+
if (!state)
- continue;
+ continue;
}
-
+
// Decls without InitExpr are not initialized explicitly.
+ const LocationContext *LC = (*I)->getLocationContext();
+
if (InitEx) {
SVal InitVal = state->getSVal(InitEx);
QualType T = VD->getType();
-
+
// Recover some path-sensitivity if a scalar value evaluated to
// UnknownVal.
- if (InitVal.isUnknown() ||
+ if (InitVal.isUnknown() ||
!getConstraintManager().canReasonAbout(InitVal)) {
- InitVal = ValMgr.getConjuredSymbolVal(InitEx, Count);
- }
-
- state = state->bindDecl(VD, InitVal);
-
+ InitVal = ValMgr.getConjuredSymbolVal(NULL, InitEx, Count);
+ }
+
+ state = state->bindDecl(VD, LC, 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(state->getRegion(VD)),
- InitVal);
- }
+ getTF().EvalBind(BuilderRef, loc::MemRegionVal(state->getRegion(VD, LC)),
+ InitVal);
+ }
else {
- state = state->bindDeclWithNoInit(VD);
+ state = state->bindDeclWithNoInit(VD, LC);
MakeNode(Dst, DS, *I, state);
}
}
@@ -2267,67 +2215,69 @@ namespace {
class VISIBILITY_HIDDEN InitListWLItem {
public:
llvm::ImmutableList<SVal> Vals;
- GRExprEngine::NodeTy* N;
+ ExplodedNode* N;
InitListExpr::reverse_iterator Itr;
-
- InitListWLItem(GRExprEngine::NodeTy* n, llvm::ImmutableList<SVal> vals,
- InitListExpr::reverse_iterator itr)
+
+ InitListWLItem(ExplodedNode* n, llvm::ImmutableList<SVal> vals,
+ InitListExpr::reverse_iterator itr)
: Vals(vals), N(n), Itr(itr) {}
};
}
-void GRExprEngine::VisitInitListExpr(InitListExpr* E, NodeTy* Pred,
- NodeSet& Dst) {
+void GRExprEngine::VisitInitListExpr(InitListExpr* E, ExplodedNode* Pred,
+ ExplodedNodeSet& Dst) {
const GRState* state = GetState(Pred);
QualType T = getContext().getCanonicalType(E->getType());
- unsigned NumInitElements = E->getNumInits();
+ unsigned NumInitElements = E->getNumInits();
- if (T->isArrayType() || T->isStructureType()) {
+ if (T->isArrayType() || T->isStructureType() ||
+ T->isUnionType() || T->isVectorType()) {
llvm::ImmutableList<SVal> StartVals = getBasicVals().getEmptySValList();
-
+
// Handle base case where the initializer has no elements.
// e.g: static int* myArray[] = {};
if (NumInitElements == 0) {
SVal V = ValMgr.makeCompoundVal(T, StartVals);
- MakeNode(Dst, E, Pred, state->bindExpr(E, V));
+ MakeNode(Dst, E, Pred, state->BindExpr(E, V));
return;
- }
-
+ }
+
// Create a worklist to process the initializers.
llvm::SmallVector<InitListWLItem, 10> WorkList;
- WorkList.reserve(NumInitElements);
- WorkList.push_back(InitListWLItem(Pred, StartVals, E->rbegin()));
+ WorkList.reserve(NumInitElements);
+ WorkList.push_back(InitListWLItem(Pred, StartVals, E->rbegin()));
InitListExpr::reverse_iterator ItrEnd = E->rend();
-
+ assert(!(E->rbegin() == E->rend()));
+
// Process the worklist until it is empty.
while (!WorkList.empty()) {
InitListWLItem X = WorkList.back();
WorkList.pop_back();
-
- NodeSet Tmp;
+
+ ExplodedNodeSet 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) {
+ for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) {
// Get the last initializer value.
state = GetState(*NI);
SVal InitV = state->getSVal(cast<Expr>(*X.Itr));
-
+
// Construct the new list of values by prepending the new value to
// the already constructed list.
llvm::ImmutableList<SVal> NewVals =
getBasicVals().consVals(InitV, X.Vals);
-
+
if (NewItr == ItrEnd) {
// Now we have a list holding all init values. Make CompoundValData.
SVal V = ValMgr.makeCompoundVal(T, NewVals);
// Make final state and node.
- MakeNode(Dst, E, *NI, state->bindExpr(E, V));
+ MakeNode(Dst, E, *NI, state->BindExpr(E, V));
}
else {
// Still some initializer values to go. Push them onto the worklist.
@@ -2335,25 +2285,18 @@ void GRExprEngine::VisitInitListExpr(InitListExpr* E, NodeTy* Pred,
}
}
}
-
- 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;
+ ExplodedNodeSet Tmp;
Expr* Init = E->getInit(0);
Visit(Init, Pred, Tmp);
- for (NodeSet::iterator I = Tmp.begin(), EI = Tmp.end(); I != EI; ++I) {
+ for (ExplodedNodeSet::iterator I = Tmp.begin(), EI = Tmp.end(); I != EI; ++I) {
state = GetState(*I);
- MakeNode(Dst, E, *I, state->bindExpr(E, state->getSVal(Init)));
+ MakeNode(Dst, E, *I, state->BindExpr(E, state->getSVal(Init)));
}
return;
}
@@ -2365,13 +2308,13 @@ void GRExprEngine::VisitInitListExpr(InitListExpr* E, NodeTy* Pred,
/// VisitSizeOfAlignOfExpr - Transfer function for sizeof(type).
void GRExprEngine::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex,
- NodeTy* Pred,
- NodeSet& Dst) {
+ ExplodedNode* Pred,
+ ExplodedNodeSet& Dst) {
QualType T = Ex->getTypeOfArgument();
- uint64_t amt;
-
+ uint64_t amt;
+
if (Ex->isSizeOf()) {
- if (T == getContext().VoidTy) {
+ if (T == getContext().VoidTy) {
// sizeof(void) == 1 byte.
amt = 1;
}
@@ -2382,195 +2325,206 @@ void GRExprEngine::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex,
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.
+ // 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,
- GetState(Pred)->bindExpr(Ex, ValMgr.makeIntVal(amt, Ex->getType())));
+ GetState(Pred)->BindExpr(Ex, ValMgr.makeIntVal(amt, Ex->getType())));
}
-void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, NodeTy* Pred,
- NodeSet& Dst, bool asLValue) {
+void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred,
+ ExplodedNodeSet& Dst, bool asLValue) {
switch (U->getOpcode()) {
-
+
default:
break;
-
+
case UnaryOperator::Deref: {
-
+
Expr* Ex = U->getSubExpr()->IgnoreParens();
- NodeSet Tmp;
+ ExplodedNodeSet Tmp;
Visit(Ex, Pred, Tmp);
-
- for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
-
+
+ for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
+
const GRState* state = GetState(*I);
SVal location = state->getSVal(Ex);
-
+
if (asLValue)
- MakeNode(Dst, U, *I, state->bindExpr(U, location),
+ MakeNode(Dst, U, *I, state->BindExpr(U, location),
ProgramPoint::PostLValueKind);
else
EvalLoad(Dst, U, *I, state, location);
- }
+ }
return;
}
-
+
case UnaryOperator::Real: {
-
+
Expr* Ex = U->getSubExpr()->IgnoreParens();
- NodeSet Tmp;
+ ExplodedNodeSet Tmp;
Visit(Ex, Pred, Tmp);
-
- for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
-
+
+ for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
+
// FIXME: We don't have complex SValues yet.
if (Ex->getType()->isAnyComplexType()) {
// Just report "Unknown."
Dst.Add(*I);
continue;
}
-
+
// For all other types, UnaryOperator::Real is an identity operation.
assert (U->getType() == Ex->getType());
const GRState* state = GetState(*I);
- MakeNode(Dst, U, *I, state->bindExpr(U, state->getSVal(Ex)));
- }
-
+ MakeNode(Dst, U, *I, state->BindExpr(U, state->getSVal(Ex)));
+ }
+
return;
}
-
+
case UnaryOperator::Imag: {
-
+
Expr* Ex = U->getSubExpr()->IgnoreParens();
- NodeSet Tmp;
+ ExplodedNodeSet Tmp;
Visit(Ex, Pred, Tmp);
-
- for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
+
+ for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
// FIXME: We don't have complex SValues yet.
if (Ex->getType()->isAnyComplexType()) {
// Just report "Unknown."
Dst.Add(*I);
continue;
}
-
+
// For all other types, UnaryOperator::Float returns 0.
assert (Ex->getType()->isIntegerType());
const GRState* state = GetState(*I);
SVal X = ValMgr.makeZeroVal(Ex->getType());
- MakeNode(Dst, U, *I, state->bindExpr(U, X));
+ MakeNode(Dst, U, *I, state->BindExpr(U, X));
}
-
+
return;
}
-
- // FIXME: Just report "Unknown" for OffsetOf.
- case UnaryOperator::OffsetOf:
+
+ case UnaryOperator::OffsetOf: {
+ Expr::EvalResult Res;
+ if (U->Evaluate(Res, getContext()) && Res.Val.isInt()) {
+ const APSInt &IV = Res.Val.getInt();
+ assert(IV.getBitWidth() == getContext().getTypeSize(U->getType()));
+ assert(U->getType()->isIntegerType());
+ assert(IV.isSigned() == U->getType()->isSignedIntegerType());
+ SVal X = ValMgr.makeIntVal(IV);
+ MakeNode(Dst, U, Pred, GetState(Pred)->BindExpr(U, X));
+ return;
+ }
+ // FIXME: Handle the case where __builtin_offsetof is not a constant.
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;
+ ExplodedNodeSet Tmp;
Visit(Ex, Pred, Tmp);
-
- for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
+
+ for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
const GRState* state = GetState(*I);
- MakeNode(Dst, U, *I, state->bindExpr(U, state->getSVal(Ex)));
+ MakeNode(Dst, U, *I, state->BindExpr(U, state->getSVal(Ex)));
}
-
+
return;
}
-
+
case UnaryOperator::AddrOf: {
-
+
assert(!asLValue);
Expr* Ex = U->getSubExpr()->IgnoreParens();
- NodeSet Tmp;
+ ExplodedNodeSet Tmp;
VisitLValue(Ex, Pred, Tmp);
-
- for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
+
+ for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
const GRState* state = GetState(*I);
SVal V = state->getSVal(Ex);
- state = state->bindExpr(U, V);
+ state = state->BindExpr(U, V);
MakeNode(Dst, U, *I, state);
}
- return;
+ return;
}
-
+
case UnaryOperator::LNot:
case UnaryOperator::Minus:
case UnaryOperator::Not: {
-
+
assert (!asLValue);
Expr* Ex = U->getSubExpr()->IgnoreParens();
- NodeSet Tmp;
+ ExplodedNodeSet Tmp;
Visit(Ex, Pred, Tmp);
-
- for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
+
+ for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
const GRState* state = GetState(*I);
-
+
// Get the value of the subexpression.
SVal V = state->getSVal(Ex);
if (V.isUnknownOrUndef()) {
- MakeNode(Dst, U, *I, state->bindExpr(U, V));
+ MakeNode(Dst, U, *I, state->BindExpr(U, V));
continue;
}
-
+
// QualType DstT = getContext().getCanonicalType(U->getType());
// QualType SrcT = getContext().getCanonicalType(Ex->getType());
-//
+//
// if (DstT != SrcT) // Perform promotions.
-// V = EvalCast(V, DstT);
-//
+// 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 = state->bindExpr(U, EvalComplement(cast<NonLoc>(V)));
- break;
-
+ state = state->BindExpr(U, EvalComplement(cast<NonLoc>(V)));
+ break;
+
case UnaryOperator::Minus:
// FIXME: Do we need to handle promotions?
- state = state->bindExpr(U, EvalMinus(cast<NonLoc>(V)));
- break;
-
- case UnaryOperator::LNot:
-
+ state = state->BindExpr(U, EvalMinus(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".
SVal Result;
-
+
if (isa<Loc>(V)) {
Loc X = ValMgr.makeNull();
Result = EvalBinOp(state, BinaryOperator::EQ, cast<Loc>(V), X,
@@ -2578,18 +2532,18 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, NodeTy* Pred,
}
else {
nonloc::ConcreteInt X(getBasicVals().getValue(0, Ex->getType()));
- Result = EvalBinOp(BinaryOperator::EQ, cast<NonLoc>(V), X,
+ Result = EvalBinOp(state, BinaryOperator::EQ, cast<NonLoc>(V), X,
U->getType());
}
-
- state = state->bindExpr(U, Result);
-
+
+ state = state->BindExpr(U, Result);
+
break;
}
-
+
MakeNode(Dst, U, *I, state);
}
-
+
return;
}
}
@@ -2597,170 +2551,183 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, NodeTy* Pred,
// Handle ++ and -- (both pre- and post-increment).
assert (U->isIncrementDecrementOp());
- NodeSet Tmp;
+ ExplodedNodeSet Tmp;
Expr* Ex = U->getSubExpr()->IgnoreParens();
VisitLValue(Ex, Pred, Tmp);
-
- for (NodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I!=E; ++I) {
-
+
+ for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I!=E; ++I) {
+
const GRState* state = GetState(*I);
SVal V1 = state->getSVal(Ex);
-
- // Perform a load.
- NodeSet Tmp2;
+
+ // Perform a load.
+ ExplodedNodeSet Tmp2;
EvalLoad(Tmp2, Ex, *I, state, V1);
- for (NodeSet::iterator I2 = Tmp2.begin(), E2 = Tmp2.end(); I2!=E2; ++I2) {
-
+ for (ExplodedNodeSet::iterator I2 = Tmp2.begin(), E2 = Tmp2.end(); I2!=E2; ++I2) {
+
state = GetState(*I2);
- SVal V2 = state->getSVal(Ex);
-
- // Propagate unknown and undefined values.
- if (V2.isUnknownOrUndef()) {
- MakeNode(Dst, U, *I2, state->bindExpr(U, V2));
+ SVal V2_untested = state->getSVal(Ex);
+
+ // Propagate unknown and undefined values.
+ if (V2_untested.isUnknownOrUndef()) {
+ MakeNode(Dst, U, *I2, state->BindExpr(U, V2_untested));
continue;
- }
-
- // Handle all other values.
+ }
+ DefinedSVal V2 = cast<DefinedSVal>(V2_untested);
+
+ // Handle all other values.
BinaryOperator::Opcode Op = U->isIncrementOp() ? BinaryOperator::Add
: BinaryOperator::Sub;
- SVal Result = EvalBinOp(state, Op, V2, ValMgr.makeIntVal(1U,U->getType()),
- U->getType());
-
+ // If the UnaryOperator has non-location type, use its type to create the
+ // constant value. If the UnaryOperator has location type, create the
+ // constant with int type and pointer width.
+ SVal RHS;
+
+ if (U->getType()->isAnyPointerType())
+ RHS = ValMgr.makeIntValWithPtrWidth(1, false);
+ else
+ RHS = ValMgr.makeIntVal(1, U->getType());
+
+ SVal Result = EvalBinOp(state, Op, V2, RHS, U->getType());
+
// Conjure a new symbol if necessary to recover precision.
if (Result.isUnknown() || !getConstraintManager().canReasonAbout(Result)){
- Result = ValMgr.getConjuredSymbolVal(Ex,
- Builder->getCurrentBlockCount());
-
+ DefinedOrUnknownSVal SymVal =
+ ValMgr.getConjuredSymbolVal(NULL, Ex,
+ Builder->getCurrentBlockCount());
+ Result = SymVal;
+
// If the value is a location, ++/-- should always preserve
// non-nullness. Check if the original value was non-null, and if so
- // propagate that constraint.
+ // propagate that constraint.
if (Loc::IsLocType(U->getType())) {
- SVal Constraint = EvalBinOp(state, BinaryOperator::EQ, V2,
- ValMgr.makeZeroVal(U->getType()),
- getContext().IntTy);
-
- if (!state->assume(Constraint, true)) {
+ DefinedOrUnknownSVal Constraint =
+ SVator.EvalEQ(state, V2, ValMgr.makeZeroVal(U->getType()));
+
+ if (!state->Assume(Constraint, true)) {
// 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);
-
- state = state->assume(Constraint, false);
+ Constraint = SVator.EvalEQ(state, SymVal,
+ ValMgr.makeZeroVal(U->getType()));
+
+
+ state = state->Assume(Constraint, false);
assert(state);
- }
- }
+ }
+ }
}
-
- state = state->bindExpr(U, U->isPostfix() ? V2 : Result);
- // Perform the store.
+ state = state->BindExpr(U, U->isPostfix() ? V2 : Result);
+
+ // Perform the store.
EvalStore(Dst, U, *I2, state, V1, Result);
}
}
}
-void GRExprEngine::VisitAsmStmt(AsmStmt* A, NodeTy* Pred, NodeSet& Dst) {
+void GRExprEngine::VisitAsmStmt(AsmStmt* A, ExplodedNode* Pred, ExplodedNodeSet& 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) {
+ ExplodedNode* Pred, ExplodedNodeSet& Dst) {
if (I == E) {
VisitAsmStmtHelperInputs(A, A->begin_inputs(), A->end_inputs(), Pred, Dst);
return;
}
-
- NodeSet Tmp;
+
+ ExplodedNodeSet Tmp;
VisitLValue(*I, Pred, Tmp);
-
+
++I;
-
- for (NodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI != NE; ++NI)
+
+ for (ExplodedNodeSet::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) {
+ ExplodedNode* Pred, ExplodedNodeSet& 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 = state->getSVal(*OI);
+
+ SVal X = state->getSVal(*OI);
assert (!isa<NonLoc>(X)); // Should be an Lval, or unknown, undef.
-
+
if (isa<Loc>(X))
state = state->bindLoc(cast<Loc>(X), UnknownVal());
}
-
+
MakeNode(Dst, A, Pred, state);
return;
}
-
- NodeSet Tmp;
+
+ ExplodedNodeSet Tmp;
Visit(*I, Pred, Tmp);
-
+
++I;
-
- for (NodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI != NE; ++NI)
+
+ for (ExplodedNodeSet::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) {
+void GRExprEngine::EvalReturn(ExplodedNodeSet& Dst, ReturnStmt* S,
+ ExplodedNode* Pred) {
assert (Builder && "GRStmtNodeBuilder must be defined.");
-
- unsigned size = Dst.size();
+
+ 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) {
+void GRExprEngine::VisitReturnStmt(ReturnStmt* S, ExplodedNode* Pred,
+ ExplodedNodeSet& Dst) {
Expr* R = S->getRetValue();
-
+
if (!R) {
EvalReturn(Dst, S, Pred);
return;
}
- NodeSet Tmp;
+ ExplodedNodeSet Tmp;
Visit(R, Pred, Tmp);
- for (NodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) {
+ for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) {
SVal X = (*I)->getState()->getSVal(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 && R->hasStackStorage()) {
// Create a special node representing the error.
- if (NodeTy* N = Builder->generateNode(S, GetState(*I), *I)) {
+ if (ExplodedNode* N = Builder->generateNode(S, GetState(*I), *I)) {
N->markAsSink();
RetsStackAddr.insert(N);
}
@@ -2769,13 +2736,13 @@ void GRExprEngine::VisitReturnStmt(ReturnStmt* S, NodeTy* Pred, NodeSet& Dst) {
}
// Check if we return an undefined value.
else if (X.isUndef()) {
- if (NodeTy* N = Builder->generateNode(S, GetState(*I), *I)) {
+ if (ExplodedNode* N = Builder->generateNode(S, GetState(*I), *I)) {
N->markAsSink();
RetsUndef.insert(N);
}
continue;
}
-
+
EvalReturn(Dst, S, *I);
}
}
@@ -2784,127 +2751,76 @@ void GRExprEngine::VisitReturnStmt(ReturnStmt* S, NodeTy* Pred, NodeSet& Dst) {
// 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.
- const GRState* zeroState = state->assume(Denom, false);
-
- // Second, "assume" that the denominator cannot be 0.
- state = state->assume(Denom, true);
-
- // Create the node for the divide-by-zero (if it occurred).
- if (zeroState)
- if (NodeTy* DivZeroNode = Builder->generateNode(Ex, zeroState, Pred)) {
- DivZeroNode->markAsSink();
-
- if (state)
- ImplicitBadDivides.insert(DivZeroNode);
- else
- ExplicitBadDivides.insert(DivZeroNode);
-
- }
-
- return state;
-}
-
void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
- GRExprEngine::NodeTy* Pred,
- GRExprEngine::NodeSet& Dst) {
+ ExplodedNode* Pred,
+ ExplodedNodeSet& Dst) {
- NodeSet Tmp1;
+ ExplodedNodeSet 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);
+
+ // FIXME: Add proper support for ObjCImplicitSetterGetterRefExpr.
+ if (isa<ObjCImplicitSetterGetterRefExpr>(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) {
-
+ for (ExplodedNodeSet::iterator I1=Tmp1.begin(), E1=Tmp1.end(); I1!=E1; ++I1) {
SVal LeftV = (*I1)->getState()->getSVal(LHS);
-
- // Process the RHS.
-
- NodeSet Tmp2;
+ ExplodedNodeSet Tmp2;
Visit(RHS, *I1, Tmp2);
-
+
+ ExplodedNodeSet CheckedSet;
+ CheckerVisit(B, CheckedSet, Tmp2, true);
+
// 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;
+ for (ExplodedNodeSet::iterator I2=CheckedSet.begin(), E2=CheckedSet.end();
+ I2 != E2; ++I2) {
+ const GRState *state = GetState(*I2);
+ const GRState *OldSt = state;
SVal RightV = state->getSVal(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) ||
+
+ if ((RightV.isUnknown() ||
+ !getConstraintManager().canReasonAbout(RightV))
+ && (Loc::IsLocType(T) ||
(T->isScalarType() && T->isIntegerType()))) {
- unsigned Count = Builder->getCurrentBlockCount();
- RightV = ValMgr.getConjuredSymbolVal(B->getRHS(), Count);
+ unsigned Count = Builder->getCurrentBlockCount();
+ RightV = ValMgr.getConjuredSymbolVal(NULL, B->getRHS(), Count);
}
-
+
// Simulate the effects of a "store": bind the value of the RHS
- // to the L-Value represented by the LHS.
- EvalStore(Dst, B, LHS, *I2, state->bindExpr(B, RightV), LeftV,
- RightV);
+ // to the L-Value represented by the LHS.
+ EvalStore(Dst, B, LHS, *I2, state->BindExpr(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-assignments except commas or short-circuited
- // logical expressions (LAnd and LOr).
+ // 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.
@@ -2912,30 +2828,28 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
}
else
Dst.Add(*I2);
-
+
continue;
}
-
- if (Result.isUndef() && !LeftV.isUndef() && !RightV.isUndef()) {
-
+
+ state = state->BindExpr(B, Result);
+
+ if (Result.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();
+ if (ExplodedNode *UndefNode = Builder->generateNode(B, state, *I2)){
+ UndefNode->markAsSink();
UndefResults.insert(UndefNode);
}
-
continue;
}
-
+
// Otherwise, create a new node.
-
- MakeNode(Dst, B, *I2, state->bindExpr(B, Result));
+ MakeNode(Dst, B, *I2, state);
continue;
}
}
-
+
assert (B->isCompoundAssignmentOp());
switch (Op) {
@@ -2952,78 +2866,44 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
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;
+ ExplodedNodeSet Tmp3;
SVal location = state->getSVal(LHS);
EvalLoad(Tmp3, LHS, *I2, state, location);
-
- for (NodeSet::iterator I3=Tmp3.begin(), E3=Tmp3.end(); I3!=E3; ++I3) {
-
+
+ for (ExplodedNodeSet::iterator I3=Tmp3.begin(), E3=Tmp3.end(); I3!=E3;
+ ++I3) {
+
state = GetState(*I3);
SVal V = state->getSVal(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, state->bindExpr(B, V), location, V);
- continue;
- }
-
- // Propagate unknown values (left and right-side).
- if (RightV.isUnknown() || V.isUnknown()) {
- EvalStore(Dst, B, LHS, *I3, state->bindExpr(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();
+ QualType CTy =
+ cast<CompoundAssignOperator>(B)->getComputationResultType();
CTy = getContext().getCanonicalType(CTy);
- QualType CLHSTy = cast<CompoundAssignOperator>(B)->getComputationLHSType();
- CLHSTy = getContext().getCanonicalType(CTy);
+ QualType CLHSTy =
+ cast<CompoundAssignOperator>(B)->getComputationLHSType();
+ CLHSTy = getContext().getCanonicalType(CLHSTy);
QualType LTy = getContext().getCanonicalType(LHS->getType());
QualType RTy = getContext().getCanonicalType(RHS->getType());
// Promote LHS.
- V = EvalCast(V, CLHSTy);
+ llvm::tie(state, V) = SVator.EvalCast(V, state, CLHSTy, LTy);
+
+ // Compute the result of the operation.
+ SVal Result;
+ llvm::tie(state, Result) = SVator.EvalCast(EvalBinOp(state, Op, V,
+ RightV, CTy),
+ state, B->getType(), CTy);
- // Evaluate operands and promote to result type.
- if (RightV.isUndef()) {
- // Propagate undefined values (right-side).
- EvalStore(Dst, B, LHS, *I3, state->bindExpr(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();
+ if (ExplodedNode* UndefNode = Builder->generateNode(B, state, *I3)) {
+ UndefNode->markAsSink();
UndefResults.insert(UndefNode);
}
continue;
@@ -3031,71 +2911,38 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
// EXPERIMENTAL: "Conjured" symbols.
// FIXME: Handle structs.
-
+
SVal LHSVal;
-
- if ((Result.isUnknown() ||
+
+ if ((Result.isUnknown() ||
!getConstraintManager().canReasonAbout(Result))
- && (Loc::IsLocType(CTy)
+ && (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);
-
+ LHSVal = ValMgr.getConjuredSymbolVal(NULL, B->getRHS(), LTy, Count);
+
// However, we need to convert the symbol to the computation type.
- Result = (LTy == CTy) ? LHSVal : EvalCast(LHSVal,CTy);
+ llvm::tie(state, Result) = SVator.EvalCast(LHSVal, state, CTy, LTy);
}
else {
// The left-hand side may bind to a different value then the
// computation type.
- LHSVal = (LTy == CTy) ? Result : EvalCast(Result,LTy);
+ llvm::tie(state, LHSVal) = SVator.EvalCast(Result, state, LTy, CTy);
}
-
- EvalStore(Dst, B, LHS, *I3, state->bindExpr(B, Result), location,
- LHSVal);
+
+ EvalStore(Dst, B, LHS, *I3, state->BindExpr(B, Result),
+ location, LHSVal);
}
}
}
}
//===----------------------------------------------------------------------===//
-// Transfer-function Helpers.
-//===----------------------------------------------------------------------===//
-
-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 SVator->EvalBinOpLL(Op, cast<Loc>(L), cast<Loc>(R), T);
- else
- return SVator->EvalBinOpLN(state, Op, cast<Loc>(L), cast<NonLoc>(R), T);
- }
-
- 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 SVator->EvalBinOpLN(state, Op, cast<Loc>(R), cast<NonLoc>(L), T);
- }
- else
- return SVator->EvalBinOpNN(Op, cast<NonLoc>(L), cast<NonLoc>(R), T);
-}
-
-//===----------------------------------------------------------------------===//
// Visualization.
//===----------------------------------------------------------------------===//
@@ -3105,67 +2952,65 @@ static SourceManager* GraphPrintSourceManager;
namespace llvm {
template<>
-struct VISIBILITY_HIDDEN DOTGraphTraits<GRExprEngine::NodeTy*> :
+struct VISIBILITY_HIDDEN DOTGraphTraits<ExplodedNode*> :
public DefaultDOTGraphTraits {
-
- static std::string getNodeAttributes(const GRExprEngine::NodeTy* N, void*) {
-
+
+ static std::string getNodeAttributes(const ExplodedNode* 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*,
- bool ShortNames) {
-
+
+ static std::string getNodeLabel(const ExplodedNode* N, void*,bool ShortNames){
+
std::string sbuf;
llvm::raw_string_ostream Out(sbuf);
// Program Location.
ProgramPoint Loc = N->getLocation();
-
+
switch (Loc.getKind()) {
case ProgramPoint::BlockEntranceKind:
- Out << "Block Entrance: B"
+ 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();
+ if (StmtPoint *L = dyn_cast<StmtPoint>(&Loc)) {
+ const Stmt* S = L->getStmt();
SourceLocation SLoc = S->getLocStart();
- Out << S->getStmtClassName() << ' ' << (void*) S << ' ';
+ Out << S->getStmtClassName() << ' ' << (void*) S << ' ';
LangOptions LO; // FIXME.
S->printPretty(Out, 0, PrintingPolicy(LO));
-
- if (SLoc.isFileID()) {
+
+ if (SLoc.isFileID()) {
Out << "\\lline="
<< GraphPrintSourceManager->getInstantiationLineNumber(SLoc)
<< " col="
<< GraphPrintSourceManager->getInstantiationColumnNumber(SLoc)
<< "\\l";
}
-
- if (isa<PostLoad>(Loc))
+
+ if (isa<PreStmt>(Loc))
+ Out << "\\lPreStmt\\l;";
+ else if (isa<PostLoad>(Loc))
Out << "\\lPostLoad\\l;";
else if (isa<PostStore>(Loc))
Out << "\\lPostStore\\l";
@@ -3175,7 +3020,7 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<GRExprEngine::NodeTy*> :
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))
@@ -3184,10 +3029,6 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<GRExprEngine::NodeTy*> :
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))
@@ -3196,43 +3037,43 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<GRExprEngine::NodeTy*> :
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: ";
LangOptions LO; // FIXME.
E.getSrc()->printTerminator(Out, LO);
-
+
if (SLoc.isFileID()) {
Out << "\\lline="
<< GraphPrintSourceManager->getInstantiationLineNumber(SLoc)
<< " col="
<< GraphPrintSourceManager->getInstantiationColumnNumber(SLoc);
}
-
+
if (isa<SwitchStmt>(T)) {
Stmt* Label = E.getDst()->getLabel();
-
- if (Label) {
+
+ if (Label) {
if (CaseStmt* C = dyn_cast<CaseStmt>(Label)) {
Out << "\\lcase ";
LangOptions LO; // FIXME.
C->getLHS()->printPretty(Out, 0, PrintingPolicy(LO));
-
+
if (Stmt* RHS = C->getRHS()) {
Out << " .. ";
RHS->printPretty(Out, 0, PrintingPolicy(LO));
}
-
+
Out << ":";
}
else {
@@ -3240,7 +3081,7 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<GRExprEngine::NodeTy*> :
Out << "\\ldefault:";
}
}
- else
+ else
Out << "\\l(implicit) default:";
}
else if (isa<IndirectGotoStmt>(T)) {
@@ -3251,46 +3092,45 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<GRExprEngine::NodeTy*> :
if (*E.getSrc()->succ_begin() == E.getDst())
Out << "true";
else
- Out << "false";
+ Out << "false";
}
-
+
Out << "\\l";
}
-
+
if (GraphPrintCheckerState->isUndefControlFlow(N)) {
Out << "\\|Control-flow based on\\lUndefined value.\\l";
}
}
}
-
+
Out << "\\|StateID: " << (void*) N->getState() << "\\|";
const GRState *state = N->getState();
state->printDOT(Out);
-
+
Out << "\\l";
return Out.str();
}
};
-} // end llvm namespace
+} // end llvm namespace
#endif
#ifndef NDEBUG
template <typename ITERATOR>
-GRExprEngine::NodeTy* GetGraphNode(ITERATOR I) { return *I; }
+ExplodedNode* GetGraphNode(ITERATOR I) { return *I; }
-template <>
-GRExprEngine::NodeTy*
-GetGraphNode<llvm::DenseMap<GRExprEngine::NodeTy*, Expr*>::iterator>
- (llvm::DenseMap<GRExprEngine::NodeTy*, Expr*>::iterator I) {
+template <> ExplodedNode*
+GetGraphNode<llvm::DenseMap<ExplodedNode*, Expr*>::iterator>
+ (llvm::DenseMap<ExplodedNode*, Expr*>::iterator I) {
return I->first;
}
#endif
void GRExprEngine::ViewGraph(bool trim) {
-#ifndef NDEBUG
+#ifndef NDEBUG
if (trim) {
- std::vector<NodeTy*> Src;
+ std::vector<ExplodedNode*> Src;
// Flush any outstanding reports to make sure we cover all the nodes.
// This does not cause them to get displayed.
@@ -3299,14 +3139,15 @@ void GRExprEngine::ViewGraph(bool trim) {
// 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) {
+ 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());
+ ExplodedNode *N = const_cast<ExplodedNode*>(R.getEndNode());
if (N) Src.push_back(N);
}
}
-
+
ViewGraph(&Src[0], &Src[0]+Src.size());
}
else {
@@ -3314,25 +3155,25 @@ void GRExprEngine::ViewGraph(bool trim) {
GraphPrintSourceManager = &getContext().getSourceManager();
llvm::ViewGraph(*G.roots_begin(), "GRExprEngine");
-
+
GraphPrintCheckerState = NULL;
GraphPrintSourceManager = NULL;
}
#endif
}
-void GRExprEngine::ViewGraph(NodeTy** Beg, NodeTy** End) {
+void GRExprEngine::ViewGraph(ExplodedNode** Beg, ExplodedNode** End) {
#ifndef NDEBUG
GraphPrintCheckerState = this;
GraphPrintSourceManager = &getContext().getSourceManager();
-
- std::auto_ptr<GRExprEngine::GraphTy> TrimmedG(G.Trim(Beg, End).first);
+
+ std::auto_ptr<ExplodedGraph> TrimmedG(G.Trim(Beg, End).first);
if (!TrimmedG.get())
- llvm::cerr << "warning: Trimmed ExplodedGraph is empty.\n";
+ llvm::errs() << "warning: Trimmed ExplodedGraph is empty.\n";
else
- llvm::ViewGraph(*TrimmedG->roots_begin(), "TrimmedGRExprEngine");
-
+ llvm::ViewGraph(*TrimmedG->roots_begin(), "TrimmedGRExprEngine");
+
GraphPrintCheckerState = NULL;
GraphPrintSourceManager = NULL;
#endif
diff --git a/lib/Analysis/GRExprEngineInternalChecks.cpp b/lib/Analysis/GRExprEngineInternalChecks.cpp
index a2ce79a..cc1ec4b 100644
--- a/lib/Analysis/GRExprEngineInternalChecks.cpp
+++ b/lib/Analysis/GRExprEngineInternalChecks.cpp
@@ -14,42 +14,30 @@
#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "clang/Analysis/PathSensitive/CheckerVisitor.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;
+using namespace clang::bugreporter;
//===----------------------------------------------------------------------===//
// Utility functions.
//===----------------------------------------------------------------------===//
template <typename ITERATOR> inline
-ExplodedNode<GRState>* GetNode(ITERATOR I) {
+ExplodedNode* GetNode(ITERATOR I) {
return *I;
}
template <> inline
-ExplodedNode<GRState>* GetNode(GRExprEngine::undef_arg_iterator I) {
+ExplodedNode* 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.
//===----------------------------------------------------------------------===//
@@ -58,17 +46,17 @@ namespace {
class VISIBILITY_HIDDEN BuiltinBugReport : public RangedBugReport {
public:
BuiltinBugReport(BugType& bt, const char* desc,
- ExplodedNode<GRState> *n)
+ ExplodedNode *n)
: RangedBugReport(bt, desc, n) {}
-
+
BuiltinBugReport(BugType& bt, const char *shortDesc, const char *desc,
- ExplodedNode<GRState> *n)
- : RangedBugReport(bt, shortDesc, desc, n) {}
-
+ ExplodedNode *n)
+ : RangedBugReport(bt, shortDesc, desc, n) {}
+
void registerInitialVisitors(BugReporterContext& BRC,
- const ExplodedNode<GRState>* N);
-};
-
+ const ExplodedNode* N);
+};
+
class VISIBILITY_HIDDEN BuiltinBug : public BugType {
GRExprEngine &Eng;
protected:
@@ -79,30 +67,32 @@ public:
BuiltinBug(GRExprEngine *eng, const char* n)
: BugType(n, "Logic errors"), Eng(*eng), desc(n) {}
-
- virtual void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) = 0;
+
+ const std::string &getDescription() const { return desc; }
+
+ virtual void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {}
void FlushReports(BugReporter& BR) { FlushReportsImpl(BR, Eng); }
-
+
virtual void registerInitialVisitors(BugReporterContext& BRC,
- const ExplodedNode<GRState>* N,
+ const ExplodedNode* 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) {
+ const ExplodedNode* N) {
static_cast<BuiltinBug&>(getBugType()).registerInitialVisitors(BRC, N, this);
-}
-
+}
+
class VISIBILITY_HIDDEN NullDeref : public BuiltinBug {
public:
NullDeref(GRExprEngine* eng)
@@ -111,14 +101,14 @@ public:
void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
Emit(BR, Eng.null_derefs_begin(), Eng.null_derefs_end());
}
-
+
void registerInitialVisitors(BugReporterContext& BRC,
- const ExplodedNode<GRState>* N,
+ const ExplodedNode* N,
BuiltinBugReport *R) {
registerTrackNullOrUndefValue(BRC, GetDerefExpr(N), N);
}
};
-
+
class VISIBILITY_HIDDEN NilReceiverStructRet : public BuiltinBug {
public:
NilReceiverStructRet(GRExprEngine* eng) :
@@ -132,20 +122,20 @@ public:
std::string sbuf;
llvm::raw_string_ostream os(sbuf);
PostStmt P = cast<PostStmt>((*I)->getLocation());
- ObjCMessageExpr *ME = cast<ObjCMessageExpr>(P.getStmt());
+ const 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.";
+ << "') 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,
+ const ExplodedNode* N,
BuiltinBugReport *R) {
registerTrackNullOrUndefValue(BRC, GetReceiverExpr(N), N);
}
@@ -156,46 +146,46 @@ 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());
+ const 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.";
-
+ << " 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,
+ const ExplodedNode* 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,
+ const ExplodedNode* N,
BuiltinBugReport *R) {
registerTrackNullOrUndefValue(BRC, GetDerefExpr(N), N);
}
@@ -203,43 +193,100 @@ public:
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());
- }
-
+ DivZero(GRExprEngine* eng = 0)
+ : BuiltinBug(eng,"Division by zero") {}
+
void registerInitialVisitors(BugReporterContext& BRC,
- const ExplodedNode<GRState>* N,
+ const ExplodedNode* 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.") {}
-
+ UndefResult(GRExprEngine* eng)
+ : BuiltinBug(eng,"Undefined or garbage result",
+ "Result of operation is garbage or undefined") {}
+
void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
- Emit(BR, Eng.undef_results_begin(), Eng.undef_results_end());
+ for (GRExprEngine::undef_result_iterator I=Eng.undef_results_begin(),
+ E = Eng.undef_results_end(); I!=E; ++I) {
+
+ ExplodedNode *N = *I;
+ const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
+ BuiltinBugReport *report = NULL;
+
+ if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S)) {
+ llvm::SmallString<256> sbuf;
+ llvm::raw_svector_ostream OS(sbuf);
+ const GRState *ST = N->getState();
+ const Expr *Ex = NULL;
+ bool isLeft = true;
+
+ if (ST->getSVal(B->getLHS()).isUndef()) {
+ Ex = B->getLHS()->IgnoreParenCasts();
+ isLeft = true;
+ }
+ else if (ST->getSVal(B->getRHS()).isUndef()) {
+ Ex = B->getRHS()->IgnoreParenCasts();
+ isLeft = false;
+ }
+
+ if (Ex) {
+ OS << "The " << (isLeft ? "left" : "right")
+ << " operand of '"
+ << BinaryOperator::getOpcodeStr(B->getOpcode())
+ << "' is a garbage value";
+ }
+ else {
+ // Neither operand was undefined, but the result is undefined.
+ OS << "The result of the '"
+ << BinaryOperator::getOpcodeStr(B->getOpcode())
+ << "' expression is undefined";
+ }
+
+ // FIXME: Use StringRefs to pass string information.
+ report = new BuiltinBugReport(*this, OS.str().str().c_str(), N);
+ if (Ex) report->addRange(Ex->getSourceRange());
+ }
+ else {
+ report = new BuiltinBugReport(*this,
+ "Expression evaluates to an uninitialized"
+ " or undefined value", N);
+ }
+
+ BR.EmitReport(report);
+ }
}
-};
+ void registerInitialVisitors(BugReporterContext& BRC,
+ const ExplodedNode* N,
+ BuiltinBugReport *R) {
+
+ const Stmt *S = N->getLocationAs<StmtPoint>()->getStmt();
+ const Stmt *X = S;
+
+ if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S)) {
+ const GRState *ST = N->getState();
+ if (ST->getSVal(B->getLHS()).isUndef())
+ X = B->getLHS();
+ else if (ST->getSVal(B->getRHS()).isUndef())
+ X = B->getRHS();
+ }
+
+ registerTrackNullOrUndefValue(BRC, X, N);
+ }
+};
+
class VISIBILITY_HIDDEN BadCall : public BuiltinBug {
public:
- BadCall(GRExprEngine *eng)
+ BadCall(GRExprEngine *eng = 0)
: 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,
+ const ExplodedNode* N,
BuiltinBugReport *R) {
registerTrackNullOrUndefValue(BRC, GetCalleeExpr(N), N);
}
@@ -249,76 +296,65 @@ public:
class VISIBILITY_HIDDEN ArgReport : public BuiltinBugReport {
const Stmt *Arg;
public:
- ArgReport(BugType& bt, const char* desc, ExplodedNode<GRState> *n,
+ ArgReport(BugType& bt, const char* desc, ExplodedNode *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; }
+ ExplodedNode *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.") {}
+public:
+ BadArg(GRExprEngine* eng=0) : 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,
+ const ExplodedNode* N,
BuiltinBugReport *R) {
registerTrackNullOrUndefValue(BRC, static_cast<ArgReport*>(R)->getArg(),
N);
- }
+ }
};
-
+
class VISIBILITY_HIDDEN BadMsgExprArg : public BadArg {
public:
- BadMsgExprArg(GRExprEngine* eng)
+ 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) {
+ 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:
+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();
+ ExplodedNode* N = *I;
+ const Stmt *S = cast<PostStmt>(N->getLocation()).getStmt();
+ const Expr* E = cast<ObjCMessageExpr>(S)->getReceiver();
assert (E && "Receiver cannot be NULL");
report->addRange(E->getSourceRange());
BR.EmitReport(report);
@@ -326,61 +362,61 @@ public:
}
void registerInitialVisitors(BugReporterContext& BRC,
- const ExplodedNode<GRState>* N,
+ const ExplodedNode* 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");
-
+ ExplodedNode* N = *I;
+ const Stmt *S = cast<PostStmt>(N->getLocation()).getStmt();
+ const 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>(N->getState()->getSVal(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 =
+ 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 {
+ }
+ 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);
@@ -388,51 +424,52 @@ public:
}
}
};
-
+
class VISIBILITY_HIDDEN RetUndef : public BuiltinBug {
public:
- RetUndef(GRExprEngine* eng) : BuiltinBug(eng, "Uninitialized return value",
- "Uninitialized or undefined value returned to caller.") {}
-
+ RetUndef(GRExprEngine* eng) : BuiltinBug(eng, "Garbage return value",
+ "Undefined or garbage 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,
+ const ExplodedNode* 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) {
+
+ 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 St->getSVal(Ex).isUndef(); }
};
-
+
public:
UndefBranch(GRExprEngine *eng)
- : BuiltinBug(eng,"Use of uninitialized value",
- "Branch condition evaluates to an uninitialized value.") {}
-
+ : BuiltinBug(eng,"Use of garbage value",
+ "Branch condition evaluates to an undefined or garbage 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) {
@@ -455,7 +492,7 @@ public:
// 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();
+ ExplodedNode *N = *(*I)->pred_begin();
ProgramPoint P = N->getLocation();
const GRState* St = (*I)->getState();
@@ -471,9 +508,9 @@ public:
BR.EmitReport(R);
}
}
-
+
void registerInitialVisitors(BugReporterContext& BRC,
- const ExplodedNode<GRState>* N,
+ const ExplodedNode* N,
BuiltinBugReport *R) {
registerTrackNullOrUndefValue(BRC, static_cast<ArgReport*>(R)->getArg(),
N);
@@ -490,12 +527,12 @@ public:
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(),
@@ -503,27 +540,27 @@ public:
// 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());
+ ExplodedNode* N = *I;
+ PostStmt PS = cast<PostStmt>(N->getLocation());
+ const 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 = N->getState()->getSVal(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() << "' "
@@ -537,9 +574,9 @@ public:
BR.EmitReport(report);
}
}
-
+
void registerInitialVisitors(BugReporterContext& BRC,
- const ExplodedNode<GRState>* N,
+ const ExplodedNode* N,
BuiltinBugReport *R) {
registerTrackNullOrUndefValue(BRC, static_cast<ArgReport*>(R)->getArg(),
N);
@@ -549,370 +586,217 @@ public:
//===----------------------------------------------------------------------===//
// __attribute__(nonnull) checking
-class VISIBILITY_HIDDEN CheckAttrNonNull : public GRSimpleAPICheck {
+class VISIBILITY_HIDDEN CheckAttrNonNull :
+ public CheckerVisitor<CheckAttrNonNull> {
+
BugType *BT;
- BugReporter &BR;
-
+
public:
- CheckAttrNonNull(BugReporter &br) : BT(0), BR(br) {}
+ CheckAttrNonNull() : BT(0) {}
+ ~CheckAttrNonNull() {}
- virtual bool Audit(ExplodedNode<GRState>* N, GRStateManager& VMgr) {
- CallExpr* CE = cast<CallExpr>(cast<PostStmt>(N->getLocation()).getStmt());
- const GRState* state = N->getState();
-
+ const void *getTag() {
+ static int x = 0;
+ return &x;
+ }
+
+ void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
+ const GRState *state = C.getState();
+ const GRState *originalState = state;
+
+ // Check if the callee has a 'nonnull' attribute.
SVal X = state->getSVal(CE->getCallee());
const FunctionDecl* FD = X.getAsFunctionDecl();
if (!FD)
- return false;
+ return;
const NonNullAttr* Att = FD->getAttr<NonNullAttr>();
-
if (!Att)
- return false;
-
+ return;
+
// 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;
+
+ for (CallExpr::const_arg_iterator I=CE->arg_begin(), E=CE->arg_end(); I!=E;
++I, ++idx) {
-
- if (!VMgr.isEqual(state, *I, 0) || !Att->isNonNull(idx))
+
+ if (!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);
+ const SVal &V = state->getSVal(*I);
+ const DefinedSVal *DV = dyn_cast<DefinedSVal>(&V);
- R->addRange((*I)->getSourceRange());
- BR.EmitReport(R);
- hasError = true;
+ if (!DV)
+ continue;
+
+ ConstraintManager &CM = C.getConstraintManager();
+ const GRState *stateNotNull, *stateNull;
+ llvm::tie(stateNotNull, stateNull) = CM.AssumeDual(state, *DV);
+
+ if (stateNull && !stateNotNull) {
+ // Generate an error node. Check for a null node in case
+ // we cache out.
+ if (ExplodedNode *errorNode = C.GenerateNode(CE, stateNull, true)) {
+
+ // 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");
+
+ EnhancedBugReport *R =
+ new EnhancedBugReport(*BT,
+ "Null pointer passed as an argument to a "
+ "'nonnull' parameter", errorNode);
+
+ // Highlight the range of the argument that was null.
+ const Expr *arg = *I;
+ R->addRange(arg->getSourceRange());
+ R->addVisitorCreator(registerTrackNullOrUndefValue, arg);
+
+ // Emit the bug report.
+ C.EmitReport(R);
+ }
+
+ // Always return. Either we cached out or we just emitted an error.
+ return;
+ }
+
+ // If a pointer value passed the check we should assume that it is
+ // indeed not null from this point forward.
+ assert(stateNotNull);
+ state = stateNotNull;
}
-
- return hasError;
+
+ // If we reach here all of the arguments passed the nonnull check.
+ // If 'state' has been updated generated a new node.
+ if (state != originalState)
+ C.addTransition(C.GenerateNode(CE, state));
}
};
} // end anonymous namespace
-//===----------------------------------------------------------------------===//
-// Definitions for bug reporter visitors.
-//===----------------------------------------------------------------------===//
+// Undefined arguments checking.
+namespace {
+class VISIBILITY_HIDDEN CheckUndefinedArg
+ : public CheckerVisitor<CheckUndefinedArg> {
-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();
+ BadArg *BT;
- 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();
+public:
+ CheckUndefinedArg() : BT(0) {}
+ ~CheckUndefinedArg() {}
+
+ const void *getTag() {
+ static int x = 0;
+ return &x;
}
- 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();
+
+ void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+};
+
+void CheckUndefinedArg::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE){
+ for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end();
+ I != E; ++I) {
+ if (C.getState()->getSVal(*I).isUndef()) {
+ if (ExplodedNode *ErrorNode = C.GenerateNode(CE, true)) {
+ if (!BT)
+ BT = new BadArg();
+ // Generate a report for this bug.
+ ArgReport *Report = new ArgReport(*BT, BT->getDescription().c_str(),
+ ErrorNode, *I);
+ Report->addRange((*I)->getSourceRange());
+ C.EmitReport(Report);
+ }
+ }
}
-
- 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;
-}
+class VISIBILITY_HIDDEN CheckBadCall : public CheckerVisitor<CheckBadCall> {
+ BadCall *BT;
-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) {
- 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 (Node->getState()->getSVal(R) != V)
- break;
- }
+ CheckBadCall() : BT(0) {}
+ ~CheckBadCall() {}
- if (!Node || !Last) {
- satisfied = true;
- return NULL;
- }
-
- StoreSite = Last;
- }
-
- if (StoreSite != N)
- return NULL;
+ const void *getTag() {
+ static int x = 0;
+ return &x;
+ }
- 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()) {
- 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";
- }
- }
- }
- }
+ void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+};
- if (os.str().empty()) {
- if (isa<loc::ConcreteInt>(V)) {
- bool b = false;
- ASTContext &C = BRC.getASTContext();
- if (R->isBoundable()) {
- if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) {
- if (C.isObjCObjectPointerType(TR->getValueType(C))) {
- os << "nil object reference stored to ";
- b = true;
- }
- }
- }
+void CheckBadCall::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
+ const Expr *Callee = CE->getCallee()->IgnoreParens();
+ SVal L = C.getState()->getSVal(Callee);
- 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;
+ if (L.isUndef() || isa<loc::ConcreteInt>(L)) {
+ if (ExplodedNode *N = C.GenerateNode(CE, true)) {
+ if (!BT)
+ BT = new BadCall();
+ C.EmitReport(new BuiltinBugReport(*BT, BT->getDescription().c_str(), N));
}
-
- // 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;
+class VISIBILITY_HIDDEN CheckBadDiv : public CheckerVisitor<CheckBadDiv> {
+ DivZero *BT;
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.
- if (PrevN->getState()->assume(Constraint, !Assumption)) {
+ CheckBadDiv() : BT(0) {}
+ ~CheckBadDiv() {}
- isSatisfied = true;
-
- // As a sanity check, make sure that the negation of the constraint
- // was infeasible in the current state. If it is feasible, we somehow
- // missed the transition point.
- if (N->getState()->assume(Constraint, !Assumption))
- return NULL;
-
- // We found the transition point for the constraint. We now need to
- // pretty-print the constraint. (work-in-progress)
- std::string sbuf;
- llvm::raw_string_ostream os(sbuf);
-
- 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;
- }
+ const void *getTag() {
+ static int x;
+ return &x;
+ }
+
+ void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
};
-} // end anonymous namespace
-static void registerTrackConstraint(BugReporterContext& BRC, SVal Constraint,
- bool Assumption) {
- BRC.addVisitor(new TrackConstraintBRVisitor(Constraint, Assumption));
-}
+void CheckBadDiv::PreVisitBinaryOperator(CheckerContext &C,
+ const BinaryOperator *B) {
+ BinaryOperator::Opcode Op = B->getOpcode();
+ if (Op != BinaryOperator::Div &&
+ Op != BinaryOperator::Rem &&
+ Op != BinaryOperator::DivAssign &&
+ Op != BinaryOperator::RemAssign)
+ return;
-static void registerTrackNullOrUndefValue(BugReporterContext& BRC,
- const Stmt *S,
- const ExplodedNode<GRState>* N) {
-
- if (!S)
+ if (!B->getRHS()->getType()->isIntegerType() ||
+ !B->getRHS()->getType()->isScalarType())
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 = state->getSVal(S);
-
- if (isa<loc::ConcreteInt>(V) || isa<nonloc::ConcreteInt>(V)
- || V.isUndef()) {
- registerFindLastStore(BRC, R, V);
- }
- }
- }
-
- SVal V = state->getSValAsScalarOrLoc(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);
+ SVal Denom = C.getState()->getSVal(B->getRHS());
+ const DefinedSVal *DV = dyn_cast<DefinedSVal>(&Denom);
+
+ // Divide-by-undefined handled in the generic checking for uses of
+ // undefined values.
+ if (!DV)
+ return;
+
+ // Check for divide by zero.
+ ConstraintManager &CM = C.getConstraintManager();
+ const GRState *stateNotZero, *stateZero;
+ llvm::tie(stateNotZero, stateZero) = CM.AssumeDual(C.getState(), *DV);
+
+ if (stateZero && !stateNotZero) {
+ if (ExplodedNode *N = C.GenerateNode(B, stateZero, true)) {
+ if (!BT)
+ BT = new DivZero();
+
+ C.EmitReport(new BuiltinBugReport(*BT, BT->getDescription().c_str(), N));
}
+ return;
}
-}
+ // If we get here, then the denom should not be zero.
+ if (stateNotZero != C.getState())
+ C.addTransition(C.GenerateNode(B, stateNotZero));
+}
+}
//===----------------------------------------------------------------------===//
// Check registration.
//===----------------------------------------------------------------------===//
@@ -926,23 +810,23 @@ void GRExprEngine::RegisterInternalChecks() {
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);
+ registerCheck(new CheckAttrNonNull());
+ registerCheck(new CheckUndefinedArg());
+ registerCheck(new CheckBadCall());
+ registerCheck(new CheckBadDiv());
}
diff --git a/lib/Analysis/GRState.cpp b/lib/Analysis/GRState.cpp
index 54c0afb..f269824 100644
--- a/lib/Analysis/GRState.cpp
+++ b/lib/Analysis/GRState.cpp
@@ -27,7 +27,7 @@ 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);
@@ -46,12 +46,11 @@ GRStateManager::RemoveDeadBindings(const GRState* state, Stmt* Loc,
llvm::SmallVector<const MemRegion*, 10> RegionRoots;
GRState NewState = *state;
- NewState.Env = EnvMgr.RemoveDeadBindings(NewState.Env, Loc, SymReaper, *this,
+ NewState.Env = EnvMgr.RemoveDeadBindings(NewState.Env, Loc, SymReaper,
state, RegionRoots);
// Clean up the store.
- NewState.St = StoreMgr->RemoveDeadBindings(&NewState, Loc, SymReaper,
- RegionRoots);
+ StoreMgr->RemoveDeadBindings(NewState, Loc, SymReaper, RegionRoots);
return ConstraintMgr->RemoveDeadBindings(getPersistentState(NewState),
SymReaper);
@@ -59,14 +58,14 @@ GRStateManager::RemoveDeadBindings(const GRState* state, Stmt* Loc,
const GRState *GRState::unbindLoc(Loc LV) const {
Store OldStore = getStore();
- Store NewStore = Mgr->StoreMgr->Remove(OldStore, LV);
-
+ Store NewStore = getStateManager().StoreMgr->Remove(OldStore, LV);
+
if (NewStore == OldStore)
return this;
-
+
GRState NewSt = *this;
NewSt.St = NewStore;
- return Mgr->getPersistentState(NewSt);
+ return getStateManager().getPersistentState(NewSt);
}
SVal GRState::getSValAsScalarOrLoc(const MemRegion *R) const {
@@ -77,7 +76,7 @@ SVal GRState::getSValAsScalarOrLoc(const MemRegion *R) const {
return UnknownVal();
if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) {
- QualType T = TR->getValueType(Mgr->getContext());
+ QualType T = TR->getValueType(getStateManager().getContext());
if (Loc::IsLocType(T) || T->isIntegerType())
return getSVal(R);
}
@@ -86,55 +85,37 @@ SVal GRState::getSValAsScalarOrLoc(const MemRegion *R) const {
}
-const GRState *GRState::bindExpr(const Stmt* Ex, SVal V, bool isBlkExpr,
- bool Invalidate) const {
-
- Environment NewEnv = Mgr->EnvMgr.BindExpr(Env, Ex, V, isBlkExpr, Invalidate);
-
+const GRState *GRState::BindExpr(const Stmt* Ex, SVal V, bool Invalidate) const{
+ Environment NewEnv = getStateManager().EnvMgr.BindExpr(Env, Ex, V,
+ Invalidate);
if (NewEnv == Env)
return this;
-
+
GRState NewSt = *this;
NewSt.Env = NewEnv;
- return Mgr->getPersistentState(NewSt);
-}
-
-const GRState *GRState::bindExpr(const Stmt* Ex, SVal V,
- bool Invalidate) const {
-
- bool isBlkExpr = false;
-
- if (Ex == Mgr->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 = Mgr->cfg.isBlkExpr(Ex);
-
- if (!isBlkExpr)
- return this;
- }
-
- return bindExpr(Ex, V, isBlkExpr, Invalidate);
+ return getStateManager().getPersistentState(NewSt);
}
-const GRState* GRStateManager::getInitialState() {
- GRState StateImpl(this, EnvMgr.getInitialEnvironment(),
- StoreMgr->getInitialStore(),
- GDMFactory.GetEmptyMap());
+const GRState* GRStateManager::getInitialState(const LocationContext *InitLoc) {
+ GRState State(this,
+ EnvMgr.getInitialEnvironment(InitLoc->getAnalysisContext()),
+ StoreMgr->getInitialStore(InitLoc),
+ GDMFactory.GetEmptyMap());
- return getPersistentState(StateImpl);
+ return getPersistentState(State);
}
const GRState* GRStateManager::getPersistentState(GRState& State) {
-
+
llvm::FoldingSetNodeID ID;
- State.Profile(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);
+ new (I) GRState(State);
StateSet.InsertNode(I, InsertPos);
return I;
}
@@ -142,7 +123,7 @@ const GRState* GRStateManager::getPersistentState(GRState& State) {
const GRState* GRState::makeWithStore(Store store) const {
GRState NewSt = *this;
NewSt.St = store;
- return Mgr->getPersistentState(NewSt);
+ return getStateManager().getPersistentState(NewSt);
}
//===----------------------------------------------------------------------===//
@@ -150,51 +131,56 @@ const GRState* GRState::makeWithStore(Store store) const {
//===----------------------------------------------------------------------===//
void GRState::print(llvm::raw_ostream& Out, const char* nl,
- const char* sep) const {
+ const char* sep) const {
// Print the store.
- Mgr->getStoreManager().print(getStore(), Out, nl, sep);
-
+ GRStateManager &Mgr = getStateManager();
+ Mgr.getStoreManager().print(getStore(), Out, nl, sep);
+
+ CFG &C = *getAnalysisContext().getCFG();
+
// Print Subexpression bindings.
bool isFirst = true;
-
- for (seb_iterator I = seb_begin(), E = seb_end(); I != E; ++I) {
-
+
+ for (Environment::iterator I = Env.begin(), E = Env.end(); I != E; ++I) {
+ if (C.isBlkExpr(I.getKey()))
+ continue;
+
if (isFirst) {
Out << nl << nl << "Sub-Expressions:" << nl;
isFirst = false;
}
else { Out << nl; }
-
+
Out << " (" << (void*) I.getKey() << ") ";
LangOptions LO; // FIXME.
I.getKey()->printPretty(Out, 0, PrintingPolicy(LO));
- Out << " : ";
- I.getData().print(Out);
+ Out << " : " << I.getData();
}
-
+
// Print block-expression bindings.
isFirst = true;
-
- for (beb_iterator I = beb_begin(), E = beb_end(); I != E; ++I) {
+
+ for (Environment::iterator I = Env.begin(), E = Env.end(); I != E; ++I) {
+ if (!C.isBlkExpr(I.getKey()))
+ continue;
if (isFirst) {
Out << nl << nl << "Block-level Expressions:" << nl;
isFirst = false;
}
else { Out << nl; }
-
+
Out << " (" << (void*) I.getKey() << ") ";
LangOptions LO; // FIXME.
I.getKey()->printPretty(Out, 0, PrintingPolicy(LO));
- Out << " : ";
- I.getData().print(Out);
+ Out << " : " << I.getData();
}
-
- Mgr->getConstraintManager().print(this, Out, nl, sep);
-
+
+ Mgr.getConstraintManager().print(this, Out, nl, sep);
+
// Print checker-specific data.
- for (std::vector<Printer*>::iterator I = Mgr->Printers.begin(),
- E = Mgr->Printers.end(); I != E; ++I) {
+ for (std::vector<Printer*>::iterator I = Mgr.Printers.begin(),
+ E = Mgr.Printers.end(); I != E; ++I) {
(*I)->Print(Out, this, nl, sep);
}
}
@@ -219,23 +205,23 @@ 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);
@@ -254,14 +240,14 @@ class VISIBILITY_HIDDEN ScanReachableSymbols : public SubRegionMap::Visitor {
SymbolVisitor &visitor;
llvm::OwningPtr<SubRegionMap> SRM;
public:
-
+
ScanReachableSymbols(const GRState *st, SymbolVisitor& v)
: state(st), visitor(v) {}
-
+
bool scan(nonloc::CompoundVal val);
bool scan(SVal val);
bool scan(const MemRegion *R);
-
+
// From SubRegionMap::Visitor.
bool Visit(const MemRegion* Parent, const MemRegion* SubRegion) {
return scan(SubRegion);
@@ -276,44 +262,44 @@ bool ScanReachableSymbols::scan(nonloc::CompoundVal val) {
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->getStateManager().getStoreManager().getSubRegionMap(state));
-
+
return SRM->iterSubRegions(R, *this);
}
@@ -326,24 +312,24 @@ bool GRState::scanReachableSymbols(SVal val, SymbolVisitor& visitor) const {
// Queries.
//===----------------------------------------------------------------------===//
-bool GRStateManager::isEqual(const GRState* state, Expr* Ex,
+bool GRStateManager::isEqual(const GRState* state, const Expr* Ex,
const llvm::APSInt& Y) {
-
+
SVal V = state->getSVal(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) {
+
+bool GRStateManager::isEqual(const GRState* state, const Expr* Ex, uint64_t x) {
return isEqual(state, Ex, getBasicVals().getValue(x, Ex->getType()));
}
diff --git a/lib/Analysis/LiveVariables.cpp b/lib/Analysis/LiveVariables.cpp
index aead7f4..4d96c8f 100644
--- a/lib/Analysis/LiveVariables.cpp
+++ b/lib/Analysis/LiveVariables.cpp
@@ -15,7 +15,7 @@
#include "clang/Basic/SourceManager.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
-#include "clang/AST/CFG.h"
+#include "clang/Analysis/CFG.h"
#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
#include "clang/Analysis/FlowSensitive/DataflowSolver.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -29,35 +29,35 @@ using namespace clang;
//===----------------------------------------------------------------------===//
// Useful constants.
-//===----------------------------------------------------------------------===//
+//===----------------------------------------------------------------------===//
static const bool Alive = true;
-static const bool Dead = false;
+static const bool Dead = false;
//===----------------------------------------------------------------------===//
// Dataflow initialization logic.
-//===----------------------------------------------------------------------===//
+//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN RegisterDecls
+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;
+ I != E; ++ I)
+ AD.AlwaysLive(*I, AD) = Alive;
}
void VisitImplicitParamDecl(ImplicitParamDecl* IPD) {
@@ -68,12 +68,12 @@ public:
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);
+ AlwaysLive.push_back(VD);
}
-
+
CFG& getCFG() { return AD.getCFG(); }
};
} // end anonymous namespace
@@ -82,14 +82,14 @@ 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 {
@@ -101,85 +101,85 @@ public:
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 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()))
+ if (VarDecl* V = dyn_cast<VarDecl>(DR->getDecl()))
LiveState(V,AD) = Alive;
}
-
-void TransferFuncs::VisitBinaryOperator(BinaryOperator* B) {
+
+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();
+ Expr* ElemExpr = cast<Expr>(Element)->IgnoreParens();
if ((DR = dyn_cast<DeclRefExpr>(ElemExpr)))
VD = cast<VarDecl>(DR->getDecl());
else {
@@ -194,10 +194,10 @@ TransferFuncs::BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) {
}
}
-
+
void TransferFuncs::VisitUnaryOperator(UnaryOperator* U) {
Expr *E = U->getSubExpr();
-
+
switch (U->getOpcode()) {
case UnaryOperator::PostInc:
case UnaryOperator::PostDec:
@@ -206,7 +206,7 @@ void TransferFuncs::VisitUnaryOperator(UnaryOperator* U) {
// 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 (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); }
@@ -215,24 +215,24 @@ void TransferFuncs::VisitUnaryOperator(UnaryOperator* U) {
}
// Fall-through.
-
+
default:
return Visit(E);
}
}
-
-void TransferFuncs::VisitAssign(BinaryOperator* B) {
+
+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)
@@ -240,7 +240,7 @@ void TransferFuncs::VisitAssign(BinaryOperator* B) {
}
else // Not assigning to a variable. Process LHS as usual.
Visit(LHS);
-
+
Visit(B->getRHS());
}
@@ -255,44 +255,44 @@ void TransferFuncs::VisitDeclStmt(DeclStmt* DS) {
// 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;
+ 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;
-
+ 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);
@@ -337,22 +337,22 @@ bool LiveVariables::isLive(const Stmt* Loc, const VarDecl* D) const {
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)) {
+ 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);
}
diff --git a/lib/Analysis/MemRegion.cpp b/lib/Analysis/MemRegion.cpp
index 4530540..353e632 100644
--- a/lib/Analysis/MemRegion.cpp
+++ b/lib/Analysis/MemRegion.cpp
@@ -15,6 +15,8 @@
#include "llvm/Support/raw_ostream.h"
#include "clang/Analysis/PathSensitive/MemRegion.h"
+#include "clang/Analysis/PathSensitive/ValueManager.h"
+#include "clang/Analysis/PathSensitive/AnalysisContext.h"
using namespace clang;
@@ -37,7 +39,6 @@ bool SubRegion::isSubRegionOf(const MemRegion* R) const {
return false;
}
-
MemRegionManager* SubRegion::getMemRegionManager() const {
const SubRegion* r = this;
do {
@@ -54,8 +55,8 @@ void MemSpaceRegion::Profile(llvm::FoldingSetNodeID& ID) const {
ID.AddInteger((unsigned)getKind());
}
-void StringRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
- const StringLiteral* Str,
+void StringRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+ const StringLiteral* Str,
const MemRegion* superRegion) {
ID.AddInteger((unsigned) StringRegionKind);
ID.AddPointer(Str);
@@ -74,13 +75,6 @@ void AllocaRegion::Profile(llvm::FoldingSetNodeID& ID) const {
ProfileRegion(ID, Ex, Cnt, superRegion);
}
-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);
}
@@ -104,6 +98,10 @@ void DeclRegion::Profile(llvm::FoldingSetNodeID& ID) const {
DeclRegion::ProfileRegion(ID, D, superRegion, getKind());
}
+void VarRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+ VarRegion::ProfileRegion(ID, getDecl(), LC, superRegion);
+}
+
void SymbolicRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, SymbolRef sym,
const MemRegion *sreg) {
ID.AddInteger((unsigned) MemRegion::SymbolicRegionKind);
@@ -116,7 +114,7 @@ void SymbolicRegion::Profile(llvm::FoldingSetNodeID& ID) const {
}
void ElementRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
- QualType ElementType, SVal Idx,
+ QualType ElementType, SVal Idx,
const MemRegion* superRegion) {
ID.AddInteger(MemRegion::ElementRegionKind);
ID.Add(ElementType);
@@ -128,90 +126,88 @@ void ElementRegion::Profile(llvm::FoldingSetNodeID& ID) const {
ElementRegion::ProfileRegion(ID, ElementType, Index, superRegion);
}
-void CodeTextRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, const void* data,
- QualType t, const MemRegion*) {
+void CodeTextRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+ const FunctionDecl *FD,
+ const MemRegion*) {
ID.AddInteger(MemRegion::CodeTextRegionKind);
- ID.AddPointer(data);
- ID.Add(t);
+ ID.AddPointer(FD);
}
void CodeTextRegion::Profile(llvm::FoldingSetNodeID& ID) const {
- CodeTextRegion::ProfileRegion(ID, Data, LocationType, superRegion);
+ CodeTextRegion::ProfileRegion(ID, FD, superRegion);
}
//===----------------------------------------------------------------------===//
// Region pretty-printing.
//===----------------------------------------------------------------------===//
-void MemRegion::printStdErr() const {
- print(llvm::errs());
+void MemRegion::dump() const {
+ dumpToStream(llvm::errs());
}
std::string MemRegion::getString() const {
std::string s;
llvm::raw_string_ostream os(s);
- print(os);
+ dumpToStream(os);
return os.str();
}
-void MemRegion::print(llvm::raw_ostream& os) const {
+void MemRegion::dumpToStream(llvm::raw_ostream& os) const {
os << "<Unknown Region>";
}
-void AllocaRegion::print(llvm::raw_ostream& os) const {
+void AllocaRegion::dumpToStream(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 CodeTextRegion::dumpToStream(llvm::raw_ostream& os) const {
+ os << "code{" << getDecl()->getDeclName().getAsString() << '}';
}
-void CompoundLiteralRegion::print(llvm::raw_ostream& os) const {
+void CompoundLiteralRegion::dumpToStream(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 ElementRegion::dumpToStream(llvm::raw_ostream& os) const {
+ os << "element{" << superRegion << ','
+ << Index << ',' << getElementType().getAsString() << '}';
}
-void FieldRegion::print(llvm::raw_ostream& os) const {
- superRegion->print(os);
- os << "->" << getDecl()->getNameAsString();
+void FieldRegion::dumpToStream(llvm::raw_ostream& os) const {
+ os << superRegion << "->" << getDecl()->getNameAsString();
}
-void StringRegion::print(llvm::raw_ostream& os) const {
- LangOptions LO; // FIXME.
- Str->printPretty(os, 0, PrintingPolicy(LO));
+void ObjCIvarRegion::dumpToStream(llvm::raw_ostream& os) const {
+ os << "ivar{" << superRegion << ',' << getDecl()->getNameAsString() << '}';
}
-void SymbolicRegion::print(llvm::raw_ostream& os) const {
- os << "SymRegion-" << sym;
+void StringRegion::dumpToStream(llvm::raw_ostream& os) const {
+ Str->printPretty(os, 0, PrintingPolicy(getContext().getLangOptions()));
}
-void TypedViewRegion::print(llvm::raw_ostream& os) const {
- os << "typed_view{" << LValueType.getAsString() << ',';
- getSuperRegion()->print(os);
- os << '}';
+void SymbolicRegion::dumpToStream(llvm::raw_ostream& os) const {
+ os << "SymRegion{" << sym << '}';
}
-void VarRegion::print(llvm::raw_ostream& os) const {
+void VarRegion::dumpToStream(llvm::raw_ostream& os) const {
os << cast<VarDecl>(D)->getNameAsString();
}
+void RegionRawOffset::dump() const {
+ dumpToStream(llvm::errs());
+}
+
+void RegionRawOffset::dumpToStream(llvm::raw_ostream& os) const {
+ os << "raw_offset{" << getRegion() << ',' << getByteOffset() << '}';
+}
+
//===----------------------------------------------------------------------===//
// MemRegionManager methods.
//===----------------------------------------------------------------------===//
-
-MemSpaceRegion* MemRegionManager::LazyAllocate(MemSpaceRegion*& region) {
- if (!region) {
+
+MemSpaceRegion* MemRegionManager::LazyAllocate(MemSpaceRegion*& region) {
+ if (!region) {
region = (MemSpaceRegion*) A.Allocate<MemSpaceRegion>();
new (region) MemSpaceRegion(this);
}
@@ -251,8 +247,16 @@ StringRegion* MemRegionManager::getStringRegion(const StringLiteral* Str) {
return getRegion<StringRegion>(Str);
}
-VarRegion* MemRegionManager::getVarRegion(const VarDecl* d) {
- return getRegion<VarRegion>(d);
+VarRegion* MemRegionManager::getVarRegion(const VarDecl *D,
+ const LocationContext *LC) {
+
+ // FIXME: Once we implement scope handling, we will need to properly lookup
+ // 'D' to the proper LocationContext. For now, just strip down to the
+ // StackFrame.
+ while (!isa<StackFrameContext>(LC))
+ LC = LC->getParent();
+
+ return getRegion<VarRegion>(D, LC);
}
CompoundLiteralRegion*
@@ -262,7 +266,8 @@ MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr* CL) {
ElementRegion*
MemRegionManager::getElementRegion(QualType elementType, SVal Idx,
- const MemRegion* superRegion, ASTContext& Ctx){
+ const MemRegion* superRegion,
+ ASTContext& Ctx){
QualType T = Ctx.getCanonicalType(elementType);
@@ -282,13 +287,8 @@ MemRegionManager::getElementRegion(QualType elementType, SVal Idx,
return R;
}
-CodeTextRegion* MemRegionManager::getCodeTextRegion(const FunctionDecl* fd,
- QualType t) {
- return getRegion<CodeTextRegion>(fd, t);
-}
-
-CodeTextRegion* MemRegionManager::getCodeTextRegion(SymbolRef sym, QualType t) {
- return getRegion<CodeTextRegion>(sym, t);
+CodeTextRegion *MemRegionManager::getCodeTextRegion(const FunctionDecl *FD) {
+ return getRegion<CodeTextRegion>(FD);
}
/// getSymbolicRegion - Retrieve or create a "symbolic" memory region.
@@ -298,40 +298,34 @@ SymbolicRegion* MemRegionManager::getSymbolicRegion(SymbolRef sym) {
FieldRegion* MemRegionManager::getFieldRegion(const FieldDecl* d,
const MemRegion* superRegion) {
- return getRegion<FieldRegion>(d, superRegion);
+ return getSubRegion<FieldRegion>(d, superRegion);
}
ObjCIvarRegion*
MemRegionManager::getObjCIvarRegion(const ObjCIvarDecl* d,
const MemRegion* superRegion) {
- return getRegion<ObjCIvarRegion>(d, superRegion);
+ return getSubRegion<ObjCIvarRegion>(d, superRegion);
}
ObjCObjectRegion*
MemRegionManager::getObjCObjectRegion(const ObjCInterfaceDecl* d,
const MemRegion* superRegion) {
- return getRegion<ObjCObjectRegion>(d, superRegion);
-}
-
-TypedViewRegion*
-MemRegionManager::getTypedViewRegion(QualType t, const MemRegion* superRegion) {
- return getRegion<TypedViewRegion>(t, superRegion);
+ return getSubRegion<ObjCObjectRegion>(d, superRegion);
}
AllocaRegion* MemRegionManager::getAllocaRegion(const Expr* E, unsigned cnt) {
return getRegion<AllocaRegion>(E, cnt);
}
-
const MemSpaceRegion *MemRegion::getMemorySpace() const {
const MemRegion *R = this;
const SubRegion* SR = dyn_cast<SubRegion>(this);
-
+
while (SR) {
R = SR->getSuperRegion();
SR = dyn_cast<SubRegion>(R);
}
-
+
return dyn_cast<MemSpaceRegion>(R);
}
@@ -371,7 +365,7 @@ bool MemRegion::hasGlobalsStorage() const {
bool MemRegion::hasParametersStorage() const {
if (const MemSpaceRegion *MS = getMemorySpace())
return MS == getMemRegionManager()->getStackArgumentsRegion();
-
+
return false;
}
@@ -388,12 +382,76 @@ bool MemRegion::hasGlobalsOrParametersStorage() const {
// 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);
+const MemRegion *MemRegion::getBaseRegion() const {
+ const MemRegion *R = this;
+ while (true) {
+ if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
+ // FIXME: generalize. Essentially we want to strip away ElementRegions
+ // that were layered on a symbolic region because of casts. We only
+ // want to strip away ElementRegions, however, where the index is 0.
+ SVal index = ER->getIndex();
+ if (nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&index)) {
+ if (CI->getValue().getSExtValue() == 0) {
+ R = ER->getSuperRegion();
+ continue;
+ }
+ }
+ }
+ break;
}
return R;
}
+
+// FIXME: Merge with the implementation of the same method in Store.cpp
+static bool IsCompleteType(ASTContext &Ctx, QualType Ty) {
+ if (const RecordType *RT = Ty->getAs<RecordType>()) {
+ const RecordDecl *D = RT->getDecl();
+ if (!D->getDefinition(Ctx))
+ return false;
+ }
+
+ return true;
+}
+
+RegionRawOffset ElementRegion::getAsRawOffset() const {
+ int64_t offset = 0;
+ const ElementRegion *ER = this;
+ const MemRegion *superR = NULL;
+ ASTContext &C = getContext();
+
+ // FIXME: Handle multi-dimensional arrays.
+
+ while (ER) {
+ superR = ER->getSuperRegion();
+
+ // FIXME: generalize to symbolic offsets.
+ SVal index = ER->getIndex();
+ if (nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&index)) {
+ // Update the offset.
+ int64_t i = CI->getValue().getSExtValue();
+
+ if (i != 0) {
+ QualType elemType = ER->getElementType();
+
+ // If we are pointing to an incomplete type, go no further.
+ if (!IsCompleteType(C, elemType)) {
+ superR = ER;
+ break;
+ }
+
+ int64_t size = (int64_t) (C.getTypeSize(elemType) / 8);
+ offset += (i * size);
+ }
+
+ // Go to the next ElementRegion (if any).
+ ER = dyn_cast<ElementRegion>(superR);
+ continue;
+ }
+
+ return NULL;
+ }
+
+ assert(superR && "super region cannot be NULL");
+ return RegionRawOffset(superR, offset);
+}
+
diff --git a/lib/Analysis/PathDiagnostic.cpp b/lib/Analysis/PathDiagnostic.cpp
index a608ce0..800496a 100644
--- a/lib/Analysis/PathDiagnostic.cpp
+++ b/lib/Analysis/PathDiagnostic.cpp
@@ -27,7 +27,7 @@ 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;
@@ -38,14 +38,14 @@ bool PathDiagnosticMacroPiece::containsEvent() const {
static size_t GetNumCharsToLastNonPeriod(const char *s) {
const char *start = s;
- const char *lastNonPeriod = 0;
+ const char *lastNonPeriod = 0;
for ( ; *s != '\0' ; ++s)
if (*s != '.') lastNonPeriod = s;
-
+
if (!lastNonPeriod)
return 0;
-
+
return (lastNonPeriod - start) + 1;
}
@@ -84,7 +84,7 @@ void PathDiagnostic::resetPath(bool deletePieces) {
if (deletePieces)
for (iterator I=begin(), E=end(); I!=E; ++I)
delete &*I;
-
+
path.clear();
}
@@ -97,7 +97,7 @@ PathDiagnostic::PathDiagnostic(const char* bugtype, const char* desc,
Category(category, GetNumCharsToLastNonPeriod(category)) {}
PathDiagnostic::PathDiagnostic(const std::string& bugtype,
- const std::string& desc,
+ const std::string& desc,
const std::string& category)
: Size(0),
BugType(bugtype, 0, GetNumCharsToLastNonPeriod(bugtype)),
@@ -106,11 +106,11 @@ PathDiagnostic::PathDiagnostic(const std::string& bugtype,
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:
@@ -124,18 +124,18 @@ void PathDiagnosticClient::HandleDiagnostic(Diagnostic::Level DiagLevel,
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);
+ HandlePathDiagnostic(D);
}
//===----------------------------------------------------------------------===//
@@ -155,7 +155,7 @@ FullSourceLoc PathDiagnosticLocation::asLocation() const {
case DeclK:
return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM));
}
-
+
return FullSourceLoc(R.getBegin(), const_cast<SourceManager&>(*SM));
}
@@ -178,7 +178,7 @@ PathDiagnosticRange PathDiagnosticLocation::asRange() const {
if (DS->isSingleDecl()) {
// Should always be the case, but we'll be defensive.
return SourceRange(DS->getLocStart(),
- DS->getSingleDecl()->getLocation());
+ DS->getSingleDecl()->getLocation());
}
break;
}
@@ -197,7 +197,7 @@ PathDiagnosticRange PathDiagnosticLocation::asRange() const {
return SourceRange(L, L);
}
}
-
+
return S->getSourceRange();
}
case DeclK:
@@ -207,7 +207,7 @@ PathDiagnosticRange PathDiagnosticLocation::asRange() const {
// 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 (Stmt *Body = FD->getBody()) {
if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Body))
return CS->getSourceRange();
else
@@ -219,7 +219,7 @@ PathDiagnosticRange PathDiagnosticLocation::asRange() const {
return PathDiagnosticRange(SourceRange(L, L), true);
}
}
-
+
return R;
}
@@ -239,4 +239,66 @@ void PathDiagnosticLocation::flatten() {
}
}
+//===----------------------------------------------------------------------===//
+// FoldingSet profiling methods.
+//===----------------------------------------------------------------------===//
+
+void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddInteger((unsigned) K);
+ switch (K) {
+ case RangeK:
+ ID.AddInteger(R.getBegin().getRawEncoding());
+ ID.AddInteger(R.getEnd().getRawEncoding());
+ break;
+ case SingleLocK:
+ ID.AddInteger(R.getBegin().getRawEncoding());
+ break;
+ case StmtK:
+ ID.Add(S);
+ break;
+ case DeclK:
+ ID.Add(D);
+ break;
+ }
+ return;
+}
+
+void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddInteger((unsigned) getKind());
+ ID.AddString(str);
+ // FIXME: Add profiling support for code hints.
+ ID.AddInteger((unsigned) getDisplayHint());
+ for (range_iterator I = ranges_begin(), E = ranges_end(); I != E; ++I) {
+ ID.AddInteger(I->getBegin().getRawEncoding());
+ ID.AddInteger(I->getEnd().getRawEncoding());
+ }
+}
+void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const {
+ PathDiagnosticPiece::Profile(ID);
+ ID.Add(Pos);
+}
+
+void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const {
+ PathDiagnosticPiece::Profile(ID);
+ for (const_iterator I = begin(), E = end(); I != E; ++I)
+ ID.Add(*I);
+}
+
+void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const {
+ PathDiagnosticSpotPiece::Profile(ID);
+ for (const_iterator I = begin(), E = end(); I != E; ++I)
+ ID.Add(**I);
+}
+
+void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddInteger(Size);
+ ID.AddString(BugType);
+ ID.AddString(Desc);
+ ID.AddString(Category);
+ for (const_iterator I = begin(), E = end(); I != E; ++I)
+ ID.Add(*I);
+
+ for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I)
+ ID.AddString(*I);
+}
diff --git a/lib/Analysis/RangeConstraintManager.cpp b/lib/Analysis/RangeConstraintManager.cpp
index 079462e..73b445e 100644
--- a/lib/Analysis/RangeConstraintManager.cpp
+++ b/lib/Analysis/RangeConstraintManager.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This file defines RangeConstraintManager, a class that tracks simple
+// This file defines RangeConstraintManager, a class that tracks simple
// equality and inequality constraints on symbolic values of GRState.
//
//===----------------------------------------------------------------------===//
@@ -66,7 +66,7 @@ public:
// 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) &&
+ return *lhs.first < *rhs.first || (!(*rhs.first < *lhs.first) &&
*lhs.second < *rhs.second);
}
};
@@ -78,7 +78,7 @@ 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.
+ // to work.
public:
typedef PrimRangeSet::Factory Factory;
typedef PrimRangeSet::iterator iterator;
@@ -88,13 +88,13 @@ public:
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); }
@@ -122,7 +122,7 @@ public:
/// 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) {
@@ -134,11 +134,11 @@ public:
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.
+ // All of the ranges are non-overlapping, so we can stop.
break;
}
}
-
+
return newRanges;
}
@@ -153,7 +153,7 @@ public:
else if (i->To() < V)
newRanges = F.Add(newRanges, *i);
}
-
+
return newRanges;
}
@@ -168,7 +168,7 @@ public:
else if (i->To() <= V)
newRanges = F.Add(newRanges, *i);
}
-
+
return newRanges;
}
@@ -181,7 +181,7 @@ public:
else if (i->From() > V)
newRanges = F.Add(newRanges, *i);
}
-
+
return newRanges;
}
@@ -208,13 +208,13 @@ public:
isFirst = false;
else
os << ", ";
-
+
os << '[' << i->From().toString(10) << ", " << i->To().toString(10)
<< ']';
}
- os << " }";
+ os << " }";
}
-
+
bool operator==(const RangeSet &other) const {
return ranges == other.ranges;
}
@@ -227,13 +227,13 @@ namespace clang {
template<>
struct GRStateTrait<ConstraintRange>
: public GRStatePartialTrait<ConstraintRangeTy> {
- static inline void* GDMIndex() { return &ConstraintRangeIndex; }
+ static inline void* GDMIndex() { return &ConstraintRangeIndex; }
};
-}
-
+}
+
namespace {
class VISIBILITY_HIDDEN RangeConstraintManager : public SimpleConstraintManager{
- RangeSet GetRange(const GRState *state, SymbolRef sym);
+ RangeSet GetRange(const GRState *state, SymbolRef sym);
public:
RangeConstraintManager() {}
@@ -256,7 +256,7 @@ public:
const llvm::APSInt& V);
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);
@@ -265,7 +265,7 @@ public:
const GRState* RemoveDeadBindings(const GRState* St, SymbolReaper& SymReaper);
- void print(const GRState* St, llvm::raw_ostream& Out,
+ void print(const GRState* St, llvm::raw_ostream& Out,
const char* nl, const char *sep);
private:
@@ -294,11 +294,11 @@ RangeConstraintManager::RemoveDeadBindings(const GRState* state,
ConstraintRangeTy::Factory& CRFactory = state->get_context<ConstraintRange>();
for (ConstraintRangeTy::iterator I = CR.begin(), E = CR.end(); I != E; ++I) {
- SymbolRef sym = I.getKey();
+ SymbolRef sym = I.getKey();
if (SymReaper.maybeDead(sym))
CR = CRFactory.Remove(CR, sym);
}
-
+
return state->set<ConstraintRange>(CR);
}
@@ -310,11 +310,11 @@ RangeSet
RangeConstraintManager::GetRange(const GRState *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();
+ BasicValueFactory& BV = state->getBasicVals();
return RangeSet(F, BV.getMinValue(T), BV.getMaxValue(T));
}
@@ -341,16 +341,16 @@ AssumeX(GE)
// Pretty-printing.
//===------------------------------------------------------------------------===/
-void RangeConstraintManager::print(const GRState* St, llvm::raw_ostream& Out,
+void RangeConstraintManager::print(const GRState* St, llvm::raw_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
index 23e8b73..3844d6a 100644
--- a/lib/Analysis/RegionStore.cpp
+++ b/lib/Analysis/RegionStore.cpp
@@ -15,9 +15,11 @@
//
//===----------------------------------------------------------------------===//
#include "clang/Analysis/PathSensitive/MemRegion.h"
+#include "clang/Analysis/PathSensitive/AnalysisContext.h"
#include "clang/Analysis/PathSensitive/GRState.h"
#include "clang/Analysis/PathSensitive/GRStateTrait.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
+#include "clang/Analysis/Support/Optional.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/ImmutableMap.h"
@@ -27,8 +29,57 @@
using namespace clang;
+#define HEAP_UNDEFINED 0
+#define USE_EXPLICIT_COMPOUND 0
+
+namespace {
+class BindingVal {
+public:
+ enum BindingKind { Direct, Default };
+private:
+ SVal Value;
+ BindingKind Kind;
+
+public:
+ BindingVal(SVal V, BindingKind K) : Value(V), Kind(K) {}
+
+ bool isDefault() const { return Kind == Default; }
+
+ const SVal *getValue() const { return &Value; }
+
+ const SVal *getDirectValue() const { return isDefault() ? 0 : &Value; }
+
+ const SVal *getDefaultValue() const { return isDefault() ? &Value : 0; }
+
+ void Profile(llvm::FoldingSetNodeID& ID) const {
+ Value.Profile(ID);
+ ID.AddInteger(Kind);
+ }
+
+ inline bool operator==(const BindingVal& R) const {
+ return Value == R.Value && Kind == R.Kind;
+ }
+
+ inline bool operator!=(const BindingVal& R) const {
+ return !(*this == R);
+ }
+};
+}
+
+namespace llvm {
+static inline
+llvm::raw_ostream& operator<<(llvm::raw_ostream& os, BindingVal V) {
+ if (V.isDefault())
+ os << "(default) ";
+ else
+ os << "(direct) ";
+ os << *V.getValue();
+ return os;
+}
+} // end llvm namespace
+
// Actual Store type.
-typedef llvm::ImmutableMap<const MemRegion*, SVal> RegionBindingsTy;
+typedef llvm::ImmutableMap<const MemRegion*, BindingVal> RegionBindings;
//===----------------------------------------------------------------------===//
// Fine-grained control of RegionStoreManager.
@@ -36,57 +87,27 @@ typedef llvm::ImmutableMap<const MemRegion*, SVal> RegionBindingsTy;
namespace {
struct VISIBILITY_HIDDEN minimal_features_tag {};
-struct VISIBILITY_HIDDEN maximal_features_tag {};
-
+struct VISIBILITY_HIDDEN maximal_features_tag {};
+
class VISIBILITY_HIDDEN RegionStoreFeatures {
bool SupportsFields;
bool SupportsRemaining;
-
+
public:
RegionStoreFeatures(minimal_features_tag) :
SupportsFields(false), SupportsRemaining(false) {}
-
+
RegionStoreFeatures(maximal_features_tag) :
SupportsFields(true), SupportsRemaining(false) {}
-
+
void enableFields(bool t) { SupportsFields = t; }
-
+
bool supportsFields() const { return SupportsFields; }
bool supportsRemaining() const { return SupportsRemaining; }
};
}
//===----------------------------------------------------------------------===//
-// 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"
//===----------------------------------------------------------------------===//
//
@@ -103,19 +124,15 @@ namespace clang {
}
//===----------------------------------------------------------------------===//
-// Regions with default values.
+// Utility functions.
//===----------------------------------------------------------------------===//
-//
-// 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; }
- };
+
+static bool IsAnyPointerOrIntptr(QualType ty, ASTContext &Ctx) {
+ if (ty->isAnyPointerType())
+ return true;
+
+ return ty->isIntegerType() && ty->isScalarType() &&
+ Ctx.getTypeSize(ty) == Ctx.getTypeSize(Ctx.VoidPtrTy);
}
//===----------------------------------------------------------------------===//
@@ -125,87 +142,104 @@ namespace clang {
namespace {
class VISIBILITY_HIDDEN RegionStoreSubRegionMap : public SubRegionMap {
- typedef llvm::DenseMap<const MemRegion*,
- llvm::ImmutableSet<const MemRegion*> > Map;
-
- llvm::ImmutableSet<const MemRegion*>::Factory F;
+ typedef llvm::ImmutableSet<const MemRegion*> SetTy;
+ typedef llvm::DenseMap<const MemRegion*, SetTy> Map;
+ SetTy::Factory F;
Map M;
-
public:
- void add(const MemRegion* Parent, const MemRegion* SubRegion) {
+ bool 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)));
+
+ if (I == M.end()) {
+ M.insert(std::make_pair(Parent, F.Add(F.GetEmptySet(), SubRegion)));
+ return true;
+ }
+
+ I->second = F.Add(I->second, SubRegion);
+ return false;
}
-
+
+ void process(llvm::SmallVectorImpl<const SubRegion*> &WL, const SubRegion *R);
+
~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;
}
-};
+
+ typedef SetTy::iterator iterator;
+
+ std::pair<iterator, iterator> begin_end(const MemRegion *R) {
+ Map::iterator I = M.find(R);
+ SetTy S = I == M.end() ? F.GetEmptySet() : I->second;
+ return std::make_pair(S.begin(), S.end());
+ }
+};
class VISIBILITY_HIDDEN RegionStoreManager : public StoreManager {
const RegionStoreFeatures Features;
- RegionBindingsTy::Factory RBFactory;
- RegionViews::Factory RVFactory;
-
- const MemRegion* SelfRegion;
- const ImplicitParamDecl *SelfDecl;
+ RegionBindings::Factory RBFactory;
+
+ typedef llvm::DenseMap<const GRState *, RegionStoreSubRegionMap*> SMCache;
+ SMCache SC;
public:
- RegionStoreManager(GRStateManager& mgr, const RegionStoreFeatures &f)
+ RegionStoreManager(GRStateManager& mgr, const RegionStoreFeatures &f)
: StoreManager(mgr),
Features(f),
- RBFactory(mgr.getAllocator()),
- RVFactory(mgr.getAllocator()),
- SelfRegion(0), SelfDecl(0) {
- if (const ObjCMethodDecl* MD =
- dyn_cast<ObjCMethodDecl>(&StateMgr.getCodeDecl()))
- SelfDecl = MD->getSelfDecl();
+ RBFactory(mgr.getAllocator()) {}
+
+ virtual ~RegionStoreManager() {
+ for (SMCache::iterator I = SC.begin(), E = SC.end(); I != E; ++I)
+ delete (*I).second;
}
- virtual ~RegionStoreManager() {}
+ SubRegionMap *getSubRegionMap(const GRState *state);
+
+ RegionStoreSubRegionMap *getRegionStoreSubRegionMap(Store store);
+
+ Optional<SVal> getBinding(RegionBindings B, const MemRegion *R);
+ Optional<SVal> getDirectBinding(RegionBindings B, const MemRegion *R);
+ /// getDefaultBinding - Returns an SVal* representing an optional default
+ /// binding associated with a region and its subregions.
+ Optional<SVal> getDefaultBinding(RegionBindings B, const MemRegion *R);
- SubRegionMap* getSubRegionMap(const GRState *state);
-
/// 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 *state, const StringLiteral* S);
+ SVal getLValueString(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 *state, const CompoundLiteralExpr*);
+ SVal getLValueCompoundLiteral(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 *state, const VarDecl* VD);
-
- SVal getLValueIvar(const GRState *state, const ObjCIvarDecl* D, SVal Base);
+ SVal getLValueVar(const VarDecl *VD, const LocationContext *LC);
- SVal getLValueField(const GRState *state, SVal Base, const FieldDecl* D);
-
- SVal getLValueFieldOrIvar(const GRState *state, SVal Base, const Decl* D);
+ SVal getLValueIvar(const ObjCIvarDecl* D, SVal Base);
+
+ SVal getLValueField(const FieldDecl* D, SVal Base);
- SVal getLValueElement(const GRState *state, QualType elementType,
- SVal Base, SVal Offset);
+ SVal getLValueFieldOrIvar(const Decl* D, SVal Base);
+
+ SVal getLValueElement(QualType elementType, SVal Offset, SVal Base);
/// ArrayToPointer - Emulates the "decay" of an array to a pointer
@@ -216,61 +250,52 @@ public:
/// 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, QualType resultTy);
- 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;
+ Store getInitialStore(const LocationContext *InitLoc) {
+ return RBFactory.GetEmptyMap().getRoot();
}
-
+
//===-------------------------------------------------------------------===//
// Binding values to regions.
//===-------------------------------------------------------------------===//
+ const GRState *InvalidateRegion(const GRState *state, const MemRegion *R,
+ const Expr *E, unsigned Count);
+
+private:
+ void RemoveSubRegionBindings(RegionBindings &B, const MemRegion *R,
+ RegionStoreSubRegionMap &M);
+
+public:
const GRState *Bind(const GRState *state, Loc LV, SVal V);
const GRState *BindCompoundLiteral(const GRState *state,
- const CompoundLiteralExpr* CL, SVal V);
-
- const GRState *BindDecl(const GRState *state, const VarDecl* VD, SVal InitVal);
+ const CompoundLiteralExpr* CL, SVal V);
+
+ const GRState *BindDecl(const GRState *ST, const VarDecl *VD,
+ const LocationContext *LC, SVal InitVal);
- const GRState *BindDeclWithNoInit(const GRState *state, const VarDecl* VD) {
+ const GRState *BindDeclWithNoInit(const GRState *state, const VarDecl*,
+ const LocationContext *) {
return state;
}
/// BindStruct - Bind a compound value to a structure.
const GRState *BindStruct(const GRState *, const TypedRegion* R, SVal V);
-
+
const GRState *BindArray(const GRState *state, const TypedRegion* R, SVal V);
-
- /// KillStruct - Set the entire struct to unknown.
- const GRState *KillStruct(const GRState *state, const TypedRegion* R);
- const GRState *setDefaultValue(const GRState *state, const MemRegion* R, SVal V);
+ /// KillStruct - Set the entire struct to unknown.
+ Store KillStruct(Store store, const TypedRegion* R);
Store Remove(Store store, Loc LV);
//===------------------------------------------------------------------===//
// Loading values from regions.
//===------------------------------------------------------------------===//
-
+
/// The high level logic for this method is this:
/// Retrieve (L)
/// if L has binding
@@ -282,55 +307,66 @@ public:
/// return undefined
/// else
/// return symbolic
- SVal Retrieve(const GRState *state, Loc L, QualType T = QualType());
+ SValuator::CastResult Retrieve(const GRState *state, Loc L,
+ QualType T = QualType());
+
+ SVal RetrieveElement(const GRState *state, const ElementRegion *R);
+
+ SVal RetrieveField(const GRState *state, const FieldRegion *R);
+
+ SVal RetrieveObjCIvar(const GRState *state, const ObjCIvarRegion *R);
- SVal RetrieveElement(const GRState* state, const ElementRegion* R);
+ SVal RetrieveVar(const GRState *state, const VarRegion *R);
- SVal RetrieveField(const GRState* state, const FieldRegion* R);
+ SVal RetrieveLazySymbol(const GRState *state, const TypedRegion *R);
+
+ SVal RetrieveFieldOrElementCommon(const GRState *state, const TypedRegion *R,
+ QualType Ty, const MemRegion *superR);
/// Retrieve the values in a struct and return a CompoundVal, used when doing
- /// struct copy:
- /// struct s x, y;
+ /// 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);
+ std::pair<const GRState*, const MemRegion*>
+ GetLazyBinding(RegionBindings B, const MemRegion *R);
+
+ const GRState* CopyLazyBindings(nonloc::LazyCompoundVal V,
+ const GRState *state,
+ const TypedRegion *R);
+
+ const ElementRegion *GetElementZeroRegion(const SymbolicRegion *SR,
+ QualType T);
+
//===------------------------------------------------------------------===//
// State pruning.
//===------------------------------------------------------------------===//
-
+
/// RemoveDeadBindings - Scans the RegionStore of 'state' for dead values.
/// It returns a new Store with these values removed.
- Store RemoveDeadBindings(const GRState *state, Stmt* Loc, SymbolReaper& SymReaper,
+ void RemoveDeadBindings(GRState &state, Stmt* Loc, SymbolReaper& SymReaper,
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots);
+ const GRState *EnterStackFrame(const GRState *state,
+ const StackFrameContext *frame);
+
//===------------------------------------------------------------------===//
// Region "extents".
//===------------------------------------------------------------------===//
-
+
const GRState *setExtent(const GRState *state, const MemRegion* R, SVal Extent);
SVal getSizeInElements(const GRState *state, const MemRegion* R);
//===------------------------------------------------------------------===//
- // Region "views".
- //===------------------------------------------------------------------===//
-
- const GRState *AddRegionView(const GRState *state, const MemRegion* View,
- const MemRegion* Base);
-
- const GRState *RemoveRegionView(const GRState *state, const MemRegion* View,
- const MemRegion* Base);
-
- //===------------------------------------------------------------------===//
// Utility methods.
//===------------------------------------------------------------------===//
-
- const GRState *setCastType(const GRState *state, const MemRegion* R, QualType T);
- static inline RegionBindingsTy GetRegionBindings(Store store) {
- return RegionBindingsTy(static_cast<const RegionBindingsTy::TreeTy*>(store));
+ static inline RegionBindings GetRegionBindings(Store store) {
+ return RegionBindings(static_cast<const RegionBindings::TreeTy*>(store));
}
void print(Store store, llvm::raw_ostream& Out, const char* nl,
@@ -344,7 +380,7 @@ public:
BasicValueFactory& getBasicVals() {
return StateMgr.getBasicVals();
}
-
+
// FIXME: Remove.
ASTContext& getContext() { return StateMgr.getContext(); }
};
@@ -366,18 +402,155 @@ StoreManager *clang::CreateFieldsOnlyRegionStoreManager(GRStateManager &StMgr) {
return new RegionStoreManager(StMgr, F);
}
-SubRegionMap* RegionStoreManager::getSubRegionMap(const GRState *state) {
- RegionBindingsTy B = GetRegionBindings(state->getStore());
+void
+RegionStoreSubRegionMap::process(llvm::SmallVectorImpl<const SubRegion*> &WL,
+ const SubRegion *R) {
+ const MemRegion *superR = R->getSuperRegion();
+ if (add(superR, R))
+ if (const SubRegion *sr = dyn_cast<SubRegion>(superR))
+ WL.push_back(sr);
+}
+
+RegionStoreSubRegionMap*
+RegionStoreManager::getRegionStoreSubRegionMap(Store store) {
+ RegionBindings B = GetRegionBindings(store);
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);
+
+ llvm::SmallVector<const SubRegion*, 10> WL;
+
+ for (RegionBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I)
+ if (const SubRegion *R = dyn_cast<SubRegion>(I.getKey()))
+ M->process(WL, R);
+
+ // We also need to record in the subregion map "intermediate" regions that
+ // don't have direct bindings but are super regions of those that do.
+ while (!WL.empty()) {
+ const SubRegion *R = WL.back();
+ WL.pop_back();
+ M->process(WL, R);
}
-
+
return M;
}
+SubRegionMap *RegionStoreManager::getSubRegionMap(const GRState *state) {
+ return getRegionStoreSubRegionMap(state->getStore());
+}
+
+//===----------------------------------------------------------------------===//
+// Binding invalidation.
+//===----------------------------------------------------------------------===//
+
+void RegionStoreManager::RemoveSubRegionBindings(RegionBindings &B,
+ const MemRegion *R,
+ RegionStoreSubRegionMap &M) {
+ RegionStoreSubRegionMap::iterator I, E;
+
+ for (llvm::tie(I, E) = M.begin_end(R); I != E; ++I)
+ RemoveSubRegionBindings(B, *I, M);
+
+ B = RBFactory.Remove(B, R);
+}
+
+const GRState *RegionStoreManager::InvalidateRegion(const GRState *state,
+ const MemRegion *R,
+ const Expr *Ex,
+ unsigned Count) {
+ ASTContext& Ctx = StateMgr.getContext();
+
+ // Strip away casts.
+ R = R->getBaseRegion();
+
+ // Get the mapping of regions -> subregions.
+ llvm::OwningPtr<RegionStoreSubRegionMap>
+ SubRegions(getRegionStoreSubRegionMap(state->getStore()));
+
+ RegionBindings B = GetRegionBindings(state->getStore());
+
+ llvm::DenseMap<const MemRegion *, unsigned> Visited;
+ llvm::SmallVector<const MemRegion *, 10> WorkList;
+ WorkList.push_back(R);
+
+ while (!WorkList.empty()) {
+ R = WorkList.back();
+ WorkList.pop_back();
+
+ // Have we visited this region before?
+ unsigned &visited = Visited[R];
+ if (visited)
+ continue;
+ visited = 1;
+
+ // Add subregions to work list.
+ RegionStoreSubRegionMap::iterator I, E;
+ for (llvm::tie(I, E) = SubRegions->begin_end(R); I!=E; ++I)
+ WorkList.push_back(*I);
+
+ // Get the old binding. Is it a region? If so, add it to the worklist.
+ if (Optional<SVal> V = getDirectBinding(B, R)) {
+ if (const MemRegion *RV = V->getAsRegion())
+ WorkList.push_back(RV);
+ }
+
+ // Handle region.
+ if (isa<AllocaRegion>(R) || isa<SymbolicRegion>(R) ||
+ isa<ObjCObjectRegion>(R)) {
+ // Invalidate the region by setting its default value to
+ // conjured symbol. The type of the symbol is irrelavant.
+ DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, Ctx.IntTy,
+ Count);
+ B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default));
+ continue;
+ }
+
+ if (!R->isBoundable())
+ continue;
+
+ const TypedRegion *TR = cast<TypedRegion>(R);
+ QualType T = TR->getValueType(Ctx);
+
+ if (const RecordType *RT = T->getAsStructureType()) {
+ const RecordDecl *RD = RT->getDecl()->getDefinition(Ctx);
+
+ // No record definition. There is nothing we can do.
+ if (!RD)
+ continue;
+
+ // Invalidate the region by setting its default value to
+ // conjured symbol. The type of the symbol is irrelavant.
+ DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, Ctx.IntTy,
+ Count);
+ B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default));
+ continue;
+ }
+
+ if (const ArrayType *AT = Ctx.getAsArrayType(T)) {
+ // Set the default value of the array to conjured symbol.
+ DefinedOrUnknownSVal V =
+ ValMgr.getConjuredSymbolVal(R, Ex, AT->getElementType(), Count);
+ B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default));
+ continue;
+ }
+
+ if ((isa<FieldRegion>(R)||isa<ElementRegion>(R)||isa<ObjCIvarRegion>(R))
+ && Visited[cast<SubRegion>(R)->getSuperRegion()]) {
+ // For fields and elements whose super region has also been invalidated,
+ // only remove the old binding. The super region will get set with a
+ // default value from which we can lazily derive a new symbolic value.
+ B = RBFactory.Remove(B, R);
+ continue;
+ }
+
+ // Invalidate the binding.
+ DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, T, Count);
+ assert(SymbolManager::canSymbolicate(T) || V.isUnknown());
+ B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Direct));
+ }
+
+ // Create a new state with the updated bindings.
+ return state->makeWithStore(B.getRoot());
+}
+
//===----------------------------------------------------------------------===//
// getLValueXXX methods.
//===----------------------------------------------------------------------===//
@@ -386,40 +559,36 @@ SubRegionMap* RegionStoreManager::getSubRegionMap(const GRState *state) {
/// 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) {
+SVal RegionStoreManager::getLValueString(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));
+SVal RegionStoreManager::getLValueVar(const VarDecl *VD,
+ const LocationContext *LC) {
+ return loc::MemRegionVal(MRMgr.getVarRegion(VD, LC));
}
/// 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) {
+SVal
+RegionStoreManager::getLValueCompoundLiteral(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::getLValueIvar(const ObjCIvarDecl* D, SVal Base) {
+ return getLValueFieldOrIvar(D, Base);
}
-SVal RegionStoreManager::getLValueField(const GRState *St, SVal Base,
- const FieldDecl* D) {
- return getLValueFieldOrIvar(St, Base, D);
+SVal RegionStoreManager::getLValueField(const FieldDecl* D, SVal Base) {
+ return getLValueFieldOrIvar(D, Base);
}
-SVal RegionStoreManager::getLValueFieldOrIvar(const GRState *St, SVal Base,
- const Decl* D) {
+SVal RegionStoreManager::getLValueFieldOrIvar(const Decl* D, SVal Base) {
if (Base.isUnknownOrUndef())
return Base;
@@ -446,7 +615,7 @@ SVal RegionStoreManager::getLValueFieldOrIvar(const GRState *St, SVal Base,
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))
@@ -455,9 +624,8 @@ SVal RegionStoreManager::getLValueFieldOrIvar(const GRState *St, SVal Base,
return loc::MemRegionVal(MRMgr.getFieldRegion(cast<FieldDecl>(D), BaseR));
}
-SVal RegionStoreManager::getLValueElement(const GRState *St,
- QualType elementType,
- SVal Base, SVal Offset) {
+SVal RegionStoreManager::getLValueElement(QualType elementType, SVal Offset,
+ SVal Base) {
// 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
@@ -474,7 +642,10 @@ SVal RegionStoreManager::getLValueElement(const GRState *St,
// Pointer of any type can be cast and used as array base.
const ElementRegion *ElemR = dyn_cast<ElementRegion>(BaseRegion);
-
+
+ // Convert the offset to the appropriate size and signedness.
+ Offset = ValMgr.convertToArrayIndex(Offset);
+
if (!ElemR) {
//
// If the base region is not an ElementRegion, create one.
@@ -485,54 +656,26 @@ SVal RegionStoreManager::getLValueElement(const GRState *St,
//
// 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 = ValMgr.makeIntVal(Tmp);
- }
- }
return loc::MemRegionVal(MRMgr.getElementRegion(elementType, Offset,
BaseRegion, getContext()));
}
-
+
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 = ValMgr.makeIntVal(Tmp);
- }
- else
- NewIdx = nonloc::ConcreteInt(getBasicVals().getValue(BaseIdxI + OffI));
+ // Compute the new index.
+ SVal NewIdx = nonloc::ConcreteInt(getBasicVals().getValue(BaseIdxI + OffI));
+ // Construct the new ElementRegion.
+ const MemRegion *ArrayR = ElemR->getSuperRegion();
return loc::MemRegionVal(MRMgr.getElementRegion(elementType, NewIdx, ArrayR,
- getContext()));
+ getContext()));
}
//===----------------------------------------------------------------------===//
@@ -540,64 +683,62 @@ SVal RegionStoreManager::getLValueElement(const GRState *St,
//===----------------------------------------------------------------------===//
SVal RegionStoreManager::getSizeInElements(const GRState *state,
- const MemRegion* R) {
- if (const VarRegion* VR = dyn_cast<VarRegion>(R)) {
- // Get the type of the variable.
- QualType T = VR->getDesugaredValueType(getContext());
+ const MemRegion *R) {
- // FIXME: Handle variable-length arrays.
- if (isa<VariableArrayType>(T))
+ switch (R->getKind()) {
+ case MemRegion::MemSpaceRegionKind:
+ assert(0 && "Cannot index into a MemSpace");
return UnknownVal();
-
- if (const ConstantArrayType* CAT = dyn_cast<ConstantArrayType>(T)) {
- // return the size as signed integer.
- return ValMgr.makeIntVal(CAT->getSize(), false);
- }
- 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);
- assert(VarSize != 0);
- return ValMgr.makeIntVal(VarSize/EleSize, false);
- }
+ case MemRegion::CodeTextRegionKind:
+ // Technically this can happen if people do funny things with casts.
+ return UnknownVal();
- // Clients can use ordinary variables as if they were arrays. These
- // essentially are arrays of size 1.
- return ValMgr.makeIntVal(1, false);
- }
+ // Not yet handled.
+ case MemRegion::AllocaRegionKind:
+ case MemRegion::CompoundLiteralRegionKind:
+ case MemRegion::ElementRegionKind:
+ case MemRegion::FieldRegionKind:
+ case MemRegion::ObjCIvarRegionKind:
+ case MemRegion::ObjCObjectRegionKind:
+ case MemRegion::SymbolicRegionKind:
+ return UnknownVal();
- 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 ValMgr.makeIntVal(Str->getByteLength()+1, false);
- }
+ case MemRegion::StringRegionKind: {
+ const StringLiteral* Str = cast<StringRegion>(R)->getStringLiteral();
+ // We intentionally made the size value signed because it participates in
+ // operations with signed indices.
+ return ValMgr.makeIntVal(Str->getByteLength()+1, false);
+ }
- if (const FieldRegion* FR = dyn_cast<FieldRegion>(R)) {
- // FIXME: Unsupported yet.
- FR = 0;
- return UnknownVal();
- }
+ case MemRegion::VarRegionKind: {
+ const VarRegion* VR = cast<VarRegion>(R);
+ // Get the type of the variable.
+ QualType T = VR->getDesugaredValueType(getContext());
- if (isa<SymbolicRegion>(R)) {
- return UnknownVal();
- }
+ // FIXME: Handle variable-length arrays.
+ if (isa<VariableArrayType>(T))
+ return UnknownVal();
- if (isa<AllocaRegion>(R)) {
- return UnknownVal();
- }
+ if (const ConstantArrayType* CAT = dyn_cast<ConstantArrayType>(T)) {
+ // return the size as signed integer.
+ return ValMgr.makeIntVal(CAT->getSize(), false);
+ }
- if (isa<ElementRegion>(R)) {
- return UnknownVal();
+ // Clients can use ordinary variables as if they were arrays. These
+ // essentially are arrays of size 1.
+ return ValMgr.makeIntVal(1, false);
+ }
+
+ case MemRegion::BEG_DECL_REGIONS:
+ case MemRegion::END_DECL_REGIONS:
+ case MemRegion::BEG_TYPED_REGIONS:
+ case MemRegion::END_TYPED_REGIONS:
+ assert(0 && "Infeasible region");
+ return UnknownVal();
}
- assert(0 && "Other regions are not supported yet.");
+ assert(0 && "Unreachable");
return UnknownVal();
}
@@ -620,105 +761,29 @@ const GRState *RegionStoreManager::setExtent(const GRState *state,
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();
+ 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, getContext());
-
- 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 (ToTy->isObjCQualifiedIdType()) {
- // 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()
- || (CastToTy->isPointerType()
- && CastToTy->getAsPointerType()->getPointeeType()->isVoidType()));
- 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()) ||
- ObjTySize == 0 /* R has 'void*' type. */) {
- // Record the cast type of the region.
- state = setCastType(state, R, ToTy);
-
- SVal Idx = ValMgr.makeZeroArrayIndex();
- ElementRegion* ER = MRMgr.getElementRegion(PointeeTy, Idx,R,getContext());
- return CastResult(state, ER);
- } else {
- state = setCastType(state, R, ToTy);
- return CastResult(state, R);
- }
- }
- if (isa<ObjCObjectRegion>(R)) {
- return CastResult(state, R);
- }
+ SVal ZeroIdx = ValMgr.makeZeroArrayIndex();
+ ElementRegion* ER = MRMgr.getElementRegion(T, ZeroIdx, ArrayR, getContext());
- assert(0 && "Unprocessed region.");
- return 0;
+ return loc::MemRegionVal(ER);
}
//===----------------------------------------------------------------------===//
// Pointer arithmetic.
//===----------------------------------------------------------------------===//
-SVal RegionStoreManager::EvalBinOp(const GRState *state,
+SVal RegionStoreManager::EvalBinOp(const GRState *state,
BinaryOperator::Opcode Op, Loc L, NonLoc R,
QualType resultTy) {
// Assume the base location is MemRegionVal.
@@ -728,64 +793,89 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state,
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)) {
- QualType T;
- // If the SymbolicRegion was cast to another type, use that type.
- if (const QualType *t = state->get<RegionCasts>(SR)) {
- T = *t;
- } else {
- // Otherwise use the symbol's type.
+ switch (MR->getKind()) {
+ case MemRegion::SymbolicRegionKind: {
+ const SymbolicRegion *SR = cast<SymbolicRegion>(MR);
SymbolRef Sym = SR->getSymbol();
- T = Sym->getType(getContext());
+ QualType T = Sym->getType(getContext());
+ QualType EleTy;
+
+ if (const PointerType *PT = T->getAs<PointerType>())
+ EleTy = PT->getPointeeType();
+ else
+ EleTy = T->getAs<ObjCObjectPointerType>()->getPointeeType();
+
+ SVal ZeroIdx = ValMgr.makeZeroArrayIndex();
+ ER = MRMgr.getElementRegion(EleTy, ZeroIdx, SR, getContext());
+ break;
+ }
+ case MemRegion::AllocaRegionKind: {
+ const AllocaRegion *AR = cast<AllocaRegion>(MR);
+ QualType T = getContext().CharTy; // Create an ElementRegion of bytes.
+ QualType EleTy = T->getAs<PointerType>()->getPointeeType();
+ SVal ZeroIdx = ValMgr.makeZeroArrayIndex();
+ ER = MRMgr.getElementRegion(EleTy, ZeroIdx, AR, getContext());
+ break;
}
- QualType EleTy = T->getAsPointerType()->getPointeeType();
- SVal ZeroIdx = ValMgr.makeZeroArrayIndex();
- ER = MRMgr.getElementRegion(EleTy, ZeroIdx, SR, getContext());
- }
- else if (const AllocaRegion *AR = dyn_cast<AllocaRegion>(MR)) {
- // Get the alloca region's current cast type.
+ case MemRegion::ElementRegionKind: {
+ ER = cast<ElementRegion>(MR);
+ break;
+ }
+ // Not yet handled.
+ case MemRegion::VarRegionKind:
+ case MemRegion::StringRegionKind: {
+
+ }
+ // Fall-through.
+ case MemRegion::CompoundLiteralRegionKind:
+ case MemRegion::FieldRegionKind:
+ case MemRegion::ObjCObjectRegionKind:
+ case MemRegion::ObjCIvarRegionKind:
+ return UnknownVal();
- GRStateTrait<RegionCasts>::lookup_type T = state->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, getContext());
- }
- else if (isa<FieldRegion>(MR)) {
- // Not track pointer arithmetic on struct fields.
- return UnknownVal();
- }
- else {
- ER = cast<ElementRegion>(MR);
+ case MemRegion::CodeTextRegionKind:
+ // Technically this can happen if people do funny things with casts.
+ return UnknownVal();
+
+ case MemRegion::MemSpaceRegionKind:
+ assert(0 && "Cannot perform pointer arithmetic on a MemSpace");
+ return UnknownVal();
+
+ case MemRegion::BEG_DECL_REGIONS:
+ case MemRegion::END_DECL_REGIONS:
+ case MemRegion::BEG_TYPED_REGIONS:
+ case MemRegion::END_TYPED_REGIONS:
+ assert(0 && "Infeasible region");
+ return UnknownVal();
}
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(ValMgr, Op, OffConverted);
- const MemRegion* NewER =
- MRMgr.getElementRegion(ER->getElementType(), NewIdx,ER->getSuperRegion(),
- getContext());
- return ValMgr.makeLoc(NewER);
+ // For now, only support:
+ // (a) concrete integer indices that can easily be resolved
+ // (b) 0 + symbolic index
+ if (Base) {
+ if (nonloc::ConcreteInt *Offset = dyn_cast<nonloc::ConcreteInt>(&R)) {
+ // FIXME: Should use SValuator here.
+ SVal NewIdx =
+ Base->evalBinOp(ValMgr, Op,
+ cast<nonloc::ConcreteInt>(ValMgr.convertToArrayIndex(*Offset)));
+ const MemRegion* NewER =
+ MRMgr.getElementRegion(ER->getElementType(), NewIdx,
+ ER->getSuperRegion(), getContext());
+ return ValMgr.makeLoc(NewER);
+ }
+ if (0 == Base->getValue()) {
+ const MemRegion* NewER =
+ MRMgr.getElementRegion(ER->getElementType(), R,
+ ER->getSuperRegion(), getContext());
+ return ValMgr.makeLoc(NewER);
+ }
}
-
+
return UnknownVal();
}
@@ -793,7 +883,71 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state,
// Loading values from regions.
//===----------------------------------------------------------------------===//
-SVal RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
+Optional<SVal> RegionStoreManager::getDirectBinding(RegionBindings B,
+ const MemRegion *R) {
+ if (const BindingVal *BV = B.lookup(R))
+ return Optional<SVal>::create(BV->getDirectValue());
+
+ return Optional<SVal>();
+}
+
+Optional<SVal> RegionStoreManager::getDefaultBinding(RegionBindings B,
+ const MemRegion *R) {
+
+ if (R->isBoundable())
+ if (const TypedRegion *TR = dyn_cast<TypedRegion>(R))
+ if (TR->getValueType(getContext())->isUnionType())
+ return UnknownVal();
+
+ if (BindingVal const *V = B.lookup(R))
+ return Optional<SVal>::create(V->getDefaultValue());
+
+ return Optional<SVal>();
+}
+
+Optional<SVal> RegionStoreManager::getBinding(RegionBindings B,
+ const MemRegion *R) {
+ if (const BindingVal *BV = B.lookup(R))
+ return Optional<SVal>::create(BV->getValue());
+
+ return Optional<SVal>();
+}
+
+static bool IsReinterpreted(QualType RTy, QualType UsedTy, ASTContext &Ctx) {
+ RTy = Ctx.getCanonicalType(RTy);
+ UsedTy = Ctx.getCanonicalType(UsedTy);
+
+ if (RTy == UsedTy)
+ return false;
+
+
+ // Recursively check the types. We basically want to see if a pointer value
+ // is ever reinterpreted as a non-pointer, e.g. void** and intptr_t*
+ // represents a reinterpretation.
+ if (Loc::IsLocType(RTy) && Loc::IsLocType(UsedTy)) {
+ const PointerType *PRTy = RTy->getAs<PointerType>();
+ const PointerType *PUsedTy = UsedTy->getAs<PointerType>();
+
+ return PUsedTy && PRTy &&
+ IsReinterpreted(PRTy->getPointeeType(),
+ PUsedTy->getPointeeType(), Ctx);
+ }
+
+ return true;
+}
+
+const ElementRegion *
+RegionStoreManager::GetElementZeroRegion(const SymbolicRegion *SR, QualType T) {
+ ASTContext &Ctx = getContext();
+ SVal idx = ValMgr.makeZeroArrayIndex();
+ assert(!T.isNull());
+ return MRMgr.getElementRegion(T, idx, SR, Ctx);
+}
+
+
+
+SValuator::CastResult
+RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
assert(!isa<UnknownVal>(L) && "location unknown");
assert(!isa<UndefinedVal>(L) && "location undefined");
@@ -801,7 +955,7 @@ SVal RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
// 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();
+ return SValuator::CastResult(state, UndefinedVal());
const MemRegion *MR = cast<loc::MemRegionVal>(L).getRegion();
@@ -811,13 +965,19 @@ SVal RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
// char* p = alloca();
// read(p);
// c = *p;
- if (isa<SymbolicRegion>(MR) || isa<AllocaRegion>(MR))
- return UnknownVal();
+ if (isa<AllocaRegion>(MR))
+ return SValuator::CastResult(state, UnknownVal());
+
+ if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(MR))
+ MR = GetElementZeroRegion(SR, T);
+
+ if (isa<CodeTextRegion>(MR))
+ return SValuator::CastResult(state, 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");
+ QualType RTy = R->getValueType(getContext());
// FIXME: We should eventually handle funny addressing. e.g.:
//
@@ -828,197 +988,319 @@ SVal RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
//
// Such funny addressing will occur due to layering of regions.
- QualType RTy = R->getValueType(getContext());
+#if 0
+ ASTContext &Ctx = getContext();
+ if (!T.isNull() && IsReinterpreted(RTy, T, Ctx)) {
+ SVal ZeroIdx = ValMgr.makeZeroArrayIndex();
+ R = MRMgr.getElementRegion(T, ZeroIdx, R, Ctx);
+ RTy = T;
+ assert(Ctx.getCanonicalType(RTy) ==
+ Ctx.getCanonicalType(R->getValueType(Ctx)));
+ }
+#endif
if (RTy->isStructureType())
- return RetrieveStruct(state, R);
+ return SValuator::CastResult(state, RetrieveStruct(state, R));
+
+ // FIXME: Handle unions.
+ if (RTy->isUnionType())
+ return SValuator::CastResult(state, UnknownVal());
if (RTy->isArrayType())
- return RetrieveArray(state, R);
+ return SValuator::CastResult(state, RetrieveArray(state, R));
// FIXME: handle Vector types.
if (RTy->isVectorType())
- return UnknownVal();
+ return SValuator::CastResult(state, UnknownVal());
if (const FieldRegion* FR = dyn_cast<FieldRegion>(R))
- return RetrieveField(state, FR);
+ return CastRetrievedVal(RetrieveField(state, FR), state, FR, T);
if (const ElementRegion* ER = dyn_cast<ElementRegion>(R))
- return RetrieveElement(state, ER);
-
- RegionBindingsTy B = GetRegionBindings(state->getStore());
- RegionBindingsTy::data_type* V = B.lookup(R);
+ return CastRetrievedVal(RetrieveElement(state, ER), state, ER, T);
- // Check if the region has a binding.
- if (V)
- return *V;
+ if (const ObjCIvarRegion *IVR = dyn_cast<ObjCIvarRegion>(R))
+ return CastRetrievedVal(RetrieveObjCIvar(state, IVR), state, IVR, T);
- if (const ObjCIvarRegion *IVR = dyn_cast<ObjCIvarRegion>(R)) {
- const MemRegion *SR = IVR->getSuperRegion();
+ if (const VarRegion *VR = dyn_cast<VarRegion>(R))
+ return CastRetrievedVal(RetrieveVar(state, VR), state, VR, T);
- // 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();
- }
+ RegionBindings B = GetRegionBindings(state->getStore());
+ RegionBindings::data_type* V = B.lookup(R);
+
+ // Check if the region has a binding.
+ if (V)
+ if (SVal const *SV = V->getValue())
+ return SValuator::CastResult(state, *SV);
// 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 (VR->hasGlobalsOrParametersStorage())
- return ValMgr.getRegionValueSymbolValOrUnknown(VR, VD->getType());
- }
-
+#if HEAP_UNDEFINED
if (R->hasHeapOrStackStorage()) {
+#else
+ if (R->hasStackStorage()) {
+#endif
// 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();
+ return SValuator::CastResult(state, UndefinedVal());
+ }
+
+ // All other values are symbolic.
+ return SValuator::CastResult(state,
+ ValMgr.getRegionValueSymbolValOrUnknown(R, RTy));
+}
+
+std::pair<const GRState*, const MemRegion*>
+RegionStoreManager::GetLazyBinding(RegionBindings B, const MemRegion *R) {
+ if (Optional<SVal> OV = getDirectBinding(B, R))
+ if (const nonloc::LazyCompoundVal *V =
+ dyn_cast<nonloc::LazyCompoundVal>(OV.getPointer()))
+ return std::make_pair(V->getState(), V->getRegion());
+
+ if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
+ const std::pair<const GRState *, const MemRegion *> &X =
+ GetLazyBinding(B, ER->getSuperRegion());
+
+ if (X.first)
+ return std::make_pair(X.first,
+ MRMgr.getElementRegionWithSuper(ER, X.second));
}
+ else if (const FieldRegion *FR = dyn_cast<FieldRegion>(R)) {
+ const std::pair<const GRState *, const MemRegion *> &X =
+ GetLazyBinding(B, FR->getSuperRegion());
- // If the region is already cast to another type, use that type to create the
- // symbol value.
- if (const QualType *p = state->get<RegionCasts>(R)) {
- QualType T = *p;
- RTy = T->getAsPointerType()->getPointeeType();
+ if (X.first)
+ return std::make_pair(X.first,
+ MRMgr.getFieldRegionWithSuper(FR, X.second));
}
- // All other values are symbolic.
- return ValMgr.getRegionValueSymbolValOrUnknown(R, RTy);
+ return std::make_pair((const GRState*) 0, (const MemRegion *) 0);
}
SVal RegionStoreManager::RetrieveElement(const GRState* state,
const ElementRegion* R) {
// Check if the region has a binding.
- RegionBindingsTy B = GetRegionBindings(state->getStore());
- if (const SVal* V = B.lookup(R))
+ RegionBindings B = GetRegionBindings(state->getStore());
+ if (Optional<SVal> V = getDirectBinding(B, R))
return *V;
const MemRegion* superR = R->getSuperRegion();
// Check if the region is an element region of a string literal.
if (const StringRegion *StrR=dyn_cast<StringRegion>(superR)) {
+ // FIXME: Handle loads from strings where the literal is treated as
+ // an integer, e.g., *((unsigned int*)"hello")
+ ASTContext &Ctx = getContext();
+ QualType T = StrR->getValueType(Ctx)->getAs<ArrayType>()->getElementType();
+ if (T != Ctx.getCanonicalType(R->getElementType()))
+ return UnknownVal();
+
const StringLiteral *Str = StrR->getStringLiteral();
SVal Idx = R->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];
- return ValMgr.makeIntVal(c, getContext().CharTy);
+ int64_t byteLength = Str->getByteLength();
+ if (i > byteLength) {
+ // Buffer overflow checking in GRExprEngine should handle this case,
+ // but we shouldn't rely on it to not overflow here if that checking
+ // is disabled.
+ return UnknownVal();
+ }
+ char c = (i == byteLength) ? '\0' : Str->getStrData()[i];
+ return ValMgr.makeIntVal(c, T);
}
}
- // Check if the super region has a default value.
- if (const SVal *D = state->get<RegionDefaultValue>(superR)) {
- if (D->hasConjuredSymbol())
- return ValMgr.getRegionValueSymbolVal(R);
- else
- return *D;
+ // Special case: the current region represents a cast and it and the super
+ // region both have pointer types or intptr_t types. If so, perform the
+ // retrieve from the super region and appropriately "cast" the value.
+ // This is needed to support OSAtomicCompareAndSwap and friends or other
+ // loads that treat integers as pointers and vis versa.
+ if (R->getIndex().isZeroConstant()) {
+ if (const TypedRegion *superTR = dyn_cast<TypedRegion>(superR)) {
+ ASTContext &Ctx = getContext();
+ if (IsAnyPointerOrIntptr(superTR->getValueType(Ctx), Ctx)) {
+ QualType valTy = R->getValueType(Ctx);
+ if (IsAnyPointerOrIntptr(valTy, Ctx)) {
+ // Retrieve the value from the super region. This will be casted to
+ // valTy when we return to 'Retrieve'.
+ const SValuator::CastResult &cr = Retrieve(state,
+ loc::MemRegionVal(superR),
+ valTy);
+ return cr.getSVal();
+ }
+ }
+ }
}
- // Check if the super region has a binding.
- if (B.lookup(superR)) {
- // We do not extract the bit value from super region for now.
+ // Check if the immediate super region has a direct binding.
+ if (Optional<SVal> V = getDirectBinding(B, superR)) {
+ if (SymbolRef parentSym = V->getAsSymbol())
+ return ValMgr.getDerivedRegionValueSymbolVal(parentSym, R);
+
+ if (V->isUnknownOrUndef())
+ return *V;
+
+ // Handle LazyCompoundVals for the immediate super region. Other cases
+ // are handled in 'RetrieveFieldOrElementCommon'.
+ if (const nonloc::LazyCompoundVal *LCV =
+ dyn_cast<nonloc::LazyCompoundVal>(V)) {
+
+ R = MRMgr.getElementRegionWithSuper(R, LCV->getRegion());
+ return RetrieveElement(LCV->getState(), R);
+ }
+
+ // Other cases: give up.
return UnknownVal();
}
- if (R->hasHeapStorage()) {
- // FIXME: If the region has heap storage and we know nothing special
- // about its bindings, should we instead return UnknownVal? Seems like
- // we should only return UndefinedVal in the cases where we know the value
- // will be undefined.
- return UndefinedVal();
+ return RetrieveFieldOrElementCommon(state, R, R->getElementType(), superR);
+}
+
+SVal RegionStoreManager::RetrieveField(const GRState* state,
+ const FieldRegion* R) {
+
+ // Check if the region has a binding.
+ RegionBindings B = GetRegionBindings(state->getStore());
+ if (Optional<SVal> V = getDirectBinding(B, R))
+ return *V;
+
+ QualType Ty = R->getValueType(getContext());
+ return RetrieveFieldOrElementCommon(state, R, Ty, R->getSuperRegion());
+}
+
+SVal RegionStoreManager::RetrieveFieldOrElementCommon(const GRState *state,
+ const TypedRegion *R,
+ QualType Ty,
+ const MemRegion *superR) {
+
+ // At this point we have already checked in either RetrieveElement or
+ // RetrieveField if 'R' has a direct binding.
+
+ RegionBindings B = GetRegionBindings(state->getStore());
+
+ while (superR) {
+ if (const Optional<SVal> &D = getDefaultBinding(B, superR)) {
+ if (SymbolRef parentSym = D->getAsSymbol())
+ return ValMgr.getDerivedRegionValueSymbolVal(parentSym, R);
+
+ if (D->isZeroConstant())
+ return ValMgr.makeZeroVal(Ty);
+
+ if (D->isUnknown())
+ return *D;
+
+ assert(0 && "Unknown default value");
+ }
+
+ // If our super region is a field or element itself, walk up the region
+ // hierarchy to see if there is a default value installed in an ancestor.
+ if (isa<FieldRegion>(superR) || isa<ElementRegion>(superR)) {
+ superR = cast<SubRegion>(superR)->getSuperRegion();
+ continue;
+ }
+
+ break;
+ }
+
+ // Lazy binding?
+ const GRState *lazyBindingState = NULL;
+ const MemRegion *lazyBindingRegion = NULL;
+ llvm::tie(lazyBindingState, lazyBindingRegion) = GetLazyBinding(B, R);
+
+ if (lazyBindingState) {
+ assert(lazyBindingRegion && "Lazy-binding region not set");
+
+ if (isa<ElementRegion>(R))
+ return RetrieveElement(lazyBindingState,
+ cast<ElementRegion>(lazyBindingRegion));
+
+ return RetrieveField(lazyBindingState,
+ cast<FieldRegion>(lazyBindingRegion));
}
if (R->hasStackStorage() && !R->hasParametersStorage()) {
- // Currently we don't reason specially about Clang-style vectors. Check
- // if superR is a vector and if so return Unknown.
- if (const TypedRegion *typedSuperR = dyn_cast<TypedRegion>(superR)) {
- if (typedSuperR->getValueType(getContext())->isVectorType())
- return UnknownVal();
+
+ if (isa<ElementRegion>(R)) {
+ // Currently we don't reason specially about Clang-style vectors. Check
+ // if superR is a vector and if so return Unknown.
+ if (const TypedRegion *typedSuperR = dyn_cast<TypedRegion>(superR)) {
+ if (typedSuperR->getValueType(getContext())->isVectorType())
+ return UnknownVal();
+ }
}
return UndefinedVal();
}
- QualType Ty = R->getValueType(getContext());
+ // All other values are symbolic.
+ return ValMgr.getRegionValueSymbolValOrUnknown(R, Ty);
+}
- // If the region is already cast to another type, use that type to create the
- // symbol value.
- if (const QualType *p = state->get<RegionCasts>(R))
- Ty = (*p)->getAsPointerType()->getPointeeType();
+SVal RegionStoreManager::RetrieveObjCIvar(const GRState* state,
+ const ObjCIvarRegion* R) {
- return ValMgr.getRegionValueSymbolValOrUnknown(R, Ty);
+ // Check if the region has a binding.
+ RegionBindings B = GetRegionBindings(state->getStore());
+
+ if (Optional<SVal> V = getDirectBinding(B, R))
+ return *V;
+
+ const MemRegion *superR = R->getSuperRegion();
+
+ // Check if the super region has a binding.
+ if (Optional<SVal> V = getDirectBinding(B, superR)) {
+ if (SymbolRef parentSym = V->getAsSymbol())
+ return ValMgr.getDerivedRegionValueSymbolVal(parentSym, R);
+
+ // Other cases: give up.
+ return UnknownVal();
+ }
+
+ return RetrieveLazySymbol(state, R);
}
-SVal RegionStoreManager::RetrieveField(const GRState* state,
- const FieldRegion* R) {
- QualType Ty = R->getValueType(getContext());
+SVal RegionStoreManager::RetrieveVar(const GRState *state,
+ const VarRegion *R) {
// Check if the region has a binding.
- RegionBindingsTy B = GetRegionBindings(state->getStore());
- if (const SVal* V = B.lookup(R))
+ RegionBindings B = GetRegionBindings(state->getStore());
+
+ if (Optional<SVal> V = getDirectBinding(B, R))
return *V;
- const MemRegion* superR = R->getSuperRegion();
- if (const SVal* D = state->get<RegionDefaultValue>(superR)) {
- if (D->hasConjuredSymbol())
- return ValMgr.getRegionValueSymbolVal(R);
+ // Lazily derive a value for the VarRegion.
+ const VarDecl *VD = R->getDecl();
- if (D->isZeroConstant())
- return ValMgr.makeZeroVal(Ty);
+ if (R->hasGlobalsOrParametersStorage())
+ return ValMgr.getRegionValueSymbolValOrUnknown(R, VD->getType());
- if (D->isUnknown())
- return *D;
+ return UndefinedVal();
+}
- assert(0 && "Unknown default value");
- }
+SVal RegionStoreManager::RetrieveLazySymbol(const GRState *state,
+ const TypedRegion *R) {
- // FIXME: Is this correct? Should it be UnknownVal?
- if (R->hasHeapStorage())
- return UndefinedVal();
-
- if (R->hasStackStorage() && !R->hasParametersStorage())
- return UndefinedVal();
-
- // If the region is already cast to another type, use that type to create the
- // symbol value.
- if (const QualType *p = state->get<RegionCasts>(R)) {
- QualType tmp = *p;
- Ty = tmp->getAsPointerType()->getPointeeType();
- }
+ QualType valTy = R->getValueType(getContext());
// All other values are symbolic.
- return ValMgr.getRegionValueSymbolValOrUnknown(R, Ty);
+ return ValMgr.getRegionValueSymbolValOrUnknown(R, valTy);
}
-SVal RegionStoreManager::RetrieveStruct(const GRState *state,
- const TypedRegion* R){
+SVal RegionStoreManager::RetrieveStruct(const GRState *state,
+ const TypedRegion* R) {
QualType T = R->getValueType(getContext());
assert(T->isStructureType());
const RecordType* RT = T->getAsStructureType();
RecordDecl* RD = RT->getDecl();
assert(RD->isDefinition());
-
+ (void)RD;
+#if USE_EXPLICIT_COMPOUND
llvm::ImmutableList<SVal> StructVal = getBasicVals().getEmptySValList();
// FIXME: We shouldn't use a std::vector. If RecordDecl doesn't have a
@@ -1030,33 +1312,38 @@ SVal RegionStoreManager::RetrieveStruct(const GRState *state,
Field != FieldEnd; ++Field) {
FieldRegion* FR = MRMgr.getFieldRegion(*Field, R);
QualType FTy = (*Field)->getType();
- SVal FieldValue = Retrieve(state, loc::MemRegionVal(FR), FTy);
+ SVal FieldValue = Retrieve(state, loc::MemRegionVal(FR), FTy).getSVal();
StructVal = getBasicVals().consVals(FieldValue, StructVal);
}
return ValMgr.makeCompoundVal(T, StructVal);
+#else
+ return ValMgr.makeLazyCompoundVal(state, R);
+#endif
}
SVal RegionStoreManager::RetrieveArray(const GRState *state,
const TypedRegion * R) {
-
+#if USE_EXPLICIT_COMPOUND
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 = ValMgr.makeIntVal(i);
+ uint64_t size = CAT->getSize().getZExtValue();
+ for (uint64_t i = 0; i < size; ++i) {
+ SVal Idx = ValMgr.makeArrayIndex(i);
ElementRegion* ER = MRMgr.getElementRegion(CAT->getElementType(), Idx, R,
- getContext());
+ getContext());
QualType ETy = ER->getElementType();
- SVal ElementVal = Retrieve(state, loc::MemRegionVal(ER), ETy);
+ SVal ElementVal = Retrieve(state, loc::MemRegionVal(ER), ETy).getSVal();
ArrayVal = getBasicVals().consVals(ElementVal, ArrayVal);
}
return ValMgr.makeCompoundVal(T, ArrayVal);
+#else
+ assert(isa<ConstantArrayType>(R->getValueType(getContext())));
+ return ValMgr.makeLazyCompoundVal(state, R);
+#endif
}
//===----------------------------------------------------------------------===//
@@ -1065,15 +1352,15 @@ SVal RegionStoreManager::RetrieveArray(const GRState *state,
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);
+ RegionBindings B = GetRegionBindings(store);
return RBFactory.Remove(B, R).getRoot();
}
-
+
return store;
}
@@ -1082,32 +1369,67 @@ const GRState *RegionStoreManager::Bind(const GRState *state, Loc L, SVal V) {
return state;
// If we get here, the location should be a region.
- const MemRegion* R = cast<loc::MemRegionVal>(L).getRegion();
-
+ const MemRegion *R = cast<loc::MemRegionVal>(L).getRegion();
+
// Check if the region is a struct region.
if (const TypedRegion* TR = dyn_cast<TypedRegion>(R))
if (TR->getValueType(getContext())->isStructureType())
return BindStruct(state, TR, V);
-
- RegionBindingsTy B = GetRegionBindings(state->getStore());
-
- B = RBFactory.Add(B, R, V);
-
- return state->makeWithStore(B.getRoot());
+
+ // Special case: the current region represents a cast and it and the super
+ // region both have pointer types or intptr_t types. If so, perform the
+ // bind to the super region.
+ // This is needed to support OSAtomicCompareAndSwap and friends or other
+ // loads that treat integers as pointers and vis versa.
+ if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
+ if (ER->getIndex().isZeroConstant()) {
+ if (const TypedRegion *superR =
+ dyn_cast<TypedRegion>(ER->getSuperRegion())) {
+ ASTContext &Ctx = getContext();
+ QualType superTy = superR->getValueType(Ctx);
+ QualType erTy = ER->getValueType(Ctx);
+
+ if (IsAnyPointerOrIntptr(superTy, Ctx) &&
+ IsAnyPointerOrIntptr(erTy, Ctx)) {
+ SValuator::CastResult cr =
+ ValMgr.getSValuator().EvalCast(V, state, superTy, erTy);
+ return Bind(cr.getState(), loc::MemRegionVal(superR), cr.getSVal());
+ }
+ // For now, just invalidate the fields of the struct/union/class.
+ // FIXME: Precisely handle the fields of the record.
+ if (superTy->isRecordType())
+ return InvalidateRegion(state, superR, NULL, 0);
+ }
+ }
+ }
+ else if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R)) {
+ // Binding directly to a symbolic region should be treated as binding
+ // to element 0.
+ QualType T = SR->getSymbol()->getType(getContext());
+ T = T->getAs<PointerType>()->getPointeeType();
+ R = GetElementZeroRegion(SR, T);
+ }
+
+ // Perform the binding.
+ RegionBindings B = GetRegionBindings(state->getStore());
+ return state->makeWithStore(
+ RBFactory.Add(B, R, BindingVal(V, BindingVal::Direct)).getRoot());
}
-const GRState *RegionStoreManager::BindDecl(const GRState *state,
- const VarDecl* VD, SVal InitVal) {
+const GRState *RegionStoreManager::BindDecl(const GRState *ST,
+ const VarDecl *VD,
+ const LocationContext *LC,
+ SVal InitVal) {
QualType T = VD->getType();
- VarRegion* VR = MRMgr.getVarRegion(VD);
+ VarRegion* VR = MRMgr.getVarRegion(VD, LC);
if (T->isArrayType())
- return BindArray(state, VR, InitVal);
+ return BindArray(ST, VR, InitVal);
if (T->isStructureType())
- return BindStruct(state, VR, InitVal);
+ return BindStruct(ST, VR, InitVal);
- return Bind(state, ValMgr.makeLoc(VR), InitVal);
+ return Bind(ST, ValMgr.makeLoc(VR), InitVal);
}
// FIXME: this method should be merged into Bind().
@@ -1115,21 +1437,20 @@ const GRState *
RegionStoreManager::BindCompoundLiteral(const GRState *state,
const CompoundLiteralExpr* CL,
SVal V) {
-
+
CompoundLiteralRegion* R = MRMgr.getCompoundLiteralRegion(CL);
return Bind(state, loc::MemRegionVal(R), V);
}
const GRState *RegionStoreManager::BindArray(const GRState *state,
- const TypedRegion* R,
+ const TypedRegion* R,
SVal Init) {
QualType T = R->getValueType(getContext());
ConstantArrayType* CAT = cast<ConstantArrayType>(T.getTypePtr());
QualType ElementTy = CAT->getElementType();
- llvm::APSInt Size(CAT->getSize(), false);
- llvm::APSInt i(llvm::APInt::getNullValue(Size.getBitWidth()), false);
+ uint64_t size = CAT->getSize().getZExtValue();
// Check if the init expr is a StringLiteral.
if (isa<loc::MemRegionVal>(Init)) {
@@ -1142,12 +1463,13 @@ const GRState *RegionStoreManager::BindArray(const GRState *state,
// 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) {
+ for (uint64_t i = 0; i < size; ++i, ++j) {
if (j >= len)
break;
- SVal Idx = ValMgr.makeIntVal(i);
- ElementRegion* ER = MRMgr.getElementRegion(ElementTy, Idx,R,getContext());
+ SVal Idx = ValMgr.makeArrayIndex(i);
+ ElementRegion* ER = MRMgr.getElementRegion(ElementTy, Idx, R,
+ getContext());
SVal V = ValMgr.makeIntVal(str[j], sizeof(char)*8, true);
state = Bind(state, loc::MemRegionVal(ER), V);
@@ -1156,29 +1478,39 @@ const GRState *RegionStoreManager::BindArray(const GRState *state,
return state;
}
+ // Handle lazy compound values.
+ if (nonloc::LazyCompoundVal *LCV = dyn_cast<nonloc::LazyCompoundVal>(&Init))
+ return CopyLazyBindings(*LCV, state, R);
+
+ // Remaining case: explicit compound values.
nonloc::CompoundVal& CV = cast<nonloc::CompoundVal>(Init);
nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end();
+ uint64_t i = 0;
- for (; i < Size; ++i, ++VI) {
+ for (; i < size; ++i, ++VI) {
// The init list might be shorter than the array length.
if (VI == VE)
break;
- SVal Idx = ValMgr.makeIntVal(i);
+ SVal Idx = ValMgr.makeArrayIndex(i);
ElementRegion* ER = MRMgr.getElementRegion(ElementTy, Idx, R, getContext());
if (CAT->getElementType()->isStructureType())
state = BindStruct(state, ER, *VI);
else
+ // FIXME: Do we need special handling of nested arrays?
state = Bind(state, ValMgr.makeLoc(ER), *VI);
}
// If the init list is shorter than the array length, set the array default
// value.
- if (i < Size) {
+ if (i < size) {
if (ElementTy->isIntegerType()) {
SVal V = ValMgr.makeZeroVal(ElementTy);
- state = setDefaultValue(state, R, V);
+ Store store = state->getStore();
+ RegionBindings B = GetRegionBindings(store);
+ B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default));
+ state = state->makeWithStore(B.getRoot());
}
}
@@ -1188,23 +1520,27 @@ const GRState *RegionStoreManager::BindArray(const GRState *state,
const GRState *
RegionStoreManager::BindStruct(const GRState *state, const TypedRegion* R,
SVal V) {
-
+
if (!Features.supportsFields())
return state;
-
+
QualType T = R->getValueType(getContext());
assert(T->isStructureType());
- const RecordType* RT = T->getAsRecordType();
+ const RecordType* RT = T->getAs<RecordType>();
RecordDecl* RD = RT->getDecl();
if (!RD->isDefinition())
return state;
+ // Handle lazy compound values.
+ if (const nonloc::LazyCompoundVal *LCV=dyn_cast<nonloc::LazyCompoundVal>(&V))
+ return CopyLazyBindings(*LCV, state, R);
+
// We may get non-CompoundVal accidentally due to imprecise cast logic.
// Ignore them and kill the field values.
if (V.isUnknown() || !isa<nonloc::CompoundVal>(V))
- return KillStruct(state, R);
+ return state->makeWithStore(KillStruct(state->getStore(), R));
nonloc::CompoundVal& CV = cast<nonloc::CompoundVal>(V);
nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end();
@@ -1217,253 +1553,286 @@ RegionStoreManager::BindStruct(const GRState *state, const TypedRegion* R,
break;
QualType FTy = (*FI)->getType();
- FieldRegion* FR = MRMgr.getFieldRegion(*FI, R);
+ const FieldRegion* FR = MRMgr.getFieldRegion(*FI, R);
- if (Loc::IsLocType(FTy) || FTy->isIntegerType())
- state = Bind(state, ValMgr.makeLoc(FR), *VI);
- else if (FTy->isArrayType())
+ if (FTy->isArrayType())
state = BindArray(state, FR, *VI);
else if (FTy->isStructureType())
state = BindStruct(state, FR, *VI);
+ else
+ state = Bind(state, ValMgr.makeLoc(FR), *VI);
}
// There may be fewer values in the initialize list than the fields of struct.
- if (FI != FE)
- state = setDefaultValue(state, R, ValMgr.makeIntVal(0, false));
+ if (FI != FE) {
+ Store store = state->getStore();
+ RegionBindings B = GetRegionBindings(store);
+ B = RBFactory.Add(B, R,
+ BindingVal(ValMgr.makeIntVal(0, false), BindingVal::Default));
+ state = state->makeWithStore(B.getRoot());
+ }
return state;
}
-const GRState *RegionStoreManager::KillStruct(const GRState *state,
- const TypedRegion* R){
+Store RegionStoreManager::KillStruct(Store store, const TypedRegion* R) {
+ RegionBindings B = GetRegionBindings(store);
+ llvm::OwningPtr<RegionStoreSubRegionMap>
+ SubRegions(getRegionStoreSubRegionMap(store));
+ RemoveSubRegionBindings(B, R, *SubRegions);
// Set the default value of the struct region to "unknown".
- state = state->set<RegionDefaultValue>(R, UnknownVal());
-
- // Remove all bindings for the subregions of the struct.
- Store store = state->getStore();
- RegionBindingsTy B = GetRegionBindings(store);
- for (RegionBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) {
- const MemRegion* R = I.getKey();
- if (const SubRegion* subRegion = dyn_cast<SubRegion>(R))
- if (subRegion->isSubRegionOf(R))
- store = Remove(store, ValMgr.makeLoc(subRegion));
- }
-
- return state->makeWithStore(store);
-}
+ B = RBFactory.Add(B, R, BindingVal(UnknownVal(), BindingVal::Default));
-//===----------------------------------------------------------------------===//
-// Region views.
-//===----------------------------------------------------------------------===//
-
-const GRState *RegionStoreManager::AddRegionView(const GRState *state,
- const MemRegion* View,
- const MemRegion* Base) {
-
- // 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);
+ return B.getRoot();
}
-const GRState *RegionStoreManager::RemoveRegionView(const GRState *state,
- const MemRegion* View,
- const MemRegion* Base) {
- // Retrieve the region view of the base region.
- const RegionViews* d = state->get<RegionViewMap>(Base);
+const GRState*
+RegionStoreManager::CopyLazyBindings(nonloc::LazyCompoundVal V,
+ const GRState *state,
+ const TypedRegion *R) {
- // If the base region has no view, return.
- if (!d)
- return state;
+ // Nuke the old bindings stemming from R.
+ RegionBindings B = GetRegionBindings(state->getStore());
- // Remove the view.
- return state->set<RegionViewMap>(Base, RVFactory.Remove(*d, View));
-}
+ llvm::OwningPtr<RegionStoreSubRegionMap>
+ SubRegions(getRegionStoreSubRegionMap(state->getStore()));
-const GRState *RegionStoreManager::setCastType(const GRState *state,
- const MemRegion* R, QualType T) {
- return state->set<RegionCasts>(R, T);
-}
+ // B and DVM are updated after the call to RemoveSubRegionBindings.
+ RemoveSubRegionBindings(B, R, *SubRegions.get());
-const GRState *RegionStoreManager::setDefaultValue(const GRState *state,
- const MemRegion* R, SVal V) {
- return state->set<RegionDefaultValue>(R, V);
+ // Now copy the bindings. This amounts to just binding 'V' to 'R'. This
+ // results in a zero-copy algorithm.
+ return state->makeWithStore(
+ RBFactory.Add(B, R, BindingVal(V, BindingVal::Direct)).getRoot());
}
//===----------------------------------------------------------------------===//
// State pruning.
//===----------------------------------------------------------------------===//
-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;
- }
+namespace {
+class VISIBILITY_HIDDEN RBDNode
+ : public std::pair<const GRState*, const MemRegion *> {
+public:
+ RBDNode(const GRState *st, const MemRegion *r)
+ : std::pair<const GRState*, const MemRegion*>(st, r) {}
- for (SVal::symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end();SI!=SE;++SI)
- SymReaper.markLive(*SI);
-}
+ const GRState *getState() const { return first; }
+ const MemRegion *getRegion() const { return second; }
+};
-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;
+enum VisitFlag { NotVisited = 0, VisitedFromSubRegion, VisitedFromSuperRegion };
+
+class RBDItem : public RBDNode {
+private:
+ const VisitFlag VF;
- // Factory objects.
- SubRegionsMapTy::Factory SubRegMapF(TmpAlloc);
- SubRegionsTy::Factory SubRegF(TmpAlloc);
+public:
+ RBDItem(const GRState *st, const MemRegion *r, VisitFlag vf)
+ : RBDNode(st, r), VF(vf) {}
+
+ VisitFlag getVisitFlag() const { return VF; }
+};
+} // end anonymous namespace
+void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
+ SymbolReaper& SymReaper,
+ llvm::SmallVectorImpl<const MemRegion*>& RegionRoots)
+{
+ Store store = state.getStore();
+ RegionBindings B = GetRegionBindings(store);
+
// The backmap from regions to subregions.
- SubRegionsMapTy SubRegMap = SubRegMapF.GetEmptyMap();
+ llvm::OwningPtr<RegionStoreSubRegionMap>
+ SubRegions(getRegionStoreSubRegionMap(store));
- // 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.
+ // 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());
+ // Scan the direct bindings for "intermediate" roots.
+ for (RegionBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
+ const MemRegion *R = I.getKey();
+ IntermediateRoots.push_back(R);
}
+ // Process the "intermediate" roots to find if they are referenced by
+ // real roots.
+ llvm::SmallVector<RBDItem, 10> WorkList;
+ llvm::DenseMap<const MemRegion*,unsigned> IntermediateVisited;
+
while (!IntermediateRoots.empty()) {
const MemRegion* R = IntermediateRoots.back();
IntermediateRoots.pop_back();
+ unsigned &visited = IntermediateVisited[R];
+ if (visited)
+ continue;
+ visited = 1;
+
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);
+ if (SymReaper.isLive(Loc, VR->getDecl()))
+ WorkList.push_back(RBDItem(&state, VR, VisitedFromSuperRegion));
+ continue;
}
- 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);
+
+ if (const SymbolicRegion* SR = dyn_cast<SymbolicRegion>(R)) {
+ if (SymReaper.isLive(SR->getSymbol()))
+ WorkList.push_back(RBDItem(&state, SR, VisitedFromSuperRegion));
+ continue;
}
+
+ // Add the super region for R to the worklist if it is a subregion.
+ if (const SubRegion* superR =
+ dyn_cast<SubRegion>(cast<SubRegion>(R)->getSuperRegion()))
+ IntermediateRoots.push_back(superR);
+ }
+
+ // Enqueue the RegionRoots onto WorkList.
+ for (llvm::SmallVectorImpl<const MemRegion*>::iterator I=RegionRoots.begin(),
+ E=RegionRoots.end(); I!=E; ++I) {
+ WorkList.push_back(RBDItem(&state, *I, VisitedFromSuperRegion));
}
+ RegionRoots.clear();
- // 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;
+ // Process the worklist.
+ typedef llvm::DenseMap<std::pair<const GRState*, const MemRegion*>, VisitFlag>
+ VisitMap;
+
+ VisitMap Visited;
- while (!RegionRoots.empty()) {
- // Dequeue the next region on the worklist.
- const MemRegion* R = RegionRoots.back();
- RegionRoots.pop_back();
+ while (!WorkList.empty()) {
+ RBDItem N = WorkList.back();
+ WorkList.pop_back();
+
+ // Have we visited this node before?
+ VisitFlag &VF = Visited[N];
+ if (VF >= N.getVisitFlag())
+ continue;
- // Check if we have already processed this region.
- if (Marked.count(R)) continue;
+ const MemRegion *R = N.getRegion();
+ const GRState *state_N = N.getState();
- // Mark this region as processed. This is needed for termination in case
- // a region is referenced more than once.
- Marked.insert(R);
+ // Enqueue subregions?
+ if (N.getVisitFlag() == VisitedFromSuperRegion) {
+ RegionStoreSubRegionMap *M;
+
+ if (&state == state_N)
+ M = SubRegions.get();
+ else {
+ RegionStoreSubRegionMap *& SM = SC[state_N];
+ if (!SM)
+ SM = getRegionStoreSubRegionMap(state_N->getStore());
+ M = SM;
+ }
+
+ RegionStoreSubRegionMap::iterator I, E;
+ for (llvm::tie(I, E) = M->begin_end(R); I != E; ++I)
+ WorkList.push_back(RBDItem(state_N, *I, VisitedFromSuperRegion));
+ }
+
+ // At this point, if we have already visited this region before, we are
+ // done.
+ if (VF != NotVisited) {
+ VF = N.getVisitFlag();
+ continue;
+ }
+ VF = N.getVisitFlag();
+ // Enqueue the super region.
+ if (const SubRegion *SR = dyn_cast<SubRegion>(R)) {
+ const MemRegion *superR = SR->getSuperRegion();
+ if (!isa<MemSpaceRegion>(superR)) {
+ // If 'R' is a field or an element, we want to keep the bindings
+ // for the other fields and elements around. The reason is that
+ // pointer arithmetic can get us to the other fields or elements.
+ // FIXME: add an assertion that this is always true.
+ VisitFlag NewVisit =
+ isa<FieldRegion>(R) || isa<ElementRegion>(R) || isa<ObjCIvarRegion>(R)
+ ? VisitedFromSuperRegion : VisitedFromSubRegion;
+
+ WorkList.push_back(RBDItem(state_N, superR, NewVisit));
+ }
+ }
+
// 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());
+
+ Store store_N = state_N->getStore();
+ RegionBindings B_N = GetRegionBindings(store_N);
// 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.
+ Optional<SVal> V = getBinding(B_N, R);
+
+ if (V) {
+ // Check for lazy bindings.
+ if (const nonloc::LazyCompoundVal *LCV =
+ dyn_cast<nonloc::LazyCompoundVal>(V.getPointer())) {
- // If X is a region, then add it to the RegionRoots.
- if (const MemRegion *RX = X.getAsRegion()) {
- RegionRoots.push_back(RX);
-
- // Mark the super region of the RX as live.
- // e.g.: int x; char *y = (char*) &x; if (*y) ...
- // 'y' => element region. 'x' is its super region.
- // We only add one level super region for now.
- // FIXME: maybe multiple level of super regions should be added.
- if (const SubRegion *SR = dyn_cast<SubRegion>(RX)) {
- RegionRoots.push_back(SR->getSuperRegion());
- }
+ const LazyCompoundValData *D = LCV->getCVData();
+ WorkList.push_back(RBDItem(D->getState(), D->getRegion(),
+ VisitedFromSuperRegion));
+ }
+ else {
+ // Update the set of live symbols.
+ for (SVal::symbol_iterator SI=V->symbol_begin(), SE=V->symbol_end();
+ SI!=SE;++SI)
+ SymReaper.markLive(*SI);
+
+ // If V is a region, then add it to the worklist.
+ if (const MemRegion *RX = V->getAsRegion())
+ WorkList.push_back(RBDItem(state_N, RX, VisitedFromSuperRegion));
}
}
-
- // 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) {
+ // as well as update DSymbols with the set symbols that are now dead.
+ for (RegionBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
const MemRegion* R = I.getKey();
// If this region live? Is so, none of its symbols are dead.
- if (Marked.count(R))
+ if (Visited.find(std::make_pair(&state, R)) != Visited.end())
continue;
-
+
// Remove this dead region from the store.
store = Remove(store, ValMgr.makeLoc(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 X = *I.getData().getValue();
SVal::symbol_iterator SI = X.symbol_begin(), SE = X.symbol_end();
- for (; SI != SE; ++SI) SymReaper.maybeDead(*SI);
+ for (; SI != SE; ++SI)
+ SymReaper.maybeDead(*SI);
}
-
- return store;
+
+ // Write the store back.
+ state.setStore(store);
+}
+
+GRState const *RegionStoreManager::EnterStackFrame(GRState const *state,
+ StackFrameContext const *frame) {
+ FunctionDecl const *FD = cast<FunctionDecl>(frame->getDecl());
+ CallExpr const *CE = cast<CallExpr>(frame->getCallSite());
+
+ FunctionDecl::param_const_iterator PI = FD->param_begin();
+
+ CallExpr::const_arg_iterator AI = CE->arg_begin(), AE = CE->arg_end();
+
+ // Copy the arg expression value to the arg variables.
+ for (; AI != AE; ++AI, ++PI) {
+ SVal ArgVal = state->getSVal(*AI);
+ MemRegion *R = MRMgr.getVarRegion(*PI, frame);
+ state = Bind(state, ValMgr.makeLoc(R), ArgVal);
+ }
+
+ return state;
}
//===----------------------------------------------------------------------===//
@@ -1472,11 +1841,9 @@ Store RegionStoreManager::RemoveDeadBindings(const GRState *state, Stmt* Loc,
void RegionStoreManager::print(Store store, llvm::raw_ostream& OS,
const char* nl, const char *sep) {
- 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;
- }
+ RegionBindings B = GetRegionBindings(store);
+ OS << "Store (direct bindings):" << nl;
+
+ for (RegionBindings::iterator I = B.begin(), E = B.end(); I != E; ++I)
+ OS << ' ' << I.getKey() << " : " << I.getData() << nl;
}
diff --git a/lib/Analysis/SVals.cpp b/lib/Analysis/SVals.cpp
index d711ce0..688b7ff 100644
--- a/lib/Analysis/SVals.cpp
+++ b/lib/Analysis/SVals.cpp
@@ -14,7 +14,6 @@
#include "clang/Analysis/PathSensitive/GRState.h"
#include "clang/Basic/IdentifierTable.h"
-#include "llvm/Support/Streams.h"
using namespace clang;
using llvm::dyn_cast;
@@ -43,52 +42,32 @@ bool SVal::hasConjuredSymbol() const {
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 {
+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();
- }
+ if (const CodeTextRegion *CTR = R->getAs<CodeTextRegion>())
+ return CTR->getDecl();
}
- return 0;
+ return NULL;
}
-/// getAsLocSymbol - If this SVal is a location (subclasses Loc) and
+/// 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;
- }
+ const MemRegion *R = X->getBaseRegion();
+ if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(R))
+ return SymR->getSymbol();
}
-
- return 0;
+ return NULL;
}
/// getAsSymbol - If this Sval wraps a symbol return that SymbolRef.
@@ -97,11 +76,11 @@ SymbolRef SVal::getAsLocSymbol() const {
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();
}
@@ -110,7 +89,7 @@ SymbolRef SVal::getAsSymbol() const {
const SymExpr *SVal::getAsSymbolicExpression() const {
if (const nonloc::SymExprVal *X = dyn_cast<nonloc::SymExprVal>(this))
return X->getSymbolicExpression();
-
+
return getAsSymbol();
}
@@ -121,6 +100,11 @@ const MemRegion *SVal::getAsRegion() const {
return 0;
}
+const MemRegion *loc::MemRegionVal::getBaseRegion() const {
+ const MemRegion *R = getRegion();
+ return R ? R->getBaseRegion() : NULL;
+}
+
bool SVal::symbol_iterator::operator==(const symbol_iterator &X) const {
return itr == X.itr;
}
@@ -131,13 +115,13 @@ bool SVal::symbol_iterator::operator!=(const symbol_iterator &X) const {
SVal::symbol_iterator::symbol_iterator(const SymExpr *SE) {
itr.push_back(SE);
- while (!isa<SymbolData>(itr.back())) expand();
+ 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();
+ itr.pop_back();
if (!itr.empty())
while (!isa<SymbolData>(itr.back())) expand();
return *this;
@@ -151,20 +135,28 @@ SymbolRef SVal::symbol_iterator::operator*() {
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");
}
+const GRState *nonloc::LazyCompoundVal::getState() const {
+ return static_cast<const LazyCompoundValData*>(Data)->getState();
+}
+
+const TypedRegion *nonloc::LazyCompoundVal::getRegion() const {
+ return static_cast<const LazyCompoundValData*>(Data)->getRegion();
+}
+
//===----------------------------------------------------------------------===//
// Other Iterators.
//===----------------------------------------------------------------------===//
@@ -197,10 +189,10 @@ bool SVal::isZeroConstant() const {
SVal nonloc::ConcreteInt::evalBinOp(ValueManager &ValMgr,
BinaryOperator::Opcode Op,
- const nonloc::ConcreteInt& R) const {
+ const nonloc::ConcreteInt& R) const {
const llvm::APSInt* X =
ValMgr.getBasicValueFactory().EvaluateAPSInt(Op, getValue(), R.getValue());
-
+
if (X)
return nonloc::ConcreteInt(*X);
else
@@ -223,12 +215,12 @@ nonloc::ConcreteInt nonloc::ConcreteInt::evalMinus(ValueManager &ValMgr) const {
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
@@ -239,98 +231,89 @@ SVal loc::ConcreteInt::EvalBinOp(BasicValueFactory& BasicVals,
// Pretty-Printing.
//===----------------------------------------------------------------------===//
-void SVal::printStdErr() const { print(llvm::errs()); }
-
-void SVal::print(llvm::raw_ostream& Out) const {
+void SVal::dump() const { dumpToStream(llvm::errs()); }
+void SVal::dumpToStream(llvm::raw_ostream& os) const {
switch (getBaseKind()) {
-
case UnknownKind:
- Out << "Invalid"; break;
-
+ os << "Invalid";
+ break;
case NonLocKind:
- cast<NonLoc>(this)->print(Out); break;
-
+ cast<NonLoc>(this)->dumpToStream(os);
+ break;
case LocKind:
- cast<Loc>(this)->print(Out); break;
-
+ cast<Loc>(this)->dumpToStream(os);
+ break;
case UndefinedKind:
- Out << "Undefined"; break;
-
+ os << "Undefined";
+ break;
default:
assert (false && "Invalid SVal.");
}
}
-void NonLoc::print(llvm::raw_ostream& Out) const {
-
- switch (getSubKind()) {
-
+void NonLoc::dumpToStream(llvm::raw_ostream& os) const {
+ switch (getSubKind()) {
case nonloc::ConcreteIntKind:
- Out << cast<nonloc::ConcreteInt>(this)->getValue().getZExtValue();
-
+ os << cast<nonloc::ConcreteInt>(this)->getValue().getZExtValue();
if (cast<nonloc::ConcreteInt>(this)->getValue().isUnsigned())
- Out << 'U';
-
+ os << 'U';
break;
-
case nonloc::SymbolValKind:
- Out << '$' << cast<nonloc::SymbolVal>(this)->getSymbol();
+ os << '$' << cast<nonloc::SymbolVal>(this)->getSymbol();
break;
-
case nonloc::SymExprValKind: {
const nonloc::SymExprVal& C = *cast<nonloc::SymExprVal>(this);
const SymExpr *SE = C.getSymbolicExpression();
- Out << SE;
+ os << SE;
break;
}
-
case nonloc::LocAsIntegerKind: {
const nonloc::LocAsInteger& C = *cast<nonloc::LocAsInteger>(this);
- C.getLoc().print(Out);
- Out << " [as " << C.getNumBits() << " bit integer]";
+ os << C.getLoc() << " [as " << C.getNumBits() << " bit integer]";
break;
}
-
case nonloc::CompoundValKind: {
const nonloc::CompoundVal& C = *cast<nonloc::CompoundVal>(this);
- Out << " {";
+ os << "compoundVal{";
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);
+ if (first) {
+ os << ' '; first = false;
+ }
+ else
+ os << ", ";
+
+ (*I).dumpToStream(os);
}
- Out << " }";
+ os << "}";
+ break;
+ }
+ case nonloc::LazyCompoundValKind: {
+ const nonloc::LazyCompoundVal &C = *cast<nonloc::LazyCompoundVal>(this);
+ os << "lazyCompoundVal{" << (void*) C.getState() << ',' << C.getRegion()
+ << '}';
break;
}
-
default:
assert (false && "Pretty-printed not implemented for this NonLoc.");
break;
}
}
-void Loc::print(llvm::raw_ostream& Out) const {
-
- switch (getSubKind()) {
-
+void Loc::dumpToStream(llvm::raw_ostream& os) const {
+ switch (getSubKind()) {
case loc::ConcreteIntKind:
- Out << cast<loc::ConcreteInt>(this)->getValue().getZExtValue()
- << " (Loc)";
+ os << cast<loc::ConcreteInt>(this)->getValue().getZExtValue() << " (Loc)";
break;
-
case loc::GotoLabelKind:
- Out << "&&"
- << cast<loc::GotoLabel>(this)->getLabel()->getID()->getName();
+ os << "&&" << cast<loc::GotoLabel>(this)->getLabel()->getID()->getName();
break;
-
case loc::MemRegionKind:
- Out << '&' << cast<loc::MemRegionVal>(this)->getRegion()->getString();
+ os << '&' << cast<loc::MemRegionVal>(this)->getRegion()->getString();
break;
-
default:
- assert (false && "Pretty-printing not implemented for this Loc.");
+ assert(false && "Pretty-printing not implemented for this Loc.");
break;
}
}
diff --git a/lib/Analysis/SValuator.cpp b/lib/Analysis/SValuator.cpp
new file mode 100644
index 0000000..573cac3
--- /dev/null
+++ b/lib/Analysis/SValuator.cpp
@@ -0,0 +1,160 @@
+// SValuator.cpp - Basic class for all SValuator implementations --*- 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 SValuator, the base class for all (complete) SValuator
+// implementations.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/SValuator.h"
+#include "clang/Analysis/PathSensitive/GRState.h"
+
+using namespace clang;
+
+
+SVal SValuator::EvalBinOp(const GRState *ST, 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 EvalBinOpLL(Op, cast<Loc>(L), cast<Loc>(R), T);
+
+ return EvalBinOpLN(ST, Op, cast<Loc>(L), cast<NonLoc>(R), T);
+ }
+
+ 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 EvalBinOpLN(ST, Op, cast<Loc>(R), cast<NonLoc>(L), T);
+ }
+
+ return EvalBinOpNN(ST, Op, cast<NonLoc>(L), cast<NonLoc>(R), T);
+}
+
+DefinedOrUnknownSVal SValuator::EvalEQ(const GRState *ST,
+ DefinedOrUnknownSVal L,
+ DefinedOrUnknownSVal R) {
+ return cast<DefinedOrUnknownSVal>(EvalBinOp(ST, BinaryOperator::EQ, L, R,
+ ValMgr.getContext().IntTy));
+}
+
+SValuator::CastResult SValuator::EvalCast(SVal val, const GRState *state,
+ QualType castTy, QualType originalTy){
+
+ if (val.isUnknownOrUndef() || castTy == originalTy)
+ return CastResult(state, val);
+
+ ASTContext &C = ValMgr.getContext();
+
+ // For const casts, just propagate the value.
+ if (C.getCanonicalType(castTy).getUnqualifiedType() ==
+ C.getCanonicalType(originalTy).getUnqualifiedType())
+ return CastResult(state, val);
+
+ // Check for casts from pointers to integers.
+ if (castTy->isIntegerType() && Loc::IsLocType(originalTy))
+ return CastResult(state, EvalCastL(cast<Loc>(val), castTy));
+
+ // Check for casts from integers to pointers.
+ if (Loc::IsLocType(castTy) && originalTy->isIntegerType()) {
+ if (nonloc::LocAsInteger *LV = dyn_cast<nonloc::LocAsInteger>(&val)) {
+ // Just unpackage the lval and return it.
+ return CastResult(state, LV->getLoc());
+ }
+
+ goto DispatchCast;
+ }
+
+ // Just pass through function and block pointers.
+ if (originalTy->isBlockPointerType() || originalTy->isFunctionPointerType()) {
+ assert(Loc::IsLocType(castTy));
+ return CastResult(state, val);
+ }
+
+ // Check for casts from array type to another type.
+ if (originalTy->isArrayType()) {
+ // We will always decay to a pointer.
+ val = ValMgr.getStateManager().ArrayToPointer(cast<Loc>(val));
+
+ // Are we casting from an array to a pointer? If so just pass on
+ // the decayed value.
+ if (castTy->isPointerType())
+ return CastResult(state, val);
+
+ // Are we casting from an array to an integer? If so, cast the decayed
+ // pointer value to an integer.
+ assert(castTy->isIntegerType());
+
+ // FIXME: Keep these here for now in case we decide soon that we
+ // need the original decayed type.
+ // QualType elemTy = cast<ArrayType>(originalTy)->getElementType();
+ // QualType pointerTy = C.getPointerType(elemTy);
+ return CastResult(state, EvalCastL(cast<Loc>(val), castTy));
+ }
+
+ // Check for casts from a region to a specific type.
+ if (const MemRegion *R = val.getAsRegion()) {
+ // FIXME: We should handle the case where we strip off view layers to get
+ // to a desugared type.
+
+ assert(Loc::IsLocType(castTy));
+ // 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(originalTy) || originalTy->isFunctionType() ||
+ originalTy->isBlockPointerType());
+
+ StoreManager &storeMgr = ValMgr.getStateManager().getStoreManager();
+
+ // Delegate to store manager to get the result of casting a region to a
+ // different type. If the MemRegion* returned is NULL, this expression
+ // evaluates to UnknownVal.
+ R = storeMgr.CastRegion(R, castTy);
+
+ if (R)
+ return CastResult(state, loc::MemRegionVal(R));
+
+ return CastResult(state, UnknownVal());
+ }
+
+ // All other cases.
+DispatchCast:
+ return CastResult(state,
+ isa<Loc>(val) ? EvalCastL(cast<Loc>(val), castTy)
+ : EvalCastNL(cast<NonLoc>(val), castTy));
+}
+
+SValuator::DefinedOrUnknownCastResult
+SValuator::EvalCast(DefinedOrUnknownSVal V, const GRState *ST,
+ QualType castTy, QualType originalType) {
+ SValuator::CastResult X = EvalCast((SVal) V, ST, castTy, originalType);
+ return DefinedOrUnknownCastResult(X.getState(),
+ cast<DefinedOrUnknownSVal>(X.getSVal()));
+}
diff --git a/lib/Analysis/SimpleConstraintManager.cpp b/lib/Analysis/SimpleConstraintManager.cpp
index 82801eb..015db76 100644
--- a/lib/Analysis/SimpleConstraintManager.cpp
+++ b/lib/Analysis/SimpleConstraintManager.cpp
@@ -23,10 +23,10 @@ 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.
@@ -46,7 +46,7 @@ bool SimpleConstraintManager::canReasonAbout(SVal X) const {
// All other cases.
default:
return true;
- }
+ }
}
return false;
@@ -54,13 +54,10 @@ bool SimpleConstraintManager::canReasonAbout(SVal X) const {
return true;
}
-
-const GRState *SimpleConstraintManager::Assume(const GRState *state,
- SVal Cond, bool Assumption) {
- if (Cond.isUnknown()) {
- return state;
- }
+const GRState *SimpleConstraintManager::Assume(const GRState *state,
+ DefinedSVal Cond,
+ bool Assumption) {
if (isa<NonLoc>(Cond))
return Assume(state, cast<NonLoc>(Cond), Assumption);
else
@@ -74,14 +71,14 @@ const GRState *SimpleConstraintManager::Assume(const GRState *state, Loc Cond,
// 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.
+ // true or false.
return state ? state->getTransferFuncs().EvalAssume(state, Cond, Assumption)
: NULL;
}
const GRState *SimpleConstraintManager::AssumeAux(const GRState *state,
Loc Cond, bool Assumption) {
-
+
BasicValueFactory &BasicVals = state->getBasicVals();
switch (Cond.getSubKind()) {
@@ -91,7 +88,7 @@ const GRState *SimpleConstraintManager::AssumeAux(const GRState *state,
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);
@@ -99,7 +96,7 @@ const GRState *SimpleConstraintManager::AssumeAux(const GRState *state,
// FIXME: now we only find the first symbolic region.
if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(SubR)) {
if (Assumption)
- return AssumeSymNE(state, SymR->getSymbol(),
+ return AssumeSymNE(state, SymR->getSymbol(),
BasicVals.getZeroWithPtrWidth());
else
return AssumeSymEQ(state, SymR->getSymbol(),
@@ -107,15 +104,15 @@ const GRState *SimpleConstraintManager::AssumeAux(const GRState *state,
}
SubR = dyn_cast<SubRegion>(SubR->getSuperRegion());
}
-
+
// FALL-THROUGH.
}
-
+
case loc::GotoLabelKind:
return Assumption ? state : NULL;
case loc::ConcreteIntKind: {
- bool b = cast<loc::ConcreteInt>(Cond).getValue() != 0;
+ bool b = cast<loc::ConcreteInt>(Cond).getValue() != 0;
bool isFeasible = b ? Assumption : !Assumption;
return isFeasible ? state : NULL;
}
@@ -130,7 +127,7 @@ const GRState *SimpleConstraintManager::Assume(const GRState *state,
// 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.
+ // true or false.
return state ? state->getTransferFuncs().EvalAssume(state, Cond, Assumption)
: NULL;
}
@@ -138,13 +135,13 @@ const GRState *SimpleConstraintManager::Assume(const GRState *state,
const GRState *SimpleConstraintManager::AssumeAux(const GRState *state,
NonLoc Cond,
bool Assumption) {
-
+
// We cannot reason about SymIntExpr and SymSymExpr.
if (!canReasonAbout(Cond)) {
// Just return the current state indicating that the path is feasible.
// This may be an over-approximation of what is possible.
return state;
- }
+ }
BasicValueFactory &BasicVals = state->getBasicVals();
SymbolManager &SymMgr = state->getSymbolManager();
@@ -156,7 +153,7 @@ const GRState *SimpleConstraintManager::AssumeAux(const GRState *state,
case nonloc::SymbolValKind: {
nonloc::SymbolVal& SV = cast<nonloc::SymbolVal>(Cond);
SymbolRef sym = SV.getSymbol();
- QualType T = SymMgr.getType(sym);
+ QualType T = SymMgr.getType(sym);
const llvm::APSInt &zero = BasicVals.getValue(0, T);
return Assumption ? AssumeSymNE(state, sym, zero)
@@ -165,9 +162,20 @@ const GRState *SimpleConstraintManager::AssumeAux(const GRState *state,
case nonloc::SymExprValKind: {
nonloc::SymExprVal V = cast<nonloc::SymExprVal>(Cond);
- if (const SymIntExpr *SE = dyn_cast<SymIntExpr>(V.getSymbolicExpression()))
- return AssumeSymInt(state, Assumption, SE);
-
+ if (const SymIntExpr *SE = dyn_cast<SymIntExpr>(V.getSymbolicExpression())){
+ // FIXME: This is a hack. It silently converts the RHS integer to be
+ // of the same type as on the left side. This should be removed once
+ // we support truncation/extension of symbolic values.
+ GRStateManager &StateMgr = state->getStateManager();
+ ASTContext &Ctx = StateMgr.getContext();
+ QualType LHSType = SE->getLHS()->getType(Ctx);
+ BasicValueFactory &BasicVals = StateMgr.getBasicVals();
+ const llvm::APSInt &RHS = BasicVals.Convert(LHSType, SE->getRHS());
+ SymIntExpr SENew(SE->getLHS(), SE->getOpcode(), RHS, SE->getType(Ctx));
+
+ return AssumeSymInt(state, Assumption, &SENew);
+ }
+
// For all other symbolic expressions, over-approximate and consider
// the constraint feasible.
return state;
@@ -194,7 +202,7 @@ const GRState *SimpleConstraintManager::AssumeSymInt(const GRState *state,
// 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. Assume the constraint is feasible.
@@ -218,7 +226,7 @@ const GRState *SimpleConstraintManager::AssumeSymInt(const GRState *state,
case BinaryOperator::LT:
return Assumption ? AssumeSymLT(state, Sym, Int)
: AssumeSymGE(state, Sym, Int);
-
+
case BinaryOperator::LE:
return Assumption ? AssumeSymLE(state, Sym, Int)
: AssumeSymGT(state, Sym, Int);
@@ -226,9 +234,9 @@ const GRState *SimpleConstraintManager::AssumeSymInt(const GRState *state,
}
const GRState *SimpleConstraintManager::AssumeInBound(const GRState *state,
- SVal Idx,
- SVal UpperBound,
- bool Assumption) {
+ DefinedSVal Idx,
+ DefinedSVal UpperBound,
+ bool Assumption) {
// Only support ConcreteInt for now.
if (!(isa<nonloc::ConcreteInt>(Idx) && isa<nonloc::ConcreteInt>(UpperBound)))
diff --git a/lib/Analysis/SimpleConstraintManager.h b/lib/Analysis/SimpleConstraintManager.h
index 1e1a10d..0c58440 100644
--- a/lib/Analysis/SimpleConstraintManager.h
+++ b/lib/Analysis/SimpleConstraintManager.h
@@ -22,15 +22,16 @@ namespace clang {
class SimpleConstraintManager : public ConstraintManager {
public:
SimpleConstraintManager() {}
- virtual ~SimpleConstraintManager();
-
+ virtual ~SimpleConstraintManager();
+
//===------------------------------------------------------------------===//
// Common implementation for the interface provided by ConstraintManager.
//===------------------------------------------------------------------===//
bool canReasonAbout(SVal X) const;
- const GRState *Assume(const GRState *state, SVal Cond, bool Assumption);
+ const GRState *Assume(const GRState *state, DefinedSVal Cond,
+ bool Assumption);
const GRState *Assume(const GRState *state, Loc Cond, bool Assumption);
@@ -38,16 +39,17 @@ public:
const GRState *AssumeSymInt(const GRState *state, bool Assumption,
const SymIntExpr *SE);
-
- const GRState *AssumeInBound(const GRState *state, SVal Idx, SVal UpperBound,
+
+ const GRState *AssumeInBound(const GRState *state, DefinedSVal Idx,
+ DefinedSVal UpperBound,
bool Assumption);
-
+
protected:
-
+
//===------------------------------------------------------------------===//
// Interface that subclasses must implement.
//===------------------------------------------------------------------===//
-
+
virtual const GRState *AssumeSymNE(const GRState *state, SymbolRef sym,
const llvm::APSInt& V) = 0;
@@ -65,13 +67,13 @@ protected:
virtual const GRState *AssumeSymGE(const GRState *state, SymbolRef sym,
const llvm::APSInt& V) = 0;
-
+
//===------------------------------------------------------------------===//
// Internal implementation.
//===------------------------------------------------------------------===//
-
+
const GRState *AssumeAux(const GRState *state, Loc Cond,bool Assumption);
-
+
const GRState *AssumeAux(const GRState *state, NonLoc Cond, bool Assumption);
};
diff --git a/lib/Analysis/SimpleSValuator.cpp b/lib/Analysis/SimpleSValuator.cpp
index 76a8bc7..636ce15 100644
--- a/lib/Analysis/SimpleSValuator.cpp
+++ b/lib/Analysis/SimpleSValuator.cpp
@@ -19,21 +19,23 @@ using namespace clang;
namespace {
class VISIBILITY_HIDDEN SimpleSValuator : public SValuator {
+protected:
+ virtual SVal EvalCastNL(NonLoc val, QualType castTy);
+ virtual SVal EvalCastL(Loc val, QualType castTy);
+
public:
SimpleSValuator(ValueManager &valMgr) : SValuator(valMgr) {}
virtual ~SimpleSValuator() {}
-
- virtual SVal EvalCast(NonLoc val, QualType castTy);
- virtual SVal EvalCast(Loc val, QualType castTy);
- virtual SVal EvalMinus(NonLoc val);
- virtual SVal EvalComplement(NonLoc val);
- virtual SVal EvalBinOpNN(BinaryOperator::Opcode op, NonLoc lhs, NonLoc rhs,
- QualType resultTy);
+
+ virtual SVal EvalMinus(NonLoc val);
+ virtual SVal EvalComplement(NonLoc val);
+ virtual SVal EvalBinOpNN(const GRState *state, BinaryOperator::Opcode op,
+ NonLoc lhs, NonLoc rhs, QualType resultTy);
virtual SVal EvalBinOpLL(BinaryOperator::Opcode op, Loc lhs, Loc rhs,
QualType resultTy);
virtual SVal EvalBinOpLN(const GRState *state, BinaryOperator::Opcode op,
Loc lhs, NonLoc rhs, QualType resultTy);
-};
+};
} // end anonymous namespace
SValuator *clang::CreateSimpleSValuator(ValueManager &valMgr) {
@@ -44,16 +46,48 @@ SValuator *clang::CreateSimpleSValuator(ValueManager &valMgr) {
// Transfer function for Casts.
//===----------------------------------------------------------------------===//
-SVal SimpleSValuator::EvalCast(NonLoc val, QualType castTy) {
+SVal SimpleSValuator::EvalCastNL(NonLoc val, QualType castTy) {
+
+ bool isLocType = Loc::IsLocType(castTy);
+
+ if (nonloc::LocAsInteger *LI = dyn_cast<nonloc::LocAsInteger>(&val)) {
+ if (isLocType)
+ return LI->getLoc();
+
+ ASTContext &Ctx = ValMgr.getContext();
+
+ // FIXME: Support promotions/truncations.
+ if (Ctx.getTypeSize(castTy) == Ctx.getTypeSize(Ctx.VoidPtrTy))
+ return val;
+
+ return UnknownVal();
+ }
+
+ if (const SymExpr *se = val.getAsSymbolicExpression()) {
+ ASTContext &Ctx = ValMgr.getContext();
+ QualType T = Ctx.getCanonicalType(se->getType(Ctx));
+ if (T == Ctx.getCanonicalType(castTy))
+ return val;
+
+ // FIXME: Remove this hack when we support symbolic truncation/extension.
+ // HACK: If both castTy and T are integers, ignore the cast. This is
+ // not a permanent solution. Eventually we want to precisely handle
+ // extension/truncation of symbolic integers. This prevents us from losing
+ // precision when we assign 'x = y' and 'y' is symbolic and x and y are
+ // different integer types.
+ if (T->isIntegerType() && castTy->isIntegerType())
+ return val;
+
+ return UnknownVal();
+ }
+
if (!isa<nonloc::ConcreteInt>(val))
return UnknownVal();
- bool isLocType = Loc::IsLocType(castTy);
-
// Only handle casts from integers to integers.
if (!isLocType && !castTy->isIntegerType())
return UnknownVal();
-
+
llvm::APSInt i = cast<nonloc::ConcreteInt>(val).getValue();
i.setIsUnsigned(castTy->isUnsignedIntegerType() || Loc::IsLocType(castTy));
i.extOrTrunc(ValMgr.getContext().getTypeSize(castTy));
@@ -64,30 +98,28 @@ SVal SimpleSValuator::EvalCast(NonLoc val, QualType castTy) {
return ValMgr.makeIntVal(i);
}
-SVal SimpleSValuator::EvalCast(Loc val, QualType castTy) {
-
+SVal SimpleSValuator::EvalCastL(Loc val, QualType castTy) {
+
// 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(!val.isUnknownOrUndef());
-
if (Loc::IsLocType(castTy) || castTy->isReferenceType())
return val;
-
+
// FIXME: Handle transparent unions where a value can be "transparently"
// lifted into a union type.
if (castTy->isUnionType())
return UnknownVal();
-
+
assert(castTy->isIntegerType());
unsigned BitWidth = ValMgr.getContext().getTypeSize(castTy);
if (!isa<loc::ConcreteInt>(val))
return ValMgr.makeLocAsInteger(val, BitWidth);
-
+
llvm::APSInt i = cast<loc::ConcreteInt>(val).getValue();
i.setIsUnsigned(castTy->isUnsignedIntegerType() || Loc::IsLocType(castTy));
i.extOrTrunc(BitWidth);
@@ -99,7 +131,7 @@ SVal SimpleSValuator::EvalCast(Loc val, QualType castTy) {
//===----------------------------------------------------------------------===//
SVal SimpleSValuator::EvalMinus(NonLoc val) {
- switch (val.getSubKind()) {
+ switch (val.getSubKind()) {
case nonloc::ConcreteIntKind:
return cast<nonloc::ConcreteInt>(val).evalMinus(ValMgr);
default:
@@ -133,18 +165,18 @@ static BinaryOperator::Opcode NegateComparison(BinaryOperator::Opcode op) {
}
}
-// Equality operators for Locs.
+// Equality operators for Locs.
// FIXME: All this logic will be revamped when we have MemRegion::getLocation()
// implemented.
static SVal EvalEquality(ValueManager &ValMgr, Loc lhs, Loc rhs, bool isEqual,
QualType resultTy) {
-
+
switch (lhs.getSubKind()) {
default:
assert(false && "EQ/NE not implemented for this Loc.");
return UnknownVal();
-
+
case loc::ConcreteIntKind: {
if (SymbolRef rSym = rhs.getAsSymbol())
return ValMgr.makeNonLoc(rSym,
@@ -153,7 +185,7 @@ static SVal EvalEquality(ValueManager &ValMgr, Loc lhs, Loc rhs, bool isEqual,
cast<loc::ConcreteInt>(lhs).getValue(),
resultTy);
break;
- }
+ }
case loc::MemRegionKind: {
if (SymbolRef lSym = lhs.getAsLocSymbol()) {
if (isa<loc::ConcreteInt>(rhs)) {
@@ -166,27 +198,43 @@ static SVal EvalEquality(ValueManager &ValMgr, Loc lhs, Loc rhs, bool isEqual,
}
break;
}
-
+
case loc::GotoLabelKind:
break;
}
-
+
return ValMgr.makeTruthVal(isEqual ? lhs == rhs : lhs != rhs, resultTy);
}
-SVal SimpleSValuator::EvalBinOpNN(BinaryOperator::Opcode op,
+SVal SimpleSValuator::EvalBinOpNN(const GRState *state,
+ BinaryOperator::Opcode op,
NonLoc lhs, NonLoc rhs,
- QualType resultTy) {
+ QualType resultTy) {
+ // Handle trivial case where left-side and right-side are the same.
+ if (lhs == rhs)
+ switch (op) {
+ default:
+ break;
+ case BinaryOperator::EQ:
+ case BinaryOperator::LE:
+ case BinaryOperator::GE:
+ return ValMgr.makeTruthVal(true, resultTy);
+ case BinaryOperator::LT:
+ case BinaryOperator::GT:
+ case BinaryOperator::NE:
+ return ValMgr.makeTruthVal(false, resultTy);
+ }
+
while (1) {
switch (lhs.getSubKind()) {
default:
- return UnknownVal();
+ return UnknownVal();
case nonloc::LocAsIntegerKind: {
- Loc lhsL = cast<nonloc::LocAsInteger>(lhs).getLoc();
+ Loc lhsL = cast<nonloc::LocAsInteger>(lhs).getLoc();
switch (rhs.getSubKind()) {
case nonloc::LocAsIntegerKind:
return EvalBinOpLL(op, lhsL, cast<nonloc::LocAsInteger>(rhs).getLoc(),
- resultTy);
+ resultTy);
case nonloc::ConcreteIntKind: {
// Transform the integer into a location and compare.
ASTContext& Ctx = ValMgr.getContext();
@@ -195,7 +243,7 @@ SVal SimpleSValuator::EvalBinOpNN(BinaryOperator::Opcode op,
i.extOrTrunc(Ctx.getTypeSize(Ctx.VoidPtrTy));
return EvalBinOpLL(op, lhsL, ValMgr.makeLoc(i), resultTy);
}
- default:
+ default:
switch (op) {
case BinaryOperator::EQ:
return ValMgr.makeTruthVal(false, resultTy);
@@ -206,15 +254,15 @@ SVal SimpleSValuator::EvalBinOpNN(BinaryOperator::Opcode op,
return UnknownVal();
}
}
- }
+ }
case nonloc::SymExprValKind: {
- // Logical not?
+ // Logical not?
if (!(op == BinaryOperator::EQ && rhs.isZeroConstant()))
return UnknownVal();
const SymExpr *symExpr =
cast<nonloc::SymExprVal>(lhs).getSymbolicExpression();
-
+
// Only handle ($sym op constant) for now.
if (const SymIntExpr *symIntExpr = dyn_cast<SymIntExpr>(symExpr)) {
BinaryOperator::Opcode opc = symIntExpr->getOpcode();
@@ -257,7 +305,7 @@ SVal SimpleSValuator::EvalBinOpNN(BinaryOperator::Opcode op,
case BinaryOperator::GT:
case BinaryOperator::LE:
case BinaryOperator::GE:
- case BinaryOperator::EQ:
+ case BinaryOperator::EQ:
case BinaryOperator::NE:
opc = NegateComparison(opc);
assert(symIntExpr->getType(ValMgr.getContext()) == resultTy);
@@ -266,7 +314,7 @@ SVal SimpleSValuator::EvalBinOpNN(BinaryOperator::Opcode op,
}
}
}
- case nonloc::ConcreteIntKind: {
+ case nonloc::ConcreteIntKind: {
if (isa<nonloc::ConcreteInt>(rhs)) {
const nonloc::ConcreteInt& lhsInt = cast<nonloc::ConcreteInt>(lhs);
return lhsInt.evalBinOp(ValMgr, op, cast<nonloc::ConcreteInt>(rhs));
@@ -278,7 +326,7 @@ SVal SimpleSValuator::EvalBinOpNN(BinaryOperator::Opcode op,
NonLoc tmp = rhs;
rhs = lhs;
lhs = tmp;
-
+
switch (op) {
case BinaryOperator::LT: op = BinaryOperator::GT; continue;
case BinaryOperator::GT: op = BinaryOperator::LT; continue;
@@ -291,12 +339,27 @@ SVal SimpleSValuator::EvalBinOpNN(BinaryOperator::Opcode op,
continue;
default:
return UnknownVal();
- }
+ }
}
}
case nonloc::SymbolValKind: {
+ nonloc::SymbolVal *slhs = cast<nonloc::SymbolVal>(&lhs);
+ SymbolRef Sym = slhs->getSymbol();
+
+ // Does the symbol simplify to a constant?
+ if (Sym->getType(ValMgr.getContext())->isIntegerType())
+ if (const llvm::APSInt *Constant = state->getSymVal(Sym)) {
+ // What should we convert it to?
+ if (nonloc::ConcreteInt *rhs_I = dyn_cast<nonloc::ConcreteInt>(&rhs)){
+ BasicValueFactory &BVF = ValMgr.getBasicValueFactory();
+ lhs = nonloc::ConcreteInt(BVF.Convert(rhs_I->getValue(),
+ *Constant));
+ continue;
+ }
+ }
+
if (isa<nonloc::ConcreteInt>(rhs)) {
- return ValMgr.makeNonLoc(cast<nonloc::SymbolVal>(lhs).getSymbol(), op,
+ return ValMgr.makeNonLoc(slhs->getSymbol(), op,
cast<nonloc::ConcreteInt>(rhs).getValue(),
resultTy);
}
@@ -308,19 +371,26 @@ SVal SimpleSValuator::EvalBinOpNN(BinaryOperator::Opcode op,
}
SVal SimpleSValuator::EvalBinOpLL(BinaryOperator::Opcode op, Loc lhs, Loc rhs,
- QualType resultTy) {
+ QualType resultTy) {
switch (op) {
default:
return UnknownVal();
case BinaryOperator::EQ:
case BinaryOperator::NE:
return EvalEquality(ValMgr, lhs, rhs, op == BinaryOperator::EQ, resultTy);
+ case BinaryOperator::LT:
+ case BinaryOperator::GT:
+ // FIXME: Generalize. For now, just handle the trivial case where
+ // the two locations are identical.
+ if (lhs == rhs)
+ return ValMgr.makeTruthVal(false, resultTy);
+ return UnknownVal();
}
}
SVal SimpleSValuator::EvalBinOpLN(const GRState *state,
BinaryOperator::Opcode op,
- Loc lhs, NonLoc rhs, QualType resultTy) {
+ Loc lhs, NonLoc rhs, QualType resultTy) {
// Special case: 'rhs' is an integer that has the same width as a pointer and
// we are using the integer location in a comparison. Normally this cannot be
// triggered, but transfer functions like those for OSCommpareAndSwapBarrier32
@@ -333,13 +403,13 @@ SVal SimpleSValuator::EvalBinOpLN(const GRState *state,
if (ctx.getTypeSize(ctx.VoidPtrTy) == x->getBitWidth()) {
// Convert the signedness of the integer (if necessary).
if (x->isSigned())
- x = &ValMgr.getBasicValueFactory().getValue(*x, true);
+ x = &ValMgr.getBasicValueFactory().getValue(*x, true);
return EvalBinOpLL(op, lhs, loc::ConcreteInt(*x), resultTy);
}
}
}
-
+
// Delegate pointer arithmetic to the StoreManager.
return state->getStateManager().getStoreManager().EvalBinOp(state, op, lhs,
rhs, resultTy);
diff --git a/lib/Analysis/Store.cpp b/lib/Analysis/Store.cpp
index cb09986..4b4ae65 100644
--- a/lib/Analysis/Store.cpp
+++ b/lib/Analysis/Store.cpp
@@ -17,95 +17,189 @@
using namespace clang;
StoreManager::StoreManager(GRStateManager &stateMgr)
- : ValMgr(stateMgr.getValueManager()),
- StateMgr(stateMgr),
+ : ValMgr(stateMgr.getValueManager()), StateMgr(stateMgr),
MRMgr(ValMgr.getRegionManager()) {}
-StoreManager::CastResult
-StoreManager::CastRegion(const GRState* state, const MemRegion* R,
- QualType CastToTy) {
-
+const MemRegion *StoreManager::MakeElementRegion(const MemRegion *Base,
+ QualType EleTy, uint64_t index) {
+ SVal idx = ValMgr.makeArrayIndex(index);
+ return MRMgr.getElementRegion(EleTy, idx, Base, ValMgr.getContext());
+}
+
+// FIXME: Merge with the implementation of the same method in MemRegion.cpp
+static bool IsCompleteType(ASTContext &Ctx, QualType Ty) {
+ if (const RecordType *RT = Ty->getAs<RecordType>()) {
+ const RecordDecl *D = RT->getDecl();
+ if (!D->getDefinition(Ctx))
+ return false;
+ }
+
+ return true;
+}
+
+const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) {
+
ASTContext& Ctx = StateMgr.getContext();
- // We need to know the real type of CastToTy.
- QualType ToTy = Ctx.getCanonicalType(CastToTy);
+ // Handle casts to Objective-C objects.
+ if (CastToTy->isObjCObjectPointerType())
+ return R->getBaseRegion();
- // 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 (CastToTy->isBlockPointerType()) {
+ // FIXME: We may need different solutions, depending on the symbol
+ // involved. Blocks can be casted to/from 'id', as they can be treated
+ // as Objective-C objects. This could possibly be handled by enhancing
+ // our reasoning of downcasts of symbolic objects.
+ if (isa<CodeTextRegion>(R) || isa<SymbolicRegion>(R))
+ return R;
- if (Ta == ToTy)
- return CastResult(state, R);
+ // We don't know what to make of it. Return a NULL region, which
+ // will be interpretted as UnknownVal.
+ return NULL;
}
-
- 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;
+
+ // Now assume we are casting from pointer to pointer. Other cases should
+ // already be handled.
+ QualType PointeeTy = CastToTy->getAs<PointerType>()->getPointeeType();
+ QualType CanonPointeeTy = Ctx.getCanonicalType(PointeeTy);
+
+ // Handle casts to void*. We just pass the region through.
+ if (CanonPointeeTy.getUnqualifiedType() == Ctx.VoidTy)
+ return R;
+
+ // Handle casts from compatible types.
+ if (R->isBoundable())
+ if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) {
+ QualType ObjTy = Ctx.getCanonicalType(TR->getValueType(Ctx));
+ if (CanonPointeeTy == ObjTy)
+ return R;
+ }
+
+ // Process region cast according to the kind of the region being cast.
+ switch (R->getKind()) {
+ case MemRegion::BEG_TYPED_REGIONS:
+ case MemRegion::MemSpaceRegionKind:
+ case MemRegion::BEG_DECL_REGIONS:
+ case MemRegion::END_DECL_REGIONS:
+ case MemRegion::END_TYPED_REGIONS: {
+ assert(0 && "Invalid region cast");
+ break;
+ }
+ case MemRegion::CodeTextRegionKind: {
+ // CodeTextRegion should be cast to only a function or block pointer type,
+ // although they can in practice be casted to anything, e.g, void*, char*,
+ // etc.
+ // Just return the region.
+ return R;
+ }
+
+ case MemRegion::StringRegionKind:
+ case MemRegion::ObjCObjectRegionKind:
+ // FIXME: Need to handle arbitrary downcasts.
+ case MemRegion::SymbolicRegionKind:
+ case MemRegion::AllocaRegionKind:
+ case MemRegion::CompoundLiteralRegionKind:
+ case MemRegion::FieldRegionKind:
+ case MemRegion::ObjCIvarRegionKind:
+ case MemRegion::VarRegionKind:
+ return MakeElementRegion(R, PointeeTy);
+
+ case MemRegion::ElementRegionKind: {
+ // If we are casting from an ElementRegion to another type, the
+ // algorithm is as follows:
+ //
+ // (1) Compute the "raw offset" of the ElementRegion from the
+ // base region. This is done by calling 'getAsRawOffset()'.
+ //
+ // (2a) If we get a 'RegionRawOffset' after calling
+ // 'getAsRawOffset()', determine if the absolute offset
+ // can be exactly divided into chunks of the size of the
+ // casted-pointee type. If so, create a new ElementRegion with
+ // the pointee-cast type as the new ElementType and the index
+ // being the offset divded by the chunk size. If not, create
+ // a new ElementRegion at offset 0 off the raw offset region.
+ //
+ // (2b) If we don't a get a 'RegionRawOffset' after calling
+ // 'getAsRawOffset()', it means that we are at offset 0.
+ //
+ // FIXME: Handle symbolic raw offsets.
+
+ const ElementRegion *elementR = cast<ElementRegion>(R);
+ const RegionRawOffset &rawOff = elementR->getAsRawOffset();
+ const MemRegion *baseR = rawOff.getRegion();
+
+ // If we cannot compute a raw offset, throw up our hands and return
+ // a NULL MemRegion*.
+ if (!baseR)
+ return NULL;
+
+ int64_t off = rawOff.getByteOffset();
+
+ if (off == 0) {
+ // Edge case: we are at 0 bytes off the beginning of baseR. We
+ // check to see if type we are casting to is the same as the base
+ // region. If so, just return the base region.
+ if (const TypedRegion *TR = dyn_cast<TypedRegion>(baseR)) {
+ QualType ObjTy = Ctx.getCanonicalType(TR->getValueType(Ctx));
+ QualType CanonPointeeTy = Ctx.getCanonicalType(PointeeTy);
+ if (CanonPointeeTy == ObjTy)
+ return baseR;
}
- 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;
+
+ // Otherwise, create a new ElementRegion at offset 0.
+ return MakeElementRegion(baseR, PointeeTy);
+ }
+
+ // We have a non-zero offset from the base region. We want to determine
+ // if the offset can be evenly divided by sizeof(PointeeTy). If so,
+ // we create an ElementRegion whose index is that value. Otherwise, we
+ // create two ElementRegions, one that reflects a raw offset and the other
+ // that reflects the cast.
+
+ // Compute the index for the new ElementRegion.
+ int64_t newIndex = 0;
+ const MemRegion *newSuperR = 0;
+
+ // We can only compute sizeof(PointeeTy) if it is a complete type.
+ if (IsCompleteType(Ctx, PointeeTy)) {
+ // Compute the size in **bytes**.
+ int64_t pointeeTySize = (int64_t) (Ctx.getTypeSize(PointeeTy) / 8);
+
+ // Is the offset a multiple of the size? If so, we can layer the
+ // ElementRegion (with elementType == PointeeTy) directly on top of
+ // the base region.
+ if (off % pointeeTySize == 0) {
+ newIndex = off / pointeeTySize;
+ newSuperR = baseR;
}
- 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 MemRegion *Base = isa<ElementRegion>(TR) ? TR->getSuperRegion()
- : TR;
- ElementRegion* ER = MRMgr.getElementRegion(Pointee, Idx, Base,
- StateMgr.getContext());
- return CastResult(state, ER);
+
+ if (!newSuperR) {
+ // Create an intermediate ElementRegion to represent the raw byte.
+ // This will be the super region of the final ElementRegion.
+ newSuperR = MakeElementRegion(baseR, Ctx.CharTy, off);
}
+
+ return MakeElementRegion(newSuperR, PointeeTy, newIndex);
}
}
- // 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.
+ assert(0 && "unreachable");
+ return 0;
+}
+
- 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);
+/// CastRetrievedVal - Used by subclasses of StoreManager to implement
+/// implicit casts that arise from loads from regions that are reinterpreted
+/// as another region.
+SValuator::CastResult StoreManager::CastRetrievedVal(SVal V,
+ const GRState *state,
+ const TypedRegion *R,
+ QualType castTy) {
+ if (castTy.isNull())
+ return SValuator::CastResult(state, V);
+
+ ASTContext &Ctx = ValMgr.getContext();
+ return ValMgr.getSValuator().EvalCast(V, state, castTy, R->getValueType(Ctx));
}
+
diff --git a/lib/Analysis/SymbolManager.cpp b/lib/Analysis/SymbolManager.cpp
index 275f30a..22e1101 100644
--- a/lib/Analysis/SymbolManager.cpp
+++ b/lib/Analysis/SymbolManager.cpp
@@ -18,9 +18,11 @@
using namespace clang;
-static void print(llvm::raw_ostream& os, const SymExpr *SE);
+void SymExpr::dump() const {
+ dumpToStream(llvm::errs());
+}
-static void print(llvm::raw_ostream& os, BinaryOperator::Opcode Op) {
+static void print(llvm::raw_ostream& os, BinaryOperator::Opcode Op) {
switch (Op) {
default:
assert(false && "operator printing not implemented");
@@ -35,92 +37,100 @@ static void print(llvm::raw_ostream& os, BinaryOperator::Opcode Op) {
case BinaryOperator::LT: os << "<" ; break;
case BinaryOperator::GT: os << '>' ; break;
case BinaryOperator::LE: os << "<=" ; break;
- case BinaryOperator::GE: 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) {
+void SymIntExpr::dumpToStream(llvm::raw_ostream& os) const {
os << '(';
- print(os, SE->getLHS());
+ getLHS()->dumpToStream(os);
os << ") ";
- print(os, SE->getOpcode());
- os << ' ' << SE->getRHS().getZExtValue();
- if (SE->getRHS().isUnsigned()) os << 'U';
+ print(os, getOpcode());
+ os << ' ' << getRHS().getZExtValue();
+ if (getRHS().isUnsigned()) os << 'U';
}
-
-static void print(llvm::raw_ostream& os, const SymSymExpr *SE) {
+
+void SymSymExpr::dumpToStream(llvm::raw_ostream& os) const {
os << '(';
- print(os, SE->getLHS());
+ getLHS()->dumpToStream(os);
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;
- }
+ getRHS()->dumpToStream(os);
+ os << ')';
}
+void SymbolConjured::dumpToStream(llvm::raw_ostream& os) const {
+ os << "conj_$" << getSymbolID() << '{' << T.getAsString() << '}';
+}
+
+void SymbolDerived::dumpToStream(llvm::raw_ostream& os) const {
+ os << "derived_$" << getSymbolID() << '{'
+ << getParentSymbol() << ',' << getRegion() << '}';
+}
-llvm::raw_ostream& llvm::operator<<(llvm::raw_ostream& os, const SymExpr *SE) {
- print(os, SE);
- return os;
+void SymbolRegionValue::dumpToStream(llvm::raw_ostream& os) const {
+ os << "reg_$" << getSymbolID() << "<" << R << ">";
}
-const SymbolRegionValue*
+const SymbolRegionValue*
SymbolManager::getRegionValueSymbol(const MemRegion* R, QualType T) {
llvm::FoldingSetNodeID profile;
SymbolRegionValue::Profile(profile, R, T);
- void* InsertPos;
- SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
- if (!SD) {
+ void* InsertPos;
+ SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
+ if (!SD) {
SD = (SymExpr*) BPAlloc.Allocate<SymbolRegionValue>();
- new (SD) SymbolRegionValue(SymbolCounter, R, T);
+ new (SD) SymbolRegionValue(SymbolCounter, R, T);
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) {
+ 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);
+ new (SD) SymbolConjured(SymbolCounter, E, T, Count, SymbolTag);
+ DataSet.InsertNode(SD, InsertPos);
++SymbolCounter;
}
-
+
return cast<SymbolConjured>(SD);
}
+const SymbolDerived*
+SymbolManager::getDerivedSymbol(SymbolRef parentSymbol,
+ const TypedRegion *R) {
+
+ llvm::FoldingSetNodeID profile;
+ SymbolDerived::Profile(profile, parentSymbol, R);
+ void* InsertPos;
+ SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
+ if (!SD) {
+ SD = (SymExpr*) BPAlloc.Allocate<SymbolDerived>();
+ new (SD) SymbolDerived(SymbolCounter, parentSymbol, R);
+ DataSet.InsertNode(SD, InsertPos);
+ ++SymbolCounter;
+ }
+
+ return cast<SymbolDerived>(SD);
+}
+
const SymIntExpr *SymbolManager::getSymIntExpr(const SymExpr *lhs,
- BinaryOperator::Opcode op,
+ BinaryOperator::Opcode op,
const llvm::APSInt& v,
QualType t) {
llvm::FoldingSetNodeID ID;
@@ -133,7 +143,7 @@ const SymIntExpr *SymbolManager::getSymIntExpr(const SymExpr *lhs,
new (data) SymIntExpr(lhs, op, v, t);
DataSet.InsertNode(data, InsertPos);
}
-
+
return cast<SymIntExpr>(data);
}
@@ -151,7 +161,7 @@ const SymSymExpr *SymbolManager::getSymSymExpr(const SymExpr *lhs,
new (data) SymSymExpr(lhs, op, rhs, t);
DataSet.InsertNode(data, InsertPos);
}
-
+
return cast<SymSymExpr>(data);
}
@@ -159,39 +169,52 @@ QualType SymbolConjured::getType(ASTContext&) const {
return T;
}
+
+QualType SymbolDerived::getType(ASTContext& Ctx) const {
+ return R->getValueType(Ctx);
+}
+
QualType SymbolRegionValue::getType(ASTContext& C) const {
if (!T.isNull())
return T;
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();
+ return Loc::IsLocType(T) || (T->isIntegerType() && T->isScalarType());
}
void SymbolReaper::markLive(SymbolRef sym) {
- TheLiving = F.Add(TheLiving, sym);
- TheDead = F.Remove(TheDead, sym);
+ TheLiving.insert(sym);
+ TheDead.erase(sym);
}
bool SymbolReaper::maybeDead(SymbolRef sym) {
if (isLive(sym))
return false;
-
- TheDead = F.Add(TheDead, sym);
+
+ TheDead.insert(sym);
return true;
}
bool SymbolReaper::isLive(SymbolRef sym) {
- if (TheLiving.contains(sym))
+ if (TheLiving.count(sym))
return true;
-
+
+ if (const SymbolDerived *derived = dyn_cast<SymbolDerived>(sym)) {
+ if (isLive(derived->getParentSymbol())) {
+ markLive(sym);
+ return true;
+ }
+ return false;
+ }
+
// Interogate the symbol. It may derive from an input value to
// the analyzed function/method.
return isa<SymbolRegionValue>(sym);
diff --git a/lib/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp
index 014ea82..8e7b158 100644
--- a/lib/Analysis/UninitializedValues.cpp
+++ b/lib/Analysis/UninitializedValues.cpp
@@ -25,21 +25,21 @@ using namespace clang;
//===----------------------------------------------------------------------===//
// Dataflow initialization logic.
-//===----------------------------------------------------------------------===//
+//===----------------------------------------------------------------------===//
namespace {
class VISIBILITY_HIDDEN RegisterDecls
- : public CFGRecStmtDeclVisitor<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) {
@@ -49,25 +49,25 @@ void UninitializedValues::InitializeValues(const CFG& cfg) {
//===----------------------------------------------------------------------===//
// 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);
@@ -76,24 +76,24 @@ public:
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;
+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.
@@ -103,17 +103,17 @@ bool TransferFuncs::VisitDeclRefExpr(DeclRefExpr* DR) {
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 (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl()))
if (VD->isBlockVarDecl()) return VD;
return NULL;
@@ -136,7 +136,7 @@ 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())
+ 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:
@@ -145,20 +145,20 @@ bool TransferFuncs::VisitDeclStmt(DeclStmt* S) {
//
// 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
+ // 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
+ else
V(VD,AD) = Uninitialized;
}
}
}
return Uninitialized; // Value is never consumed.
}
-
+
bool TransferFuncs::VisitCallExpr(CallExpr* C) {
VisitChildren(C);
return Initialized;
@@ -172,14 +172,14 @@ bool TransferFuncs::VisitUnaryOperator(UnaryOperator* U) {
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'
@@ -203,12 +203,12 @@ TransferFuncs::BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) {
else
return Visit(ElemExpr);
}
-
+
V(VD,AD) = Initialized;
return Initialized;
}
-
-
+
+
bool TransferFuncs::VisitConditionalOperator(ConditionalOperator* C) {
Visit(C->getCond());
@@ -228,21 +228,21 @@ bool TransferFuncs::VisitStmt(Stmt* S) {
// 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);
+ bool x = static_cast<CFGStmtVisitor<TransferFuncs,bool>*>(this)->Visit(E);
if (AD.isTracked(E)) V(E,AD) = x;
return x;
}
-
+
} // end anonymous namespace
//===----------------------------------------------------------------------===//
@@ -255,7 +255,7 @@ bool TransferFuncs::BlockStmt_VisitExpr(Expr* E) {
// 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;
@@ -264,28 +264,28 @@ namespace {
//===----------------------------------------------------------------------===//
// 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()),
@@ -297,13 +297,13 @@ public:
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;
diff --git a/lib/Analysis/ValueManager.cpp b/lib/Analysis/ValueManager.cpp
index 724a2e9..fe670e7 100644
--- a/lib/Analysis/ValueManager.cpp
+++ b/lib/Analysis/ValueManager.cpp
@@ -22,16 +22,16 @@ using namespace llvm;
// Utility methods for constructing SVals.
//===----------------------------------------------------------------------===//
-SVal ValueManager::makeZeroVal(QualType T) {
+DefinedOrUnknownSVal ValueManager::makeZeroVal(QualType T) {
if (Loc::IsLocType(T))
return makeNull();
if (T->isIntegerType())
return makeIntVal(0, T);
-
+
// FIXME: Handle floats.
// FIXME: Handle structs.
- return UnknownVal();
+ return UnknownVal();
}
//===----------------------------------------------------------------------===//
@@ -55,71 +55,89 @@ NonLoc ValueManager::makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op,
}
-SVal ValueManager::getRegionValueSymbolVal(const MemRegion* R, QualType T) {
- SymbolRef sym = SymMgr.getRegionValueSymbol(R, T);
-
- if (const TypedRegion* TR = dyn_cast<TypedRegion>(R)) {
- if (T.isNull())
- T = TR->getValueType(SymMgr.getContext());
-
- // If T is of function pointer type, create a CodeTextRegion wrapping a
- // symbol.
- if (T->isFunctionPointerType()) {
- return loc::MemRegionVal(MemMgr.getCodeTextRegion(sym, T));
- }
-
- if (Loc::IsLocType(T))
- return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym));
-
- // Only handle integers for now.
- if (T->isIntegerType() && T->isScalarType())
- return nonloc::SymbolVal(sym);
+SVal ValueManager::convertToArrayIndex(SVal V) {
+ if (V.isUnknownOrUndef())
+ return V;
+
+ // Common case: we have an appropriately sized integer.
+ if (nonloc::ConcreteInt* CI = dyn_cast<nonloc::ConcreteInt>(&V)) {
+ const llvm::APSInt& I = CI->getValue();
+ if (I.getBitWidth() == ArrayIndexWidth && I.isSigned())
+ return V;
}
- return UnknownVal();
+ return SVator->EvalCastNL(cast<NonLoc>(V), ArrayIndexTy);
}
-SVal ValueManager::getConjuredSymbolVal(const Expr* E, unsigned Count) {
- QualType T = E->getType();
- SymbolRef sym = SymMgr.getConjuredSymbol(E, Count);
+DefinedOrUnknownSVal ValueManager::getRegionValueSymbolVal(const MemRegion* R,
+ QualType T) {
- // If T is of function pointer type, create a CodeTextRegion wrapping a
- // symbol.
- if (T->isFunctionPointerType()) {
- return loc::MemRegionVal(MemMgr.getCodeTextRegion(sym, T));
+ if (T.isNull()) {
+ const TypedRegion* TR = cast<TypedRegion>(R);
+ T = TR->getValueType(SymMgr.getContext());
}
+ if (!SymbolManager::canSymbolicate(T))
+ return UnknownVal();
+
+ SymbolRef sym = SymMgr.getRegionValueSymbol(R, T);
+
if (Loc::IsLocType(T))
return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym));
- if (T->isIntegerType() && T->isScalarType())
- return nonloc::SymbolVal(sym);
-
- return UnknownVal();
+ return nonloc::SymbolVal(sym);
}
-SVal ValueManager::getConjuredSymbolVal(const Expr* E, QualType T,
- unsigned Count) {
+DefinedOrUnknownSVal ValueManager::getConjuredSymbolVal(const void *SymbolTag,
+ const Expr *E,
+ unsigned Count) {
+ QualType T = E->getType();
+
+ if (!SymbolManager::canSymbolicate(T))
+ return UnknownVal();
- SymbolRef sym = SymMgr.getConjuredSymbol(E, T, Count);
+ SymbolRef sym = SymMgr.getConjuredSymbol(E, Count, SymbolTag);
- // If T is of function pointer type, create a CodeTextRegion wrapping a
- // symbol.
- if (T->isFunctionPointerType()) {
- return loc::MemRegionVal(MemMgr.getCodeTextRegion(sym, T));
- }
+ if (Loc::IsLocType(T))
+ return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym));
+
+ return nonloc::SymbolVal(sym);
+}
+
+DefinedOrUnknownSVal ValueManager::getConjuredSymbolVal(const void *SymbolTag,
+ const Expr *E,
+ QualType T,
+ unsigned Count) {
+
+ if (!SymbolManager::canSymbolicate(T))
+ return UnknownVal();
+
+ SymbolRef sym = SymMgr.getConjuredSymbol(E, T, Count, SymbolTag);
if (Loc::IsLocType(T))
return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym));
- if (T->isIntegerType() && T->isScalarType())
- return nonloc::SymbolVal(sym);
+ return nonloc::SymbolVal(sym);
+}
+
- return UnknownVal();
+DefinedOrUnknownSVal
+ValueManager::getDerivedRegionValueSymbolVal(SymbolRef parentSymbol,
+ const TypedRegion *R) {
+ QualType T = R->getValueType(R->getContext());
+
+ if (!SymbolManager::canSymbolicate(T))
+ return UnknownVal();
+
+ SymbolRef sym = SymMgr.getDerivedSymbol(parentSymbol, R);
+
+ if (Loc::IsLocType(T))
+ return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym));
+
+ return nonloc::SymbolVal(sym);
}
-SVal ValueManager::getFunctionPointer(const FunctionDecl* FD) {
- CodeTextRegion* R
- = MemMgr.getCodeTextRegion(FD, Context.getPointerType(FD->getType()));
+DefinedSVal ValueManager::getFunctionPointer(const FunctionDecl* FD) {
+ CodeTextRegion *R = MemMgr.getCodeTextRegion(FD);
return loc::MemRegionVal(R);
}
diff --git a/lib/Basic/Builtins.cpp b/lib/Basic/Builtins.cpp
index 6cb5dab..1a32937 100644
--- a/lib/Basic/Builtins.cpp
+++ b/lib/Basic/Builtins.cpp
@@ -34,7 +34,7 @@ Builtin::Context::Context(const TargetInfo &Target) {
// Get the target specific builtins from the target.
TSRecords = 0;
NumTSRecords = 0;
- Target.getTargetBuiltins(TSRecords, NumTSRecords);
+ Target.getTargetBuiltins(TSRecords, NumTSRecords);
}
/// InitializeBuiltins - Mark the identifiers for all the builtins with their
@@ -51,13 +51,13 @@ void Builtin::Context::InitializeBuiltins(IdentifierTable &Table,
// Step #2: Register target-specific builtins.
for (unsigned i = 0, e = NumTSRecords; i != e; ++i)
if (!TSRecords[i].Suppressed &&
- (!NoBuiltins ||
- (TSRecords[i].Attributes &&
+ (!NoBuiltins ||
+ (TSRecords[i].Attributes &&
!strchr(TSRecords[i].Attributes, 'f'))))
Table.get(TSRecords[i].Name).setBuiltinID(i+Builtin::FirstTSBuiltin);
}
-void
+void
Builtin::Context::GetBuiltinNames(llvm::SmallVectorImpl<const char *> &Names,
bool NoBuiltins) {
// Final all target-independent names
@@ -65,18 +65,18 @@ Builtin::Context::GetBuiltinNames(llvm::SmallVectorImpl<const char *> &Names,
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 &&
+ (!NoBuiltins ||
+ (TSRecords[i].Attributes &&
!strchr(TSRecords[i].Attributes, 'f'))))
Names.push_back(TSRecords[i].Name);
}
-bool
-Builtin::Context::isPrintfLike(unsigned ID, unsigned &FormatIdx,
+bool
+Builtin::Context::isPrintfLike(unsigned ID, unsigned &FormatIdx,
bool &HasVAListArg) {
const char *Printf = strpbrk(GetRecord(ID).Attributes, "pP");
if (!Printf)
diff --git a/lib/Basic/CMakeLists.txt b/lib/Basic/CMakeLists.txt
index e0e9a10..527ebf9 100644
--- a/lib/Basic/CMakeLists.txt
+++ b/lib/Basic/CMakeLists.txt
@@ -11,8 +11,19 @@ add_clang_library(clangBasic
TargetInfo.cpp
Targets.cpp
TokenKinds.cpp
+ Version.cpp
)
+# Determine Subversion revision.
+# FIXME: This only gets updated when CMake is run, so this revision number
+# may be out-of-date!
+find_package(Subversion)
+if (Subversion_FOUND)
+ Subversion_WC_INFO(${CLANG_SOURCE_DIR} CLANG)
+ set_source_files_properties(Version.cpp
+ PROPERTIES COMPILE_DEFINITIONS "SVN_REVISION=\"${CLANG_WC_REVISION}\"")
+endif()
+
add_dependencies(clangBasic
ClangDiagnosticAnalysis
ClangDiagnosticAST
diff --git a/lib/Basic/ConvertUTF.c b/lib/Basic/ConvertUTF.c
index e5dd3e6..124e386 100644
--- a/lib/Basic/ConvertUTF.c
+++ b/lib/Basic/ConvertUTF.c
@@ -34,10 +34,10 @@
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.
+ 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.
+ 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.
@@ -61,8 +61,8 @@ static const UTF32 halfMask = 0x3FFUL;
#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
+#define false 0
+#define true 1
/* --------------------------------------------------------------------- */
@@ -90,7 +90,7 @@ static const char trailingBytesForUTF8[256] = {
* in a UTF-8 sequence.
*/
static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL,
- 0x03C82080UL, 0xFA082080UL, 0x82082080UL };
+ 0x03C82080UL, 0xFA082080UL, 0x82082080UL };
/*
* Once the bits are split out into bytes of UTF-8, this is a mask OR-ed
@@ -116,46 +116,46 @@ static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF32toUTF16 (
- const UTF32** sourceStart, const UTF32* sourceEnd,
- UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
+ 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);
- }
+ 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;
@@ -165,48 +165,48 @@ ConversionResult ConvertUTF32toUTF16 (
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF16toUTF32 (
- const UTF16** sourceStart, const UTF16* sourceEnd,
- UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
+ 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;
+ 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;
@@ -219,67 +219,67 @@ if (result == sourceIllegal) {
return result;
}
ConversionResult ConvertUTF16toUTF8 (
- const UTF16** sourceStart, const UTF16* sourceEnd,
- UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
+ 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;
+ 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;
@@ -289,50 +289,50 @@ ConversionResult ConvertUTF16toUTF8 (
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF32toUTF8 (
- const UTF32** sourceStart, const UTF32* sourceEnd,
- UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
+ 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;
+ 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;
@@ -342,59 +342,59 @@ ConversionResult ConvertUTF32toUTF8 (
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF8toUTF32 (
- const UTF8** sourceStart, const UTF8* sourceEnd,
- UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
+ 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;
- }
+ 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;
@@ -420,19 +420,19 @@ static Boolean isLegalUTF8(const UTF8 *source, int length) {
const UTF8 *srcptr = source+length;
switch (length) {
default: return false;
- /* Everything else falls through when "true"... */
+ /* 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;
- }
+ 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;
}
@@ -449,7 +449,7 @@ static Boolean isLegalUTF8(const UTF8 *source, int length) {
Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) {
int length = trailingBytesForUTF8[*source]+1;
if (source+length > sourceEnd) {
- return false;
+ return false;
}
return isLegalUTF8(source, length);
}
@@ -457,70 +457,70 @@ Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) {
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF8toUTF16 (
- const UTF8** sourceStart, const UTF8* sourceEnd,
- UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
+ 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);
- }
+ 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;
@@ -533,14 +533,14 @@ ConversionResult ConvertUTF8toUTF16 (
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);
- }
+ {
+ 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
index 78b8b0a..4a29997 100644
--- a/lib/Basic/Diagnostic.cpp
+++ b/lib/Basic/Diagnostic.cpp
@@ -49,7 +49,7 @@ struct StaticDiagInfoRec {
bool SFINAE : 1;
const char *Description;
const char *OptionGroup;
-
+
bool operator<(const StaticDiagInfoRec &RHS) const {
return DiagID < RHS.DiagID;
}
@@ -88,16 +88,16 @@ static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) {
IsFirst = false;
}
#endif
-
+
// Search the diagnostic table with a binary search.
StaticDiagInfoRec Find = { DiagID, 0, 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;
}
@@ -141,7 +141,7 @@ namespace clang {
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 {
@@ -149,14 +149,14 @@ namespace clang {
"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);
@@ -164,7 +164,7 @@ namespace clang {
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));
@@ -172,9 +172,9 @@ namespace clang {
return ID;
}
};
-
- } // end diag namespace
-} // end clang namespace
+
+ } // end diag namespace
+} // end clang namespace
//===----------------------------------------------------------------------===//
@@ -196,32 +196,48 @@ Diagnostic::Diagnostic(DiagnosticClient *client) : Client(client) {
IgnoreAllWarnings = false;
WarningsAsErrors = false;
SuppressSystemWarnings = false;
+ SuppressAllDiagnostics = 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));
+ DiagMappings BlankDiags(diag::DIAG_UPPER_LIMIT/2, 0);
+ DiagMappingsStack.push_back(BlankDiags);
}
Diagnostic::~Diagnostic() {
delete CustomDiagInfo;
}
+
+void Diagnostic::pushMappings() {
+ DiagMappingsStack.push_back(DiagMappingsStack.back());
+}
+
+bool Diagnostic::popMappings() {
+ if (DiagMappingsStack.size() == 1)
+ return false;
+
+ DiagMappingsStack.pop_back();
+ return true;
+}
+
/// 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)
+ if (CustomDiagInfo == 0)
CustomDiagInfo = new diag::CustomDiagInfo();
return CustomDiagInfo->getOrCreateDiagID(L, Message, *this);
}
@@ -267,7 +283,7 @@ 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);
@@ -281,14 +297,14 @@ 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:
@@ -311,29 +327,29 @@ Diagnostic::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass) const {
// 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;
}
@@ -342,7 +358,7 @@ Diagnostic::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass) const {
// block, silence it.
if (AllExtensionsSilenced && isBuiltinExtensionDiag(DiagID))
return Diagnostic::Ignored;
-
+
return Result;
}
@@ -377,7 +393,7 @@ static void MapGroupMembers(const WarningOption *Group, diag::Mapping Mapping,
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)
@@ -390,7 +406,7 @@ static void MapGroupMembers(const WarningOption *Group, diag::Mapping Mapping,
/// 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,
@@ -398,7 +414,7 @@ bool Diagnostic::setDiagnosticGroupMapping(const char *Group,
if (Found == OptionTable + OptionTableSize ||
strcmp(Found->Name, Group) != 0)
return true; // Option not found.
-
+
MapGroupMembers(Found, Map, *this);
return false;
}
@@ -408,19 +424,22 @@ bool Diagnostic::setDiagnosticGroupMapping(const char *Group,
/// finally fully formed.
bool Diagnostic::ProcessDiag() {
DiagnosticInfo Info(this);
-
+
+ if (SuppressAllDiagnostics)
+ return false;
+
// 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 {
@@ -432,12 +451,12 @@ bool Diagnostic::ProcessDiag() {
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.
+ // 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);
}
}
@@ -451,7 +470,7 @@ bool Diagnostic::ProcessDiag() {
FatalErrorOccurred = true;
LastDiagLevel = DiagLevel;
- }
+ }
// If a fatal error has already been emitted, silence all subsequent
// diagnostics.
@@ -478,7 +497,7 @@ bool Diagnostic::ProcessDiag() {
ErrorOccurred = true;
++NumErrors;
}
-
+
// Finally, report it.
Client->HandleDiagnostic(DiagLevel, Info);
if (Client->IncludeInDiagnosticCounts()) ++NumDiagnostics;
@@ -508,7 +527,7 @@ 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, '|');
@@ -517,7 +536,7 @@ static void HandleSelectModifier(unsigned ValNo,
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.
@@ -590,7 +609,7 @@ static bool EvalPluralExpr(unsigned ValNo, const char *Start, const char *End) {
// Scan for next or-expr part.
Start = std::find(Start, End, ',');
- if(Start == End)
+ if (Start == End)
break;
++Start;
}
@@ -659,7 +678,7 @@ 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.
@@ -672,10 +691,10 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const {
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.
@@ -683,7 +702,7 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const {
// 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;
@@ -696,14 +715,14 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const {
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';
@@ -722,14 +741,14 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const {
// 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")) {
@@ -746,7 +765,7 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const {
}
case Diagnostic::ak_uint: {
unsigned Val = getArgUInt(ArgNo);
-
+
if (ModifierIs(Modifier, ModifierLen, "select")) {
HandleSelectModifier(Val, Argument, ArgumentLen, OutStr);
} else if (ModifierIs(Modifier, ModifierLen, "s")) {
@@ -755,7 +774,7 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const {
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());
@@ -782,6 +801,8 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const {
case Diagnostic::ak_qualtype:
case Diagnostic::ak_declarationname:
case Diagnostic::ak_nameddecl:
+ case Diagnostic::ak_nestednamespec:
+ case Diagnostic::ak_declcontext:
getDiags()->ConvertArgToString(getArgKind(ArgNo), getRawArg(ArgNo),
Modifier, ModifierLen,
Argument, ArgumentLen, OutStr);
diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp
index cc25d33..df86f9d 100644
--- a/lib/Basic/FileManager.cpp
+++ b/lib/Basic/FileManager.cpp
@@ -19,9 +19,12 @@
#include "clang/Basic/FileManager.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/System/Path.h"
-#include "llvm/Support/Streams.h"
#include "llvm/Config/config.h"
+#include <map>
+#include <set>
+#include <string>
using namespace clang;
// FIXME: Enhance libsystem to support inode and other fields.
@@ -44,8 +47,7 @@ using namespace clang;
#define IS_DIR_SEPARATOR_CHAR(x) ((x) == '/' || (x) == '\\')
namespace {
- static std::string GetFullPath(const char *relPath)
- {
+ static std::string GetFullPath(const char *relPath) {
char *absPathStrPtr = _fullpath(NULL, relPath, 0);
assert(absPathStrPtr && "_fullpath() returned NULL!");
@@ -59,7 +61,7 @@ namespace {
class FileManager::UniqueDirContainer {
/// UniqueDirs - Cache from full path to existing directories/files.
///
- llvm::StringMap<DirectoryEntry> UniqueDirs;
+ llvm::StringMap<DirectoryEntry> UniqueDirs;
public:
DirectoryEntry &getDirectory(const char *Name, struct stat &StatBuf) {
@@ -69,7 +71,7 @@ public:
FullPath.c_str() + FullPath.size()
).getValue();
}
-
+
size_t size() { return UniqueDirs.size(); }
};
@@ -101,7 +103,7 @@ public:
class FileManager::UniqueDirContainer {
/// UniqueDirs - Cache from ID's to existing directories/files.
///
- std::map<std::pair<dev_t, ino_t>, DirectoryEntry> UniqueDirs;
+ std::map<std::pair<dev_t, ino_t>, DirectoryEntry> UniqueDirs;
public:
DirectoryEntry &getDirectory(const char *Name, struct stat &StatBuf) {
@@ -149,27 +151,27 @@ FileManager::~FileManager() {
/// 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.
@@ -177,13 +179,13 @@ const DirectoryEntry *FileManager::getDirectory(const char *NameStart,
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.
+ // 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;
@@ -196,11 +198,11 @@ const DirectoryEntry *FileManager::getDirectory(const char *NameStart,
/// 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);
@@ -209,7 +211,7 @@ const FileEntry *FileManager::getFile(const char *NameStart,
if (NamedFileEnt.getValue())
return NamedFileEnt.getValue() == NON_EXISTENT_FILE
? 0 : NamedFileEnt.getValue();
-
+
++NumFileCacheMisses;
// By default, initialize it to invalid.
@@ -221,7 +223,10 @@ const FileEntry *FileManager::getFile(const char *NameStart,
const char *SlashPos = NameEnd-1;
while (SlashPos >= NameStart && !IS_DIR_SEPARATOR_CHAR(SlashPos[0]))
--SlashPos;
-
+ // Ignore duplicate //'s.
+ while (SlashPos > NameStart && IS_DIR_SEPARATOR_CHAR(SlashPos[-1]))
+ --SlashPos;
+
const DirectoryEntry *DirInfo;
if (SlashPos < NameStart) {
// Use the current directory if file has no path component.
@@ -231,32 +236,32 @@ const FileEntry *FileManager::getFile(const char *NameStart,
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;
+ //llvm::errs() << "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";
+ //llvm::errs() << ": Not existing\n";
return 0;
}
- //llvm::cerr << ": exists\n";
-
+ //llvm::errs() << ": 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;
@@ -273,23 +278,24 @@ const FileEntry *FileManager::getFile(const char *NameStart,
}
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;
+ llvm::errs() << "\n*** File Manager Stats:\n";
+ llvm::errs() << UniqueFiles.size() << " files found, "
+ << UniqueDirs.size() << " dirs found.\n";
+ llvm::errs() << NumDirLookups << " dir lookups, "
+ << NumDirCacheMisses << " dir cache misses.\n";
+ llvm::errs() << NumFileLookups << " file lookups, "
+ << NumFileCacheMisses << " file cache misses.\n";
+
+ //llvm::errs() << PagesMapped << BytesOfPagesMapped << FSLookups;
}
int MemorizeStatCalls::stat(const char *path, struct stat *buf) {
int result = ::stat(path, buf);
-
- if (result != 0) {
+
+ if (result != 0) {
// Cache failed 'stat' results.
struct stat empty;
+ memset(&empty, 0, sizeof(empty));
StatCalls[path] = StatResult(result, empty);
}
else if (!S_ISDIR(buf->st_mode) || llvm::sys::Path(path).isAbsolute()) {
@@ -297,6 +303,6 @@ int MemorizeStatCalls::stat(const char *path, struct stat *buf) {
// paths.
StatCalls[path] = StatResult(result, *buf);
}
-
- return result;
+
+ return result;
}
diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp
index 3810c49..93c260f 100644
--- a/lib/Basic/IdentifierTable.cpp
+++ b/lib/Basic/IdentifierTable.cpp
@@ -109,9 +109,9 @@ static void AddCXXOperatorKeyword(const char *Keyword, unsigned KWLen,
Info.setIsCPlusPlusOperatorKeyword();
}
-/// AddObjCKeyword - Register an Objective-C @keyword like "class" "selector" or
+/// AddObjCKeyword - Register an Objective-C @keyword like "class" "selector" or
/// "property".
-static void AddObjCKeyword(tok::ObjCKeywordKind ObjCID,
+static void AddObjCKeyword(tok::ObjCKeywordKind ObjCID,
const char *Name, unsigned NameLen,
IdentifierTable &Table) {
Table.get(Name, Name+NameLen).setObjCKeywordID(ObjCID);
@@ -144,13 +144,13 @@ tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const {
// 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();
@@ -179,7 +179,7 @@ tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const {
CASE( 8, 'u', 'a', unassert);
CASE(12, 'i', 'c', include_next);
-
+
CASE(16, '_', 'i', __include_macros);
#undef CASE
#undef HASH
@@ -198,7 +198,7 @@ void IdentifierTable::PrintStats() const {
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) {
@@ -207,7 +207,7 @@ void IdentifierTable::PrintStats() const {
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);
@@ -216,7 +216,7 @@ void IdentifierTable::PrintStats() const {
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();
}
@@ -232,42 +232,42 @@ unsigned llvm::DenseMapInfo<clang::Selector>::getHashValue(clang::Selector S) {
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
+/// to unique aggregate names (keyword selectors in ObjC parlance). Access to
/// this class is provided strictly through Selector.
-class MultiKeywordSelector
+class MultiKeywordSelector
: public DeclarationNameExtra, public llvm::FoldingSetNode {
MultiKeywordSelector(unsigned nKeys) {
ExtraKindOrNumArgs = NUM_EXTRA_KINDS + nKeys;
}
-public:
+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();
+ 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,
+ static void Profile(llvm::FoldingSetNodeID &ID,
keyword_iterator ArgTys, unsigned NumArgs) {
ID.AddInteger(NumArgs);
for (unsigned i = 0; i != NumArgs; ++i)
@@ -287,7 +287,7 @@ unsigned Selector::getNumArgs() const {
return 1;
// We point to a MultiKeywordSelector (pointer doesn't contain any flags).
MultiKeywordSelector *SI = reinterpret_cast<MultiKeywordSelector *>(InfoPtr);
- return SI->getNumArgs();
+ return SI->getNumArgs();
}
IdentifierInfo *Selector::getIdentifierInfoForSlot(unsigned argIndex) const {
@@ -308,16 +308,16 @@ std::string MultiKeywordSelector::getName() const {
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;
}
@@ -327,7 +327,7 @@ std::string Selector::getAsString() const {
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();
@@ -336,7 +336,7 @@ std::string Selector::getAsString() const {
Res += ":";
return Res;
}
-
+
// We have a multiple keyword selector (no embedded flags).
return reinterpret_cast<MultiKeywordSelector *>(InfoPtr)->getName();
}
@@ -357,9 +357,9 @@ static SelectorTableImpl &getSelectorTableImpl(void *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);
@@ -368,12 +368,12 @@ Selector SelectorTable::getSelector(unsigned nKeys, IdentifierInfo **IIV) {
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,
+ (MultiKeywordSelector*)SelTabImpl.Allocator.Allocate(Size,
llvm::alignof<MultiKeywordSelector>());
new (SI) MultiKeywordSelector(nKeys, IIV);
SelTabImpl.Table.InsertNode(SI, InsertPos);
diff --git a/lib/Basic/Makefile b/lib/Basic/Makefile
index 3fd6c2c..5bd4314 100644
--- a/lib/Basic/Makefile
+++ b/lib/Basic/Makefile
@@ -20,3 +20,14 @@ CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
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)/Version.o: $(ObjDir)/.ver-svn
diff --git a/lib/Basic/SourceLocation.cpp b/lib/Basic/SourceLocation.cpp
index f21ec8b..578a4eb 100644
--- a/lib/Basic/SourceLocation.cpp
+++ b/lib/Basic/SourceLocation.cpp
@@ -40,7 +40,7 @@ void SourceLocation::print(llvm::raw_ostream &OS, const SourceManager &SM)const{
OS << "<invalid loc>";
return;
}
-
+
if (isFileID()) {
PresumedLoc PLoc = SM.getPresumedLoc(*this);
// The instantiation and spelling pos is identical for file locs.
@@ -48,7 +48,7 @@ void SourceLocation::print(llvm::raw_ostream &OS, const SourceManager &SM)const{
<< ':' << PLoc.getColumn();
return;
}
-
+
SM.getInstantiationLoc(*this).print(OS, SM);
OS << " <Spelling=";
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index 6640c61..962cb4c 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -16,10 +16,9 @@
#include "clang/Basic/FileManager.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/System/Path.h"
-#include "llvm/Support/Streams.h"
#include <algorithm>
-#include <iostream>
using namespace clang;
using namespace SrcMgr;
using llvm::MemoryBuffer;
@@ -42,29 +41,74 @@ unsigned ContentCache::getSizeBytesMapped() 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, that
-/// file is not lazily brought in from disk to satisfy this query.
+/// file is not lazily brought in from disk to satisfy this query unless it
+/// needs to be truncated due to a truncateAt() call.
unsigned ContentCache::getSize() const {
- return Entry ? Entry->getSize() : Buffer->getBufferSize();
+ return Buffer ? Buffer->getBufferSize() : Entry->getSize();
}
-const llvm::MemoryBuffer *ContentCache::getBuffer() const {
+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());
+ if (isTruncated())
+ const_cast<ContentCache *>(this)->truncateAt(TruncateAtLine,
+ TruncateAtColumn);
}
return Buffer;
}
+void ContentCache::truncateAt(unsigned Line, unsigned Column) {
+ TruncateAtLine = Line;
+ TruncateAtColumn = Column;
+
+ if (!isTruncated() || !Buffer)
+ return;
+
+ // Find the byte position of the truncation point.
+ const char *Position = Buffer->getBufferStart();
+ for (unsigned Line = 1; Line < TruncateAtLine; ++Line) {
+ for (; *Position; ++Position) {
+ if (*Position != '\r' && *Position != '\n')
+ continue;
+
+ // Eat \r\n or \n\r as a single line.
+ if ((Position[1] == '\r' || Position[1] == '\n') &&
+ Position[0] != Position[1])
+ ++Position;
+ ++Position;
+ break;
+ }
+ }
+
+ for (unsigned Column = 1; Column < TruncateAtColumn; ++Column, ++Position) {
+ if (!*Position)
+ break;
+
+ if (*Position == '\t')
+ Column += 7;
+ }
+
+ // Truncate the buffer.
+ if (Position != Buffer->getBufferEnd()) {
+ MemoryBuffer *TruncatedBuffer
+ = MemoryBuffer::getMemBufferCopy(Buffer->getBufferStart(), Position,
+ Buffer->getBufferIdentifier());
+ delete Buffer;
+ Buffer = TruncatedBuffer;
+ }
+}
+
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 =
+ 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);
@@ -77,25 +121,25 @@ unsigned LineTableInfo::getLineTableFilenameID(const char *Ptr, unsigned Len) {
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));
}
@@ -110,9 +154,9 @@ void LineTableInfo::AddLineNote(unsigned FID, unsigned Offset,
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!");
@@ -124,14 +168,14 @@ void LineTableInfo::AddLineNote(unsigned FID, unsigned Offset,
} 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));
}
@@ -139,7 +183,7 @@ void LineTableInfo::AddLineNote(unsigned FID, unsigned Offset,
/// FindNearestLineEntry - Find the line entry nearest to FID that is before
/// it. If there is no line entry before Offset in FID, return null.
-const LineEntry *LineTableInfo::FindNearestLineEntry(unsigned FID,
+const LineEntry *LineTableInfo::FindNearestLineEntry(unsigned FID,
unsigned Offset) {
const std::vector<LineEntry> &Entries = LineEntries[FID];
assert(!Entries.empty() && "No #line entries for this FID after all!");
@@ -158,13 +202,13 @@ const LineEntry *LineTableInfo::FindNearestLineEntry(unsigned FID,
/// \brief Add a new line entry that has already been encoded into
/// the internal representation of the line table.
-void LineTableInfo::AddEntry(unsigned FID,
+void LineTableInfo::AddEntry(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();
@@ -178,12 +222,12 @@ unsigned SourceManager::getLineTableFilenameID(const char *Ptr, unsigned Len) {
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);
@@ -201,16 +245,16 @@ void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo,
"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;
@@ -218,13 +262,13 @@ void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo,
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);
}
@@ -241,7 +285,7 @@ LineTableInfo &SourceManager::getLineTable() {
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.
@@ -262,10 +306,10 @@ void SourceManager::clearIDTables() {
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);
@@ -276,11 +320,11 @@ void SourceManager::clearIDTables() {
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.
@@ -288,6 +332,16 @@ SourceManager::getOrCreateContentCache(const FileEntry *FileEnt) {
EntryAlign = std::max(8U, EntryAlign);
Entry = ContentCacheAlloc.Allocate<ContentCache>(1, EntryAlign);
new (Entry) ContentCache(FileEnt);
+
+ if (FileEnt == TruncateFile) {
+ // If we had queued up a file truncation request, perform the truncation
+ // now.
+ Entry->truncateAt(TruncateAtLine, TruncateAtColumn);
+ TruncateFile = 0;
+ TruncateAtLine = 0;
+ TruncateAtColumn = 0;
+ }
+
return Entry;
}
@@ -350,12 +404,12 @@ FileID SourceManager::createFileID(const ContentCache *File,
if (PreallocatedID) {
// If we're filling in a preallocated ID, just load in the file
// entry and return.
- assert(PreallocatedID < SLocEntryLoaded.size() &&
+ assert(PreallocatedID < SLocEntryLoaded.size() &&
"Preallocate ID out-of-range");
- assert(!SLocEntryLoaded[PreallocatedID] &&
+ assert(!SLocEntryLoaded[PreallocatedID] &&
"Source location entry already loaded");
assert(Offset && "Preallocate source location cannot have zero offset");
- SLocEntryTable[PreallocatedID]
+ SLocEntryTable[PreallocatedID]
= SLocEntry::get(Offset, FileInfo::get(IncludePos, File, FileCharacter));
SLocEntryLoaded[PreallocatedID] = true;
FileID FID = FileID::get(PreallocatedID);
@@ -364,13 +418,13 @@ FileID SourceManager::createFileID(const ContentCache *File,
return LastFileIDLookup = FID;
}
- SLocEntryTable.push_back(SLocEntry::get(NextOffset,
+ 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.
FileID FID = FileID::get(SLocEntryTable.size()-1);
@@ -392,9 +446,9 @@ SourceLocation SourceManager::createInstantiationLoc(SourceLocation SpellingLoc,
if (PreallocatedID) {
// If we're filling in a preallocated ID, just load in the
// instantiation entry and return.
- assert(PreallocatedID < SLocEntryLoaded.size() &&
+ assert(PreallocatedID < SLocEntryLoaded.size() &&
"Preallocate ID out-of-range");
- assert(!SLocEntryLoaded[PreallocatedID] &&
+ assert(!SLocEntryLoaded[PreallocatedID] &&
"Source location entry already loaded");
assert(Offset && "Preallocate source location cannot have zero offset");
SLocEntryTable[PreallocatedID] = SLocEntry::get(Offset, II);
@@ -427,7 +481,7 @@ SourceManager::getBufferData(FileID FID) const {
///
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
@@ -436,11 +490,11 @@ FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const {
// 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();
@@ -475,7 +529,7 @@ FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const {
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();
@@ -487,16 +541,16 @@ FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const {
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
@@ -514,7 +568,7 @@ FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const {
NumBinaryProbes += NumProbes;
return Res;
}
-
+
// Otherwise, move the low-side up to the middle index.
LessIndex = MiddleIndex;
}
@@ -551,12 +605,12 @@ SourceManager::getDecomposedInstantiationLocSlowCase(const SrcMgr::SLocEntry *E,
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);
}
@@ -569,12 +623,12 @@ SourceManager::getDecomposedSpellingLocSlowCase(const SrcMgr::SLocEntry *E,
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);
}
@@ -604,10 +658,10 @@ SourceManager::getImmediateInstantiationRange(SourceLocation Loc) const {
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())
@@ -629,7 +683,7 @@ 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;
@@ -640,7 +694,7 @@ const char *SourceManager::getCharacterData(SourceLocation SL) const {
/// 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;
@@ -663,17 +717,17 @@ unsigned SourceManager::getInstantiationColumnNumber(SourceLocation Loc) const {
static void ComputeLineNumbers(ContentCache* FI,
llvm::BumpPtrAllocator &Alloc) DISABLE_INLINE;
-static void ComputeLineNumbers(ContentCache* FI, llvm::BumpPtrAllocator &Alloc){
+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;
@@ -686,7 +740,7 @@ static void ComputeLineNumbers(ContentCache* FI, llvm::BumpPtrAllocator &Alloc){
++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])
@@ -700,7 +754,7 @@ static void ComputeLineNumbers(ContentCache* FI, llvm::BumpPtrAllocator &Alloc){
++Offs, ++Buf;
}
}
-
+
// Copy the offsets into the FileInfo structure.
FI->NumLines = LineOffsets.size();
FI->SourceLineCache = Alloc.Allocate<unsigned>(LineOffsets.size());
@@ -718,7 +772,7 @@ unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos) const {
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)
@@ -729,11 +783,11 @@ unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos) const {
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.
+ // 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
@@ -749,7 +803,7 @@ unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos) const {
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
@@ -771,17 +825,17 @@ unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos) const {
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);
@@ -790,17 +844,17 @@ unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos) const {
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;
@@ -820,14 +874,14 @@ unsigned SourceManager::getSpellingLineNumber(SourceLocation Loc) const {
}
/// getFileCharacteristic - return the file characteristic of the specified
-/// source location, indicating whether this is a normal file, a system
+/// 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
+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);
@@ -837,12 +891,12 @@ SourceManager::getFileCharacteristic(SourceLocation Loc) const {
// 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();
@@ -855,7 +909,7 @@ SourceManager::getFileCharacteristic(SourceLocation Loc) const {
/// for normal clients.
const char *SourceManager::getBufferName(SourceLocation Loc) const {
if (Loc.isInvalid()) return "<invalid loc>";
-
+
return getBuffer(getFileID(Loc))->getBufferIdentifier();
}
@@ -869,22 +923,22 @@ const char *SourceManager::getBufferName(SourceLocation Loc) const {
/// 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 =
+ 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()) {
@@ -902,9 +956,9 @@ PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc) const {
// 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);
@@ -933,7 +987,7 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile,
if (FI == FileInfos.end())
return SourceLocation();
ContentCache *Content = FI->second;
-
+
// If this is the first use of line information for this buffer, compute the
/// SourceLineCache for it on demand.
if (Content->SourceLineCache == 0)
@@ -941,7 +995,7 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile,
if (Line > Content->NumLines)
return SourceLocation();
-
+
unsigned FilePos = Content->SourceLineCache[Line - 1];
const char *Buf = Content->getBuffer()->getBufferStart() + FilePos;
unsigned BufLength = Content->getBuffer()->getBufferEnd() - Buf;
@@ -952,7 +1006,7 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile,
++i;
if (i < Col-1)
return SourceLocation();
-
+
return getLocForStartOfFile(Content->FirstFID).
getFileLocWithOffset(FilePos + Col - 1);
}
@@ -965,24 +1019,24 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS,
assert(LHS.isValid() && RHS.isValid() && "Passed invalid source location!");
if (LHS == RHS)
return false;
-
+
std::pair<FileID, unsigned> LOffs = getDecomposedLoc(LHS);
std::pair<FileID, unsigned> ROffs = getDecomposedLoc(RHS);
-
+
// If the source locations are in the same file, just compare offsets.
if (LOffs.first == ROffs.first)
return LOffs.second < ROffs.second;
// If we are comparing a source location with multiple locations in the same
// file, we get a big win by caching the result.
-
+
if (LastLFIDForBeforeTUCheck == LOffs.first &&
LastRFIDForBeforeTUCheck == ROffs.first)
return LastResForBeforeTUCheck;
-
+
LastLFIDForBeforeTUCheck = LOffs.first;
LastRFIDForBeforeTUCheck = ROffs.first;
-
+
// "Traverse" the include/instantiation stacks of both locations and try to
// find a common "ancestor".
//
@@ -1000,15 +1054,15 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS,
UpperLoc = Entry.getInstantiation().getInstantiationLocStart();
else
UpperLoc = Entry.getFile().getIncludeLoc();
-
+
if (UpperLoc.isInvalid())
break; // We reached the top.
-
+
ROffs = getDecomposedLoc(UpperLoc);
-
+
if (LOffs.first == ROffs.first)
return LastResForBeforeTUCheck = LOffs.second < ROffs.second;
-
+
ROffsMap[ROffs.first] = ROffs.second;
}
@@ -1022,33 +1076,33 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS,
UpperLoc = Entry.getInstantiation().getInstantiationLocStart();
else
UpperLoc = Entry.getFile().getIncludeLoc();
-
+
if (UpperLoc.isInvalid())
break; // We reached the top.
-
+
LOffs = getDecomposedLoc(UpperLoc);
-
+
std::map<FileID, unsigned>::iterator I = ROffsMap.find(LOffs.first);
if (I != ROffsMap.end())
return LastResForBeforeTUCheck = LOffs.second < I->second;
}
-
+
// No common ancestor.
// Now we are getting into murky waters. Most probably this is because one
// location is in the predefines buffer.
-
+
const FileEntry *LEntry =
getSLocEntry(LOffs.first).getFile().getContentCache()->Entry;
const FileEntry *REntry =
getSLocEntry(ROffs.first).getFile().getContentCache()->Entry;
-
+
// If the locations are in two memory buffers we give up, we can't answer
// which one should be considered first.
// FIXME: Should there be a way to "include" memory buffers in the translation
// unit ?
assert((LEntry != 0 || REntry != 0) && "Locations in memory buffers.");
(void) REntry;
-
+
// Consider the memory buffer as coming before the file in the translation
// unit.
if (LEntry == 0)
@@ -1059,26 +1113,48 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS,
}
}
+void SourceManager::truncateFileAt(const FileEntry *Entry, unsigned Line,
+ unsigned Column) {
+ llvm::DenseMap<const FileEntry*, SrcMgr::ContentCache*>::iterator FI
+ = FileInfos.find(Entry);
+ if (FI != FileInfos.end()) {
+ FI->second->truncateAt(Line, Column);
+ return;
+ }
+
+ // We cannot perform the truncation until we actually see the file, so
+ // save the truncation information.
+ assert(TruncateFile == 0 && "Can't queue up multiple file truncations!");
+ TruncateFile = Entry;
+ TruncateAtLine = Line;
+ TruncateAtColumn = Column;
+}
+
+/// \brief Determine whether this file was truncated.
+bool SourceManager::isTruncatedFile(FileID FID) const {
+ return getSLocEntry(FID).getFile().getContentCache()->isTruncated();
+}
+
/// 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";
-
+ llvm::errs() << "\n*** Source Manager Stats:\n";
+ llvm::errs() << FileInfos.size() << " files mapped, " << MemBufferInfos.size()
+ << " mem buffers mapped.\n";
+ llvm::errs() << SLocEntryTable.size() << " SLocEntry's allocated, "
+ << 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";
+
+ llvm::errs() << NumFileBytesMapped << " bytes of files mapped, "
+ << NumLineNumsComputed << " files with line #'s computed.\n";
+ llvm::errs() << "FileID scans: " << NumLinearScans << " linear, "
+ << NumBinaryProbes << " binary.\n";
}
ExternalSLocEntrySource::~ExternalSLocEntrySource() { }
diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp
index ba7f190..9cd1249 100644
--- a/lib/Basic/TargetInfo.cpp
+++ b/lib/Basic/TargetInfo.cpp
@@ -25,6 +25,8 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
TLSSupported = true;
PointerWidth = PointerAlign = 32;
WCharWidth = WCharAlign = 32;
+ Char16Width = Char16Align = 16;
+ Char32Width = Char32Align = 32;
IntWidth = IntAlign = 32;
LongWidth = LongAlign = 32;
LongLongWidth = LongLongAlign = 64;
@@ -41,6 +43,8 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
UIntMaxType = UnsignedLongLong;
IntPtrType = SignedLong;
WCharType = SignedInt;
+ Char16Type = UnsignedShort;
+ Char32Type = UnsignedInt;
Int64Type = SignedLongLong;
FloatFormat = &llvm::APFloat::IEEEsingle;
DoubleFormat = &llvm::APFloat::IEEEdouble;
@@ -83,17 +87,17 @@ static void removeGCCRegisterPrefix(const char *&Name) {
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;
@@ -107,11 +111,11 @@ bool TargetInfo::isValidGCCRegisterName(const char *Name) const {
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++) {
@@ -121,15 +125,15 @@ bool TargetInfo::isValidGCCRegisterName(const char *Name) const {
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;
@@ -140,16 +144,16 @@ const char *TargetInfo::getNormalizedGCCRegisterName(const char *Name) const {
char *End;
int n = (int)strtol(Name, &End, 0);
if (*End == 0) {
- assert(n >= 0 && (unsigned)n < NumNames &&
+ 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++) {
@@ -159,7 +163,7 @@ const char *TargetInfo::getNormalizedGCCRegisterName(const char *Name) const {
return Aliases[i].Register;
}
}
-
+
return Name;
}
@@ -184,6 +188,9 @@ bool TargetInfo::validateOutputConstraint(ConstraintInfo &Info) const {
}
case '&': // early clobber.
break;
+ case '%': // commutative.
+ // FIXME: Check that there is a another register after this one.
+ break;
case 'r': // general register.
Info.setAllowsRegister();
break;
@@ -196,10 +203,10 @@ bool TargetInfo::validateOutputConstraint(ConstraintInfo &Info) const {
Info.setAllowsMemory();
break;
}
-
+
Name++;
}
-
+
return true;
}
@@ -212,14 +219,14 @@ bool TargetInfo::resolveSymbolicName(const char *&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;
@@ -238,12 +245,12 @@ bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints,
// 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
+
+ // The constraint should have the same info as the respective
// output constraint.
Info.setTiedOperand(i, OutputConstraints[i]);
} else if (!validateAsmConstraint(Name, Info)) {
@@ -257,9 +264,9 @@ bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints,
unsigned Index = 0;
if (!resolveSymbolicName(Name, OutputConstraints, NumOutputs, Index))
return false;
-
+
break;
- }
+ }
case '%': // commutative
// FIXME: Fail if % is used with the last operand.
break;
@@ -287,9 +294,9 @@ bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints,
Info.setAllowsMemory();
break;
}
-
+
Name++;
}
-
+
return true;
}
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index 3f7d9a3..1d4d123 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -16,22 +16,25 @@
#include "clang/Basic/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"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/MC/MCSectionMachO.h"
using namespace clang;
//===----------------------------------------------------------------------===//
// Common code shared among targets.
//===----------------------------------------------------------------------===//
-static void Define(std::vector<char> &Buf, const char *Macro,
- const char *Val = "1") {
+static void Define(std::vector<char> &Buf, const llvm::StringRef &Macro,
+ const llvm::StringRef &Val = "1") {
const char *Def = "#define ";
Buf.insert(Buf.end(), Def, Def+strlen(Def));
- Buf.insert(Buf.end(), Macro, Macro+strlen(Macro));
+ Buf.insert(Buf.end(), Macro.begin(), Macro.end());
Buf.push_back(' ');
- Buf.insert(Buf.end(), Val, Val+strlen(Val));
+ Buf.insert(Buf.end(), Val.begin(), Val.end());
Buf.push_back('\n');
}
@@ -51,91 +54,34 @@ static void DefineStd(std::vector<char> &Buf, const char *MacroName,
llvm::SmallString<20> TmpStr;
TmpStr = "__";
TmpStr += MacroName;
- Define(Buf, TmpStr.c_str());
+ Define(Buf, TmpStr.str());
// Define __unix__.
TmpStr += "__";
- Define(Buf, TmpStr.c_str());
+ Define(Buf, TmpStr.str());
}
//===----------------------------------------------------------------------===//
// Defines specific to certain operating systems.
//===----------------------------------------------------------------------===//
+
namespace {
template<typename TgtInfo>
class OSTargetInfo : public TgtInfo {
protected:
- virtual void getOSDefines(const LangOptions &Opts, const char *Triple,
+ virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
std::vector<char> &Defines) const=0;
public:
OSTargetInfo(const std::string& triple) : TgtInfo(triple) {}
virtual void getTargetDefines(const LangOptions &Opts,
std::vector<char> &Defines) const {
TgtInfo::getTargetDefines(Opts, Defines);
- getOSDefines(Opts, TgtInfo::getTargetTriple(), Defines);
+ getOSDefines(Opts, TgtInfo::getTriple(), Defines);
}
};
-}
-
-namespace {
-/// 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;
- }
+} // end anonymous namespace
- return true;
-}
static void getDarwinDefines(std::vector<char> &Defs, const LangOptions &Opts) {
Define(Defs, "__APPLE_CC__", "5621");
@@ -156,81 +102,94 @@ static void getDarwinDefines(std::vector<char> &Defs, const LangOptions &Opts) {
Define(Defs, "__STATIC__");
else
Define(Defs, "__DYNAMIC__");
+
+ if (Opts.POSIXThreads)
+ Define(Defs, "_REENTRANT", "1");
}
-static void getDarwinOSXDefines(std::vector<char> &Defs, const char *Triple) {
+static void getDarwinOSXDefines(std::vector<char> &Defs,
+ const llvm::Triple &Triple) {
+ if (Triple.getOS() != llvm::Triple::Darwin)
+ return;
+
// 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;
- }
+ Triple.getDarwinNumber(Maj, Min, Rev);
- // 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);
+ 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) {
+ const llvm::Triple &Triple) {
+ if (Triple.getOS() != llvm::Triple::Darwin)
+ return;
+
// 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;
- }
+ Triple.getDarwinNumber(Maj, Min, Rev);
- // 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);
+ // 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) {
+ const llvm::Triple &Triple) {
Opts.NeXTRuntime = true;
- unsigned Maj, Min, Rev;
- if (!getDarwinNumber(Triple, Maj, Min, Rev))
+ if (Triple.getOS() != llvm::Triple::Darwin)
return;
+ unsigned MajorVersion = Triple.getDarwinMajorNumber();
+
// Blocks and stack protectors default to on for 10.6 (darwin10) and beyond.
- if (Maj > 9) {
+ if (MajorVersion > 9) {
Opts.Blocks = 1;
Opts.setStackProtectorMode(LangOptions::SSPOn);
}
// Non-fragile ABI (in 64-bit mode) default to on for 10.5 (darwin9) and
// beyond.
- if (Maj >= 9 && Opts.ObjC1 && !strncmp(Triple, "x86_64", 6))
+ if (MajorVersion >= 9 && Opts.ObjC1 &&
+ Triple.getArch() == llvm::Triple::x86_64)
Opts.ObjCNonFragileABI = 1;
}
+namespace {
template<typename Target>
class DarwinTargetInfo : public OSTargetInfo<Target> {
protected:
- virtual void getOSDefines(const LangOptions &Opts, const char *Triple,
+ virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
std::vector<char> &Defines) const {
getDarwinDefines(Defines, Opts);
getDarwinOSXDefines(Defines, Triple);
}
-
+
/// 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) {
TargetInfo::getDefaultLangOptions(Opts);
- GetDarwinLanguageOptions(Opts, TargetInfo::getTargetTriple());
+ GetDarwinLanguageOptions(Opts, TargetInfo::getTriple());
}
public:
DarwinTargetInfo(const std::string& triple) :
@@ -238,28 +197,25 @@ public:
this->TLSSupported = false;
}
- virtual const char *getCFStringSymbolPrefix() const {
- return "\01L_unnamed_cfstring_";
- }
-
- 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 std::string isValidSectionSpecifier(const llvm::StringRef &SR) const {
+ // Let MCSectionMachO validate this.
+ llvm::StringRef Segment, Section;
+ unsigned TAA, StubSize;
+ return llvm::MCSectionMachO::ParseSectionSpecifier(SR, Segment, Section,
+ TAA, StubSize);
+ }
};
+
// DragonFlyBSD Target
template<typename Target>
class DragonFlyBSDTargetInfo : public OSTargetInfo<Target> {
protected:
- virtual void getOSDefines(const LangOptions &Opts, const char *Triple,
+ virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
std::vector<char> &Defs) const {
// DragonFly defines; list based off of gcc output
Define(Defs, "__DragonFly__");
@@ -270,7 +226,7 @@ protected:
DefineStd(Defs, "unix", Opts);
}
public:
- DragonFlyBSDTargetInfo(const std::string &triple)
+ DragonFlyBSDTargetInfo(const std::string &triple)
: OSTargetInfo<Target>(triple) {}
};
@@ -278,11 +234,13 @@ public:
template<typename Target>
class FreeBSDTargetInfo : public OSTargetInfo<Target> {
protected:
- virtual void getOSDefines(const LangOptions &Opts, const char *Triple,
+ virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
std::vector<char> &Defs) const {
// FreeBSD defines; list based off of gcc output
- const char *FreeBSD = strstr(Triple, "-freebsd");
+ // FIXME: Move version number handling to llvm::Triple.
+ const char *FreeBSD = strstr(Triple.getTriple().c_str(),
+ "-freebsd");
FreeBSD += strlen("-freebsd");
char release[] = "X";
release[0] = FreeBSD[0];
@@ -296,43 +254,69 @@ protected:
Define(Defs, "__ELF__", "1");
}
public:
- FreeBSDTargetInfo(const std::string &triple)
- : OSTargetInfo<Target>(triple) {}
+ FreeBSDTargetInfo(const std::string &triple)
+ : OSTargetInfo<Target>(triple) {
+ this->UserLabelPrefix = "";
+ }
};
// Linux target
template<typename Target>
class LinuxTargetInfo : public OSTargetInfo<Target> {
protected:
- virtual void getOSDefines(const LangOptions &Opts, const char *Triple,
+ virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
std::vector<char> &Defs) const {
// Linux defines; list based off of gcc output
DefineStd(Defs, "unix", Opts);
DefineStd(Defs, "linux", Opts);
Define(Defs, "__gnu_linux__");
Define(Defs, "__ELF__", "1");
+ if (Opts.POSIXThreads)
+ Define(Defs, "_REENTRANT", "1");
}
public:
- LinuxTargetInfo(const std::string& triple)
+ LinuxTargetInfo(const std::string& triple)
: OSTargetInfo<Target>(triple) {
this->UserLabelPrefix = "";
}
};
+// NetBSD Target
+template<typename Target>
+class NetBSDTargetInfo : public OSTargetInfo<Target> {
+protected:
+ virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ std::vector<char> &Defs) const {
+ // NetBSD defines; list based off of gcc output
+ Define(Defs, "__NetBSD__", "1");
+ Define(Defs, "__unix__", "1");
+ Define(Defs, "__ELF__", "1");
+ if (Opts.POSIXThreads)
+ Define(Defs, "_POSIX_THREADS", "1");
+ }
+public:
+ NetBSDTargetInfo(const std::string &triple)
+ : OSTargetInfo<Target>(triple) {
+ this->UserLabelPrefix = "";
+ }
+};
+
// OpenBSD Target
template<typename Target>
class OpenBSDTargetInfo : public OSTargetInfo<Target> {
protected:
- virtual void getOSDefines(const LangOptions &Opts, const char *Triple,
+ virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
std::vector<char> &Defs) const {
// OpenBSD defines; list based off of gcc output
Define(Defs, "__OpenBSD__", "1");
DefineStd(Defs, "unix", Opts);
Define(Defs, "__ELF__", "1");
+ if (Opts.POSIXThreads)
+ Define(Defs, "_POSIX_THREADS", "1");
}
public:
- OpenBSDTargetInfo(const std::string &triple)
+ OpenBSDTargetInfo(const std::string &triple)
: OSTargetInfo<Target>(triple) {}
};
@@ -340,7 +324,7 @@ public:
template<typename Target>
class SolarisTargetInfo : public OSTargetInfo<Target> {
protected:
- virtual void getOSDefines(const LangOptions &Opts, const char *Triple,
+ virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
std::vector<char> &Defs) const {
DefineStd(Defs, "sun", Opts);
DefineStd(Defs, "unix", Opts);
@@ -349,20 +333,14 @@ protected:
Define(Defs, "__SVR4");
}
public:
- SolarisTargetInfo(const std::string& triple)
+ SolarisTargetInfo(const std::string& triple)
: OSTargetInfo<Target>(triple) {
this->UserLabelPrefix = "";
this->WCharType = this->SignedLong;
// FIXME: WIntType should be SignedLong
}
};
-} // end anonymous namespace.
-
-/// GetWindowsLanguageOptions - Set the default language options for Windows.
-static void GetWindowsLanguageOptions(LangOptions &Opts,
- const char *Triple) {
- Opts.Microsoft = true;
-}
+} // end anonymous namespace.
//===----------------------------------------------------------------------===//
// Specific target implementations.
@@ -398,9 +376,6 @@ public:
" 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,
@@ -464,21 +439,21 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts,
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",
+ "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",
+ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
+ "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
+ "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
+ "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
"mq", "lr", "ctr", "ap",
- "0", "1", "2", "3", "4", "5", "6", "7",
+ "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7",
"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",
+ "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",
+ "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15",
+ "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
+ "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31",
"vrsave", "vscr",
"spe_acc", "spefscr",
"sfp"
@@ -493,38 +468,71 @@ void PPCTargetInfo::getGCCRegNames(const char * const *&Names,
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" },
+ { { "0" }, "r0" },
+ { { "1"}, "r1" },
+ { { "2" }, "r2" },
+ { { "3" }, "r3" },
+ { { "4" }, "r4" },
+ { { "5" }, "r5" },
+ { { "6" }, "r6" },
+ { { "7" }, "r7" },
+ { { "8" }, "r8" },
+ { { "9" }, "r9" },
+ { { "10" }, "r10" },
+ { { "11" }, "r11" },
+ { { "12" }, "r12" },
+ { { "13" }, "r13" },
+ { { "14" }, "r14" },
+ { { "15" }, "r15" },
+ { { "16" }, "r16" },
+ { { "17" }, "r17" },
+ { { "18" }, "r18" },
+ { { "19" }, "r19" },
+ { { "20" }, "r20" },
+ { { "21" }, "r21" },
+ { { "22" }, "r22" },
+ { { "23" }, "r23" },
+ { { "24" }, "r24" },
+ { { "25" }, "r25" },
+ { { "26" }, "r26" },
+ { { "27" }, "r27" },
+ { { "28" }, "r28" },
+ { { "29" }, "r29" },
+ { { "30" }, "r30" },
+ { { "31" }, "r31" },
+ { { "fr0" }, "f0" },
+ { { "fr1" }, "f1" },
+ { { "fr2" }, "f2" },
+ { { "fr3" }, "f3" },
+ { { "fr4" }, "f4" },
+ { { "fr5" }, "f5" },
+ { { "fr6" }, "f6" },
+ { { "fr7" }, "f7" },
+ { { "fr8" }, "f8" },
+ { { "fr9" }, "f9" },
+ { { "fr10" }, "f10" },
+ { { "fr11" }, "f11" },
+ { { "fr12" }, "f12" },
+ { { "fr13" }, "f13" },
+ { { "fr14" }, "f14" },
+ { { "fr15" }, "f15" },
+ { { "fr16" }, "f16" },
+ { { "fr17" }, "f17" },
+ { { "fr18" }, "f18" },
+ { { "fr19" }, "f19" },
+ { { "fr20" }, "f20" },
+ { { "fr21" }, "f21" },
+ { { "fr22" }, "f22" },
+ { { "fr23" }, "f23" },
+ { { "fr24" }, "f24" },
+ { { "fr25" }, "f25" },
+ { { "fr26" }, "f26" },
+ { { "fr27" }, "f27" },
+ { { "fr28" }, "f28" },
+ { { "fr29" }, "f29" },
+ { { "fr30" }, "f30" },
+ { { "fr31" }, "f31" },
+ { { "cc" }, "cr0" },
};
void PPCTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases,
@@ -603,9 +611,6 @@ public:
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;
@@ -627,12 +632,12 @@ public:
virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features,
const std::string &Name,
bool Enabled) const;
- virtual void getDefaultFeatures(const std::string &CPU,
+ 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,
+void X86TargetInfo::getDefaultFeatures(const std::string &CPU,
llvm::StringMap<bool> &Features) const {
// FIXME: This should not be here.
Features["3dnow"] = false;
@@ -676,7 +681,7 @@ void X86TargetInfo::getDefaultFeatures(const std::string &CPU,
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" ||
+ 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);
@@ -685,14 +690,14 @@ void X86TargetInfo::getDefaultFeatures(const std::string &CPU,
setFeatureEnabled(Features, "3dnowa", true);
} else if (CPU == "k8" || CPU == "opteron" || CPU == "athlon64" ||
CPU == "athlon-fx") {
- setFeatureEnabled(Features, "sse2", true);
+ 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,
+ const std::string &Name,
bool Enabled) const {
// FIXME: This *really* should not be here.
if (!Features.count(Name) && Name != "sse4")
@@ -706,13 +711,13 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
else if (Name == "sse2")
Features["mmx"] = Features["sse"] = Features["sse2"] = true;
else if (Name == "sse3")
- Features["mmx"] = Features["sse"] = Features["sse2"] =
+ Features["mmx"] = Features["sse"] = Features["sse2"] =
Features["sse3"] = true;
else if (Name == "ssse3")
- Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
+ Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
Features["ssse3"] = true;
else if (Name == "sse4")
- Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
+ Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
Features["ssse3"] = Features["sse41"] = Features["sse42"] = true;
else if (Name == "3dnow")
Features["3dnowa"] = true;
@@ -720,16 +725,16 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
Features["3dnow"] = Features["3dnowa"] = true;
} else {
if (Name == "mmx")
- Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
+ 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["sse"] = Features["sse2"] = Features["sse3"] =
Features["ssse3"] = Features["sse41"] = Features["sse42"] = false;
else if (Name == "sse2")
- Features["sse2"] = Features["sse3"] = Features["ssse3"] =
+ Features["sse2"] = Features["sse3"] = Features["ssse3"] =
Features["sse41"] = Features["sse42"] = false;
else if (Name == "sse3")
- Features["sse3"] = Features["ssse3"] = Features["sse41"] =
+ Features["sse3"] = Features["ssse3"] = Features["sse41"] =
Features["sse42"] = false;
else if (Name == "ssse3")
Features["ssse3"] = Features["sse41"] = Features["sse42"] = false;
@@ -885,6 +890,24 @@ public:
virtual const char *getVAListDeclaration() const {
return "typedef char* __builtin_va_list;";
}
+
+ int getEHDataRegisterNumber(unsigned RegNo) const {
+ if (RegNo == 0) return 0;
+ if (RegNo == 1) return 2;
+ return -1;
+ }
+};
+} // end anonymous namespace
+
+namespace {
+class OpenBSDI386TargetInfo : public OpenBSDTargetInfo<X86_32TargetInfo> {
+public:
+ OpenBSDI386TargetInfo(const std::string& triple) :
+ OpenBSDTargetInfo<X86_32TargetInfo>(triple) {
+ SizeType = UnsignedLong;
+ IntPtrType = SignedLong;
+ PtrDiffType = SignedLong;
+ }
};
} // end anonymous namespace
@@ -927,12 +950,75 @@ public:
DefineStd(Defines, "WIN32", Opts);
DefineStd(Defines, "WINNT", Opts);
Define(Defines, "_X86_");
- Define(Defines, "__MSVCRT__");
}
+};
+} // end anonymous namespace
+namespace {
+
+/// GetWindowsVisualStudioLanguageOptions - Set the default language options for Windows.
+static void GetWindowsVisualStudioLanguageOptions(LangOptions &Opts) {
+ Opts.Microsoft = true;
+}
+
+// x86-32 Windows Visual Studio target
+class VisualStudioWindowsX86_32TargetInfo : public WindowsX86_32TargetInfo {
+public:
+ VisualStudioWindowsX86_32TargetInfo(const std::string& triple)
+ : WindowsX86_32TargetInfo(triple) {
+ }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ std::vector<char> &Defines) const {
+ WindowsX86_32TargetInfo::getTargetDefines(Opts, Defines);
+ // The value of the following reflects processor type.
+ // 300=386, 400=486, 500=Pentium, 600=Blend (default)
+ // We lost the original triple, so we use the default.
+ Define(Defines, "_M_IX86", "600");
+ }
virtual void getDefaultLangOptions(LangOptions &Opts) {
- X86_32TargetInfo::getDefaultLangOptions(Opts);
- GetWindowsLanguageOptions(Opts, getTargetTriple());
+ WindowsX86_32TargetInfo::getDefaultLangOptions(Opts);
+ GetWindowsVisualStudioLanguageOptions(Opts);
+ }
+};
+} // end anonymous namespace
+
+namespace {
+// x86-32 MinGW target
+class MinGWX86_32TargetInfo : public WindowsX86_32TargetInfo {
+public:
+ MinGWX86_32TargetInfo(const std::string& triple)
+ : WindowsX86_32TargetInfo(triple) {
+ }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ std::vector<char> &Defines) const {
+ WindowsX86_32TargetInfo::getTargetDefines(Opts, Defines);
+ Define(Defines, "__MSVCRT__");
+ Define(Defines, "__MINGW32__");
+ Define(Defines, "__declspec", "__declspec");
+ }
+};
+} // end anonymous namespace
+
+namespace {
+// x86-32 Cygwin target
+class CygwinX86_32TargetInfo : public X86_32TargetInfo {
+public:
+ CygwinX86_32TargetInfo(const std::string& triple)
+ : X86_32TargetInfo(triple) {
+ TLSSupported = false;
+ WCharType = UnsignedShort;
+ WCharWidth = WCharAlign = 16;
+ DoubleAlign = LongLongAlign = 64;
+ DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
+ "i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-"
+ "a0:0:64-f80:32:32";
+ }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ std::vector<char> &Defines) const {
+ X86_32TargetInfo::getTargetDefines(Opts, Defines);
+ Define(Defines, "__CYGWIN__");
+ Define(Defines, "__CYGWIN32__");
+ DefineStd(Defines, "unix", Opts);
}
};
} // end anonymous namespace
@@ -963,13 +1049,75 @@ public:
"} __va_list_tag;"
"typedef __va_list_tag __builtin_va_list[1];";
}
+
+ int getEHDataRegisterNumber(unsigned RegNo) const {
+ if (RegNo == 0) return 0;
+ if (RegNo == 1) return 1;
+ return -1;
+ }
+};
+} // end anonymous namespace
+
+namespace {
+// x86-64 Windows target
+class WindowsX86_64TargetInfo : public X86_64TargetInfo {
+public:
+ WindowsX86_64TargetInfo(const std::string& triple)
+ : X86_64TargetInfo(triple) {
+ TLSSupported = false;
+ WCharType = UnsignedShort;
+ WCharWidth = WCharAlign = 16;
+ LongWidth = LongAlign = 32;
+ DoubleAlign = LongLongAlign = 64;
+ }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ std::vector<char> &Defines) const {
+ X86_64TargetInfo::getTargetDefines(Opts, Defines);
+ Define(Defines, "_WIN64");
+ DefineStd(Defines, "WIN64", Opts);
+ }
+};
+} // end anonymous namespace
+
+namespace {
+// x86-64 Windows Visual Studio target
+class VisualStudioWindowsX86_64TargetInfo : public WindowsX86_64TargetInfo {
+public:
+ VisualStudioWindowsX86_64TargetInfo(const std::string& triple)
+ : WindowsX86_64TargetInfo(triple) {
+ }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ std::vector<char> &Defines) const {
+ WindowsX86_64TargetInfo::getTargetDefines(Opts, Defines);
+ Define(Defines, "_M_X64");
+ }
+ virtual const char *getVAListDeclaration() const {
+ return "typedef char* va_list;";
+ }
+};
+} // end anonymous namespace
+
+namespace {
+// x86-64 MinGW target
+class MinGWX86_64TargetInfo : public WindowsX86_64TargetInfo {
+public:
+ MinGWX86_64TargetInfo(const std::string& triple)
+ : WindowsX86_64TargetInfo(triple) {
+ }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ std::vector<char> &Defines) const {
+ WindowsX86_64TargetInfo::getTargetDefines(Opts, Defines);
+ Define(Defines, "__MSVCRT__");
+ Define(Defines, "__MINGW64__");
+ Define(Defines, "__declspec");
+ }
};
} // end anonymous namespace
namespace {
class DarwinX86_64TargetInfo : public DarwinTargetInfo<X86_64TargetInfo> {
public:
- DarwinX86_64TargetInfo(const std::string& triple)
+ DarwinX86_64TargetInfo(const std::string& triple)
: DarwinTargetInfo<X86_64TargetInfo>(triple) {
Int64Type = SignedLongLong;
}
@@ -977,33 +1125,107 @@ public:
} // end anonymous namespace
namespace {
+class OpenBSDX86_64TargetInfo : public OpenBSDTargetInfo<X86_64TargetInfo> {
+public:
+ OpenBSDX86_64TargetInfo(const std::string& triple)
+ : OpenBSDTargetInfo<X86_64TargetInfo>(triple) {
+ IntMaxType = SignedLongLong;
+ UIntMaxType = UnsignedLongLong;
+ Int64Type = SignedLongLong;
+ }
+};
+} // end anonymous namespace
+
+namespace {
class ARMTargetInfo : public TargetInfo {
enum {
Armv4t,
Armv5,
Armv6,
+ Armv7a,
XScale
} ArmArch;
+
+ static const TargetInfo::GCCRegAlias GCCRegAliases[];
+ static const char * const GCCRegNames[];
+
+ std::string ABI;
+ bool IsThumb;
+
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)
+ ARMTargetInfo(const std::string &TripleStr)
+ : TargetInfo(TripleStr), ABI("aapcs-linux"), IsThumb(false)
+ {
+ llvm::Triple Triple(TripleStr);
+
+ SizeType = UnsignedInt;
+ PtrDiffType = SignedInt;
+
+ // FIXME: This shouldn't be done this way, we should use features to
+ // indicate the arch. See lib/Driver/Tools.cpp.
+ llvm::StringRef Version(""), Arch = Triple.getArchName();
+ if (Arch.startswith("arm"))
+ Version = Arch.substr(3);
+ else if (Arch.startswith("thumb"))
+ Version = Arch.substr(5);
+ if (Version == "v7")
+ ArmArch = Armv7a;
+ else if (Version.empty() || Version == "v6" || Version == "v6t2")
ArmArch = Armv6;
- else if (triple.find("armv5-") == 0)
+ else if (Version == "v5")
ArmArch = Armv5;
- else if (triple.find("armv4t-") == 0)
+ else if (Version == "v4t")
ArmArch = Armv4t;
- else if (triple.find("xscale-") == 0)
+ else if (Arch == "xscale" || Arch == "thumbv5e")
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.
+ else
ArmArch = Armv6;
+
+ if (Arch.startswith("thumb"))
+ IsThumb = true;
+
+ if (IsThumb) {
+ DescriptionString = ("e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-"
+ "i64:64:64-f32:32:32-f64:64:64-"
+ "v64:64:64-v128:128:128-a0:0:32");
+ } else {
+ DescriptionString = ("e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
+ "i64:64:64-f32:32:32-f64:64:64-"
+ "v64:64:64-v128:128:128-a0:0:64");
}
}
+ virtual const char *getABI() const { return ABI.c_str(); }
+ virtual bool setABI(const std::string &Name) {
+ ABI = Name;
+
+ // The defaults (above) are for AAPCS, check if we need to change them.
+ //
+ // FIXME: We need support for -meabi... we could just mangle it into the
+ // name.
+ if (Name == "apcs-gnu") {
+ DoubleAlign = LongLongAlign = 32;
+ SizeType = UnsignedLong;
+
+ if (IsThumb) {
+ DescriptionString = ("e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-"
+ "i64:32:32-f32:32:32-f64:32:32-"
+ "v64:64:64-v128:128:128-a0:0:32");
+ } else {
+ DescriptionString = ("e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
+ "i64:32:32-f32:32:32-f64:32:32-"
+ "v64:64:64-v128:128:128-a0:0:64");
+ }
+
+ // FIXME: Override "preferred align" for double and long long.
+ } else if (Name == "aapcs") {
+ // FIXME: Enumerated types are variable width in straight AAPCS.
+ } else if (Name == "aapcs-linux") {
+ ;
+ } else
+ return false;
+
+ return true;
+ }
virtual void getTargetDefines(const LangOptions &Opts,
std::vector<char> &Defs) const {
// Target identification.
@@ -1014,7 +1236,13 @@ public:
Define(Defs, "__LITTLE_ENDIAN__");
// Subtarget options.
- if (ArmArch == Armv6) {
+ //
+ // FIXME: Neither THUMB_INTERWORK nor SOFTFP is not being set correctly
+ // here.
+ if (ArmArch == Armv7a) {
+ Define(Defs, "__ARM_ARCH_7A__");
+ Define(Defs, "__THUMB_INTERWORK__");
+ } else if (ArmArch == Armv6) {
Define(Defs, "__ARM_ARCH_6K__");
Define(Defs, "__THUMB_INTERWORK__");
} else if (ArmArch == Armv5) {
@@ -1029,9 +1257,22 @@ public:
Define(Defs, "__XSCALE__");
Define(Defs, "__SOFTFP__");
}
+
Define(Defs, "__ARMEL__");
+
+ if (IsThumb) {
+ Define(Defs, "__THUMBEL__");
+ Define(Defs, "__thumb__");
+ if (ArmArch == Armv7a)
+ Define(Defs, "__thumb2__");
+ }
+
+ // Note, this is always on in gcc, even though it doesn't make sense.
Define(Defs, "__APCS_32__");
+ // FIXME: This should be conditional on VFP instruction support.
Define(Defs, "__VFP_FP__");
+
+ Define(Defs, "__USING_SJLJ_EXCEPTIONS__");
}
virtual void getTargetBuiltins(const Builtin::Info *&Records,
unsigned &NumRecords) const {
@@ -1042,21 +1283,10 @@ public:
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;
- }
+ unsigned &NumNames) const;
virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
- unsigned &NumAliases) const {
- // FIXME: Implement.
- Aliases = 0;
- NumAliases = 0;
- }
+ unsigned &NumAliases) const;
virtual bool validateAsmConstraint(const char *&Name,
TargetInfo::ConstraintInfo &Info) const {
// FIXME: Check if this is complete
@@ -1076,21 +1306,58 @@ public:
return "";
}
};
+
+const char * const ARMTargetInfo::GCCRegNames[] = {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
+};
+
+void ARMTargetInfo::getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const {
+ Names = GCCRegNames;
+ NumNames = llvm::array_lengthof(GCCRegNames);
+}
+
+const TargetInfo::GCCRegAlias ARMTargetInfo::GCCRegAliases[] = {
+
+ { { "a1" }, "r0" },
+ { { "a2" }, "r1" },
+ { { "a3" }, "r2" },
+ { { "a4" }, "r3" },
+ { { "v1" }, "r4" },
+ { { "v2" }, "r5" },
+ { { "v3" }, "r6" },
+ { { "v4" }, "r7" },
+ { { "v5" }, "r8" },
+ { { "v6", "rfp" }, "r9" },
+ { { "sl" }, "r10" },
+ { { "fp" }, "r11" },
+ { { "ip" }, "r12" },
+ { { "sp" }, "r13" },
+ { { "lr" }, "r14" },
+ { { "pc" }, "r15" },
+};
+
+void ARMTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const {
+ Aliases = GCCRegAliases;
+ NumAliases = llvm::array_lengthof(GCCRegAliases);
+}
} // end anonymous namespace.
namespace {
-class DarwinARMTargetInfo :
+class DarwinARMTargetInfo :
public DarwinTargetInfo<ARMTargetInfo> {
protected:
- virtual void getOSDefines(const LangOptions &Opts, const char *Triple,
+ virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
std::vector<char> &Defines) const {
getDarwinDefines(Defines, Opts);
getDarwinIPhoneOSDefines(Defines, Triple);
}
public:
- DarwinARMTargetInfo(const std::string& triple)
+ DarwinARMTargetInfo(const std::string& triple)
: DarwinTargetInfo<ARMTargetInfo>(triple) {}
};
} // end anonymous namespace.
@@ -1118,9 +1385,6 @@ public:
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,
@@ -1236,12 +1500,25 @@ namespace {
virtual void getTargetDefines(const LangOptions &Opts,
std::vector<char> &Defines) const {
Define(Defines, "__pic16");
+ Define(Defines, "rom", "__attribute__((address_space(1)))");
+ Define(Defines, "ram", "__attribute__((address_space(0)))");
+ Define(Defines, "_section(SectName)",
+ "__attribute__((section(SectName)))");
+ Define(Defines, "_address(Addr)",
+ "__attribute__((section(\"Address=\"#Addr)))");
+ Define(Defines, "_CONFIG(conf)", "asm(\"CONFIG \"#conf)");
+ Define(Defines, "_interrupt",
+ "__attribute__((section(\"interrupt=0x4\"))) \
+ __attribute__((used))");
}
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 const char *getVAListDeclaration() const {
+ return "";
+ }
+ virtual const char *getClobbers() const {
+ return "";
+ }
virtual void getGCCRegNames(const char * const *&Names,
unsigned &NumNames) const {}
virtual bool validateAsmConstraint(const char *&Name,
@@ -1286,9 +1563,6 @@ namespace {
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,
@@ -1325,93 +1599,309 @@ namespace {
}
+namespace {
+ class SystemZTargetInfo : public TargetInfo {
+ static const char * const GCCRegNames[];
+ public:
+ SystemZTargetInfo(const std::string& triple) : TargetInfo(triple) {
+ TLSSupported = false;
+ IntWidth = IntAlign = 32;
+ LongWidth = LongLongWidth = LongAlign = LongLongAlign = 64;
+ PointerWidth = PointerAlign = 64;
+ DescriptionString = "E-p:64:64:64-i8:8:16-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-f128:128:128-a0:16:16";
+ }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ std::vector<char> &Defines) const {
+ Define(Defines, "__s390__");
+ Define(Defines, "__s390x__");
+ }
+ virtual void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const {
+ // FIXME: Implement.
+ Records = 0;
+ NumRecords = 0;
+ }
+
+ virtual void getDefaultLangOptions(LangOptions &Opts) {
+ TargetInfo::getDefaultLangOptions(Opts);
+ Opts.CharIsSigned = false;
+ }
+
+ 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 SystemZTargetInfo::GCCRegNames[] = {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
+ };
+
+ void SystemZTargetInfo::getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const {
+ Names = GCCRegNames;
+ NumNames = llvm::array_lengthof(GCCRegNames);
+ }
+}
+
+namespace {
+ class BlackfinTargetInfo : public TargetInfo {
+ static const char * const GCCRegNames[];
+ public:
+ BlackfinTargetInfo(const std::string& triple) : TargetInfo(triple) {
+ TLSSupported = false;
+ DoubleAlign = 32;
+ LongLongAlign = 32;
+ LongDoubleAlign = 32;
+ DescriptionString = "e-p:32:32-i64:32-f64:32";
+ }
+
+ virtual void getTargetDefines(const LangOptions &Opts,
+ std::vector<char> &Defines) const {
+ DefineStd(Defines, "bfin", Opts);
+ DefineStd(Defines, "BFIN", Opts);
+ Define(Defines, "__ADSPBLACKFIN__");
+ // FIXME: This one is really dependent on -mcpu
+ Define(Defines, "__ADSPLPBLACKFIN__");
+ // FIXME: Add cpu-dependent defines and __SILICON_REVISION__
+ }
+
+ virtual void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const {
+ // FIXME: Implement.
+ Records = 0;
+ NumRecords = 0;
+ }
+
+ 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 {
+ if (strchr("adzDWeABbvfcCtukxywZY", Name[0])) {
+ Info.setAllowsRegister();
+ return true;
+ }
+ return false;
+ }
+
+ virtual const char *getClobbers() const {
+ return "";
+ }
+
+ virtual const char *getVAListDeclaration() const {
+ return "typedef char* __builtin_va_list;";
+ }
+ };
+
+ const char * const BlackfinTargetInfo::GCCRegNames[] = {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "p0", "p1", "p2", "p3", "p4", "p5", "sp", "fp",
+ "i0", "i1", "i2", "i3", "b0", "b1", "b2", "b3",
+ "l0", "l1", "l2", "l3", "m0", "m1", "m2", "m3",
+ "a0", "a1", "cc",
+ "rets", "reti", "retx", "retn", "rete", "astat", "seqstat", "usp",
+ "argp", "lt0", "lt1", "lc0", "lc1", "lb0", "lb1"
+ };
+
+ void BlackfinTargetInfo::getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const {
+ Names = GCCRegNames;
+ NumNames = llvm::array_lengthof(GCCRegNames);
+ }
+}
+
+namespace {
+
+ // LLVM and Clang cannot be used directly to output native binaries for
+ // target, but is used to compile C code to llvm bitcode with correct
+ // type and alignment information.
+ //
+ // TCE uses the llvm bitcode as input and uses it for generating customized
+ // target processor and program binary. TCE co-design environment is
+ // publicly available in http://tce.cs.tut.fi
+
+ class TCETargetInfo : public TargetInfo{
+ public:
+ TCETargetInfo(const std::string& triple) : TargetInfo(triple) {
+ TLSSupported = false;
+ IntWidth = 32;
+ LongWidth = LongLongWidth = 32;
+ IntMaxTWidth = 32;
+ PointerWidth = 32;
+ IntAlign = 32;
+ LongAlign = LongLongAlign = 32;
+ PointerAlign = 32;
+ SizeType = UnsignedInt;
+ IntMaxType = SignedLong;
+ UIntMaxType = UnsignedLong;
+ IntPtrType = SignedInt;
+ 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:32:32:32-a0:32:32"
+ "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64"
+ "-f32:32:32-f64:32:64";
+ }
+
+ virtual void getTargetDefines(const LangOptions &Opts,
+ std::vector<char> &Defines) const {
+ DefineStd(Defines, "tce", Opts);
+ Define(Defines, "__TCE__");
+ Define(Defines, "__TCE_V1__");
+ }
+ virtual void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const {}
+ virtual const char *getClobbers() const {
+ return "";
+ }
+ virtual const char *getVAListDeclaration() const {
+ return "typedef void* __builtin_va_list;";
+ }
+ 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 {}
+ };
+}
+
//===----------------------------------------------------------------------===//
// 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 isOpenBSD = T.find("-openbsd") != 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)
+ llvm::Triple Triple(T);
+ llvm::Triple::OSType os = Triple.getOS();
+
+ switch (Triple.getArch()) {
+ default:
+ return NULL;
+
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ switch (os) {
+ case llvm::Triple::Darwin:
+ return new DarwinARMTargetInfo(T);
+ case llvm::Triple::FreeBSD:
+ return new FreeBSDTargetInfo<ARMTargetInfo>(T);
+ default:
+ return new ARMTargetInfo(T);
+ }
+
+ case llvm::Triple::bfin:
+ return new BlackfinTargetInfo(T);
+
+ case llvm::Triple::msp430:
+ return new MSP430TargetInfo(T);
+
+ case llvm::Triple::pic16:
+ return new PIC16TargetInfo(T);
+
+ case llvm::Triple::ppc:
+ if (os == llvm::Triple::Darwin)
return new DarwinTargetInfo<PPCTargetInfo>(T);
return new PPC32TargetInfo(T);
- }
- if (T.find("ppc64-") == 0 || T.find("powerpc64-") == 0) {
- if (isDarwin)
+ case llvm::Triple::ppc64:
+ if (os == llvm::Triple::Darwin)
return new DarwinTargetInfo<PPC64TargetInfo>(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 FreeBSDTargetInfo<ARMTargetInfo>(T);
- return new ARMTargetInfo(T);
- }
- if (T.find("sparc-") == 0) {
- if (isSolaris)
+ case llvm::Triple::sparc:
+ if (os == llvm::Triple::Solaris)
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 LinuxTargetInfo<X86_64TargetInfo>(T);
- if (isOpenBSD)
- return new OpenBSDTargetInfo<X86_64TargetInfo>(T);
- if (isFreeBSD)
- return new FreeBSDTargetInfo<X86_64TargetInfo>(T);
- if (isSolaris)
- return new SolarisTargetInfo<X86_64TargetInfo>(T);
- return new X86_64TargetInfo(T);
- }
- if (T.find("pic16-") == 0)
- return new PIC16TargetInfo(T);
+ case llvm::Triple::systemz:
+ return new SystemZTargetInfo(T);
- if (T.find("msp430-") == 0)
- return new MSP430TargetInfo(T);
+ case llvm::Triple::tce:
+ return new TCETargetInfo(T);
- if (IsX86(T)) {
- if (isDarwin)
+ case llvm::Triple::x86:
+ switch (os) {
+ case llvm::Triple::Darwin:
return new DarwinI386TargetInfo(T);
- if (isLinux)
+ case llvm::Triple::Linux:
return new LinuxTargetInfo<X86_32TargetInfo>(T);
- if (isDragonFly)
+ case llvm::Triple::DragonFly:
return new DragonFlyBSDTargetInfo<X86_32TargetInfo>(T);
- if (isOpenBSD)
- return new OpenBSDTargetInfo<X86_32TargetInfo>(T);
- if (isFreeBSD)
+ case llvm::Triple::NetBSD:
+ return new NetBSDTargetInfo<X86_32TargetInfo>(T);
+ case llvm::Triple::OpenBSD:
+ return new OpenBSDI386TargetInfo(T);
+ case llvm::Triple::FreeBSD:
return new FreeBSDTargetInfo<X86_32TargetInfo>(T);
- if (isSolaris)
+ case llvm::Triple::Solaris:
return new SolarisTargetInfo<X86_32TargetInfo>(T);
- if (isWindows)
- return new WindowsX86_32TargetInfo(T);
- return new X86_32TargetInfo(T);
- }
+ case llvm::Triple::Cygwin:
+ return new CygwinX86_32TargetInfo(T);
+ case llvm::Triple::MinGW32:
+ return new MinGWX86_32TargetInfo(T);
+ case llvm::Triple::Win32:
+ return new VisualStudioWindowsX86_32TargetInfo(T);
+ default:
+ return new X86_32TargetInfo(T);
+ }
- return NULL;
+ case llvm::Triple::x86_64:
+ switch (os) {
+ case llvm::Triple::Darwin:
+ return new DarwinX86_64TargetInfo(T);
+ case llvm::Triple::Linux:
+ return new LinuxTargetInfo<X86_64TargetInfo>(T);
+ case llvm::Triple::NetBSD:
+ return new NetBSDTargetInfo<X86_64TargetInfo>(T);
+ case llvm::Triple::OpenBSD:
+ return new OpenBSDX86_64TargetInfo(T);
+ case llvm::Triple::FreeBSD:
+ return new FreeBSDTargetInfo<X86_64TargetInfo>(T);
+ case llvm::Triple::Solaris:
+ return new SolarisTargetInfo<X86_64TargetInfo>(T);
+ case llvm::Triple::MinGW64:
+ return new MinGWX86_64TargetInfo(T);
+ case llvm::Triple::Win32: // This is what Triple.h supports now.
+ return new VisualStudioWindowsX86_64TargetInfo(T);
+ default:
+ return new X86_64TargetInfo(T);
+ }
+ }
}
diff --git a/lib/Basic/Version.cpp b/lib/Basic/Version.cpp
new file mode 100644
index 0000000..30383f6
--- /dev/null
+++ b/lib/Basic/Version.cpp
@@ -0,0 +1,49 @@
+//===- Version.cpp - 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 file defines several version-related utility functions for Clang.
+//
+//===----------------------------------------------------------------------===//
+#include <cstring>
+#include <cstdlib>
+using namespace std;
+
+namespace clang {
+
+const char *getClangSubversionPath() {
+ static const char *Path = 0;
+ if (Path)
+ return Path;
+
+ static char URL[] = "$URL: http://llvm.org/svn/llvm-project/cfe/trunk/lib/Basic/Version.cpp $";
+ char *End = strstr(URL, "/lib/Basic");
+ if (End)
+ *End = 0;
+
+ char *Begin = strstr(URL, "cfe/");
+ if (Begin) {
+ Path = Begin + 4;
+ return Path;
+ }
+
+ Path = URL;
+ return Path;
+}
+
+
+unsigned getClangSubversionRevision() {
+#ifndef SVN_REVISION
+ // Subversion was not available at build time?
+ return 0;
+#else
+ return strtol(SVN_REVISION, 0, 10);
+#endif
+}
+
+} // end namespace clang
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index e3da531..2bfaa44 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -9,3 +9,4 @@ add_subdirectory(Analysis)
add_subdirectory(Rewrite)
add_subdirectory(Driver)
add_subdirectory(Frontend)
+add_subdirectory(Index)
diff --git a/lib/CodeGen/ABIInfo.h b/lib/CodeGen/ABIInfo.h
index 58e5a77..1ab2f55 100644
--- a/lib/CodeGen/ABIInfo.h
+++ b/lib/CodeGen/ABIInfo.h
@@ -17,6 +17,7 @@
namespace llvm {
class Type;
class Value;
+ class LLVMContext;
}
namespace clang {
@@ -71,11 +72,12 @@ namespace clang {
Kind TheKind;
const llvm::Type *TypeData;
unsigned UIntData;
+ bool BoolData;
ABIArgInfo(Kind K, const llvm::Type *TD=0,
- unsigned UI=0) : TheKind(K),
- TypeData(TD),
- UIntData(UI) {}
+ unsigned UI=0, bool B = false)
+ : TheKind(K), TypeData(TD), UIntData(UI), BoolData(B) {}
+
public:
ABIArgInfo() : TheKind(Direct), TypeData(0), UIntData(0) {}
@@ -91,8 +93,8 @@ namespace clang {
static ABIArgInfo getCoerce(const llvm::Type *T) {
return ABIArgInfo(Coerce, T);
}
- static ABIArgInfo getIndirect(unsigned Alignment) {
- return ABIArgInfo(Indirect, 0, Alignment);
+ static ABIArgInfo getIndirect(unsigned Alignment, bool ByVal = true) {
+ return ABIArgInfo(Indirect, 0, Alignment, ByVal);
}
static ABIArgInfo getExpand() {
return ABIArgInfo(Expand);
@@ -112,12 +114,17 @@ namespace clang {
return TypeData;
}
- // ByVal accessors
+ // Indirect accessors
unsigned getIndirectAlign() const {
assert(TheKind == Indirect && "Invalid kind!");
return UIntData;
}
+ bool getIndirectByVal() const {
+ assert(TheKind == Indirect && "Invalid kind!");
+ return BoolData;
+ }
+
void dump() const;
};
@@ -128,7 +135,8 @@ namespace clang {
virtual ~ABIInfo();
virtual void computeInfo(CodeGen::CGFunctionInfo &FI,
- ASTContext &Ctx) const = 0;
+ ASTContext &Ctx,
+ llvm::LLVMContext &VMContext) const = 0;
/// EmitVAArg - Emit the target dependent code to load a value of
/// \arg Ty from the va_list pointed to by \arg VAListAddr.
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index d5f803b..736425e 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -11,12 +11,15 @@
//
//===----------------------------------------------------------------------===//
+#include "CGDebugInfo.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "clang/AST/DeclObjC.h"
#include "llvm/Module.h"
#include "llvm/Target/TargetData.h"
#include <algorithm>
+#include <cstdio>
+
using namespace clang;
using namespace CodeGen;
@@ -48,24 +51,24 @@ BuildDescriptorBlockDecl(bool BlockHasCopyDispose, uint64_t Size,
Elts.push_back(BuildDestroyHelper(Ty, NoteForHelper));
}
- C = llvm::ConstantStruct::get(Elts);
+ C = llvm::ConstantStruct::get(VMContext, Elts, false);
- C = new llvm::GlobalVariable(C->getType(), true,
+ C = new llvm::GlobalVariable(CGM.getModule(), C->getType(), true,
llvm::GlobalValue::InternalLinkage,
- C, "__block_descriptor_tmp", &CGM.getModule());
+ C, "__block_descriptor_tmp");
return C;
}
llvm::Constant *BlockModule::getNSConcreteGlobalBlock() {
if (NSConcreteGlobalBlock == 0)
- NSConcreteGlobalBlock = CGM.CreateRuntimeVariable(PtrToInt8Ty,
+ NSConcreteGlobalBlock = CGM.CreateRuntimeVariable(PtrToInt8Ty,
"_NSConcreteGlobalBlock");
return NSConcreteGlobalBlock;
}
llvm::Constant *BlockModule::getNSConcreteStackBlock() {
if (NSConcreteStackBlock == 0)
- NSConcreteStackBlock = CGM.CreateRuntimeVariable(PtrToInt8Ty,
+ NSConcreteStackBlock = CGM.CreateRuntimeVariable(PtrToInt8Ty,
"_NSConcreteStackBlock");
return NSConcreteStackBlock;
}
@@ -125,7 +128,8 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
llvm::SmallVector<const Expr *, 8> subBlockDeclRefDecls;
bool subBlockHasCopyDispose = false;
llvm::Function *Fn
- = CodeGenFunction(CGM).GenerateBlockFunction(BE, Info, CurFuncDecl, LocalDeclMap,
+ = CodeGenFunction(CGM).GenerateBlockFunction(BE, Info, CurFuncDecl,
+ LocalDeclMap,
subBlockSize,
subBlockAlign,
subBlockDeclRefDecls,
@@ -161,13 +165,13 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
Elts[0] = CGM.getNSConcreteGlobalBlock();
Elts[1] = llvm::ConstantInt::get(IntTy, flags|BLOCK_IS_GLOBAL);
- C = llvm::ConstantStruct::get(Elts);
+ C = llvm::ConstantStruct::get(VMContext, Elts, false);
char Name[32];
sprintf(Name, "__block_holder_tmp_%d", CGM.getGlobalUniqueCount());
- C = new llvm::GlobalVariable(C->getType(), true,
+ C = new llvm::GlobalVariable(CGM.getModule(), C->getType(), true,
llvm::GlobalValue::InternalLinkage,
- C, Name, &CGM.getModule());
+ C, Name);
QualType BPT = BE->getType();
C = llvm::ConstantExpr::getBitCast(C, ConvertType(BPT));
return C;
@@ -183,13 +187,12 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
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);
+ Types[i+5] = llvm::PointerType::get(BuildByRefType(BDRE->getDecl()), 0);
} else
Types[i+5] = ConvertType(Ty);
}
- llvm::StructType *Ty = llvm::StructType::get(Types, true);
+ llvm::StructType *Ty = llvm::StructType::get(VMContext, Types, true);
llvm::AllocaInst *A = CreateTempAlloca(Ty);
A->setAlignment(subBlockAlign);
@@ -217,20 +220,21 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
llvm::Value* Addr = Builder.CreateStructGEP(V, i+5, "tmp");
NoteForHelper[helpersize].index = i+5;
- NoteForHelper[helpersize].RequiresCopying = BlockRequiresCopying(VD->getType());
+ NoteForHelper[helpersize].RequiresCopying
+ = BlockRequiresCopying(VD->getType());
NoteForHelper[helpersize].flag
- = VD->getType()->isBlockPointerType() ? BLOCK_FIELD_IS_BLOCK : BLOCK_FIELD_IS_OBJECT;
+ = (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;
@@ -265,7 +269,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
llvm::Value *BlockLiteral = LoadBlockStruct();
Loc = Builder.CreateGEP(BlockLiteral,
- llvm::ConstantInt::get(llvm::Type::Int64Ty,
+ llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
offset),
"block.literal");
Ty = llvm::PointerType::get(Ty, 0);
@@ -310,7 +314,8 @@ const llvm::Type *BlockModule::getBlockDescriptorType() {
// unsigned long reserved;
// unsigned long block_size;
// };
- BlockDescriptorType = llvm::StructType::get(UnsignedLongTy,
+ BlockDescriptorType = llvm::StructType::get(UnsignedLongTy->getContext(),
+ UnsignedLongTy,
UnsignedLongTy,
NULL);
@@ -337,7 +342,8 @@ const llvm::Type *BlockModule::getGenericBlockLiteralType() {
// void (*__invoke)(void *);
// struct __block_descriptor *__descriptor;
// };
- GenericBlockLiteralType = llvm::StructType::get(PtrToInt8Ty,
+ GenericBlockLiteralType = llvm::StructType::get(IntTy->getContext(),
+ PtrToInt8Ty,
IntTy,
IntTy,
PtrToInt8Ty,
@@ -369,7 +375,8 @@ const llvm::Type *BlockModule::getGenericExtendedBlockLiteralType() {
// void *__copy_func_helper_decl;
// void *__destroy_func_decl;
// };
- GenericExtendedBlockLiteralType = llvm::StructType::get(PtrToInt8Ty,
+ GenericExtendedBlockLiteralType = llvm::StructType::get(IntTy->getContext(),
+ PtrToInt8Ty,
IntTy,
IntTy,
PtrToInt8Ty,
@@ -384,9 +391,13 @@ const llvm::Type *BlockModule::getGenericExtendedBlockLiteralType() {
return GenericExtendedBlockLiteralType;
}
+bool BlockFunction::BlockRequiresCopying(QualType Ty) {
+ return CGM.BlockRequiresCopying(Ty);
+}
+
RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E) {
const BlockPointerType *BPT =
- E->getCallee()->getType()->getAsBlockPointerType();
+ E->getCallee()->getType()->getAs<BlockPointerType>();
llvm::Value *Callee = EmitScalarExpr(E->getCallee());
@@ -403,7 +414,7 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E) {
BlockLiteral =
Builder.CreateBitCast(BlockLiteral,
- llvm::PointerType::getUnqual(llvm::Type::Int8Ty),
+ llvm::Type::getInt8PtrTy(VMContext),
"tmp");
// Add the block literal.
@@ -414,33 +425,33 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E) {
QualType FnType = BPT->getPointeeType();
// And the rest of the arguments.
- EmitCallArgs(Args, FnType->getAsFunctionProtoType(),
+ EmitCallArgs(Args, FnType->getAs<FunctionProtoType>(),
E->arg_begin(), E->arg_end());
// Load the function.
llvm::Value *Func = Builder.CreateLoad(FuncPtr, false, "tmp");
- QualType ResultType = FnType->getAsFunctionType()->getResultType();
+ QualType ResultType = FnType->getAs<FunctionType>()->getResultType();
- const CGFunctionInfo &FnInfo =
+ const CGFunctionInfo &FnInfo =
CGM.getTypes().getFunctionInfo(ResultType, Args);
-
+
// Cast the function pointer to the right type.
- const llvm::Type *BlockFTy =
+ 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 ValueDecl *VD = E->getDecl();
+
+ uint64_t &offset = BlockDecls[VD];
- 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) {
@@ -453,25 +464,27 @@ llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const BlockDeclRefExpr *E) {
llvm::Value *BlockLiteral = LoadBlockStruct();
llvm::Value *V = Builder.CreateGEP(BlockLiteral,
- llvm::ConstantInt::get(llvm::Type::Int64Ty,
- offset),
+ llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
+ 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);
+ = llvm::PointerType::get(BuildByRefType(VD), 0);
// The block literal will need a copy/destroy helper.
BlockHasCopyDispose = true;
- Ty = PtrStructTy;
+
+ const llvm::Type *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");
+ V = Builder.CreateStructGEP(V, getByRefValueLLVMField(VD),
+ VD->getNameAsString());
} else {
+ const llvm::Type *Ty = CGM.getTypes().ConvertType(VD->getType());
+
Ty = llvm::PointerType::get(Ty, 0);
V = Builder.CreateBitCast(V, Ty);
}
@@ -507,16 +520,16 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) {
// block literal struct.
uint64_t BlockLiteralSize =
TheTargetData.getTypeStoreSizeInBits(getGenericBlockLiteralType()) / 8;
- DescriptorFields[1] = llvm::ConstantInt::get(UnsignedLongTy,BlockLiteralSize);
+ DescriptorFields[1] =
+ llvm::ConstantInt::get(UnsignedLongTy,BlockLiteralSize);
llvm::Constant *DescriptorStruct =
- llvm::ConstantStruct::get(&DescriptorFields[0], 2);
+ llvm::ConstantStruct::get(VMContext, &DescriptorFields[0], 2, false);
llvm::GlobalVariable *Descriptor =
- new llvm::GlobalVariable(DescriptorStruct->getType(), true,
+ new llvm::GlobalVariable(getModule(), DescriptorStruct->getType(), true,
llvm::GlobalVariable::InternalLinkage,
- DescriptorStruct, "__block_descriptor_global",
- &getModule());
+ DescriptorStruct, "__block_descriptor_global");
// Generate the constants for the block literal.
llvm::Constant *LiteralFields[5];
@@ -552,13 +565,12 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) {
LiteralFields[4] = Descriptor;
llvm::Constant *BlockLiteralStruct =
- llvm::ConstantStruct::get(&LiteralFields[0], 5);
+ llvm::ConstantStruct::get(VMContext, &LiteralFields[0], 5, false);
llvm::GlobalVariable *BlockLiteral =
- new llvm::GlobalVariable(BlockLiteralStruct->getType(), true,
+ new llvm::GlobalVariable(getModule(), BlockLiteralStruct->getType(), true,
llvm::GlobalVariable::InternalLinkage,
- BlockLiteralStruct, "__block_literal_global",
- &getModule());
+ BlockLiteralStruct, "__block_literal_global");
return BlockLiteral;
}
@@ -580,7 +592,7 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
// 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.
@@ -588,7 +600,7 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
i != ldm.end();
++i) {
const VarDecl *VD = dyn_cast<VarDecl>(i->first);
-
+
if (VD->getStorageClass() == VarDecl::Static || VD->hasExternalStorage())
LocalDeclMap[VD] = i->second;
}
@@ -606,12 +618,11 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
const FunctionType *BlockFunctionType = BExpr->getFunctionType();
QualType ResultType;
bool IsVariadic;
- if (const FunctionProtoType *FTy =
+ if (const FunctionProtoType *FTy =
dyn_cast<FunctionProtoType>(BlockFunctionType)) {
ResultType = FTy->getResultType();
IsVariadic = FTy->isVariadic();
- }
- else {
+ } else {
// K&R style block.
ResultType = BlockFunctionType->getResultType();
IsVariadic = false;
@@ -650,9 +661,44 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
StartFunction(BD, ResultType, Fn, Args,
BExpr->getBody()->getLocEnd());
+
CurFuncDecl = OuterFuncDecl;
CurCodeDecl = BD;
+
+ // Save a spot to insert the debug information for all the BlockDeclRefDecls.
+ llvm::BasicBlock *entry = Builder.GetInsertBlock();
+ llvm::BasicBlock::iterator entry_ptr = Builder.GetInsertPoint();
+ --entry_ptr;
+
EmitStmt(BExpr->getBody());
+
+ // Remember where we were...
+ llvm::BasicBlock *resume = Builder.GetInsertBlock();
+
+ // Go back to the entry.
+ ++entry_ptr;
+ Builder.SetInsertPoint(entry, entry_ptr);
+
+ if (CGDebugInfo *DI = getDebugInfo()) {
+ // Emit debug information for all the BlockDeclRefDecls.
+ for (unsigned i=0; i < BlockDeclRefDecls.size(); ++i) {
+ const Expr *E = BlockDeclRefDecls[i];
+ const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E);
+ if (BDRE) {
+ const ValueDecl *D = BDRE->getDecl();
+ DI->setLocation(D->getLocation());
+ DI->EmitDeclareOfBlockDeclRefVariable(BDRE,
+ LocalDeclMap[getBlockStructDecl()],
+ Builder, this);
+ }
+ }
+ }
+ // And resume where we left off.
+ if (resume == 0)
+ Builder.ClearInsertionPoint();
+ else
+ Builder.SetInsertPoint(resume);
+
FinishFunction(cast<CompoundStmt>(BExpr->getBody())->getRBracLoc());
// The runtime needs a minimum alignment of a void *.
@@ -687,13 +733,12 @@ uint64_t BlockFunction::getBlockOffset(const BlockDeclRefExpr *BDRE) {
uint64_t Pad = BlockOffset - OldOffset;
if (Pad) {
- llvm::ArrayType::get(llvm::Type::Int8Ty, Pad);
+ llvm::ArrayType::get(llvm::Type::getInt8Ty(VMContext), 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());
+ 0, QualType(PadTy), 0, VarDecl::None);
Expr *E;
E = new (getContext()) DeclRefExpr(PadDecl, PadDecl->getType(),
SourceLocation(), false, false);
@@ -720,7 +765,7 @@ GenerateCopyHelperFunction(bool BlockHasCopyDispose, const llvm::StructType *T,
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);
@@ -740,7 +785,7 @@ GenerateCopyHelperFunction(bool BlockHasCopyDispose, const llvm::StructType *T,
FunctionDecl *FD = FunctionDecl::Create(getContext(),
getContext().getTranslationUnitDecl(),
- SourceLocation(), II, R,
+ SourceLocation(), II, R, 0,
FunctionDecl::Static, false,
true);
CGF.StartFunction(FD, R, Fn, Args, SourceLocation());
@@ -776,7 +821,8 @@ GenerateCopyHelperFunction(bool BlockHasCopyDispose, const llvm::StructType *T,
llvm::Value *Dstv = Builder.CreateStructGEP(DstObj, index);
Dstv = Builder.CreateBitCast(Dstv, PtrToInt8Ty);
- llvm::Value *N = llvm::ConstantInt::get(llvm::Type::Int32Ty, flag);
+ llvm::Value *N = llvm::ConstantInt::get(
+ llvm::Type::getInt32Ty(T->getContext()), flag);
llvm::Value *F = getBlockObjectAssign();
Builder.CreateCall3(F, Dstv, Srcv, N);
}
@@ -801,7 +847,7 @@ GenerateDestroyHelperFunction(bool BlockHasCopyDispose,
getContext().getPointerType(getContext().VoidTy));
Args.push_back(std::make_pair(Src, Src->getType()));
-
+
const CGFunctionInfo &FI =
CGM.getTypes().getFunctionInfo(R, Args);
@@ -821,7 +867,7 @@ GenerateDestroyHelperFunction(bool BlockHasCopyDispose,
FunctionDecl *FD = FunctionDecl::Create(getContext(),
getContext().getTranslationUnitDecl(),
- SourceLocation(), II, R,
+ SourceLocation(), II, R, 0,
FunctionDecl::Static, false,
true);
CGF.StartFunction(FD, R, Fn, Args, SourceLocation());
@@ -885,7 +931,7 @@ GeneratebyrefCopyHelperFunction(const llvm::Type *T, int flag) {
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);
@@ -905,7 +951,7 @@ GeneratebyrefCopyHelperFunction(const llvm::Type *T, int flag) {
FunctionDecl *FD = FunctionDecl::Create(getContext(),
getContext().getTranslationUnitDecl(),
- SourceLocation(), II, R,
+ SourceLocation(), II, R, 0,
FunctionDecl::Static, false,
true);
CGF.StartFunction(FD, R, Fn, Args, SourceLocation());
@@ -924,10 +970,11 @@ GeneratebyrefCopyHelperFunction(const llvm::Type *T, int flag) {
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 *N = llvm::ConstantInt::get(
+ llvm::Type::getInt32Ty(T->getContext()), flag);
llvm::Value *F = getBlockObjectAssign();
Builder.CreateCall3(F, DstObj, SrcObj, N);
@@ -948,7 +995,7 @@ BlockFunction::GeneratebyrefDestroyHelperFunction(const llvm::Type *T,
getContext().getPointerType(getContext().VoidTy));
Args.push_back(std::make_pair(Src, Src->getType()));
-
+
const CGFunctionInfo &FI =
CGM.getTypes().getFunctionInfo(R, Args);
@@ -968,7 +1015,7 @@ BlockFunction::GeneratebyrefDestroyHelperFunction(const llvm::Type *T,
FunctionDecl *FD = FunctionDecl::Create(getContext(),
getContext().getTranslationUnitDecl(),
- SourceLocation(), II, R,
+ SourceLocation(), II, R, 0,
FunctionDecl::Static, false,
true);
CGF.StartFunction(FD, R, Fn, Args, SourceLocation());
@@ -1024,9 +1071,9 @@ 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;
+ const llvm::Type *ResultType = llvm::Type::getVoidTy(VMContext);
ArgTys.push_back(PtrToInt8Ty);
- ArgTys.push_back(llvm::Type::Int32Ty);
+ ArgTys.push_back(llvm::Type::getInt32Ty(VMContext));
FTy = llvm::FunctionType::get(ResultType, ArgTys, false);
CGM.BlockObjectDispose
= CGM.CreateRuntimeFunction(FTy, "_Block_object_dispose");
@@ -1038,10 +1085,10 @@ 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;
+ const llvm::Type *ResultType = llvm::Type::getVoidTy(VMContext);
ArgTys.push_back(PtrToInt8Ty);
ArgTys.push_back(PtrToInt8Ty);
- ArgTys.push_back(llvm::Type::Int32Ty);
+ ArgTys.push_back(llvm::Type::getInt32Ty(VMContext));
FTy = llvm::FunctionType::get(ResultType, ArgTys, false);
CGM.BlockObjectAssign
= CGM.CreateRuntimeFunction(FTy, "_Block_object_assign");
@@ -1053,7 +1100,7 @@ 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);
+ N = llvm::ConstantInt::get(llvm::Type::getInt32Ty(V->getContext()), flag);
Builder.CreateCall2(F, V, N);
}
@@ -1061,8 +1108,9 @@ 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);
+ : CGM(cgm), CGF(cgf), VMContext(cgm.getLLVMContext()), Builder(B) {
+ PtrToInt8Ty = llvm::PointerType::getUnqual(
+ llvm::Type::getInt8Ty(VMContext));
BlockHasCopyDispose = false;
}
diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h
index 5d46ac7..3a860c0 100644
--- a/lib/CodeGen/CGBlocks.h
+++ b/lib/CodeGen/CGBlocks.h
@@ -16,6 +16,7 @@
#include "CodeGenTypes.h"
#include "clang/AST/Type.h"
+#include "llvm/Module.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "clang/Basic/TargetInfo.h"
@@ -38,6 +39,7 @@ namespace llvm {
class TargetData;
class FunctionType;
class Value;
+ class LLVMContext;
}
namespace clang {
@@ -63,7 +65,8 @@ class BlockModule : public BlockBase {
const llvm::TargetData &TheTargetData;
CodeGenTypes &Types;
CodeGenModule &CGM;
-
+ llvm::LLVMContext &VMContext;
+
ASTContext &getContext() const { return Context; }
llvm::Module &getModule() const { return TheModule; }
CodeGenTypes &getTypes() { return Types; }
@@ -86,7 +89,7 @@ public:
/// 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;
@@ -104,12 +107,22 @@ public:
BlockModule(ASTContext &C, llvm::Module &M, const llvm::TargetData &TD,
CodeGenTypes &T, CodeGenModule &CodeGen)
: Context(C), TheModule(M), TheTargetData(TD), Types(T),
- CGM(CodeGen),
+ CGM(CodeGen), VMContext(M.getContext()),
NSConcreteGlobalBlock(0), NSConcreteStackBlock(0), BlockDescriptorType(0),
GenericBlockLiteralType(0), GenericExtendedBlockLiteralType(0),
BlockObjectAssign(0), BlockObjectDispose(0) {
Block.GlobalUniqueCount = 0;
- PtrToInt8Ty = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+ PtrToInt8Ty = llvm::Type::getInt8PtrTy(M.getContext());
+ }
+
+ bool BlockRequiresCopying(QualType Ty) {
+ if (Ty->isBlockPointerType())
+ return true;
+ if (getContext().isObjCNSObjectType(Ty))
+ return true;
+ if (Ty->isObjCObjectPointerType())
+ return true;
+ return false;
}
};
@@ -118,6 +131,9 @@ class BlockFunction : public BlockBase {
CodeGenFunction &CGF;
ASTContext &getContext() const;
+protected:
+ llvm::LLVMContext &VMContext;
+
public:
const llvm::Type *PtrToInt8Ty;
struct HelperInfo {
@@ -150,11 +166,11 @@ public:
/// 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
+
+ // 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.
@@ -212,15 +228,7 @@ public:
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;
- }
+ bool BlockRequiresCopying(QualType Ty);
};
} // end namespace CodeGen
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index a919dfa..987cd24 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -25,21 +25,21 @@ using namespace llvm;
/// Utility to insert an atomic instruction based on Instrinsic::ID
/// and the expression node.
-static RValue EmitBinaryAtomic(CodeGenFunction& CGF,
+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)),
+ 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,
+static RValue EmitBinaryAtomicPost(CodeGenFunction& CGF,
Intrinsic::ID Id, const CallExpr *E,
Instruction::BinaryOps Op) {
const llvm::Type *ResType[2];
@@ -49,25 +49,26 @@ static RValue EmitBinaryAtomicPost(CodeGenFunction& CGF,
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,
+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()));
+ return RValue::get(llvm::ConstantInt::get(VMContext,
+ Result.Val.getInt()));
else if (Result.Val.isFloat())
- return RValue::get(llvm::ConstantFP::get(Result.Val.getFloat()));
+ return RValue::get(ConstantFP::get(VMContext, Result.Val.getFloat()));
}
-
+
switch (BuiltinID) {
default: break; // Handle intrinsics and libm functions below.
case Builtin::BI__builtin___CFStringMakeConstantString:
@@ -76,13 +77,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__builtin_va_start:
case Builtin::BI__builtin_va_end: {
Value *ArgValue = EmitVAListRef(E->getArg(0));
- const llvm::Type *DestType =
- llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+ const llvm::Type *DestType = llvm::Type::getInt8PtrTy(VMContext);
if (ArgValue->getType() != DestType)
- ArgValue = Builder.CreateBitCast(ArgValue, DestType,
- ArgValue->getNameStart());
+ ArgValue = Builder.CreateBitCast(ArgValue, DestType,
+ ArgValue->getName().data());
- Intrinsic::ID inst = (BuiltinID == Builtin::BI__builtin_va_end) ?
+ Intrinsic::ID inst = (BuiltinID == Builtin::BI__builtin_va_end) ?
Intrinsic::vaend : Intrinsic::vastart;
return RValue::get(Builder.CreateCall(CGM.getIntrinsic(inst), ArgValue));
}
@@ -90,35 +90,35 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Value *DstPtr = EmitVAListRef(E->getArg(0));
Value *SrcPtr = EmitVAListRef(E->getArg(1));
- const llvm::Type *Type =
- llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+ const llvm::Type *Type = llvm::Type::getInt8PtrTy(VMContext);
DstPtr = Builder.CreateBitCast(DstPtr, Type);
SrcPtr = Builder.CreateBitCast(SrcPtr, Type);
- return RValue::get(Builder.CreateCall2(CGM.getIntrinsic(Intrinsic::vacopy),
+ return RValue::get(Builder.CreateCall2(CGM.getIntrinsic(Intrinsic::vacopy),
DstPtr, SrcPtr));
}
case Builtin::BI__builtin_abs: {
- Value *ArgValue = EmitScalarExpr(E->getArg(0));
-
+ Value *ArgValue = EmitScalarExpr(E->getArg(0));
+
Value *NegOp = Builder.CreateNeg(ArgValue, "neg");
- Value *CmpResult =
- Builder.CreateICmpSGE(ArgValue, Constant::getNullValue(ArgValue->getType()),
+ Value *CmpResult =
+ Builder.CreateICmpSGE(ArgValue,
+ llvm::Constant::getNullValue(ArgValue->getType()),
"abscond");
- Value *Result =
+ 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());
+ const llvm::Type *ResultType = ConvertType(E->getType());
Value *Result = Builder.CreateCall(F, ArgValue, "tmp");
if (Result->getType() != ResultType)
Result = Builder.CreateIntCast(Result, ResultType, "cast");
@@ -128,11 +128,11 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
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());
+ const llvm::Type *ResultType = ConvertType(E->getType());
Value *Result = Builder.CreateCall(F, ArgValue, "tmp");
if (Result->getType() != ResultType)
Result = Builder.CreateIntCast(Result, ResultType, "cast");
@@ -143,13 +143,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
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 *Tmp = Builder.CreateAdd(Builder.CreateCall(F, ArgValue, "tmp"),
+ llvm::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");
@@ -162,13 +162,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
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),
+ Value *Result = Builder.CreateAnd(Tmp, llvm::ConstantInt::get(ArgType, 1),
"tmp");
if (Result->getType() != ResultType)
Result = Builder.CreateIntCast(Result, ResultType, "cast");
@@ -178,10 +178,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
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)
@@ -197,7 +197,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
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.
@@ -205,15 +205,16 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
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));
+ return RValue::get(
+ llvm::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);
+ RW = (E->getNumArgs() > 1) ? EmitScalarExpr(E->getArg(1)) :
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 0);
+ Locality = (E->getNumArgs() > 2) ? EmitScalarExpr(E->getArg(2)) :
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 3);
Value *F = CGM.getIntrinsic(Intrinsic::prefetch, 0, 0);
return RValue::get(Builder.CreateCall3(F, Address, RW, Locality));
}
@@ -221,7 +222,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Value *F = CGM.getIntrinsic(Intrinsic::trap, 0, 0);
return RValue::get(Builder.CreateCall(F));
}
-
+ case Builtin::BI__builtin_unreachable: {
+ Value *V = Builder.CreateUnreachable();
+ Builder.ClearInsertionPoint();
+ return RValue::get(V);
+ }
+
case Builtin::BI__builtin_powi:
case Builtin::BI__builtin_powif:
case Builtin::BI__builtin_powil: {
@@ -240,9 +246,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
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 *LHS = EmitScalarExpr(E->getArg(0));
Value *RHS = EmitScalarExpr(E->getArg(1));
-
+
switch (BuiltinID) {
default: assert(0 && "Unknown ordered comparison");
case Builtin::BI__builtin_isgreater:
@@ -260,7 +266,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__builtin_islessgreater:
LHS = Builder.CreateFCmpONE(LHS, RHS, "cmp");
break;
- case Builtin::BI__builtin_isunordered:
+ case Builtin::BI__builtin_isunordered:
LHS = Builder.CreateFCmpUNO(LHS, RHS, "cmp");
break;
}
@@ -268,19 +274,24 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
return RValue::get(Builder.CreateZExt(LHS, ConvertType(E->getType()),
"tmp"));
}
+ case Builtin::BI__builtin_isnan: {
+ Value *V = EmitScalarExpr(E->getArg(0));
+ V = Builder.CreateFCmpUNO(V, V, "cmp");
+ return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType()), "tmp"));
+ }
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"));
+ Size = Builder.CreateIntCast(Size, llvm::Type::getInt32Ty(VMContext), false, "tmp");
+ return RValue::get(Builder.CreateAlloca(llvm::Type::getInt8Ty(VMContext), 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),
+ llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), 0),
EmitScalarExpr(E->getArg(1)),
- llvm::ConstantInt::get(llvm::Type::Int32Ty, 1));
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 1));
return RValue::get(Address);
}
case Builtin::BI__builtin_memcpy: {
@@ -288,7 +299,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Builder.CreateCall4(CGM.getMemCpyFn(), Address,
EmitScalarExpr(E->getArg(1)),
EmitScalarExpr(E->getArg(2)),
- llvm::ConstantInt::get(llvm::Type::Int32Ty, 1));
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 1));
return RValue::get(Address);
}
case Builtin::BI__builtin_memmove: {
@@ -296,16 +307,16 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Builder.CreateCall4(CGM.getMemMoveFn(), Address,
EmitScalarExpr(E->getArg(1)),
EmitScalarExpr(E->getArg(2)),
- llvm::ConstantInt::get(llvm::Type::Int32Ty, 1));
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 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),
+ llvm::Type::getInt8Ty(VMContext)),
EmitScalarExpr(E->getArg(2)),
- llvm::ConstantInt::get(llvm::Type::Int32Ty, 1));
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 1));
return RValue::get(Address);
}
case Builtin::BI__builtin_return_address: {
@@ -332,20 +343,18 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Value *FrameAddrF = CGM.getIntrinsic(Intrinsic::frameaddress, 0, 0);
Value *FrameAddr =
Builder.CreateCall(FrameAddrF,
- Constant::getNullValue(llvm::Type::Int32Ty));
+ Constant::getNullValue(llvm::Type::getInt32Ty(VMContext)));
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);
+ const llvm::Type *DestType = llvm::Type::getInt8PtrTy(VMContext);
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);
+ const llvm::Type *DestType = llvm::Type::getInt8PtrTy(VMContext);
Buf = Builder.CreateBitCast(Buf, DestType);
return RValue::get(Builder.CreateCall(F, Buf));
}
@@ -401,7 +410,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
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);
@@ -417,7 +426,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__sync_add_and_fetch_4:
case Builtin::BI__sync_add_and_fetch_8:
case Builtin::BI__sync_add_and_fetch_16:
- return EmitBinaryAtomicPost(*this, Intrinsic::atomic_load_add, E,
+ return EmitBinaryAtomicPost(*this, Intrinsic::atomic_load_add, E,
llvm::Instruction::Add);
case Builtin::BI__sync_sub_and_fetch_1:
case Builtin::BI__sync_sub_and_fetch_2:
@@ -454,7 +463,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
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:
@@ -465,7 +474,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
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,
+ return RValue::get(Builder.CreateCall3(AtomF,
EmitScalarExpr(E->getArg(0)),
EmitScalarExpr(E->getArg(1)),
EmitScalarExpr(E->getArg(2))));
@@ -482,7 +491,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
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,
+ Value *PrevVal = Builder.CreateCall3(AtomF,
EmitScalarExpr(E->getArg(0)),
OldVal,
EmitScalarExpr(E->getArg(2)));
@@ -511,12 +520,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
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);
+ C[0] = C[1] = C[2] = C[3] = llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), 1);
+ C[4] = llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), 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:
@@ -543,29 +552,31 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
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),
+ return EmitCall(CGM.getBuiltinLibFunction(FD, 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);
-
+ Intrinsic::ID IntrinsicID = Intrinsic::not_intrinsic;
+ if (const char *Prefix =
+ llvm::Triple::getArchTypePrefix(Target.getTriple().getArch()))
+ IntrinsicID = Intrinsic::getIntrinsicForGCCBuiltin(Prefix, 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);
@@ -574,50 +585,54 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
"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;
+
+ const llvm::Type *RetTy = llvm::Type::getVoidTy(VMContext);
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())));
-}
+ return RValue::get(llvm::UndefValue::get(ConvertType(E->getType())));
+}
Value *CodeGenFunction::EmitTargetBuiltinExpr(unsigned BuiltinID,
const CallExpr *E) {
- const char *TargetPrefix = Target.getTargetPrefix();
- if (strcmp(TargetPrefix, "x86") == 0)
+ switch (Target.getTriple().getArch()) {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
return EmitX86BuiltinExpr(BuiltinID, E);
- else if (strcmp(TargetPrefix, "ppc") == 0)
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
return EmitPPCBuiltinExpr(BuiltinID, E);
- return 0;
+ default:
+ return 0;
+ }
}
-Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
+Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
const CallExpr *E) {
-
+
llvm::SmallVector<Value*, 4> Ops;
for (unsigned i = 0, e = E->getNumArgs(); i != e; i++)
@@ -625,23 +640,23 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
switch (BuiltinID) {
default: return 0;
- case X86::BI__builtin_ia32_pslldi128:
+ case X86::BI__builtin_ia32_pslldi128:
case X86::BI__builtin_ia32_psllqi128:
- case X86::BI__builtin_ia32_psllwi128:
+ 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.CreateZExt(Ops[1], llvm::Type::getInt64Ty(VMContext), "zext");
+ const llvm::Type *Ty = llvm::VectorType::get(llvm::Type::getInt64Ty(VMContext), 2);
+ llvm::Value *Zero = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 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:
@@ -678,22 +693,22 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
break;
}
llvm::Function *F = CGM.getIntrinsic(ID);
- return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), name);
+ return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), name);
}
- case X86::BI__builtin_ia32_pslldi:
+ case X86::BI__builtin_ia32_pslldi:
case X86::BI__builtin_ia32_psllqi:
- case X86::BI__builtin_ia32_psllwi:
+ 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.CreateZExt(Ops[1], llvm::Type::getInt64Ty(VMContext), "zext");
+ const llvm::Type *Ty = llvm::VectorType::get(llvm::Type::getInt64Ty(VMContext), 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:
@@ -730,7 +745,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
break;
}
llvm::Function *F = CGM.getIntrinsic(ID);
- return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), name);
+ return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), name);
}
case X86::BI__builtin_ia32_cmpps: {
llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_sse_cmp_ps);
@@ -741,17 +756,17 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
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");
+ const llvm::Type *PtrTy = llvm::Type::getInt8PtrTy(VMContext);
+ Value *One = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 1);
+ Value *Tmp = Builder.CreateAlloca(llvm::Type::getInt32Ty(VMContext), 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");
+ const llvm::Type *PtrTy = llvm::Type::getInt8PtrTy(VMContext);
+ Value *One = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 1);
+ Value *Tmp = Builder.CreateAlloca(llvm::Type::getInt32Ty(VMContext), One, "tmp");
One = Builder.CreateCall(CGM.getIntrinsic(Intrinsic::x86_sse_stmxcsr),
Builder.CreateBitCast(Tmp, PtrTy));
return Builder.CreateLoad(Tmp, "stmxcsr");
@@ -766,16 +781,16 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
}
case X86::BI__builtin_ia32_storehps:
case X86::BI__builtin_ia32_storelps: {
- const llvm::Type *EltTy = llvm::Type::Int64Ty;
+ const llvm::Type *EltTy = llvm::Type::getInt64Ty(VMContext);
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);
+ llvm::Value *Idx = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), Index);
Ops[1] = Builder.CreateExtractElement(Ops[1], Idx, "extract");
// cast pointer to i64 & store
@@ -785,9 +800,9 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
}
}
-Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
+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
index 5f3acea..3960cf5 100644
--- a/lib/CodeGen/CGCXX.cpp
+++ b/lib/CodeGen/CGCXX.cpp
@@ -11,22 +11,123 @@
//
//===----------------------------------------------------------------------===//
-// We might split this into multiple files if it gets too unwieldy
+// 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/RecordLayout.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/StmtCXX.h"
#include "llvm/ADT/StringExtras.h"
using namespace clang;
using namespace CodeGen;
-void
-CodeGenFunction::GenerateStaticCXXBlockVarDeclInit(const VarDecl &D,
- llvm::GlobalVariable *GV) {
+void
+CodeGenFunction::EmitCXXGlobalDtorRegistration(const CXXDestructorDecl *Dtor,
+ llvm::Constant *DeclPtr) {
+ const llvm::Type *Int8PtrTy =
+ llvm::Type::getInt8Ty(VMContext)->getPointerTo();
+
+ std::vector<const llvm::Type *> Params;
+ Params.push_back(Int8PtrTy);
+
+ // Get the destructor function type
+ const llvm::Type *DtorFnTy =
+ llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Params, false);
+ DtorFnTy = llvm::PointerType::getUnqual(DtorFnTy);
+
+ Params.clear();
+ Params.push_back(DtorFnTy);
+ Params.push_back(Int8PtrTy);
+ Params.push_back(Int8PtrTy);
+
+ // Get the __cxa_atexit function type
+ // extern "C" int __cxa_atexit ( void (*f)(void *), void *p, void *d );
+ const llvm::FunctionType *AtExitFnTy =
+ llvm::FunctionType::get(ConvertType(getContext().IntTy), Params, false);
+
+ llvm::Constant *AtExitFn = CGM.CreateRuntimeFunction(AtExitFnTy,
+ "__cxa_atexit");
+
+ llvm::Constant *Handle = CGM.CreateRuntimeVariable(Int8PtrTy,
+ "__dso_handle");
+
+ llvm::Constant *DtorFn = CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete);
+
+ llvm::Value *Args[3] = { llvm::ConstantExpr::getBitCast(DtorFn, DtorFnTy),
+ llvm::ConstantExpr::getBitCast(DeclPtr, Int8PtrTy),
+ llvm::ConstantExpr::getBitCast(Handle, Int8PtrTy) };
+ Builder.CreateCall(AtExitFn, &Args[0], llvm::array_endof(Args));
+}
+
+void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D,
+ llvm::Constant *DeclPtr) {
+ assert(D.hasGlobalStorage() &&
+ "VarDecl must have global storage!");
+
+ const Expr *Init = D.getInit();
+ QualType T = D.getType();
+
+ if (T->isReferenceType()) {
+ ErrorUnsupported(Init, "global variable that binds to a reference");
+ } else if (!hasAggregateLLVMType(T)) {
+ llvm::Value *V = EmitScalarExpr(Init);
+ EmitStoreOfScalar(V, DeclPtr, T.isVolatileQualified(), T);
+ } else if (T->isAnyComplexType()) {
+ EmitComplexExprIntoAddr(Init, DeclPtr, T.isVolatileQualified());
+ } else {
+ EmitAggExpr(Init, DeclPtr, T.isVolatileQualified());
+
+ if (const RecordType *RT = T->getAs<RecordType>()) {
+ CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+ if (!RD->hasTrivialDestructor())
+ EmitCXXGlobalDtorRegistration(RD->getDestructor(getContext()), DeclPtr);
+ }
+ }
+}
+
+void
+CodeGenModule::EmitCXXGlobalInitFunc() {
+ if (CXXGlobalInits.empty())
+ return;
+
+ const llvm::FunctionType *FTy = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
+ false);
+
+ // Create our global initialization function.
+ // FIXME: Should this be tweakable by targets?
+ llvm::Function *Fn =
+ llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
+ "__cxx_global_initialization", &TheModule);
+
+ CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn,
+ &CXXGlobalInits[0],
+ CXXGlobalInits.size());
+ AddGlobalCtor(Fn);
+}
+
+void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
+ const VarDecl **Decls,
+ unsigned NumDecls) {
+ StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(),
+ SourceLocation());
+
+ for (unsigned i = 0; i != NumDecls; ++i) {
+ const VarDecl *D = Decls[i];
+
+ llvm::Constant *DeclPtr = CGM.GetAddrOfGlobalVar(D);
+ EmitCXXGlobalVarDeclInit(*D, DeclPtr);
+ }
+ FinishFunction();
+}
+
+void
+CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D,
+ llvm::GlobalVariable *GV) {
// FIXME: This should use __cxa_guard_{acquire,release}?
assert(!getContext().getLangOptions().ThreadsafeStatics &&
@@ -34,46 +135,37 @@ CodeGenFunction::GenerateStaticCXXBlockVarDeclInit(const VarDecl &D,
llvm::SmallString<256> GuardVName;
llvm::raw_svector_ostream GuardVOut(GuardVName);
- mangleGuardVariable(&D, getContext(), GuardVOut);
-
+ mangleGuardVariable(CGM.getMangleContext(), &D, GuardVOut);
+
// Create the guard variable.
- llvm::GlobalValue *GuardV =
- new llvm::GlobalVariable(llvm::Type::Int64Ty, false,
+ llvm::GlobalValue *GuardV =
+ new llvm::GlobalVariable(CGM.getModule(), llvm::Type::getInt64Ty(VMContext), false,
GV->getLinkage(),
- llvm::Constant::getNullValue(llvm::Type::Int64Ty),
- GuardVName.c_str(),
- &CGM.getModule());
-
+ llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext)),
+ GuardVName.str());
+
// 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),
+ const llvm::Type *PtrTy = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 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 *nullValue = llvm::Constant::getNullValue(llvm::Type::getInt8Ty(VMContext));
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),
+ EmitCXXGlobalVarDeclInit(D, GV);
+
+ Builder.CreateStore(llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), 1),
Builder.CreateBitCast(GuardV, PtrTy));
-
+
EmitBlock(EndBlock);
}
@@ -82,336 +174,1399 @@ RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD,
llvm::Value *This,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd) {
- assert(MD->isInstance() &&
+ assert(MD->isInstance() &&
"Trying to emit a member call expr on a static method!");
- const FunctionProtoType *FPT = MD->getType()->getAsFunctionProtoType();
-
+ // A call to a trivial destructor requires no code generation.
+ if (const CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(MD))
+ if (Destructor->isTrivial())
+ return RValue::get(0);
+
+ const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
+
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();
+
+ QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType();
return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args),
Callee, Args, MD);
}
+/// canDevirtualizeMemberFunctionCalls - Checks whether virtual calls on given
+/// expr can be devirtualized.
+static bool canDevirtualizeMemberFunctionCalls(const Expr *Base) {
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base)) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
+ // This is a record decl. We know the type and can devirtualize it.
+ return VD->getType()->isRecordType();
+ }
+
+ return false;
+ }
+
+ // We can always devirtualize calls on temporary object expressions.
+ if (isa<CXXTemporaryObjectExpr>(Base))
+ return true;
+
+ // And calls on bound temporaries.
+ if (isa<CXXBindTemporaryExpr>(Base))
+ return true;
+
+ // Check if this is a call expr that returns a record type.
+ if (const CallExpr *CE = dyn_cast<CallExpr>(Base))
+ return CE->getCallReturnType()->isRecordType();
+
+ // We can't devirtualize the call.
+ return false;
+}
+
RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE) {
+ if (isa<BinaryOperator>(CE->getCallee()))
+ return EmitCXXMemberPointerCallExpr(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);
+ if (MD->isStatic()) {
+ // The method is static, emit it as we would a regular call.
+ llvm::Value *Callee = CGM.GetAddrOfFunction(MD);
+ return EmitCall(Callee, getContext().getPointerType(MD->getType()),
+ CE->arg_begin(), CE->arg_end(), 0);
+
+ }
+ const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
+
+ const llvm::Type *Ty =
+ CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
+ FPT->isVariadic());
llvm::Value *This;
-
+
if (ME->isArrow())
This = EmitScalarExpr(ME->getBase());
else {
LValue BaseLV = EmitLValue(ME->getBase());
This = BaseLV.getAddress();
}
-
- return EmitCXXMemberCall(MD, Callee, This,
+
+ // C++ [class.virtual]p12:
+ // Explicit qualification with the scope operator (5.1) suppresses the
+ // virtual call mechanism.
+ //
+ // We also don't emit a virtual call if the base expression has a record type
+ // because then we know what the type is.
+ llvm::Value *Callee;
+ if (MD->isVirtual() && !ME->hasQualifier() &&
+ !canDevirtualizeMemberFunctionCalls(ME->getBase()))
+ Callee = BuildVirtualCall(MD, This, Ty);
+ else if (const CXXDestructorDecl *Destructor
+ = dyn_cast<CXXDestructorDecl>(MD))
+ Callee = CGM.GetAddrOfFunction(GlobalDecl(Destructor, Dtor_Complete), Ty);
+ else
+ Callee = CGM.GetAddrOfFunction(MD, Ty);
+
+ 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!");
+RValue
+CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E) {
+ const BinaryOperator *BO = cast<BinaryOperator>(E->getCallee());
+ const Expr *BaseExpr = BO->getLHS();
+ const Expr *MemFnExpr = BO->getRHS();
+ const MemberPointerType *MPT =
+ MemFnExpr->getType()->getAs<MemberPointerType>();
+ const FunctionProtoType *FPT =
+ MPT->getPointeeType()->getAs<FunctionProtoType>();
+ const CXXRecordDecl *RD =
+ cast<CXXRecordDecl>(cast<RecordType>(MPT->getClass())->getDecl());
+
+ const llvm::FunctionType *FTy =
+ CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(RD, FPT),
+ FPT->isVariadic());
+
+ const llvm::Type *Int8PtrTy =
+ llvm::Type::getInt8Ty(VMContext)->getPointerTo();
+
+ // Get the member function pointer.
+ llvm::Value *MemFnPtr =
+ CreateTempAlloca(ConvertType(MemFnExpr->getType()), "mem.fn");
+ EmitAggExpr(MemFnExpr, MemFnPtr, /*VolatileDest=*/false);
+
+ // Emit the 'this' pointer.
+ llvm::Value *This;
- 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);
+ if (BO->getOpcode() == BinaryOperator::PtrMemI)
+ This = EmitScalarExpr(BaseExpr);
+ else
+ This = EmitLValue(BaseExpr).getAddress();
- llvm::Value *This = EmitLValue(E->getArg(0)).getAddress();
+ // Adjust it.
+ llvm::Value *Adj = Builder.CreateStructGEP(MemFnPtr, 1);
+ Adj = Builder.CreateLoad(Adj, "mem.fn.adj");
+
+ llvm::Value *Ptr = Builder.CreateBitCast(This, Int8PtrTy, "ptr");
+ Ptr = Builder.CreateGEP(Ptr, Adj, "adj");
+
+ This = Builder.CreateBitCast(Ptr, This->getType(), "this");
+
+ llvm::Value *FnPtr = Builder.CreateStructGEP(MemFnPtr, 0, "mem.fn.ptr");
+ const llvm::Type *PtrDiffTy = ConvertType(getContext().getPointerDiffType());
+
+ llvm::Value *FnAsInt = Builder.CreateLoad(FnPtr, "fn");
+
+ // If the LSB in the function pointer is 1, the function pointer points to
+ // a virtual function.
+ llvm::Value *IsVirtual
+ = Builder.CreateAnd(FnAsInt, llvm::ConstantInt::get(PtrDiffTy, 1),
+ "and");
+
+ IsVirtual = Builder.CreateTrunc(IsVirtual,
+ llvm::Type::getInt1Ty(VMContext));
+
+ llvm::BasicBlock *FnVirtual = createBasicBlock("fn.virtual");
+ llvm::BasicBlock *FnNonVirtual = createBasicBlock("fn.nonvirtual");
+ llvm::BasicBlock *FnEnd = createBasicBlock("fn.end");
+
+ Builder.CreateCondBr(IsVirtual, FnVirtual, FnNonVirtual);
+ EmitBlock(FnVirtual);
+
+ const llvm::Type *VTableTy =
+ FTy->getPointerTo()->getPointerTo()->getPointerTo();
+
+ llvm::Value *VTable = Builder.CreateBitCast(This, VTableTy);
+ VTable = Builder.CreateLoad(VTable);
+
+ VTable = Builder.CreateGEP(VTable, FnAsInt, "fn");
+
+ // Since the function pointer is 1 plus the virtual table offset, we
+ // subtract 1 by using a GEP.
+ VTable = Builder.CreateConstGEP1_64(VTable, (uint64_t)-1);
+
+ llvm::Value *VirtualFn = Builder.CreateLoad(VTable, "virtualfn");
+
+ EmitBranch(FnEnd);
+ EmitBlock(FnNonVirtual);
+
+ // If the function is not virtual, just load the pointer.
+ llvm::Value *NonVirtualFn = Builder.CreateLoad(FnPtr, "fn");
+ NonVirtualFn = Builder.CreateIntToPtr(NonVirtualFn, FTy->getPointerTo());
+
+ EmitBlock(FnEnd);
+
+ llvm::PHINode *Callee = Builder.CreatePHI(FTy->getPointerTo());
+ Callee->reserveOperandSpace(2);
+ Callee->addIncoming(VirtualFn, FnVirtual);
+ Callee->addIncoming(NonVirtualFn, FnNonVirtual);
+
+ CallArgList Args;
+
+ QualType ThisType =
+ getContext().getPointerType(getContext().getTagDeclType(RD));
+
+ // Push the this ptr.
+ Args.push_back(std::make_pair(RValue::get(This), ThisType));
+
+ // And the rest of the call args
+ EmitCallArgs(Args, FPT, E->arg_begin(), E->arg_end());
+ QualType ResultType = BO->getType()->getAs<FunctionType>()->getResultType();
+ return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args),
+ Callee, Args, 0);
+}
+
+RValue
+CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E,
+ const CXXMethodDecl *MD) {
+ assert(MD->isInstance() &&
+ "Trying to emit a member call expr on a static method!");
+
+ if (MD->isCopyAssignment()) {
+ const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(MD->getDeclContext());
+ if (ClassDecl->hasTrivialCopyAssignment()) {
+ assert(!ClassDecl->hasUserDeclaredCopyAssignment() &&
+ "EmitCXXOperatorMemberCallExpr - user declared copy assignment");
+ llvm::Value *This = EmitLValue(E->getArg(0)).getAddress();
+ llvm::Value *Src = EmitLValue(E->getArg(1)).getAddress();
+ QualType Ty = E->getType();
+ EmitAggregateCopy(This, Src, Ty);
+ return RValue::get(This);
+ }
+ }
+
+ const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
+ const llvm::Type *Ty =
+ CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
+ FPT->isVariadic());
+ llvm::Constant *Callee = CGM.GetAddrOfFunction(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) &&
+ 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");
}
+/// EmitCXXAggrConstructorCall - This routine essentially creates a (nested)
+/// for-loop to call the default constructor on individual members of the
+/// array.
+/// 'D' is the default constructor for elements of the array, 'ArrayTy' is the
+/// array type and 'ArrayPtr' points to the beginning fo the array.
+/// It is assumed that all relevant checks have been made by the caller.
+void
+CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
+ const ConstantArrayType *ArrayTy,
+ llvm::Value *ArrayPtr) {
+ const llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
+ llvm::Value * NumElements =
+ llvm::ConstantInt::get(SizeTy,
+ getContext().getConstantArrayElementCount(ArrayTy));
+
+ EmitCXXAggrConstructorCall(D, NumElements, ArrayPtr);
+}
+
+void
+CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
+ llvm::Value *NumElements,
+ llvm::Value *ArrayPtr) {
+ const llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
+
+ // Create a temporary for the loop index and initialize it with 0.
+ llvm::Value *IndexPtr = CreateTempAlloca(SizeTy, "loop.index");
+ llvm::Value *Zero = llvm::Constant::getNullValue(SizeTy);
+ Builder.CreateStore(Zero, IndexPtr, false);
+
+ // Start the loop with a block that tests the condition.
+ llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
+ llvm::BasicBlock *AfterFor = createBasicBlock("for.end");
+
+ EmitBlock(CondBlock);
+
+ llvm::BasicBlock *ForBody = createBasicBlock("for.body");
+
+ // Generate: if (loop-index < number-of-elements fall to the loop body,
+ // otherwise, go to the block after the for-loop.
+ llvm::Value *Counter = Builder.CreateLoad(IndexPtr);
+ llvm::Value *IsLess = Builder.CreateICmpULT(Counter, NumElements, "isless");
+ // If the condition is true, execute the body.
+ Builder.CreateCondBr(IsLess, ForBody, AfterFor);
+
+ EmitBlock(ForBody);
+
+ llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc");
+ // Inside the loop body, emit the constructor call on the array element.
+ Counter = Builder.CreateLoad(IndexPtr);
+ llvm::Value *Address = Builder.CreateInBoundsGEP(ArrayPtr, Counter,
+ "arrayidx");
+ EmitCXXConstructorCall(D, Ctor_Complete, Address, 0, 0);
+
+ EmitBlock(ContinueBlock);
+
+ // Emit the increment of the loop counter.
+ llvm::Value *NextVal = llvm::ConstantInt::get(SizeTy, 1);
+ Counter = Builder.CreateLoad(IndexPtr);
+ NextVal = Builder.CreateAdd(Counter, NextVal, "inc");
+ Builder.CreateStore(NextVal, IndexPtr, false);
+
+ // Finally, branch back up to the condition for the next iteration.
+ EmitBranch(CondBlock);
+
+ // Emit the fall-through block.
+ EmitBlock(AfterFor, true);
+}
+
+/// EmitCXXAggrDestructorCall - calls the default destructor on array
+/// elements in reverse order of construction.
+void
+CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
+ const ArrayType *Array,
+ llvm::Value *This) {
+ const ConstantArrayType *CA = dyn_cast<ConstantArrayType>(Array);
+ assert(CA && "Do we support VLA for destruction ?");
+ llvm::Value *One = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
+ 1);
+ uint64_t ElementCount = getContext().getConstantArrayElementCount(CA);
+ // Create a temporary for the loop index and initialize it with count of
+ // array elements.
+ llvm::Value *IndexPtr = CreateTempAlloca(llvm::Type::getInt64Ty(VMContext),
+ "loop.index");
+ // Index = ElementCount;
+ llvm::Value* UpperCount =
+ llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), ElementCount);
+ Builder.CreateStore(UpperCount, IndexPtr, false);
+
+ // Start the loop with a block that tests the condition.
+ llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
+ llvm::BasicBlock *AfterFor = createBasicBlock("for.end");
+
+ EmitBlock(CondBlock);
+
+ llvm::BasicBlock *ForBody = createBasicBlock("for.body");
+
+ // Generate: if (loop-index != 0 fall to the loop body,
+ // otherwise, go to the block after the for-loop.
+ llvm::Value* zeroConstant =
+ llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext));
+ llvm::Value *Counter = Builder.CreateLoad(IndexPtr);
+ llvm::Value *IsNE = Builder.CreateICmpNE(Counter, zeroConstant,
+ "isne");
+ // If the condition is true, execute the body.
+ Builder.CreateCondBr(IsNE, ForBody, AfterFor);
+
+ EmitBlock(ForBody);
+
+ llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc");
+ // Inside the loop body, emit the constructor call on the array element.
+ Counter = Builder.CreateLoad(IndexPtr);
+ Counter = Builder.CreateSub(Counter, One);
+ llvm::Value *Address = Builder.CreateInBoundsGEP(This, Counter, "arrayidx");
+ EmitCXXDestructorCall(D, Dtor_Complete, Address);
+
+ EmitBlock(ContinueBlock);
+
+ // Emit the decrement of the loop counter.
+ Counter = Builder.CreateLoad(IndexPtr);
+ Counter = Builder.CreateSub(Counter, One, "dec");
+ Builder.CreateStore(Counter, IndexPtr, false);
+
+ // Finally, branch back up to the condition for the next iteration.
+ EmitBranch(CondBlock);
+
+ // Emit the fall-through block.
+ EmitBlock(AfterFor, true);
+}
+
void
-CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
- CXXCtorType Type,
+CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
+ CXXCtorType Type,
llvm::Value *This,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd) {
+ if (D->isCopyConstructor(getContext())) {
+ const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(D->getDeclContext());
+ if (ClassDecl->hasTrivialCopyConstructor()) {
+ assert(!ClassDecl->hasUserDeclaredCopyConstructor() &&
+ "EmitCXXConstructorCall - user declared copy constructor");
+ const Expr *E = (*ArgBeg);
+ QualType Ty = E->getType();
+ llvm::Value *Src = EmitLValue(E).getAddress();
+ EmitAggregateCopy(This, Src, Ty);
+ return;
+ }
+ }
+
llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type);
EmitCXXMemberCall(D, Callee, This, ArgBeg, ArgEnd);
}
-void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *D,
+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,
+void
+CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest,
const CXXConstructExpr *E) {
assert(Dest && "Must have a destination!");
-
- const CXXRecordDecl *RD =
- cast<CXXRecordDecl>(E->getType()->getAsRecordType()->getDecl());
+
+ const CXXRecordDecl *RD =
+ cast<CXXRecordDecl>(E->getType()->getAs<RecordType>()->getDecl());
if (RD->hasTrivialConstructor())
return;
-
- // Call the constructor.
- EmitCXXConstructorCall(E->getConstructor(), Ctor_Complete, Dest,
- E->arg_begin(), E->arg_end());
-}
-
-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(), E = RD->field_end();
- I != E; ++I) {
- // We don't support ctors for fields that aren't POD.
- if (!I->getType()->isPODType())
- return false;
+ // Code gen optimization to eliminate copy constructor and return
+ // its first argument instead.
+ if (getContext().getLangOptions().ElideConstructors && E->isElidable()) {
+ CXXConstructExpr::const_arg_iterator i = E->arg_begin();
+ EmitAggExpr((*i), Dest, false);
+ return;
}
-
- return true;
+ // Call the constructor.
+ EmitCXXConstructorCall(E->getConstructor(), Ctor_Complete, Dest,
+ E->arg_begin(), E->arg_end());
}
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,
+void CodeGenModule::EmitCXXConstructor(const CXXConstructorDecl *D,
CXXCtorType Type) {
-
+
llvm::Function *Fn = GetAddrOfCXXConstructor(D, Type);
-
- CodeGenFunction(*this).GenerateCode(D, Fn);
-
+
+ CodeGenFunction(*this).GenerateCode(GlobalDecl(D, Type), Fn);
+
SetFunctionDefinitionAttributes(D, Fn);
SetLLVMFunctionAttributesForDefinition(D, Fn);
}
llvm::Function *
-CodeGenModule::GetAddrOfCXXConstructor(const CXXConstructorDecl *D,
+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,
+const char *CodeGenModule::getMangledCXXCtorName(const CXXConstructorDecl *D,
CXXCtorType Type) {
llvm::SmallString<256> Name;
llvm::raw_svector_ostream Out(Name);
- mangleCXXCtor(D, Type, Context, Out);
-
+ mangleCXXCtor(getMangleContext(), D, Type, 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,
+void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *D,
CXXDtorType Type) {
llvm::Function *Fn = GetAddrOfCXXDestructor(D, Type);
-
- CodeGenFunction(*this).GenerateCode(D, Fn);
-
+
+ CodeGenFunction(*this).GenerateCode(GlobalDecl(D, Type), Fn);
+
SetFunctionDefinitionAttributes(D, Fn);
SetLLVMFunctionAttributesForDefinition(D, Fn);
}
llvm::Function *
-CodeGenModule::GetAddrOfCXXDestructor(const CXXDestructorDecl *D,
+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,
+const char *CodeGenModule::getMangledCXXDtorName(const CXXDestructorDecl *D,
CXXDtorType Type) {
llvm::SmallString<256> Name;
llvm::raw_svector_ostream Out(Name);
- mangleCXXDtor(D, Type, Context, Out);
-
+ mangleCXXDtor(getMangleContext(), D, Type, Out);
+
Name += '\0';
return UniqueMangledName(Name.begin(), Name.end());
}
+
+llvm::Constant *CodeGenFunction::GenerateThunk(llvm::Function *Fn,
+ const CXXMethodDecl *MD,
+ bool Extern, int64_t nv,
+ int64_t v) {
+ QualType R = MD->getType()->getAs<FunctionType>()->getResultType();
+
+ FunctionArgList Args;
+ ImplicitParamDecl *ThisDecl =
+ ImplicitParamDecl::Create(getContext(), 0, SourceLocation(), 0,
+ MD->getThisType(getContext()));
+ Args.push_back(std::make_pair(ThisDecl, ThisDecl->getType()));
+ for (FunctionDecl::param_const_iterator i = MD->param_begin(),
+ e = MD->param_end();
+ i != e; ++i) {
+ ParmVarDecl *D = *i;
+ Args.push_back(std::make_pair(D, D->getType()));
+ }
+ IdentifierInfo *II
+ = &CGM.getContext().Idents.get("__thunk_named_foo_");
+ FunctionDecl *FD = FunctionDecl::Create(getContext(),
+ getContext().getTranslationUnitDecl(),
+ SourceLocation(), II, R, 0,
+ Extern
+ ? FunctionDecl::Extern
+ : FunctionDecl::Static,
+ false, true);
+ StartFunction(FD, R, Fn, Args, SourceLocation());
+ // FIXME: generate body
+ FinishFunction();
+ return Fn;
+}
+
+llvm::Constant *CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn,
+ const CXXMethodDecl *MD,
+ bool Extern,
+ int64_t nv_t,
+ int64_t v_t,
+ int64_t nv_r,
+ int64_t v_r) {
+ QualType R = MD->getType()->getAs<FunctionType>()->getResultType();
+
+ FunctionArgList Args;
+ ImplicitParamDecl *ThisDecl =
+ ImplicitParamDecl::Create(getContext(), 0, SourceLocation(), 0,
+ MD->getThisType(getContext()));
+ Args.push_back(std::make_pair(ThisDecl, ThisDecl->getType()));
+ for (FunctionDecl::param_const_iterator i = MD->param_begin(),
+ e = MD->param_end();
+ i != e; ++i) {
+ ParmVarDecl *D = *i;
+ Args.push_back(std::make_pair(D, D->getType()));
+ }
+ IdentifierInfo *II
+ = &CGM.getContext().Idents.get("__thunk_named_foo_");
+ FunctionDecl *FD = FunctionDecl::Create(getContext(),
+ getContext().getTranslationUnitDecl(),
+ SourceLocation(), II, R, 0,
+ Extern
+ ? FunctionDecl::Extern
+ : FunctionDecl::Static,
+ false, true);
+ StartFunction(FD, R, Fn, Args, SourceLocation());
+ // FIXME: generate body
+ FinishFunction();
+ return Fn;
+}
+
+llvm::Constant *CodeGenModule::BuildThunk(const CXXMethodDecl *MD, bool Extern,
+ int64_t nv, int64_t v) {
+ llvm::SmallString<256> OutName;
+ llvm::raw_svector_ostream Out(OutName);
+ mangleThunk(getMangleContext(), MD, nv, v, Out);
+ llvm::GlobalVariable::LinkageTypes linktype;
+ linktype = llvm::GlobalValue::WeakAnyLinkage;
+ if (!Extern)
+ linktype = llvm::GlobalValue::InternalLinkage;
+ llvm::Type *Ptr8Ty=llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),0);
+ const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
+ const llvm::FunctionType *FTy =
+ getTypes().GetFunctionType(getTypes().getFunctionInfo(MD),
+ FPT->isVariadic());
+
+ llvm::Function *Fn = llvm::Function::Create(FTy, linktype, Out.str(),
+ &getModule());
+ CodeGenFunction(*this).GenerateThunk(Fn, MD, Extern, nv, v);
+ // Fn = Builder.CreateBitCast(Fn, Ptr8Ty);
+ llvm::Constant *m = llvm::ConstantExpr::getBitCast(Fn, Ptr8Ty);
+ return m;
+}
+
+llvm::Constant *CodeGenModule::BuildCovariantThunk(const CXXMethodDecl *MD,
+ bool Extern, int64_t nv_t,
+ int64_t v_t, int64_t nv_r,
+ int64_t v_r) {
+ llvm::SmallString<256> OutName;
+ llvm::raw_svector_ostream Out(OutName);
+ mangleCovariantThunk(getMangleContext(), MD, nv_t, v_t, nv_r, v_r, Out);
+ llvm::GlobalVariable::LinkageTypes linktype;
+ linktype = llvm::GlobalValue::WeakAnyLinkage;
+ if (!Extern)
+ linktype = llvm::GlobalValue::InternalLinkage;
+ llvm::Type *Ptr8Ty=llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),0);
+ const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
+ const llvm::FunctionType *FTy =
+ getTypes().GetFunctionType(getTypes().getFunctionInfo(MD),
+ FPT->isVariadic());
+
+ llvm::Function *Fn = llvm::Function::Create(FTy, linktype, Out.str(),
+ &getModule());
+ CodeGenFunction(*this).GenerateCovariantThunk(Fn, MD, Extern, nv_t, v_t, nv_r,
+ v_r);
+ // Fn = Builder.CreateBitCast(Fn, Ptr8Ty);
+ llvm::Constant *m = llvm::ConstantExpr::getBitCast(Fn, Ptr8Ty);
+ return m;
+}
+
+llvm::Value *
+CodeGenFunction::GetVirtualCXXBaseClassOffset(llvm::Value *This,
+ const CXXRecordDecl *ClassDecl,
+ const CXXRecordDecl *BaseClassDecl) {
+ const llvm::Type *Int8PtrTy =
+ llvm::Type::getInt8Ty(VMContext)->getPointerTo();
+
+ llvm::Value *VTablePtr = Builder.CreateBitCast(This,
+ Int8PtrTy->getPointerTo());
+ VTablePtr = Builder.CreateLoad(VTablePtr, "vtable");
+
+ int64_t VBaseOffsetIndex =
+ CGM.getVtableInfo().getVirtualBaseOffsetIndex(ClassDecl, BaseClassDecl);
+
+ llvm::Value *VBaseOffsetPtr =
+ Builder.CreateConstGEP1_64(VTablePtr, VBaseOffsetIndex, "vbase.offset.ptr");
+ const llvm::Type *PtrDiffTy =
+ ConvertType(getContext().getPointerDiffType());
+
+ VBaseOffsetPtr = Builder.CreateBitCast(VBaseOffsetPtr,
+ PtrDiffTy->getPointerTo());
+
+ llvm::Value *VBaseOffset = Builder.CreateLoad(VBaseOffsetPtr, "vbase.offset");
+
+ return VBaseOffset;
+}
+
+llvm::Value *
+CodeGenFunction::BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *&This,
+ const llvm::Type *Ty) {
+ int64_t Index = CGM.getVtableInfo().getMethodVtableIndex(MD);
+
+ Ty = llvm::PointerType::get(Ty, 0);
+ Ty = llvm::PointerType::get(Ty, 0);
+ Ty = llvm::PointerType::get(Ty, 0);
+ llvm::Value *vtbl = Builder.CreateBitCast(This, Ty);
+ vtbl = Builder.CreateLoad(vtbl);
+ llvm::Value *vfn = Builder.CreateConstInBoundsGEP1_64(vtbl,
+ Index, "vfn");
+ vfn = Builder.CreateLoad(vfn);
+ return vfn;
+}
+
+/// EmitClassAggrMemberwiseCopy - This routine generates code to copy a class
+/// array of objects from SrcValue to DestValue. Copying can be either a bitwise
+/// copy or via a copy constructor call.
+// FIXME. Consolidate this with EmitCXXAggrConstructorCall.
+void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest,
+ llvm::Value *Src,
+ const ArrayType *Array,
+ const CXXRecordDecl *BaseClassDecl,
+ QualType Ty) {
+ const ConstantArrayType *CA = dyn_cast<ConstantArrayType>(Array);
+ assert(CA && "VLA cannot be copied over");
+ bool BitwiseCopy = BaseClassDecl->hasTrivialCopyConstructor();
+
+ // Create a temporary for the loop index and initialize it with 0.
+ llvm::Value *IndexPtr = CreateTempAlloca(llvm::Type::getInt64Ty(VMContext),
+ "loop.index");
+ llvm::Value* zeroConstant =
+ llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext));
+ Builder.CreateStore(zeroConstant, IndexPtr, false);
+ // Start the loop with a block that tests the condition.
+ llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
+ llvm::BasicBlock *AfterFor = createBasicBlock("for.end");
+
+ EmitBlock(CondBlock);
+
+ llvm::BasicBlock *ForBody = createBasicBlock("for.body");
+ // Generate: if (loop-index < number-of-elements fall to the loop body,
+ // otherwise, go to the block after the for-loop.
+ uint64_t NumElements = getContext().getConstantArrayElementCount(CA);
+ llvm::Value * NumElementsPtr =
+ llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), NumElements);
+ llvm::Value *Counter = Builder.CreateLoad(IndexPtr);
+ llvm::Value *IsLess = Builder.CreateICmpULT(Counter, NumElementsPtr,
+ "isless");
+ // If the condition is true, execute the body.
+ Builder.CreateCondBr(IsLess, ForBody, AfterFor);
+
+ EmitBlock(ForBody);
+ llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc");
+ // Inside the loop body, emit the constructor call on the array element.
+ Counter = Builder.CreateLoad(IndexPtr);
+ Src = Builder.CreateInBoundsGEP(Src, Counter, "srcaddress");
+ Dest = Builder.CreateInBoundsGEP(Dest, Counter, "destaddress");
+ if (BitwiseCopy)
+ EmitAggregateCopy(Dest, Src, Ty);
+ else if (CXXConstructorDecl *BaseCopyCtor =
+ BaseClassDecl->getCopyConstructor(getContext(), 0)) {
+ llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(BaseCopyCtor,
+ Ctor_Complete);
+ CallArgList CallArgs;
+ // Push the this (Dest) ptr.
+ CallArgs.push_back(std::make_pair(RValue::get(Dest),
+ BaseCopyCtor->getThisType(getContext())));
+
+ // Push the Src ptr.
+ CallArgs.push_back(std::make_pair(RValue::get(Src),
+ BaseCopyCtor->getParamDecl(0)->getType()));
+ QualType ResultType =
+ BaseCopyCtor->getType()->getAs<FunctionType>()->getResultType();
+ EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
+ Callee, CallArgs, BaseCopyCtor);
+ }
+ EmitBlock(ContinueBlock);
+
+ // Emit the increment of the loop counter.
+ llvm::Value *NextVal = llvm::ConstantInt::get(Counter->getType(), 1);
+ Counter = Builder.CreateLoad(IndexPtr);
+ NextVal = Builder.CreateAdd(Counter, NextVal, "inc");
+ Builder.CreateStore(NextVal, IndexPtr, false);
+
+ // Finally, branch back up to the condition for the next iteration.
+ EmitBranch(CondBlock);
+
+ // Emit the fall-through block.
+ EmitBlock(AfterFor, true);
+}
+
+/// EmitClassAggrCopyAssignment - This routine generates code to assign a class
+/// array of objects from SrcValue to DestValue. Assignment can be either a
+/// bitwise assignment or via a copy assignment operator function call.
+/// FIXME. This can be consolidated with EmitClassAggrMemberwiseCopy
+void CodeGenFunction::EmitClassAggrCopyAssignment(llvm::Value *Dest,
+ llvm::Value *Src,
+ const ArrayType *Array,
+ const CXXRecordDecl *BaseClassDecl,
+ QualType Ty) {
+ const ConstantArrayType *CA = dyn_cast<ConstantArrayType>(Array);
+ assert(CA && "VLA cannot be asssigned");
+ bool BitwiseAssign = BaseClassDecl->hasTrivialCopyAssignment();
+
+ // Create a temporary for the loop index and initialize it with 0.
+ llvm::Value *IndexPtr = CreateTempAlloca(llvm::Type::getInt64Ty(VMContext),
+ "loop.index");
+ llvm::Value* zeroConstant =
+ llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext));
+ Builder.CreateStore(zeroConstant, IndexPtr, false);
+ // Start the loop with a block that tests the condition.
+ llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
+ llvm::BasicBlock *AfterFor = createBasicBlock("for.end");
+
+ EmitBlock(CondBlock);
+
+ llvm::BasicBlock *ForBody = createBasicBlock("for.body");
+ // Generate: if (loop-index < number-of-elements fall to the loop body,
+ // otherwise, go to the block after the for-loop.
+ uint64_t NumElements = getContext().getConstantArrayElementCount(CA);
+ llvm::Value * NumElementsPtr =
+ llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), NumElements);
+ llvm::Value *Counter = Builder.CreateLoad(IndexPtr);
+ llvm::Value *IsLess = Builder.CreateICmpULT(Counter, NumElementsPtr,
+ "isless");
+ // If the condition is true, execute the body.
+ Builder.CreateCondBr(IsLess, ForBody, AfterFor);
+
+ EmitBlock(ForBody);
+ llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc");
+ // Inside the loop body, emit the assignment operator call on array element.
+ Counter = Builder.CreateLoad(IndexPtr);
+ Src = Builder.CreateInBoundsGEP(Src, Counter, "srcaddress");
+ Dest = Builder.CreateInBoundsGEP(Dest, Counter, "destaddress");
+ const CXXMethodDecl *MD = 0;
+ if (BitwiseAssign)
+ EmitAggregateCopy(Dest, Src, Ty);
+ else {
+ bool hasCopyAssign = BaseClassDecl->hasConstCopyAssignment(getContext(),
+ MD);
+ assert(hasCopyAssign && "EmitClassAggrCopyAssignment - No user assign");
+ (void)hasCopyAssign;
+ const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
+ const llvm::Type *LTy =
+ CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
+ FPT->isVariadic());
+ llvm::Constant *Callee = CGM.GetAddrOfFunction(MD, LTy);
+
+ CallArgList CallArgs;
+ // Push the this (Dest) ptr.
+ CallArgs.push_back(std::make_pair(RValue::get(Dest),
+ MD->getThisType(getContext())));
+
+ // Push the Src ptr.
+ CallArgs.push_back(std::make_pair(RValue::get(Src),
+ MD->getParamDecl(0)->getType()));
+ QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType();
+ EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
+ Callee, CallArgs, MD);
+ }
+ EmitBlock(ContinueBlock);
+
+ // Emit the increment of the loop counter.
+ llvm::Value *NextVal = llvm::ConstantInt::get(Counter->getType(), 1);
+ Counter = Builder.CreateLoad(IndexPtr);
+ NextVal = Builder.CreateAdd(Counter, NextVal, "inc");
+ Builder.CreateStore(NextVal, IndexPtr, false);
+
+ // Finally, branch back up to the condition for the next iteration.
+ EmitBranch(CondBlock);
+
+ // Emit the fall-through block.
+ EmitBlock(AfterFor, true);
+}
+
+/// EmitClassMemberwiseCopy - This routine generates code to copy a class
+/// object from SrcValue to DestValue. Copying can be either a bitwise copy
+/// or via a copy constructor call.
+void CodeGenFunction::EmitClassMemberwiseCopy(
+ llvm::Value *Dest, llvm::Value *Src,
+ const CXXRecordDecl *ClassDecl,
+ const CXXRecordDecl *BaseClassDecl, QualType Ty) {
+ if (ClassDecl) {
+ Dest = GetAddressCXXOfBaseClass(Dest, ClassDecl, BaseClassDecl,
+ /*NullCheckValue=*/false);
+ Src = GetAddressCXXOfBaseClass(Src, ClassDecl, BaseClassDecl,
+ /*NullCheckValue=*/false);
+ }
+ if (BaseClassDecl->hasTrivialCopyConstructor()) {
+ EmitAggregateCopy(Dest, Src, Ty);
+ return;
+ }
+
+ if (CXXConstructorDecl *BaseCopyCtor =
+ BaseClassDecl->getCopyConstructor(getContext(), 0)) {
+ llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(BaseCopyCtor,
+ Ctor_Complete);
+ CallArgList CallArgs;
+ // Push the this (Dest) ptr.
+ CallArgs.push_back(std::make_pair(RValue::get(Dest),
+ BaseCopyCtor->getThisType(getContext())));
+
+ // Push the Src ptr.
+ CallArgs.push_back(std::make_pair(RValue::get(Src),
+ BaseCopyCtor->getParamDecl(0)->getType()));
+ QualType ResultType =
+ BaseCopyCtor->getType()->getAs<FunctionType>()->getResultType();
+ EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
+ Callee, CallArgs, BaseCopyCtor);
+ }
+}
+
+/// EmitClassCopyAssignment - This routine generates code to copy assign a class
+/// object from SrcValue to DestValue. Assignment can be either a bitwise
+/// assignment of via an assignment operator call.
+// FIXME. Consolidate this with EmitClassMemberwiseCopy as they share a lot.
+void CodeGenFunction::EmitClassCopyAssignment(
+ llvm::Value *Dest, llvm::Value *Src,
+ const CXXRecordDecl *ClassDecl,
+ const CXXRecordDecl *BaseClassDecl,
+ QualType Ty) {
+ if (ClassDecl) {
+ Dest = GetAddressCXXOfBaseClass(Dest, ClassDecl, BaseClassDecl,
+ /*NullCheckValue=*/false);
+ Src = GetAddressCXXOfBaseClass(Src, ClassDecl, BaseClassDecl,
+ /*NullCheckValue=*/false);
+ }
+ if (BaseClassDecl->hasTrivialCopyAssignment()) {
+ EmitAggregateCopy(Dest, Src, Ty);
+ return;
+ }
+
+ const CXXMethodDecl *MD = 0;
+ bool ConstCopyAssignOp = BaseClassDecl->hasConstCopyAssignment(getContext(),
+ MD);
+ assert(ConstCopyAssignOp && "EmitClassCopyAssignment - missing copy assign");
+ (void)ConstCopyAssignOp;
+
+ const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
+ const llvm::Type *LTy =
+ CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
+ FPT->isVariadic());
+ llvm::Constant *Callee = CGM.GetAddrOfFunction(MD, LTy);
+
+ CallArgList CallArgs;
+ // Push the this (Dest) ptr.
+ CallArgs.push_back(std::make_pair(RValue::get(Dest),
+ MD->getThisType(getContext())));
+
+ // Push the Src ptr.
+ CallArgs.push_back(std::make_pair(RValue::get(Src),
+ MD->getParamDecl(0)->getType()));
+ QualType ResultType =
+ MD->getType()->getAs<FunctionType>()->getResultType();
+ EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
+ Callee, CallArgs, MD);
+}
+
+/// SynthesizeDefaultConstructor - synthesize a default constructor
+void
+CodeGenFunction::SynthesizeDefaultConstructor(const CXXConstructorDecl *Ctor,
+ CXXCtorType Type,
+ llvm::Function *Fn,
+ const FunctionArgList &Args) {
+ StartFunction(GlobalDecl(Ctor, Type), Ctor->getResultType(), Fn, Args,
+ SourceLocation());
+ EmitCtorPrologue(Ctor, Type);
+ FinishFunction();
+}
+
+/// SynthesizeCXXCopyConstructor - This routine implicitly defines body of a copy
+/// constructor, in accordance with section 12.8 (p7 and p8) of C++03
+/// The implicitly-defined copy constructor for class X performs a memberwise
+/// copy of its subobjects. The order of copying is the same as the order
+/// of initialization of bases and members in a user-defined constructor
+/// Each subobject is copied in the manner appropriate to its type:
+/// if the subobject is of class type, the copy constructor for the class is
+/// used;
+/// if the subobject is an array, each element is copied, in the manner
+/// appropriate to the element type;
+/// if the subobject is of scalar type, the built-in assignment operator is
+/// used.
+/// Virtual base class subobjects shall be copied only once by the
+/// implicitly-defined copy constructor
+
+void
+CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor,
+ CXXCtorType Type,
+ llvm::Function *Fn,
+ const FunctionArgList &Args) {
+ const CXXRecordDecl *ClassDecl = Ctor->getParent();
+ assert(!ClassDecl->hasUserDeclaredCopyConstructor() &&
+ "SynthesizeCXXCopyConstructor - copy constructor has definition already");
+ StartFunction(GlobalDecl(Ctor, Type), Ctor->getResultType(), Fn, Args,
+ SourceLocation());
+
+ FunctionArgList::const_iterator i = Args.begin();
+ const VarDecl *ThisArg = i->first;
+ llvm::Value *ThisObj = GetAddrOfLocalVar(ThisArg);
+ llvm::Value *LoadOfThis = Builder.CreateLoad(ThisObj, "this");
+ const VarDecl *SrcArg = (i+1)->first;
+ llvm::Value *SrcObj = GetAddrOfLocalVar(SrcArg);
+ llvm::Value *LoadOfSrc = Builder.CreateLoad(SrcObj);
+
+ for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin();
+ Base != ClassDecl->bases_end(); ++Base) {
+ // FIXME. copy constrution of virtual base NYI
+ if (Base->isVirtual())
+ continue;
+
+ CXXRecordDecl *BaseClassDecl
+ = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ EmitClassMemberwiseCopy(LoadOfThis, LoadOfSrc, ClassDecl, BaseClassDecl,
+ Base->getType());
+ }
+
+ for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
+ FieldEnd = ClassDecl->field_end();
+ Field != FieldEnd; ++Field) {
+ QualType FieldType = getContext().getCanonicalType((*Field)->getType());
+ const ConstantArrayType *Array =
+ getContext().getAsConstantArrayType(FieldType);
+ if (Array)
+ FieldType = getContext().getBaseElementType(FieldType);
+
+ if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
+ CXXRecordDecl *FieldClassDecl
+ = cast<CXXRecordDecl>(FieldClassType->getDecl());
+ LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0);
+ LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0);
+ if (Array) {
+ const llvm::Type *BasePtr = ConvertType(FieldType);
+ BasePtr = llvm::PointerType::getUnqual(BasePtr);
+ llvm::Value *DestBaseAddrPtr =
+ Builder.CreateBitCast(LHS.getAddress(), BasePtr);
+ llvm::Value *SrcBaseAddrPtr =
+ Builder.CreateBitCast(RHS.getAddress(), BasePtr);
+ EmitClassAggrMemberwiseCopy(DestBaseAddrPtr, SrcBaseAddrPtr, Array,
+ FieldClassDecl, FieldType);
+ }
+ else
+ EmitClassMemberwiseCopy(LHS.getAddress(), RHS.getAddress(),
+ 0 /*ClassDecl*/, FieldClassDecl, FieldType);
+ continue;
+ }
+ // Do a built-in assignment of scalar data members.
+ LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0);
+ LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0);
+ RValue RVRHS = EmitLoadOfLValue(RHS, FieldType);
+ EmitStoreThroughLValue(RVRHS, LHS, FieldType);
+ }
+ FinishFunction();
+}
+
+/// SynthesizeCXXCopyAssignment - Implicitly define copy assignment operator.
+/// Before the implicitly-declared copy assignment operator for a class is
+/// implicitly defined, all implicitly- declared copy assignment operators for
+/// its direct base classes and its nonstatic data members shall have been
+/// implicitly defined. [12.8-p12]
+/// The implicitly-defined copy assignment operator for class X performs
+/// memberwise assignment of its subob- jects. The direct base classes of X are
+/// assigned first, in the order of their declaration in
+/// the base-specifier-list, and then the immediate nonstatic data members of X
+/// are assigned, in the order in which they were declared in the class
+/// definition.Each subobject is assigned in the manner appropriate to its type:
+/// if the subobject is of class type, the copy assignment operator for the
+/// class is used (as if by explicit qualification; that is, ignoring any
+/// possible virtual overriding functions in more derived classes);
+///
+/// if the subobject is an array, each element is assigned, in the manner
+/// appropriate to the element type;
+///
+/// if the subobject is of scalar type, the built-in assignment operator is
+/// used.
+void CodeGenFunction::SynthesizeCXXCopyAssignment(const CXXMethodDecl *CD,
+ llvm::Function *Fn,
+ const FunctionArgList &Args) {
+
+ const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(CD->getDeclContext());
+ assert(!ClassDecl->hasUserDeclaredCopyAssignment() &&
+ "SynthesizeCXXCopyAssignment - copy assignment has user declaration");
+ StartFunction(CD, CD->getResultType(), Fn, Args, SourceLocation());
+
+ FunctionArgList::const_iterator i = Args.begin();
+ const VarDecl *ThisArg = i->first;
+ llvm::Value *ThisObj = GetAddrOfLocalVar(ThisArg);
+ llvm::Value *LoadOfThis = Builder.CreateLoad(ThisObj, "this");
+ const VarDecl *SrcArg = (i+1)->first;
+ llvm::Value *SrcObj = GetAddrOfLocalVar(SrcArg);
+ llvm::Value *LoadOfSrc = Builder.CreateLoad(SrcObj);
+
+ for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin();
+ Base != ClassDecl->bases_end(); ++Base) {
+ // FIXME. copy assignment of virtual base NYI
+ if (Base->isVirtual())
+ continue;
+
+ CXXRecordDecl *BaseClassDecl
+ = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ EmitClassCopyAssignment(LoadOfThis, LoadOfSrc, ClassDecl, BaseClassDecl,
+ Base->getType());
+ }
+
+ for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
+ FieldEnd = ClassDecl->field_end();
+ Field != FieldEnd; ++Field) {
+ QualType FieldType = getContext().getCanonicalType((*Field)->getType());
+ const ConstantArrayType *Array =
+ getContext().getAsConstantArrayType(FieldType);
+ if (Array)
+ FieldType = getContext().getBaseElementType(FieldType);
+
+ if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
+ CXXRecordDecl *FieldClassDecl
+ = cast<CXXRecordDecl>(FieldClassType->getDecl());
+ LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0);
+ LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0);
+ if (Array) {
+ const llvm::Type *BasePtr = ConvertType(FieldType);
+ BasePtr = llvm::PointerType::getUnqual(BasePtr);
+ llvm::Value *DestBaseAddrPtr =
+ Builder.CreateBitCast(LHS.getAddress(), BasePtr);
+ llvm::Value *SrcBaseAddrPtr =
+ Builder.CreateBitCast(RHS.getAddress(), BasePtr);
+ EmitClassAggrCopyAssignment(DestBaseAddrPtr, SrcBaseAddrPtr, Array,
+ FieldClassDecl, FieldType);
+ }
+ else
+ EmitClassCopyAssignment(LHS.getAddress(), RHS.getAddress(),
+ 0 /*ClassDecl*/, FieldClassDecl, FieldType);
+ continue;
+ }
+ // Do a built-in assignment of scalar data members.
+ LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0);
+ LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0);
+ RValue RVRHS = EmitLoadOfLValue(RHS, FieldType);
+ EmitStoreThroughLValue(RVRHS, LHS, FieldType);
+ }
+
+ // return *this;
+ Builder.CreateStore(LoadOfThis, ReturnValue);
+
+ FinishFunction();
+}
+
+/// EmitCtorPrologue - This routine generates necessary code to initialize
+/// base classes and non-static data members belonging to this constructor.
+/// FIXME: This needs to take a CXXCtorType.
+void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
+ CXXCtorType CtorType) {
+ const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(CD->getDeclContext());
+ // FIXME: Add vbase initialization
+ llvm::Value *LoadOfThis = 0;
+
+ for (CXXConstructorDecl::init_const_iterator B = CD->init_begin(),
+ E = CD->init_end();
+ B != E; ++B) {
+ CXXBaseOrMemberInitializer *Member = (*B);
+ if (Member->isBaseInitializer()) {
+ LoadOfThis = LoadCXXThis();
+ Type *BaseType = Member->getBaseClass();
+ CXXRecordDecl *BaseClassDecl =
+ cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl());
+ llvm::Value *V = GetAddressCXXOfBaseClass(LoadOfThis, ClassDecl,
+ BaseClassDecl,
+ /*NullCheckValue=*/false);
+ EmitCXXConstructorCall(Member->getConstructor(),
+ CtorType, V,
+ Member->const_arg_begin(),
+ Member->const_arg_end());
+ } else {
+ // non-static data member initilaizers.
+ FieldDecl *Field = Member->getMember();
+ QualType FieldType = getContext().getCanonicalType((Field)->getType());
+ const ConstantArrayType *Array =
+ getContext().getAsConstantArrayType(FieldType);
+ if (Array)
+ FieldType = getContext().getBaseElementType(FieldType);
+
+ LoadOfThis = LoadCXXThis();
+ LValue LHS;
+ if (FieldType->isReferenceType()) {
+ // FIXME: This is really ugly; should be refactored somehow
+ unsigned idx = CGM.getTypes().getLLVMFieldNo(Field);
+ llvm::Value *V = Builder.CreateStructGEP(LoadOfThis, idx, "tmp");
+ assert(!FieldType.getObjCGCAttr() && "fields cannot have GC attrs");
+ LHS = LValue::MakeAddr(V, MakeQualifiers(FieldType));
+ } else {
+ LHS = EmitLValueForField(LoadOfThis, Field, false, 0);
+ }
+ if (FieldType->getAs<RecordType>()) {
+ if (!Field->isAnonymousStructOrUnion()) {
+ assert(Member->getConstructor() &&
+ "EmitCtorPrologue - no constructor to initialize member");
+ if (Array) {
+ const llvm::Type *BasePtr = ConvertType(FieldType);
+ BasePtr = llvm::PointerType::getUnqual(BasePtr);
+ llvm::Value *BaseAddrPtr =
+ Builder.CreateBitCast(LHS.getAddress(), BasePtr);
+ EmitCXXAggrConstructorCall(Member->getConstructor(),
+ Array, BaseAddrPtr);
+ }
+ else
+ EmitCXXConstructorCall(Member->getConstructor(),
+ Ctor_Complete, LHS.getAddress(),
+ Member->const_arg_begin(),
+ Member->const_arg_end());
+ continue;
+ }
+ else {
+ // Initializing an anonymous union data member.
+ FieldDecl *anonMember = Member->getAnonUnionMember();
+ LHS = EmitLValueForField(LHS.getAddress(), anonMember,
+ /*IsUnion=*/true, 0);
+ FieldType = anonMember->getType();
+ }
+ }
+
+ assert(Member->getNumArgs() == 1 && "Initializer count must be 1 only");
+ Expr *RhsExpr = *Member->arg_begin();
+ RValue RHS;
+ if (FieldType->isReferenceType())
+ RHS = EmitReferenceBindingToExpr(RhsExpr, FieldType,
+ /*IsInitializer=*/true);
+ else
+ RHS = RValue::get(EmitScalarExpr(RhsExpr, true));
+ EmitStoreThroughLValue(RHS, LHS, FieldType);
+ }
+ }
+
+ if (!CD->getNumBaseOrMemberInitializers() && !CD->isTrivial()) {
+ // Nontrivial default constructor with no initializer list. It may still
+ // have bases classes and/or contain non-static data members which require
+ // construction.
+ for (CXXRecordDecl::base_class_const_iterator Base =
+ ClassDecl->bases_begin();
+ Base != ClassDecl->bases_end(); ++Base) {
+ // FIXME. copy assignment of virtual base NYI
+ if (Base->isVirtual())
+ continue;
+
+ CXXRecordDecl *BaseClassDecl
+ = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ if (BaseClassDecl->hasTrivialConstructor())
+ continue;
+ if (CXXConstructorDecl *BaseCX =
+ BaseClassDecl->getDefaultConstructor(getContext())) {
+ LoadOfThis = LoadCXXThis();
+ llvm::Value *V = GetAddressCXXOfBaseClass(LoadOfThis, ClassDecl,
+ BaseClassDecl,
+ /*NullCheckValue=*/false);
+ EmitCXXConstructorCall(BaseCX, Ctor_Complete, V, 0, 0);
+ }
+ }
+
+ for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
+ FieldEnd = ClassDecl->field_end();
+ Field != FieldEnd; ++Field) {
+ QualType FieldType = getContext().getCanonicalType((*Field)->getType());
+ const ConstantArrayType *Array =
+ getContext().getAsConstantArrayType(FieldType);
+ if (Array)
+ FieldType = getContext().getBaseElementType(FieldType);
+ if (!FieldType->getAs<RecordType>() || Field->isAnonymousStructOrUnion())
+ continue;
+ const RecordType *ClassRec = FieldType->getAs<RecordType>();
+ CXXRecordDecl *MemberClassDecl =
+ dyn_cast<CXXRecordDecl>(ClassRec->getDecl());
+ if (!MemberClassDecl || MemberClassDecl->hasTrivialConstructor())
+ continue;
+ if (CXXConstructorDecl *MamberCX =
+ MemberClassDecl->getDefaultConstructor(getContext())) {
+ LoadOfThis = LoadCXXThis();
+ LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0);
+ if (Array) {
+ const llvm::Type *BasePtr = ConvertType(FieldType);
+ BasePtr = llvm::PointerType::getUnqual(BasePtr);
+ llvm::Value *BaseAddrPtr =
+ Builder.CreateBitCast(LHS.getAddress(), BasePtr);
+ EmitCXXAggrConstructorCall(MamberCX, Array, BaseAddrPtr);
+ }
+ else
+ EmitCXXConstructorCall(MamberCX, Ctor_Complete, LHS.getAddress(),
+ 0, 0);
+ }
+ }
+ }
+
+ // Initialize the vtable pointer
+ if (ClassDecl->isDynamicClass()) {
+ if (!LoadOfThis)
+ LoadOfThis = LoadCXXThis();
+ llvm::Value *VtableField;
+ llvm::Type *Ptr8Ty, *PtrPtr8Ty;
+ Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0);
+ PtrPtr8Ty = llvm::PointerType::get(Ptr8Ty, 0);
+ VtableField = Builder.CreateBitCast(LoadOfThis, PtrPtr8Ty);
+ llvm::Value *vtable = GenerateVtable(ClassDecl);
+ Builder.CreateStore(vtable, VtableField);
+ }
+}
+
+/// EmitDtorEpilogue - Emit all code that comes at the end of class's
+/// destructor. This is to call destructors on members and base classes
+/// in reverse order of their construction.
+/// FIXME: This needs to take a CXXDtorType.
+void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD,
+ CXXDtorType DtorType) {
+ const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(DD->getDeclContext());
+ assert(!ClassDecl->getNumVBases() &&
+ "FIXME: Destruction of virtual bases not supported");
+ (void)ClassDecl; // prevent warning.
+
+ for (CXXDestructorDecl::destr_const_iterator *B = DD->destr_begin(),
+ *E = DD->destr_end(); B != E; ++B) {
+ uintptr_t BaseOrMember = (*B);
+ if (DD->isMemberToDestroy(BaseOrMember)) {
+ FieldDecl *FD = DD->getMemberToDestroy(BaseOrMember);
+ QualType FieldType = getContext().getCanonicalType((FD)->getType());
+ const ConstantArrayType *Array =
+ getContext().getAsConstantArrayType(FieldType);
+ if (Array)
+ FieldType = getContext().getBaseElementType(FieldType);
+ const RecordType *RT = FieldType->getAs<RecordType>();
+ CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
+ if (FieldClassDecl->hasTrivialDestructor())
+ continue;
+ llvm::Value *LoadOfThis = LoadCXXThis();
+ LValue LHS = EmitLValueForField(LoadOfThis, FD, false, 0);
+ if (Array) {
+ const llvm::Type *BasePtr = ConvertType(FieldType);
+ BasePtr = llvm::PointerType::getUnqual(BasePtr);
+ llvm::Value *BaseAddrPtr =
+ Builder.CreateBitCast(LHS.getAddress(), BasePtr);
+ EmitCXXAggrDestructorCall(FieldClassDecl->getDestructor(getContext()),
+ Array, BaseAddrPtr);
+ }
+ else
+ EmitCXXDestructorCall(FieldClassDecl->getDestructor(getContext()),
+ Dtor_Complete, LHS.getAddress());
+ } else {
+ const RecordType *RT =
+ DD->getAnyBaseClassToDestroy(BaseOrMember)->getAs<RecordType>();
+ CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(RT->getDecl());
+ if (BaseClassDecl->hasTrivialDestructor())
+ continue;
+ llvm::Value *V = GetAddressCXXOfBaseClass(LoadCXXThis(),
+ ClassDecl, BaseClassDecl,
+ /*NullCheckValue=*/false);
+ EmitCXXDestructorCall(BaseClassDecl->getDestructor(getContext()),
+ DtorType, V);
+ }
+ }
+ if (DD->getNumBaseOrMemberDestructions() || DD->isTrivial())
+ return;
+ // Case of destructor synthesis with fields and base classes
+ // which have non-trivial destructors. They must be destructed in
+ // reverse order of their construction.
+ llvm::SmallVector<FieldDecl *, 16> DestructedFields;
+
+ for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
+ FieldEnd = ClassDecl->field_end();
+ Field != FieldEnd; ++Field) {
+ QualType FieldType = getContext().getCanonicalType((*Field)->getType());
+ if (getContext().getAsConstantArrayType(FieldType))
+ FieldType = getContext().getBaseElementType(FieldType);
+ if (const RecordType *RT = FieldType->getAs<RecordType>()) {
+ CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
+ if (FieldClassDecl->hasTrivialDestructor())
+ continue;
+ DestructedFields.push_back(*Field);
+ }
+ }
+ if (!DestructedFields.empty())
+ for (int i = DestructedFields.size() -1; i >= 0; --i) {
+ FieldDecl *Field = DestructedFields[i];
+ QualType FieldType = Field->getType();
+ const ConstantArrayType *Array =
+ getContext().getAsConstantArrayType(FieldType);
+ if (Array)
+ FieldType = getContext().getBaseElementType(FieldType);
+ const RecordType *RT = FieldType->getAs<RecordType>();
+ CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
+ llvm::Value *LoadOfThis = LoadCXXThis();
+ LValue LHS = EmitLValueForField(LoadOfThis, Field, false, 0);
+ if (Array) {
+ const llvm::Type *BasePtr = ConvertType(FieldType);
+ BasePtr = llvm::PointerType::getUnqual(BasePtr);
+ llvm::Value *BaseAddrPtr =
+ Builder.CreateBitCast(LHS.getAddress(), BasePtr);
+ EmitCXXAggrDestructorCall(FieldClassDecl->getDestructor(getContext()),
+ Array, BaseAddrPtr);
+ }
+ else
+ EmitCXXDestructorCall(FieldClassDecl->getDestructor(getContext()),
+ Dtor_Complete, LHS.getAddress());
+ }
+
+ llvm::SmallVector<CXXRecordDecl*, 4> DestructedBases;
+ for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin();
+ Base != ClassDecl->bases_end(); ++Base) {
+ // FIXME. copy assignment of virtual base NYI
+ if (Base->isVirtual())
+ continue;
+
+ CXXRecordDecl *BaseClassDecl
+ = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ if (BaseClassDecl->hasTrivialDestructor())
+ continue;
+ DestructedBases.push_back(BaseClassDecl);
+ }
+ if (DestructedBases.empty())
+ return;
+ for (int i = DestructedBases.size() -1; i >= 0; --i) {
+ CXXRecordDecl *BaseClassDecl = DestructedBases[i];
+ llvm::Value *V = GetAddressCXXOfBaseClass(LoadCXXThis(),
+ ClassDecl,BaseClassDecl,
+ /*NullCheckValue=*/false);
+ EmitCXXDestructorCall(BaseClassDecl->getDestructor(getContext()),
+ Dtor_Complete, V);
+ }
+}
+
+void CodeGenFunction::SynthesizeDefaultDestructor(const CXXDestructorDecl *Dtor,
+ CXXDtorType DtorType,
+ llvm::Function *Fn,
+ const FunctionArgList &Args) {
+
+ const CXXRecordDecl *ClassDecl = Dtor->getParent();
+ assert(!ClassDecl->hasUserDeclaredDestructor() &&
+ "SynthesizeDefaultDestructor - destructor has user declaration");
+ (void) ClassDecl;
+
+ StartFunction(GlobalDecl(Dtor, DtorType), Dtor->getResultType(), Fn, Args,
+ SourceLocation());
+ EmitDtorEpilogue(Dtor, DtorType);
+ FinishFunction();
+}
+
+// FIXME: Move this to CGCXXStmt.cpp
+void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
+ // FIXME: We need to do more here.
+ EmitStmt(S.getTryBlock());
+}
diff --git a/lib/CodeGen/CGCXX.h b/lib/CodeGen/CGCXX.h
index 6051d91..1e6adb0 100644
--- a/lib/CodeGen/CGCXX.h
+++ b/lib/CodeGen/CGCXX.h
@@ -30,7 +30,7 @@ enum CXXDtorType {
Dtor_Complete, // Complete object dtor
Dtor_Base // Base object dtor
};
-
+
} // end namespace clang
#endif // CLANG_CODEGEN_CGCXX_H
diff --git a/lib/CodeGen/CGCXXClass.cpp b/lib/CodeGen/CGCXXClass.cpp
new file mode 100644
index 0000000..56a28fc
--- /dev/null
+++ b/lib/CodeGen/CGCXXClass.cpp
@@ -0,0 +1,176 @@
+//===--- CGCXXClass.cpp - Emit LLVM Code for C++ classes ------------------===//
+//
+// 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 of classes
+//
+//===----------------------------------------------------------------------===//
+
+#include "CodeGenFunction.h"
+#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/RecordLayout.h"
+
+using namespace clang;
+using namespace CodeGen;
+
+static uint64_t
+ComputeNonVirtualBaseClassOffset(ASTContext &Context, CXXBasePaths &Paths,
+ unsigned Start) {
+ uint64_t Offset = 0;
+
+ const CXXBasePath &Path = Paths.front();
+ for (unsigned i = Start, e = Path.size(); i != e; ++i) {
+ const CXXBasePathElement& Element = Path[i];
+
+ // Get the layout.
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(Element.Class);
+
+ const CXXBaseSpecifier *BS = Element.Base;
+ assert(!BS->isVirtual() && "Should not see virtual bases here!");
+
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(BS->getType()->getAs<RecordType>()->getDecl());
+
+ // Add the offset.
+ Offset += Layout.getBaseClassOffset(Base) / 8;
+ }
+
+ return Offset;
+}
+
+llvm::Constant *
+CodeGenModule::GetCXXBaseClassOffset(const CXXRecordDecl *ClassDecl,
+ const CXXRecordDecl *BaseClassDecl) {
+ if (ClassDecl == BaseClassDecl)
+ return 0;
+
+ CXXBasePaths Paths(/*FindAmbiguities=*/false,
+ /*RecordPaths=*/true, /*DetectVirtual=*/false);
+ if (!const_cast<CXXRecordDecl *>(ClassDecl)->
+ isDerivedFrom(const_cast<CXXRecordDecl *>(BaseClassDecl), Paths)) {
+ assert(false && "Class must be derived from the passed in base class!");
+ return 0;
+ }
+
+ uint64_t Offset = ComputeNonVirtualBaseClassOffset(getContext(), Paths, 0);
+ if (!Offset)
+ return 0;
+
+ const llvm::Type *PtrDiffTy =
+ Types.ConvertType(getContext().getPointerDiffType());
+
+ return llvm::ConstantInt::get(PtrDiffTy, Offset);
+}
+
+static llvm::Value *GetCXXBaseClassOffset(CodeGenFunction &CGF,
+ llvm::Value *BaseValue,
+ const CXXRecordDecl *ClassDecl,
+ const CXXRecordDecl *BaseClassDecl) {
+ CXXBasePaths Paths(/*FindAmbiguities=*/false,
+ /*RecordPaths=*/true, /*DetectVirtual=*/true);
+ if (!const_cast<CXXRecordDecl *>(ClassDecl)->
+ isDerivedFrom(const_cast<CXXRecordDecl *>(BaseClassDecl), Paths)) {
+ assert(false && "Class must be derived from the passed in base class!");
+ return 0;
+ }
+
+ unsigned Start = 0;
+ llvm::Value *VirtualOffset = 0;
+ if (const RecordType *RT = Paths.getDetectedVirtual()) {
+ const CXXRecordDecl *VBase = cast<CXXRecordDecl>(RT->getDecl());
+
+ VirtualOffset =
+ CGF.GetVirtualCXXBaseClassOffset(BaseValue, ClassDecl, VBase);
+
+ const CXXBasePath &Path = Paths.front();
+ unsigned e = Path.size();
+ for (Start = 0; Start != e; ++Start) {
+ const CXXBasePathElement& Element = Path[Start];
+
+ if (Element.Class == VBase)
+ break;
+ }
+ }
+
+ uint64_t Offset =
+ ComputeNonVirtualBaseClassOffset(CGF.getContext(), Paths, Start);
+
+ if (!Offset)
+ return VirtualOffset;
+
+ const llvm::Type *PtrDiffTy =
+ CGF.ConvertType(CGF.getContext().getPointerDiffType());
+ llvm::Value *NonVirtualOffset = llvm::ConstantInt::get(PtrDiffTy, Offset);
+
+ if (VirtualOffset)
+ return CGF.Builder.CreateAdd(VirtualOffset, NonVirtualOffset);
+
+ return NonVirtualOffset;
+}
+
+llvm::Value *
+CodeGenFunction::GetAddressCXXOfBaseClass(llvm::Value *BaseValue,
+ const CXXRecordDecl *ClassDecl,
+ const CXXRecordDecl *BaseClassDecl,
+ bool NullCheckValue) {
+ QualType BTy =
+ getContext().getCanonicalType(
+ getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(BaseClassDecl)));
+ const llvm::Type *BasePtrTy = llvm::PointerType::getUnqual(ConvertType(BTy));
+
+ if (ClassDecl == BaseClassDecl) {
+ // Just cast back.
+ return Builder.CreateBitCast(BaseValue, BasePtrTy);
+ }
+
+ llvm::BasicBlock *CastNull = 0;
+ llvm::BasicBlock *CastNotNull = 0;
+ llvm::BasicBlock *CastEnd = 0;
+
+ if (NullCheckValue) {
+ CastNull = createBasicBlock("cast.null");
+ CastNotNull = createBasicBlock("cast.notnull");
+ CastEnd = createBasicBlock("cast.end");
+
+ llvm::Value *IsNull =
+ Builder.CreateICmpEQ(BaseValue,
+ llvm::Constant::getNullValue(BaseValue->getType()));
+ Builder.CreateCondBr(IsNull, CastNull, CastNotNull);
+ EmitBlock(CastNotNull);
+ }
+
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
+
+ llvm::Value *Offset =
+ GetCXXBaseClassOffset(*this, BaseValue, ClassDecl, BaseClassDecl);
+
+ if (Offset) {
+ // Apply the offset.
+ BaseValue = Builder.CreateBitCast(BaseValue, Int8PtrTy);
+ BaseValue = Builder.CreateGEP(BaseValue, Offset, "add.ptr");
+ }
+
+ // Cast back.
+ BaseValue = Builder.CreateBitCast(BaseValue, BasePtrTy);
+
+ if (NullCheckValue) {
+ Builder.CreateBr(CastEnd);
+ EmitBlock(CastNull);
+ Builder.CreateBr(CastEnd);
+ EmitBlock(CastEnd);
+
+ llvm::PHINode *PHI = Builder.CreatePHI(BaseValue->getType());
+ PHI->reserveOperandSpace(2);
+ PHI->addIncoming(BaseValue, CastNotNull);
+ PHI->addIncoming(llvm::Constant::getNullValue(BaseValue->getType()),
+ CastNull);
+ BaseValue = PHI;
+ }
+
+ return BaseValue;
+}
diff --git a/lib/CodeGen/CGCXXExpr.cpp b/lib/CodeGen/CGCXXExpr.cpp
new file mode 100644
index 0000000..2d62df6
--- /dev/null
+++ b/lib/CodeGen/CGCXXExpr.cpp
@@ -0,0 +1,304 @@
+//===--- CGCXXExpr.cpp - Emit LLVM Code for C++ 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 dealing with code generation of C++ expressions
+//
+//===----------------------------------------------------------------------===//
+
+#include "CodeGenFunction.h"
+using namespace clang;
+using namespace CodeGen;
+
+static uint64_t CalculateCookiePadding(ASTContext &Ctx, const CXXNewExpr *E) {
+ if (!E->isArray())
+ return 0;
+
+ QualType T = E->getAllocatedType();
+
+ const RecordType *RT = T->getAs<RecordType>();
+ if (!RT)
+ return 0;
+
+ const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
+ if (!RD)
+ return 0;
+
+ // Check if the class has a trivial destructor.
+ if (RD->hasTrivialDestructor()) {
+ // FIXME: Check for a two-argument delete.
+ return 0;
+ }
+
+ // Padding is the maximum of sizeof(size_t) and alignof(T)
+ return std::max(Ctx.getTypeSize(Ctx.getSizeType()),
+ static_cast<uint64_t>(Ctx.getTypeAlign(T))) / 8;
+}
+
+static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
+ const CXXNewExpr *E,
+ llvm::Value *& NumElements) {
+ QualType Type = E->getAllocatedType();
+ uint64_t TypeSizeInBytes = CGF.getContext().getTypeSize(Type) / 8;
+ const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType());
+
+ if (!E->isArray())
+ return llvm::ConstantInt::get(SizeTy, TypeSizeInBytes);
+
+ uint64_t CookiePadding = CalculateCookiePadding(CGF.getContext(), E);
+
+ Expr::EvalResult Result;
+ if (E->getArraySize()->Evaluate(Result, CGF.getContext()) &&
+ !Result.HasSideEffects && Result.Val.isInt()) {
+
+ uint64_t AllocSize =
+ Result.Val.getInt().getZExtValue() * TypeSizeInBytes + CookiePadding;
+
+ NumElements =
+ llvm::ConstantInt::get(SizeTy, Result.Val.getInt().getZExtValue());
+
+ return llvm::ConstantInt::get(SizeTy, AllocSize);
+ }
+
+ // Emit the array size expression.
+ NumElements = CGF.EmitScalarExpr(E->getArraySize());
+
+ // Multiply with the type size.
+ llvm::Value *V =
+ CGF.Builder.CreateMul(NumElements,
+ llvm::ConstantInt::get(SizeTy, TypeSizeInBytes));
+
+ // And add the cookie padding if necessary.
+ if (CookiePadding)
+ V = CGF.Builder.CreateAdd(V, llvm::ConstantInt::get(SizeTy, CookiePadding));
+
+ return V;
+}
+
+static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E,
+ llvm::Value *NewPtr,
+ llvm::Value *NumElements) {
+ QualType AllocType = E->getAllocatedType();
+
+ if (!E->isArray()) {
+ if (CXXConstructorDecl *Ctor = E->getConstructor()) {
+ CGF.EmitCXXConstructorCall(Ctor, Ctor_Complete, NewPtr,
+ E->constructor_arg_begin(),
+ E->constructor_arg_end());
+
+ return;
+ }
+
+ // We have a POD type.
+ if (E->getNumConstructorArgs() == 0)
+ return;
+
+ assert(E->getNumConstructorArgs() == 1 &&
+ "Can only have one argument to initializer of POD type.");
+
+ const Expr *Init = E->getConstructorArg(0);
+
+ if (!CGF.hasAggregateLLVMType(AllocType))
+ CGF.Builder.CreateStore(CGF.EmitScalarExpr(Init), NewPtr);
+ else if (AllocType->isAnyComplexType())
+ CGF.EmitComplexExprIntoAddr(Init, NewPtr,
+ AllocType.isVolatileQualified());
+ else
+ CGF.EmitAggExpr(Init, NewPtr, AllocType.isVolatileQualified());
+ return;
+ }
+
+ if (CXXConstructorDecl *Ctor = E->getConstructor())
+ CGF.EmitCXXAggrConstructorCall(Ctor, NumElements, NewPtr);
+}
+
+llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
+ QualType AllocType = E->getAllocatedType();
+ FunctionDecl *NewFD = E->getOperatorNew();
+ const FunctionProtoType *NewFTy = NewFD->getType()->getAs<FunctionProtoType>();
+
+ CallArgList NewArgs;
+
+ // The allocation size is the first argument.
+ QualType SizeTy = getContext().getSizeType();
+
+ llvm::Value *NumElements = 0;
+ llvm::Value *AllocSize = EmitCXXNewAllocSize(*this, E, NumElements);
+
+ 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(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);
+ }
+
+ if (uint64_t CookiePadding = CalculateCookiePadding(getContext(), E)) {
+ uint64_t CookieOffset =
+ CookiePadding - getContext().getTypeSize(SizeTy) / 8;
+
+ llvm::Value *NumElementsPtr =
+ Builder.CreateConstInBoundsGEP1_64(NewPtr, CookieOffset);
+
+ NumElementsPtr = Builder.CreateBitCast(NumElementsPtr,
+ ConvertType(SizeTy)->getPointerTo());
+ Builder.CreateStore(NumElements, NumElementsPtr);
+
+ // Now add the padding to the new ptr.
+ NewPtr = Builder.CreateConstInBoundsGEP1_64(NewPtr, CookiePadding);
+ }
+
+ NewPtr = Builder.CreateBitCast(NewPtr, ConvertType(E->getType()));
+
+ EmitNewInitializer(*this, E, NewPtr, NumElements);
+
+ 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;
+}
+
+void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) {
+ if (E->isArrayForm()) {
+ ErrorUnsupported(E, "delete[] expression");
+ return;
+ };
+
+ // Get at the argument before we performed the implicit conversion
+ // to void*.
+ const Expr *Arg = E->getArgument();
+ while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
+ if (ICE->getCastKind() != CastExpr::CK_UserDefinedConversion &&
+ ICE->getType()->isVoidPointerType())
+ Arg = ICE->getSubExpr();
+ else
+ break;
+ }
+
+ QualType DeleteTy = Arg->getType()->getAs<PointerType>()->getPointeeType();
+
+ llvm::Value *Ptr = EmitScalarExpr(Arg);
+
+ // Null check the pointer.
+ llvm::BasicBlock *DeleteNotNull = createBasicBlock("delete.notnull");
+ llvm::BasicBlock *DeleteEnd = createBasicBlock("delete.end");
+
+ llvm::Value *IsNull =
+ Builder.CreateICmpEQ(Ptr, llvm::Constant::getNullValue(Ptr->getType()),
+ "isnull");
+
+ Builder.CreateCondBr(IsNull, DeleteEnd, DeleteNotNull);
+ EmitBlock(DeleteNotNull);
+
+ // Call the destructor if necessary.
+ if (const RecordType *RT = DeleteTy->getAs<RecordType>()) {
+ if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
+ if (!RD->hasTrivialDestructor()) {
+ const CXXDestructorDecl *Dtor = RD->getDestructor(getContext());
+ if (Dtor->isVirtual()) {
+ const llvm::Type *Ty =
+ CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(Dtor),
+ /*isVariadic=*/false);
+
+ llvm::Value *Callee = BuildVirtualCall(Dtor, Ptr, Ty);
+ EmitCXXMemberCall(Dtor, Callee, Ptr, 0, 0);
+ } else
+ EmitCXXDestructorCall(Dtor, Dtor_Complete, Ptr);
+ }
+ }
+ }
+
+ // Call delete.
+ FunctionDecl *DeleteFD = E->getOperatorDelete();
+ const FunctionProtoType *DeleteFTy =
+ DeleteFD->getType()->getAs<FunctionProtoType>();
+
+ CallArgList DeleteArgs;
+
+ QualType ArgTy = DeleteFTy->getArgType(0);
+ llvm::Value *DeletePtr = Builder.CreateBitCast(Ptr, ConvertType(ArgTy));
+ DeleteArgs.push_back(std::make_pair(RValue::get(DeletePtr), ArgTy));
+
+ // Emit the call to delete.
+ EmitCall(CGM.getTypes().getFunctionInfo(DeleteFTy->getResultType(),
+ DeleteArgs),
+ CGM.GetAddrOfFunction(DeleteFD),
+ DeleteArgs, DeleteFD);
+
+ EmitBlock(DeleteEnd);
+}
diff --git a/lib/CodeGen/CGCXXTemp.cpp b/lib/CodeGen/CGCXXTemp.cpp
index a6e6d11..4768556 100644
--- a/lib/CodeGen/CGCXXTemp.cpp
+++ b/lib/CodeGen/CGCXXTemp.cpp
@@ -15,29 +15,29 @@
using namespace clang;
using namespace CodeGen;
-void CodeGenFunction::PushCXXTemporary(const CXXTemporary *Temporary,
+void CodeGenFunction::PushCXXTemporary(const CXXTemporary *Temporary,
llvm::Value *Ptr) {
llvm::BasicBlock *DtorBlock = createBasicBlock("temp.dtor");
-
+
llvm::Value *CondPtr = 0;
-
- // Check if temporaries need to be conditional. If so, we'll create a
- // condition boolean, initialize it to 0 and
+
+ // Check if temporaries need to be conditional. If so, we'll create a
+ // condition boolean, initialize it to 0 and
if (!ConditionalTempDestructionStack.empty()) {
- CondPtr = CreateTempAlloca(llvm::Type::Int1Ty, "cond");
-
+ CondPtr = CreateTempAlloca(llvm::Type::getInt1Ty(VMContext), "cond");
+
// Initialize it to false. This initialization takes place right after
// the alloca insert point.
- llvm::StoreInst *SI =
- new llvm::StoreInst(llvm::ConstantInt::getFalse(), CondPtr);
+ llvm::StoreInst *SI =
+ new llvm::StoreInst(llvm::ConstantInt::getFalse(VMContext), CondPtr);
llvm::BasicBlock *Block = AllocaInsertPt->getParent();
Block->getInstList().insertAfter((llvm::Instruction *)AllocaInsertPt, SI);
// Now set it to true.
- Builder.CreateStore(llvm::ConstantInt::getTrue(), CondPtr);
+ Builder.CreateStore(llvm::ConstantInt::getTrue(VMContext), CondPtr);
}
-
- LiveTemporaries.push_back(CXXLiveTemporaryInfo(Temporary, Ptr, DtorBlock,
+
+ LiveTemporaries.push_back(CXXLiveTemporaryInfo(Temporary, Ptr, DtorBlock,
CondPtr));
PushCleanupBlock(DtorBlock);
@@ -45,16 +45,22 @@ void CodeGenFunction::PushCXXTemporary(const CXXTemporary *Temporary,
void CodeGenFunction::PopCXXTemporary() {
const CXXLiveTemporaryInfo& Info = LiveTemporaries.back();
-
+
CleanupBlockInfo CleanupInfo = PopCleanupBlock();
- assert(CleanupInfo.CleanupBlock == Info.DtorBlock &&
+ assert(CleanupInfo.CleanupBlock == Info.DtorBlock &&
"Cleanup block mismatch!");
- assert(!CleanupInfo.SwitchBlock &&
+ assert(!CleanupInfo.SwitchBlock &&
"Should not have a switch block for temporary cleanup!");
- assert(!CleanupInfo.EndBlock &&
+ assert(!CleanupInfo.EndBlock &&
"Should not have an end block for temporary cleanup!");
-
- EmitBlock(Info.DtorBlock);
+
+ llvm::BasicBlock *CurBB = Builder.GetInsertBlock();
+ if (CurBB && !CurBB->getTerminator() &&
+ Info.DtorBlock->getNumUses() == 0) {
+ CurBB->getInstList().splice(CurBB->end(), Info.DtorBlock->getInstList());
+ delete Info.DtorBlock;
+ } else
+ EmitBlock(Info.DtorBlock);
llvm::BasicBlock *CondEnd = 0;
@@ -63,52 +69,80 @@ void CodeGenFunction::PopCXXTemporary() {
if (Info.CondPtr) {
llvm::BasicBlock *CondBlock = createBasicBlock("cond.dtor.call");
CondEnd = createBasicBlock("cond.dtor.end");
-
+
llvm::Value *Cond = Builder.CreateLoad(Info.CondPtr);
Builder.CreateCondBr(Cond, CondBlock, CondEnd);
EmitBlock(CondBlock);
}
-
+
EmitCXXDestructorCall(Info.Temporary->getDestructor(),
Dtor_Complete, Info.ThisPtr);
if (CondEnd) {
// Reset the condition. to false.
- Builder.CreateStore(llvm::ConstantInt::getFalse(), Info.CondPtr);
+ Builder.CreateStore(llvm::ConstantInt::getFalse(VMContext), Info.CondPtr);
EmitBlock(CondEnd);
}
-
+
LiveTemporaries.pop_back();
}
RValue
CodeGenFunction::EmitCXXExprWithTemporaries(const CXXExprWithTemporaries *E,
llvm::Value *AggLoc,
- bool isAggLocVolatile) {
+ bool IsAggLocVolatile,
+ bool IsInitializer) {
// If we shouldn't destroy the temporaries, just emit the
// child expression.
if (!E->shouldDestroyTemporaries())
- return EmitAnyExpr(E->getSubExpr(), AggLoc, isAggLocVolatile);
+ return EmitAnyExpr(E->getSubExpr(), AggLoc, IsAggLocVolatile,
+ /*IgnoreResult=*/false, IsInitializer);
// Keep track of the current cleanup stack depth.
size_t CleanupStackDepth = CleanupEntries.size();
(void) CleanupStackDepth;
unsigned OldNumLiveTemporaries = LiveTemporaries.size();
-
- RValue RV = EmitAnyExpr(E->getSubExpr(), AggLoc, isAggLocVolatile);
-
+
+ RValue RV = EmitAnyExpr(E->getSubExpr(), AggLoc, IsAggLocVolatile,
+ /*IgnoreResult=*/false, IsInitializer);
+
// Pop temporaries.
while (LiveTemporaries.size() > OldNumLiveTemporaries)
PopCXXTemporary();
-
+
assert(CleanupEntries.size() == CleanupStackDepth &&
"Cleanup size mismatch!");
-
+
return RV;
}
-void
+LValue CodeGenFunction::EmitCXXExprWithTemporariesLValue(
+ const CXXExprWithTemporaries *E) {
+ // If we shouldn't destroy the temporaries, just emit the
+ // child expression.
+ if (!E->shouldDestroyTemporaries())
+ return EmitLValue(E->getSubExpr());
+
+ // Keep track of the current cleanup stack depth.
+ size_t CleanupStackDepth = CleanupEntries.size();
+ (void) CleanupStackDepth;
+
+ unsigned OldNumLiveTemporaries = LiveTemporaries.size();
+
+ LValue LV = EmitLValue(E->getSubExpr());
+
+ // Pop temporaries.
+ while (LiveTemporaries.size() > OldNumLiveTemporaries)
+ PopCXXTemporary();
+
+ assert(CleanupEntries.size() == CleanupStackDepth &&
+ "Cleanup size mismatch!");
+
+ return LV;
+}
+
+void
CodeGenFunction::PushConditionalTempDestruction() {
// Store the current number of live temporaries.
ConditionalTempDestructionStack.push_back(LiveTemporaries.size());
@@ -117,13 +151,13 @@ CodeGenFunction::PushConditionalTempDestruction() {
void CodeGenFunction::PopConditionalTempDestruction() {
size_t NumLiveTemporaries = ConditionalTempDestructionStack.back();
ConditionalTempDestructionStack.pop_back();
-
+
// Pop temporaries.
while (LiveTemporaries.size() > NumLiveTemporaries) {
- assert(LiveTemporaries.back().CondPtr &&
+ assert(LiveTemporaries.back().CondPtr &&
"Conditional temporary must have a cond ptr!");
PopCXXTemporary();
- }
+ }
}
-
+
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index 97391bc..bad166f 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -33,19 +33,49 @@ using namespace CodeGen;
// FIXME: Use iterator and sidestep silly type array creation.
-const
+const
CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionNoProtoType *FTNP) {
- return getFunctionInfo(FTNP->getResultType(),
- llvm::SmallVector<QualType, 16>());
+ // FIXME: Set calling convention correctly, it needs to be associated with the
+ // type somehow.
+ return getFunctionInfo(FTNP->getResultType(),
+ llvm::SmallVector<QualType, 16>(), 0);
}
-const
+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);
+ // FIXME: Set calling convention correctly, it needs to be associated with the
+ // type somehow.
+ return getFunctionInfo(FTP->getResultType(), ArgTys, 0);
+}
+
+static unsigned getCallingConventionForDecl(const Decl *D) {
+ // Set the appropriate calling convention for the Function.
+ if (D->hasAttr<StdCallAttr>())
+ return llvm::CallingConv::X86_StdCall;
+
+ if (D->hasAttr<FastCallAttr>())
+ return llvm::CallingConv::X86_FastCall;
+
+ return llvm::CallingConv::C;
+}
+
+const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXRecordDecl *RD,
+ const FunctionProtoType *FTP) {
+ llvm::SmallVector<QualType, 16> ArgTys;
+
+ // Add the 'this' pointer.
+ ArgTys.push_back(Context.getPointerType(Context.getTagDeclType(RD)));
+
+ for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i)
+ ArgTys.push_back(FTP->getArgType(i));
+
+ // FIXME: Set calling convention correctly, it needs to be associated with the
+ // type somehow.
+ return getFunctionInfo(FTP->getResultType(), ArgTys, 0);
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXMethodDecl *MD) {
@@ -53,22 +83,32 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXMethodDecl *MD) {
// 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();
+
+ const FunctionProtoType *FTP = MD->getType()->getAs<FunctionProtoType>();
for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i)
ArgTys.push_back(FTP->getArgType(i));
- return getFunctionInfo(FTP->getResultType(), ArgTys);
+ return getFunctionInfo(FTP->getResultType(), ArgTys,
+ getCallingConventionForDecl(MD));
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionDecl *FD) {
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD))
if (MD->isInstance())
return getFunctionInfo(MD);
+
+ unsigned CallingConvention = getCallingConventionForDecl(FD);
+ const FunctionType *FTy = FD->getType()->getAs<FunctionType>();
+ if (const FunctionNoProtoType *FNTP = dyn_cast<FunctionNoProtoType>(FTy))
+ return getFunctionInfo(FNTP->getResultType(),
+ llvm::SmallVector<QualType, 16>(),
+ CallingConvention);
- const FunctionType *FTy = FD->getType()->getAsFunctionType();
- if (const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FTy))
- return getFunctionInfo(FTP);
- return getFunctionInfo(cast<FunctionNoProtoType>(FTy));
+ const FunctionProtoType *FPT = cast<FunctionProtoType>(FTy);
+ llvm::SmallVector<QualType, 16> ArgTys;
+ // FIXME: Kill copy.
+ for (unsigned i = 0, e = FPT->getNumArgs(); i != e; ++i)
+ ArgTys.push_back(FPT->getArgType(i));
+ return getFunctionInfo(FPT->getResultType(), ArgTys, CallingConvention);
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const ObjCMethodDecl *MD) {
@@ -79,34 +119,39 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const ObjCMethodDecl *MD) {
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);
+ return getFunctionInfo(MD->getResultType(), ArgTys,
+ getCallingConventionForDecl(MD));
}
-const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy,
- const CallArgList &Args) {
+const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy,
+ const CallArgList &Args,
+ unsigned CallingConvention){
// FIXME: Kill copy.
llvm::SmallVector<QualType, 16> ArgTys;
- for (CallArgList::const_iterator i = Args.begin(), e = Args.end();
+ for (CallArgList::const_iterator i = Args.begin(), e = Args.end();
i != e; ++i)
ArgTys.push_back(i->second);
- return getFunctionInfo(ResTy, ArgTys);
+ return getFunctionInfo(ResTy, ArgTys, CallingConvention);
}
-const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy,
- const FunctionArgList &Args) {
+const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy,
+ const FunctionArgList &Args,
+ unsigned CallingConvention){
// FIXME: Kill copy.
llvm::SmallVector<QualType, 16> ArgTys;
- for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end();
+ for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end();
i != e; ++i)
ArgTys.push_back(i->second);
- return getFunctionInfo(ResTy, ArgTys);
+ return getFunctionInfo(ResTy, ArgTys, CallingConvention);
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy,
- const llvm::SmallVector<QualType, 16> &ArgTys) {
+ const llvm::SmallVector<QualType, 16> &ArgTys,
+ unsigned CallingConvention){
// Lookup or create unique function info.
llvm::FoldingSetNodeID ID;
- CGFunctionInfo::Profile(ID, ResTy, ArgTys.begin(), ArgTys.end());
+ CGFunctionInfo::Profile(ID, CallingConvention, ResTy,
+ ArgTys.begin(), ArgTys.end());
void *InsertPos = 0;
CGFunctionInfo *FI = FunctionInfos.FindNodeOrInsertPos(ID, InsertPos);
@@ -114,17 +159,21 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy,
return *FI;
// Construct the function info.
- FI = new CGFunctionInfo(ResTy, ArgTys);
+ FI = new CGFunctionInfo(CallingConvention, ResTy, ArgTys);
FunctionInfos.InsertNode(FI, InsertPos);
// Compute ABI information.
- getABIInfo().computeInfo(*FI, getContext());
+ getABIInfo().computeInfo(*FI, getContext(), TheModule.getContext());
return *FI;
}
-CGFunctionInfo::CGFunctionInfo(QualType ResTy,
- const llvm::SmallVector<QualType, 16> &ArgTys) {
+CGFunctionInfo::CGFunctionInfo(unsigned _CallingConvention,
+ QualType ResTy,
+ const llvm::SmallVector<QualType, 16> &ArgTys)
+ : CallingConvention(_CallingConvention),
+ EffectiveCallingConvention(_CallingConvention)
+{
NumArgs = ArgTys.size();
Args = new ArgInfo[1 + NumArgs];
Args[0].type = ResTy;
@@ -134,20 +183,20 @@ CGFunctionInfo::CGFunctionInfo(QualType ResTy,
/***/
-void CodeGenTypes::GetExpandedTypes(QualType Ty,
+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() &&
+ assert(!RD->hasFlexibleArrayMember() &&
"Cannot expand structure with flexible array.");
-
+
for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
i != e; ++i) {
const FieldDecl *FD = *i;
- assert(!FD->isBitField() &&
+ assert(!FD->isBitField() &&
"Cannot expand structure with bit-field members.");
-
+
QualType FT = FD->getType();
if (CodeGenFunction::hasAggregateLLVMType(FT)) {
GetExpandedTypes(FT, ArgTys);
@@ -157,19 +206,19 @@ void CodeGenTypes::GetExpandedTypes(QualType Ty,
}
}
-llvm::Function::arg_iterator
+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.");
+ assert(LV.isSimple() &&
+ "Unexpected non-simple lvalue during struct expansion.");
llvm::Value *Addr = LV.getAddress();
for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
i != e; ++i) {
- FieldDecl *FD = *i;
+ FieldDecl *FD = *i;
QualType FT = FD->getType();
// FIXME: What are the right qualifiers here?
@@ -185,8 +234,8 @@ CodeGenFunction::ExpandTypeFromArgs(QualType Ty, LValue LV,
return AI;
}
-void
-CodeGenFunction::ExpandTypeToArgs(QualType Ty, RValue RV,
+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.");
@@ -196,16 +245,16 @@ CodeGenFunction::ExpandTypeToArgs(QualType Ty, RValue RV,
llvm::Value *Addr = RV.getAggregateAddr();
for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
i != e; ++i) {
- FieldDecl *FD = *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() &&
+ assert(RV.isScalar() &&
"Unexpected non-scalar rvalue during struct expansion.");
Args.push_back(RV.getScalarVal());
}
@@ -221,7 +270,7 @@ CodeGenFunction::ExpandTypeToArgs(QualType Ty, RValue RV,
static llvm::Value *CreateCoercedLoad(llvm::Value *SrcPtr,
const llvm::Type *Ty,
CodeGenFunction &CGF) {
- const llvm::Type *SrcTy =
+ 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);
@@ -244,9 +293,9 @@ static llvm::Value *CreateCoercedLoad(llvm::Value *SrcPtr,
// Otherwise do coercion through memory. This is stupid, but
// simple.
llvm::Value *Tmp = CGF.CreateTempAlloca(Ty);
- llvm::Value *Casted =
+ llvm::Value *Casted =
CGF.Builder.CreateBitCast(Tmp, llvm::PointerType::getUnqual(SrcTy));
- llvm::StoreInst *Store =
+ llvm::StoreInst *Store =
CGF.Builder.CreateStore(CGF.Builder.CreateLoad(SrcPtr), Casted);
// FIXME: Use better alignment / avoid requiring aligned store.
Store->setAlignment(1);
@@ -263,7 +312,7 @@ static void CreateCoercedStore(llvm::Value *Src,
llvm::Value *DstPtr,
CodeGenFunction &CGF) {
const llvm::Type *SrcTy = Src->getType();
- const llvm::Type *DstTy =
+ const llvm::Type *DstTy =
cast<llvm::PointerType>(DstPtr->getType())->getElementType();
uint64_t SrcSize = CGF.CGM.getTargetData().getTypeAllocSize(SrcTy);
@@ -287,7 +336,7 @@ static void CreateCoercedStore(llvm::Value *Src,
// to that information.
llvm::Value *Tmp = CGF.CreateTempAlloca(SrcTy);
CGF.Builder.CreateStore(Src, Tmp);
- llvm::Value *Casted =
+ 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.
@@ -321,25 +370,25 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool IsVariadic) {
case ABIArgInfo::Indirect: {
assert(!RetAI.getIndirectAlign() && "Align unused on indirect return.");
- ResultType = llvm::Type::VoidTy;
+ ResultType = llvm::Type::getVoidTy(getLLVMContext());
const llvm::Type *STy = ConvertType(RetTy);
ArgTys.push_back(llvm::PointerType::get(STy, RetTy.getAddressSpace()));
break;
}
case ABIArgInfo::Ignore:
- ResultType = llvm::Type::VoidTy;
+ ResultType = llvm::Type::getVoidTy(getLLVMContext());
break;
case ABIArgInfo::Coerce:
ResultType = RetAI.getCoerceToType();
break;
}
-
- for (CGFunctionInfo::const_arg_iterator it = FI.arg_begin(),
+
+ 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;
@@ -359,7 +408,7 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool IsVariadic) {
case ABIArgInfo::Direct:
ArgTys.push_back(ConvertType(it->type));
break;
-
+
case ABIArgInfo::Expand:
GetExpandedTypes(it->type, ArgTys);
break;
@@ -371,10 +420,13 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool IsVariadic) {
void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
const Decl *TargetDecl,
- AttributeListType &PAL) {
+ AttributeListType &PAL,
+ unsigned &CallingConv) {
unsigned FuncAttrs = 0;
unsigned RetAttrs = 0;
+ CallingConv = FI.getEffectiveCallingConvention();
+
// FIXME: handle sseregparm someday...
if (TargetDecl) {
if (TargetDecl->hasAttr<NoThrowAttr>())
@@ -385,6 +437,8 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
FuncAttrs |= llvm::Attribute::ReadNone;
else if (TargetDecl->hasAttr<PureAttr>())
FuncAttrs |= llvm::Attribute::ReadOnly;
+ if (TargetDecl->hasAttr<MallocAttr>())
+ RetAttrs |= llvm::Attribute::NoAlias;
}
if (CompileOpts.DisableRedZone)
@@ -412,7 +466,7 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
break;
case ABIArgInfo::Indirect:
- PAL.push_back(llvm::AttributeWithIndex::get(Index,
+ PAL.push_back(llvm::AttributeWithIndex::get(Index,
llvm::Attribute::StructRet |
llvm::Attribute::NoAlias));
++Index;
@@ -426,7 +480,7 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
break;
case ABIArgInfo::Expand:
- assert(0 && "Invalid ABI kind for return argument");
+ assert(0 && "Invalid ABI kind for return argument");
}
if (RetAttrs)
@@ -437,12 +491,12 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
// register variable.
signed RegParm = 0;
if (TargetDecl)
- if (const RegparmAttr *RegParmAttr
+ 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(),
+ 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;
@@ -453,7 +507,9 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
break;
case ABIArgInfo::Indirect:
- Attributes |= llvm::Attribute::ByVal;
+ if (AI.getIndirectByVal())
+ Attributes |= llvm::Attribute::ByVal;
+
Attributes |=
llvm::Attribute::constructAlignmentFromInt(AI.getIndirectAlign());
// byval disables readnone and readonly.
@@ -481,10 +537,10 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
case ABIArgInfo::Ignore:
// Skip increment, no matching LLVM parameter.
- continue;
+ continue;
case ABIArgInfo::Expand: {
- std::vector<const llvm::Type*> Tys;
+ 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.
@@ -493,7 +549,7 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
continue;
}
}
-
+
if (Attributes)
PAL.push_back(llvm::AttributeWithIndex::get(Index, Attributes));
++Index;
@@ -505,18 +561,31 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
llvm::Function *Fn,
const FunctionArgList &Args) {
+ // If this is an implicit-return-zero function, go ahead and
+ // initialize the return value. TODO: it might be nice to have
+ // a more general mechanism for this that didn't require synthesized
+ // return statements.
+ if (const FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(CurFuncDecl)) {
+ if (FD->hasImplicitReturnZero()) {
+ QualType RetTy = FD->getResultType().getUnqualifiedType();
+ const llvm::Type* LLVMTy = CGM.getTypes().ConvertType(RetTy);
+ llvm::Constant* Zero = llvm::Constant::getNullValue(LLVMTy);
+ Builder.CreateStore(Zero, ReturnValue);
+ }
+ }
+
// 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();
@@ -541,7 +610,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
V = EmitScalarConversion(V, Ty, Arg->getType());
}
}
- EmitParmDecl(*Arg, V);
+ EmitParmDecl(*Arg, V);
break;
}
@@ -565,36 +634,36 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
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),
+ 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);
+ llvm::Function::arg_iterator End =
+ ExpandTypeFromArgs(Ty, LValue::MakeAddr(Temp, Qualifiers()), 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));
+ AI->setName(Name + "." + llvm::Twine(Index));
continue;
}
case ABIArgInfo::Ignore:
// Initialize the local variable appropriately.
- if (hasAggregateLLVMType(Ty)) {
+ if (hasAggregateLLVMType(Ty)) {
EmitParmDecl(*Arg, CreateTempAlloca(ConvertTypeForMem(Ty)));
} else {
EmitParmDecl(*Arg, llvm::UndefValue::get(ConvertType(Arg->getType())));
}
-
+
// Skip increment, no matching LLVM parameter.
- continue;
+ continue;
case ABIArgInfo::Coerce: {
assert(AI != Fn->arg_end() && "Argument mismatch!");
@@ -653,16 +722,16 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
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");
+ assert(0 && "Invalid ABI kind for return argument");
}
}
-
+
if (RV) {
Builder.CreateRet(RV);
} else {
@@ -673,12 +742,12 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
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,
+ llvm::Value *Callee,
const CallArgList &CallArgs,
const Decl *TargetDecl) {
// FIXME: We no longer need the types from CallArgs; lift up and simplify.
@@ -688,17 +757,17 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
// location that we would like to return into.
QualType RetTy = CallInfo.getReturnType();
const ABIArgInfo &RetAI = CallInfo.getReturnInfo();
-
-
+
+
// If the call returns a temporary with struct return, create a temporary
// alloca to hold the result.
if (CGM.ReturnTypeUsesSret(CallInfo))
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();
+ 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;
@@ -711,7 +780,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
if (RV.isScalar())
EmitStoreOfScalar(RV.getScalarVal(), Args.back(), false, I->second);
else
- StoreComplexToAddr(RV.getComplexVal(), Args.back(), false);
+ StoreComplexToAddr(RV.getComplexVal(), Args.back(), false);
} else {
Args.push_back(RV.getAggregateAddr());
}
@@ -730,7 +799,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
Args.push_back(Builder.CreateLoad(RV.getAggregateAddr()));
}
break;
-
+
case ABIArgInfo::Ignore:
break;
@@ -743,9 +812,9 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
} else if (RV.isComplex()) {
SrcPtr = CreateTempAlloca(ConvertTypeForMem(I->second), "coerce");
StoreComplexToAddr(RV.getComplexVal(), SrcPtr, false);
- } else
+ } else
SrcPtr = RV.getAggregateAddr();
- Args.push_back(CreateCoercedLoad(SrcPtr, ArgInfo.getCoerceToType(),
+ Args.push_back(CreateCoercedLoad(SrcPtr, ArgInfo.getCoerceToType(),
*this));
break;
}
@@ -755,7 +824,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
break;
}
}
-
+
// If the callee is a bitcast of a function to a varargs pointer to function
// type, check to see if we can remove the bitcast. This handles some cases
// with unprototyped functions.
@@ -765,7 +834,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
const llvm::FunctionType *CurFT =
cast<llvm::FunctionType>(CurPT->getElementType());
const llvm::FunctionType *ActualFT = CalleeF->getFunctionType();
-
+
if (CE->getOpcode() == llvm::Instruction::BitCast &&
ActualFT->getReturnType() == CurFT->getReturnType() &&
ActualFT->getNumParams() == CurFT->getNumParams() &&
@@ -776,7 +845,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
ArgsMatch = false;
break;
}
-
+
// Strip the cast if we can get away with it. This is a nice cleanup,
// but also allows us to inline the function at -O0 if it is marked
// always_inline.
@@ -784,28 +853,27 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
Callee = CalleeF;
}
}
-
+
llvm::BasicBlock *InvokeDest = getInvokeDest();
+ unsigned CallingConv;
CodeGen::AttributeListType AttributeList;
- CGM.ConstructAttributeList(CallInfo, TargetDecl, AttributeList);
+ CGM.ConstructAttributeList(CallInfo, TargetDecl, AttributeList, CallingConv);
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,
+ 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());
+ CS.setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv));
// If the call doesn't return, finish the basic block and clear the
// insertion point; this allows the rest of IRgen to discard
@@ -813,18 +881,18 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
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)
+ if (Builder.isNamePreserving() && !CI->getType()->isVoidTy())
CI->setName("call");
switch (RetAI.getKind()) {
@@ -866,7 +934,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
}
case ABIArgInfo::Expand:
- assert(0 && "Invalid ABI kind for return argument");
+ assert(0 && "Invalid ABI kind for return argument");
}
assert(0 && "Unhandled ABIArgInfo::Kind");
diff --git a/lib/CodeGen/CGCall.h b/lib/CodeGen/CGCall.h
index daf6f00..ebf801d 100644
--- a/lib/CodeGen/CGCall.h
+++ b/lib/CodeGen/CGCall.h
@@ -49,9 +49,9 @@ namespace CodeGen {
/// 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>,
+ 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 {
@@ -60,6 +60,14 @@ namespace CodeGen {
ABIArgInfo info;
};
+ /// The LLVM::CallingConv to use for this function (as specified by the
+ /// user).
+ unsigned CallingConvention;
+
+ /// The LLVM::CallingConv to actually use for this function, which may
+ /// depend on the ABI.
+ unsigned EffectiveCallingConvention;
+
unsigned NumArgs;
ArgInfo *Args;
@@ -67,7 +75,8 @@ namespace CodeGen {
typedef const ArgInfo *const_arg_iterator;
typedef ArgInfo *arg_iterator;
- CGFunctionInfo(QualType ResTy,
+ CGFunctionInfo(unsigned CallingConvention,
+ QualType ResTy,
const llvm::SmallVector<QualType, 16> &ArgTys);
~CGFunctionInfo() { delete[] Args; }
@@ -78,21 +87,37 @@ namespace CodeGen {
unsigned arg_size() const { return NumArgs; }
+ /// getCallingConvention - Return the user specified calling
+ /// convention.
+ unsigned getCallingConvention() const { return CallingConvention; }
+
+ /// getEffectiveCallingConvention - Return the actual calling convention to
+ /// use, which may depend on the ABI.
+ unsigned getEffectiveCallingConvention() const {
+ return EffectiveCallingConvention;
+ }
+ void setEffectiveCallingConvention(unsigned Value) {
+ EffectiveCallingConvention = Value;
+ }
+
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) {
+ ID.AddInteger(getCallingConvention());
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,
+ static void Profile(llvm::FoldingSetNodeID &ID,
+ unsigned CallingConvention,
QualType ResTy,
Iterator begin,
Iterator end) {
+ ID.AddInteger(CallingConvention);
ResTy.Profile(ID);
for (; begin != end; ++begin)
begin->Profile(ID);
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 2bf8a22..4c62420 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "CGDebugInfo.h"
+#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
@@ -19,6 +20,7 @@
#include "clang/AST/RecordLayout.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
+#include "clang/Basic/Version.h"
#include "clang/Frontend/CompileOptions.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
@@ -47,6 +49,22 @@ void CGDebugInfo::setLocation(SourceLocation Loc) {
CurLoc = M->getContext().getSourceManager().getInstantiationLoc(Loc);
}
+/// getContext - Get context info for the decl.
+llvm::DIDescriptor CGDebugInfo::getContext(const VarDecl *Decl,
+ llvm::DIDescriptor &CompileUnit) {
+ if (Decl->isFileVarDecl())
+ return CompileUnit;
+ if (Decl->getDeclContext()->isFunctionOrMethod()) {
+ // Find the last subprogram in region stack.
+ for (unsigned RI = RegionStack.size(), RE = 0; RI != RE; --RI) {
+ llvm::DIDescriptor R = RegionStack[RI - 1];
+ if (R.isSubprogram())
+ return R;
+ }
+ }
+ return CompileUnit;
+}
+
/// 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) {
@@ -59,7 +77,7 @@ llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation 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;
@@ -104,7 +122,11 @@ llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) {
LangTag = llvm::dwarf::DW_LANG_C89;
}
- std::string Producer = "clang 1.0";// FIXME: clang version.
+ std::string Producer =
+#ifdef CLANG_VENDOR
+ CLANG_VENDOR
+#endif
+ "clang " CLANG_VERSION_STRING;
bool isOptimized = LO.Optimize;
const char *Flags = ""; // FIXME: Encode command line options.
@@ -112,10 +134,10 @@ llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) {
unsigned RuntimeVers = 0;
if (LO.ObjC1)
RuntimeVers = LO.ObjCNonFragileABI ? 2 : 1;
-
+
// Create new compile unit.
return Unit = DebugFactory.CreateCompileUnit(LangTag, AbsFileName.getLast(),
- AbsFileName.getDirname(),
+ AbsFileName.getDirname(),
Producer, isMain, isOptimized,
Flags, RuntimeVers);
}
@@ -143,14 +165,15 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT,
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::LongDouble:
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,
+
+ return DebugFactory.CreateBasicType(Unit,
BT->getName(M->getContext().getLangOptions()),
Unit, 0, Size, Align,
Offset, /*flags*/ 0, Encoding);
@@ -162,52 +185,72 @@ llvm::DIType CGDebugInfo::CreateType(const ComplexType *Ty,
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
+/// CreateCVRType - Get the qualified type from the cache or create
/// a new one if necessary.
-llvm::DIType CGDebugInfo::CreateCVRType(QualType Ty, llvm::DICompileUnit Unit) {
+llvm::DIType CGDebugInfo::CreateQualifiedType(QualType Ty, llvm::DICompileUnit Unit) {
+ QualifierCollector Qc;
+ const Type *T = Qc.strip(Ty);
+
+ // Ignore these qualifiers for now.
+ Qc.removeObjCGCAttr();
+ Qc.removeAddressSpace();
+
// We will create one Derived type for one qualifier and recurse to handle any
// additional ones.
- llvm::DIType FromTy;
unsigned Tag;
- if (Ty.isConstQualified()) {
+ if (Qc.hasConst()) {
Tag = llvm::dwarf::DW_TAG_const_type;
- Ty.removeConst();
- FromTy = getOrCreateType(Ty, Unit);
- } else if (Ty.isVolatileQualified()) {
+ Qc.removeConst();
+ } else if (Qc.hasVolatile()) {
Tag = llvm::dwarf::DW_TAG_volatile_type;
- Ty.removeVolatile();
- FromTy = getOrCreateType(Ty, Unit);
- } else {
- assert(Ty.isRestrictQualified() && "Unknown type qualifier for debug info");
+ Qc.removeVolatile();
+ } else if (Qc.hasRestrict()) {
Tag = llvm::dwarf::DW_TAG_restrict_type;
- Ty.removeRestrict();
- FromTy = getOrCreateType(Ty, Unit);
+ Qc.removeRestrict();
+ } else {
+ assert(Qc.empty() && "Unknown type qualifier for debug info");
+ return getOrCreateType(QualType(T, 0), Unit);
}
-
+
+ llvm::DIType FromTy = getOrCreateType(Qc.apply(T), 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 ObjCObjectPointerType *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 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);
@@ -258,14 +301,16 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
Elements = DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size());
EltTys.clear();
+ unsigned Flags = llvm::DIType::FlagAppleBlock;
+
EltTy = DebugFactory.CreateCompositeType(Tag, Unit, "__block_descriptor",
- DefUnit, 0, FieldOffset, 0, 0, 0,
+ DefUnit, 0, FieldOffset, 0, 0, Flags,
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);
@@ -329,9 +374,9 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
Elements = DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size());
EltTy = DebugFactory.CreateCompositeType(Tag, Unit, "__block_literal_generic",
- DefUnit, 0, FieldOffset, 0, 0, 0,
+ DefUnit, 0, FieldOffset, 0, 0, Flags,
llvm::DIType(), Elements);
-
+
BlockLiteralGenericSet = true;
BlockLiteralGeneric
= DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_pointer_type, Unit,
@@ -345,7 +390,7 @@ llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty,
// 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();
@@ -366,7 +411,7 @@ llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty,
// 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)) {
@@ -378,7 +423,7 @@ llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty,
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,
@@ -389,7 +434,7 @@ llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty,
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;
@@ -412,24 +457,24 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
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 =
+ llvm::DICompositeType 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;
+ TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl.getNode();
// Convert all the elements.
llvm::SmallVector<llvm::DIDescriptor, 16> EltTys;
@@ -438,7 +483,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
unsigned FieldNo = 0;
for (RecordDecl::field_iterator I = Decl->field_begin(),
- E = Decl->field_end();
+ E = Decl->field_end();
I != E; ++I, ++FieldNo) {
FieldDecl *Field = *I;
llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit);
@@ -454,7 +499,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
PresumedLoc PLoc = SM.getPresumedLoc(FieldDefLoc);
llvm::DICompileUnit FieldDefUnit;
unsigned FieldLine = 0;
-
+
if (!PLoc.isInvalid()) {
FieldDefUnit = getOrCreateCompileUnit(FieldDefLoc);
FieldLine = PLoc.getLine();
@@ -464,18 +509,18 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
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);
-
+ 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.
@@ -485,23 +530,25 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
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 =
+
+ llvm::DICompositeType RealDecl =
DebugFactory.CreateCompositeType(Tag, Unit, Name, DefUnit, Line, Size,
Align, 0, 0, llvm::DIType(), Elements);
+ // Update TypeCache.
+ TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = RealDecl.getNode();
+
// 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();
-
+ FwdDecl.replaceAllUsesWith(RealDecl);
+
return RealDecl;
}
@@ -509,7 +556,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
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();
@@ -520,7 +567,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation());
unsigned Line = PLoc.isInvalid() ? 0 : PLoc.getLine();
-
+
unsigned RuntimeLang = DefUnit.getLanguage();
// To handle recursive interface, we
@@ -529,27 +576,27 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
// 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 =
+ llvm::DICompositeType 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;
+ TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl.getNode();
// Convert all the elements.
llvm::SmallVector<llvm::DIDescriptor, 16> EltTys;
ObjCInterfaceDecl *SClass = Decl->getSuperClass();
if (SClass) {
- llvm::DIType SClassTy =
+ llvm::DIType SClassTy =
getOrCreateType(M->getContext().getObjCInterfaceType(SClass), Unit);
- llvm::DIType InhTag =
+ llvm::DIType InhTag =
DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_inheritance,
Unit, "", llvm::DICompileUnit(), 0, 0, 0,
0 /* offset */, 0, SClassTy);
@@ -576,13 +623,13 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
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();
@@ -592,14 +639,14 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
FieldAlign = M->getContext().getTypeAlign(FType);
}
- uint64_t FieldOffset = RL.getFieldOffset(FieldNo);
-
+ 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.
@@ -609,24 +656,26 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
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 =
+
+ llvm::DICompositeType RealDecl =
DebugFactory.CreateCompositeType(Tag, Unit, Name, DefUnit, Line, Size,
Align, 0, 0, llvm::DIType(), Elements,
RuntimeLang);
+ // Update TypeCache.
+ TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = RealDecl.getNode();
+
// 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();
-
+ FwdDecl.replaceAllUsesWith(RealDecl);
+
return RealDecl;
}
@@ -637,13 +686,13 @@ llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty,
llvm::SmallVector<llvm::DIDescriptor, 32> Enumerators;
// Create DIEnumerator elements for each enumerator.
- for (EnumDecl::enumerator_iterator
+ for (EnumDecl::enumerator_iterator
Enum = Decl->enumerator_begin(), EnumEnd = Decl->enumerator_end();
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());
@@ -655,7 +704,7 @@ llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty,
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;
@@ -663,7 +712,7 @@ llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty,
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,
@@ -676,7 +725,7 @@ llvm::DIType CGDebugInfo::CreateType(const TagType *Ty,
return CreateType(RT, Unit);
else if (const EnumType *ET = dyn_cast<EnumType>(Ty))
return CreateType(ET, Unit);
-
+
return llvm::DIType();
}
@@ -684,8 +733,8 @@ 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;
@@ -699,7 +748,7 @@ llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty,
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?
@@ -708,12 +757,13 @@ llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty,
while ((Ty = dyn_cast<ArrayType>(EltTy))) {
uint64_t Upper = 0;
if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Ty))
- Upper = CAT->getSize().getZExtValue() - 1;
+ if (CAT->getSize().getZExtValue())
+ 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());
@@ -731,14 +781,29 @@ 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);
+ // Check for existing entry.
+ std::map<void *, llvm::WeakVH>::iterator it =
+ TypeCache.find(Ty.getAsOpaquePtr());
+ if (it != TypeCache.end()) {
+ // Verify that the debug info still exists.
+ if (&*it->second)
+ return llvm::DIType(cast<llvm::MDNode>(it->second));
+ }
+
+ // Otherwise create the type.
+ llvm::DIType Res = CreateTypeNode(Ty, Unit);
+ TypeCache.insert(std::make_pair(Ty.getAsOpaquePtr(), Res.getNode()));
+ return Res;
+}
+
+/// getOrCreateTypeNode - Get the type metadata node from the cache or create a
+/// new one if necessary.
+llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty,
+ llvm::DICompileUnit Unit) {
+ // Handle qualifiers, which recursively handles what they refer to.
+ if (Ty.hasQualifiers())
+ return CreateQualifiedType(Ty, Unit);
// Work out details of type.
switch (Ty->getTypeClass()) {
@@ -748,53 +813,52 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty,
#define DEPENDENT_TYPE(Class, Base) case Type::Class:
#include "clang/AST/TypeNodes.def"
assert(false && "Dependent types cannot show up in debug information");
-
+
+ default:
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::ObjCObjectPointer: // 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::ObjCObjectPointer:
+ return CreateType(cast<ObjCObjectPointerType>(Ty), Unit);
+ case Type::ObjCInterface:
+ return CreateType(cast<ObjCInterfaceType>(Ty), Unit);
+ case Type::Builtin: return CreateType(cast<BuiltinType>(Ty), Unit);
+ case Type::Complex: return CreateType(cast<ComplexType>(Ty), Unit);
+ case Type::Pointer: return 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);
+ return CreateType(cast<BlockPointerType>(Ty), Unit);
+ case Type::Typedef: return CreateType(cast<TypedefType>(Ty), Unit);
case Type::Record:
case Type::Enum:
- return Slot = CreateType(cast<TagType>(Ty), Unit);
+ return CreateType(cast<TagType>(Ty), Unit);
case Type::FunctionProto:
case Type::FunctionNoProto:
- return Slot = CreateType(cast<FunctionType>(Ty), Unit);
-
+ return CreateType(cast<FunctionType>(Ty), Unit);
+ case Type::Elaborated:
+ return getOrCreateType(cast<ElaboratedType>(Ty)->getUnderlyingType(),
+ Unit);
+
case Type::ConstantArray:
+ case Type::ConstantArrayWithExpr:
+ case Type::ConstantArrayWithoutExpr:
case Type::VariableArray:
case Type::IncompleteArray:
- return Slot = CreateType(cast<ArrayType>(Ty), Unit);
+ return CreateType(cast<ArrayType>(Ty), Unit);
case Type::TypeOfExpr:
- return Slot = getOrCreateType(cast<TypeOfExprType>(Ty)->getUnderlyingExpr()
- ->getType(), Unit);
+ return getOrCreateType(cast<TypeOfExprType>(Ty)->getUnderlyingExpr()
+ ->getType(), Unit);
case Type::TypeOf:
- return Slot = getOrCreateType(cast<TypeOfType>(Ty)->getUnderlyingType(),
- Unit);
+ return getOrCreateType(cast<TypeOfType>(Ty)->getUnderlyingType(), Unit);
case Type::Decltype:
- return Slot = getOrCreateType(cast<DecltypeType>(Ty)->getUnderlyingExpr()
- ->getType(), Unit);
+ return getOrCreateType(cast<DecltypeType>(Ty)->getUnderlyingType(), Unit);
}
-
- return Slot;
}
/// EmitFunctionStart - Constructs the debug code for entering a function -
@@ -803,25 +867,27 @@ 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*/);
-
+
+#ifndef ATTACH_DEBUG_INFO_TO_AN_INSN
DebugFactory.InsertSubprogramStart(SP, Builder.GetInsertBlock());
-
+#endif
+
// Push function on region stack.
RegionStack.push_back(SP);
}
@@ -829,10 +895,10 @@ void CGDebugInfo::EmitFunctionStart(const char *Name, QualType ReturnType,
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
+ if (CurLoc == PrevLoc
|| (SM.getInstantiationLineNumber(CurLoc) ==
SM.getInstantiationLineNumber(PrevLoc)
&& SM.isFromSameFile(CurLoc, PrevLoc)))
@@ -844,8 +910,19 @@ void CGDebugInfo::EmitStopPoint(llvm::Function *Fn, CGBuilderTy &Builder) {
// Get the appropriate compile unit.
llvm::DICompileUnit Unit = getOrCreateCompileUnit(CurLoc);
PresumedLoc PLoc = SM.getPresumedLoc(CurLoc);
+
+#ifdef ATTACH_DEBUG_INFO_TO_AN_INSN
+ llvm::DIDescriptor DR = RegionStack.back();
+ llvm::DIScope DS = llvm::DIScope(DR.getNode());
+ llvm::DILocation DO(NULL);
+ llvm::DILocation DL =
+ DebugFactory.CreateLocation(PLoc.getLine(), PLoc.getColumn(),
+ DS, DO);
+ Builder.SetCurrentDebugLocation(DL.getNode());
+#else
DebugFactory.InsertStopPoint(Unit, PLoc.getLine(), PLoc.getColumn(),
- Builder.GetInsertBlock());
+ Builder.GetInsertBlock());
+#endif
}
/// EmitRegionStart- Constructs the debug code for entering a declarative
@@ -854,9 +931,11 @@ void CGDebugInfo::EmitRegionStart(llvm::Function *Fn, CGBuilderTy &Builder) {
llvm::DIDescriptor D;
if (!RegionStack.empty())
D = RegionStack.back();
- D = DebugFactory.CreateBlock(D);
+ D = DebugFactory.CreateLexicalBlock(D);
RegionStack.push_back(D);
+#ifndef ATTACH_DEBUG_INFO_TO_AN_INSN
DebugFactory.InsertRegionStart(D, Builder.GetInsertBlock());
+#endif
}
/// EmitRegionEnd - Constructs the debug code for exiting a declarative
@@ -866,8 +945,10 @@ void CGDebugInfo::EmitRegionEnd(llvm::Function *Fn, CGBuilderTy &Builder) {
// Provide an region stop point.
EmitStopPoint(Fn, Builder);
-
+
+#ifndef ATTACH_DEBUG_INFO_TO_AN_INSN
DebugFactory.InsertRegionEnd(RegionStack.back(), Builder.GetInsertBlock());
+#endif
RegionStack.pop_back();
}
@@ -884,7 +965,139 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag,
return;
llvm::DICompileUnit Unit = getOrCreateCompileUnit(Decl->getLocation());
- llvm::DIType Ty = getOrCreateType(Decl->getType(), Unit);
+ QualType Type = Decl->getType();
+ llvm::DIType Ty = getOrCreateType(Type, Unit);
+ if (Decl->hasAttr<BlocksAttr>()) {
+ 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;
+
+ // Build up structure for the byref. See BuildByRefType.
+ 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().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,
+ "__forwarding", DefUnit,
+ 0, FieldSize, FieldAlign,
+ FieldOffset, 0, FieldTy);
+ EltTys.push_back(FieldTy);
+ FieldOffset += FieldSize;
+
+ FType = M->getContext().getFixedWidthIntType(32, true); // Int32Ty;
+ 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().getFixedWidthIntType(32, true); // Int32Ty;
+ 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;
+
+ bool HasCopyAndDispose = M->BlockRequiresCopying(Type);
+ if (HasCopyAndDispose) {
+ 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,
+ "__copy_helper", 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,
+ "__destroy_helper", DefUnit,
+ 0, FieldSize, FieldAlign,
+ FieldOffset, 0, FieldTy);
+ EltTys.push_back(FieldTy);
+ FieldOffset += FieldSize;
+ }
+
+ unsigned Align = M->getContext().getDeclAlignInBytes(Decl);
+ if (Align > M->getContext().Target.getPointerAlign(0) / 8) {
+ unsigned AlignedOffsetInBytes
+ = llvm::RoundUpToAlignment(FieldOffset/8, Align);
+ unsigned NumPaddingBytes
+ = AlignedOffsetInBytes - FieldOffset/8;
+
+ if (NumPaddingBytes > 0) {
+ llvm::APInt pad(32, NumPaddingBytes);
+ FType = M->getContext().getConstantArrayType(M->getContext().CharTy,
+ pad, ArrayType::Normal, 0);
+ FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
+ FieldSize = M->getContext().getTypeSize(FType);
+ FieldAlign = M->getContext().getTypeAlign(FType);
+ FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member,
+ Unit, "", DefUnit,
+ 0, FieldSize, FieldAlign,
+ FieldOffset, 0, FieldTy);
+ EltTys.push_back(FieldTy);
+ FieldOffset += FieldSize;
+ }
+ }
+
+ FType = Type;
+ FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
+ FieldSize = M->getContext().getTypeSize(FType);
+ FieldAlign = Align*8;
+ std::string Name = Decl->getNameAsString();
+
+ FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
+ Name, DefUnit,
+ 0, FieldSize, FieldAlign,
+ FieldOffset, 0, FieldTy);
+ EltTys.push_back(FieldTy);
+ FieldOffset += FieldSize;
+
+ Elements = DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size());
+
+ unsigned Flags = llvm::DIType::FlagBlockByrefStruct;
+
+ Ty = DebugFactory.CreateCompositeType(Tag, Unit, "",
+ llvm::DICompileUnit(),
+ 0, FieldOffset, 0, 0, Flags,
+ llvm::DIType(), Elements);
+ }
// Get location information.
SourceManager &SM = M->getContext().getSourceManager();
@@ -895,21 +1108,222 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag,
else
Unit = llvm::DICompileUnit();
-
+
// Create the descriptor for the variable.
- llvm::DIVariable D =
+ 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());
}
+/// EmitDeclare - Emit local variable declaration debug info.
+void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
+ llvm::Value *Storage, CGBuilderTy &Builder,
+ CodeGenFunction *CGF) {
+ const ValueDecl *Decl = BDRE->getDecl();
+ 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 || Builder.GetInsertBlock() == 0)
+ return;
+
+ uint64_t XOffset = 0;
+ llvm::DICompileUnit Unit = getOrCreateCompileUnit(Decl->getLocation());
+ QualType Type = Decl->getType();
+ llvm::DIType Ty = getOrCreateType(Type, Unit);
+ if (Decl->hasAttr<BlocksAttr>()) {
+ 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;
+
+ // Build up structure for the byref. See BuildByRefType.
+ 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().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,
+ "__forwarding", DefUnit,
+ 0, FieldSize, FieldAlign,
+ FieldOffset, 0, FieldTy);
+ EltTys.push_back(FieldTy);
+ FieldOffset += FieldSize;
+
+ FType = M->getContext().getFixedWidthIntType(32, true); // Int32Ty;
+ 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().getFixedWidthIntType(32, true); // Int32Ty;
+ 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;
+
+ bool HasCopyAndDispose = M->BlockRequiresCopying(Type);
+ if (HasCopyAndDispose) {
+ 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,
+ "__copy_helper", 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,
+ "__destroy_helper", DefUnit,
+ 0, FieldSize, FieldAlign,
+ FieldOffset, 0, FieldTy);
+ EltTys.push_back(FieldTy);
+ FieldOffset += FieldSize;
+ }
+
+ unsigned Align = M->getContext().getDeclAlignInBytes(Decl);
+ if (Align > M->getContext().Target.getPointerAlign(0) / 8) {
+ unsigned AlignedOffsetInBytes
+ = llvm::RoundUpToAlignment(FieldOffset/8, Align);
+ unsigned NumPaddingBytes
+ = AlignedOffsetInBytes - FieldOffset/8;
+
+ if (NumPaddingBytes > 0) {
+ llvm::APInt pad(32, NumPaddingBytes);
+ FType = M->getContext().getConstantArrayType(M->getContext().CharTy,
+ pad, ArrayType::Normal, 0);
+ FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
+ FieldSize = M->getContext().getTypeSize(FType);
+ FieldAlign = M->getContext().getTypeAlign(FType);
+ FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member,
+ Unit, "", DefUnit,
+ 0, FieldSize, FieldAlign,
+ FieldOffset, 0, FieldTy);
+ EltTys.push_back(FieldTy);
+ FieldOffset += FieldSize;
+ }
+ }
+
+ FType = Type;
+ FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
+ FieldSize = M->getContext().getTypeSize(FType);
+ FieldAlign = Align*8;
+ std::string Name = Decl->getNameAsString();
+
+ XOffset = FieldOffset;
+ FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
+ Name, DefUnit,
+ 0, FieldSize, FieldAlign,
+ FieldOffset, 0, FieldTy);
+ EltTys.push_back(FieldTy);
+ FieldOffset += FieldSize;
+
+ Elements = DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size());
+
+ unsigned Flags = llvm::DIType::FlagBlockByrefStruct;
+
+ Ty = DebugFactory.CreateCompositeType(Tag, Unit, "",
+ llvm::DICompileUnit(),
+ 0, FieldOffset, 0, 0, Flags,
+ llvm::DIType(), Elements);
+ }
+
+ // 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();
+
+ uint64_t offset = CGF->BlockDecls[Decl];
+ llvm::SmallVector<llvm::Value *, 9> addr;
+ llvm::LLVMContext &VMContext = M->getLLVMContext();
+ addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
+ llvm::DIFactory::OpDeref));
+ addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
+ llvm::DIFactory::OpPlus));
+ addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
+ offset));
+ if (BDRE->isByRef()) {
+ addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
+ llvm::DIFactory::OpDeref));
+ addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
+ llvm::DIFactory::OpPlus));
+ offset = CGF->LLVMPointerWidth/8; // offset of __forwarding field
+ addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
+ offset));
+ addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
+ llvm::DIFactory::OpDeref));
+ addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
+ llvm::DIFactory::OpPlus));
+ offset = XOffset/8; // offset of x field
+ addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
+ offset));
+ }
+
+ // Create the descriptor for the variable.
+ llvm::DIVariable D =
+ DebugFactory.CreateComplexVariable(Tag, RegionStack.back(),
+ Decl->getNameAsString(), Unit, Line, Ty,
+ addr);
+ // Insert an llvm.dbg.declare into the current block.
+ DebugFactory.InsertDeclare(Storage, D, Builder.GetInsertPoint());
+}
+
void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *Decl,
llvm::Value *Storage,
CGBuilderTy &Builder) {
EmitDeclare(Decl, llvm::dwarf::DW_TAG_auto_variable, Storage, Builder);
}
+void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(
+ const BlockDeclRefExpr *BDRE, llvm::Value *Storage, CGBuilderTy &Builder,
+ CodeGenFunction *CGF) {
+ EmitDeclare(BDRE, llvm::dwarf::DW_TAG_auto_variable, Storage, Builder, CGF);
+}
+
/// EmitDeclareOfArgVariable - Emit call to llvm.dbg.declare for an argument
/// variable declaration.
void CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *Decl, llvm::Value *AI,
@@ -920,7 +1334,7 @@ void CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *Decl, llvm::Value *AI,
/// EmitGlobalVariable - Emit information about a global variable.
-void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
+void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
const VarDecl *Decl) {
// Do not emit variable debug information while generating optimized code.
@@ -936,29 +1350,30 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation());
unsigned LineNo = PLoc.isInvalid() ? 0 : PLoc.getLine();
- std::string Name = Decl->getNameAsString();
+ std::string Name = Var->getName();
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,
+
+ T = M->getContext().getConstantArrayType(ET, ConstVal,
ArrayType::Normal, 0);
}
- DebugFactory.CreateGlobalVariable(Unit, Name, Name, "", Unit, LineNo,
+ DebugFactory.CreateGlobalVariable(getContext(Decl, 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,
+void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
ObjCInterfaceDecl *Decl) {
// Create global variable debug descriptor.
llvm::DICompileUnit Unit = getOrCreateCompileUnit(Decl->getLocation());
@@ -970,14 +1385,14 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
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,
+
+ T = M->getContext().getConstantArrayType(ET, ConstVal,
ArrayType::Normal, 0);
}
@@ -986,4 +1401,3 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
Var->hasInternalLinkage(),
true/*definition*/, Var);
}
-
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index de65580..0a617b9 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This is the source level debug info generator for llvm translation.
+// This is the source level debug info generator for llvm translation.
//
//===----------------------------------------------------------------------===//
@@ -15,28 +15,35 @@
#define CLANG_CODEGEN_CGDEBUGINFO_H
#include "clang/AST/Type.h"
+#include "clang/AST/Expr.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/Analysis/DebugInfo.h"
+#include "llvm/Support/ValueHandle.h"
#include <map>
#include "CGBuilder.h"
+namespace llvm {
+ class MDNode;
+}
+
namespace clang {
class VarDecl;
class ObjCInterfaceDecl;
namespace CodeGen {
class CodeGenModule;
+ class CodeGenFunction;
-/// CGDebugInfo - This class gathers all debug information during compilation
-/// and is responsible for emitting to llvm globals or pass directly to
+/// 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.
@@ -44,8 +51,8 @@ class CGDebugInfo {
/// TypeCache - Cache of previously constructed Types.
// FIXME: Eliminate this map. Be careful of iterator invalidation.
- std::map<void *, llvm::DIType> TypeCache;
-
+ std::map<void *, llvm::WeakVH> TypeCache;
+
bool BlockLiteralGenericSet;
llvm::DIType BlockLiteralGeneric;
@@ -54,8 +61,10 @@ class CGDebugInfo {
/// 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 CreateQualifiedType(QualType Ty, llvm::DICompileUnit U);
llvm::DIType CreateType(const TypedefType *Ty, llvm::DICompileUnit U);
+ llvm::DIType CreateType(const ObjCObjectPointerType *Ty,
+ llvm::DICompileUnit Unit);
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);
@@ -81,12 +90,12 @@ public:
/// 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.
+ /// of a new block.
void EmitRegionStart(llvm::Function *Fn, CGBuilderTy &Builder);
-
- /// EmitRegionEnd - Emit call to llvm.dbg.region.end to indicate end of a
+
+ /// EmitRegionEnd - Emit call to llvm.dbg.region.end to indicate end of a
/// block.
void EmitRegionEnd(llvm::Function *Fn, CGBuilderTy &Builder);
@@ -95,23 +104,36 @@ public:
void EmitDeclareOfAutoVariable(const VarDecl *Decl, llvm::Value *AI,
CGBuilderTy &Builder);
+ /// EmitDeclareOfBlockDeclRefVariable - Emit call to llvm.dbg.declare for an
+ /// imported variable declaration in a block.
+ void EmitDeclareOfBlockDeclRefVariable(const BlockDeclRefExpr *BDRE,
+ llvm::Value *AI,
+ CGBuilderTy &Builder,
+ CodeGenFunction *CGF);
+
/// 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);
-
-
+
+ /// EmitDeclare - Emit call to llvm.dbg.declare for a variable declaration.
+ void EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, llvm::Value *AI,
+ CGBuilderTy &Builder, CodeGenFunction *CGF);
+
+ /// getContext - Get context info for the decl.
+ llvm::DIDescriptor getContext(const VarDecl *Decl,llvm::DIDescriptor &CU);
+
/// getOrCreateCompileUnit - Get the compile unit from the cache or create a
/// new one if necessary.
llvm::DICompileUnit getOrCreateCompileUnit(SourceLocation Loc);
@@ -119,8 +141,12 @@ private:
/// getOrCreateType - Get the type from the cache or create a new type if
/// necessary.
llvm::DIType getOrCreateType(QualType Ty, llvm::DICompileUnit Unit);
+
+ /// CreateTypeNode - Create type metadata for a source language type.
+ llvm::DIType CreateTypeNode(QualType Ty, llvm::DICompileUnit Unit);
};
} // namespace CodeGen
} // namespace clang
+
#endif
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 2ae7e22..7feff83 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -35,22 +35,22 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
case Decl::Function: // void X();
case Decl::Record: // struct/union/class X;
case Decl::Enum: // enum X;
- case Decl::EnumConstant: // 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() &&
+ 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);
}
@@ -62,7 +62,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
void CodeGenFunction::EmitBlockVarDecl(const VarDecl &D) {
if (D.hasAttr<AsmLabelAttr>())
CGM.ErrorUnsupported(&D, "__asm__");
-
+
switch (D.getStorageClass()) {
case VarDecl::None:
case VarDecl::Auto:
@@ -95,27 +95,28 @@ CodeGenFunction::CreateStaticBlockVarDecl(const VarDecl &D,
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());
+ ContextName = CurFn->getName();
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());
+ llvm::GlobalVariable *GV =
+ new llvm::GlobalVariable(CGM.getModule(), LTy,
+ Ty.isConstant(getContext()), Linkage,
+ CGM.EmitNullConstant(D.getType()), Name, 0,
+ D.isThreadSpecified(), Ty.getAddressSpace());
+ GV->setAlignment(getContext().getDeclAlignInBytes(&D));
+ return GV;
}
-void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D) {
-
+void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D) {
llvm::Value *&DMEntry = LocalDeclMap[&D];
assert(DMEntry == 0 && "Decl already exists in localdeclmap!");
-
- llvm::GlobalVariable *GV =
+
+ llvm::GlobalVariable *GV =
CreateStaticBlockVarDecl(D, ".", llvm::GlobalValue::InternalLinkage);
// Store into LocalDeclMap before generating initializer to handle
@@ -123,14 +124,11 @@ void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D) {
DMEntry = GV;
// Make sure to evaluate VLA bounds now so that we have them for later.
+ //
+ // FIXME: Can this happen?
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);
@@ -140,7 +138,7 @@ void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D) {
if (!getContext().getLangOptions().CPlusPlus)
CGM.ErrorUnsupported(D.getInit(), "constant l-value expression");
else
- GenerateStaticCXXBlockVarDeclInit(D, GV);
+ EmitStaticCXXBlockVarDeclInit(D, GV);
} else {
// The initializer may differ in type from the global. Rewrite
// the global to match the initializer. (We have to do this
@@ -148,23 +146,24 @@ void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D) {
// in the LLVM type system.)
if (GV->getType() != Init->getType()) {
llvm::GlobalVariable *OldGV = GV;
-
- GV = new llvm::GlobalVariable(Init->getType(), OldGV->isConstant(),
+
+ GV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(),
+ OldGV->isConstant(),
OldGV->getLinkage(), Init, "",
- &CGM.getModule(), D.isThreadSpecified(),
+ 0, 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::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);
}
@@ -174,14 +173,14 @@ void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D) {
if (const AnnotateAttr *AA = D.getAttr<AnnotateAttr>()) {
SourceManager &SM = CGM.getContext().getSourceManager();
llvm::Constant *Ann =
- CGM.EmitAnnotateAttr(GV, AA,
+ 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);
@@ -202,7 +201,13 @@ void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D) {
DI->EmitGlobalVariable(static_cast<llvm::GlobalVariable *>(GV), &D);
}
}
+
+unsigned CodeGenFunction::getByRefValueLLVMField(const ValueDecl *VD) const {
+ assert(ByRefValueInfo.count(VD) && "Did not find value!");
+ return ByRefValueInfo.find(VD)->second.second;
+}
+
/// BuildByRefType - This routine changes a __block variable declared as T x
/// into:
///
@@ -211,32 +216,91 @@ void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D) {
/// void *__forwarding;
/// int32_t __flags;
/// int32_t __size;
-/// void *__copy_helper;
-/// void *__destroy_helper;
+/// void *__copy_helper; // only if needed
+/// void *__destroy_helper; // only if needed
+/// char padding[X]; // only if needed
/// 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;
+const llvm::Type *CodeGenFunction::BuildByRefType(const ValueDecl *D) {
+ std::pair<const llvm::Type *, unsigned> &Info = ByRefValueInfo[D];
+ if (Info.first)
+ return Info.first;
+
+ QualType Ty = D->getType();
+
+ std::vector<const llvm::Type *> Types;
+
+ const llvm::PointerType *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
+
+ llvm::PATypeHolder ByRefTypeHolder = llvm::OpaqueType::get(VMContext);
+
+ // void *__isa;
+ Types.push_back(Int8PtrTy);
+
+ // void *__forwarding;
+ Types.push_back(llvm::PointerType::getUnqual(ByRefTypeHolder));
+
+ // int32_t __flags;
+ Types.push_back(llvm::Type::getInt32Ty(VMContext));
+
+ // int32_t __size;
+ Types.push_back(llvm::Type::getInt32Ty(VMContext));
+
+ bool HasCopyAndDispose = BlockRequiresCopying(Ty);
+ if (HasCopyAndDispose) {
+ /// void *__copy_helper;
+ Types.push_back(Int8PtrTy);
+
+ /// void *__destroy_helper;
+ Types.push_back(Int8PtrTy);
}
- // FIXME: Align this on at least an Align boundary, assert if we can't.
- assert((Align <= unsigned(Target.getPointerAlign(0))/8)
- && "Can't align more than pointer yet");
- Types[needsCopyDispose*2 + 4] = LTy;
- return llvm::StructType::get(Types, false);
+
+ bool Packed = false;
+ unsigned Align = getContext().getDeclAlignInBytes(D);
+ if (Align > Target.getPointerAlign(0) / 8) {
+ // We have to insert padding.
+
+ // The struct above has 2 32-bit integers.
+ unsigned CurrentOffsetInBytes = 4 * 2;
+
+ // And either 2 or 4 pointers.
+ CurrentOffsetInBytes += (HasCopyAndDispose ? 4 : 2) *
+ CGM.getTargetData().getTypeAllocSize(Int8PtrTy);
+
+ // Align the offset.
+ unsigned AlignedOffsetInBytes =
+ llvm::RoundUpToAlignment(CurrentOffsetInBytes, Align);
+
+ unsigned NumPaddingBytes = AlignedOffsetInBytes - CurrentOffsetInBytes;
+ if (NumPaddingBytes > 0) {
+ const llvm::Type *Ty = llvm::Type::getInt8Ty(VMContext);
+ // FIXME: We need a sema error for alignment larger than the minimum of the
+ // maximal stack alignmint and the alignment of malloc on the system.
+ if (NumPaddingBytes > 1)
+ Ty = llvm::ArrayType::get(Ty, NumPaddingBytes);
+
+ Types.push_back(Ty);
+
+ // We want a packed struct.
+ Packed = true;
+ }
+ }
+
+ // T x;
+ Types.push_back(ConvertType(Ty));
+
+ const llvm::Type *T = llvm::StructType::get(VMContext, Types, Packed);
+
+ cast<llvm::OpaqueType>(ByRefTypeHolder.get())->refineAbstractTypeTo(T);
+ CGM.getModule().addTypeName("struct.__block_byref_" + D->getNameAsString(),
+ ByRefTypeHolder.get());
+
+ Info.first = ByRefTypeHolder.get();
+
+ Info.second = Types.size() - 1;
+
+ return Info.first;
}
/// EmitLocalBlockVarDecl - Emit code and set up an entry in LocalDeclMap for a
@@ -255,10 +319,10 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
const llvm::Type *LTy = ConvertTypeForMem(Ty);
Align = getContext().getDeclAlignInBytes(&D);
if (isByRef)
- LTy = BuildByRefType(Ty, Align);
+ LTy = BuildByRefType(&D);
llvm::AllocaInst *Alloc = CreateTempAlloca(LTy);
Alloc->setName(D.getNameAsString().c_str());
-
+
if (isByRef)
Align = std::max(Align, unsigned(Target.getPointerAlign(0) / 8));
Alloc->setAlignment(Align);
@@ -267,48 +331,55 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
// Targets that don't support recursion emit locals as globals.
const char *Class =
D.getStorageClass() == VarDecl::Register ? ".reg." : ".auto.";
- DeclPtr = CreateStaticBlockVarDecl(D, Class,
+ DeclPtr = CreateStaticBlockVarDecl(D, Class,
llvm::GlobalValue
::InternalLinkage);
}
-
+
+ // FIXME: Can this happen?
if (Ty->isVariablyModifiedType())
EmitVLASize(Ty);
} else {
+ EnsureInsertPoint();
+
if (!DidCallStackSave) {
// Save the stack.
- const llvm::Type *LTy = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+ const llvm::Type *LTy = llvm::Type::getInt8PtrTy(VMContext);
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 *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");
-
+ VLASize = Builder.CreateIntCast(VLASize, llvm::Type::getInt32Ty(VMContext),
+ false, "tmp");
+
// Allocate memory for the array.
- llvm::Value *VLA = Builder.CreateAlloca(llvm::Type::Int8Ty, VLASize, "vla");
+ llvm::AllocaInst *VLA =
+ Builder.CreateAlloca(llvm::Type::getInt8Ty(VMContext), VLASize, "vla");
+ VLA->setAlignment(getContext().getDeclAlignInBytes(&D));
+
DeclPtr = Builder.CreateBitCast(VLA, LElemPtrTy, "tmp");
}
@@ -318,35 +389,39 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
// Emit debug info for local var declaration.
if (CGDebugInfo *DI = getDebugInfo()) {
+ assert(HaveInsertPoint() && "Unexpected unreachable point!");
+
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()) {
+ const Expr *Init = D.getInit();
+
+ // If we are at an unreachable point, we don't need to emit the initializer
+ // unless it contains a label.
+ if (!HaveInsertPoint()) {
+ if (!ContainsLabel(Init))
+ Init = 0;
+ else
+ EnsureInsertPoint();
+ }
+
+ if (Init) {
llvm::Value *Loc = DeclPtr;
- if (isByRef) {
- bool needsCopyDispose = BlockRequiresCopying(Ty);
- Loc = Builder.CreateStructGEP(DeclPtr, needsCopyDispose*2+4, "x");
- }
+ if (isByRef)
+ Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D),
+ D.getNameAsString());
+
if (Ty->isReferenceType()) {
- llvm::Value *V = EmitReferenceBindingToExpr(Init, Ty).getScalarVal();
- EmitStoreOfScalar(V, Loc, false, Ty);
+ RValue RV = EmitReferenceBindingToExpr(Init, Ty, /*IsInitializer=*/true);
+ EmitStoreOfScalar(RV.getScalarVal(), Loc, false, Ty);
} else if (!hasAggregateLLVMType(Init->getType())) {
llvm::Value *V = EmitScalarExpr(Init);
- EmitStoreOfScalar(V, Loc, D.getType().isVolatileQualified(),
+ EmitStoreOfScalar(V, Loc, D.getType().isVolatileQualified(),
D.getType());
} else if (Init->getType()->isAnyComplexType()) {
EmitComplexExprIntoAddr(Init, Loc, D.getType().isVolatileQualified());
@@ -354,10 +429,11 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
EmitAggExpr(Init, Loc, D.getType().isVolatileQualified());
}
}
+
if (isByRef) {
- const llvm::PointerType *PtrToInt8Ty
- = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+ const llvm::PointerType *PtrToInt8Ty = llvm::Type::getInt8PtrTy(VMContext);
+ EnsureInsertPoint();
llvm::Value *isa_field = Builder.CreateStructGEP(DeclPtr, 0);
llvm::Value *forwarding_field = Builder.CreateStructGEP(DeclPtr, 1);
llvm::Value *flags_field = Builder.CreateStructGEP(DeclPtr, 2);
@@ -383,19 +459,18 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
int isa = 0;
if (flag&BLOCK_FIELD_IS_WEAK)
isa = 1;
- V = llvm::ConstantInt::get(llvm::Type::Int32Ty, isa);
+ V = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), isa);
V = Builder.CreateIntToPtr(V, PtrToInt8Ty, "isa");
Builder.CreateStore(V, isa_field);
- V = Builder.CreateBitCast(DeclPtr, PtrToInt8Ty, "forwarding");
- Builder.CreateStore(V, forwarding_field);
+ Builder.CreateStore(DeclPtr, forwarding_field);
- V = llvm::ConstantInt::get(llvm::Type::Int32Ty, flags);
+ V = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), flags);
Builder.CreateStore(V, flags_field);
const llvm::Type *V1;
V1 = cast<llvm::PointerType>(DeclPtr->getType())->getElementType();
- V = llvm::ConstantInt::get(llvm::Type::Int32Ty,
+ V = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
(CGM.getTargetData().getTypeStoreSizeInBits(V1)
/ 8));
Builder.CreateStore(V, size_field);
@@ -413,13 +488,29 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
}
}
+ // Handle CXX destruction of variables.
+ QualType DtorTy(Ty);
+ if (const ArrayType *Array = DtorTy->getAs<ArrayType>())
+ DtorTy = Array->getElementType();
+ if (const RecordType *RT = DtorTy->getAs<RecordType>())
+ if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
+ if (!ClassDecl->hasTrivialDestructor()) {
+ const CXXDestructorDecl *D = ClassDecl->getDestructor(getContext());
+ assert(D && "EmitLocalBlockVarDecl - destructor is nul");
+ assert(!Ty->getAs<ArrayType>() && "FIXME - destruction of arrays NYI");
+
+ CleanupScope scope(*this);
+ EmitCXXDestructorCall(D, Dtor_Complete, DeclPtr);
+ }
+ }
+
// Handle the cleanup attribute
if (const CleanupAttr *CA = D.getAttr<CleanupAttr>()) {
const FunctionDecl *FD = CA->getFunctionDecl();
-
- llvm::Constant* F = CGM.GetAddrOfFunction(GlobalDecl(FD));
+
+ llvm::Constant* F = CGM.GetAddrOfFunction(FD);
assert(F && "Could not find function!");
-
+
CleanupScope scope(*this);
const CGFunctionInfo &Info = CGM.getTypes().getFunctionInfo(FD);
@@ -428,15 +519,15 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
// 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),
+ Args.push_back(std::make_pair(RValue::get(DeclPtr),
getContext().getPointerType(D.getType())));
-
+
EmitCall(Info, F, Args);
}
@@ -448,14 +539,14 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
}
}
-/// Emit an alloca (or GlobalValue depending on target)
+/// 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.
@@ -469,7 +560,7 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg) {
Name += ".addr";
DeclPtr = CreateTempAlloca(LTy);
DeclPtr->setName(Name.c_str());
-
+
// Store the initial value into the alloca.
EmitStoreOfScalar(Arg, DeclPtr, Ty.isVolatileQualified(), Ty);
} else {
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 0951019..2834dfe 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -46,33 +46,38 @@ llvm::Value *CodeGenFunction::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.
-RValue CodeGenFunction::EmitAnyExpr(const Expr *E, llvm::Value *AggLoc,
- bool isAggLocVolatile, bool IgnoreResult) {
+/// 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,
+ bool IsInitializer) {
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);
+
+ EmitAggExpr(E, AggLoc, IsAggLocVolatile, IgnoreResult, IsInitializer);
+ 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()) &&
+/// EmitAnyExprToTemp - Similary to EmitAnyExpr(), however, the result will
+/// always be accessible even if no aggregate location is provided.
+RValue CodeGenFunction::EmitAnyExprToTemp(const Expr *E,
+ bool IsAggLocVolatile,
+ bool IsInitializer) {
+ llvm::Value *AggLoc = 0;
+
+ if (hasAggregateLLVMType(E->getType()) &&
!E->getType()->isAnyComplexType())
AggLoc = CreateTempAlloca(ConvertType(E->getType()), "agg.tmp");
- return EmitAnyExpr(E, AggLoc, isAggLocVolatile);
+ return EmitAnyExpr(E, AggLoc, IsAggLocVolatile, /*IgnoreResult=*/false,
+ IsInitializer);
}
RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E,
- QualType DestType) {
+ QualType DestType,
+ bool IsInitializer) {
RValue Val;
if (E->isLvalue(getContext()) == Expr::LV_Valid) {
// Emit the expr as an lvalue.
@@ -81,14 +86,33 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E,
return RValue::get(LV.getAddress());
Val = EmitLoadOfLValue(LV, E->getType());
} else {
- Val = EmitAnyExprToTemp(E);
+ // FIXME: Initializers don't work with casts yet. For example
+ // const A& a = B();
+ // if B inherits from A.
+ Val = EmitAnyExprToTemp(E, /*IsAggLocVolatile=*/false,
+ IsInitializer);
+
+ if (IsInitializer) {
+ // We might have to destroy the temporary variable.
+ if (const RecordType *RT = E->getType()->getAs<RecordType>()) {
+ if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
+ if (!ClassDecl->hasTrivialDestructor()) {
+ const CXXDestructorDecl *Dtor =
+ ClassDecl->getDestructor(getContext());
+
+ CleanupScope scope(*this);
+ EmitCXXDestructorCall(Dtor, Dtor_Complete, Val.getAggregateAddr());
+ }
+ }
+ }
+ }
}
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()),
+ llvm::Value *Temp = CreateTempAlloca(ConvertTypeForMem(E->getType()),
"reftmp");
if (Val.isScalar())
EmitStoreOfScalar(Val.getScalarVal(), Temp, false, E->getType());
@@ -101,13 +125,13 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E,
}
-/// getAccessedFieldNo - Given an encoded value and a result number, return
-/// the input field number being accessed.
-unsigned CodeGenFunction::getAccessedFieldNo(unsigned Idx,
+/// 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();
}
@@ -119,7 +143,7 @@ unsigned CodeGenFunction::getAccessedFieldNo(unsigned Idx,
RValue CodeGenFunction::GetUndefRValue(QualType Ty) {
if (Ty->isVoidType()) {
return RValue::get(0);
- } else if (const ComplexType *CTy = Ty->getAsComplexType()) {
+ } else if (const ComplexType *CTy = Ty->getAs<ComplexType>()) {
const llvm::Type *EltTy = ConvertType(CTy->getElementType());
llvm::Value *U = llvm::UndefValue::get(EltTy);
return RValue::getComplex(std::make_pair(U, U));
@@ -142,38 +166,37 @@ LValue CodeGenFunction::EmitUnsupportedLValue(const Expr *E,
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()));
+ MakeQualifiers(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.
+/// 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 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.
+/// 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:
+ case Expr::BinaryOperatorClass:
return EmitBinaryOperatorLValue(cast<BinaryOperator>(E));
- case Expr::CallExprClass:
+ case Expr::CallExprClass:
+ case Expr::CXXMemberCallExprClass:
case Expr::CXXOperatorCallExprClass:
return EmitCallExprLValue(cast<CallExpr>(E));
case Expr::VAArgExprClass:
return EmitVAArgExprLValue(cast<VAArgExpr>(E));
- case Expr::DeclRefExprClass:
+ case Expr::DeclRefExprClass:
case Expr::QualifiedDeclRefExprClass:
return EmitDeclRefLValue(cast<DeclRefExpr>(E));
case Expr::ParenExprClass:return EmitLValue(cast<ParenExpr>(E)->getSubExpr());
@@ -184,7 +207,7 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
case Expr::ObjCEncodeExprClass:
return EmitObjCEncodeExprLValue(cast<ObjCEncodeExpr>(E));
- case Expr::BlockDeclRefExprClass:
+ case Expr::BlockDeclRefExprClass:
return EmitBlockDeclRefLValue(cast<BlockDeclRefExpr>(E));
case Expr::CXXConditionDeclExprClass:
@@ -194,31 +217,34 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
return EmitCXXConstructLValue(cast<CXXConstructExpr>(E));
case Expr::CXXBindTemporaryExprClass:
return EmitCXXBindTemporaryLValue(cast<CXXBindTemporaryExpr>(E));
+ case Expr::CXXExprWithTemporariesClass:
+ return EmitCXXExprWithTemporariesLValue(cast<CXXExprWithTemporaries>(E));
case Expr::ObjCMessageExprClass:
return EmitObjCMessageExprLValue(cast<ObjCMessageExpr>(E));
- case Expr::ObjCIvarRefExprClass:
+ 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::ObjCImplicitSetterGetterRefExprClass:
+ return EmitObjCKVCRefLValue(cast<ObjCImplicitSetterGetterRefExpr>(E));
case Expr::ObjCSuperExprClass:
return EmitObjCSuperExprLValue(cast<ObjCSuperExpr>(E));
case Expr::StmtExprClass:
return EmitStmtExprLValue(cast<StmtExpr>(E));
- case Expr::UnaryOperatorClass:
+ 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::MemberExprClass:
+ return EmitMemberExpr(cast<MemberExpr>(E));
case Expr::CompoundLiteralExprClass:
return EmitCompoundLiteralLValue(cast<CompoundLiteralExpr>(E));
case Expr::ConditionalOperatorClass:
- return EmitConditionalOperator(cast<ConditionalOperator>(E));
+ return EmitConditionalOperatorLValue(cast<ConditionalOperator>(E));
case Expr::ChooseExprClass:
return EmitLValue(cast<ChooseExpr>(E)->getChosenSubExpr(getContext()));
case Expr::ImplicitCastExprClass:
@@ -238,55 +264,54 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
// 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");
-
+ if (V->getType() != llvm::Type::getInt1Ty(VMContext))
+ V = Builder.CreateTrunc(V, llvm::Type::getInt1Ty(VMContext), "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 =
+ const llvm::Type *MemTy =
llvm::PointerType::get(SrcTy, DstPtr->getAddressSpace());
Addr = Builder.CreateBitCast(Addr, MemTy, "storetmp");
}
}
-
- Builder.CreateStore(Value, Addr, Volatile);
+ 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.
+/// 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.
+ // load of a __weak object.
llvm::Value *AddrWeakObj = LV.getAddress();
- llvm::Value *read_weak = CGM.getObjCRuntime().EmitObjCWeakRead(*this,
+ 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(),
+ 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");
@@ -315,59 +340,58 @@ RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV,
unsigned BitfieldSize = LV.getBitfieldSize();
llvm::Value *Ptr = LV.getBitfieldAddr();
- const llvm::Type *EltTy =
+ 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.
+ // 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),
+ 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));
+ llvm::Constant *LowMask = llvm::ConstantInt::get(VMContext,
+ 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,
+ llvm::Value *HighPtr = Builder.CreateGEP(Ptr, llvm::ConstantInt::get(
+ llvm::Type::getInt32Ty(VMContext), 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));
+ llvm::Constant *HighMask = llvm::ConstantInt::get(VMContext,
+ 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,
+ 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,
+ llvm::Value *ExtraBits = llvm::ConstantInt::get(EltTy,
EltTySize - BitfieldSize);
- Val = Builder.CreateAShr(Builder.CreateShl(Val, ExtraBits),
+ 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).
+ // 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);
@@ -389,27 +413,29 @@ 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 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->getAs<VectorType>();
if (!ExprVT) {
unsigned InIdx = getAccessedFieldNo(0, Elts);
- llvm::Value *Elt = llvm::ConstantInt::get(llvm::Type::Int32Ty, InIdx);
+ llvm::Value *Elt = llvm::ConstantInt::get(
+ llvm::Type::getInt32Ty(VMContext), 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));
+ Mask.push_back(llvm::ConstantInt::get(
+ llvm::Type::getInt32Ty(VMContext), InIdx));
}
-
+
llvm::Value *MaskV = llvm::ConstantVector::get(&Mask[0], Mask.size());
Vec = Builder.CreateShuffleVector(Vec,
llvm::UndefValue::get(Vec->getType()),
@@ -422,7 +448,7 @@ RValue CodeGenFunction::EmitLoadOfExtVectorElementLValue(LValue LV,
/// 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,
+void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst,
QualType Ty) {
if (!Dst.isSimple()) {
if (Dst.isVectorElt()) {
@@ -434,7 +460,7 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst,
Builder.CreateStore(Vec, Dst.getVectorAddr(),Dst.isVolatileQualified());
return;
}
-
+
// If this is an update of extended vector elements, insert them as
// appropriate.
if (Dst.isExtVectorElt())
@@ -451,58 +477,60 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst,
assert(0 && "Unknown LValue type");
}
-
+
if (Dst.isObjCWeak() && !Dst.isNonGC()) {
- // load of a __weak object.
+ // 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.
+ // 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())
+ if (Dst.isObjCIvar()) {
+ assert(Dst.getBaseIvarExp() && "BaseIvarExp is NULL");
+ const llvm::Type *ResultType = ConvertType(getContext().LongTy);
+ llvm::Value *RHS = EmitScalarExpr(Dst.getBaseIvarExp());
+ llvm::Value *dst = RHS;
+ RHS = Builder.CreatePtrToInt(RHS, ResultType, "sub.ptr.rhs.cast");
+ llvm::Value *LHS =
+ Builder.CreatePtrToInt(LvalueDst, ResultType, "sub.ptr.lhs.cast");
+ llvm::Value *BytesBetween = Builder.CreateSub(LHS, RHS, "ivar.offset");
+ CGM.getObjCRuntime().EmitObjCIvarAssign(*this, src, dst,
+ BytesBetween);
+ }
+ else 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,
+ QualType Ty,
llvm::Value **Result) {
unsigned StartBit = Dst.getBitfieldStartBit();
unsigned BitfieldSize = Dst.getBitfieldSize();
llvm::Value *Ptr = Dst.getBitfieldAddr();
- const llvm::Type *EltTy =
+ 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.
+ // 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));
+ llvm::Constant *Mask = llvm::ConstantInt::get(VMContext,
+ llvm::APInt::getLowBitsSet(EltTySize, BitfieldSize));
NewVal = Builder.CreateAnd(NewVal, Mask, "bf.value");
// Return the new value of the bit-field, if requested.
@@ -517,61 +545,60 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst,
unsigned SrcTySize = CGM.getTargetData().getTypeSizeInBits(SrcTy);
llvm::Value *ExtraBits = llvm::ConstantInt::get(SrcTy,
SrcTySize - BitfieldSize);
- SrcTrunc = Builder.CreateAShr(Builder.CreateShl(SrcTrunc, ExtraBits),
+ 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.
+ // 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));
-
+ llvm::Constant *InvMask =
+ llvm::ConstantInt::get(VMContext,
+ ~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");
+ 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,
+ llvm::Value *HighPtr = Builder.CreateGEP(Ptr, llvm::ConstantInt::get(
+ llvm::Type::getInt32Ty(VMContext), 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));
-
+ llvm::Constant *InvMask =
+ llvm::ConstantInt::get(VMContext, ~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");
+ 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());
}
@@ -597,29 +624,29 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src,
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()) {
+
+ if (const VectorType *VTy = Ty->getAs<VectorType>()) {
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 and restore the vector mask since it is on the side
- // it will be stored.
+ // Use shuffle vector is the src and destination are the same number of
+ // elements and restore the vector mask since it is on the side it will be
+ // stored.
llvm::SmallVector<llvm::Constant*, 4> Mask(NumDstElts);
for (unsigned i = 0; i != NumSrcElts; ++i) {
unsigned InIdx = getAccessedFieldNo(i, Elts);
- Mask[InIdx] = llvm::ConstantInt::get(llvm::Type::Int32Ty, i);
+ Mask[InIdx] = llvm::ConstantInt::get(
+ llvm::Type::getInt32Ty(VMContext), i);
}
-
+
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) {
+ } 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
@@ -627,96 +654,153 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src,
llvm::SmallVector<llvm::Constant*, 4> ExtMask;
unsigned i;
for (i = 0; i != NumSrcElts; ++i)
- ExtMask.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, i));
+ ExtMask.push_back(llvm::ConstantInt::get(
+ llvm::Type::getInt32Ty(VMContext), i));
for (; i != NumDstElts; ++i)
- ExtMask.push_back(llvm::UndefValue::get(llvm::Type::Int32Ty));
+ ExtMask.push_back(llvm::UndefValue::get(
+ llvm::Type::getInt32Ty(VMContext)));
llvm::Value *ExtMaskV = llvm::ConstantVector::get(&ExtMask[0],
ExtMask.size());
- llvm::Value *ExtSrcVal =
+ 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));
+ Mask.push_back(llvm::ConstantInt::get(
+ llvm::Type::getInt32Ty(VMContext), 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);
+ Mask[Idx] = llvm::ConstantInt::get(
+ llvm::Type::getInt32Ty(VMContext), i+NumDstElts);
}
llvm::Value *MaskV = llvm::ConstantVector::get(&Mask[0], Mask.size());
Vec = Builder.CreateShuffleVector(Vec, ExtSrcVal, MaskV, "tmp");
- }
- else {
+ } 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);
+ llvm::Value *Elt = llvm::ConstantInt::get(
+ llvm::Type::getInt32Ty(VMContext), InIdx);
Vec = Builder.CreateInsertElement(Vec, SrcVal, Elt, "tmp");
}
-
+
Builder.CreateStore(Vec, Dst.getExtVectorAddr(), Dst.isVolatileQualified());
}
+// setObjCGCLValueClass - sets class of he lvalue for the purpose of
+// generating write-barries API. It is currently a global, ivar,
+// or neither.
+static
+void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E, LValue &LV) {
+ if (Ctx.getLangOptions().getGCMode() == LangOptions::NonGC)
+ return;
+
+ if (isa<ObjCIvarRefExpr>(E)) {
+ LV.SetObjCIvar(LV, true);
+ ObjCIvarRefExpr *Exp = cast<ObjCIvarRefExpr>(const_cast<Expr*>(E));
+ LV.setBaseIvarExp(Exp->getBase());
+ LV.SetObjCArray(LV, E->getType()->isArrayType());
+ return;
+ }
+ if (const DeclRefExpr *Exp = dyn_cast<DeclRefExpr>(E)) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(Exp->getDecl())) {
+ if ((VD->isBlockVarDecl() && !VD->hasLocalStorage()) ||
+ VD->isFileVarDecl())
+ LV.SetGlobalObjCRef(LV, true);
+ }
+ LV.SetObjCArray(LV, E->getType()->isArrayType());
+ }
+ else if (const UnaryOperator *Exp = dyn_cast<UnaryOperator>(E))
+ setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV);
+ else if (const ParenExpr *Exp = dyn_cast<ParenExpr>(E)) {
+ setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV);
+ if (LV.isObjCIvar()) {
+ // If cast is to a structure pointer, follow gcc's behavior and make it
+ // a non-ivar write-barrier.
+ QualType ExpTy = E->getType();
+ if (ExpTy->isPointerType())
+ ExpTy = ExpTy->getAs<PointerType>()->getPointeeType();
+ if (ExpTy->isRecordType())
+ LV.SetObjCIvar(LV, false);
+ }
+ }
+ else if (const ImplicitCastExpr *Exp = dyn_cast<ImplicitCastExpr>(E))
+ setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV);
+ else if (const CStyleCastExpr *Exp = dyn_cast<CStyleCastExpr>(E))
+ setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV);
+ else if (const ArraySubscriptExpr *Exp = dyn_cast<ArraySubscriptExpr>(E)) {
+ setObjCGCLValueClass(Ctx, Exp->getBase(), LV);
+ if (LV.isObjCIvar() && !LV.isObjCArray())
+ // Using array syntax to assigning to what an ivar points to is not
+ // same as assigning to the ivar itself. {id *Names;} Names[i] = 0;
+ LV.SetObjCIvar(LV, false);
+ else if (LV.isGlobalObjCRef() && !LV.isObjCArray())
+ // Using array syntax to assigning to what global points to is not
+ // same as assigning to the global itself. {id *G;} G[i] = 0;
+ LV.SetGlobalObjCRef(LV, false);
+ }
+ else if (const MemberExpr *Exp = dyn_cast<MemberExpr>(E)) {
+ setObjCGCLValueClass(Ctx, Exp->getBase(), LV);
+ // We don't know if member is an 'ivar', but this flag is looked at
+ // only in the context of LV.isObjCIvar().
+ LV.SetObjCArray(LV, E->getType()->isArrayType());
+ }
+}
+
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() &&
+ 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 {
+ LV = LValue::MakeAddr(V, MakeQualifiers(E->getType()));
+ } else {
llvm::Value *V = LocalDeclMap[VD];
assert(V && "DeclRefExpr not entered in LocalDeclMap?");
+
+ Qualifiers Quals = MakeQualifiers(E->getType());
// local variables do not get their gc attribute set.
- QualType::GCAttrTypes attr = QualType::GCNone;
// local static?
- if (!NonGCable)
- attr = getContext().getObjCGCAttrKind(E->getType());
+ if (NonGCable) Quals.removeObjCGCAttr();
+
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");
+ V = Builder.CreateStructGEP(V, getByRefValueLLVMField(VD),
+ VD->getNameAsString());
}
if (VD->getType()->isReferenceType())
V = Builder.CreateLoad(V, "tmp");
- LV = LValue::MakeAddr(V, E->getType().getCVRQualifiers(), attr);
+ LV = LValue::MakeAddr(V, Quals);
}
LValue::SetObjCNonGC(LV, NonGCable);
+ setObjCGCLValueClass(getContext(), E, LV);
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);
+ LValue LV = LValue::MakeAddr(V, MakeQualifiers(E->getType()));
+ setObjCGCLValueClass(getContext(), E, LV);
return LV;
} else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(E->getDecl())) {
- llvm::Value* V = CGM.GetAddrOfFunction(GlobalDecl(FD));
+ llvm::Value* V = CGM.GetAddrOfFunction(FD);
if (!FD->hasPrototype()) {
if (const FunctionProtoType *Proto =
- FD->getType()->getAsFunctionProtoType()) {
+ FD->getType()->getAs<FunctionProtoType>()) {
// 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.
@@ -726,15 +810,12 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
V = Builder.CreateBitCast(V, ConvertType(NoProtoType), "tmp");
}
}
- return LValue::MakeAddr(V, E->getType().getCVRQualifiers(),
- getContext().getObjCGCAttrKind(E->getType()));
- }
- else if (const ImplicitParamDecl *IPD =
+ return LValue::MakeAddr(V, MakeQualifiers(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()));
+ return LValue::MakeAddr(V, MakeQualifiers(E->getType()));
}
assert(0 && "Unimp declref");
//an invalid LValue, but the assert will
@@ -743,27 +824,26 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
}
LValue CodeGenFunction::EmitBlockDeclRefLValue(const BlockDeclRefExpr *E) {
- return LValue::MakeAddr(GetAddrOfBlockDecl(E),
- E->getType().getCVRQualifiers(),
- getContext().getObjCGCAttrKind(E->getType()));
+ return LValue::MakeAddr(GetAddrOfBlockDecl(E), MakeQualifiers(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));
+ QualType T = E->getSubExpr()->getType()->getPointeeType();
+ assert(!T.isNull() && "CodeGenFunction::EmitUnaryOpLValue: Illegal type");
+
+ Qualifiers Quals = MakeQualifiers(T);
+ Quals.setAddressSpace(ExprTy.getAddressSpace());
+
+ LValue LV = LValue::MakeAddr(EmitScalarExpr(E->getSubExpr()), Quals);
// 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
@@ -780,16 +860,18 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) {
unsigned Idx = E->getOpcode() == UnaryOperator::Imag;
return LValue::MakeAddr(Builder.CreateStructGEP(LV.getAddress(),
Idx, "idx"),
- ExprTy.getCVRQualifiers());
+ MakeQualifiers(ExprTy));
}
}
LValue CodeGenFunction::EmitStringLiteralLValue(const StringLiteral *E) {
- return LValue::MakeAddr(CGM.GetAddrOfConstantStringFromLiteral(E), 0);
+ return LValue::MakeAddr(CGM.GetAddrOfConstantStringFromLiteral(E),
+ Qualifiers());
}
LValue CodeGenFunction::EmitObjCEncodeExprLValue(const ObjCEncodeExpr *E) {
- return LValue::MakeAddr(CGM.GetAddrOfConstantStringFromObjCEncode(E), 0);
+ return LValue::MakeAddr(CGM.GetAddrOfConstantStringFromObjCEncode(E),
+ Qualifiers());
}
@@ -806,32 +888,25 @@ LValue CodeGenFunction::EmitPredefinedFunctionName(unsigned Type) {
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);
- }
+ llvm::StringRef FnName = CurFn->getName();
+ if (FnName.startswith("\01"))
+ FnName = FnName.substr(1);
+ GlobalVarName += FnName;
- GlobalVarName += FunctionName;
- llvm::Constant *C =
+ std::string FunctionName =
+ PredefinedExpr::ComputeName(getContext(), (PredefinedExpr::IdentType)Type,
+ CurCodeDecl);
+
+ llvm::Constant *C =
CGM.GetAddrOfConstantCString(FunctionName, GlobalVarName.c_str());
- return LValue::MakeAddr(C, 0);
+ return LValue::MakeAddr(C, Qualifiers());
}
-LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) {
+LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) {
switch (E->getIdentType()) {
default:
return EmitUnsupportedLValue(E, "predefined expression");
@@ -854,68 +929,78 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
// Emit the vector as an lvalue to get its address.
LValue LHS = EmitLValue(E->getBase());
assert(LHS.isSimple() && "Can only subscript lvalue vectors here!");
- Idx = Builder.CreateIntCast(Idx, llvm::Type::Int32Ty, IdxSigned, "vidx");
+ Idx = Builder.CreateIntCast(Idx,
+ llvm::Type::getInt32Ty(VMContext), IdxSigned, "vidx");
return LValue::MakeVectorElt(LHS.getAddress(), Idx,
- E->getBase()->getType().getCVRQualifiers());
+ 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.
unsigned IdxBitwidth = cast<llvm::IntegerType>(Idx->getType())->getBitWidth();
if (IdxBitwidth != LLVMPointerWidth)
- Idx = Builder.CreateIntCast(Idx, llvm::IntegerType::get(LLVMPointerWidth),
+ Idx = Builder.CreateIntCast(Idx,
+ llvm::IntegerType::get(VMContext, 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.
+ // 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 =
+ if (const VariableArrayType *VAT =
getContext().getAsVariableArrayType(E->getType())) {
- llvm::Value *VLASize = VLASizeMap[VAT];
-
+ llvm::Value *VLASize = GetVLASize(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(),
+ llvm::ConstantInt::get(Idx->getType(),
BaseTypeSize));
- Address = Builder.CreateGEP(Base, Idx, "arrayidx");
- } else if (const ObjCInterfaceType *OIT =
+ Address = Builder.CreateInBoundsGEP(Base, Idx, "arrayidx");
+ } else if (const ObjCInterfaceType *OIT =
dyn_cast<ObjCInterfaceType>(E->getType())) {
- llvm::Value *InterfaceSize =
+ 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),
+ const llvm::Type *i8PTy = llvm::Type::getInt8PtrTy(VMContext);
+ Address = Builder.CreateGEP(Builder.CreateBitCast(Base, i8PTy),
Idx, "arrayidx");
Address = Builder.CreateBitCast(Address, Base->getType());
} else {
- Address = Builder.CreateGEP(Base, Idx, "arrayidx");
+ Address = Builder.CreateInBoundsGEP(Base, Idx, "arrayidx");
}
-
- QualType T = E->getBase()->getType()->getAsPointerType()->getPointeeType();
- LValue LV = LValue::MakeAddr(Address,
- T.getCVRQualifiers(),
- getContext().getObjCGCAttrKind(T));
+
+ QualType T = E->getBase()->getType()->getPointeeType();
+ assert(!T.isNull() &&
+ "CodeGenFunction::EmitArraySubscriptExpr(): Illegal base type");
+
+ Qualifiers Quals = MakeQualifiers(T);
+ Quals.setAddressSpace(E->getBase()->getType().getAddressSpace());
+
+ LValue LV = LValue::MakeAddr(Address, Quals);
if (getContext().getLangOptions().ObjC1 &&
- getContext().getLangOptions().getGCMode() != LangOptions::NonGC)
+ getContext().getLangOptions().getGCMode() != LangOptions::NonGC) {
LValue::SetObjCNonGC(LV, !E->isOBJCGCCandidate(getContext()));
+ setObjCGCLValueClass(getContext(), E, LV);
+ }
return LV;
}
-static
-llvm::Constant *GenerateConstantVector(llvm::SmallVector<unsigned, 4> &Elts) {
+static
+llvm::Constant *GenerateConstantVector(llvm::LLVMContext &VMContext,
+ 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]));
+ CElts.push_back(llvm::ConstantInt::get(
+ llvm::Type::getInt32Ty(VMContext), Elts[i]));
return llvm::ConstantVector::get(&CElts[0], CElts.size());
}
@@ -930,9 +1015,11 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) {
assert(E->getBase()->getType()->isVectorType());
Base = EmitLValue(E->getBase());
} else {
- const PointerType *PT = E->getBase()->getType()->getAsPointerType();
+ const PointerType *PT = E->getBase()->getType()->getAs<PointerType>();
llvm::Value *Ptr = EmitScalarExpr(E->getBase());
- Base = LValue::MakeAddr(Ptr, PT->getPointeeType().getCVRQualifiers());
+ Qualifiers Quals = MakeQualifiers(PT->getPointeeType());
+ Quals.removeObjCGCAttr();
+ Base = LValue::MakeAddr(Ptr, Quals);
}
// Encode the element access list into a vector of unsigned indices.
@@ -940,9 +1027,9 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) {
E->getEncodedElementAccess(Indices);
if (Base.isSimple()) {
- llvm::Constant *CV = GenerateConstantVector(Indices);
+ llvm::Constant *CV = GenerateConstantVector(VMContext, Indices);
return LValue::MakeExtVectorElt(Base.getAddress(), CV,
- Base.getQualifiers());
+ Base.getVRQualifiers());
}
assert(Base.isExtVectorElt() && "Can only subscript lvalue vec elts here!");
@@ -951,68 +1038,69 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) {
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));
+ CElts.push_back(llvm::ConstantInt::get(
+ llvm::Type::getInt32Ty(VMContext), 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());
+ Base.getVRQualifiers());
}
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;
+ Qualifiers BaseQuals;
// 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();
+ const PointerType *PTy =
+ BaseExpr->getType()->getAs<PointerType>();
if (PTy->getPointeeType()->isUnionType())
isUnion = true;
- CVRQualifiers = PTy->getPointeeType().getCVRQualifiers();
- } else if (isa<ObjCPropertyRefExpr>(BaseExpr) ||
- isa<ObjCKVCRefExpr>(BaseExpr)) {
+ BaseQuals = PTy->getPointeeType().getQualifiers();
+ } else if (isa<ObjCPropertyRefExpr>(BaseExpr->IgnoreParens()) ||
+ isa<ObjCImplicitSetterGetterRefExpr>(
+ BaseExpr->IgnoreParens())) {
RValue RV = EmitObjCPropertyGet(BaseExpr);
BaseValue = RV.getAggregateAddr();
if (BaseExpr->getType()->isUnionType())
isUnion = true;
- CVRQualifiers = BaseExpr->getType().getCVRQualifiers();
+ BaseQuals = BaseExpr->getType().getQualifiers();
} 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())
+ QualType BaseTy = BaseExpr->getType();
+ if (BaseTy->isUnionType())
isUnion = true;
- CVRQualifiers = BaseExpr->getType().getCVRQualifiers();
+ BaseQuals = BaseTy.getQualifiers();
}
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);
+ BaseQuals.getCVRQualifiers());
LValue::SetObjCNonGC(MemExpLV, isNonGC);
+ setObjCGCLValueClass(getContext(), E, MemExpLV);
return MemExpLV;
}
LValue CodeGenFunction::EmitLValueForBitfield(llvm::Value* BaseValue,
FieldDecl* Field,
unsigned CVRQualifiers) {
- unsigned idx = CGM.getTypes().getLLVMFieldNo(Field);
+ CodeGenTypes::BitFieldInfo Info = CGM.getTypes().getBitFieldInfo(Field);
+
// FIXME: CodeGenTypes should expose a method to get the appropriate type for
// FieldTy (the appropriate type is ABI-dependent).
- const llvm::Type *FieldTy =
+ const llvm::Type *FieldTy =
CGM.getTypes().ConvertTypeForMem(Field->getType());
const llvm::PointerType *BaseTy =
cast<llvm::PointerType>(BaseValue->getType());
@@ -1020,13 +1108,12 @@ LValue CodeGenFunction::EmitLValueForBitfield(llvm::Value* BaseValue,
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,
+
+ llvm::Value *Idx =
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), Info.FieldNo);
+ llvm::Value *V = Builder.CreateGEP(BaseValue, Idx, "tmp");
+
+ return LValue::MakeBitfield(V, Info.Start, Info.Size,
Field->getType()->isSignedIntegerType(),
Field->getType().getCVRQualifiers()|CVRQualifiers);
}
@@ -1034,46 +1121,34 @@ LValue CodeGenFunction::EmitLValueForBitfield(llvm::Value* BaseValue,
LValue CodeGenFunction::EmitLValueForField(llvm::Value* BaseValue,
FieldDecl* Field,
bool isUnion,
- unsigned CVRQualifiers)
-{
+ 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 =
+ const llvm::Type *FieldTy =
CGM.getTypes().ConvertTypeForMem(Field->getType());
- const llvm::PointerType * BaseTy =
+ const llvm::PointerType * BaseTy =
cast<llvm::PointerType>(BaseValue->getType());
unsigned AS = BaseTy->getAddressSpace();
- V = Builder.CreateBitCast(V,
- llvm::PointerType::get(FieldTy, AS),
+ 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;
+ Qualifiers Quals = MakeQualifiers(Field->getType());
+ Quals.addCVRQualifiers(CVRQualifiers);
+ // __weak attribute on a field is ignored.
+ if (Quals.getObjCGCAttr() == Qualifiers::Weak)
+ Quals.removeObjCGCAttr();
+
+ return LValue::MakeAddr(V, Quals);
}
LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr* E){
@@ -1081,7 +1156,7 @@ LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr* E){
llvm::Value *DeclPtr = CreateTempAlloca(LTy, ".compoundliteral");
const Expr* InitExpr = E->getInitializer();
- LValue Result = LValue::MakeAddr(DeclPtr, E->getType().getCVRQualifiers());
+ LValue Result = LValue::MakeAddr(DeclPtr, MakeQualifiers(E->getType()));
if (E->getType()->isComplexType()) {
EmitComplexExprIntoAddr(InitExpr, DeclPtr, false);
@@ -1094,22 +1169,51 @@ LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr* E){
return Result;
}
-LValue CodeGenFunction::EmitConditionalOperator(const ConditionalOperator* E) {
- // We don't handle vectors yet.
- if (E->getType()->isVectorType())
- return EmitUnsupportedLValue(E, "conditional operator");
+LValue
+CodeGenFunction::EmitConditionalOperatorLValue(const ConditionalOperator* E) {
+ if (E->isLvalue(getContext()) == Expr::LV_Valid) {
+ llvm::BasicBlock *LHSBlock = createBasicBlock("cond.true");
+ llvm::BasicBlock *RHSBlock = createBasicBlock("cond.false");
+ llvm::BasicBlock *ContBlock = createBasicBlock("cond.end");
+
+ llvm::Value *Cond = EvaluateExprAsBool(E->getCond());
+ Builder.CreateCondBr(Cond, LHSBlock, RHSBlock);
+
+ EmitBlock(LHSBlock);
+
+ LValue LHS = EmitLValue(E->getLHS());
+ if (!LHS.isSimple())
+ return EmitUnsupportedLValue(E, "conditional operator");
+
+ llvm::Value *Temp = CreateTempAlloca(LHS.getAddress()->getType(),
+ "condtmp");
+
+ Builder.CreateStore(LHS.getAddress(), Temp);
+ EmitBranch(ContBlock);
+
+ EmitBlock(RHSBlock);
+ LValue RHS = EmitLValue(E->getRHS());
+ if (!RHS.isSimple())
+ return EmitUnsupportedLValue(E, "conditional operator");
+
+ Builder.CreateStore(RHS.getAddress(), Temp);
+ EmitBranch(ContBlock);
+ EmitBlock(ContBlock);
+
+ Temp = Builder.CreateLoad(Temp, "lv");
+ return LValue::MakeAddr(Temp, MakeQualifiers(E->getType()));
+ }
+
// ?: here should be an aggregate.
- assert((hasAggregateLLVMType(E->getType()) &&
+ 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()));
-
+ return LValue::MakeAddr(Temp, MakeQualifiers(E->getType()));
}
/// EmitCastLValue - Casts are never lvalues. If a cast is needed by the code
@@ -1118,21 +1222,47 @@ LValue CodeGenFunction::EmitConditionalOperator(const ConditionalOperator* E) {
/// 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()))
+ switch (E->getCastKind()) {
+ default:
+ // If this is an lvalue cast, treat it as a no-op.
+ // FIXME: We shouldn't need to check for this explicitly!
+ if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E))
+ if (ICE->isLvalueCast())
+ return EmitLValue(E->getSubExpr());
+
+ assert(0 && "Unhandled cast!");
+
+ case CastExpr::CK_NoOp:
+ case CastExpr::CK_ConstructorConversion:
+ case CastExpr::CK_UserDefinedConversion:
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()));
+ case CastExpr::CK_DerivedToBase: {
+ const RecordType *DerivedClassTy =
+ E->getSubExpr()->getType()->getAs<RecordType>();
+ CXXRecordDecl *DerivedClassDecl =
+ cast<CXXRecordDecl>(DerivedClassTy->getDecl());
+
+ const RecordType *BaseClassTy = E->getType()->getAs<RecordType>();
+ CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseClassTy->getDecl());
+
+ LValue LV = EmitLValue(E->getSubExpr());
+
+ // Perform the derived-to-base conversion
+ llvm::Value *Base =
+ GetAddressCXXOfBaseClass(LV.getAddress(), DerivedClassDecl,
+ BaseClassDecl, /*NullCheckValue=*/false);
+
+ return LValue::MakeAddr(Base, MakeQualifiers(E->getType()));
+ }
+
+ case CastExpr::CK_ToUnion: {
+ llvm::Value *Temp = CreateTempAlloca(ConvertType(E->getType()));
+ EmitAnyExpr(E->getSubExpr(), Temp, false);
+
+ return LValue::MakeAddr(Temp, MakeQualifiers(E->getType()));
+ }
+ }
}
//===--------------------------------------------------------------------===//
@@ -1147,13 +1277,13 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *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()))
+ if (unsigned builtinID = FD->getBuiltinID())
return EmitBuiltinExpr(FD, builtinID, E);
}
}
@@ -1161,7 +1291,17 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E) {
if (const CXXOperatorCallExpr *CE = dyn_cast<CXXOperatorCallExpr>(E))
if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(TargetDecl))
return EmitCXXOperatorMemberCallExpr(CE, MD);
-
+
+ if (isa<CXXPseudoDestructorExpr>(E->getCallee())) {
+ // C++ [expr.pseudo]p1:
+ // The result shall only be used as the operand for the function call
+ // operator (), and the result of such a call has type void. The only
+ // effect is the evaluation of the postfix-expression before the dot or
+ // arrow.
+ EmitScalarExpr(E->getCallee());
+ return RValue::get(0);
+ }
+
llvm::Value *Callee = EmitScalarExpr(E->getCallee());
return EmitCall(Callee, E->getCallee()->getType(),
E->arg_begin(), E->arg_end(), TargetDecl);
@@ -1173,7 +1313,7 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) {
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)
@@ -1182,8 +1322,7 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) {
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()));
+ return LValue::MakeAddr(Temp, MakeQualifiers(E->getType()));
}
LValue CodeGenFunction::EmitCallExprLValue(const CallExpr *E) {
@@ -1193,21 +1332,18 @@ LValue CodeGenFunction::EmitCallExprLValue(const CallExpr *E) {
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.getScalarVal(), MakeQualifiers(E->getType()));
}
-
- return LValue::MakeAddr(RV.getAggregateAddr(),
- E->getType().getCVRQualifiers(),
- getContext().getObjCGCAttrKind(E->getType()));
+
+ return LValue::MakeAddr(RV.getAggregateAddr(), MakeQualifiers(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());
+ return LValue::MakeAddr(Temp, MakeQualifiers(E->getType()));
}
LValue
@@ -1219,15 +1355,15 @@ CodeGenFunction::EmitCXXConditionDeclLValue(const CXXConditionDeclExpr *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());
+ return LValue::MakeAddr(Temp, MakeQualifiers(E->getType()));
}
LValue
CodeGenFunction::EmitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *E) {
LValue LV = EmitLValue(E->getSubExpr());
-
+
PushCXXTemporary(E->getTemporary(), LV.getAddress());
-
+
return LV;
}
@@ -1235,9 +1371,7 @@ 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()));
+ return LValue::MakeAddr(RV.getAggregateAddr(), MakeQualifiers(E->getType()));
}
llvm::Value *CodeGenFunction::EmitIvarOffset(const ObjCInterfaceDecl *Interface,
@@ -1257,35 +1391,39 @@ 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;
+ Qualifiers BaseQuals;
QualType ObjectTy;
if (E->isArrow()) {
BaseValue = EmitScalarExpr(BaseExpr);
- const PointerType *PTy = BaseExpr->getType()->getAsPointerType();
- ObjectTy = PTy->getPointeeType();
- CVRQualifiers = ObjectTy.getCVRQualifiers();
+ ObjectTy = BaseExpr->getType()->getPointeeType();
+ BaseQuals = ObjectTy.getQualifiers();
} else {
LValue BaseLV = EmitLValue(BaseExpr);
// FIXME: this isn't right for bitfields.
BaseValue = BaseLV.getAddress();
ObjectTy = BaseExpr->getType();
- CVRQualifiers = ObjectTy.getCVRQualifiers();
+ BaseQuals = ObjectTy.getQualifiers();
}
- return EmitLValueForIvar(ObjectTy, BaseValue, E->getDecl(), CVRQualifiers);
+ LValue LV =
+ EmitLValueForIvar(ObjectTy, BaseValue, E->getDecl(),
+ BaseQuals.getCVRQualifiers());
+ setObjCGCLValueClass(getContext(), E, LV);
+ return LV;
}
-LValue
+LValue
CodeGenFunction::EmitObjCPropertyRefLValue(const ObjCPropertyRefExpr *E) {
- // This is a special l-value that just issues sends when we load or
- // store through it.
+ // 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.
+LValue
+CodeGenFunction::EmitObjCKVCRefLValue(
+ const ObjCImplicitSetterGetterRefExpr *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());
}
@@ -1295,31 +1433,36 @@ CodeGenFunction::EmitObjCSuperExprLValue(const ObjCSuperExpr *E) {
}
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()));
+ return LValue::MakeAddr(RV.getAggregateAddr(), MakeQualifiers(E->getType()));
}
-RValue CodeGenFunction::EmitCall(llvm::Value *Callee, QualType CalleeType,
+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() &&
+ // 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();
+ QualType FnType = CalleeType->getAs<PointerType>()->getPointeeType();
+ QualType ResultType = FnType->getAs<FunctionType>()->getResultType();
CallArgList Args;
- EmitCallArgs(Args, FnType->getAsFunctionProtoType(), ArgBeg, ArgEnd);
-
- return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args),
+ EmitCallArgs(Args, FnType->getAs<FunctionProtoType>(), ArgBeg, ArgEnd);
+
+ // FIXME: We should not need to do this, it should be part of the function
+ // type.
+ unsigned CallingConvention = 0;
+ if (const llvm::Function *F =
+ dyn_cast<llvm::Function>(Callee->stripPointerCasts()))
+ CallingConvention = F->getCallingConv();
+ return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args,
+ CallingConvention),
Callee, Args, TargetDecl);
}
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index 412a065..0866ff8 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -13,6 +13,7 @@
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
+#include "CGObjCRuntime.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/StmtVisitor.h"
@@ -35,12 +36,14 @@ class VISIBILITY_HIDDEN AggExprEmitter : public StmtVisitor<AggExprEmitter> {
llvm::Value *DestPtr;
bool VolatileDest;
bool IgnoreResult;
-
+ bool IsInitializer;
+ bool RequiresGCollection;
public:
AggExprEmitter(CodeGenFunction &cgf, llvm::Value *destPtr, bool v,
- bool ignore)
+ bool ignore, bool isinit, bool requiresGCollection)
: CGF(cgf), Builder(CGF.Builder),
- DestPtr(destPtr), VolatileDest(v), IgnoreResult(ignore) {
+ DestPtr(destPtr), VolatileDest(v), IgnoreResult(ignore),
+ IsInitializer(isinit), RequiresGCollection(requiresGCollection) {
}
//===--------------------------------------------------------------------===//
@@ -59,7 +62,7 @@ public:
//===--------------------------------------------------------------------===//
// Visitor Methods
//===--------------------------------------------------------------------===//
-
+
void VisitStmt(Stmt *S) {
CGF.ErrorUnsupported(S, "aggregate expression");
}
@@ -72,35 +75,36 @@ public:
void VisitUnaryDeref(UnaryOperator *E) { EmitAggLoadOfLValue(E); }
void VisitStringLiteral(StringLiteral *E) { EmitAggLoadOfLValue(E); }
void VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
- EmitAggLoadOfLValue(E);
+ EmitAggLoadOfLValue(E);
}
void VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
EmitAggLoadOfLValue(E);
}
void VisitBlockDeclRefExpr(const BlockDeclRefExpr *E) {
- EmitAggLoadOfLValue(E);
+ EmitAggLoadOfLValue(E);
}
void VisitPredefinedExpr(const PredefinedExpr *E) {
- EmitAggLoadOfLValue(E);
+ EmitAggLoadOfLValue(E);
}
-
+
// Operators.
- void VisitCStyleCastExpr(CStyleCastExpr *E);
- void VisitImplicitCastExpr(ImplicitCastExpr *E);
+ void VisitCastExpr(CastExpr *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 VisitUnaryAddrOf(const UnaryOperator *E);
void VisitObjCMessageExpr(ObjCMessageExpr *E);
void VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
EmitAggLoadOfLValue(E);
}
void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E);
- void VisitObjCKVCRefExpr(ObjCKVCRefExpr *E);
-
+ void VisitObjCImplicitSetterGetterRefExpr(ObjCImplicitSetterGetterRefExpr *E);
+
void VisitConditionalOperator(const ConditionalOperator *CO);
+ void VisitChooseExpr(const ChooseExpr *CE);
void VisitInitListExpr(InitListExpr *E);
void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) {
Visit(DAE->getExpr());
@@ -143,6 +147,12 @@ void AggExprEmitter::EmitFinalDestCopy(const Expr *E, RValue Src, bool Ignore) {
DestPtr = CGF.CreateTempAlloca(CGF.ConvertType(E->getType()), "agg.tmp");
}
+ if (RequiresGCollection) {
+ CGF.CGM.getObjCRuntime().EmitGCMemmoveCollectable(CGF,
+ DestPtr, Src.getAggregateAddr(),
+ E->getType());
+ return;
+ }
// 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
@@ -164,25 +174,80 @@ void AggExprEmitter::EmitFinalDestCopy(const Expr *E, LValue Src, bool Ignore) {
// Visitor Methods
//===----------------------------------------------------------------------===//
-void AggExprEmitter::VisitCStyleCastExpr(CStyleCastExpr *E) {
- // GCC union extension
- if (E->getSubExpr()->getType()->isScalarType()) {
+void AggExprEmitter::VisitCastExpr(CastExpr *E) {
+ switch (E->getCastKind()) {
+ default: assert(0 && "Unhandled cast kind!");
+
+ case CastExpr::CK_ToUnion: {
+ // GCC union extension
QualType PtrTy =
- CGF.getContext().getPointerType(E->getSubExpr()->getType());
+ CGF.getContext().getPointerType(E->getSubExpr()->getType());
llvm::Value *CastPtr = Builder.CreateBitCast(DestPtr,
CGF.ConvertType(PtrTy));
- EmitInitializationToLValue(E->getSubExpr(), LValue::MakeAddr(CastPtr, 0));
- return;
+ EmitInitializationToLValue(E->getSubExpr(),
+ LValue::MakeAddr(CastPtr, Qualifiers()));
+ break;
}
- Visit(E->getSubExpr());
-}
+ // FIXME: Remove the CK_Unknown check here.
+ case CastExpr::CK_Unknown:
+ case CastExpr::CK_NoOp:
+ case CastExpr::CK_UserDefinedConversion:
+ case CastExpr::CK_ConstructorConversion:
+ assert(CGF.getContext().hasSameUnqualifiedType(E->getSubExpr()->getType(),
+ E->getType()) &&
+ "Implicit cast types must be compatible");
+ Visit(E->getSubExpr());
+ break;
+
+ case CastExpr::CK_NullToMemberPointer: {
+ const llvm::Type *PtrDiffTy =
+ CGF.ConvertType(CGF.getContext().getPointerDiffType());
-void AggExprEmitter::VisitImplicitCastExpr(ImplicitCastExpr *E) {
- assert(CGF.getContext().hasSameUnqualifiedType(E->getSubExpr()->getType(),
- E->getType()) &&
- "Implicit cast types must be compatible");
- Visit(E->getSubExpr());
+ llvm::Value *NullValue = llvm::Constant::getNullValue(PtrDiffTy);
+ llvm::Value *Ptr = Builder.CreateStructGEP(DestPtr, 0, "ptr");
+ Builder.CreateStore(NullValue, Ptr, VolatileDest);
+
+ llvm::Value *Adj = Builder.CreateStructGEP(DestPtr, 1, "adj");
+ Builder.CreateStore(NullValue, Adj, VolatileDest);
+
+ break;
+ }
+
+ case CastExpr::CK_BaseToDerivedMemberPointer: {
+ QualType SrcType = E->getSubExpr()->getType();
+
+ llvm::Value *Src = CGF.CreateTempAlloca(CGF.ConvertTypeForMem(SrcType),
+ "tmp");
+ CGF.EmitAggExpr(E->getSubExpr(), Src, SrcType.isVolatileQualified());
+
+ llvm::Value *SrcPtr = Builder.CreateStructGEP(Src, 0, "src.ptr");
+ SrcPtr = Builder.CreateLoad(SrcPtr);
+
+ llvm::Value *SrcAdj = Builder.CreateStructGEP(Src, 1, "src.adj");
+ SrcAdj = Builder.CreateLoad(SrcAdj);
+
+ llvm::Value *DstPtr = Builder.CreateStructGEP(DestPtr, 0, "dst.ptr");
+ Builder.CreateStore(SrcPtr, DstPtr, VolatileDest);
+
+ llvm::Value *DstAdj = Builder.CreateStructGEP(DestPtr, 1, "dst.adj");
+
+ // Now See if we need to update the adjustment.
+ const CXXRecordDecl *SrcDecl =
+ cast<CXXRecordDecl>(SrcType->getAs<MemberPointerType>()->
+ getClass()->getAs<RecordType>()->getDecl());
+ const CXXRecordDecl *DstDecl =
+ cast<CXXRecordDecl>(E->getType()->getAs<MemberPointerType>()->
+ getClass()->getAs<RecordType>()->getDecl());
+
+ llvm::Constant *Adj = CGF.CGM.GetCXXBaseClassOffset(DstDecl, SrcDecl);
+ if (Adj)
+ SrcAdj = Builder.CreateAdd(SrcAdj, Adj, "adj");
+
+ Builder.CreateStore(SrcAdj, DstAdj, VolatileDest);
+ break;
+ }
+ }
}
void AggExprEmitter::VisitCallExpr(const CallExpr *E) {
@@ -190,7 +255,7 @@ void AggExprEmitter::VisitCallExpr(const CallExpr *E) {
EmitAggLoadOfLValue(E);
return;
}
-
+
RValue RV = CGF.EmitCallExpr(E);
EmitFinalDestCopy(E, RV);
}
@@ -205,14 +270,49 @@ void AggExprEmitter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
EmitFinalDestCopy(E, RV);
}
-void AggExprEmitter::VisitObjCKVCRefExpr(ObjCKVCRefExpr *E) {
+void AggExprEmitter::VisitObjCImplicitSetterGetterRefExpr(
+ ObjCImplicitSetterGetterRefExpr *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);
+ CGF.EmitAggExpr(E->getRHS(), DestPtr, VolatileDest,
+ /*IgnoreResult=*/false, IsInitializer);
+}
+
+void AggExprEmitter::VisitUnaryAddrOf(const UnaryOperator *E) {
+ // We have a member function pointer.
+ const MemberPointerType *MPT = E->getType()->getAs<MemberPointerType>();
+ assert(MPT->getPointeeType()->isFunctionProtoType() &&
+ "Unexpected member pointer type!");
+
+ const QualifiedDeclRefExpr *DRE = cast<QualifiedDeclRefExpr>(E->getSubExpr());
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(DRE->getDecl());
+
+ const llvm::Type *PtrDiffTy =
+ CGF.ConvertType(CGF.getContext().getPointerDiffType());
+
+ llvm::Value *DstPtr = Builder.CreateStructGEP(DestPtr, 0, "dst.ptr");
+ llvm::Value *FuncPtr;
+
+ if (MD->isVirtual()) {
+ int64_t Index =
+ CGF.CGM.getVtableInfo().getMethodVtableIndex(MD);
+
+ FuncPtr = llvm::ConstantInt::get(PtrDiffTy, Index + 1);
+ } else {
+ FuncPtr = llvm::ConstantExpr::getPtrToInt(CGF.CGM.GetAddrOfFunction(MD),
+ PtrDiffTy);
+ }
+ Builder.CreateStore(FuncPtr, DstPtr, VolatileDest);
+
+ llvm::Value *AdjPtr = Builder.CreateStructGEP(DestPtr, 1, "dst.adj");
+
+ // The adjustment will always be 0.
+ Builder.CreateStore(llvm::ConstantInt::get(PtrDiffTy, 0), AdjPtr,
+ VolatileDest);
}
void AggExprEmitter::VisitStmtExpr(const StmtExpr *E) {
@@ -238,19 +338,25 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
if (!AggLoc)
AggLoc = CGF.CreateTempAlloca(CGF.ConvertType(E->getRHS()->getType()));
CGF.EmitAggExpr(E->getRHS(), AggLoc, VolatileDest);
- CGF.EmitObjCPropertySet(LHS.getPropertyRefExpr(),
+ CGF.EmitObjCPropertySet(LHS.getPropertyRefExpr(),
RValue::getAggregate(AggLoc, VolatileDest));
- }
- else if (LHS.isKVCRef()) {
+ } 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(),
+ CGF.EmitObjCPropertySet(LHS.getKVCRefExpr(),
RValue::getAggregate(AggLoc, VolatileDest));
} else {
+ bool RequiresGCollection = false;
+ if (CGF.getContext().getLangOptions().NeXTRuntime) {
+ QualType LHSTy = E->getLHS()->getType();
+ if (const RecordType *FDTTy = LHSTy.getTypePtr()->getAs<RecordType>())
+ RequiresGCollection = FDTTy->getDecl()->hasObjectMember();
+ }
// Codegen the RHS so that it stores directly into the LHS.
- CGF.EmitAggExpr(E->getRHS(), LHS.getAddress(), LHS.isVolatileQualified());
+ CGF.EmitAggExpr(E->getRHS(), LHS.getAddress(), LHS.isVolatileQualified(),
+ false, false, RequiresGCollection);
EmitFinalDestCopy(E, LHS, true);
}
}
@@ -259,30 +365,34 @@ 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.PushConditionalTempDestruction();
CGF.EmitBlock(LHSBlock);
-
+
// Handle the GNU extension for missing LHS.
assert(E->getLHS() && "Must have LHS for aggregate value");
Visit(E->getLHS());
CGF.PopConditionalTempDestruction();
CGF.EmitBranch(ContBlock);
-
+
CGF.PushConditionalTempDestruction();
CGF.EmitBlock(RHSBlock);
-
+
Visit(E->getRHS());
CGF.PopConditionalTempDestruction();
CGF.EmitBranch(ContBlock);
-
+
CGF.EmitBlock(ContBlock);
}
+void AggExprEmitter::VisitChooseExpr(const ChooseExpr *CE) {
+ Visit(CE->getChosenSubExpr(CGF.getContext()));
+}
+
void AggExprEmitter::VisitVAArgExpr(VAArgExpr *VE) {
llvm::Value *ArgValue = CGF.EmitVAListRef(VE->getSubExpr());
llvm::Value *ArgPtr = CGF.EmitVAArg(ArgValue, VE->getType());
@@ -292,28 +402,30 @@ void AggExprEmitter::VisitVAArgExpr(VAArgExpr *VE) {
return;
}
- EmitFinalDestCopy(VE, LValue::MakeAddr(ArgPtr, 0));
+ EmitFinalDestCopy(VE, LValue::MakeAddr(ArgPtr, Qualifiers()));
}
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
+ } else
Visit(E->getSubExpr());
-
- CGF.PushCXXTemporary(E->getTemporary(), Val);
+
+ // Don't make this a live temporary if we're emitting an initializer expr.
+ if (!IsInitializer)
+ 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");
@@ -323,7 +435,7 @@ AggExprEmitter::VisitCXXConstructExpr(const CXXConstructExpr *E) {
}
void AggExprEmitter::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E) {
- CGF.EmitCXXExprWithTemporaries(E, DestPtr, VolatileDest);
+ CGF.EmitCXXExprWithTemporaries(E, DestPtr, VolatileDest, IsInitializer);
}
void AggExprEmitter::EmitInitializationToLValue(Expr* E, LValue LV) {
@@ -359,7 +471,7 @@ void AggExprEmitter::EmitNullInitializationToLValue(LValue LV, QualType T) {
void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
#if 0
- // FIXME: Disabled while we figure out what to do about
+ // 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
@@ -387,7 +499,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
cast<llvm::PointerType>(DestPtr->getType());
const llvm::ArrayType *AType =
cast<llvm::ArrayType>(APType->getElementType());
-
+
uint64_t NumInitElements = E->getNumInits();
if (E->getNumInits() > 0) {
@@ -402,29 +514,30 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
uint64_t NumArrayElements = AType->getNumElements();
QualType ElementType = CGF.getContext().getCanonicalType(E->getType());
ElementType = CGF.getContext().getAsArrayType(ElementType)->getElementType();
-
- unsigned CVRqualifier = ElementType.getCVRQualifiers();
+
+ // FIXME: were we intentionally ignoring address spaces and GC attributes?
+ Qualifiers Quals = CGF.MakeQualifiers(ElementType);
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));
+ LValue::MakeAddr(NextVal, Quals));
else
- EmitNullInitializationToLValue(LValue::MakeAddr(NextVal, CVRqualifier),
+ EmitNullInitializationToLValue(LValue::MakeAddr(NextVal, Quals),
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();
+ RecordDecl *SD = E->getType()->getAs<RecordType>()->getDecl();
unsigned CurInitVal = 0;
if (E->getType()->isUnionType()) {
@@ -432,7 +545,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
// 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.
@@ -458,7 +571,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
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(),
@@ -494,13 +607,16 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
/// 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) {
+ bool VolatileDest, bool IgnoreResult,
+ bool IsInitializer,
+ bool RequiresGCollection) {
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)
+
+ AggExprEmitter(*this, DestPtr, VolatileDest, IgnoreResult, IsInitializer,
+ RequiresGCollection)
.Visit(const_cast<Expr*>(E));
}
@@ -514,7 +630,7 @@ 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
@@ -525,18 +641,19 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr,
// 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);
+ const llvm::Type *BP = llvm::Type::getInt8PtrTy(VMContext);
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);
-
+ const llvm::Type *IntPtr =
+ llvm::IntegerType::get(VMContext, LLVMPointerWidth);
+
// FIXME: If we have a volatile struct, the optimizer can remove what might
// appear to be `extra' memory ops:
//
@@ -553,6 +670,6 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr,
DestPtr, SrcPtr,
// TypeInfo.first describes size in bits.
llvm::ConstantInt::get(IntPtr, TypeInfo.first/8),
- llvm::ConstantInt::get(llvm::Type::Int32Ty,
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
TypeInfo.second/8));
}
diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp
index 3555c8c..9e81e4f 100644
--- a/lib/CodeGen/CGExprComplex.cpp
+++ b/lib/CodeGen/CGExprComplex.cpp
@@ -46,7 +46,7 @@ public:
IgnoreRealAssign(irn), IgnoreImagAssign(iin) {
}
-
+
//===--------------------------------------------------------------------===//
// Utilities
//===--------------------------------------------------------------------===//
@@ -82,23 +82,23 @@ public:
if (LV.isPropertyRef())
return CGF.EmitObjCPropertyGet(LV.getPropertyRefExpr()).getComplexVal();
-
+
assert(LV.isKVCRef() && "Unknown LValue type!");
return CGF.EmitObjCPropertyGet(LV.getKVCRefExpr()).getComplexVal();
}
-
+
/// 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
//===--------------------------------------------------------------------===//
@@ -111,16 +111,17 @@ public:
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 VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
+ ComplexPairTy VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
return EmitLoadOfLValue(E);
}
ComplexPairTy VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
return EmitLoadOfLValue(E);
}
- ComplexPairTy VisitObjCKVCRefExpr(ObjCKVCRefExpr *E) {
+ ComplexPairTy VisitObjCImplicitSetterGetterRefExpr(
+ ObjCImplicitSetterGetterRefExpr *E) {
return EmitLoadOfLValue(E);
}
ComplexPairTy VisitObjCMessageExpr(ObjCMessageExpr *E) {
@@ -130,7 +131,7 @@ public:
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
@@ -180,23 +181,24 @@ public:
}
ComplexPairTy VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) {
assert(E->getType()->isAnyComplexType() && "Expected complex type!");
- QualType Elem = E->getType()->getAsComplexType()->getElementType();
+ QualType Elem = E->getType()->getAs<ComplexType>()->getElementType();
llvm::Constant *Null = llvm::Constant::getNullValue(CGF.ConvertType(Elem));
return ComplexPairTy(Null, Null);
}
ComplexPairTy VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) {
assert(E->getType()->isAnyComplexType() && "Expected complex type!");
- QualType Elem = E->getType()->getAsComplexType()->getElementType();
- llvm::Constant *Null = llvm::Constant::getNullValue(CGF.ConvertType(Elem));
+ QualType Elem = E->getType()->getAs<ComplexType>()->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)
@@ -206,7 +208,7 @@ public:
ComplexPairTy EmitBinSub(const BinOpInfo &Op);
ComplexPairTy EmitBinMul(const BinOpInfo &Op);
ComplexPairTy EmitBinDiv(const BinOpInfo &Op);
-
+
ComplexPairTy VisitBinMul(const BinaryOperator *E) {
return EmitBinMul(EmitBinOps(E));
}
@@ -219,7 +221,7 @@ public:
ComplexPairTy VisitBinDiv(const BinaryOperator *E) {
return EmitBinDiv(EmitBinOps(E));
}
-
+
// Compound assignments.
ComplexPairTy VisitBinAddAssign(const CompoundAssignOperator *E) {
return EmitCompoundAssign(E, &ComplexExprEmitter::EmitBinAdd);
@@ -233,7 +235,7 @@ public:
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.
@@ -241,7 +243,7 @@ public:
ComplexPairTy VisitBinAssign (const BinaryOperator *E);
ComplexPairTy VisitBinComma (const BinaryOperator *E);
-
+
ComplexPairTy VisitConditionalOperator(const ConditionalOperator *CO);
ComplexPairTy VisitChooseExpr(ChooseExpr *CE);
@@ -259,27 +261,34 @@ public:
/// 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::SmallString<64> Name(SrcPtr->getName().begin(),
+ SrcPtr->getName().end());
+
llvm::Value *Real=0, *Imag=0;
if (!IgnoreReal) {
+ // FIXME: Clean this up once builder takes Twine/StringRef.
Name += ".realp";
- llvm::Value *RealPtr = Builder.CreateStructGEP(SrcPtr, 0, Name.c_str());
+ llvm::Value *RealPtr = Builder.CreateStructGEP(SrcPtr, 0,
+ Name.str().str().c_str());
Name.pop_back(); // .realp -> .real
- Real = Builder.CreateLoad(RealPtr, isVolatile, Name.c_str());
+ // FIXME: Clean this up once builder takes Twine/StringRef.
+ Real = Builder.CreateLoad(RealPtr, isVolatile,
+ Name.str().str().c_str());
Name.resize(Name.size()-4); // .real -> .imagp
}
-
+
if (!IgnoreImag) {
Name += "imagp";
-
- llvm::Value *ImagPtr = Builder.CreateStructGEP(SrcPtr, 1, Name.c_str());
+
+ // FIXME: Clean this up once builder takes Twine/StringRef.
+ llvm::Value *ImagPtr = Builder.CreateStructGEP(SrcPtr, 1,
+ Name.str().str().c_str());
Name.pop_back(); // .imagp -> .imag
- Imag = Builder.CreateLoad(ImagPtr, isVolatile, Name.c_str());
+ // FIXME: Clean this up once builder takes Twine/StringRef.
+ Imag = Builder.CreateLoad(ImagPtr, isVolatile, Name.str().str().c_str());
}
return ComplexPairTy(Real, Imag);
}
@@ -290,7 +299,7 @@ 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);
}
@@ -303,8 +312,8 @@ void ComplexExprEmitter::EmitStoreOfComplex(ComplexPairTy Val, llvm::Value *Ptr,
ComplexPairTy ComplexExprEmitter::VisitExpr(Expr *E) {
CGF.ErrorUnsupported(E, "complex expression");
- const llvm::Type *EltTy =
- CGF.ConvertType(E->getType()->getAsComplexType()->getElementType());
+ const llvm::Type *EltTy =
+ CGF.ConvertType(E->getType()->getAs<ComplexType>()->getElementType());
llvm::Value *U = llvm::UndefValue::get(EltTy);
return ComplexPairTy(U, U);
}
@@ -312,7 +321,8 @@ ComplexPairTy ComplexExprEmitter::VisitExpr(Expr *E) {
ComplexPairTy ComplexExprEmitter::
VisitImaginaryLiteral(const ImaginaryLiteral *IL) {
llvm::Value *Imag = CGF.EmitScalarExpr(IL->getSubExpr());
- return ComplexPairTy(llvm::Constant::getNullValue(Imag->getType()), Imag);
+ return
+ ComplexPairTy(llvm::Constant::getNullValue(Imag->getType()), Imag);
}
@@ -332,8 +342,8 @@ ComplexPairTy ComplexExprEmitter::EmitComplexToComplexCast(ComplexPairTy Val,
QualType SrcType,
QualType DestType) {
// Get the src/dest element type.
- SrcType = SrcType->getAsComplexType()->getElementType();
- DestType = DestType->getAsComplexType()->getElementType();
+ SrcType = SrcType->getAs<ComplexType>()->getElementType();
+ DestType = DestType->getAs<ComplexType>()->getElementType();
// C99 6.3.1.6: When a value of complex type is converted to another
// complex type, both the real and imaginary parts follow the conversion
@@ -347,7 +357,7 @@ 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
@@ -355,9 +365,9 @@ ComplexPairTy ComplexExprEmitter::EmitCast(Expr *Op, QualType DestTy) {
llvm::Value *Elt = CGF.EmitScalarExpr(Op);
// Convert the input element to the element type of the complex.
- DestTy = DestTy->getAsComplexType()->getElementType();
+ DestTy = DestTy->getAs<ComplexType>()->getElementType();
Elt = CGF.EmitScalarConversion(Elt, Op->getType(), DestTy);
-
+
// Return (realval, 0).
return ComplexPairTy(Elt, llvm::Constant::getNullValue(Elt->getType()));
}
@@ -367,31 +377,30 @@ ComplexPairTy ComplexExprEmitter::VisitPrePostIncDec(const UnaryOperator *E,
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);
-
+
// Add the inc/dec to the real part.
NextVal = Builder.CreateAdd(InVal.first, NextVal, isInc ? "inc" : "dec");
-
} else {
- QualType ElemTy = E->getType()->getAsComplexType()->getElementType();
+ QualType ElemTy = E->getType()->getAs<ComplexType>()->getElementType();
llvm::APFloat FVal(CGF.getContext().getFloatTypeSemantics(ElemTy), 1);
if (!isInc)
FVal.changeSign();
- NextVal = llvm::ConstantFP::get(FVal);
-
+ NextVal = llvm::ConstantFP::get(CGF.getLLVMContext(), FVal);
+
// Add the inc/dec to the real part.
NextVal = Builder.CreateFAdd(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;
@@ -403,7 +412,7 @@ ComplexPairTy ComplexExprEmitter::VisitUnaryMinus(const UnaryOperator *E) {
TestAndClearIgnoreRealAssign();
TestAndClearIgnoreImagAssign();
ComplexPairTy Op = Visit(E->getSubExpr());
-
+
llvm::Value *ResR, *ResI;
if (Op.first->getType()->isFloatingPoint()) {
ResR = Builder.CreateFNeg(Op.first, "neg.r");
@@ -427,13 +436,13 @@ ComplexPairTy ComplexExprEmitter::VisitUnaryNot(const UnaryOperator *E) {
ResI = Builder.CreateFNeg(Op.second, "conj.i");
else
ResI = Builder.CreateNeg(Op.second, "conj.i");
-
+
return ComplexPairTy(Op.first, ResI);
}
ComplexPairTy ComplexExprEmitter::EmitBinAdd(const BinOpInfo &Op) {
llvm::Value *ResR, *ResI;
-
+
if (Op.LHS.first->getType()->isFloatingPoint()) {
ResR = Builder.CreateFAdd(Op.LHS.first, Op.RHS.first, "add.r");
ResI = Builder.CreateFAdd(Op.LHS.second, Op.RHS.second, "add.i");
@@ -460,12 +469,12 @@ ComplexPairTy ComplexExprEmitter::EmitBinSub(const BinOpInfo &Op) {
ComplexPairTy ComplexExprEmitter::EmitBinMul(const BinOpInfo &Op) {
using llvm::Value;
Value *ResR, *ResI;
-
+
if (Op.LHS.first->getType()->isFloatingPoint()) {
Value *ResRl = Builder.CreateFMul(Op.LHS.first, Op.RHS.first, "mul.rl");
Value *ResRr = Builder.CreateFMul(Op.LHS.second, Op.RHS.second,"mul.rr");
ResR = Builder.CreateFSub(ResRl, ResRr, "mul.r");
-
+
Value *ResIl = Builder.CreateFMul(Op.LHS.second, Op.RHS.first, "mul.il");
Value *ResIr = Builder.CreateFMul(Op.LHS.first, Op.RHS.second, "mul.ir");
ResI = Builder.CreateFAdd(ResIl, ResIr, "mul.i");
@@ -473,7 +482,7 @@ ComplexPairTy ComplexExprEmitter::EmitBinMul(const BinOpInfo &Op) {
Value *ResRl = Builder.CreateMul(Op.LHS.first, Op.RHS.first, "mul.rl");
Value *ResRr = Builder.CreateMul(Op.LHS.second, Op.RHS.second,"mul.rr");
ResR = Builder.CreateSub(ResRl, ResRr, "mul.r");
-
+
Value *ResIl = Builder.CreateMul(Op.LHS.second, Op.RHS.first, "mul.il");
Value *ResIr = Builder.CreateMul(Op.LHS.first, Op.RHS.second, "mul.ir");
ResI = Builder.CreateAdd(ResIl, ResIr, "mul.i");
@@ -484,7 +493,7 @@ ComplexPairTy ComplexExprEmitter::EmitBinMul(const BinOpInfo &Op) {
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;
-
+
llvm::Value *DSTr, *DSTi;
if (Op.LHS.first->getType()->isFloatingPoint()) {
@@ -492,15 +501,15 @@ ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) {
llvm::Value *Tmp1 = Builder.CreateFMul(LHSr, RHSr, "tmp"); // a*c
llvm::Value *Tmp2 = Builder.CreateFMul(LHSi, RHSi, "tmp"); // b*d
llvm::Value *Tmp3 = Builder.CreateFAdd(Tmp1, Tmp2, "tmp"); // ac+bd
-
+
llvm::Value *Tmp4 = Builder.CreateFMul(RHSr, RHSr, "tmp"); // c*c
llvm::Value *Tmp5 = Builder.CreateFMul(RHSi, RHSi, "tmp"); // d*d
llvm::Value *Tmp6 = Builder.CreateFAdd(Tmp4, Tmp5, "tmp"); // cc+dd
-
+
llvm::Value *Tmp7 = Builder.CreateFMul(LHSi, RHSr, "tmp"); // b*c
llvm::Value *Tmp8 = Builder.CreateFMul(LHSr, RHSi, "tmp"); // a*d
llvm::Value *Tmp9 = Builder.CreateFSub(Tmp7, Tmp8, "tmp"); // bc-ad
-
+
DSTr = Builder.CreateFDiv(Tmp3, Tmp6, "tmp");
DSTi = Builder.CreateFDiv(Tmp9, Tmp6, "tmp");
} else {
@@ -508,16 +517,16 @@ ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) {
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
-
- if (Op.Ty->getAsComplexType()->getElementType()->isUnsignedIntegerType()) {
+
+ if (Op.Ty->getAs<ComplexType>()->getElementType()->isUnsignedIntegerType()) {
DSTr = Builder.CreateUDiv(Tmp3, Tmp6, "tmp");
DSTi = Builder.CreateUDiv(Tmp9, Tmp6, "tmp");
} else {
@@ -525,11 +534,11 @@ ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) {
DSTi = Builder.CreateSDiv(Tmp9, Tmp6, "tmp");
}
}
-
+
return ComplexPairTy(DSTr, DSTi);
}
-ComplexExprEmitter::BinOpInfo
+ComplexExprEmitter::BinOpInfo
ComplexExprEmitter::EmitBinOps(const BinaryOperator *E) {
TestAndClearIgnoreReal();
TestAndClearIgnoreImag();
@@ -554,27 +563,27 @@ EmitCompoundAssign(const CompoundAssignOperator *E,
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=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
@@ -598,7 +607,7 @@ ComplexPairTy ComplexExprEmitter::VisitBinAssign(const BinaryOperator *E) {
// Compute the address to store into.
LValue LHS = CGF.EmitLValue(E->getLHS());
-
+
// Store into it, if simple.
if (LHS.isSimple()) {
EmitStoreOfComplex(Val, LHS.getAddress(), LHS.isVolatileQualified());
@@ -610,7 +619,7 @@ ComplexPairTy ComplexExprEmitter::VisitBinAssign(const BinaryOperator *E) {
IgnoreImagAssign = ignimag;
return EmitLoadOfComplex(LHS.getAddress(), LHS.isVolatileQualified());
}
-
+
// Otherwise we must have a property setter (no complex vector/bitfields).
if (LHS.isPropertyRef())
CGF.EmitObjCPropertySet(LHS.getPropertyRefExpr(), RValue::getComplex(Val));
@@ -641,27 +650,27 @@ 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 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);
@@ -673,7 +682,7 @@ VisitConditionalOperator(const ConditionalOperator *E) {
ImagPN->reserveOperandSpace(2);
ImagPN->addIncoming(LHS.second, LHSBlock);
ImagPN->addIncoming(RHS.second, RHSBlock);
-
+
return ComplexPairTy(RealPN, ImagPN);
}
@@ -692,7 +701,7 @@ ComplexPairTy ComplexExprEmitter::VisitInitListExpr(InitListExpr *E) {
return Visit(E->getInit(0));
// Empty init list intializes to null
- QualType Ty = E->getType()->getAsComplexType()->getElementType();
+ QualType Ty = E->getType()->getAs<ComplexType>()->getElementType();
const llvm::Type* LTy = CGF.ConvertType(Ty);
llvm::Value* zeroConstant = llvm::Constant::getNullValue(LTy);
return ComplexPairTy(zeroConstant, zeroConstant);
@@ -704,8 +713,8 @@ ComplexPairTy ComplexExprEmitter::VisitVAArgExpr(VAArgExpr *E) {
if (!ArgPtr) {
CGF.ErrorUnsupported(E, "complex va_arg expression");
- const llvm::Type *EltTy =
- CGF.ConvertType(E->getType()->getAsComplexType()->getElementType());
+ const llvm::Type *EltTy =
+ CGF.ConvertType(E->getType()->getAs<ComplexType>()->getElementType());
llvm::Value *U = llvm::UndefValue::get(EltTy);
return ComplexPairTy(U, U);
}
@@ -724,7 +733,7 @@ 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));
@@ -750,7 +759,7 @@ void CodeGenFunction::StoreComplexToAddr(ComplexPairTy V,
}
/// LoadComplexFromAddr - Load a complex number from the specified address.
-ComplexPairTy CodeGenFunction::LoadComplexFromAddr(llvm::Value *SrcAddr,
+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
index 37c9c36..7f540c3 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -16,6 +16,7 @@
#include "CGObjCRuntime.h"
#include "clang/AST/APValue.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/Builtins.h"
#include "llvm/Constants.h"
@@ -27,45 +28,541 @@ using namespace clang;
using namespace CodeGen;
namespace {
-class VISIBILITY_HIDDEN ConstExprEmitter :
+
+class VISIBILITY_HIDDEN ConstStructBuilder {
+ CodeGenModule &CGM;
+ CodeGenFunction *CGF;
+
+ bool Packed;
+
+ unsigned NextFieldOffsetInBytes;
+
+ unsigned LLVMStructAlignment;
+
+ std::vector<llvm::Constant *> Elements;
+
+ ConstStructBuilder(CodeGenModule &CGM, CodeGenFunction *CGF)
+ : CGM(CGM), CGF(CGF), Packed(false), NextFieldOffsetInBytes(0),
+ LLVMStructAlignment(1) { }
+
+ bool AppendField(const FieldDecl *Field, uint64_t FieldOffset,
+ const Expr *InitExpr) {
+ uint64_t FieldOffsetInBytes = FieldOffset / 8;
+
+ assert(NextFieldOffsetInBytes <= FieldOffsetInBytes
+ && "Field offset mismatch!");
+
+ // Emit the field.
+ llvm::Constant *C = CGM.EmitConstantExpr(InitExpr, Field->getType(), CGF);
+ if (!C)
+ return false;
+
+ unsigned FieldAlignment = getAlignment(C);
+
+ // Round up the field offset to the alignment of the field type.
+ uint64_t AlignedNextFieldOffsetInBytes =
+ llvm::RoundUpToAlignment(NextFieldOffsetInBytes, FieldAlignment);
+
+ if (AlignedNextFieldOffsetInBytes > FieldOffsetInBytes) {
+ assert(!Packed && "Alignment is wrong even with a packed struct!");
+
+ // Convert the struct to a packed struct.
+ ConvertStructToPacked();
+
+ AlignedNextFieldOffsetInBytes = NextFieldOffsetInBytes;
+ }
+
+ if (AlignedNextFieldOffsetInBytes < FieldOffsetInBytes) {
+ // We need to append padding.
+ AppendPadding(FieldOffsetInBytes - NextFieldOffsetInBytes);
+
+ assert(NextFieldOffsetInBytes == FieldOffsetInBytes &&
+ "Did not add enough padding!");
+
+ AlignedNextFieldOffsetInBytes = NextFieldOffsetInBytes;
+ }
+
+ // Add the field.
+ Elements.push_back(C);
+ NextFieldOffsetInBytes = AlignedNextFieldOffsetInBytes + getSizeInBytes(C);
+
+ if (Packed)
+ assert(LLVMStructAlignment == 1 && "Packed struct not byte-aligned!");
+ else
+ LLVMStructAlignment = std::max(LLVMStructAlignment, FieldAlignment);
+
+ return true;
+ }
+
+ bool AppendBitField(const FieldDecl *Field, uint64_t FieldOffset,
+ const Expr *InitExpr) {
+ llvm::ConstantInt *CI =
+ cast_or_null<llvm::ConstantInt>(CGM.EmitConstantExpr(InitExpr,
+ Field->getType(),
+ CGF));
+ // FIXME: Can this ever happen?
+ if (!CI)
+ return false;
+
+ if (FieldOffset > NextFieldOffsetInBytes * 8) {
+ // We need to add padding.
+ uint64_t NumBytes =
+ llvm::RoundUpToAlignment(FieldOffset -
+ NextFieldOffsetInBytes * 8, 8) / 8;
+
+ AppendPadding(NumBytes);
+ }
+
+ uint64_t FieldSize =
+ Field->getBitWidth()->EvaluateAsInt(CGM.getContext()).getZExtValue();
+
+ llvm::APInt FieldValue = CI->getValue();
+
+ // Promote the size of FieldValue 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 (FieldSize > FieldValue.getBitWidth())
+ FieldValue.zext(FieldSize);
+
+ // Truncate the size of FieldValue to the bit field size.
+ if (FieldSize < FieldValue.getBitWidth())
+ FieldValue.trunc(FieldSize);
+
+ if (FieldOffset < NextFieldOffsetInBytes * 8) {
+ // Either part of the field or the entire field can go into the previous
+ // byte.
+ assert(!Elements.empty() && "Elements can't be empty!");
+
+ unsigned BitsInPreviousByte =
+ NextFieldOffsetInBytes * 8 - FieldOffset;
+
+ bool FitsCompletelyInPreviousByte =
+ BitsInPreviousByte >= FieldValue.getBitWidth();
+
+ llvm::APInt Tmp = FieldValue;
+
+ if (!FitsCompletelyInPreviousByte) {
+ unsigned NewFieldWidth = FieldSize - BitsInPreviousByte;
+
+ if (CGM.getTargetData().isBigEndian()) {
+ Tmp = Tmp.lshr(NewFieldWidth);
+ Tmp.trunc(BitsInPreviousByte);
+
+ // We want the remaining high bits.
+ FieldValue.trunc(NewFieldWidth);
+ } else {
+ Tmp.trunc(BitsInPreviousByte);
+
+ // We want the remaining low bits.
+ FieldValue = FieldValue.lshr(BitsInPreviousByte);
+ FieldValue.trunc(NewFieldWidth);
+ }
+ }
+
+ Tmp.zext(8);
+ if (CGM.getTargetData().isBigEndian()) {
+ if (FitsCompletelyInPreviousByte)
+ Tmp = Tmp.shl(BitsInPreviousByte - FieldValue.getBitWidth());
+ } else {
+ Tmp = Tmp.shl(8 - BitsInPreviousByte);
+ }
+
+ // Or in the bits that go into the previous byte.
+ Tmp |= cast<llvm::ConstantInt>(Elements.back())->getValue();
+ Elements.back() = llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp);
+
+ if (FitsCompletelyInPreviousByte)
+ return true;
+ }
+
+ while (FieldValue.getBitWidth() > 8) {
+ llvm::APInt Tmp;
+
+ if (CGM.getTargetData().isBigEndian()) {
+ // We want the high bits.
+ Tmp = FieldValue;
+ Tmp = Tmp.lshr(Tmp.getBitWidth() - 8);
+ Tmp.trunc(8);
+ } else {
+ // We want the low bits.
+ Tmp = FieldValue;
+ Tmp.trunc(8);
+
+ FieldValue = FieldValue.lshr(8);
+ }
+
+ Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp));
+ NextFieldOffsetInBytes++;
+
+ FieldValue.trunc(FieldValue.getBitWidth() - 8);
+ }
+
+ assert(FieldValue.getBitWidth() > 0 &&
+ "Should have at least one bit left!");
+ assert(FieldValue.getBitWidth() <= 8 &&
+ "Should not have more than a byte left!");
+
+ if (FieldValue.getBitWidth() < 8) {
+ if (CGM.getTargetData().isBigEndian()) {
+ unsigned BitWidth = FieldValue.getBitWidth();
+
+ FieldValue.zext(8);
+ FieldValue = FieldValue << (8 - BitWidth);
+ } else
+ FieldValue.zext(8);
+ }
+
+ // Append the last element.
+ Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(),
+ FieldValue));
+ NextFieldOffsetInBytes++;
+ return true;
+ }
+
+ void AppendPadding(uint64_t NumBytes) {
+ if (!NumBytes)
+ return;
+
+ const llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext());
+ if (NumBytes > 1)
+ Ty = llvm::ArrayType::get(Ty, NumBytes);
+
+ llvm::Constant *C = llvm::Constant::getNullValue(Ty);
+ Elements.push_back(C);
+ assert(getAlignment(C) == 1 && "Padding must have 1 byte alignment!");
+
+ NextFieldOffsetInBytes += getSizeInBytes(C);
+ }
+
+ void AppendTailPadding(uint64_t RecordSize) {
+ assert(RecordSize % 8 == 0 && "Invalid record size!");
+
+ uint64_t RecordSizeInBytes = RecordSize / 8;
+ assert(NextFieldOffsetInBytes <= RecordSizeInBytes && "Size mismatch!");
+
+ unsigned NumPadBytes = RecordSizeInBytes - NextFieldOffsetInBytes;
+ AppendPadding(NumPadBytes);
+ }
+
+ void ConvertStructToPacked() {
+ std::vector<llvm::Constant *> PackedElements;
+ uint64_t ElementOffsetInBytes = 0;
+
+ for (unsigned i = 0, e = Elements.size(); i != e; ++i) {
+ llvm::Constant *C = Elements[i];
+
+ unsigned ElementAlign =
+ CGM.getTargetData().getABITypeAlignment(C->getType());
+ uint64_t AlignedElementOffsetInBytes =
+ llvm::RoundUpToAlignment(ElementOffsetInBytes, ElementAlign);
+
+ if (AlignedElementOffsetInBytes > ElementOffsetInBytes) {
+ // We need some padding.
+ uint64_t NumBytes =
+ AlignedElementOffsetInBytes - ElementOffsetInBytes;
+
+ const llvm::Type *Ty = llvm::Type::getInt8Ty(CGF->getLLVMContext());
+ if (NumBytes > 1)
+ Ty = llvm::ArrayType::get(Ty, NumBytes);
+
+ llvm::Constant *Padding = llvm::Constant::getNullValue(Ty);
+ PackedElements.push_back(Padding);
+ ElementOffsetInBytes += getSizeInBytes(Padding);
+ }
+
+ PackedElements.push_back(C);
+ ElementOffsetInBytes += getSizeInBytes(C);
+ }
+
+ assert(ElementOffsetInBytes == NextFieldOffsetInBytes &&
+ "Packing the struct changed its size!");
+
+ Elements = PackedElements;
+ LLVMStructAlignment = 1;
+ Packed = true;
+ }
+
+ bool Build(InitListExpr *ILE) {
+ RecordDecl *RD = ILE->getType()->getAs<RecordType>()->getDecl();
+ const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
+
+ unsigned FieldNo = 0;
+ unsigned ElementNo = 0;
+ for (RecordDecl::field_iterator Field = RD->field_begin(),
+ FieldEnd = RD->field_end();
+ ElementNo < ILE->getNumInits() && Field != FieldEnd;
+ ++Field, ++FieldNo) {
+ if (RD->isUnion() && ILE->getInitializedFieldInUnion() != *Field)
+ continue;
+
+ if (Field->isBitField()) {
+ if (!Field->getIdentifier())
+ continue;
+
+ if (!AppendBitField(*Field, Layout.getFieldOffset(FieldNo),
+ ILE->getInit(ElementNo)))
+ return false;
+ } else {
+ if (!AppendField(*Field, Layout.getFieldOffset(FieldNo),
+ ILE->getInit(ElementNo)))
+ return false;
+ }
+
+ ElementNo++;
+ }
+
+ uint64_t LayoutSizeInBytes = Layout.getSize() / 8;
+
+ if (NextFieldOffsetInBytes > LayoutSizeInBytes) {
+ // If the struct is bigger than the size of the record type,
+ // we must have a flexible array member at the end.
+ assert(RD->hasFlexibleArrayMember() &&
+ "Must have flexible array member if struct is bigger than type!");
+
+ // No tail padding is necessary.
+ return true;
+ }
+
+ uint64_t LLVMSizeInBytes = llvm::RoundUpToAlignment(NextFieldOffsetInBytes,
+ LLVMStructAlignment);
+
+ // Check if we need to convert the struct to a packed struct.
+ if (NextFieldOffsetInBytes <= LayoutSizeInBytes &&
+ LLVMSizeInBytes > LayoutSizeInBytes) {
+ assert(!Packed && "Size mismatch!");
+
+ ConvertStructToPacked();
+ assert(NextFieldOffsetInBytes == LayoutSizeInBytes &&
+ "Converting to packed did not help!");
+ }
+
+ // Append tail padding if necessary.
+ AppendTailPadding(Layout.getSize());
+
+ assert(Layout.getSize() / 8 == NextFieldOffsetInBytes &&
+ "Tail padding mismatch!");
+
+ return true;
+ }
+
+ unsigned getAlignment(const llvm::Constant *C) const {
+ if (Packed)
+ return 1;
+
+ return CGM.getTargetData().getABITypeAlignment(C->getType());
+ }
+
+ uint64_t getSizeInBytes(const llvm::Constant *C) const {
+ return CGM.getTargetData().getTypeAllocSize(C->getType());
+ }
+
+public:
+ static llvm::Constant *BuildStruct(CodeGenModule &CGM, CodeGenFunction *CGF,
+ InitListExpr *ILE) {
+ ConstStructBuilder Builder(CGM, CGF);
+
+ if (!Builder.Build(ILE))
+ return 0;
+
+ llvm::Constant *Result =
+ llvm::ConstantStruct::get(CGM.getLLVMContext(),
+ Builder.Elements, Builder.Packed);
+
+ assert(llvm::RoundUpToAlignment(Builder.NextFieldOffsetInBytes,
+ Builder.getAlignment(Result)) ==
+ Builder.getSizeInBytes(Result) && "Size mismatch!");
+
+ return Result;
+ }
+};
+
+class VISIBILITY_HIDDEN ConstExprEmitter :
public StmtVisitor<ConstExprEmitter, llvm::Constant*> {
CodeGenModule &CGM;
CodeGenFunction *CGF;
+ llvm::LLVMContext &VMContext;
public:
ConstExprEmitter(CodeGenModule &cgm, CodeGenFunction *cgf)
- : CGM(cgm), CGF(cgf) {
+ : CGM(cgm), CGF(cgf), VMContext(cgm.getLLVMContext()) {
}
-
+
//===--------------------------------------------------------------------===//
// Visitor Methods
//===--------------------------------------------------------------------===//
-
+
llvm::Constant *VisitStmt(Stmt *S) {
return 0;
}
-
- llvm::Constant *VisitParenExpr(ParenExpr *PE) {
- return Visit(PE->getSubExpr());
+
+ llvm::Constant *VisitParenExpr(ParenExpr *PE) {
+ return Visit(PE->getSubExpr());
}
-
+
llvm::Constant *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
return Visit(E->getInitializer());
}
-
+
+ llvm::Constant *EmitMemberFunctionPointer(CXXMethodDecl *MD) {
+ assert(MD->isInstance() && "Member function must not be static!");
+
+ const llvm::Type *PtrDiffTy =
+ CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType());
+
+ llvm::Constant *Values[2];
+
+ // Get the function pointer (or index if this is a virtual function).
+ if (MD->isVirtual()) {
+ int64_t Index = CGM.getVtableInfo().getMethodVtableIndex(MD);
+
+ Values[0] = llvm::ConstantInt::get(PtrDiffTy, Index + 1);
+ } else {
+ llvm::Constant *FuncPtr = CGM.GetAddrOfFunction(MD);
+
+ Values[0] = llvm::ConstantExpr::getPtrToInt(FuncPtr, PtrDiffTy);
+ }
+
+ // The adjustment will always be 0.
+ Values[1] = llvm::ConstantInt::get(PtrDiffTy, 0);
+
+ return llvm::ConstantStruct::get(CGM.getLLVMContext(),
+ Values, 2, /*Packed=*/false);
+ }
+
+ llvm::Constant *VisitUnaryAddrOf(UnaryOperator *E) {
+ if (const MemberPointerType *MPT =
+ E->getType()->getAs<MemberPointerType>()) {
+ QualType T = MPT->getPointeeType();
+ if (T->isFunctionProtoType()) {
+ QualifiedDeclRefExpr *DRE = cast<QualifiedDeclRefExpr>(E->getSubExpr());
+
+ return EmitMemberFunctionPointer(cast<CXXMethodDecl>(DRE->getDecl()));
+ }
+
+ // FIXME: Should we handle other member pointer types here too,
+ // or should they be handled by Expr::Evaluate?
+ }
+
+ return 0;
+ }
+
+ llvm::Constant *VisitBinSub(BinaryOperator *E) {
+ // This must be a pointer/pointer subtraction. This only happens for
+ // address of label.
+ if (!isa<AddrLabelExpr>(E->getLHS()->IgnoreParenNoopCasts(CGM.getContext())) ||
+ !isa<AddrLabelExpr>(E->getRHS()->IgnoreParenNoopCasts(CGM.getContext())))
+ return 0;
+
+ llvm::Constant *LHS = CGM.EmitConstantExpr(E->getLHS(),
+ E->getLHS()->getType(), CGF);
+ llvm::Constant *RHS = CGM.EmitConstantExpr(E->getRHS(),
+ E->getRHS()->getType(), CGF);
+
+ const llvm::Type *ResultType = ConvertType(E->getType());
+ LHS = llvm::ConstantExpr::getPtrToInt(LHS, ResultType);
+ RHS = llvm::ConstantExpr::getPtrToInt(RHS, ResultType);
+
+ // No need to divide by element size, since addr of label is always void*,
+ // which has size 1 in GNUish.
+ return llvm::ConstantExpr::getSub(LHS, RHS);
+ }
+
llvm::Constant *VisitCastExpr(CastExpr* E) {
- // GCC cast to union extension
- if (E->getType()->isUnionType()) {
+ switch (E->getCastKind()) {
+ case CastExpr::CK_ToUnion: {
+ // GCC cast to union extension
+ assert(E->getType()->isUnionType() &&
+ "Destination type is not union type!");
const llvm::Type *Ty = ConvertType(E->getType());
Expr *SubExpr = E->getSubExpr();
- return EmitUnion(CGM.EmitConstantExpr(SubExpr, SubExpr->getType(), CGF),
- Ty);
+
+ llvm::Constant *C =
+ CGM.EmitConstantExpr(SubExpr, SubExpr->getType(), CGF);
+ 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);
+
+ assert(CurSize <= TotalSize && "Union size mismatch!");
+ if (unsigned NumPadBytes = TotalSize - CurSize) {
+ const llvm::Type *Ty = llvm::Type::getInt8Ty(VMContext);
+ if (NumPadBytes > 1)
+ Ty = llvm::ArrayType::get(Ty, NumPadBytes);
+
+ Elts.push_back(llvm::Constant::getNullValue(Ty));
+ Types.push_back(Ty);
+ }
+
+ llvm::StructType* STy =
+ llvm::StructType::get(C->getType()->getContext(), Types, false);
+ return llvm::ConstantStruct::get(STy, Elts);
+ }
+ case CastExpr::CK_NullToMemberPointer:
+ return CGM.EmitNullConstant(E->getType());
+
+ case CastExpr::CK_BaseToDerivedMemberPointer: {
+ Expr *SubExpr = E->getSubExpr();
+
+ const MemberPointerType *SrcTy =
+ SubExpr->getType()->getAs<MemberPointerType>();
+ const MemberPointerType *DestTy =
+ E->getType()->getAs<MemberPointerType>();
+
+ const CXXRecordDecl *BaseClass =
+ cast<CXXRecordDecl>(cast<RecordType>(SrcTy->getClass())->getDecl());
+ const CXXRecordDecl *DerivedClass =
+ cast<CXXRecordDecl>(cast<RecordType>(DestTy->getClass())->getDecl());
+
+ if (SrcTy->getPointeeType()->isFunctionProtoType()) {
+ llvm::Constant *C =
+ CGM.EmitConstantExpr(SubExpr, SubExpr->getType(), CGF);
+ if (!C)
+ return 0;
+
+ llvm::ConstantStruct *CS = cast<llvm::ConstantStruct>(C);
+
+ // Check if we need to update the adjustment.
+ if (llvm::Constant *Offset = CGM.GetCXXBaseClassOffset(DerivedClass,
+ BaseClass)) {
+ llvm::Constant *Values[2];
+
+ Values[0] = CS->getOperand(0);
+ Values[1] = llvm::ConstantExpr::getAdd(CS->getOperand(1), Offset);
+ return llvm::ConstantStruct::get(CGM.getLLVMContext(), Values, 2,
+ /*Packed=*/false);
+ }
+
+ return CS;
+ }
+ }
+
+ default: {
+ // FIXME: This should be handled by the CK_NoOp cast kind.
+ // Explicit and implicit no-op casts
+ QualType Ty = E->getType(), SubTy = E->getSubExpr()->getType();
+ if (CGM.getContext().hasSameUnqualifiedType(Ty, SubTy))
+ return Visit(E->getSubExpr());
+
+ // Handle integer->integer casts for address-of-label differences.
+ if (Ty->isIntegerType() && SubTy->isIntegerType() &&
+ CGF) {
+ llvm::Value *Src = Visit(E->getSubExpr());
+ if (Src == 0) return 0;
+
+ // Use EmitScalarConversion to perform the conversion.
+ return cast<llvm::Constant>(CGF->EmitScalarConversion(Src, SubTy, Ty));
+ }
+
+ return 0;
}
- // 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) {
@@ -79,7 +576,7 @@ public:
unsigned NumInitElements = ILE->getNumInits();
// FIXME: Check for wide strings
// FIXME: Check for NumInitElements exactly equal to 1??
- if (NumInitElements > 0 &&
+ if (NumInitElements > 0 &&
(isa<StringLiteral>(ILE->getInit(0)) ||
isa<ObjCEncodeExpr>(ILE->getInit(0))) &&
ILE->getType()->getArrayElementTypeNoTypeQual()->isCharType())
@@ -87,7 +584,7 @@ public:
const llvm::Type *ElemTy = AType->getElementType();
unsigned NumElements = AType->getNumElements();
- // Initialising an array requires us to automatically
+ // Initialising an array requires us to automatically
// initialise any elements that have not been initialised explicitly
unsigned NumInitableElts = std::min(NumInitElements, NumElements);
@@ -113,184 +610,20 @@ public:
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);
+ const llvm::StructType *SType = llvm::StructType::get(AType->getContext(),
+ 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);
+ return llvm::ConstantArray::get(AType, Elts);
}
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
- bool RewriteType = false;
- for (RecordDecl::field_iterator Field = RD->field_begin(),
- FieldEnd = RD->field_end();
- EltNo < ILE->getNumInits() && Field != FieldEnd; ++Field) {
- if (Field->isBitField()) {
- if (!Field->getIdentifier())
- continue;
- 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);
+ return ConstStructBuilder::BuildStruct(CGM, CGF, ILE);
}
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(),
- FieldEnd = RD->field_end();
- 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);
+ return ConstStructBuilder::BuildStruct(CGM, CGF, ILE);
}
llvm::Constant *EmitVectorInitialization(InitListExpr *ILE) {
@@ -316,13 +649,13 @@ public:
for (; i < NumElements; ++i)
Elts.push_back(llvm::Constant::getNullValue(ElemTy));
- return llvm::ConstantVector::get(VType, Elts);
+ 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.
@@ -332,7 +665,7 @@ public:
}
return CGM.EmitNullConstant(ILE->getType());
}
-
+
if (ILE->getType()->isArrayType())
return EmitArrayInitialization(ILE);
@@ -353,11 +686,12 @@ public:
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);
+ return llvm::ConstantArray::get(VMContext,
+ CGM.GetStringForStringLiteral(E), false);
}
llvm::Constant *VisitObjCEncodeExpr(ObjCEncodeExpr *E) {
@@ -367,13 +701,13 @@ public:
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);
+ return llvm::ConstantArray::get(VMContext, Str, false);
}
-
+
llvm::Constant *VisitUnaryExtension(const UnaryOperator *E) {
return Visit(E->getSubExpr());
}
@@ -394,20 +728,21 @@ public:
llvm::Constant* C = Visit(CLE->getInitializer());
// FIXME: "Leaked" on failure.
if (C)
- C = new llvm::GlobalVariable(C->getType(),
- E->getType().isConstQualified(),
+ C = new llvm::GlobalVariable(CGM.getModule(), C->getType(),
+ E->getType().isConstant(CGM.getContext()),
llvm::GlobalValue::InternalLinkage,
- C, ".compoundliteral", &CGM.getModule());
+ C, ".compoundliteral", 0, false,
+ E->getType().getAddressSpace());
return C;
}
- case Expr::DeclRefExprClass:
+ 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));
+ return CGM.GetAddrOfFunction(FD);
if (const VarDecl* VD = dyn_cast<VarDecl>(Decl)) {
// We can never refer to a variable with local storage.
- if (!VD->hasLocalStorage()) {
+ if (!VD->hasLocalStorage()) {
if (VD->isFileVarDecl() || VD->hasExternalStorage())
return CGM.GetAddrOfGlobalVar(VD);
else if (VD->isBlockVarDecl()) {
@@ -430,21 +765,23 @@ public:
case Expr::PredefinedExprClass: {
// __func__/__FUNCTION__ -> "". __PRETTY_FUNCTION__ -> "top level".
std::string Str;
- if (cast<PredefinedExpr>(E)->getIdentType() ==
+ 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);
+ unsigned id =
+ CGF->GetIDForAddrOfLabel(cast<AddrLabelExpr>(E)->getLabel());
+ llvm::Constant *C =
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), id);
return llvm::ConstantExpr::getIntToPtr(C, ConvertType(E->getType()));
}
case Expr::CallExprClass: {
CallExpr* CE = cast<CallExpr>(E);
- if (CE->isBuiltinCall(CGM.getContext()) !=
+ if (CE->isBuiltinCall(CGM.getContext()) !=
Builtin::BI__builtin___CFStringMakeConstantString)
break;
const Expr *Arg = CE->getArg(0)->IgnoreParenCasts();
@@ -466,23 +803,23 @@ public:
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
+ else
Success = E->Evaluate(Result, Context);
-
+
if (Success) {
- assert(!Result.HasSideEffects &&
+ assert(!Result.HasSideEffects &&
"Constant expr should not have any side effects!");
switch (Result.Val.getKind()) {
case APValue::Uninitialized:
@@ -490,18 +827,17 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E,
return 0;
case APValue::LValue: {
const llvm::Type *DestTy = getTypes().ConvertTypeForMem(DestType);
- llvm::Constant *Offset =
- llvm::ConstantInt::get(llvm::Type::Int64Ty,
+ llvm::Constant *Offset =
+ llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
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);
+ const llvm::Type *Type = llvm::Type::getInt8PtrTy(VMContext);
llvm::Constant *Casted = llvm::ConstantExpr::getBitCast(C, Type);
Casted = llvm::ConstantExpr::getGetElementPtr(Casted, &Offset, 1);
C = llvm::ConstantExpr::getBitCast(Casted, C->getType());
@@ -529,9 +865,10 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E,
}
}
case APValue::Int: {
- llvm::Constant *C = llvm::ConstantInt::get(Result.Val.getInt());
-
- if (C->getType() == llvm::Type::Int1Ty) {
+ llvm::Constant *C = llvm::ConstantInt::get(VMContext,
+ Result.Val.getInt());
+
+ if (C->getType() == llvm::Type::getInt1Ty(VMContext)) {
const llvm::Type *BoolTy = getTypes().ConvertTypeForMem(E->getType());
C = llvm::ConstantExpr::getZExt(C, BoolTy);
}
@@ -539,32 +876,38 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E,
}
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);
+
+ Complex[0] = llvm::ConstantInt::get(VMContext,
+ Result.Val.getComplexIntReal());
+ Complex[1] = llvm::ConstantInt::get(VMContext,
+ Result.Val.getComplexIntImag());
+
+ // FIXME: the target may want to specify that this is packed.
+ return llvm::ConstantStruct::get(VMContext, Complex, 2, false);
}
case APValue::Float:
- return llvm::ConstantFP::get(Result.Val.getFloat());
+ return llvm::ConstantFP::get(VMContext, 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);
+
+ Complex[0] = llvm::ConstantFP::get(VMContext,
+ Result.Val.getComplexFloatReal());
+ Complex[1] = llvm::ConstantFP::get(VMContext,
+ Result.Val.getComplexFloatImag());
+
+ // FIXME: the target may want to specify that this is packed.
+ return llvm::ConstantStruct::get(VMContext, Complex, 2, false);
}
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()));
+ Inits.push_back(llvm::ConstantInt::get(VMContext, Elt.getInt()));
else
- Inits.push_back(llvm::ConstantFP::get(Elt.getFloat()));
+ Inits.push_back(llvm::ConstantFP::get(VMContext, Elt.getFloat()));
}
return llvm::ConstantVector::get(&Inits[0], Inits.size());
}
@@ -572,15 +915,58 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E,
}
llvm::Constant* C = ConstExprEmitter(*this, CGF).Visit(const_cast<Expr*>(E));
- if (C && C->getType() == llvm::Type::Int1Ty) {
+ if (C && C->getType() == llvm::Type::getInt1Ty(VMContext)) {
const llvm::Type *BoolTy = getTypes().ConvertTypeForMem(E->getType());
C = llvm::ConstantExpr::getZExt(C, BoolTy);
}
return C;
}
+static inline bool isDataMemberPointerType(QualType T) {
+ if (const MemberPointerType *MPT = T->getAs<MemberPointerType>())
+ return !MPT->getPointeeType()->isFunctionType();
+
+ return false;
+}
+
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));
+ // No need to check for member pointers when not compiling C++.
+ if (!getContext().getLangOptions().CPlusPlus)
+ return llvm::Constant::getNullValue(getTypes().ConvertTypeForMem(T));
+
+ if (const ConstantArrayType *CAT = Context.getAsConstantArrayType(T)) {
+
+ QualType ElementTy = CAT->getElementType();
+
+ // FIXME: Handle arrays of structs that contain member pointers.
+ if (isDataMemberPointerType(Context.getBaseElementType(ElementTy))) {
+ llvm::Constant *Element = EmitNullConstant(ElementTy);
+ uint64_t NumElements = CAT->getSize().getZExtValue();
+ std::vector<llvm::Constant *> Array(NumElements);
+ for (uint64_t i = 0; i != NumElements; ++i)
+ Array[i] = Element;
+
+ const llvm::ArrayType *ATy =
+ cast<llvm::ArrayType>(getTypes().ConvertTypeForMem(T));
+ return llvm::ConstantArray::get(ATy, Array);
+ }
+ }
+
+ if (const RecordType *RT = T->getAs<RecordType>()) {
+ const RecordDecl *RD = RT->getDecl();
+ // FIXME: It would be better if there was a way to explicitly compute the
+ // record layout instead of converting to a type.
+ Types.ConvertTagDeclType(RD);
+
+ const CGRecordLayout &Layout = Types.getCGRecordLayout(RD);
+ if (Layout.containsMemberPointer()) {
+ assert(0 && "FIXME: No support for structs with member pointers yet!");
+ }
+ }
+
+ // FIXME: Handle structs that contain member pointers.
+ if (isDataMemberPointerType(T))
+ return llvm::Constant::getAllOnesValue(getTypes().ConvertTypeForMem(T));
+
+ return llvm::Constant::getNullValue(getTypes().ConvertTypeForMem(T));
}
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index 2af0639..cc81256 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "CodeGenFunction.h"
+#include "CGObjCRuntime.h"
#include "CodeGenModule.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
@@ -49,20 +50,23 @@ class VISIBILITY_HIDDEN ScalarExprEmitter
CodeGenFunction &CGF;
CGBuilderTy &Builder;
bool IgnoreResultAssign;
-
+ llvm::LLVMContext &VMContext;
public:
ScalarExprEmitter(CodeGenFunction &cgf, bool ira=false)
- : CGF(cgf), Builder(CGF.Builder), IgnoreResultAssign(ira) {
+ : CGF(cgf), Builder(CGF.Builder), IgnoreResultAssign(ira),
+ VMContext(cgf.getLLVMContext()) {
}
-
+
//===--------------------------------------------------------------------===//
// Utilities
//===--------------------------------------------------------------------===//
bool TestAndClearIgnoreResultAssign() {
- bool I = IgnoreResultAssign; IgnoreResultAssign = false;
- return I; }
+ 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); }
@@ -70,25 +74,25 @@ public:
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.
+ /// 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);
@@ -106,10 +110,10 @@ public:
// Leaves.
Value *VisitIntegerLiteral(const IntegerLiteral *E) {
- return llvm::ConstantInt::get(E->getValue());
+ return llvm::ConstantInt::get(VMContext, E->getValue());
}
Value *VisitFloatingLiteral(const FloatingLiteral *E) {
- return llvm::ConstantFP::get(E->getValue());
+ return llvm::ConstantFP::get(VMContext, E->getValue());
}
Value *VisitCharacterLiteral(const CharacterLiteral *E) {
return llvm::ConstantInt::get(ConvertType(E->getType()), E->getValue());
@@ -130,32 +134,33 @@ public:
}
Value *VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E);
Value *VisitAddrLabelExpr(const AddrLabelExpr *E) {
- llvm::Value *V =
- llvm::ConstantInt::get(llvm::Type::Int32Ty,
+ llvm::Value *V =
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(CGF.getLLVMContext()),
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 llvm::ConstantInt::get(VMContext, EC->getInitVal());
return EmitLoadOfLValue(E);
}
- Value *VisitObjCSelectorExpr(ObjCSelectorExpr *E) {
- return CGF.EmitObjCSelectorExpr(E);
+ Value *VisitObjCSelectorExpr(ObjCSelectorExpr *E) {
+ return CGF.EmitObjCSelectorExpr(E);
}
- Value *VisitObjCProtocolExpr(ObjCProtocolExpr *E) {
- return CGF.EmitObjCProtocolExpr(E);
+ Value *VisitObjCProtocolExpr(ObjCProtocolExpr *E) {
+ return CGF.EmitObjCProtocolExpr(E);
}
- Value *VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
+ Value *VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
return EmitLoadOfLValue(E);
}
Value *VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
return EmitLoadOfLValue(E);
}
- Value *VisitObjCKVCRefExpr(ObjCKVCRefExpr *E) {
+ Value *VisitObjCImplicitSetterGetterRefExpr(
+ ObjCImplicitSetterGetterRefExpr *E) {
return EmitLoadOfLValue(E);
}
Value *VisitObjCMessageExpr(ObjCMessageExpr *E) {
@@ -173,7 +178,7 @@ public:
Value *VisitObjCEncodeExpr(const ObjCEncodeExpr *E) {
return EmitLValue(E).getAddress();
}
-
+
Value *VisitPredefinedExpr(Expr *E) { return EmitLValue(E).getAddress(); }
Value *VisitInitListExpr(InitListExpr *E) {
@@ -181,66 +186,67 @@ public:
(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 =
+ const llvm::VectorType *VType =
dyn_cast<llvm::VectorType>(ConvertType(E->getType()));
-
+
// We have a scalar in braces. Just use the first element.
- if (!VType)
+ if (!VType)
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);
+ Value *Idx =
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(CGF.getLLVMContext()), 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);
+ Value *Idx =
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(CGF.getLLVMContext()), 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());
+ return EmitCastExpr(E);
}
- Value *EmitCastExpr(const Expr *E, QualType T);
+ Value *EmitCastExpr(const CastExpr *E);
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) {
@@ -273,22 +279,40 @@ public:
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);
}
-
+ Value *VisitCXXDeleteExpr(const CXXDeleteExpr *E) {
+ CGF.EmitCXXDeleteExpr(E);
+ return 0;
+ }
+
+ Value *VisitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *E) {
+ // C++ [expr.pseudo]p1:
+ // The result shall only be used as the operand for the function call
+ // operator (), and the result of such a call has type void. The only
+ // effect is the evaluation of the postfix-expression before the dot or
+ // arrow.
+ CGF.EmitScalarExpr(E->getBase());
+ return 0;
+ }
+
+ Value *VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E) {
+ return llvm::Constant::getNullValue(ConvertType(E->getType()));
+ }
+
// Binary Operators.
Value *EmitMul(const BinOpInfo &Ops) {
if (CGF.getContext().getLangOptions().OverflowChecking
@@ -355,7 +379,7 @@ public:
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);
@@ -381,21 +405,30 @@ public:
/// 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");
}
-
+
+ if (SrcType->isMemberPointerType()) {
+ // FIXME: This is ABI specific.
+
+ // Compare against -1.
+ llvm::Value *NegativeOne = llvm::Constant::getAllOnesValue(Src->getType());
+ return Builder.CreateICmpNE(Src, NegativeOne, "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) {
+ if (ZI->getOperand(0)->getType() ==
+ llvm::Type::getInt1Ty(CGF.getLLVMContext())) {
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
@@ -405,7 +438,7 @@ Value *ScalarExprEmitter::EmitConversionToBool(Value *Src, QualType SrcType) {
return Result;
}
}
-
+
// Compare against an integer or pointer null.
llvm::Value *Zero = llvm::Constant::getNullValue(Src->getType());
return Builder.CreateICmpNE(Src, Zero, "tobool");
@@ -418,61 +451,66 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
SrcType = CGF.getContext().getCanonicalType(SrcType);
DstType = CGF.getContext().getCanonicalType(DstType);
if (SrcType == DstType) return Src;
-
+
if (DstType->isVoidType()) return 0;
+ llvm::LLVMContext &VMContext = CGF.getLLVMContext();
+
// 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.
+ // 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);
+ const llvm::Type *MiddleTy =
+ llvm::IntegerType::get(VMContext, 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)) {
+ if (DstType->isExtVectorType() && !SrcType->isVectorType()) {
// Cast the scalar to element type
- QualType EltTy = DstType->getAsExtVectorType()->getElementType();
+ QualType EltTy = DstType->getAs<ExtVectorType>()->getElementType();
llvm::Value *Elt = EmitScalarConversion(Src, SrcType, EltTy);
// Insert the element in element zero of an undef vector
llvm::Value *UnV = llvm::UndefValue::get(DstTy);
- llvm::Value *Idx = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0);
+ llvm::Value *Idx =
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 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));
-
+ Args.push_back(llvm::ConstantInt::get(
+ llvm::Type::getInt32Ty(VMContext), 0));
+
llvm::Constant *Mask = llvm::ConstantVector::get(&Args[0], NumElements);
llvm::Value *Yay = Builder.CreateShuffleVector(UnV, UnV, Mask, "splat");
return Yay;
@@ -482,7 +520,7 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
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();
@@ -493,7 +531,7 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
else
return Builder.CreateUIToFP(Src, DstTy, "conv");
}
-
+
assert(Src->getType()->isFloatingPoint() && "Unknown real conversion");
if (isa<llvm::IntegerType>(DstTy)) {
if (DstType->isSignedIntegerType())
@@ -509,15 +547,15 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
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.
+/// 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();
-
+ SrcTy = SrcTy->getAs<ComplexType>()->getElementType();
+
// Handle conversions to bool first, they are special: comparisons against 0.
if (DstTy->isBooleanType()) {
// Complex != 0 -> (Real != 0) | (Imag != 0)
@@ -525,11 +563,11 @@ EmitComplexToScalarConversion(CodeGenFunction::ComplexPairTy Src,
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.
+ // corresponding real type.
return EmitScalarConversion(Src.first, SrcTy, DstTy);
}
@@ -565,72 +603,122 @@ Value *ScalarExprEmitter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
// 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,
+ Idx = Builder.CreateIntCast(Idx,
+ llvm::Type::getInt32Ty(CGF.getLLVMContext()),
+ 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();
+// 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 CastExpr *CE) {
+ const Expr *E = CE->getSubExpr();
+ QualType DestTy = CE->getType();
+ CastExpr::CastKind Kind = CE->getCastKind();
- // 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.
+ if (!DestTy->isVoidType())
+ TestAndClearIgnoreResultAssign();
+
+ switch (Kind) {
+ default:
+ // FIXME: Assert here.
+ // assert(0 && "Unhandled cast kind!");
+ break;
+ case CastExpr::CK_Unknown:
+ // FIXME: We should really assert here - Unknown casts should never get
+ // as far as to codegen.
+ break;
+ case CastExpr::CK_BitCast: {
+ Value *Src = Visit(const_cast<Expr*>(E));
+ return Builder.CreateBitCast(Src, ConvertType(DestTy));
+ }
+ case CastExpr::CK_ArrayToPointerDecay: {
+ assert(E->getType()->isArrayType() &&
+ "Array to pointer decay must have array source type!");
+
+ Value *V = EmitLValue(E).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()) {
+ if (!E->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");
+ const llvm::Type *DestLTy = ConvertType(DestTy);
+ if (V->getType() != DestLTy) {
+ if (isa<llvm::PointerType>(DestLTy))
+ V = Builder.CreateBitCast(V, DestLTy, "ptrconv");
else {
- assert(isa<llvm::IntegerType>(DestTy) && "Unknown array decay");
- V = Builder.CreatePtrToInt(V, DestTy, "ptrconv");
+ assert(isa<llvm::IntegerType>(DestLTy) && "Unknown array decay");
+ V = Builder.CreatePtrToInt(V, DestLTy, "ptrconv");
}
}
return V;
}
+ case CastExpr::CK_NullToMemberPointer:
+ return CGF.CGM.EmitNullConstant(DestTy);
+
+ case CastExpr::CK_DerivedToBase: {
+ const RecordType *DerivedClassTy =
+ E->getType()->getAs<PointerType>()->getPointeeType()->getAs<RecordType>();
+ CXXRecordDecl *DerivedClassDecl =
+ cast<CXXRecordDecl>(DerivedClassTy->getDecl());
+
+ const RecordType *BaseClassTy =
+ DestTy->getAs<PointerType>()->getPointeeType()->getAs<RecordType>();
+ CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseClassTy->getDecl());
+
+ Value *Src = Visit(const_cast<Expr*>(E));
- return EmitCastExpr(Op, E->getType());
-}
+ bool NullCheckValue = true;
+
+ if (isa<CXXThisExpr>(E)) {
+ // We always assume that 'this' is never null.
+ NullCheckValue = false;
+ } else if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(CE)) {
+ // And that lvalue casts are never null.
+ if (ICE->isLvalueCast())
+ NullCheckValue = false;
+ }
+ return CGF.GetAddressCXXOfBaseClass(Src, DerivedClassDecl, BaseClassDecl,
+ NullCheckValue);
+ }
+ case CastExpr::CK_IntegralToPointer: {
+ Value *Src = Visit(const_cast<Expr*>(E));
+ return Builder.CreateIntToPtr(Src, ConvertType(DestTy));
+ }
-// 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();
+ case CastExpr::CK_PointerToIntegral: {
+ Value *Src = Visit(const_cast<Expr*>(E));
+ return Builder.CreatePtrToInt(Src, ConvertType(DestTy));
+ }
+
+ }
// 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;
@@ -661,7 +749,10 @@ Value *ScalarExprEmitter::VisitStmtExpr(const StmtExpr *E) {
}
Value *ScalarExprEmitter::VisitBlockDeclRefExpr(const BlockDeclRefExpr *E) {
- return Builder.CreateLoad(CGF.GetAddrOfBlockDecl(E), false, "tmp");
+ llvm::Value *V = CGF.GetAddrOfBlockDecl(E);
+ if (E->getType().isObjCGCWeak())
+ return CGF.CGM.getObjCRuntime().EmitObjCWeakRead(CGF, V);
+ return Builder.CreateLoad(V, false, "tmp");
}
//===----------------------------------------------------------------------===//
@@ -673,55 +764,80 @@ Value *ScalarExprEmitter::VisitPrePostIncDec(const UnaryOperator *E,
LValue LV = EmitLValue(E->getSubExpr());
QualType ValTy = E->getSubExpr()->getType();
Value *InVal = CGF.EmitLoadOfLValue(LV, ValTy).getScalarVal();
-
+
+ llvm::LLVMContext &VMContext = CGF.getLLVMContext();
+
int AmountVal = isInc ? 1 : -1;
if (ValTy->isPointerType() &&
- ValTy->getAsPointerType()->isVariableArrayType()) {
+ ValTy->getAs<PointerType>()->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 =
+ if (const llvm::PointerType *PT =
dyn_cast<llvm::PointerType>(InVal->getType())) {
- llvm::Constant *Inc =llvm::ConstantInt::get(llvm::Type::Int32Ty, AmountVal);
+ llvm::Constant *Inc =
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), AmountVal);
if (!isa<llvm::FunctionType>(PT->getElementType())) {
- NextVal = Builder.CreateGEP(InVal, Inc, "ptrincdec");
+ QualType PTEE = ValTy->getPointeeType();
+ if (const ObjCInterfaceType *OIT =
+ dyn_cast<ObjCInterfaceType>(PTEE)) {
+ // Handle interface types, which are not represented with a concrete type.
+ int size = CGF.getContext().getTypeSize(OIT) / 8;
+ if (!isInc)
+ size = -size;
+ Inc = llvm::ConstantInt::get(Inc->getType(), size);
+ const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(VMContext);
+ InVal = Builder.CreateBitCast(InVal, i8Ty);
+ NextVal = Builder.CreateGEP(InVal, Inc, "add.ptr");
+ llvm::Value *lhs = LV.getAddress();
+ lhs = Builder.CreateBitCast(lhs, llvm::PointerType::getUnqual(i8Ty));
+ LV = LValue::MakeAddr(lhs, CGF.MakeQualifiers(ValTy));
+ } else
+ NextVal = Builder.CreateInBoundsGEP(InVal, Inc, "ptrincdec");
} else {
- const llvm::Type *i8Ty = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+ const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(VMContext);
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) {
+ } else if (InVal->getType() == llvm::Type::getInt1Ty(VMContext) && 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();
+ NextVal = llvm::ConstantInt::getTrue(VMContext);
} else if (isa<llvm::IntegerType>(InVal->getType())) {
NextVal = llvm::ConstantInt::get(InVal->getType(), AmountVal);
- NextVal = Builder.CreateAdd(InVal, NextVal, isInc ? "inc" : "dec");
+
+ // Signed integer overflow is undefined behavior.
+ if (ValTy->isSignedIntegerType())
+ NextVal = Builder.CreateNSWAdd(InVal, NextVal, isInc ? "inc" : "dec");
+ else
+ NextVal = Builder.CreateAdd(InVal, NextVal, isInc ? "inc" : "dec");
} else {
// Add the inc/dec to the real part.
- 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)));
+ if (InVal->getType()->isFloatTy())
+ NextVal =
+ llvm::ConstantFP::get(VMContext,
+ llvm::APFloat(static_cast<float>(AmountVal)));
+ else if (InVal->getType()->isDoubleTy())
+ NextVal =
+ llvm::ConstantFP::get(VMContext,
+ 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 = llvm::ConstantFP::get(VMContext, F);
}
NextVal = Builder.CreateFAdd(InVal, NextVal, isInc ? "inc" : "dec");
}
-
+
// Store the updated result through the lvalue.
if (LV.isBitfield())
CGF.EmitStoreThroughBitfieldLValue(RValue::get(NextVal), LV, ValTy,
@@ -752,12 +868,12 @@ Value *ScalarExprEmitter::VisitUnaryNot(const UnaryOperator *E) {
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");
}
@@ -768,7 +884,7 @@ Value *
ScalarExprEmitter::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) {
QualType TypeToSize = E->getTypeOfArgument();
if (E->isSizeOf()) {
- if (const VariableArrayType *VAT =
+ if (const VariableArrayType *VAT =
CGF.getContext().getAsVariableArrayType(TypeToSize)) {
if (E->isArgumentType()) {
// sizeof(type) - make sure to emit the VLA size.
@@ -778,16 +894,16 @@ ScalarExprEmitter::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) {
// 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.
+ // 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());
+ return llvm::ConstantInt::get(VMContext, Result.Val.getInt());
}
Value *ScalarExprEmitter::VisitUnaryReal(const UnaryOperator *E) {
@@ -800,7 +916,7 @@ 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)
@@ -810,8 +926,7 @@ Value *ScalarExprEmitter::VisitUnaryImag(const UnaryOperator *E) {
return llvm::Constant::getNullValue(ConvertType(E->getType()));
}
-Value *ScalarExprEmitter::VisitUnaryOffsetOf(const UnaryOperator *E)
-{
+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");
@@ -839,10 +954,10 @@ Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E,
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.)
+ // 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()));
}
@@ -857,17 +972,17 @@ Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E,
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...'.
+ // 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,
@@ -949,31 +1064,31 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
Builder.SetInsertPoint(overflowBB);
// Handler is:
- // long long *__overflow_handler)(long long a, long long b, char op,
+ // 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);
+ handerArgTypes.push_back(llvm::Type::getInt64Ty(VMContext));
+ handerArgTypes.push_back(llvm::Type::getInt64Ty(VMContext));
+ handerArgTypes.push_back(llvm::Type::getInt8Ty(VMContext));
+ handerArgTypes.push_back(llvm::Type::getInt8Ty(VMContext));
+ llvm::FunctionType *handlerTy = llvm::FunctionType::get(
+ llvm::Type::getInt64Ty(VMContext), 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,
+ Builder.CreateSExt(Ops.LHS, llvm::Type::getInt64Ty(VMContext)),
+ Builder.CreateSExt(Ops.RHS, llvm::Type::getInt64Ty(VMContext)),
+ llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), OpID),
+ llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext),
cast<llvm::IntegerType>(opTy)->getBitWidth()));
handlerResult = Builder.CreateTrunc(handlerResult, opTy);
Builder.CreateBr(continueBB);
-
+
// Set up the continuation
Builder.SetInsertPoint(continueBB);
// Get the correct result
@@ -986,31 +1101,39 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
}
Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) {
- if (!Ops.Ty->isPointerType()) {
+ if (!Ops.Ty->isAnyPointerType()) {
if (CGF.getContext().getLangOptions().OverflowChecking &&
Ops.Ty->isSignedIntegerType())
return EmitOverflowCheckedBinOp(Ops);
-
+
if (Ops.LHS->getType()->isFPOrFPVector())
return Builder.CreateFAdd(Ops.LHS, Ops.RHS, "add");
-
+
+ // Signed integer overflow is undefined behavior.
+ if (Ops.Ty->isSignedIntegerType())
+ return Builder.CreateNSWAdd(Ops.LHS, Ops.RHS, "add");
+
return Builder.CreateAdd(Ops.LHS, Ops.RHS, "add");
}
- if (Ops.Ty->getAsPointerType()->isVariableArrayType()) {
+ if (Ops.Ty->isPointerType() &&
+ Ops.Ty->getAs<PointerType>()->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())) {
+ const PointerType *PT = Ops.E->getLHS()->getType()->getAs<PointerType>();
+ const ObjCObjectPointerType *OPT =
+ Ops.E->getLHS()->getType()->getAs<ObjCObjectPointerType>();
+ if (PT || OPT) {
Ptr = Ops.LHS;
Idx = Ops.RHS;
IdxExp = Ops.E->getRHS();
- } else { // int + pointer
- PT = Ops.E->getRHS()->getType()->getAsPointerType();
- assert(PT && "Invalid add expr");
+ } else { // int + pointer
+ PT = Ops.E->getRHS()->getType()->getAs<PointerType>();
+ OPT = Ops.E->getRHS()->getType()->getAs<ObjCObjectPointerType>();
+ assert((PT || OPT) && "Invalid add expr");
Ptr = Ops.RHS;
Idx = Ops.LHS;
IdxExp = Ops.E->getLHS();
@@ -1020,38 +1143,37 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) {
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);
+ const llvm::Type *IdxType =
+ llvm::IntegerType::get(VMContext, 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.
+ const QualType ElementType = PT ? PT->getPointeeType() : OPT->getPointeeType();
+ // Handle interface types, which are not represented with a concrete type.
if (const ObjCInterfaceType *OIT = dyn_cast<ObjCInterfaceType>(ElementType)) {
- llvm::Value *InterfaceSize =
+ 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);
+ const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(VMContext);
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.
+ // 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);
+ const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(VMContext);
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");
+ }
+
+ return Builder.CreateInBoundsGEP(Ptr, Idx, "add.ptr");
}
Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) {
@@ -1065,7 +1187,8 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) {
return Builder.CreateSub(Ops.LHS, Ops.RHS, "sub");
}
- if (Ops.E->getLHS()->getType()->getAsPointerType()->isVariableArrayType()) {
+ if (Ops.E->getLHS()->getType()->isPointerType() &&
+ Ops.E->getLHS()->getType()->getAs<PointerType>()->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
@@ -1074,7 +1197,7 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) {
}
const QualType LHSType = Ops.E->getLHS()->getType();
- const QualType LHSElementType = LHSType->getAsPointerType()->getPointeeType();
+ const QualType LHSElementType = LHSType->getPointeeType();
if (!isa<llvm::PointerType>(Ops.RHS->getType())) {
// pointer - int
Value *Idx = Ops.RHS;
@@ -1082,7 +1205,8 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) {
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);
+ const llvm::Type *IdxType =
+ llvm::IntegerType::get(VMContext, CGF.LLVMPointerWidth);
if (Ops.E->getRHS()->getType()->isSignedIntegerType())
Idx = Builder.CreateSExt(Idx, IdxType, "idx.ext");
else
@@ -1090,36 +1214,35 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) {
}
Idx = Builder.CreateNeg(Idx, "sub.ptr.neg");
- // Handle interface types, which are not represented with a concrete
- // type.
- if (const ObjCInterfaceType *OIT =
+ // Handle interface types, which are not represented with a concrete type.
+ if (const ObjCInterfaceType *OIT =
dyn_cast<ObjCInterfaceType>(LHSElementType)) {
- llvm::Value *InterfaceSize =
+ 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);
+ const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(VMContext);
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.
+ // 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);
+ const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(VMContext);
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");
+ }
+
+ return Builder.CreateInBoundsGEP(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
@@ -1129,28 +1252,21 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) {
} 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.
+
+ // Otherwise, do a full sdiv. This uses the "exact" form of sdiv, since
+ // pointer difference in C is only defined in the case where both operands
+ // are pointing to elements of an array.
Value *BytesPerElt = llvm::ConstantInt::get(ResultType, ElementSize);
- return Builder.CreateSDiv(BytesBetween, BytesPerElt, "sub.ptr.div");
+ return Builder.CreateExactSDiv(BytesBetween, BytesPerElt, "sub.ptr.div");
}
}
@@ -1160,7 +1276,7 @@ Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) {
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");
}
@@ -1170,7 +1286,7 @@ Value *ScalarExprEmitter::EmitShr(const BinOpInfo &Ops) {
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");
@@ -1181,11 +1297,11 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc,
TestAndClearIgnoreResultAssign();
Value *Result;
QualType LHSTy = E->getLHS()->getType();
- if (!LHSTy->isAnyComplexType() && !LHSTy->isVectorType()) {
+ if (!LHSTy->isAnyComplexType()) {
Value *LHS = Visit(E->getLHS());
Value *RHS = Visit(E->getRHS());
-
- if (LHS->getType()->isFloatingPoint()) {
+
+ if (LHS->getType()->isFPOrFPVector()) {
Result = Builder.CreateFCmp((llvm::CmpInst::Predicate)FCmpOpc,
LHS, RHS, "cmp");
} else if (LHSTy->isSignedIntegerType()) {
@@ -1196,29 +1312,19 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc,
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;
+
+ // If this is a vector comparison, sign extend the result to the appropriate
+ // vector integer type and return it (don't convert to bool).
+ if (LHSTy->isVectorType())
+ return Builder.CreateSExt(Result, ConvertType(E->getType()), "sext");
+
} 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();
-
+
+ QualType CETy = LHSTy->getAs<ComplexType>()->getElementType();
+
Value *ResultR, *ResultI;
if (CETy->isRealFloatingType()) {
ResultR = Builder.CreateFCmp((llvm::FCmpInst::Predicate)FCmpOpc,
@@ -1233,7 +1339,7 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc,
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 {
@@ -1253,7 +1359,7 @@ Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) {
// 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
@@ -1281,12 +1387,12 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
// 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");
@@ -1296,17 +1402,18 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
// 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);
+ llvm::PHINode *PN = llvm::PHINode::Create(llvm::Type::getInt1Ty(VMContext),
+ "", 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);
-
+ PN->addIncoming(llvm::ConstantInt::getFalse(VMContext), *PI);
+
CGF.PushConditionalTempDestruction();
CGF.EmitBlock(RHSBlock);
Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());
CGF.PopConditionalTempDestruction();
-
+
// Reaquire the RHS block, as there may be subblocks inserted.
RHSBlock = Builder.GetInsertBlock();
@@ -1314,7 +1421,7 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
// 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");
}
@@ -1328,43 +1435,44 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
// 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);
+ llvm::PHINode *PN = llvm::PHINode::Create(llvm::Type::getInt1Ty(VMContext),
+ "", 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);
+ PN->addIncoming(llvm::ConstantInt::getTrue(VMContext), *PI);
CGF.PushConditionalTempDestruction();
// Emit the RHS condition as a bool value.
CGF.EmitBlock(RHSBlock);
Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());
-
+
CGF.PopConditionalTempDestruction();
-
+
// 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");
}
@@ -1386,19 +1494,19 @@ Value *ScalarExprEmitter::VisitBinComma(const BinaryOperator *E) {
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;
}
@@ -1412,7 +1520,7 @@ VisitConditionalOperator(const ConditionalOperator *E) {
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.
@@ -1420,8 +1528,8 @@ VisitConditionalOperator(const ConditionalOperator *E) {
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.
@@ -1432,15 +1540,15 @@ VisitConditionalOperator(const ConditionalOperator *E) {
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 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.
@@ -1450,7 +1558,7 @@ VisitConditionalOperator(const ConditionalOperator *E) {
// 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
@@ -1458,7 +1566,7 @@ VisitConditionalOperator(const ConditionalOperator *E) {
// 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);
@@ -1467,33 +1575,33 @@ VisitConditionalOperator(const ConditionalOperator *E) {
CGF.PushConditionalTempDestruction();
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());
-
+
CGF.PopConditionalTempDestruction();
LHSBlock = Builder.GetInsertBlock();
CGF.EmitBranch(ContBlock);
-
+
CGF.PushConditionalTempDestruction();
CGF.EmitBlock(RHSBlock);
-
+
Value *RHS = Visit(E->getRHS());
CGF.PopConditionalTempDestruction();
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);
@@ -1511,7 +1619,7 @@ Value *ScalarExprEmitter::VisitVAArgExpr(VAArgExpr *VE) {
llvm::Value *ArgPtr = CGF.EmitVAArg(ArgValue, VE->getType());
// If EmitVAArg fails, we fall back to the LLVM instruction.
- if (!ArgPtr)
+ if (!ArgPtr)
return Builder.CreateVAArg(ArgValue, ConvertType(VE->getType()));
// FIXME Volatility.
@@ -1526,12 +1634,12 @@ Value *ScalarExprEmitter::VisitBlockExpr(const BlockExpr *BE) {
// Entry Point into this File
//===----------------------------------------------------------------------===//
-/// EmitScalarExpr - Emit the computation of the specified expression of
-/// scalar type, ignoring the result.
+/// 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));
}
@@ -1545,9 +1653,9 @@ Value *CodeGenFunction::EmitScalarConversion(Value *Src, QualType SrcTy,
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.
+/// 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) {
@@ -1560,38 +1668,40 @@ Value *CodeGenFunction::EmitComplexToScalarConversion(ComplexPairTy Src,
Value *CodeGenFunction::EmitShuffleVector(Value* V1, Value *V2, ...) {
assert(V1->getType() == V2->getType() &&
"Vector operands must be of the same type");
- unsigned NumElements =
+ 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 &&
+ assert(n >= 0 && n < (int)NumElements * 2 &&
"Vector shuffle index out of bounds!");
- Args.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, n));
+ Args.push_back(llvm::ConstantInt::get(
+ llvm::Type::getInt32Ty(VMContext), 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,
+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);
+ llvm::Value *Idx = llvm::ConstantInt::get(
+ llvm::Type::getInt32Ty(VMContext), i);
Vec = Builder.CreateInsertElement(Vec, Val, Idx, "tmp");
}
-
- return Vec;
+
+ return Vec;
}
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index 33cb5bc..cadba32 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -24,7 +24,7 @@ using namespace clang;
using namespace CodeGen;
/// Emits an instance of NSConstantString representing the object.
-llvm::Value *CodeGenFunction::EmitObjCStringLiteral(const ObjCStringLiteral *E)
+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.
@@ -50,7 +50,7 @@ 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;
@@ -70,7 +70,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E) {
} else {
Receiver = Runtime.GetClass(Builder, OID);
}
-
+
isClassMessage = true;
} else if (isa<ObjCSuperExpr>(E->getReceiver())) {
isSuperMessage = true;
@@ -81,7 +81,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E) {
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);
@@ -92,9 +92,11 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E) {
isCategoryImpl,
Receiver,
isClassMessage,
- Args);
+ Args,
+ E->getMethodDecl());
}
- return Runtime.GenerateMessageSend(*this, E->getType(), E->getSelector(),
+
+ return Runtime.GenerateMessageSend(*this, E->getType(), E->getSelector(),
Receiver, isClassMessage, Args,
E->getMethodDecl());
}
@@ -110,7 +112,7 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD,
const CGFunctionInfo &FI = CGM.getTypes().getFunctionInfo(OMD);
CGM.SetInternalFunctionAttributes(OMD, Fn, FI);
- Args.push_back(std::make_pair(OMD->getSelfDecl(),
+ Args.push_back(std::make_pair(OMD->getSelfDecl(),
OMD->getSelfDecl()->getType()));
Args.push_back(std::make_pair(OMD->getCmdDecl(),
OMD->getCmdDecl()->getType()));
@@ -123,10 +125,10 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD,
}
/// Generate an Objective-C method. An Objective-C method is a C function with
-/// its pointer, name, and types registered in the class struture.
+/// 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>())
+ if (CGM.getDebugInfo() && !OMD->hasAttr<NoDebugAttr>())
DebugInfo = CGM.getDebugInfo();
StartObjCMethod(OMD, OMD->getClassInterface());
EmitStmt(OMD->getBody());
@@ -159,9 +161,9 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP,
!(PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic) &&
(PD->getSetterKind() == ObjCPropertyDecl::Copy ||
PD->getSetterKind() == ObjCPropertyDecl::Retain)) {
- llvm::Value *GetPropertyFn =
+ llvm::Value *GetPropertyFn =
CGM.getObjCRuntime().GetPropertyGetFunction();
-
+
if (!GetPropertyFn) {
CGM.ErrorUnsupported(PID, "Obj-C getter requiring atomic copy");
FinishFunction();
@@ -175,7 +177,7 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP,
ValueDecl *Cmd = OMD->getCmdDecl();
llvm::Value *CmdVal = Builder.CreateLoad(LocalDeclMap[Cmd], "cmd");
QualType IdTy = getContext().getObjCIdType();
- llvm::Value *SelfAsId =
+ llvm::Value *SelfAsId =
Builder.CreateBitCast(LoadObjCSelf(), Types.ConvertType(IdTy));
llvm::Value *Offset = EmitIvarOffset(IMP->getClassInterface(), Ivar);
llvm::Value *True =
@@ -187,24 +189,23 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP,
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),
+ 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(),
+ 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 {
+ } else {
CodeGenTypes &Types = CGM.getTypes();
RValue RV = EmitLoadOfLValue(LV, Ivar->getType());
RV = RValue::get(Builder.CreateBitCast(RV.getScalarVal(),
- Types.ConvertType(PD->getType())));
+ Types.ConvertType(PD->getType())));
EmitReturnOfRValue(RV, PD->getType());
}
}
@@ -227,7 +228,7 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
StartObjCMethod(OMD, IMP->getClassInterface());
bool IsCopy = PD->getSetterKind() == ObjCPropertyDecl::Copy;
- bool IsAtomic =
+ bool IsAtomic =
!(PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic);
// Determine if we should use an objc_setProperty call for
@@ -237,16 +238,16 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
if (IsCopy ||
(CGM.getLangOptions().getGCMode() != LangOptions::GCOnly &&
PD->getSetterKind() == ObjCPropertyDecl::Retain)) {
- llvm::Value *SetPropertyFn =
+ 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,
+
+ // 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.
@@ -254,11 +255,11 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
ValueDecl *Cmd = OMD->getCmdDecl();
llvm::Value *CmdVal = Builder.CreateLoad(LocalDeclMap[Cmd], "cmd");
QualType IdTy = getContext().getObjCIdType();
- llvm::Value *SelfAsId =
+ 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 =
+ llvm::Value *ArgAsId =
Builder.CreateBitCast(Builder.CreateLoad(Arg, "arg"),
Types.ConvertType(IdTy));
llvm::Value *True =
@@ -270,13 +271,13 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
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),
+ Args.push_back(std::make_pair(RValue::get(IsAtomic ? True : False),
getContext().BoolTy));
- Args.push_back(std::make_pair(RValue::get(IsCopy ? True : False),
+ 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),
+ EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args),
SetPropertyFn, Args);
} else {
SourceLocation Loc = PD->getLocation();
@@ -305,18 +306,18 @@ llvm::Value *CodeGenFunction::LoadObjCSelf() {
QualType CodeGenFunction::TypeOfSelfObject() {
const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl);
ImplicitParamDecl *selfDecl = OMD->getSelfDecl();
- const PointerType *PTy =
- cast<PointerType>(getContext().getCanonicalType(selfDecl->getType()));
+ const ObjCObjectPointerType *PTy = cast<ObjCObjectPointerType>(
+ getContext().getCanonicalType(selfDecl->getType()));
return PTy->getPointeeType();
}
-RValue CodeGenFunction::EmitObjCSuperPropertyGet(const Expr *Exp,
+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,
+ return CGM.getObjCRuntime().GenerateMessageSendSuper(*this,
Exp->getType(),
S,
OMD->getClassInterface(),
@@ -324,36 +325,36 @@ RValue CodeGenFunction::EmitObjCSuperPropertyGet(const Expr *Exp,
Receiver,
isClassMessage,
CallArgList());
-
+
}
RValue CodeGenFunction::EmitObjCPropertyGet(const Expr *Exp) {
+ Exp = Exp->IgnoreParens();
// 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()),
+ GenerateMessageSend(*this, Exp->getType(), S,
+ EmitScalarExpr(E->getBase()),
false, CallArgList());
- }
- else {
- const ObjCKVCRefExpr *KE = cast<ObjCKVCRefExpr>(Exp);
+ } else {
+ const ObjCImplicitSetterGetterRefExpr *KE =
+ cast<ObjCImplicitSetterGetterRefExpr>(Exp);
Selector S = KE->getGetterMethod()->getSelector();
llvm::Value *Receiver;
- if (KE->getClassProp()) {
- const ObjCInterfaceDecl *OID = KE->getClassProp();
+ if (KE->getInterfaceDecl()) {
+ const ObjCInterfaceDecl *OID = KE->getInterfaceDecl();
Receiver = CGM.getObjCRuntime().GetClass(Builder, OID);
- }
- else if (isa<ObjCSuperExpr>(KE->getBase()))
+ } else if (isa<ObjCSuperExpr>(KE->getBase()))
return EmitObjCSuperPropertyGet(KE, S);
- else
+ else
Receiver = EmitScalarExpr(KE->getBase());
return CGM.getObjCRuntime().
- GenerateMessageSend(*this, Exp->getType(), S,
- Receiver,
- KE->getClassProp() != 0, CallArgList());
+ GenerateMessageSend(*this, Exp->getType(), S,
+ Receiver,
+ KE->getInterfaceDecl() != 0, CallArgList());
}
}
@@ -366,7 +367,7 @@ void CodeGenFunction::EmitObjCSuperPropertySet(const Expr *Exp,
bool isClassMessage = OMD->isClassMethod();
bool isCategoryImpl = isa<ObjCCategoryImplDecl>(OMD->getDeclContext());
Args.push_back(std::make_pair(Src, Exp->getType()));
- CGM.getObjCRuntime().GenerateMessageSendSuper(*this,
+ CGM.getObjCRuntime().GenerateMessageSendSuper(*this,
Exp->getType(),
S,
OMD->getClassInterface(),
@@ -385,42 +386,39 @@ void CodeGenFunction::EmitObjCPropertySet(const Expr *Exp,
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()),
+ CGM.getObjCRuntime().GenerateMessageSend(*this, getContext().VoidTy, S,
+ EmitScalarExpr(E->getBase()),
false, Args);
- }
- else if (const ObjCKVCRefExpr *E = dyn_cast<ObjCKVCRefExpr>(Exp)) {
+ } else if (const ObjCImplicitSetterGetterRefExpr *E =
+ dyn_cast<ObjCImplicitSetterGetterRefExpr>(Exp)) {
Selector S = E->getSetterMethod()->getSelector();
CallArgList Args;
llvm::Value *Receiver;
- if (E->getClassProp()) {
- const ObjCInterfaceDecl *OID = E->getClassProp();
+ if (E->getInterfaceDecl()) {
+ const ObjCInterfaceDecl *OID = E->getInterfaceDecl();
Receiver = CGM.getObjCRuntime().GetClass(Builder, OID);
- }
- else if (isa<ObjCSuperExpr>(E->getBase())) {
+ } else if (isa<ObjCSuperExpr>(E->getBase())) {
EmitObjCSuperPropertySet(E, S, Src);
return;
- }
- else
+ } 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
+ CGM.getObjCRuntime().GenerateMessageSend(*this, getContext().VoidTy, S,
+ Receiver,
+ E->getInterfaceDecl() != 0, Args);
+ } else
assert (0 && "bad expression node in EmitObjCPropertySet");
}
void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
- llvm::Constant *EnumerationMutationFn =
+ llvm::Constant *EnumerationMutationFn =
CGM.getObjCRuntime().EnumerationMutationFunction();
llvm::Value *DeclAddress;
QualType ElementTy;
-
+
if (!EnumerationMutationFn) {
CGM.ErrorUnsupported(&S, "Obj-C fast enumeration for this runtime");
return;
@@ -431,62 +429,62 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
assert(HaveInsertPoint() && "DeclStmt destroyed insert point!");
const Decl* D = SD->getSingleDecl();
ElementTy = cast<ValueDecl>(D)->getType();
- DeclAddress = LocalDeclMap[D];
+ 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),
+ llvm::AllocaInst *StatePtr = CreateTempAlloca(ConvertType(StateTy),
"state.ptr");
- StatePtr->setAlignment(getContext().getTypeAlign(StateTy) >> 3);
+ 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(),
+ Selector FastEnumSel = CGM.getContext().Selectors.getSelector(II.size(),
&II[0]);
QualType ItemsTy =
getContext().getConstantArrayType(getContext().getObjCIdType(),
- llvm::APInt(32, NumItems),
+ 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),
+ Args.push_back(std::make_pair(RValue::get(StatePtr),
getContext().getPointerType(StateTy)));
-
- Args.push_back(std::make_pair(RValue::get(ItemsPtr),
+
+ 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),
+ Args.push_back(std::make_pair(RValue::get(Count),
getContext().UnsignedLongTy));
-
- RValue CountRV =
- CGM.getObjCRuntime().GenerateMessageSend(*this,
+
+ 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);
@@ -494,60 +492,60 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
Builder.CreateCondBr(IsZero, NoElements, SetStartMutations);
EmitBlock(SetStartMutations);
-
- llvm::Value *StartMutationsPtr =
+
+ llvm::Value *StartMutationsPtr =
CreateTempAlloca(UnsignedLongLTy);
-
- llvm::Value *StateMutationsPtrPtr =
+
+ llvm::Value *StateMutationsPtrPtr =
Builder.CreateStructGEP(StatePtr, 2, "mutationsptr.ptr");
- llvm::Value *StateMutationsPtr = Builder.CreateLoad(StateMutationsPtrPtr,
+ llvm::Value *StateMutationsPtr = Builder.CreateLoad(StateMutationsPtrPtr,
"mutationsptr");
-
- llvm::Value *StateMutations = Builder.CreateLoad(StateMutationsPtr,
+
+ 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");
+
+ llvm::BasicBlock *LoopBody = createBasicBlock("loopbody");
EmitBlock(LoopBody);
StateMutationsPtr = Builder.CreateLoad(StateMutationsPtrPtr, "mutationsptr");
StateMutations = Builder.CreateLoad(StateMutationsPtr, "statemutations");
- llvm::Value *StartMutations = Builder.CreateLoad(StartMutationsPtr,
+ llvm::Value *StartMutations = Builder.CreateLoad(StartMutationsPtr,
"mutations");
- llvm::Value *MutationsEqual = Builder.CreateICmpEQ(StateMutations,
+ 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,
+ Builder.CreateBitCast(Collection,
ConvertType(getContext().getObjCIdType()),
"tmp");
CallArgList Args2;
- Args2.push_back(std::make_pair(RValue::get(V),
+ 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),
+ EmitCall(CGM.getTypes().getFunctionInfo(getContext().VoidTy, Args2),
EnumerationMutationFn, Args2);
-
+
EmitBlock(WasNotMutated);
-
- llvm::Value *StateItemsPtr =
+
+ llvm::Value *StateItemsPtr =
Builder.CreateStructGEP(StatePtr, 1, "stateitems.ptr");
llvm::Value *Counter = Builder.CreateLoad(CounterPtr, "counter");
@@ -555,39 +553,39 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
llvm::Value *EnumStateItems = Builder.CreateLoad(StateItemsPtr,
"stateitems");
- llvm::Value *CurrentItemPtr =
+ 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,
+ 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);
@@ -597,18 +595,18 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
// Fetch more elements.
EmitBlock(FetchMore);
-
- CountRV =
- CGM.getObjCRuntime().GenerateMessageSend(*this,
+
+ CountRV =
+ CGM.getObjCRuntime().GenerateMessageSend(*this,
getContext().UnsignedLongTy,
- FastEnumSel,
+ 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);
@@ -616,7 +614,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
// 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());
@@ -625,19 +623,16 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
EmitBlock(LoopEnd);
}
-void CodeGenFunction::EmitObjCAtTryStmt(const ObjCAtTryStmt &S)
-{
+void CodeGenFunction::EmitObjCAtTryStmt(const ObjCAtTryStmt &S) {
CGM.getObjCRuntime().EmitTryOrSynchronizedStmt(*this, S);
}
-void CodeGenFunction::EmitObjCAtThrowStmt(const ObjCAtThrowStmt &S)
-{
+void CodeGenFunction::EmitObjCAtThrowStmt(const ObjCAtThrowStmt &S) {
CGM.getObjCRuntime().EmitThrowStmt(*this, S);
}
void CodeGenFunction::EmitObjCAtSynchronizedStmt(
- const ObjCAtSynchronizedStmt &S)
-{
+ const ObjCAtSynchronizedStmt &S) {
CGM.getObjCRuntime().EmitTryOrSynchronizedStmt(*this, S);
}
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index 6554da9..f348bff 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -43,6 +43,7 @@ using llvm::dyn_cast;
static const int RuntimeVersion = 8;
static const int NonFragileRuntimeVersion = 9;
static const int ProtocolVersion = 2;
+static const int NonFragileProtocolVersion = 3;
namespace {
class CGObjCGNU : public CodeGen::CGObjCRuntime {
@@ -50,9 +51,11 @@ private:
CodeGen::CodeGenModule &CGM;
llvm::Module &TheModule;
const llvm::PointerType *SelectorTy;
+ const llvm::IntegerType *Int8Ty;
const llvm::PointerType *PtrToInt8Ty;
const llvm::FunctionType *IMPTy;
const llvm::PointerType *IdTy;
+ QualType ASTIdTy;
const llvm::IntegerType *IntTy;
const llvm::PointerType *PtrTy;
const llvm::IntegerType *LongTy;
@@ -70,6 +73,7 @@ private:
// Some zeros used for GEPs in lots of places.
llvm::Constant *Zeros[2];
llvm::Constant *NULLPtr;
+ llvm::LLVMContext &VMContext;
private:
llvm::Constant *GenerateIvarList(
const llvm::SmallVectorImpl<llvm::Constant *> &IvarNames,
@@ -77,12 +81,19 @@ private:
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,
+ const llvm::SmallVectorImpl<Selector> &MethodSels,
+ const llvm::SmallVectorImpl<llvm::Constant *> &MethodTypes,
bool isClassMethodList);
llvm::Constant *GenerateEmptyProtocol(const std::string &ProtocolName);
+ llvm::Constant *GeneratePropertyList(const ObjCImplementationDecl *OID,
+ llvm::SmallVectorImpl<Selector> &InstanceMethodSels,
+ llvm::SmallVectorImpl<llvm::Constant*> &InstanceMethodTypes);
llvm::Constant *GenerateProtocolList(
const llvm::SmallVectorImpl<std::string> &Protocols);
+ // To ensure that all protocols are seen by the runtime, we add a category on
+ // a class defined in the runtime, declaring no methods, but adopting the
+ // protocols.
+ void GenerateProtocolHolderCategory(void);
llvm::Constant *GenerateClassStructure(
llvm::Constant *MetaClass,
llvm::Constant *SuperClass,
@@ -92,12 +103,16 @@ private:
llvm::Constant *InstanceSize,
llvm::Constant *IVars,
llvm::Constant *Methods,
- llvm::Constant *Protocols);
+ llvm::Constant *Protocols,
+ llvm::Constant *IvarOffsets,
+ llvm::Constant *Properties);
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 *ExportUniqueString(const std::string &Str, const std::string
+ prefix);
llvm::Constant *MakeGlobal(const llvm::StructType *Ty,
std::vector<llvm::Constant*> &V, const std::string &Name="");
llvm::Constant *MakeGlobal(const llvm::ArrayType *Ty,
@@ -108,7 +123,7 @@ private:
public:
CGObjCGNU(CodeGen::CodeGenModule &cgm);
virtual llvm::Constant *GenerateConstantString(const ObjCStringLiteral *);
- virtual CodeGen::RValue
+ virtual CodeGen::RValue
GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
QualType ResultType,
Selector Sel,
@@ -116,7 +131,7 @@ public:
bool IsClassMessage,
const CallArgList &CallArgs,
const ObjCMethodDecl *Method);
- virtual CodeGen::RValue
+ virtual CodeGen::RValue
GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
QualType ResultType,
Selector Sel,
@@ -124,14 +139,15 @@ public:
bool isCategoryImpl,
llvm::Value *Receiver,
bool IsClassMessage,
- const CallArgList &CallArgs);
+ const CallArgList &CallArgs,
+ const ObjCMethodDecl *Method);
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,
+
+ virtual llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD,
const ObjCContainerDecl *CD);
virtual void GenerateCategory(const ObjCCategoryImplDecl *CMD);
virtual void GenerateClass(const ObjCImplementationDecl *ClassDecl);
@@ -139,11 +155,10 @@ public:
const ObjCProtocolDecl *PD);
virtual void GenerateProtocol(const ObjCProtocolDecl *PD);
virtual llvm::Function *ModuleInitFunction();
- virtual void MergeMetadataGlobals(std::vector<llvm::Constant*> &UsedArray);
virtual llvm::Function *GetPropertyGetFunction();
virtual llvm::Function *GetPropertySetFunction();
- virtual llvm::Function *EnumerationMutationFunction();
-
+ virtual llvm::Constant *EnumerationMutationFunction();
+
virtual void EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
const Stmt &S);
virtual void EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
@@ -155,9 +170,14 @@ public:
virtual void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dest);
virtual void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dest);
+ llvm::Value *src, llvm::Value *dest,
+ llvm::Value *ivarOffset);
virtual void EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dest);
+ virtual void EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *DestPtr,
+ llvm::Value *SrcPtr,
+ QualType Ty);
virtual LValue EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF,
QualType ObjectTy,
llvm::Value *BaseValue,
@@ -173,18 +193,19 @@ public:
/// Emits a reference to a dummy variable which is emitted with each class.
/// This ensures that a linker error will be generated when trying to link
/// together modules where a referenced class is not defined.
-void CGObjCGNU::EmitClassRef(const std::string &className){
+void CGObjCGNU::EmitClassRef(const std::string &className) {
std::string symbolRef = "__objc_class_ref_" + className;
// Don't emit two copies of the same symbol
- if (TheModule.getGlobalVariable(symbolRef)) return;
+ if (TheModule.getGlobalVariable(symbolRef))
+ return;
std::string symbolName = "__objc_class_name_" + className;
llvm::GlobalVariable *ClassSymbol = TheModule.getGlobalVariable(symbolName);
if (!ClassSymbol) {
- ClassSymbol = new llvm::GlobalVariable(LongTy, false,
- llvm::GlobalValue::ExternalLinkage, 0, symbolName, &TheModule);
+ ClassSymbol = new llvm::GlobalVariable(TheModule, LongTy, false,
+ llvm::GlobalValue::ExternalLinkage, 0, symbolName);
}
- new llvm::GlobalVariable(ClassSymbol->getType(), true,
- llvm::GlobalValue::CommonLinkage, ClassSymbol, symbolRef, &TheModule);
+ new llvm::GlobalVariable(TheModule, ClassSymbol->getType(), true,
+ llvm::GlobalValue::WeakAnyLinkage, ClassSymbol, symbolRef);
}
static std::string SymbolNameForClass(const std::string &ClassName) {
@@ -200,36 +221,37 @@ static std::string SymbolNameForMethod(const std::string &ClassName, const
CGObjCGNU::CGObjCGNU(CodeGen::CodeGenModule &cgm)
: CGM(cgm), TheModule(CGM.getModule()), ClassPtrAlias(0),
- MetaClassPtrAlias(0) {
+ MetaClassPtrAlias(0), VMContext(cgm.getLLVMContext()) {
IntTy = cast<llvm::IntegerType>(
CGM.getTypes().ConvertType(CGM.getContext().IntTy));
LongTy = cast<llvm::IntegerType>(
CGM.getTypes().ConvertType(CGM.getContext().LongTy));
-
+
+ Int8Ty = llvm::Type::getInt8Ty(VMContext);
+ // C string type. Used in lots of places.
+ PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty);
+
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);
+ NULLPtr = llvm::ConstantPointerNull::get(PtrToInt8Ty);
// 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()));
-
+ ASTIdTy = CGM.getContext().getObjCIdType();
+ IdTy = cast<llvm::PointerType>(CGM.getTypes().ConvertType(ASTIdTy));
+
// 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,
@@ -251,10 +273,10 @@ 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",
+ llvm::GlobalValue::PrivateLinkage,
+ ".objc_untyped_selector_alias"+Sel.getAsString(),
NULL, &TheModule);
-
+
return Builder.CreateLoad(US);
}
@@ -269,15 +291,14 @@ llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl
SelTypes);
// If it's already cached, return it.
- if (TypedSelectors[Selector])
- {
- return Builder.CreateLoad(TypedSelectors[Selector]);
+ 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,
+ llvm::GlobalValue::PrivateLinkage, ".objc_selector_alias" + SelName,
NULL, &TheModule);
TypedSelectors[Selector] = Sel;
@@ -286,23 +307,33 @@ llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl
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);
+ llvm::Constant *ConstStr = CGM.GetAddrOfConstantCString(Str, Name.c_str());
return llvm::ConstantExpr::getGetElementPtr(ConstStr, Zeros, 2);
}
+llvm::Constant *CGObjCGNU::ExportUniqueString(const std::string &Str,
+ const std::string prefix) {
+ std::string name = prefix + Str;
+ llvm::Constant *ConstStr = TheModule.getGlobalVariable(name);
+ if (!ConstStr) {
+ llvm::Constant *value = llvm::ConstantArray::get(VMContext, Str, true);
+ ConstStr = new llvm::GlobalVariable(TheModule, value->getType(), true,
+ llvm::GlobalValue::LinkOnceODRLinkage, value, prefix + Str);
+ }
+ 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);
+ return new llvm::GlobalVariable(TheModule, Ty, false,
+ llvm::GlobalValue::InternalLinkage, C, Name);
}
+
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);
+ return new llvm::GlobalVariable(TheModule, Ty, false,
+ llvm::GlobalValue::InternalLinkage, C, Name);
}
/// Generate an NSConstantString object.
@@ -310,14 +341,14 @@ llvm::Constant *CGObjCGNU::MakeGlobal(const llvm::ArrayType *Ty,
//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(),
+ 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),
+ llvm::StructType::get(VMContext, PtrToInt8Ty, PtrToInt8Ty, IntTy, NULL),
Ivars, ".objc_str");
ConstantStrings.push_back(
llvm::ConstantExpr::getBitCast(ObjCStr, PtrToInt8Ty));
@@ -335,21 +366,23 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
bool isCategoryImpl,
llvm::Value *Receiver,
bool IsClassMessage,
- const CallArgList &CallArgs) {
+ const CallArgList &CallArgs,
+ const ObjCMethodDecl *Method) {
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()));
+ std::make_pair(RValue::get(CGF.Builder.CreateBitCast(Receiver, IdTy)),
+ ASTIdTy));
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);
+ const llvm::FunctionType *impType =
+ Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false);
llvm::Value *ReceiverClass = 0;
if (isCategoryImpl) {
@@ -368,8 +401,8 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
} 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
+ // 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) {
@@ -388,15 +421,16 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
}
}
// 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)));
+ ReceiverClass = CGF.Builder.CreateBitCast(ReceiverClass,
+ llvm::PointerType::getUnqual(
+ llvm::StructType::get(VMContext, 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::StructType *ObjCSuperTy = llvm::StructType::get(VMContext,
+ Receiver->getType(), IdTy, NULL);
llvm::Value *ObjCSuper = CGF.Builder.CreateAlloca(ObjCSuperTy);
CGF.Builder.CreateStore(Receiver, CGF.Builder.CreateStructGEP(ObjCSuper, 0));
@@ -407,7 +441,7 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
std::vector<const llvm::Type*> Params;
Params.push_back(llvm::PointerType::getUnqual(ObjCSuperTy));
Params.push_back(SelectorTy);
- llvm::Constant *lookupFunction =
+ llvm::Constant *lookupFunction =
CGM.CreateRuntimeFunction(llvm::FunctionType::get(
llvm::PointerType::getUnqual(impType), Params, true),
"objc_msg_lookup_super");
@@ -419,7 +453,7 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
return CGF.EmitCall(FnInfo, imp, ActualArgs);
}
-/// Generate code for a message send expression.
+/// Generate code for a message send expression.
CodeGen::RValue
CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
QualType ResultType,
@@ -428,32 +462,38 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
bool IsClassMessage,
const CallArgList &CallArgs,
const ObjCMethodDecl *Method) {
+ CGBuilderTy &Builder = CGF.Builder;
+ IdTy = cast<llvm::PointerType>(CGM.getTypes().ConvertType(ASTIdTy));
llvm::Value *cmd;
if (Method)
- cmd = GetSelector(CGF.Builder, Method);
+ cmd = GetSelector(Builder, Method);
else
- cmd = GetSelector(CGF.Builder, Sel);
+ cmd = GetSelector(Builder, Sel);
CallArgList ActualArgs;
+ Receiver = Builder.CreateBitCast(Receiver, IdTy);
ActualArgs.push_back(
- std::make_pair(RValue::get(CGF.Builder.CreateBitCast(Receiver, IdTy)),
- CGF.getContext().getObjCIdType()));
+ std::make_pair(RValue::get(Receiver), ASTIdTy));
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);
+ const llvm::FunctionType *impType =
+ Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : 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) {
+ // objc_msg_lookup_sender(id *receiver, SEL selector, id sender);
+ if (CGM.getContext().getLangOptions().ObjCNonFragileABI) {
+
+ std::vector<const llvm::Type*> Params;
+ llvm::Value *ReceiverPtr = CGF.CreateTempAlloca(Receiver->getType());
+ Builder.CreateStore(Receiver, ReceiverPtr);
+ Params.push_back(ReceiverPtr->getType());
+ Params.push_back(SelectorTy);
llvm::Value *self;
if (isa<ObjCMethodDecl>(CGF.CurFuncDecl)) {
@@ -461,34 +501,55 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
} else {
self = llvm::ConstantPointerNull::get(IdTy);
}
+
Params.push_back(self->getType());
- llvm::Constant *lookupFunction =
+
+ // The lookup function returns a slot, which can be safely cached.
+ llvm::Type *SlotTy = llvm::StructType::get(VMContext, PtrTy, PtrTy, PtrTy,
+ IntTy, llvm::PointerType::getUnqual(impType), NULL);
+ llvm::Constant *lookupFunction =
CGM.CreateRuntimeFunction(llvm::FunctionType::get(
- llvm::PointerType::getUnqual(impType), Params, true),
+ llvm::PointerType::getUnqual(SlotTy), Params, true),
"objc_msg_lookup_sender");
- imp = CGF.Builder.CreateCall3(lookupFunction, Receiver, cmd, self);
+ // The lookup function is guaranteed not to capture the receiver pointer.
+ if (llvm::Function *LookupFn = dyn_cast<llvm::Function>(lookupFunction)) {
+ LookupFn->setDoesNotCapture(1);
+ }
+
+ llvm::Value *slot =
+ Builder.CreateCall3(lookupFunction, ReceiverPtr, cmd, self);
+ imp = Builder.CreateLoad(Builder.CreateStructGEP(slot, 4));
+ // The lookup function may have changed the receiver, so make sure we use
+ // the new one.
+ ActualArgs[0] =
+ std::make_pair(RValue::get(Builder.CreateLoad(ReceiverPtr)), ASTIdTy);
} else {
- llvm::Constant *lookupFunction =
+ std::vector<const llvm::Type*> Params;
+ Params.push_back(Receiver->getType());
+ Params.push_back(SelectorTy);
+ llvm::Constant *lookupFunction =
CGM.CreateRuntimeFunction(llvm::FunctionType::get(
llvm::PointerType::getUnqual(impType), Params, true),
"objc_msg_lookup");
- imp = CGF.Builder.CreateCall2(lookupFunction, Receiver, cmd);
+ imp = Builder.CreateCall2(lookupFunction, Receiver, cmd);
}
return CGF.EmitCall(FnInfo, imp, ActualArgs);
}
-/// Generates a MethodList. Used in construction of a objc_class and
+/// 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,
+ 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(
+ if (MethodSels.empty())
+ return NULLPtr;
+ // Get the method structure type.
+ llvm::StructType *ObjCMethodTy = llvm::StructType::get(VMContext,
PtrToInt8Ty, // Really a selector, but the runtime creates it us.
PtrToInt8Ty, // Method types
llvm::PointerType::getUnqual(IMPTy), //Method pointer
@@ -501,11 +562,9 @@ llvm::Constant *CGObjCGNU::GenerateMethodList(const std::string &ClassName,
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));
+ llvm::Constant *C = MakeConstantString(MethodSels[i].getAsString());
+ Elements.push_back(C);
+ Elements.push_back(MethodTypes[i]);
Method = llvm::ConstantExpr::getBitCast(Method,
llvm::PointerType::getUnqual(IMPTy));
Elements.push_back(Method);
@@ -521,10 +580,11 @@ llvm::Constant *CGObjCGNU::GenerateMethodList(const std::string &ClassName,
// Structure containing list pointer, array and array count
llvm::SmallVector<const llvm::Type*, 16> ObjCMethodListFields;
- llvm::PATypeHolder OpaqueNextTy = llvm::OpaqueType::get();
+ llvm::PATypeHolder OpaqueNextTy = llvm::OpaqueType::get(VMContext);
llvm::Type *NextPtrTy = llvm::PointerType::getUnqual(OpaqueNextTy);
- llvm::StructType *ObjCMethodListTy = llvm::StructType::get(NextPtrTy,
- IntTy,
+ llvm::StructType *ObjCMethodListTy = llvm::StructType::get(VMContext,
+ NextPtrTy,
+ IntTy,
ObjCMethodArrayTy,
NULL);
// Refine next pointer type to concrete type
@@ -535,10 +595,10 @@ llvm::Constant *CGObjCGNU::GenerateMethodList(const std::string &ClassName,
Methods.clear();
Methods.push_back(llvm::ConstantPointerNull::get(
llvm::PointerType::getUnqual(ObjCMethodListTy)));
- Methods.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty,
+ Methods.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
MethodTypes.size()));
Methods.push_back(MethodArray);
-
+
// Create an instance of the structure
return MakeGlobal(ObjCMethodListTy, Methods, ".objc_method_list");
}
@@ -548,8 +608,8 @@ 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(
+ // Get the method structure type.
+ llvm::StructType *ObjCIvarTy = llvm::StructType::get(VMContext,
PtrToInt8Ty,
PtrToInt8Ty,
IntTy,
@@ -558,10 +618,8 @@ llvm::Constant *CGObjCGNU::GenerateIvarList(
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(IvarNames[i]);
+ Elements.push_back(IvarTypes[i]);
Elements.push_back(IvarOffsets[i]);
Ivars.push_back(llvm::ConstantStruct::get(ObjCIvarTy, Elements));
}
@@ -570,12 +628,12 @@ llvm::Constant *CGObjCGNU::GenerateIvarList(
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,
+ llvm::StructType *ObjCIvarListTy = llvm::StructType::get(VMContext, IntTy,
ObjCIvarArrayTy,
NULL);
@@ -593,11 +651,17 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure(
llvm::Constant *InstanceSize,
llvm::Constant *IVars,
llvm::Constant *Methods,
- llvm::Constant *Protocols) {
+ llvm::Constant *Protocols,
+ llvm::Constant *IvarOffsets,
+ llvm::Constant *Properties) {
// 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(
+ //
+ // Fields marked New ABI are part of the GNUstep runtime. We emit them
+ // anyway; the classes will still work with the GNU runtime, they will just
+ // be ignored.
+ llvm::StructType *ClassTy = llvm::StructType::get(VMContext,
PtrToInt8Ty, // class_pointer
PtrToInt8Ty, // super_class
PtrToInt8Ty, // name
@@ -606,16 +670,18 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure(
LongTy, // instance_size
IVars->getType(), // ivars
Methods->getType(), // methods
- // These are all filled in by the runtime, so we pretend
+ // 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
+ // New ABI:
+ LongTy, // abi_version
+ IvarOffsets->getType(), // ivar_offsets
+ Properties->getType(), // properties
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));
@@ -626,11 +692,14 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure(
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(NULLPtr);
+ Elements.push_back(NULLPtr);
+ Elements.push_back(NULLPtr);
Elements.push_back(llvm::ConstantExpr::getBitCast(Protocols, PtrTy));
- Elements.push_back(NullP);
+ Elements.push_back(NULLPtr);
+ Elements.push_back(Zero);
+ Elements.push_back(IvarOffsets);
+ Elements.push_back(Properties);
// Create an instance of the structure
return MakeGlobal(ClassTy, Elements, SymbolNameForClass(Name));
}
@@ -638,8 +707,8 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure(
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(
+ // Get the method structure type.
+ llvm::StructType *ObjCMethodDescTy = llvm::StructType::get(VMContext,
PtrToInt8Ty, // Really a selector, but the runtime does the casting for us.
PtrToInt8Ty,
NULL);
@@ -647,40 +716,40 @@ llvm::Constant *CGObjCGNU::GenerateProtocolMethodList(
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));
+ Elements.push_back(MethodNames[i]);
+ Elements.push_back(MethodTypes[i]);
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(
+ llvm::Constant *Array = llvm::ConstantArray::get(ObjCMethodArrayTy,
+ Methods);
+ llvm::StructType *ObjCMethodDescListTy = llvm::StructType::get(VMContext,
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(
+ llvm::StructType *ProtocolListTy = llvm::StructType::get(VMContext,
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;
+ 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);
+ llvm::Constant *Ptr = llvm::ConstantExpr::getBitCast(protocol,
+ PtrToInt8Ty);
Elements.push_back(Ptr);
}
llvm::Constant * ProtocolArray = llvm::ConstantArray::get(ProtocolArrayTy,
@@ -692,10 +761,10 @@ llvm::Constant *CGObjCGNU::GenerateProtocolList(
return MakeGlobal(ProtocolListTy, Elements, ".objc_protocol_list");
}
-llvm::Value *CGObjCGNU::GenerateProtocolRef(CGBuilderTy &Builder,
+llvm::Value *CGObjCGNU::GenerateProtocolRef(CGBuilderTy &Builder,
const ObjCProtocolDecl *PD) {
llvm::Value *protocol = ExistingProtocols[PD->getNameAsString()];
- const llvm::Type *T =
+ const llvm::Type *T =
CGM.getTypes().ConvertType(CGM.getContext().getObjCProtoType());
return Builder.CreateBitCast(protocol, llvm::PointerType::getUnqual(T));
}
@@ -706,27 +775,31 @@ llvm::Constant *CGObjCGNU::GenerateEmptyProtocol(
llvm::SmallVector<llvm::Constant*, 0> EmptyConstantVector;
llvm::Constant *ProtocolList = GenerateProtocolList(EmptyStringVector);
- llvm::Constant *InstanceMethodList =
- GenerateProtocolMethodList(EmptyConstantVector, EmptyConstantVector);
- llvm::Constant *ClassMethodList =
+ llvm::Constant *MethodList =
GenerateProtocolMethodList(EmptyConstantVector, EmptyConstantVector);
// Protocols are objects containing lists of the methods implemented and
// protocols adopted.
- llvm::StructType *ProtocolTy = llvm::StructType::get(IdTy,
+ llvm::StructType *ProtocolTy = llvm::StructType::get(VMContext, IdTy,
PtrToInt8Ty,
ProtocolList->getType(),
- InstanceMethodList->getType(),
- ClassMethodList->getType(),
+ MethodList->getType(),
+ MethodList->getType(),
+ MethodList->getType(),
+ MethodList->getType(),
NULL);
- std::vector<llvm::Constant*> Elements;
+ std::vector<llvm::Constant*> Elements;
// The isa pointer must be set to a magic number so the runtime knows it's
// the correct layout.
+ int Version = CGM.getContext().getLangOptions().ObjCNonFragileABI ?
+ NonFragileProtocolVersion : ProtocolVersion;
Elements.push_back(llvm::ConstantExpr::getIntToPtr(
- llvm::ConstantInt::get(llvm::Type::Int32Ty, ProtocolVersion), IdTy));
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), Version), IdTy));
Elements.push_back(MakeConstantString(ProtocolName, ".objc_protocol_name"));
Elements.push_back(ProtocolList);
- Elements.push_back(InstanceMethodList);
- Elements.push_back(ClassMethodList);
+ Elements.push_back(MethodList);
+ Elements.push_back(MethodList);
+ Elements.push_back(MethodList);
+ Elements.push_back(MethodList);
return MakeGlobal(ProtocolTy, Elements, ".objc_protocol");
}
@@ -739,25 +812,41 @@ void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) {
Protocols.push_back((*PI)->getNameAsString());
llvm::SmallVector<llvm::Constant*, 16> InstanceMethodNames;
llvm::SmallVector<llvm::Constant*, 16> InstanceMethodTypes;
+ llvm::SmallVector<llvm::Constant*, 16> OptionalInstanceMethodNames;
+ llvm::SmallVector<llvm::Constant*, 16> OptionalInstanceMethodTypes;
for (ObjCProtocolDecl::instmeth_iterator iter = PD->instmeth_begin(),
E = PD->instmeth_end(); iter != E; iter++) {
std::string TypeStr;
Context.getObjCEncodingForMethodDecl(*iter, TypeStr);
- InstanceMethodNames.push_back(
- CGM.GetAddrOfConstantCString((*iter)->getSelector().getAsString()));
- InstanceMethodTypes.push_back(CGM.GetAddrOfConstantCString(TypeStr));
+ if ((*iter)->getImplementationControl() == ObjCMethodDecl::Optional) {
+ InstanceMethodNames.push_back(
+ MakeConstantString((*iter)->getSelector().getAsString()));
+ InstanceMethodTypes.push_back(MakeConstantString(TypeStr));
+ } else {
+ OptionalInstanceMethodNames.push_back(
+ MakeConstantString((*iter)->getSelector().getAsString()));
+ OptionalInstanceMethodTypes.push_back(MakeConstantString(TypeStr));
+ }
}
// Collect information about class methods:
llvm::SmallVector<llvm::Constant*, 16> ClassMethodNames;
llvm::SmallVector<llvm::Constant*, 16> ClassMethodTypes;
- for (ObjCProtocolDecl::classmeth_iterator
+ llvm::SmallVector<llvm::Constant*, 16> OptionalClassMethodNames;
+ llvm::SmallVector<llvm::Constant*, 16> OptionalClassMethodTypes;
+ for (ObjCProtocolDecl::classmeth_iterator
iter = PD->classmeth_begin(), endIter = PD->classmeth_end();
iter != endIter ; iter++) {
std::string TypeStr;
Context.getObjCEncodingForMethodDecl((*iter),TypeStr);
- ClassMethodNames.push_back(
- CGM.GetAddrOfConstantCString((*iter)->getSelector().getAsString()));
- ClassMethodTypes.push_back(CGM.GetAddrOfConstantCString(TypeStr));
+ if ((*iter)->getImplementationControl() == ObjCMethodDecl::Optional) {
+ ClassMethodNames.push_back(
+ MakeConstantString((*iter)->getSelector().getAsString()));
+ ClassMethodTypes.push_back(MakeConstantString(TypeStr));
+ } else {
+ OptionalClassMethodNames.push_back(
+ MakeConstantString((*iter)->getSelector().getAsString()));
+ OptionalClassMethodTypes.push_back(MakeConstantString(TypeStr));
+ }
}
llvm::Constant *ProtocolList = GenerateProtocolList(Protocols);
@@ -765,27 +854,165 @@ void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) {
GenerateProtocolMethodList(InstanceMethodNames, InstanceMethodTypes);
llvm::Constant *ClassMethodList =
GenerateProtocolMethodList(ClassMethodNames, ClassMethodTypes);
+ llvm::Constant *OptionalInstanceMethodList =
+ GenerateProtocolMethodList(OptionalInstanceMethodNames,
+ OptionalInstanceMethodTypes);
+ llvm::Constant *OptionalClassMethodList =
+ GenerateProtocolMethodList(OptionalClassMethodNames,
+ OptionalClassMethodTypes);
+
+ // Property metadata: name, attributes, isSynthesized, setter name, setter
+ // types, getter name, getter types.
+ // The isSynthesized value is always set to 0 in a protocol. It exists to
+ // simplify the runtime library by allowing it to use the same data
+ // structures for protocol metadata everywhere.
+ llvm::StructType *PropertyMetadataTy = llvm::StructType::get(VMContext,
+ PtrToInt8Ty, Int8Ty, Int8Ty, PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty,
+ PtrToInt8Ty, NULL);
+ std::vector<llvm::Constant*> Properties;
+ std::vector<llvm::Constant*> OptionalProperties;
+
+ // Add all of the property methods need adding to the method list and to the
+ // property metadata list.
+ for (ObjCContainerDecl::prop_iterator
+ iter = PD->prop_begin(), endIter = PD->prop_end();
+ iter != endIter ; iter++) {
+ std::vector<llvm::Constant*> Fields;
+ ObjCPropertyDecl *property = (*iter);
+
+ Fields.push_back(MakeConstantString(property->getNameAsString()));
+ Fields.push_back(llvm::ConstantInt::get(Int8Ty,
+ property->getPropertyAttributes()));
+ Fields.push_back(llvm::ConstantInt::get(Int8Ty, 0));
+ if (ObjCMethodDecl *getter = property->getGetterMethodDecl()) {
+ std::string TypeStr;
+ Context.getObjCEncodingForMethodDecl(getter,TypeStr);
+ llvm::Constant *TypeEncoding = MakeConstantString(TypeStr);
+ InstanceMethodTypes.push_back(TypeEncoding);
+ Fields.push_back(MakeConstantString(getter->getSelector().getAsString()));
+ Fields.push_back(TypeEncoding);
+ } else {
+ Fields.push_back(NULLPtr);
+ Fields.push_back(NULLPtr);
+ }
+ if (ObjCMethodDecl *setter = property->getSetterMethodDecl()) {
+ std::string TypeStr;
+ Context.getObjCEncodingForMethodDecl(setter,TypeStr);
+ llvm::Constant *TypeEncoding = MakeConstantString(TypeStr);
+ InstanceMethodTypes.push_back(TypeEncoding);
+ Fields.push_back(MakeConstantString(setter->getSelector().getAsString()));
+ Fields.push_back(TypeEncoding);
+ } else {
+ Fields.push_back(NULLPtr);
+ Fields.push_back(NULLPtr);
+ }
+ if (property->getPropertyImplementation() == ObjCPropertyDecl::Optional) {
+ OptionalProperties.push_back(llvm::ConstantStruct::get(PropertyMetadataTy, Fields));
+ } else {
+ Properties.push_back(llvm::ConstantStruct::get(PropertyMetadataTy, Fields));
+ }
+ }
+ llvm::Constant *PropertyArray = llvm::ConstantArray::get(
+ llvm::ArrayType::get(PropertyMetadataTy, Properties.size()), Properties);
+ llvm::Constant* PropertyListInitFields[] =
+ {llvm::ConstantInt::get(IntTy, Properties.size()), NULLPtr, PropertyArray};
+
+ llvm::Constant *PropertyListInit =
+ llvm::ConstantStruct::get(VMContext, PropertyListInitFields, 3, false);
+ llvm::Constant *PropertyList = new llvm::GlobalVariable(TheModule,
+ PropertyListInit->getType(), false, llvm::GlobalValue::InternalLinkage,
+ PropertyListInit, ".objc_property_list");
+
+ llvm::Constant *OptionalPropertyArray =
+ llvm::ConstantArray::get(llvm::ArrayType::get(PropertyMetadataTy,
+ OptionalProperties.size()) , OptionalProperties);
+ llvm::Constant* OptionalPropertyListInitFields[] = {
+ llvm::ConstantInt::get(IntTy, OptionalProperties.size()), NULLPtr,
+ OptionalPropertyArray };
+
+ llvm::Constant *OptionalPropertyListInit =
+ llvm::ConstantStruct::get(VMContext, OptionalPropertyListInitFields, 3, false);
+ llvm::Constant *OptionalPropertyList = new llvm::GlobalVariable(TheModule,
+ OptionalPropertyListInit->getType(), false,
+ llvm::GlobalValue::InternalLinkage, OptionalPropertyListInit,
+ ".objc_property_list");
+
// Protocols are objects containing lists of the methods implemented and
// protocols adopted.
- llvm::StructType *ProtocolTy = llvm::StructType::get(IdTy,
+ llvm::StructType *ProtocolTy = llvm::StructType::get(VMContext, IdTy,
PtrToInt8Ty,
ProtocolList->getType(),
InstanceMethodList->getType(),
ClassMethodList->getType(),
+ OptionalInstanceMethodList->getType(),
+ OptionalClassMethodList->getType(),
+ PropertyList->getType(),
+ OptionalPropertyList->getType(),
NULL);
- std::vector<llvm::Constant*> Elements;
+ std::vector<llvm::Constant*> Elements;
// The isa pointer must be set to a magic number so the runtime knows it's
// the correct layout.
+ int Version = CGM.getContext().getLangOptions().ObjCNonFragileABI ?
+ NonFragileProtocolVersion : ProtocolVersion;
Elements.push_back(llvm::ConstantExpr::getIntToPtr(
- llvm::ConstantInt::get(llvm::Type::Int32Ty, ProtocolVersion), IdTy));
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), Version), IdTy));
Elements.push_back(MakeConstantString(ProtocolName, ".objc_protocol_name"));
Elements.push_back(ProtocolList);
Elements.push_back(InstanceMethodList);
Elements.push_back(ClassMethodList);
- ExistingProtocols[ProtocolName] =
+ Elements.push_back(OptionalInstanceMethodList);
+ Elements.push_back(OptionalClassMethodList);
+ Elements.push_back(PropertyList);
+ Elements.push_back(OptionalPropertyList);
+ ExistingProtocols[ProtocolName] =
llvm::ConstantExpr::getBitCast(MakeGlobal(ProtocolTy, Elements,
".objc_protocol"), IdTy);
}
+void CGObjCGNU::GenerateProtocolHolderCategory(void) {
+ // Collect information about instance methods
+ llvm::SmallVector<Selector, 1> MethodSels;
+ llvm::SmallVector<llvm::Constant*, 1> MethodTypes;
+
+ std::vector<llvm::Constant*> Elements;
+ const std::string ClassName = "__ObjC_Protocol_Holder_Ugly_Hack";
+ const std::string CategoryName = "AnotherHack";
+ Elements.push_back(MakeConstantString(CategoryName));
+ Elements.push_back(MakeConstantString(ClassName));
+ // Instance method list
+ Elements.push_back(llvm::ConstantExpr::getBitCast(GenerateMethodList(
+ ClassName, CategoryName, MethodSels, MethodTypes, false), PtrTy));
+ // Class method list
+ Elements.push_back(llvm::ConstantExpr::getBitCast(GenerateMethodList(
+ ClassName, CategoryName, MethodSels, MethodTypes, true), PtrTy));
+ // Protocol list
+ llvm::ArrayType *ProtocolArrayTy = llvm::ArrayType::get(PtrTy,
+ ExistingProtocols.size());
+ llvm::StructType *ProtocolListTy = llvm::StructType::get(VMContext,
+ PtrTy, //Should be a recurisve pointer, but it's always NULL here.
+ LongTy,//FIXME: Should be size_t
+ ProtocolArrayTy,
+ NULL);
+ std::vector<llvm::Constant*> ProtocolElements;
+ for (llvm::StringMapIterator<llvm::Constant*> iter =
+ ExistingProtocols.begin(), endIter = ExistingProtocols.end();
+ iter != endIter ; iter++) {
+ llvm::Constant *Ptr = llvm::ConstantExpr::getBitCast(iter->getValue(),
+ PtrTy);
+ ProtocolElements.push_back(Ptr);
+ }
+ llvm::Constant * ProtocolArray = llvm::ConstantArray::get(ProtocolArrayTy,
+ ProtocolElements);
+ ProtocolElements.clear();
+ ProtocolElements.push_back(NULLPtr);
+ ProtocolElements.push_back(llvm::ConstantInt::get(LongTy,
+ ExistingProtocols.size()));
+ ProtocolElements.push_back(ProtocolArray);
+ Elements.push_back(llvm::ConstantExpr::getBitCast(MakeGlobal(ProtocolListTy,
+ ProtocolElements, ".objc_protocol_list"), PtrTy));
+ Categories.push_back(llvm::ConstantExpr::getBitCast(
+ MakeGlobal(llvm::StructType::get(VMContext, PtrToInt8Ty, PtrToInt8Ty,
+ PtrTy, PtrTy, PtrTy, NULL), Elements), PtrTy));
+}
void CGObjCGNU::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
std::string ClassName = OCD->getClassInterface()->getNameAsString();
@@ -799,19 +1026,19 @@ void CGObjCGNU::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
InstanceMethodSels.push_back((*iter)->getSelector());
std::string TypeStr;
CGM.getContext().getObjCEncodingForMethodDecl(*iter,TypeStr);
- InstanceMethodTypes.push_back(CGM.GetAddrOfConstantCString(TypeStr));
+ InstanceMethodTypes.push_back(MakeConstantString(TypeStr));
}
// Collect information about class methods
llvm::SmallVector<Selector, 16> ClassMethodSels;
llvm::SmallVector<llvm::Constant*, 16> ClassMethodTypes;
- for (ObjCCategoryImplDecl::classmeth_iterator
+ for (ObjCCategoryImplDecl::classmeth_iterator
iter = OCD->classmeth_begin(), endIter = OCD->classmeth_end();
iter != endIter ; iter++) {
ClassMethodSels.push_back((*iter)->getSelector());
std::string TypeStr;
CGM.getContext().getObjCEncodingForMethodDecl(*iter,TypeStr);
- ClassMethodTypes.push_back(CGM.GetAddrOfConstantCString(TypeStr));
+ ClassMethodTypes.push_back(MakeConstantString(TypeStr));
}
// Collect the names of referenced protocols
@@ -825,7 +1052,7 @@ void CGObjCGNU::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
std::vector<llvm::Constant*> Elements;
Elements.push_back(MakeConstantString(CategoryName));
Elements.push_back(MakeConstantString(ClassName));
- // Instance method list
+ // Instance method list
Elements.push_back(llvm::ConstantExpr::getBitCast(GenerateMethodList(
ClassName, CategoryName, InstanceMethodSels, InstanceMethodTypes,
false), PtrTy));
@@ -837,15 +1064,82 @@ void CGObjCGNU::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
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));
+ MakeGlobal(llvm::StructType::get(VMContext, PtrToInt8Ty, PtrToInt8Ty,
+ PtrTy, PtrTy, PtrTy, NULL), Elements), PtrTy));
+}
+
+llvm::Constant *CGObjCGNU::GeneratePropertyList(const ObjCImplementationDecl *OID,
+ llvm::SmallVectorImpl<Selector> &InstanceMethodSels,
+ llvm::SmallVectorImpl<llvm::Constant*> &InstanceMethodTypes) {
+ ASTContext &Context = CGM.getContext();
+ //
+ // Property metadata: name, attributes, isSynthesized, setter name, setter
+ // types, getter name, getter types.
+ llvm::StructType *PropertyMetadataTy = llvm::StructType::get(VMContext,
+ PtrToInt8Ty, Int8Ty, Int8Ty, PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty,
+ PtrToInt8Ty, NULL);
+ std::vector<llvm::Constant*> Properties;
+
+
+ // Add all of the property methods need adding to the method list and to the
+ // property metadata list.
+ for (ObjCImplDecl::propimpl_iterator
+ iter = OID->propimpl_begin(), endIter = OID->propimpl_end();
+ iter != endIter ; iter++) {
+ std::vector<llvm::Constant*> Fields;
+ ObjCPropertyDecl *property = (*iter)->getPropertyDecl();
+
+ Fields.push_back(MakeConstantString(property->getNameAsString()));
+ Fields.push_back(llvm::ConstantInt::get(Int8Ty,
+ property->getPropertyAttributes()));
+ Fields.push_back(llvm::ConstantInt::get(Int8Ty,
+ (*iter)->getPropertyImplementation() ==
+ ObjCPropertyImplDecl::Synthesize));
+ if (ObjCMethodDecl *getter = property->getGetterMethodDecl()) {
+ InstanceMethodSels.push_back(getter->getSelector());
+ std::string TypeStr;
+ Context.getObjCEncodingForMethodDecl(getter,TypeStr);
+ llvm::Constant *TypeEncoding = MakeConstantString(TypeStr);
+ InstanceMethodTypes.push_back(TypeEncoding);
+ Fields.push_back(MakeConstantString(getter->getSelector().getAsString()));
+ Fields.push_back(TypeEncoding);
+ } else {
+ Fields.push_back(NULLPtr);
+ Fields.push_back(NULLPtr);
+ }
+ if (ObjCMethodDecl *setter = property->getSetterMethodDecl()) {
+ InstanceMethodSels.push_back(setter->getSelector());
+ std::string TypeStr;
+ Context.getObjCEncodingForMethodDecl(setter,TypeStr);
+ llvm::Constant *TypeEncoding = MakeConstantString(TypeStr);
+ InstanceMethodTypes.push_back(TypeEncoding);
+ Fields.push_back(MakeConstantString(setter->getSelector().getAsString()));
+ Fields.push_back(TypeEncoding);
+ } else {
+ Fields.push_back(NULLPtr);
+ Fields.push_back(NULLPtr);
+ }
+ Properties.push_back(llvm::ConstantStruct::get(PropertyMetadataTy, Fields));
+ }
+ llvm::ArrayType *PropertyArrayTy =
+ llvm::ArrayType::get(PropertyMetadataTy, Properties.size());
+ llvm::Constant *PropertyArray = llvm::ConstantArray::get(PropertyArrayTy,
+ Properties);
+ llvm::Constant* PropertyListInitFields[] =
+ {llvm::ConstantInt::get(IntTy, Properties.size()), NULLPtr, PropertyArray};
+
+ llvm::Constant *PropertyListInit =
+ llvm::ConstantStruct::get(VMContext, PropertyListInitFields, 3, false);
+ return new llvm::GlobalVariable(TheModule, PropertyListInit->getType(), false,
+ llvm::GlobalValue::InternalLinkage, PropertyListInit,
+ ".objc_property_list");
}
void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
ASTContext &Context = CGM.getContext();
// Get the superclass name.
- const ObjCInterfaceDecl * SuperClassDecl =
+ const ObjCInterfaceDecl * SuperClassDecl =
OID->getClassInterface()->getSuperClass();
std::string SuperClassName;
if (SuperClassDecl) {
@@ -860,14 +1154,15 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
// Emit the symbol that is used to generate linker errors if this class is
// referenced in other modules but not declared.
std::string classSymbolName = "__objc_class_name_" + ClassName;
- if (llvm::GlobalVariable *symbol =
+ if (llvm::GlobalVariable *symbol =
TheModule.getGlobalVariable(classSymbolName)) {
symbol->setInitializer(llvm::ConstantInt::get(LongTy, 0));
} else {
- new llvm::GlobalVariable(LongTy, false, llvm::GlobalValue::ExternalLinkage,
- llvm::ConstantInt::get(LongTy, 0), classSymbolName, &TheModule);
+ new llvm::GlobalVariable(TheModule, LongTy, false,
+ llvm::GlobalValue::ExternalLinkage, llvm::ConstantInt::get(LongTy, 0),
+ classSymbolName);
}
-
+
// Get the size of instances.
int instanceSize = Context.getASTObjCImplementationLayout(OID).getSize() / 8;
@@ -875,8 +1170,10 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
llvm::SmallVector<llvm::Constant*, 16> IvarNames;
llvm::SmallVector<llvm::Constant*, 16> IvarTypes;
llvm::SmallVector<llvm::Constant*, 16> IvarOffsets;
-
- int superInstanceSize = !SuperClassDecl ? 0 :
+
+ std::vector<llvm::Constant*> IvarOffsetValues;
+
+ 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.
@@ -886,54 +1183,49 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
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()));
+ IvarNames.push_back(MakeConstantString((*iter)->getNameAsString()));
// Get the type encoding for this ivar
std::string TypeStr;
Context.getObjCEncodingForType((*iter)->getType(), TypeStr);
- IvarTypes.push_back(CGM.GetAddrOfConstantCString(TypeStr));
+ IvarTypes.push_back(MakeConstantString(TypeStr));
// Get the offset
- uint64_t Offset;
+ uint64_t Offset = 0;
+ uint64_t BaseOffset = ComputeIvarBaseOffset(CGM, ClassDecl, *iter);
if (CGM.getContext().getLangOptions().ObjCNonFragileABI) {
- Offset = ComputeIvarBaseOffset(CGM, ClassDecl, *iter) -
- superInstanceSize;
- ObjCIvarOffsetVariable(ClassDecl, *iter);
- } else {
- Offset = ComputeIvarBaseOffset(CGM, ClassDecl, *iter);
+ Offset = BaseOffset - superInstanceSize;
}
IvarOffsets.push_back(
- llvm::ConstantInt::get(llvm::Type::Int32Ty, Offset));
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), Offset));
+ IvarOffsetValues.push_back(new llvm::GlobalVariable(TheModule, IntTy,
+ false, llvm::GlobalValue::ExternalLinkage,
+ llvm::ConstantInt::get(IntTy, BaseOffset),
+ "__objc_ivar_offset_value_" + ClassName +"." +
+ (*iter)->getNameAsString()));
}
+ llvm::Constant *IvarOffsetArrayInit =
+ llvm::ConstantArray::get(llvm::ArrayType::get(PtrToIntTy,
+ IvarOffsetValues.size()), IvarOffsetValues);
+ llvm::GlobalVariable *IvarOffsetArray = new llvm::GlobalVariable(TheModule,
+ IvarOffsetArrayInit->getType(), false,
+ llvm::GlobalValue::InternalLinkage, IvarOffsetArrayInit,
+ ".ivar.offsets");
// Collect information about instance methods
llvm::SmallVector<Selector, 16> InstanceMethodSels;
llvm::SmallVector<llvm::Constant*, 16> InstanceMethodTypes;
- for (ObjCImplementationDecl::instmeth_iterator
+ for (ObjCImplementationDecl::instmeth_iterator
iter = OID->instmeth_begin(), endIter = OID->instmeth_end();
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(), endIter = OID->propimpl_end();
- 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));
- }
+ InstanceMethodTypes.push_back(MakeConstantString(TypeStr));
}
+ llvm::Constant *Properties = GeneratePropertyList(OID, InstanceMethodSels,
+ InstanceMethodTypes);
+
+
// Collect information about class methods
llvm::SmallVector<Selector, 16> ClassMethodSels;
llvm::SmallVector<llvm::Constant*, 16> ClassMethodTypes;
@@ -943,7 +1235,7 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
ClassMethodSels.push_back((*iter)->getSelector());
std::string TypeStr;
Context.getObjCEncodingForMethodDecl((*iter),TypeStr);
- ClassMethodTypes.push_back(CGM.GetAddrOfConstantCString(TypeStr));
+ ClassMethodTypes.push_back(MakeConstantString(TypeStr));
}
// Collect the names of referenced protocols
llvm::SmallVector<std::string, 16> Protocols;
@@ -970,17 +1262,55 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
ClassMethodSels, ClassMethodTypes, true);
llvm::Constant *IvarList = GenerateIvarList(IvarNames, IvarTypes,
IvarOffsets);
+ // Irrespective of whether we are compiling for a fragile or non-fragile ABI,
+ // we emit a symbol containing the offset for each ivar in the class. This
+ // allows code compiled for the non-Fragile ABI to inherit from code compiled
+ // for the legacy ABI, without causing problems. The converse is also
+ // possible, but causes all ivar accesses to be fragile.
+ int i = 0;
+ // Offset pointer for getting at the correct field in the ivar list when
+ // setting up the alias. These are: The base address for the global, the
+ // ivar array (second field), the ivar in this list (set for each ivar), and
+ // the offset (third field in ivar structure)
+ const llvm::Type *IndexTy = llvm::Type::getInt32Ty(VMContext);
+ llvm::Constant *offsetPointerIndexes[] = {Zeros[0],
+ llvm::ConstantInt::get(IndexTy, 1), 0,
+ llvm::ConstantInt::get(IndexTy, 2) };
+
+ for (ObjCInterfaceDecl::ivar_iterator iter = ClassDecl->ivar_begin(),
+ endIter = ClassDecl->ivar_end() ; iter != endIter ; iter++) {
+ const std::string Name = "__objc_ivar_offset_" + ClassName + '.'
+ +(*iter)->getNameAsString();
+ offsetPointerIndexes[2] = llvm::ConstantInt::get(IndexTy, i++);
+ // Get the correct ivar field
+ llvm::Constant *offsetValue = llvm::ConstantExpr::getGetElementPtr(
+ IvarList, offsetPointerIndexes, 4);
+ // Get the existing alias, if one exists.
+ llvm::GlobalVariable *offset = TheModule.getNamedGlobal(Name);
+ if (offset) {
+ offset->setInitializer(offsetValue);
+ // If this is the real definition, change its linkage type so that
+ // different modules will use this one, rather than their private
+ // copy.
+ offset->setLinkage(llvm::GlobalValue::ExternalLinkage);
+ } else {
+ // Add a new alias if there isn't one already.
+ offset = new llvm::GlobalVariable(TheModule, offsetValue->getType(),
+ false, llvm::GlobalValue::ExternalLinkage, offsetValue, Name);
+ }
+ }
//Generate metaclass for class methods
llvm::Constant *MetaClassStruct = GenerateClassStructure(NULLPtr,
- NULLPtr, 0x2L, /*name*/"", 0, Zeros[0], GenerateIvarList(
- empty, empty, empty), ClassMethodList, NULLPtr);
+ NULLPtr, 0x12L, /*name*/"", 0, Zeros[0], GenerateIvarList(
+ empty, empty, empty), ClassMethodList, NULLPtr, NULLPtr, NULLPtr);
// Generate the class structure
llvm::Constant *ClassStruct =
- GenerateClassStructure(MetaClassStruct, SuperClass, 0x1L,
+ GenerateClassStructure(MetaClassStruct, SuperClass, 0x11L,
ClassName.c_str(), 0,
llvm::ConstantInt::get(LongTy, instanceSize), IvarList,
- MethodList, GenerateProtocolList(Protocols));
+ MethodList, GenerateProtocolList(Protocols), IvarOffsetArray,
+ Properties);
// Resolve the class aliases, if they exist.
if (ClassPtrAlias) {
@@ -999,23 +1329,24 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
Classes.push_back(ClassStruct);
}
-void CGObjCGNU::MergeMetadataGlobals(
- std::vector<llvm::Constant*> &UsedArray) {
-}
-llvm::Function *CGObjCGNU::ModuleInitFunction() {
+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;
+ // Add all referenced protocols to a category.
+ GenerateProtocolHolderCategory();
+
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);
+ SelStructTy = llvm::StructType::get(VMContext, PtrToInt8Ty,
+ PtrToInt8Ty, NULL);
SelStructPtrTy = llvm::PointerType::getUnqual(SelStructTy);
isSelOpaque = true;
}
@@ -1032,13 +1363,17 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
llvm::ArrayType *StaticsArrayTy = llvm::ArrayType::get(PtrToInt8Ty,
ConstantStrings.size() + 1);
ConstantStrings.push_back(NULLPtr);
- Elements.push_back(MakeConstantString("NSConstantString",
- ".objc_static_class_name"));
+
+ const char *StringClass = CGM.getLangOptions().ObjCConstantStringClass;
+ if (!StringClass) StringClass = "NXConstantString";
+ Elements.push_back(MakeConstantString(StringClass,
+ ".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);
+ llvm::StructType *StaticsListTy =
+ llvm::StructType::get(VMContext, PtrToInt8Ty, StaticsArrayTy, NULL);
+ llvm::Type *StaticsListPtrTy =
+ llvm::PointerType::getUnqual(StaticsListTy);
Statics = MakeGlobal(StaticsListTy, Elements, ".objc_statics");
llvm::ArrayType *StaticsListArrayTy =
llvm::ArrayType::get(StaticsListPtrTy, 2);
@@ -1051,9 +1386,10 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
// 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,
+ llvm::StructType *SymTabTy = llvm::StructType::get(VMContext,
+ LongTy, SelStructPtrTy,
+ llvm::Type::getInt16Ty(VMContext),
+ llvm::Type::getInt16Ty(VMContext),
ClassListTy, NULL);
Elements.clear();
@@ -1062,7 +1398,7 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
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(ExportUniqueString(iter->first.first, ".objc_sel_name"));
Elements.push_back(MakeConstantString(iter->first.second,
".objc_sel_types"));
Selectors.push_back(llvm::ConstantStruct::get(SelStructTy, Elements));
@@ -1072,7 +1408,7 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
iter = UntypedSelectors.begin(), iterEnd = UntypedSelectors.end();
iter != iterEnd; ++iter) {
Elements.push_back(
- MakeConstantString(iter->getKeyData(), ".objc_sel_name"));
+ ExportUniqueString(iter->getKeyData(), ".objc_sel_name"));
Elements.push_back(NULLPtr);
Selectors.push_back(llvm::ConstantStruct::get(SelStructTy, Elements));
Elements.clear();
@@ -1086,7 +1422,7 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
llvm::Constant *SelectorList = MakeGlobal(
llvm::ArrayType::get(SelStructTy, Selectors.size()), Selectors,
".objc_selector_list");
- Elements.push_back(llvm::ConstantExpr::getBitCast(SelectorList,
+ Elements.push_back(llvm::ConstantExpr::getBitCast(SelectorList,
SelStructPtrTy));
// Now that all of the static selectors exist, create pointers to them.
@@ -1095,11 +1431,11 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
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,
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), index++), Zeros[0]};
+ llvm::Constant *SelPtr = new llvm::GlobalVariable(TheModule, SelStructPtrTy,
true, llvm::GlobalValue::InternalLinkage,
llvm::ConstantExpr::getGetElementPtr(SelectorList, Idxs, 2),
- ".objc_sel_ptr", &TheModule);
+ ".objc_sel_ptr");
// If selectors are defined as an opaque type, cast the pointer to this
// type.
if (isSelOpaque) {
@@ -1112,11 +1448,12 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
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);
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), index++), Zeros[0]};
+ llvm::Constant *SelPtr = new llvm::GlobalVariable
+ (TheModule, SelStructPtrTy,
+ true, llvm::GlobalValue::InternalLinkage,
+ llvm::ConstantExpr::getGetElementPtr(SelectorList, Idxs, 2),
+ ".objc_sel_ptr");
// If selectors are defined as an opaque type, cast the pointer to this
// type.
if (isSelOpaque) {
@@ -1126,10 +1463,10 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
(*iter).second->setAliasee(SelPtr);
}
// Number of classes defined.
- Elements.push_back(llvm::ConstantInt::get(llvm::Type::Int16Ty,
+ Elements.push_back(llvm::ConstantInt::get(llvm::Type::getInt16Ty(VMContext),
Classes.size()));
// Number of categories defined
- Elements.push_back(llvm::ConstantInt::get(llvm::Type::Int16Ty,
+ Elements.push_back(llvm::ConstantInt::get(llvm::Type::getInt16Ty(VMContext),
Categories.size()));
// Create an array of classes, then categories, then static object instances
Classes.insert(Classes.end(), Categories.begin(), Categories.end());
@@ -1138,24 +1475,25 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
Classes.push_back(NULLPtr);
llvm::Constant *ClassList = llvm::ConstantArray::get(ClassListTy, Classes);
Elements.push_back(ClassList);
- // Construct the symbol table
+ // 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,
+ llvm::StructType * ModuleTy = llvm::StructType::get(VMContext, 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,
+ 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));
+ 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);
@@ -1164,17 +1502,18 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
// Create the load function calling the runtime entry point with the module
// structure
llvm::Function * LoadFunction = llvm::Function::Create(
- llvm::FunctionType::get(llvm::Type::VoidTy, false),
+ llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), false),
llvm::GlobalValue::InternalLinkage, ".objc_load_function",
&TheModule);
- llvm::BasicBlock *EntryBB = llvm::BasicBlock::Create("entry", LoadFunction);
- CGBuilderTy Builder;
+ llvm::BasicBlock *EntryBB =
+ llvm::BasicBlock::Create(VMContext, "entry", LoadFunction);
+ CGBuilderTy Builder(VMContext);
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");
+ llvm::Type::getVoidTy(VMContext), Params, true), "__objc_exec_class");
Builder.CreateCall(Register, Module);
Builder.CreateRetVoid();
@@ -1182,8 +1521,8 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
}
llvm::Function *CGObjCGNU::GenerateMethod(const ObjCMethodDecl *OMD,
- const ObjCContainerDecl *CD) {
- const ObjCCategoryImplDecl *OCD =
+ const ObjCContainerDecl *CD) {
+ const ObjCCategoryImplDecl *OCD =
dyn_cast<ObjCCategoryImplDecl>(OMD->getDeclContext());
std::string CategoryName = OCD ? OCD->getNameAsString() : "";
std::string ClassName = OMD->getClassInterface()->getNameAsString();
@@ -1191,71 +1530,76 @@ llvm::Function *CGObjCGNU::GenerateMethod(const ObjCMethodDecl *OMD,
bool isClassMethod = !OMD->isInstanceMethod();
CodeGenTypes &Types = CGM.getTypes();
- const llvm::FunctionType *MethodTy =
+ 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);
+ 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"));
+ 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"));
+ 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::getVoidTy(VMContext), 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"));
+llvm::Constant *CGObjCGNU::EnumerationMutationFunction() {
+ CodeGen::CodeGenTypes &Types = CGM.getTypes();
+ ASTContext &Ctx = CGM.getContext();
+ // void objc_enumerationMutation (id)
+ llvm::SmallVector<QualType,16> Params;
+ Params.push_back(ASTIdTy);
+ const llvm::FunctionType *FTy =
+ Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params), false);
+ return CGM.CreateRuntimeFunction(FTy, "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,
+ CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty(VMContext),
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,
+ CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
Params, false), "_Unwind_Resume_or_Rethrow");
bool isTry = isa<ObjCAtTryStmt>(S);
@@ -1271,9 +1615,9 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
if (!isTry) {
std::vector<const llvm::Type*> Args(1, IdTy);
llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::VoidTy, Args, false);
+ llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Args, false);
llvm::Value *SyncEnter = CGM.CreateRuntimeFunction(FTy, "objc_sync_enter");
- llvm::Value *SyncArg =
+ llvm::Value *SyncArg =
CGF.EmitScalarExpr(cast<ObjCAtSynchronizedStmt>(S).getSynchExpr());
SyncArg = CGF.Builder.CreateBitCast(SyncArg, IdTy);
CGF.Builder.CreateCall(SyncEnter, SyncArg);
@@ -1288,7 +1632,7 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
CGF.setInvokeDest(TryHandler);
CGF.EmitBlock(TryBlock);
- CGF.EmitStmt(isTry ? cast<ObjCAtTryStmt>(S).getTryBody()
+ CGF.EmitStmt(isTry ? cast<ObjCAtTryStmt>(S).getTryBody()
: cast<ObjCAtSynchronizedStmt>(S).getSynchBody());
// Jump to @finally if there is no exception
@@ -1299,17 +1643,12 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
// 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 =
+ 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);
+ llvm::Value *llvm_eh_selector =
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_selector);
+ llvm::Value *llvm_eh_typeid_for =
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for);
// Exception object
llvm::Value *Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc");
@@ -1330,23 +1669,25 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
for (; CatchStmt; CatchStmt = CatchStmt->getNextCatchStmt()) {
const ParmVarDecl *CatchDecl = CatchStmt->getCatchParamDecl();
- Handlers.push_back(std::make_pair(CatchDecl, CatchStmt->getCatchBody()));
+ 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())
+ if (!CatchDecl || CatchDecl->getType()->isObjCIdType()
|| 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();
+ const ObjCObjectPointerType *OPT =
+ CatchDecl->getType()->getAs<ObjCObjectPointerType>();
+ assert(OPT && "Invalid @catch type.");
+ const ObjCInterfaceType *IT =
+ OPT->getPointeeType()->getAs<ObjCInterfaceType>();
assert(IT && "Invalid @catch type.");
llvm::Value *EHType =
MakeConstantString(IT->getDecl()->getNameAsString());
@@ -1357,7 +1698,7 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
// We use a cleanup unless there was already a catch all.
if (!HasCatchAll) {
- ESelArgs.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, 0));
+ ESelArgs.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 0));
Handlers.push_back(std::make_pair((const ParmVarDecl*) 0, (const Stmt*) 0));
}
@@ -1386,11 +1727,11 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
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
@@ -1422,7 +1763,7 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
ESelArgs.clear();
ESelArgs.push_back(Exc);
ESelArgs.push_back(Personality);
- ESelArgs.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, 0));
+ ESelArgs.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 0));
CGF.Builder.CreateCall(llvm_eh_selector, ESelArgs.begin(), ESelArgs.end(),
"selector");
CGF.Builder.CreateCall(llvm_eh_typeid_for,
@@ -1438,7 +1779,7 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
if (isTry) {
- if (const ObjCAtFinallyStmt* FinallyStmt =
+ if (const ObjCAtFinallyStmt* FinallyStmt =
cast<ObjCAtTryStmt>(S).getFinallyStmt())
CGF.EmitStmt(FinallyStmt->getFinallyBody());
} else {
@@ -1446,9 +1787,9 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
// @synchronized.
std::vector<const llvm::Type*> Args(1, IdTy);
llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::VoidTy, Args, false);
+ llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Args, false);
llvm::Value *SyncExit = CGM.CreateRuntimeFunction(FTy, "objc_sync_exit");
- llvm::Value *SyncArg =
+ llvm::Value *SyncArg =
CGF.EmitScalarExpr(cast<ObjCAtSynchronizedStmt>(S).getSynchExpr());
SyncArg = CGF.Builder.CreateBitCast(SyncArg, IdTy);
CGF.Builder.CreateCall(SyncExit, SyncArg);
@@ -1465,7 +1806,7 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
CGF.EmitBlock(FinallyRethrow);
CGF.Builder.CreateCall(RethrowFn, CGF.Builder.CreateLoad(RethrowPtr));
CGF.Builder.CreateUnreachable();
-
+
CGF.EmitBlock(FinallyEnd);
}
@@ -1476,21 +1817,21 @@ void CGObjCGNU::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
std::vector<const llvm::Type*> Args(1, IdTy);
llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::VoidTy, Args, false);
- llvm::Value *ThrowFn =
+ llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), 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()) &&
+ 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);
@@ -1513,32 +1854,35 @@ void CGObjCGNU::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
}
llvm::Value * CGObjCGNU::EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
- llvm::Value *AddrWeakObj)
-{
+ llvm::Value *AddrWeakObj) {
return 0;
}
void CGObjCGNU::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dst)
-{
+ llvm::Value *src, llvm::Value *dst) {
return;
}
void CGObjCGNU::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dst)
-{
+ llvm::Value *src, llvm::Value *dst) {
return;
}
void CGObjCGNU::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dst)
-{
+ llvm::Value *src, llvm::Value *dst,
+ llvm::Value *ivarOffset) {
return;
}
void CGObjCGNU::EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dst)
-{
+ llvm::Value *src, llvm::Value *dst) {
+ return;
+}
+
+void CGObjCGNU::EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *DestPtr,
+ llvm::Value *SrcPtr,
+ QualType Ty) {
return;
}
@@ -1550,15 +1894,29 @@ llvm::GlobalVariable *CGObjCGNU::ObjCIvarOffsetVariable(
// 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) {
+ llvm::GlobalVariable *IvarOffsetPointer = TheModule.getNamedGlobal(Name);
+ if (!IvarOffsetPointer) {
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);
+ // Don't emit the guess in non-PIC code because the linker will not be able
+ // to replace it with the real version for a library. In non-PIC code you
+ // must compile with the fragile ABI if you want to use ivars from a
+ // GCC-compiled class.
+ if (CGM.getLangOptions().PICLevel) {
+ llvm::GlobalVariable *IvarOffsetGV = new llvm::GlobalVariable(TheModule,
+ llvm::Type::getInt32Ty(VMContext), false,
+ llvm::GlobalValue::PrivateLinkage, OffsetGuess, Name+".guess");
+ IvarOffsetPointer = new llvm::GlobalVariable(TheModule,
+ IvarOffsetGV->getType(), false, llvm::GlobalValue::LinkOnceAnyLinkage,
+ IvarOffsetGV, Name);
+ } else {
+ IvarOffsetPointer = new llvm::GlobalVariable(TheModule,
+ llvm::Type::getInt32PtrTy(VMContext), false,
+ llvm::GlobalValue::ExternalLinkage, 0, Name);
+ }
}
- return IvarOffsetGV;
+ return IvarOffsetPointer;
}
LValue CGObjCGNU::EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF,
@@ -1566,10 +1924,11 @@ LValue CGObjCGNU::EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF,
llvm::Value *BaseValue,
const ObjCIvarDecl *Ivar,
unsigned CVRQualifiers) {
- const ObjCInterfaceDecl *ID = ObjectTy->getAsObjCInterfaceType()->getDecl();
+ const ObjCInterfaceDecl *ID = ObjectTy->getAs<ObjCInterfaceType>()->getDecl();
return EmitValueForIvarAtOffset(CGF, ID, BaseValue, Ivar, CVRQualifiers,
EmitIvarOffset(CGF, ID, Ivar));
}
+
static const ObjCInterfaceDecl *FindIvarInterface(ASTContext &Context,
const ObjCInterfaceDecl *OID,
const ObjCIvarDecl *OIVD) {
@@ -1579,27 +1938,27 @@ static const ObjCInterfaceDecl *FindIvarInterface(ASTContext &Context,
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)
- {
+ if (CGM.getLangOptions().ObjCNonFragileABI) {
Interface = FindIvarInterface(CGM.getContext(), Interface, Ivar);
- return CGF.Builder.CreateLoad(ObjCIvarOffsetVariable(Interface, Ivar),
- false, "ivar");
+ return CGF.Builder.CreateLoad(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){
+CodeGen::CGObjCRuntime *
+CodeGen::CreateGNUObjCRuntime(CodeGen::CodeGenModule &CGM) {
return new CGObjCGNU(CGM);
}
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index c335457..4485ed5 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -23,10 +23,14 @@
#include "clang/Basic/LangOptions.h"
#include "llvm/Intrinsics.h"
+#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetData.h"
-#include <sstream>
+#include <cstdio>
using namespace clang;
using namespace CodeGen;
@@ -35,7 +39,7 @@ using namespace CodeGen;
// don't belong in CGObjCRuntime either so we will live with it for
// now.
-/// FindIvarInterface - Find the interface containing the ivar.
+/// FindIvarInterface - Find the interface containing the ivar.
///
/// FIXME: We shouldn't need to do this, the containing context should
/// be fixed.
@@ -54,11 +58,11 @@ static const ObjCInterfaceDecl *FindIvarInterface(ASTContext &Context,
return OID;
++Index;
}
-
+
// Otherwise check in the super class.
if (const ObjCInterfaceDecl *Super = OID->getSuperClass())
return FindIvarInterface(Context, Super, OIVD, Index);
-
+
return 0;
}
@@ -67,13 +71,13 @@ static uint64_t LookupFieldBitOffset(CodeGen::CodeGenModule &CGM,
const ObjCImplementationDecl *ID,
const ObjCIvarDecl *Ivar) {
unsigned Index;
- const ObjCInterfaceDecl *Container =
+ 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;
+ const ASTRecordLayout *RL;
if (ID && ID->getClassInterface() == Container)
RL = &CGM.getContext().getASTObjCImplementationLayout(ID);
else
@@ -100,13 +104,16 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF,
unsigned CVRQualifiers,
llvm::Value *Offset) {
// Compute (type*) ( (char *) BaseValue + Offset)
- llvm::Type *I8Ptr = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+ const llvm::Type *I8Ptr = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
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));
-
+
+ Qualifiers Quals = CGF.MakeQualifiers(IvarTy);
+ Quals.addCVRQualifiers(CVRQualifiers);
+
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
@@ -119,12 +126,11 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF,
Ivar->getBitWidth()->EvaluateAsInt(CGF.getContext()).getZExtValue();
return LValue::MakeBitfield(V, BitOffset, BitFieldSize,
IvarTy->isSignedIntegerType(),
- IvarTy.getCVRQualifiers()|CVRQualifiers);
+ Quals.getCVRQualifiers());
}
- LValue LV = LValue::MakeAddr(V, IvarTy.getCVRQualifiers()|CVRQualifiers,
- CGF.CGM.getContext().getObjCGCAttrKind(IvarTy));
- LValue::SetObjCIvar(LV, true);
+
+ LValue LV = LValue::MakeAddr(V, Quals);
return LV;
}
@@ -132,12 +138,15 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF,
namespace {
- typedef std::vector<llvm::Constant*> ConstantVector;
+typedef std::vector<llvm::Constant*> ConstantVector;
- // FIXME: We should find a nicer way to make the labels for metadata, string
- // concatenation is lame.
+// FIXME: We should find a nicer way to make the labels for metadata, string
+// concatenation is lame.
class ObjCCommonTypesHelper {
+protected:
+ llvm::LLVMContext &VMContext;
+
private:
llvm::Constant *getMessageSendFn() const {
// id objc_msgSend (id, SEL, ...)
@@ -145,23 +154,23 @@ private:
Params.push_back(ObjectPtrTy);
Params.push_back(SelectorPtrTy);
return
- CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
- Params, true),
- "objc_msgSend");
+ 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");
-
+ CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
+ 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, ...)
@@ -169,13 +178,14 @@ private:
Params.push_back(ObjectPtrTy);
Params.push_back(SelectorPtrTy);
return
- CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::DoubleTy,
- Params,
- true),
- "objc_msgSend_fpret");
-
+ CGM.CreateRuntimeFunction(llvm::FunctionType::get(
+ llvm::Type::getDoubleTy(VMContext),
+ Params,
+ true),
+ "objc_msgSend_fpret");
+
}
-
+
llvm::Constant *getMessageSendSuperFn() const {
// id objc_msgSendSuper(struct objc_super *super, SEL op, ...)
const char *SuperName = "objc_msgSendSuper";
@@ -186,7 +196,7 @@ private:
Params, true),
SuperName);
}
-
+
llvm::Constant *getMessageSendSuperFn2() const {
// id objc_msgSendSuper2(struct objc_super *super, SEL op, ...)
const char *SuperName = "objc_msgSendSuper2";
@@ -197,7 +207,7 @@ private:
Params, true),
SuperName);
}
-
+
llvm::Constant *getMessageSendSuperStretFn() const {
// void objc_msgSendSuper_stret(void * stretAddr, struct objc_super *super,
// SEL op, ...)
@@ -205,11 +215,12 @@ private:
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");
+ return CGM.CreateRuntimeFunction(
+ llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
+ Params, true),
+ "objc_msgSendSuper_stret");
}
-
+
llvm::Constant *getMessageSendSuperStretFn2() const {
// void objc_msgSendSuper2_stret(void * stretAddr, struct objc_super *super,
// SEL op, ...)
@@ -217,68 +228,69 @@ private:
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");
+ return CGM.CreateRuntimeFunction(
+ llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
+ 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();
@@ -294,7 +306,7 @@ public:
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();
@@ -312,25 +324,28 @@ public:
Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params), false);
return CGM.CreateRuntimeFunction(FTy, "objc_setProperty");
}
-
+
llvm::Constant *getEnumerationMutationFn() {
+ CodeGen::CodeGenTypes &Types = CGM.getTypes();
+ ASTContext &Ctx = CGM.getContext();
// 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);
+ llvm::SmallVector<QualType,16> Params;
+ Params.push_back(Ctx.getObjCIdType());
+ const llvm::FunctionType *FTy =
+ Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params), 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);
+ 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 *)
@@ -340,31 +355,45 @@ public:
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);
+ 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 *)
+ // id objc_assign_ivar(id, id *, ptrdiff_t)
std::vector<const llvm::Type*> Args(1, ObjectPtrTy);
Args.push_back(ObjectPtrTy->getPointerTo());
- llvm::FunctionType *FTy = llvm::FunctionType::get(ObjectPtrTy, Args, false);
+ Args.push_back(LongTy);
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(ObjectPtrTy, Args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_assign_ivar");
}
-
+
+ /// GcMemmoveCollectableFn -- LLVM objc_memmove_collectable function.
+ llvm::Constant *GcMemmoveCollectableFn() {
+ // void *objc_memmove_collectable(void *dst, const void *src, size_t size)
+ std::vector<const llvm::Type*> Args(1, Int8PtrTy);
+ Args.push_back(Int8PtrTy);
+ Args.push_back(LongTy);
+ llvm::FunctionType *FTy = llvm::FunctionType::get(Int8PtrTy, Args, false);
+ return CGM.CreateRuntimeFunction(FTy, "objc_memmove_collectable");
+ }
+
/// 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);
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(ObjectPtrTy, Args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_assign_strongCast");
}
@@ -373,52 +402,52 @@ public:
// void objc_exception_throw(id)
std::vector<const llvm::Type*> Args(1, ObjectPtrTy);
llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::VoidTy, Args, false);
+ llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), 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);
+ llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), 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);
+ llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), 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(){}
};
@@ -477,26 +506,28 @@ public:
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");
+ return CGM.CreateRuntimeFunction(
+ llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
+ 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");
+ return CGM.CreateRuntimeFunction(
+ llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
+ Params, false),
+ "objc_exception_try_exit");
}
/// ExceptionExtractFn - LLVM objc_exception_extract function.
@@ -506,31 +537,32 @@ public:
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");
-
+ return CGM.CreateRuntimeFunction(
+ llvm::FunctionType::get(llvm::Type::getInt32Ty(VMContext),
+ 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));
+ Params.push_back(llvm::Type::getInt32PtrTy(VMContext));
return
- CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::Int32Ty,
+ CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty(VMContext),
Params, false),
"_setjmp");
-
+
}
-
+
public:
ObjCTypesHelper(CodeGen::CodeGenModule &cgm);
~ObjCTypesHelper() {}
@@ -540,51 +572,51 @@ public:
/// 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;
@@ -593,22 +625,22 @@ public:
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;
@@ -621,7 +653,7 @@ public:
Params, true),
"objc_msgSend_fixup");
}
-
+
llvm::Constant *getMessageSendFpretFixupFn() {
// id objc_msgSend_fpret_fixup(id, struct message_ref_t*, ...)
std::vector<const llvm::Type*> Params;
@@ -631,7 +663,7 @@ public:
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;
@@ -641,7 +673,7 @@ public:
Params, true),
"objc_msgSend_stret_fixup");
}
-
+
llvm::Constant *getMessageSendIdFixupFn() {
// id objc_msgSendId_fixup(id, struct message_ref_t*, ...)
std::vector<const llvm::Type*> Params;
@@ -651,7 +683,7 @@ public:
Params, true),
"objc_msgSendId_fixup");
}
-
+
llvm::Constant *getMessageSendIdStretFixupFn() {
// id objc_msgSendId_stret_fixup(id, struct message_ref_t*, ...)
std::vector<const llvm::Type*> Params;
@@ -662,7 +694,7 @@ public:
"objc_msgSendId_stret_fixup");
}
llvm::Constant *getMessageSendSuper2FixupFn() {
- // id objc_msgSendSuper2_fixup (struct objc_super *,
+ // id objc_msgSendSuper2_fixup (struct objc_super *,
// struct _super_message_ref_t*, ...)
std::vector<const llvm::Type*> Params;
Params.push_back(SuperPtrTy);
@@ -671,9 +703,9 @@ public:
Params, true),
"objc_msgSendSuper2_fixup");
}
-
+
llvm::Constant *getMessageSendSuper2StretFixupFn() {
- // id objc_msgSendSuper2_stret_fixup(struct objc_super *,
+ // id objc_msgSendSuper2_stret_fixup(struct objc_super *,
// struct _super_message_ref_t*, ...)
std::vector<const llvm::Type*> Params;
Params.push_back(SuperPtrTy);
@@ -682,34 +714,35 @@ public:
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,
+ llvm::Constant *Personality =
+ CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty(VMContext),
true),
- "__objc_personality_v0");
+ "__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");
+ return CGM.CreateRuntimeFunction(
+ llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
+ Params, false),
+ "_Unwind_Resume_or_Rethrow");
}
-
+
llvm::Constant *getObjCEndCatchFn() {
- return CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::VoidTy,
+ return CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
false),
"objc_end_catch");
-
+
}
-
+
llvm::Constant *getObjCBeginCatchFn() {
std::vector<const llvm::Type*> Params;
Params.push_back(Int8PtrTy);
@@ -724,7 +757,7 @@ public:
ObjCNonFragileABITypesHelper(CodeGen::CodeGenModule &cgm);
~ObjCNonFragileABITypesHelper(){}
};
-
+
class CGObjCCommonMac : public CodeGen::CGObjCRuntime {
public:
// FIXME - accessibility
@@ -733,129 +766,126 @@ public:
unsigned ivar_bytepos;
unsigned ivar_size;
GC_IVAR(unsigned bytepos = 0, unsigned size = 0)
- : ivar_bytepos(bytepos), ivar_size(size) {}
+ : 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_SCAN(unsigned _skip = 0, unsigned _scan = 0)
: skip(_skip), scan(_scan) {}
};
-
+
protected:
CodeGen::CodeGenModule &CGM;
+ llvm::LLVMContext &VMContext;
// 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;
-
+ llvm::SetVector<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;
-
+ llvm::SetVector<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);
+ unsigned int BytePos, bool ForStrongLayout,
+ bool &HasUnion);
void BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
const llvm::StructLayout *Layout,
const RecordDecl *RD,
@@ -867,14 +897,14 @@ protected:
/// 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 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.
@@ -885,7 +915,7 @@ protected:
///
/// 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.
+ /// global to the "llvm.used" list.
///
/// \param Name - The variable name.
/// \param Init - The variable initializer; this is also used to
@@ -907,33 +937,32 @@ protected:
QualType Arg0Ty,
bool IsSuper,
const CallArgList &CallArgs,
+ const ObjCMethodDecl *OMD,
const ObjCCommonTypesHelper &ObjCTypes);
- virtual void MergeMetadataGlobals(std::vector<llvm::Constant*> &UsedArray);
-
public:
- CGObjCCommonMac(CodeGen::CodeGenModule &cgm) : CGM(cgm)
- { }
-
+ CGObjCCommonMac(CodeGen::CodeGenModule &cgm) :
+ CGM(cgm), VMContext(cgm.getLLVMContext()) { }
+
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;
@@ -942,7 +971,7 @@ private:
void EmitImageInfo();
/// EmitModuleInfo - Another marker encoding module level
- /// information.
+ /// information.
void EmitModuleInfo();
/// EmitModuleSymols - Emit module symbols, the list of defined
@@ -960,7 +989,7 @@ private:
/// EmitClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy,
/// for the given class.
- llvm::Value *EmitClassRef(CGBuilderTy &Builder,
+ llvm::Value *EmitClassRef(CGBuilderTy &Builder,
const ObjCInterfaceDecl *ID);
CodeGen::RValue EmitMessageSend(CodeGen::CodeGenFunction &CGF,
@@ -978,7 +1007,7 @@ private:
/// 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.
@@ -989,9 +1018,9 @@ private:
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
@@ -1001,7 +1030,7 @@ private:
const ConstantVector &Methods);
/// EmitMethodDescList - Emit a method description list for a list of
- /// method declarations.
+ /// 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.
@@ -1044,12 +1073,12 @@ private:
/// EmitSelector - Return a Value*, of type ObjCTypes.SelectorPtrTy,
/// for the given selector.
llvm::Value *EmitSelector(CGBuilderTy &Builder, Selector Sel);
-
- public:
+
+public:
CGObjCMac(CodeGen::CodeGenModule &cgm);
virtual llvm::Function *ModuleInitFunction();
-
+
virtual CodeGen::RValue GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
QualType ResultType,
Selector Sel,
@@ -1058,7 +1087,7 @@ private:
const CallArgList &CallArgs,
const ObjCMethodDecl *Method);
- virtual CodeGen::RValue
+ virtual CodeGen::RValue
GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
QualType ResultType,
Selector Sel,
@@ -1066,8 +1095,9 @@ private:
bool isCategoryImpl,
llvm::Value *Receiver,
bool IsClassMessage,
- const CallArgList &CallArgs);
-
+ const CallArgList &CallArgs,
+ const ObjCMethodDecl *Method);
+
virtual llvm::Value *GetClass(CGBuilderTy &Builder,
const ObjCInterfaceDecl *ID);
@@ -1084,26 +1114,30 @@ private:
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);
+ llvm::Value *AddrWeakObj);
virtual void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dst);
+ 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);
+ llvm::Value *src, llvm::Value *dest,
+ llvm::Value *ivarOffset);
virtual void EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dest);
-
+ virtual void EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *dest, llvm::Value *src,
+ QualType Ty);
+
virtual LValue EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF,
QualType ObjectTy,
llvm::Value *BaseValue,
@@ -1113,30 +1147,30 @@ private:
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();
@@ -1147,20 +1181,20 @@ private:
const char *SymbolName,
const char *SectionName);
- llvm::GlobalVariable * BuildClassRoTInitializer(unsigned flags,
- unsigned InstanceStart,
- unsigned InstanceSize,
- const ObjCImplementationDecl *ID);
+ llvm::GlobalVariable * BuildClassRoTInitializer(unsigned flags,
+ unsigned InstanceStart,
+ unsigned InstanceSize,
+ const ObjCImplementationDecl *ID);
llvm::GlobalVariable * BuildClassMetaData(std::string &ClassName,
- llvm::Constant *IsAGV,
+ 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,
@@ -1172,28 +1206,28 @@ private:
/// 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,
@@ -1205,29 +1239,29 @@ private:
/// 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,
+ 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);
-
+ 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,
+ 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);
-
+ 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);
@@ -1237,10 +1271,10 @@ private:
llvm::Value *GetInterfaceEHType(const ObjCInterfaceDecl *ID,
bool ForDefinition);
- const char *getMetaclassSymbolPrefix() const {
+ const char *getMetaclassSymbolPrefix() const {
return "OBJC_METACLASS_$_";
}
-
+
const char *getClassSymbolPrefix() const {
return "OBJC_CLASS_$_";
}
@@ -1248,13 +1282,13 @@ private:
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);
@@ -1268,7 +1302,7 @@ 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,
@@ -1276,8 +1310,8 @@ public:
bool IsClassMessage,
const CallArgList &CallArgs,
const ObjCMethodDecl *Method);
-
- virtual CodeGen::RValue
+
+ virtual CodeGen::RValue
GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
QualType ResultType,
Selector Sel,
@@ -1285,11 +1319,12 @@ public:
bool isCategoryImpl,
llvm::Value *Receiver,
bool IsClassMessage,
- const CallArgList &CallArgs);
-
+ const CallArgList &CallArgs,
+ const ObjCMethodDecl *Method);
+
virtual llvm::Value *GetClass(CGBuilderTy &Builder,
const ObjCInterfaceDecl *ID);
-
+
virtual llvm::Value *GetSelector(CGBuilderTy &Builder, Selector Sel)
{ return EmitSelector(Builder, Sel); }
@@ -1298,23 +1333,23 @@ public:
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() {
+
+ virtual llvm::Constant *GetPropertyGetFunction() {
return ObjCTypes.getGetPropertyFn();
}
- virtual llvm::Constant *GetPropertySetFunction() {
- return ObjCTypes.getSetPropertyFn();
+ 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,
@@ -1326,9 +1361,13 @@ public:
virtual void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dest);
virtual void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dest);
+ llvm::Value *src, llvm::Value *dest,
+ llvm::Value *ivarOffset);
virtual void EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dest);
+ virtual void EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *dest, llvm::Value *src,
+ QualType Ty);
virtual LValue EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF,
QualType ObjectTy,
llvm::Value *BaseValue,
@@ -1338,25 +1377,26 @@ public:
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,
+static llvm::Constant *getConstantGEP(llvm::LLVMContext &VMContext,
+ llvm::Constant *C,
unsigned idx0,
unsigned idx1) {
llvm::Value *Idxs[] = {
- llvm::ConstantInt::get(llvm::Type::Int32Ty, idx0),
- llvm::ConstantInt::get(llvm::Type::Int32Ty, idx1)
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), idx0),
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 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(ASTContext &Context,
+static bool hasObjCExceptionAttribute(ASTContext &Context,
const ObjCInterfaceDecl *OID) {
if (OID->hasAttr<ObjCExceptionAttr>())
return true;
@@ -1366,12 +1406,11 @@ static bool hasObjCExceptionAttribute(ASTContext &Context,
}
/* *** CGObjCMac Public Interface *** */
-
+
CGObjCMac::CGObjCMac(CodeGen::CodeGenModule &cgm) : CGObjCCommonMac(cgm),
- ObjCTypes(cgm)
-{
+ ObjCTypes(cgm) {
ObjCABI = 1;
- EmitImageInfo();
+ EmitImageInfo();
}
/// GetClass - Return a reference to the class for the given interface
@@ -1386,18 +1425,18 @@ llvm::Value *CGObjCMac::GetSelector(CGBuilderTy &Builder, Selector Sel) {
return EmitSelector(Builder, Sel);
}
llvm::Value *CGObjCMac::GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl
- *Method) {
+ *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;
- };
+/*
+ struct __builtin_CFString {
+ const int *isa; // point to __CFConstantStringClassReference
+ int flags;
+ const char *str;
+ long length;
+ };
*/
llvm::Constant *CGObjCCommonMac::GenerateConstantString(
@@ -1416,14 +1455,15 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
bool isCategoryImpl,
llvm::Value *Receiver,
bool IsClassMessage,
- const CodeGen::CallArgList &CallArgs) {
+ const CodeGen::CallArgList &CallArgs,
+ const ObjCMethodDecl *Method) {
// Create and init a super structure; this is a (receiver, class)
// pair we will pass to objc_msgSendSuper.
- llvm::Value *ObjCSuper =
+ llvm::Value *ObjCSuper =
CGF.Builder.CreateAlloca(ObjCTypes.SuperTy, 0, "objc_super");
- llvm::Value *ReceiverAsObject =
+ llvm::Value *ReceiverAsObject =
CGF.Builder.CreateBitCast(Receiver, ObjCTypes.ObjectPtrTy);
- CGF.Builder.CreateStore(ReceiverAsObject,
+ CGF.Builder.CreateStore(ReceiverAsObject,
CGF.Builder.CreateStructGEP(ObjCSuper, 0));
// If this is a class message the metaclass is passed as the target.
@@ -1439,30 +1479,29 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
Target = EmitClassRef(CGF.Builder, Class->getSuperClass());
Target = CGF.Builder.CreateStructGEP(Target, 0);
Target = CGF.Builder.CreateLoad(Target);
- }
- else {
+ } 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 =
+ const llvm::Type *ClassTy =
CGM.getTypes().ConvertType(CGF.getContext().getObjCClassType());
Target = CGF.Builder.CreateBitCast(Target, ClassTy);
- CGF.Builder.CreateStore(Target,
+ CGF.Builder.CreateStore(Target,
CGF.Builder.CreateStructGEP(ObjCSuper, 1));
- return EmitLegacyMessageSend(CGF, ResultType,
+ return EmitLegacyMessageSend(CGF, ResultType,
EmitSelector(CGF.Builder, Sel),
ObjCSuper, ObjCTypes.SuperPtrCTy,
- true, CallArgs, ObjCTypes);
+ true, CallArgs, Method, ObjCTypes);
}
-
-/// Generate code for a message send expression.
+
+/// Generate code for a message send expression.
CodeGen::RValue CGObjCMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
QualType ResultType,
Selector Sel,
@@ -1473,18 +1512,19 @@ CodeGen::RValue CGObjCMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
return EmitLegacyMessageSend(CGF, ResultType,
EmitSelector(CGF.Builder, Sel),
Receiver, CGF.getContext().getObjCIdType(),
- false, CallArgs, ObjCTypes);
+ false, CallArgs, Method, 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) {
+CodeGen::RValue
+CGObjCCommonMac::EmitLegacyMessageSend(CodeGen::CodeGenFunction &CGF,
+ QualType ResultType,
+ llvm::Value *Sel,
+ llvm::Value *Arg0,
+ QualType Arg0Ty,
+ bool IsSuper,
+ const CallArgList &CallArgs,
+ const ObjCMethodDecl *Method,
+ const ObjCCommonTypesHelper &ObjCTypes) {
CallArgList ActualArgs;
if (!IsSuper)
Arg0 = CGF.Builder.CreateBitCast(Arg0, ObjCTypes.ObjectPtrTy, "tmp");
@@ -1492,41 +1532,40 @@ CodeGen::RValue CGObjCCommonMac::EmitLegacyMessageSend(
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));
-
+ const llvm::FunctionType *FTy =
+ Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false);
+
llvm::Constant *Fn = NULL;
if (CGM.ReturnTypeUsesSret(FnInfo)) {
Fn = (ObjCABI == 2) ? ObjCTypes.getSendStretFn2(IsSuper)
- : ObjCTypes.getSendStretFn(IsSuper);
+ : ObjCTypes.getSendStretFn(IsSuper);
} else if (ResultType->isFloatingType()) {
if (ObjCABI == 2) {
- if (const BuiltinType *BT = ResultType->getAsBuiltinType()) {
+ if (const BuiltinType *BT = ResultType->getAs<BuiltinType>()) {
BuiltinType::Kind k = BT->getKind();
Fn = (k == BuiltinType::LongDouble) ? ObjCTypes.getSendFpretFn2(IsSuper)
- : ObjCTypes.getSendFn2(IsSuper);
+ : ObjCTypes.getSendFn2(IsSuper);
} else {
Fn = ObjCTypes.getSendFn2(IsSuper);
}
- }
- else
+ } 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);
+ : ObjCTypes.getSendFn(IsSuper);
}
assert(Fn && "EmitLegacyMessageSend - unknown API");
- Fn = llvm::ConstantExpr::getBitCast(Fn, llvm::PointerType::getUnqual(FTy));
+ Fn = llvm::ConstantExpr::getBitCast(Fn,
+ llvm::PointerType::getUnqual(FTy));
return CGF.EmitCall(FnInfo, Fn, ActualArgs);
}
-llvm::Value *CGObjCMac::GenerateProtocolRef(CGBuilderTy &Builder,
+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.
@@ -1544,7 +1583,7 @@ void CGObjCCommonMac::GenerateProtocol(const ObjCProtocolDecl *PD) {
// 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()))
+ if (Protocols.count(PD->getIdentifier()))
GetOrEmitProtocol(PD);
}
@@ -1555,16 +1594,16 @@ llvm::Constant *CGObjCCommonMac::GetProtocolRef(const ObjCProtocolDecl *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
- };
+// 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().
+See EmitProtocolExtension().
*/
llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) {
llvm::GlobalVariable *&Entry = Protocols[PD->getIdentifier()];
@@ -1582,7 +1621,7 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) {
// Construct method lists.
std::vector<llvm::Constant*> InstanceMethods, ClassMethods;
std::vector<llvm::Constant*> OptInstanceMethods, OptClassMethods;
- for (ObjCProtocolDecl::instmeth_iterator
+ for (ObjCProtocolDecl::instmeth_iterator
i = PD->instmeth_begin(), e = PD->instmeth_end(); i != e; ++i) {
ObjCMethodDecl *MD = *i;
llvm::Constant *C = GetMethodDescriptionConstant(MD);
@@ -1590,10 +1629,10 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) {
OptInstanceMethods.push_back(C);
} else {
InstanceMethods.push_back(C);
- }
+ }
}
- for (ObjCProtocolDecl::classmeth_iterator
+ for (ObjCProtocolDecl::classmeth_iterator
i = PD->classmeth_begin(), e = PD->classmeth_end(); i != e; ++i) {
ObjCMethodDecl *MD = *i;
llvm::Constant *C = GetMethodDescriptionConstant(MD);
@@ -1601,46 +1640,45 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) {
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] =
+ Values[2] =
EmitProtocolList("\01L_OBJC_PROTOCOL_REFS_" + PD->getNameAsString(),
PD->protocol_begin(),
PD->protocol_end());
- Values[3] =
+ Values[3] =
EmitMethodDescList("\01L_OBJC_PROTOCOL_INSTANCE_METHODS_"
- + PD->getNameAsString(),
+ + PD->getNameAsString(),
"__OBJC,__cat_inst_meth,regular,no_dead_strip",
InstanceMethods);
- Values[4] =
- EmitMethodDescList("\01L_OBJC_PROTOCOL_CLASS_METHODS_"
- + PD->getNameAsString(),
+ 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,
+ Entry =
+ new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolTy, false,
llvm::GlobalValue::InternalLinkage,
- Init,
- std::string("\01L_OBJC_PROTOCOL_")+ProtocolName,
- &CGM.getModule());
+ Init,
+ std::string("\01L_OBJC_PROTOCOL_")+ProtocolName);
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);
}
+ CGM.AddUsedGlobal(Entry);
return Entry;
}
@@ -1652,71 +1690,69 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocolRef(const ObjCProtocolDecl *PD) {
// 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,
+ Entry =
+ new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolTy, false,
llvm::GlobalValue::ExternalLinkage,
0,
- "\01L_OBJC_PROTOCOL_" + PD->getNameAsString(),
- &CGM.getModule());
+ "\01L_OBJC_PROTOCOL_" + PD->getNameAsString());
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;
+ 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 =
+ 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(),
+ Values[1] =
+ EmitMethodDescList("\01L_OBJC_PROTOCOL_INSTANCE_METHODS_OPT_"
+ + PD->getNameAsString(),
"__OBJC,__cat_inst_meth,regular,no_dead_strip",
OptInstanceMethods);
- Values[2] =
+ Values[2] =
EmitMethodDescList("\01L_OBJC_PROTOCOL_CLASS_METHODS_OPT_"
- + PD->getNameAsString(),
+ + PD->getNameAsString(),
"__OBJC,__cat_cls_meth,regular,no_dead_strip",
OptClassMethods);
- Values[3] = EmitPropertyList("\01L_OBJC_$_PROP_PROTO_LIST_" +
- PD->getNameAsString(),
+ 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() &&
+ if (Values[1]->isNullValue() && Values[2]->isNullValue() &&
Values[3]->isNullValue())
return llvm::Constant::getNullValue(ObjCTypes.ProtocolExtensionPtrTy);
- llvm::Constant *Init =
+ 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,
+ Init,
0, 0, true);
}
/*
struct objc_protocol_list {
- struct objc_protocol_list *next;
- long count;
- Protocol *list[];
+ struct objc_protocol_list *next;
+ long count;
+ Protocol *list[];
};
*/
llvm::Constant *
@@ -1729,7 +1765,7 @@ CGObjCMac::EmitProtocolList(const std::string &Name,
ProtocolRefs.push_back(GetProtocolRef(*begin));
// Just return null for empty protocol lists
- if (ProtocolRefs.empty())
+ if (ProtocolRefs.empty())
return llvm::Constant::getNullValue(ObjCTypes.ProtocolListPtrTy);
// This list is null terminated.
@@ -1738,14 +1774,15 @@ CGObjCMac::EmitProtocolList(const std::string &Name,
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()),
+ 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 =
+
+ llvm::Constant *Init = llvm::ConstantStruct::get(VMContext, Values, false);
+ llvm::GlobalVariable *GV =
CreateMetadataVar(Name, Init, "__OBJC,__cat_cls_meth,regular,no_dead_strip",
4, false);
return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.ProtocolListPtrTy);
@@ -1753,23 +1790,23 @@ CGObjCMac::EmitProtocolList(const std::string &Name,
/*
struct _objc_property {
- const char * const name;
- const char * const attributes;
+ 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];
+ 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) {
+ const Decl *Container,
+ const ObjCContainerDecl *OCD,
+ const ObjCCommonTypesHelper &ObjCTypes) {
std::vector<llvm::Constant*> Properties, Prop(2);
- for (ObjCContainerDecl::prop_iterator I = OCD->prop_begin(),
- E = OCD->prop_end(); I != E; ++I) {
+ for (ObjCContainerDecl::prop_iterator I = OCD->prop_begin(),
+ E = OCD->prop_end(); I != E; ++I) {
const ObjCPropertyDecl *PD = *I;
Prop[0] = GetPropertyName(PD->getIdentifier());
Prop[1] = GetPropertyTypeString(PD, Container);
@@ -1781,36 +1818,37 @@ llvm::Constant *CGObjCCommonMac::EmitPropertyList(const std::string &Name,
if (Properties.empty())
return llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy);
- unsigned PropertySize =
+ 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,
+ 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::Constant *Init = llvm::ConstantStruct::get(VMContext, Values, false);
- llvm::GlobalVariable *GV =
- CreateMetadataVar(Name, Init,
- (ObjCABI == 2) ? "__DATA, __objc_const" :
+ llvm::GlobalVariable *GV =
+ CreateMetadataVar(Name, Init,
+ (ObjCABI == 2) ? "__DATA, __objc_const" :
"__OBJC,__property,regular,no_dead_strip",
- (ObjCABI == 2) ? 8 : 4,
+ (ObjCABI == 2) ? 8 : 4,
true);
return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.PropertyListPtrTy);
}
/*
struct objc_method_description_list {
- int count;
- 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[0] =
+ llvm::ConstantExpr::getBitCast(GetMethodVarName(MD->getSelector()),
+ ObjCTypes.SelectorPtrTy);
Desc[1] = GetMethodVarType(MD);
return llvm::ConstantStruct::get(ObjCTypes.MethodDescriptionTy,
Desc);
@@ -1825,27 +1863,27 @@ llvm::Constant *CGObjCMac::EmitMethodDescList(const std::string &Name,
std::vector<llvm::Constant*> Values(2);
Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Methods.size());
- llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.MethodDescriptionTy,
+ 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::Constant *Init = llvm::ConstantStruct::get(VMContext, Values, false);
llvm::GlobalVariable *GV = CreateMetadataVar(Name, Init, Section, 4, true);
- return llvm::ConstantExpr::getBitCast(GV,
+ 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;
+ 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);
@@ -1854,18 +1892,18 @@ void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
// 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 =
+ const ObjCCategoryDecl *Category =
Interface->FindCategoryDeclaration(OCD->getIdentifier());
std::string ExtName(Interface->getNameAsString() + "_" +
OCD->getNameAsString());
std::vector<llvm::Constant*> InstanceMethods, ClassMethods;
- for (ObjCCategoryImplDecl::instmeth_iterator
+ for (ObjCCategoryImplDecl::instmeth_iterator
i = OCD->instmeth_begin(), e = OCD->instmeth_end(); i != e; ++i) {
// Instance methods should always be defined.
InstanceMethods.push_back(GetMethodConstant(*i));
}
- for (ObjCCategoryImplDecl::classmeth_iterator
+ for (ObjCCategoryImplDecl::classmeth_iterator
i = OCD->classmeth_begin(), e = OCD->classmeth_end(); i != e; ++i) {
// Class methods should always be defined.
ClassMethods.push_back(GetMethodConstant(*i));
@@ -1875,17 +1913,17 @@ void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
Values[0] = GetClassName(OCD->getIdentifier());
Values[1] = GetClassName(Interface->getIdentifier());
LazySymbols.insert(Interface->getIdentifier());
- Values[2] =
- EmitMethodList(std::string("\01L_OBJC_CATEGORY_INSTANCE_METHODS_") +
+ Values[2] =
+ EmitMethodList(std::string("\01L_OBJC_CATEGORY_INSTANCE_METHODS_") +
ExtName,
"__OBJC,__cat_inst_meth,regular,no_dead_strip",
InstanceMethods);
- Values[3] =
+ Values[3] =
EmitMethodList(std::string("\01L_OBJC_CATEGORY_CLASS_METHODS_") + ExtName,
"__OBJC,__cat_cls_meth,regular,no_dead_strip",
ClassMethods);
if (Category) {
- Values[4] =
+ Values[4] =
EmitProtocolList(std::string("\01L_OBJC_CATEGORY_PROTOCOLS_") + ExtName,
Category->protocol_begin(),
Category->protocol_end());
@@ -1896,16 +1934,16 @@ void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
// If there is no category @interface then there can be no properties.
if (Category) {
- Values[6] = EmitPropertyList(std::string("\01l_OBJC_$_PROP_LIST_") + ExtName,
+ 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 =
+ llvm::GlobalVariable *GV =
CreateMetadataVar(std::string("\01L_OBJC_CATEGORY_")+ExtName, Init,
"__OBJC,__category,regular,no_dead_strip",
4, true);
@@ -1925,36 +1963,36 @@ enum ClassFlags {
/*
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;
+ 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 =
+ ObjCInterfaceDecl *Interface =
const_cast<ObjCInterfaceDecl*>(ID->getClassInterface());
- llvm::Constant *Protocols =
+ llvm::Constant *Protocols =
EmitProtocolList("\01L_OBJC_CLASS_PROTOCOLS_" + ID->getNameAsString(),
Interface->protocol_begin(),
Interface->protocol_end());
unsigned Flags = eClassFlags_Factory;
- unsigned Size =
+ unsigned Size =
CGM.getContext().getASTObjCImplementationLayout(ID).getSize() / 8;
// FIXME: Set CXX-structors flag.
@@ -1962,18 +2000,18 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
Flags |= eClassFlags_Hidden;
std::vector<llvm::Constant*> InstanceMethods, ClassMethods;
- for (ObjCImplementationDecl::instmeth_iterator
+ for (ObjCImplementationDecl::instmeth_iterator
i = ID->instmeth_begin(), e = ID->instmeth_end(); i != e; ++i) {
// Instance methods should always be defined.
InstanceMethods.push_back(GetMethodConstant(*i));
}
- for (ObjCImplementationDecl::classmeth_iterator
+ for (ObjCImplementationDecl::classmeth_iterator
i = ID->classmeth_begin(), e = ID->classmeth_end(); i != e; ++i) {
// Class methods should always be defined.
ClassMethods.push_back(GetMethodConstant(*i));
}
- for (ObjCImplementationDecl::propimpl_iterator
+ for (ObjCImplementationDecl::propimpl_iterator
i = ID->propimpl_begin(), e = ID->propimpl_end(); i != e; ++i) {
ObjCPropertyImplDecl *PID = *i;
@@ -1995,7 +2033,7 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
// Record a reference to the super class.
LazySymbols.insert(Super->getIdentifier());
- Values[ 1] =
+ Values[ 1] =
llvm::ConstantExpr::getBitCast(GetClassName(Super->getIdentifier()),
ObjCTypes.ClassPtrTy);
} else {
@@ -2007,19 +2045,19 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
Values[ 4] = llvm::ConstantInt::get(ObjCTypes.LongTy, Flags);
Values[ 5] = llvm::ConstantInt::get(ObjCTypes.LongTy, Size);
Values[ 6] = EmitIvarList(ID, false);
- Values[ 7] =
+ 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[10] = BuildIvarLayout(ID, true);
Values[11] = EmitClassExtension(ID);
llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassTy,
Values);
- llvm::GlobalVariable *GV =
+ llvm::GlobalVariable *GV =
CreateMetadataVar(std::string("\01L_OBJC_CLASS_")+ClassName, Init,
"__OBJC,__class,regular,no_dead_strip",
4, true);
@@ -2034,20 +2072,20 @@ llvm::Constant *CGObjCMac::EmitMetaClass(const ObjCImplementationDecl *ID,
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] =
+ 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] =
+ Values[ 1] =
llvm::ConstantExpr::getBitCast(GetClassName(Super->getIdentifier()),
ObjCTypes.ClassPtrTy);
} else {
@@ -2059,7 +2097,7 @@ llvm::Constant *CGObjCMac::EmitMetaClass(const ObjCImplementationDecl *ID,
Values[ 4] = llvm::ConstantInt::get(ObjCTypes.LongTy, Flags);
Values[ 5] = llvm::ConstantInt::get(ObjCTypes.LongTy, Size);
Values[ 6] = EmitIvarList(ID, true);
- Values[ 7] =
+ Values[ 7] =
EmitMethodList("\01L_OBJC_CLASS_METHODS_" + ID->getNameAsString(),
"__OBJC,__cls_meth,regular,no_dead_strip",
Methods);
@@ -2084,19 +2122,18 @@ llvm::Constant *CGObjCMac::EmitMetaClass(const ObjCImplementationDecl *ID,
GV->setLinkage(llvm::GlobalValue::InternalLinkage);
GV->setInitializer(Init);
} else {
- GV = new llvm::GlobalVariable(ObjCTypes.ClassTy, false,
+ GV = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassTy, false,
llvm::GlobalValue::InternalLinkage,
- Init, Name,
- &CGM.getModule());
+ Init, Name);
}
GV->setSection("__OBJC,__meta_class,regular,no_dead_strip");
GV->setAlignment(4);
- UsedGlobals.push_back(GV);
+ CGM.AddUsedGlobal(GV);
return GV;
}
-llvm::Constant *CGObjCMac::EmitMetaClassRef(const ObjCInterfaceDecl *ID) {
+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
@@ -2107,31 +2144,31 @@ llvm::Constant *CGObjCMac::EmitMetaClassRef(const ObjCInterfaceDecl *ID) {
// 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)) {
+ 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,
+ return new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassTy, false,
llvm::GlobalValue::ExternalLinkage,
0,
- Name,
- &CGM.getModule());
+ Name);
}
}
/*
struct objc_class_ext {
- uint32_t size;
- const char *weak_ivar_layout;
- struct _objc_property_list *properties;
+ uint32_t size;
+ const char *weak_ivar_layout;
+ struct _objc_property_list *properties;
};
*/
llvm::Constant *
CGObjCMac::EmitClassExtension(const ObjCImplementationDecl *ID) {
- uint64_t Size =
+ uint64_t Size =
CGM.getTargetData().getTypeAllocSize(ObjCTypes.ClassExtensionTy);
std::vector<llvm::Constant*> Values(3);
@@ -2144,25 +2181,25 @@ CGObjCMac::EmitClassExtension(const ObjCImplementationDecl *ID) {
if (Values[1]->isNullValue() && Values[2]->isNullValue())
return llvm::Constant::getNullValue(ObjCTypes.ClassExtensionPtrTy);
- llvm::Constant *Init =
+ llvm::Constant *Init =
llvm::ConstantStruct::get(ObjCTypes.ClassExtensionTy, Values);
return CreateMetadataVar("\01L_OBJC_CLASSEXT_" + ID->getNameAsString(),
- Init, "__OBJC,__class_ext,regular,no_dead_strip",
+ Init, "__OBJC,__class_ext,regular,no_dead_strip",
4, true);
}
/*
struct objc_ivar {
- char *ivar_name;
- char *ivar_type;
- int ivar_offset;
+ char *ivar_name;
+ char *ivar_type;
+ int ivar_offset;
};
struct objc_ivar_list {
- int ivar_count;
- struct objc_ivar list[count];
+ int ivar_count;
+ struct objc_ivar list[count];
};
- */
+*/
llvm::Constant *CGObjCMac::EmitIvarList(const ObjCImplementationDecl *ID,
bool ForClass) {
std::vector<llvm::Constant*> Ivars, Ivar(3);
@@ -2174,21 +2211,21 @@ llvm::Constant *CGObjCMac::EmitIvarList(const ObjCImplementationDecl *ID,
// for the class.
if (ForClass)
return llvm::Constant::getNullValue(ObjCTypes.IvarListPtrTy);
-
- ObjCInterfaceDecl *OID =
+
+ ObjCInterfaceDecl *OID =
const_cast<ObjCInterfaceDecl*>(ID->getClassInterface());
-
+
llvm::SmallVector<ObjCIvarDecl*, 16> OIvars;
CGM.getContext().ShallowCollectObjCIvars(OID, OIvars);
-
+
for (unsigned i = 0, e = OIvars.size(); i != e; ++i) {
ObjCIvarDecl *IVD = OIvars[i];
// Ignore unnamed bit-fields.
if (!IVD->getDeclName())
- continue;
+ continue;
Ivar[0] = GetMethodVarName(IVD->getIdentifier());
Ivar[1] = GetMethodVarType(IVD);
- Ivar[2] = llvm::ConstantInt::get(ObjCTypes.IntTy,
+ Ivar[2] = llvm::ConstantInt::get(ObjCTypes.IntTy,
ComputeIvarBaseOffset(CGM, OID, IVD));
Ivars.push_back(llvm::ConstantStruct::get(ObjCTypes.IvarTy, Ivar));
}
@@ -2202,12 +2239,12 @@ llvm::Constant *CGObjCMac::EmitIvarList(const ObjCImplementationDecl *ID,
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::Constant *Init = llvm::ConstantStruct::get(VMContext, Values, false);
llvm::GlobalVariable *GV;
if (ForClass)
GV = CreateMetadataVar("\01L_OBJC_CLASS_VARIABLES_" + ID->getNameAsString(),
- Init, "__OBJC,__class_vars,regular,no_dead_strip",
+ Init, "__OBJC,__class_vars,regular,no_dead_strip",
4, true);
else
GV = CreateMetadataVar("\01L_OBJC_INSTANCE_VARIABLES_"
@@ -2219,15 +2256,15 @@ llvm::Constant *CGObjCMac::EmitIvarList(const ObjCImplementationDecl *ID,
/*
struct objc_method {
- SEL method_name;
- char *method_types;
- void *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];
+ struct objc_method_list *obsolete;
+ int count;
+ struct objc_method methods_list[count];
};
*/
@@ -2239,9 +2276,9 @@ llvm::Constant *CGObjCMac::GetMethodConstant(const ObjCMethodDecl *MD) {
llvm::Function *Fn = MethodDefinitions[MD];
if (!Fn)
return 0;
-
+
std::vector<llvm::Constant*> Method(3);
- Method[0] =
+ Method[0] =
llvm::ConstantExpr::getBitCast(GetMethodVarName(MD->getSelector()),
ObjCTypes.SelectorPtrTy);
Method[1] = GetMethodVarType(MD);
@@ -2262,7 +2299,7 @@ llvm::Constant *CGObjCMac::EmitMethodList(const std::string &Name,
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::Constant *Init = llvm::ConstantStruct::get(VMContext, Values, false);
llvm::GlobalVariable *GV = CreateMetadataVar(Name, Init, Section, 4, true);
return llvm::ConstantExpr::getBitCast(GV,
@@ -2270,14 +2307,14 @@ llvm::Constant *CGObjCMac::EmitMethodList(const std::string &Name,
}
llvm::Function *CGObjCCommonMac::GenerateMethod(const ObjCMethodDecl *OMD,
- const ObjCContainerDecl *CD) {
+ 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 *Method =
llvm::Function::Create(MethodTy,
llvm::GlobalValue::InternalLinkage,
Name,
@@ -2294,25 +2331,21 @@ CGObjCCommonMac::CreateMetadataVar(const std::string &Name,
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());
+ llvm::GlobalVariable *GV =
+ new llvm::GlobalVariable(CGM.getModule(), Ty, false,
+ llvm::GlobalValue::InternalLinkage, Init, Name);
if (Section)
GV->setSection(Section);
if (Align)
GV->setAlignment(Align);
if (AddToUsed)
- UsedGlobals.push_back(GV);
+ CGM.AddUsedGlobal(GV);
return GV;
}
-llvm::Function *CGObjCMac::ModuleInitFunction() {
+llvm::Function *CGObjCMac::ModuleInitFunction() {
// Abuse this interface function as a place to finalize.
FinishModule();
-
return NULL;
}
@@ -2328,92 +2361,92 @@ llvm::Constant *CGObjCMac::EnumerationMutationFunction() {
return ObjCTypes.getEnumerationMutationFn();
}
-/*
+/*
-Objective-C setjmp-longjmp (sjlj) Exception Handling
---
+ Objective-C setjmp-longjmp (sjlj) Exception Handling
+ --
-The basic framework for a @try-catch-finally is as follows:
-{
+ 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 ...
+ ... 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 ...
- }
+ // 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:
+ finally:
if (_call_try_exit)
- objc_exception_try_exit(&d);
+ objc_exception_try_exit(&d);
... finally block ....
... dispatch to finally destination ...
-finally_rethrow:
+ finally_rethrow:
objc_exception_throw(_rethrow);
-finally_end:
-}
+ 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:
-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); }
+ - 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,
@@ -2425,14 +2458,14 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
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 =
+ SyncArg =
CGF.EmitScalarExpr(cast<ObjCAtSynchronizedStmt>(S).getSynchExpr());
SyncArg = CGF.Builder.CreateBitCast(SyncArg, ObjCTypes.ObjectPtrTy);
CGF.Builder.CreateCall(ObjCTypes.getSyncEnterFn(), SyncArg);
@@ -2443,19 +2476,21 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
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,
+ llvm::Value *RethrowPtr = CGF.CreateTempAlloca(ObjCTypes.ObjectPtrTy,
"_rethrow");
- llvm::Value *CallTryExitPtr = CGF.CreateTempAlloca(llvm::Type::Int1Ty,
+ llvm::Value *CallTryExitPtr = CGF.CreateTempAlloca(
+ llvm::Type::getInt1Ty(VMContext),
"_call_try_exit");
- CGF.Builder.CreateStore(llvm::ConstantInt::getTrue(), CallTryExitPtr);
-
+ CGF.Builder.CreateStore(llvm::ConstantInt::getTrue(VMContext),
+ CallTryExitPtr);
+
// Enter a new try block and call setjmp.
CGF.Builder.CreateCall(ObjCTypes.getExceptionTryEnterFn(), ExceptionData);
- llvm::Value *JmpBufPtr = CGF.Builder.CreateStructGEP(ExceptionData, 0,
+ llvm::Value *JmpBufPtr = CGF.Builder.CreateStructGEP(ExceptionData, 0,
"jmpbufarray");
JmpBufPtr = CGF.Builder.CreateStructGEP(JmpBufPtr, 0, "tmp");
llvm::Value *SetJmpResult = CGF.Builder.CreateCall(ObjCTypes.getSetJmpFn(),
@@ -2463,15 +2498,15 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
llvm::BasicBlock *TryBlock = CGF.createBasicBlock("try");
llvm::BasicBlock *TryHandler = CGF.createBasicBlock("try.handler");
- CGF.Builder.CreateCondBr(CGF.Builder.CreateIsNotNull(SetJmpResult, "threw"),
+ 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.EmitStmt(isTry ? cast<ObjCAtTryStmt>(S).getTryBody()
+ : cast<ObjCAtSynchronizedStmt>(S).getSynchBody());
CGF.EmitBranchThroughCleanup(FinallyEnd);
-
+
// Emit the "exception in @try" block.
CGF.EmitBlock(TryHandler);
@@ -2481,19 +2516,17 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
CGF.Builder.CreateCall(ObjCTypes.getExceptionExtractFn(),
ExceptionData, "caught");
CGF.ObjCEHValueStack.back() = Caught;
- if (!isTry)
- {
+ if (!isTry) {
CGF.Builder.CreateStore(Caught, RethrowPtr);
- CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(), CallTryExitPtr);
+ CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(VMContext),
+ CallTryExitPtr);
CGF.EmitBranchThroughCleanup(FinallyRethrow);
- }
- else if (const ObjCAtCatchStmt* CatchStmt =
- cast<ObjCAtTryStmt>(S).getCatchStmts())
- {
+ } 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");
@@ -2501,9 +2534,9 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
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.
@@ -2512,64 +2545,64 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
llvm::BasicBlock *NextCatchBlock = CGF.createBasicBlock("catch");
const ParmVarDecl *CatchParam = CatchStmt->getCatchParamDecl();
- const PointerType *PT = 0;
+ const ObjCObjectPointerType *OPT = 0;
// catch(...) always matches.
if (!CatchParam) {
AllMatched = true;
} else {
- PT = CatchParam->getType()->getAsPointerType();
-
- // catch(id e) always matches.
+ OPT = CatchParam->getType()->getAs<ObjCObjectPointerType>();
+
+ // 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())
+ if (OPT && (OPT->isObjCIdType() || OPT->isObjCQualifiedIdType()))
AllMatched = true;
}
-
- if (AllMatched) {
+
+ 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(OPT && "Unexpected non-object pointer type in @catch");
+ QualType T = OPT->getPointeeType();
+ const ObjCInterfaceType *ObjCType = T->getAs<ObjCInterfaceType>();
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"),
+
+ 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()),
+ 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);
}
@@ -2579,41 +2612,43 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
CGF.Builder.CreateStore(Caught, RethrowPtr);
CGF.EmitBranchThroughCleanup(FinallyRethrow);
}
-
+
// Emit the exception handler for the @catch blocks.
- CGF.EmitBlock(CatchHandler);
+ CGF.EmitBlock(CatchHandler);
CGF.Builder.CreateStore(
- CGF.Builder.CreateCall(ObjCTypes.getExceptionExtractFn(),
- ExceptionData),
- RethrowPtr);
- CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(), CallTryExitPtr);
+ CGF.Builder.CreateCall(ObjCTypes.getExceptionExtractFn(),
+ ExceptionData),
+ RethrowPtr);
+ CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(VMContext),
+ CallTryExitPtr);
CGF.EmitBranchThroughCleanup(FinallyRethrow);
} else {
CGF.Builder.CreateStore(Caught, RethrowPtr);
- CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(), CallTryExitPtr);
+ CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(VMContext),
+ 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())
+ if (const ObjCAtFinallyStmt* FinallyStmt =
+ cast<ObjCAtTryStmt>(S).getFinallyStmt())
CGF.EmitStmt(FinallyStmt->getFinallyBody());
} else {
// Emit objc_sync_exit(expr); as finally's sole statement for
@@ -2626,29 +2661,29 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
CGF.EmitBlock(Info.SwitchBlock);
if (Info.EndBlock)
CGF.EmitBlock(Info.EndBlock);
-
+
CGF.EmitBlock(FinallyRethrow);
- CGF.Builder.CreateCall(ObjCTypes.getExceptionThrowFn(),
+ 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 =
+ ExceptionAsObject =
CGF.Builder.CreateBitCast(Exception, ObjCTypes.ObjectPtrTy, "tmp");
} else {
- assert((!CGF.ObjCEHValueStack.empty() && CGF.ObjCEHValueStack.back()) &&
+ 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();
@@ -2660,11 +2695,11 @@ void CGObjCMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
/// object: objc_read_weak (id *src)
///
llvm::Value * CGObjCMac::EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
- llvm::Value *AddrWeakObj)
-{
+ llvm::Value *AddrWeakObj) {
const llvm::Type* DestTy =
- cast<llvm::PointerType>(AddrWeakObj->getType())->getElementType();
- AddrWeakObj = CGF.Builder.CreateBitCast(AddrWeakObj, ObjCTypes.PtrObjectPtrTy);
+ 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);
@@ -2675,14 +2710,13 @@ llvm::Value * CGObjCMac::EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
/// objc_assign_weak (id src, id *dst)
///
void CGObjCMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dst)
-{
+ 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);
+ : CGF.Builder.CreateBitCast(src, ObjCTypes.LongLongTy);
src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
@@ -2696,14 +2730,13 @@ void CGObjCMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
/// objc_assign_global (id src, id *dst)
///
void CGObjCMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dst)
-{
+ 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);
+ : CGF.Builder.CreateBitCast(src, ObjCTypes.LongLongTy);
src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
@@ -2714,23 +2747,24 @@ void CGObjCMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
}
/// EmitObjCIvarAssign - Code gen for assigning to a __strong object.
-/// objc_assign_ivar (id src, id *dst)
+/// objc_assign_ivar (id src, id *dst, ptrdiff_t ivaroffset)
///
void CGObjCMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dst)
-{
+ llvm::Value *src, llvm::Value *dst,
+ llvm::Value *ivarOffset) {
+ assert(ivarOffset && "EmitObjCIvarAssign - ivarOffset is NULL");
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);
+ : 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");
+ CGF.Builder.CreateCall3(ObjCTypes.getGcAssignIvarFn(),
+ src, dst, ivarOffset);
return;
}
@@ -2738,14 +2772,13 @@ void CGObjCMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
/// objc_assign_strongCast (id src, id *dst)
///
void CGObjCMac::EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dst)
-{
+ 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);
+ : CGF.Builder.CreateBitCast(src, ObjCTypes.LongLongTy);
src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
@@ -2755,6 +2788,21 @@ void CGObjCMac::EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
return;
}
+void CGObjCMac::EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *DestPtr,
+ llvm::Value *SrcPtr,
+ QualType Ty) {
+ // Get size info for this aggregate.
+ std::pair<uint64_t, unsigned> TypeInfo = CGM.getContext().getTypeInfo(Ty);
+ unsigned long size = TypeInfo.first/8;
+ SrcPtr = CGF.Builder.CreateBitCast(SrcPtr, ObjCTypes.Int8PtrTy);
+ DestPtr = CGF.Builder.CreateBitCast(DestPtr, ObjCTypes.Int8PtrTy);
+ llvm::Value *N = llvm::ConstantInt::get(ObjCTypes.LongTy, size);
+ CGF.Builder.CreateCall3(ObjCTypes.GcMemmoveCollectableFn(),
+ DestPtr, SrcPtr, N);
+ return;
+}
+
/// EmitObjCValueForIvar - Code Gen for ivar reference.
///
LValue CGObjCMac::EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF,
@@ -2762,7 +2810,7 @@ LValue CGObjCMac::EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF,
llvm::Value *BaseValue,
const ObjCIvarDecl *Ivar,
unsigned CVRQualifiers) {
- const ObjCInterfaceDecl *ID = ObjectTy->getAsObjCInterfaceType()->getDecl();
+ const ObjCInterfaceDecl *ID = ObjectTy->getAs<ObjCInterfaceType>()->getDecl();
return EmitValueForIvarAtOffset(CGF, ID, BaseValue, Ivar, CVRQualifiers,
EmitIvarOffset(CGF, ID, Ivar));
}
@@ -2772,8 +2820,8 @@ llvm::Value *CGObjCMac::EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
const ObjCIvarDecl *Ivar) {
uint64_t Offset = ComputeIvarBaseOffset(CGM, Interface, Ivar);
return llvm::ConstantInt::get(
- CGM.getTypes().ConvertType(CGM.getContext().LongTy),
- Offset);
+ CGM.getTypes().ConvertType(CGM.getContext().LongTy),
+ Offset);
}
/* *** Private Interface *** */
@@ -2789,8 +2837,8 @@ llvm::Value *CGObjCMac::EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
enum ImageInfoFlags {
eImageInfo_FixAndContinue = (1 << 0), // FIXME: Not sure what
// this implies.
- eImageInfo_GarbageCollected = (1 << 1),
- eImageInfo_GCOnly = (1 << 2),
+ 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
@@ -2807,23 +2855,23 @@ void CGObjCMac::EmitImageInfo() {
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::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), version),
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), flags)
};
- llvm::ArrayType *AT = llvm::ArrayType::get(llvm::Type::Int32Ty, 2);
+ llvm::ArrayType *AT = llvm::ArrayType::get(llvm::Type::getInt32Ty(VMContext), 2);
const char *Section;
if (ObjCABI == 1)
Section = "__OBJC, __image_info,regular";
else
Section = "__DATA, __objc_imageinfo, regular, no_dead_strip";
- llvm::GlobalVariable *GV =
+ llvm::GlobalVariable *GV =
CreateMetadataVar("\01L_OBJC_IMAGE_INFO",
llvm::ConstantArray::get(AT, values, 2),
Section,
@@ -2845,14 +2893,14 @@ 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",
+ CreateMetadataVar("\01L_OBJC_MODULES",
llvm::ConstantStruct::get(ObjCTypes.ModuleTy, Values),
"__OBJC,__module_info,regular,no_dead_strip",
4, true);
@@ -2879,16 +2927,16 @@ llvm::Constant *CGObjCMac::EmitModuleSymbols() {
Symbols[i] = llvm::ConstantExpr::getBitCast(DefinedClasses[i],
ObjCTypes.Int8PtrTy);
for (unsigned i=0; i<NumCategories; i++)
- Symbols[NumClasses + i] =
+ Symbols[NumClasses + i] =
llvm::ConstantExpr::getBitCast(DefinedCategories[i],
ObjCTypes.Int8PtrTy);
- Values[4] =
+ Values[4] =
llvm::ConstantArray::get(llvm::ArrayType::get(ObjCTypes.Int8PtrTy,
NumClasses + NumCategories),
Symbols);
- llvm::Constant *Init = llvm::ConstantStruct::get(Values);
+ llvm::Constant *Init = llvm::ConstantStruct::get(VMContext, Values, false);
llvm::GlobalVariable *GV =
CreateMetadataVar("\01L_OBJC_SYMBOLS", Init,
@@ -2897,17 +2945,17 @@ llvm::Constant *CGObjCMac::EmitModuleSymbols() {
return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.SymtabPtrTy);
}
-llvm::Value *CGObjCMac::EmitClassRef(CGBuilderTy &Builder,
+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::Constant *Casted =
llvm::ConstantExpr::getBitCast(GetClassName(ID->getIdentifier()),
ObjCTypes.ClassPtrTy);
- Entry =
+ Entry =
CreateMetadataVar("\01L_OBJC_CLASS_REFERENCES_", Casted,
"__OBJC,__cls_refs,literal_pointers,no_dead_strip",
4, true);
@@ -2918,12 +2966,12 @@ llvm::Value *CGObjCMac::EmitClassRef(CGBuilderTy &Builder,
llvm::Value *CGObjCMac::EmitSelector(CGBuilderTy &Builder, Selector Sel) {
llvm::GlobalVariable *&Entry = SelectorReferences[Sel];
-
+
if (!Entry) {
- llvm::Constant *Casted =
+ llvm::Constant *Casted =
llvm::ConstantExpr::getBitCast(GetMethodVarName(Sel),
ObjCTypes.SelectorPtrTy);
- Entry =
+ Entry =
CreateMetadataVar("\01L_OBJC_SELECTOR_REFERENCES_", Casted,
"__OBJC,__message_refs,literal_pointers,no_dead_strip",
4, true);
@@ -2936,59 +2984,58 @@ llvm::Constant *CGObjCCommonMac::GetClassName(IdentifierInfo *Ident) {
llvm::GlobalVariable *&Entry = ClassNames[Ident];
if (!Entry)
- Entry = CreateMetadataVar("\01L_OBJC_CLASS_NAME_",
- llvm::ConstantArray::get(Ident->getName()),
+ Entry = CreateMetadataVar("\01L_OBJC_CLASS_NAME_",
+ llvm::ConstantArray::get(VMContext, Ident->getName()),
"__TEXT,__cstring,cstring_literals",
1, true);
- return getConstantGEP(Entry, 0, 0);
+ return getConstantGEP(VMContext, Entry, 0, 0);
}
/// GetIvarLayoutName - Returns a unique constant for the given
/// ivar layout bitmap.
llvm::Constant *CGObjCCommonMac::GetIvarLayoutName(IdentifierInfo *Ident,
- const ObjCCommonTypesHelper &ObjCTypes) {
+ const ObjCCommonTypesHelper &ObjCTypes) {
return llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy);
}
-static QualType::GCAttrTypes GetGCAttrTypeForType(ASTContext &Ctx,
- QualType FQT) {
+static Qualifiers::GC GetGCAttrTypeForType(ASTContext &Ctx, QualType FQT) {
if (FQT.isObjCGCStrong())
- return QualType::Strong;
+ return Qualifiers::Strong;
if (FQT.isObjCGCWeak())
- return QualType::Weak;
+ return Qualifiers::Weak;
- if (Ctx.isObjCObjectPointerType(FQT))
- return QualType::Strong;
+ if (FQT->isObjCObjectPointerType() || FQT->isBlockPointerType())
+ return Qualifiers::Strong;
- if (const PointerType *PT = FQT->getAsPointerType())
+ if (const PointerType *PT = FQT->getAs<PointerType>())
return GetGCAttrTypeForType(Ctx, PT->getPointeeType());
- return QualType::GCNone;
+ return Qualifiers::GCNone;
}
void CGObjCCommonMac::BuildAggrIvarRecordLayout(const RecordType *RT,
- unsigned int BytePos,
+ unsigned int BytePos,
bool ForStrongLayout,
bool &HasUnion) {
const RecordDecl *RD = RT->getDecl();
// FIXME - Use iterator.
llvm::SmallVector<FieldDecl*, 16> Fields(RD->field_begin(), RD->field_end());
const llvm::Type *Ty = CGM.getTypes().ConvertType(QualType(RT, 0));
- const llvm::StructLayout *RecLayout =
+ 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::StructLayout *Layout,
+ const RecordDecl *RD,
const llvm::SmallVectorImpl<FieldDecl*> &RecFields,
- unsigned int BytePos, bool ForStrongLayout,
- bool &HasUnion) {
+ unsigned int BytePos, bool ForStrongLayout,
+ bool &HasUnion) {
bool IsUnion = (RD && RD->isUnion());
uint64_t MaxUnionIvarSize = 0;
uint64_t MaxSkippedUnionIvarSize = 0;
@@ -2998,7 +3045,7 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
uint64_t MaxFieldOffset = 0;
uint64_t MaxSkippedFieldOffset = 0;
uint64_t LastBitfieldOffset = 0;
-
+
if (RecFields.empty())
return;
unsigned WordSizeInBits = CGM.getContext().Target.getPointerWidth(0);
@@ -3007,10 +3054,19 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
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
+ if (RD) {
+ if (Field->isBitField()) {
+ CodeGenTypes::BitFieldInfo Info = CGM.getTypes().getBitFieldInfo(Field);
+
+ const llvm::Type *Ty =
+ CGM.getTypes().ConvertTypeForMemRecursive(Field->getType());
+ uint64_t TypeSize =
+ CGM.getTypes().getTargetData().getTypeAllocSize(Ty);
+ FieldOffset = Info.FieldNo * TypeSize;
+ } else
+ FieldOffset =
+ Layout->getElementOffset(CGM.getTypes().getLLVMFieldNo(Field));
+ } else
FieldOffset = ComputeIvarBaseOffset(CGM, OI, cast<ObjCIvarDecl>(Field));
// Skip over unnamed or bitfields
@@ -3026,14 +3082,14 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
if (FQT->isUnionType())
HasUnion = true;
- BuildAggrIvarRecordLayout(FQT->getAsRecordType(),
+ BuildAggrIvarRecordLayout(FQT->getAs<RecordType>(),
BytePos + FieldOffset,
ForStrongLayout, HasUnion);
continue;
}
-
+
if (const ArrayType *Array = CGM.getContext().getAsArrayType(FQT)) {
- const ConstantArrayType *CArray =
+ 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");
@@ -3044,22 +3100,22 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
ElCount *= CArray->getSize().getZExtValue();
FQT = CArray->getElementType();
}
-
- assert(!FQT->isUnionType() &&
+
+ 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();
+
+ const RecordType *RT = FQT->getAs<RecordType>();
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++) {
+ 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,
@@ -3073,11 +3129,11 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
}
// 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);
+ Qualifiers::GC GCAttr = GetGCAttrTypeForType(CGM.getContext(), FQT);
unsigned FieldSize = CGM.getContext().getTypeSize(Field->getType());
- if ((ForStrongLayout && GCAttr == QualType::Strong)
- || (!ForStrongLayout && GCAttr == QualType::Weak)) {
+ if ((ForStrongLayout && GCAttr == Qualifiers::Strong)
+ || (!ForStrongLayout && GCAttr == Qualifiers::Weak)) {
if (IsUnion) {
uint64_t UnionIvarSize = FieldSize / WordSizeInBits;
if (UnionIvarSize > MaxUnionIvarSize) {
@@ -3089,9 +3145,9 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
IvarsInfo.push_back(GC_IVAR(BytePos + FieldOffset,
FieldSize / WordSizeInBits));
}
- } else if ((ForStrongLayout &&
- (GCAttr == QualType::GCNone || GCAttr == QualType::Weak))
- || (!ForStrongLayout && GCAttr != QualType::Weak)) {
+ } else if ((ForStrongLayout &&
+ (GCAttr == Qualifiers::GCNone || GCAttr == Qualifiers::Weak))
+ || (!ForStrongLayout && GCAttr != Qualifiers::Weak)) {
if (IsUnion) {
// FIXME: Why the asymmetry? We divide by word size in bits on other
// side.
@@ -3116,13 +3172,13 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
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);
+ skivar.ivar_size = (BitFieldSize / ByteSizeInBits)
+ + ((BitFieldSize % ByteSizeInBits) != 0);
+ SkipIvars.push_back(skivar);
}
-
+
if (MaxField)
- IvarsInfo.push_back(GC_IVAR(BytePos + MaxFieldOffset,
+ IvarsInfo.push_back(GC_IVAR(BytePos + MaxFieldOffset,
MaxUnionIvarSize));
if (MaxSkippedField)
SkipIvars.push_back(GC_IVAR(BytePos + MaxSkippedFieldOffset,
@@ -3131,60 +3187,60 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
/// 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
+/// 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
+/// 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) {
+ const ObjCImplementationDecl *OMD,
+ bool ForStrongLayout) {
bool hasUnion = false;
-
+
unsigned int WordsToScan, WordsToSkip;
- const llvm::Type *PtrTy = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+ const llvm::Type *PtrTy = llvm::Type::getInt8PtrTy(VMContext);
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();
+
+ 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 =
+ unsigned int WordSize =
CGM.getTypes().getTargetData().getTypeAllocSize(PtrTy);
if (IvarsInfo[0].ivar_bytepos == 0) {
WordsToSkip = 0;
@@ -3194,7 +3250,7 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout(
WordsToScan = IvarsInfo[0].ivar_size;
}
for (unsigned int i=1, Last=IvarsInfo.size(); i != Last; i++) {
- unsigned int TailPrevGCObjC =
+ unsigned int TailPrevGCObjC =
IvarsInfo[i-1].ivar_bytepos + IvarsInfo[i-1].ivar_size * WordSize;
if (IvarsInfo[i].ivar_bytepos == TailPrevGCObjC) {
// consecutive 'scanned' object pointers.
@@ -3209,7 +3265,7 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout(
SkScan.skip = WordsToSkip;
SkScan.scan = WordsToScan;
SkipScanIvars.push_back(SkScan);
-
+
// Skip the hole.
SkScan.skip = (IvarsInfo[i].ivar_bytepos - TailPrevGCObjC) / WordSize;
SkScan.scan = 0;
@@ -3224,16 +3280,16 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout(
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;
+ 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;
+ 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) {
@@ -3257,7 +3313,7 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout(
--SkipScan;
}
}
-
+
// Generate the string.
std::string BitMap;
for (int i = 0; i <= SkipScan; i++) {
@@ -3272,7 +3328,7 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout(
// 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;
@@ -3297,9 +3353,9 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout(
// null terminate string.
unsigned char zero = 0;
BitMap += zero;
-
+
if (CGM.getLangOptions().ObjCGCBitmapPrint) {
- printf("\n%s ivar layout for class '%s': ",
+ printf("\n%s ivar layout for class '%s': ",
ForStrongLayout ? "strong" : "weak",
OMD->getClassInterface()->getNameAsCString());
const unsigned char *s = (unsigned char*)BitMap.c_str();
@@ -3310,16 +3366,12 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout(
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::GlobalVariable * Entry =
+ CreateMetadataVar("\01L_OBJC_CLASS_NAME_",
+ llvm::ConstantArray::get(VMContext, BitMap.c_str()),
+ "__TEXT,__cstring,cstring_literals",
+ 1, true);
+ return getConstantGEP(VMContext, Entry, 0, 0);
}
llvm::Constant *CGObjCCommonMac::GetMethodVarName(Selector Sel) {
@@ -3327,12 +3379,12 @@ llvm::Constant *CGObjCCommonMac::GetMethodVarName(Selector Sel) {
// FIXME: Avoid std::string copying.
if (!Entry)
- Entry = CreateMetadataVar("\01L_OBJC_METH_VAR_NAME_",
- llvm::ConstantArray::get(Sel.getAsString()),
+ Entry = CreateMetadataVar("\01L_OBJC_METH_VAR_NAME_",
+ llvm::ConstantArray::get(VMContext, Sel.getAsString()),
"__TEXT,__cstring,cstring_literals",
1, true);
- return getConstantGEP(Entry, 0, 0);
+ return getConstantGEP(VMContext, Entry, 0, 0);
}
// FIXME: Merge into a single cstring creation function.
@@ -3353,11 +3405,11 @@ llvm::Constant *CGObjCCommonMac::GetMethodVarType(const FieldDecl *Field) {
if (!Entry)
Entry = CreateMetadataVar("\01L_OBJC_METH_VAR_TYPE_",
- llvm::ConstantArray::get(TypeStr),
+ llvm::ConstantArray::get(VMContext, TypeStr),
"__TEXT,__cstring,cstring_literals",
1, true);
-
- return getConstantGEP(Entry, 0, 0);
+
+ return getConstantGEP(VMContext, Entry, 0, 0);
}
llvm::Constant *CGObjCCommonMac::GetMethodVarType(const ObjCMethodDecl *D) {
@@ -3369,37 +3421,37 @@ llvm::Constant *CGObjCCommonMac::GetMethodVarType(const ObjCMethodDecl *D) {
if (!Entry)
Entry = CreateMetadataVar("\01L_OBJC_METH_VAR_TYPE_",
- llvm::ConstantArray::get(TypeStr),
+ llvm::ConstantArray::get(VMContext, TypeStr),
"__TEXT,__cstring,cstring_literals",
1, true);
- return getConstantGEP(Entry, 0, 0);
+ return getConstantGEP(VMContext, 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()),
+ Entry = CreateMetadataVar("\01L_OBJC_PROP_NAME_ATTR_",
+ llvm::ConstantArray::get(VMContext, Ident->getName()),
"__TEXT,__cstring,cstring_literals",
1, true);
- return getConstantGEP(Entry, 0, 0);
+ return getConstantGEP(VMContext, 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) {
+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,
+void CGObjCCommonMac::GetNameForMethod(const ObjCMethodDecl *D,
const ObjCContainerDecl *CD,
std::string &NameOut) {
NameOut = '\01';
@@ -3407,7 +3459,7 @@ void CGObjCCommonMac::GetNameForMethod(const ObjCMethodDecl *D,
NameOut += '[';
assert (CD && "Missing container decl in GetNameForMethod");
NameOut += CD->getNameAsString();
- if (const ObjCCategoryImplDecl *CID =
+ if (const ObjCCategoryImplDecl *CID =
dyn_cast<ObjCCategoryImplDecl>(D->getDeclContext())) {
NameOut += '(';
NameOut += CID->getNameAsString();
@@ -3418,64 +3470,55 @@ void CGObjCCommonMac::GetNameForMethod(const ObjCMethodDecl *D,
NameOut += ']';
}
-void CGObjCCommonMac::MergeMetadataGlobals(
- std::vector<llvm::Constant*> &UsedArray) {
- llvm::Type *i8PTy = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
- for (std::vector<llvm::GlobalVariable*>::iterator i = UsedGlobals.begin(),
- e = UsedGlobals.end(); i != e; ++i) {
- UsedArray.push_back(llvm::ConstantExpr::getBitCast(cast<llvm::Constant>(*i),
- i8PTy));
- }
-}
-
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())
+ 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[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,
+ I->second->setLinkage(llvm::GlobalValue::InternalLinkage);
+ I->second->setInitializer(llvm::ConstantStruct::get(ObjCTypes.ProtocolTy,
Values));
+ CGM.AddUsedGlobal(I->second);
}
// 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());
+ //
+ // FIXME: It would be nice if we had an LLVM construct for this.
+ if (!LazySymbols.empty() || !DefinedSymbols.empty()) {
+ llvm::SmallString<256> Asm;
+ Asm += CGM.getModule().getModuleInlineAsm();
+ if (!Asm.empty() && Asm.back() != '\n')
+ Asm += '\n';
+
+ llvm::raw_svector_ostream OS(Asm);
+ for (llvm::SetVector<IdentifierInfo*>::iterator I = LazySymbols.begin(),
+ e = LazySymbols.end(); I != e; ++I)
+ OS << "\t.lazy_reference .objc_class_name_" << (*I)->getName() << "\n";
+ for (llvm::SetVector<IdentifierInfo*>::iterator I = DefinedSymbols.begin(),
+ e = DefinedSymbols.end(); I != e; ++I)
+ OS << "\t.objc_class_name_" << (*I)->getName() << "=0\n"
+ << "\t.globl .objc_class_name_" << (*I)->getName() << "\n";
+
+ CGM.getModule().setModuleInlineAsm(OS.str());
+ }
}
-CGObjCNonFragileABIMac::CGObjCNonFragileABIMac(CodeGen::CodeGenModule &cgm)
+CGObjCNonFragileABIMac::CGObjCNonFragileABIMac(CodeGen::CodeGenModule &cgm)
: CGObjCCommonMac(cgm),
- ObjCTypes(cgm)
-{
+ ObjCTypes(cgm) {
ObjCEmptyCacheVar = ObjCEmptyVtableVar = NULL;
ObjCABI = 2;
}
@@ -3483,119 +3526,117 @@ CGObjCNonFragileABIMac::CGObjCNonFragileABIMac(CodeGen::CodeGenModule &cgm)
/* *** */
ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm)
-: CGM(cgm)
-{
+ : VMContext(cgm.getLLVMContext()), 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);
-
+ Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
+
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(FieldDecl::Create(Ctx, RD, SourceLocation(), 0,
- Ctx.getObjCIdType(), 0, false));
+ &Ctx.Idents.get("_objc_super"));
+ RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), 0,
+ Ctx.getObjCIdType(), 0, 0, false));
RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), 0,
- Ctx.getObjCClassType(), 0, false));
+ Ctx.getObjCClassType(), 0, 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);
-
+ SuperPtrTy = llvm::PointerType::getUnqual(SuperTy);
+
// struct _prop_t {
// char *name;
- // char *attributes;
+ // char *attributes;
// }
- PropertyTy = llvm::StructType::get(Int8PtrTy, Int8PtrTy, NULL);
- CGM.getModule().addTypeName("struct._prop_t",
+ PropertyTy = llvm::StructType::get(VMContext, 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,
+ PropertyListTy = llvm::StructType::get(VMContext, IntTy,
IntTy,
llvm::ArrayType::get(PropertyTy, 0),
NULL);
- CGM.getModule().addTypeName("struct._prop_list_t",
+ 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,
+ MethodTy = llvm::StructType::get(VMContext, SelectorPtrTy,
Int8PtrTy,
Int8PtrTy,
NULL);
CGM.getModule().addTypeName("struct._objc_method", MethodTy);
-
+
// struct _objc_cache *
- CacheTy = llvm::OpaqueType::get();
+ CacheTy = llvm::OpaqueType::get(VMContext);
CGM.getModule().addTypeName("struct._objc_cache", CacheTy);
CachePtrTy = llvm::PointerType::getUnqual(CacheTy);
}
-ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
- : ObjCCommonTypesHelper(cgm)
-{
+ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
+ : ObjCCommonTypesHelper(cgm) {
// struct _objc_method_description {
// SEL name;
// char *types;
// }
- MethodDescriptionTy =
- llvm::StructType::get(SelectorPtrTy,
+ MethodDescriptionTy =
+ llvm::StructType::get(VMContext, SelectorPtrTy,
Int8PtrTy,
NULL);
- CGM.getModule().addTypeName("struct._objc_method_description",
+ 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,
+ MethodDescriptionListTy =
+ llvm::StructType::get(VMContext, IntTy,
llvm::ArrayType::get(MethodDescriptionTy, 0),
NULL);
- CGM.getModule().addTypeName("struct._objc_method_description_list",
+ CGM.getModule().addTypeName("struct._objc_method_description_list",
MethodDescriptionListTy);
-
+
// struct _objc_method_description_list *
- MethodDescriptionListPtrTy =
+ MethodDescriptionListPtrTy =
llvm::PointerType::getUnqual(MethodDescriptionListTy);
// Protocol description structures
@@ -3606,25 +3647,26 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// struct _objc_method_description_list *optional_class_methods;
// struct _objc_property_list *instance_properties;
// }
- ProtocolExtensionTy =
- llvm::StructType::get(IntTy,
+ ProtocolExtensionTy =
+ llvm::StructType::get(VMContext, IntTy,
MethodDescriptionListPtrTy,
MethodDescriptionListPtrTy,
PropertyListPtrTy,
NULL);
- CGM.getModule().addTypeName("struct._objc_protocol_extension",
+ 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();
+ llvm::PATypeHolder ProtocolTyHolder = llvm::OpaqueType::get(VMContext);
+ llvm::PATypeHolder ProtocolListTyHolder = llvm::OpaqueType::get(VMContext);
- const llvm::Type *T =
- llvm::StructType::get(llvm::PointerType::getUnqual(ProtocolListTyHolder),
+ const llvm::Type *T =
+ llvm::StructType::get(VMContext,
+ llvm::PointerType::getUnqual(ProtocolListTyHolder),
LongTy,
llvm::ArrayType::get(ProtocolTyHolder, 0),
NULL);
@@ -3637,7 +3679,7 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// struct _objc_method_description_list *instance_methods;
// struct _objc_method_description_list *class_methods;
// }
- T = llvm::StructType::get(ProtocolExtensionPtrTy,
+ T = llvm::StructType::get(VMContext, ProtocolExtensionPtrTy,
Int8PtrTy,
llvm::PointerType::getUnqual(ProtocolListTyHolder),
MethodDescriptionListPtrTy,
@@ -3646,7 +3688,7 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
cast<llvm::OpaqueType>(ProtocolTyHolder.get())->refineAbstractTypeTo(T);
ProtocolListTy = cast<llvm::StructType>(ProtocolListTyHolder.get());
- CGM.getModule().addTypeName("struct._objc_protocol_list",
+ CGM.getModule().addTypeName("struct._objc_protocol_list",
ProtocolListTy);
// struct _objc_protocol_list *
ProtocolListPtrTy = llvm::PointerType::getUnqual(ProtocolListTy);
@@ -3662,32 +3704,32 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// char *ivar_type;
// int ivar_offset;
// }
- IvarTy = llvm::StructType::get(Int8PtrTy,
- Int8PtrTy,
- IntTy,
+ IvarTy = llvm::StructType::get(VMContext, Int8PtrTy,
+ Int8PtrTy,
+ IntTy,
NULL);
CGM.getModule().addTypeName("struct._objc_ivar", IvarTy);
// struct _objc_ivar_list *
- IvarListTy = llvm::OpaqueType::get();
+ IvarListTy = llvm::OpaqueType::get(VMContext);
CGM.getModule().addTypeName("struct._objc_ivar_list", IvarListTy);
IvarListPtrTy = llvm::PointerType::getUnqual(IvarListTy);
// struct _objc_method_list *
- MethodListTy = llvm::OpaqueType::get();
+ MethodListTy = llvm::OpaqueType::get(VMContext);
CGM.getModule().addTypeName("struct._objc_method_list", MethodListTy);
MethodListPtrTy = llvm::PointerType::getUnqual(MethodListTy);
// struct _objc_class_extension *
- ClassExtensionTy =
- llvm::StructType::get(IntTy,
+ ClassExtensionTy =
+ llvm::StructType::get(VMContext, IntTy,
Int8PtrTy,
PropertyListPtrTy,
NULL);
CGM.getModule().addTypeName("struct._objc_class_extension", ClassExtensionTy);
ClassExtensionPtrTy = llvm::PointerType::getUnqual(ClassExtensionTy);
- llvm::PATypeHolder ClassTyHolder = llvm::OpaqueType::get();
+ llvm::PATypeHolder ClassTyHolder = llvm::OpaqueType::get(VMContext);
// struct _objc_class {
// Class isa;
@@ -3703,7 +3745,8 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// char *ivar_layout;
// struct _objc_class_ext *ext;
// };
- T = llvm::StructType::get(llvm::PointerType::getUnqual(ClassTyHolder),
+ T = llvm::StructType::get(VMContext,
+ llvm::PointerType::getUnqual(ClassTyHolder),
llvm::PointerType::getUnqual(ClassTyHolder),
Int8PtrTy,
LongTy,
@@ -3717,7 +3760,7 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
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);
@@ -3730,7 +3773,7 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// uint32_t size; // sizeof(struct _objc_category)
// struct _objc_property_list *instance_properties;// category's @property
// }
- CategoryTy = llvm::StructType::get(Int8PtrTy,
+ CategoryTy = llvm::StructType::get(VMContext, Int8PtrTy,
Int8PtrTy,
MethodListPtrTy,
MethodListPtrTy,
@@ -3749,7 +3792,7 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// short cat_def_cnt;
// char *defs[cls_def_cnt + cat_def_cnt];
// }
- SymtabTy = llvm::StructType::get(LongTy,
+ SymtabTy = llvm::StructType::get(VMContext, LongTy,
SelectorPtrTy,
ShortTy,
ShortTy,
@@ -3764,41 +3807,40 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// char *name;
// struct _objc_symtab* symtab;
// }
- ModuleTy =
- llvm::StructType::get(LongTy,
+ ModuleTy =
+ llvm::StructType::get(VMContext, 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),
+ const llvm::Type *StackPtrTy = llvm::ArrayType::get(
+ llvm::Type::getInt8PtrTy(VMContext), 4);
+
+ ExceptionDataTy =
+ llvm::StructType::get(VMContext, llvm::ArrayType::get(llvm::Type::getInt32Ty(VMContext),
+ SetJmpBufferSize),
StackPtrTy, NULL);
- CGM.getModule().addTypeName("struct._objc_exception_data",
+ CGM.getModule().addTypeName("struct._objc_exception_data",
ExceptionDataTy);
}
-ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModule &cgm)
-: ObjCCommonTypesHelper(cgm)
-{
+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,
+ MethodListnfABITy = llvm::StructType::get(VMContext, IntTy,
IntTy,
llvm::ArrayType::get(MethodTy, 0),
NULL);
@@ -3806,7 +3848,7 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
MethodListnfABITy);
// struct method_list_t *
MethodListnfABIPtrTy = llvm::PointerType::getUnqual(MethodListnfABITy);
-
+
// struct _protocol_t {
// id isa; // NULL
// const char * const protocol_name;
@@ -3819,11 +3861,11 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// 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,
+ llvm::PATypeHolder ProtocolListTyHolder = llvm::OpaqueType::get(VMContext);
+
+ ProtocolnfABITy = llvm::StructType::get(VMContext, ObjectPtrTy,
Int8PtrTy,
llvm::PointerType::getUnqual(
ProtocolListTyHolder),
@@ -3840,23 +3882,23 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// 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,
+ ProtocolListnfABITy = llvm::StructType::get(VMContext, LongTy,
llvm::ArrayType::get(
ProtocolnfABIPtrTy, 0),
NULL);
CGM.getModule().addTypeName("struct._objc_protocol_list",
ProtocolListnfABITy);
cast<llvm::OpaqueType>(ProtocolListTyHolder.get())->refineAbstractTypeTo(
- ProtocolListnfABITy);
-
+ ProtocolListnfABITy);
+
// struct _objc_protocol_list*
ProtocolListnfABIPtrTy = llvm::PointerType::getUnqual(ProtocolListnfABITy);
-
+
// struct _ivar_t {
// unsigned long int *offset; // pointer to ivar offset location
// char *name;
@@ -3864,28 +3906,29 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// uint32_t alignment;
// uint32_t size;
// }
- IvarnfABITy = llvm::StructType::get(llvm::PointerType::getUnqual(LongTy),
+ IvarnfABITy = llvm::StructType::get(VMContext,
+ 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,
+ IvarListnfABITy = llvm::StructType::get(VMContext, IntTy,
IntTy,
llvm::ArrayType::get(
- IvarnfABITy, 0),
+ 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;
@@ -3899,9 +3942,9 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// 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,
+ ClassRonfABITy = llvm::StructType::get(VMContext, IntTy,
IntTy,
IntTy,
Int8PtrTy,
@@ -3914,14 +3957,14 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
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));
-
+ llvm::FunctionType::get(ObjectPtrTy, Params, false));
+
// struct _class_t {
// struct _class_t *isa;
// struct _class_t * const superclass;
@@ -3929,23 +3972,24 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// 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);
+
+ llvm::PATypeHolder ClassTyHolder = llvm::OpaqueType::get(VMContext);
+ ClassnfABITy =
+ llvm::StructType::get(VMContext,
+ 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);
-
+ ClassnfABITy);
+
// LLVM for struct _class_t *
ClassnfABIPtrTy = llvm::PointerType::getUnqual(ClassnfABITy);
-
+
// struct _category_t {
// const char * const name;
// struct _class_t *const cls;
@@ -3954,7 +3998,7 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// const struct _protocol_list_t * const protocols;
// const struct _prop_list_t * const properties;
// }
- CategorynfABITy = llvm::StructType::get(Int8PtrTy,
+ CategorynfABITy = llvm::StructType::get(VMContext, Int8PtrTy,
ClassnfABIPtrTy,
MethodListnfABIPtrTy,
MethodListnfABIPtrTy,
@@ -3962,54 +4006,55 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
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(FieldDecl::Create(Ctx, RD, SourceLocation(), 0,
- Ctx.VoidPtrTy, 0, false));
+ Ctx.VoidPtrTy, 0, 0, false));
RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), 0,
- Ctx.getObjCSelType(), 0, false));
+ Ctx.getObjCSelType(), 0, 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,
+ SuperMessageRefTy = llvm::StructType::get(VMContext, 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);
-
+ 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),
+ EHTypeTy = llvm::StructType::get(VMContext,
+ llvm::PointerType::getUnqual(Int8PtrTy),
Int8PtrTy,
ClassnfABIPtrTy,
NULL);
@@ -4017,63 +4062,62 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
EHTypePtrTy = llvm::PointerType::getUnqual(EHTypeTy);
}
-llvm::Function *CGObjCNonFragileABIMac::ModuleInitFunction() {
+llvm::Function *CGObjCNonFragileABIMac::ModuleInitFunction() {
FinishNonFragileABIModule();
-
+
return NULL;
}
-void CGObjCNonFragileABIMac::AddModuleClassList(const
- std::vector<llvm::GlobalValue*>
- &Container,
+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::Constant* Init =
llvm::ConstantArray::get(llvm::ArrayType::get(ObjCTypes.Int8PtrTy,
NumClasses),
Symbols);
-
+
llvm::GlobalVariable *GV =
- new llvm::GlobalVariable(Init->getType(), false,
+ new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false,
llvm::GlobalValue::InternalLinkage,
Init,
- SymbolName,
- &CGM.getModule());
+ SymbolName);
GV->setAlignment(8);
GV->setSection(SectionName);
- UsedGlobals.push_back(GV);
+ CGM.AddUsedGlobal(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,
+ AddModuleClassList(DefinedClasses,
"\01L_OBJC_LABEL_CLASS_$",
"__DATA, __objc_classlist, regular, no_dead_strip");
- AddModuleClassList(DefinedNonLazyClasses,
+ 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,
+ AddModuleClassList(DefinedCategories,
"\01L_OBJC_LABEL_CATEGORY_$",
"__DATA, __objc_catlist, regular, no_dead_strip");
- AddModuleClassList(DefinedNonLazyCategories,
+ 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);
@@ -4086,22 +4130,21 @@ void CGObjCNonFragileABIMac::FinishNonFragileABIModule() {
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::ArrayType::get(ObjCTypes.IntTy, 2),
+ Values);
llvm::GlobalVariable *IMGV =
- new llvm::GlobalVariable(Init->getType(), false,
+ new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false,
llvm::GlobalValue::InternalLinkage,
Init,
- "\01L_OBJC_IMAGE_INFO",
- &CGM.getModule());
+ "\01L_OBJC_IMAGE_INFO");
IMGV->setSection("__DATA, __objc_imageinfo, regular, no_dead_strip");
IMGV->setConstant(true);
- UsedGlobals.push_back(IMGV);
+ CGM.AddUsedGlobal(IMGV);
}
/// 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
+/// except for the 19 selectors in the list, we generate 32bit-style
/// message dispatch call for all the rest.
///
bool CGObjCNonFragileABIMac::LegacyDispatchedSelector(Selector Sel) {
@@ -4116,7 +4159,7 @@ bool CGObjCNonFragileABIMac::LegacyDispatchedSelector(Selector Sel) {
NonLegacyDispatchMethods.insert(GetNullarySelector("release"));
NonLegacyDispatchMethods.insert(GetNullarySelector("autorelease"));
NonLegacyDispatchMethods.insert(GetNullarySelector("hash"));
-
+
NonLegacyDispatchMethods.insert(GetUnarySelector("allocWithZone"));
NonLegacyDispatchMethods.insert(GetUnarySelector("isKindOfClass"));
NonLegacyDispatchMethods.insert(GetUnarySelector("respondsToSelector"));
@@ -4125,11 +4168,11 @@ bool CGObjCNonFragileABIMac::LegacyDispatchedSelector(Selector Sel) {
NonLegacyDispatchMethods.insert(GetUnarySelector("isEqualToString"));
NonLegacyDispatchMethods.insert(GetUnarySelector("isEqual"));
NonLegacyDispatchMethods.insert(GetUnarySelector("addObject"));
- // "countByEnumeratingWithState:objects:count"
+ // "countByEnumeratingWithState:objects:count"
IdentifierInfo *KeyIdents[] = {
- &CGM.getContext().Idents.get("countByEnumeratingWithState"),
- &CGM.getContext().Idents.get("objects"),
- &CGM.getContext().Idents.get("count")
+ &CGM.getContext().Idents.get("countByEnumeratingWithState"),
+ &CGM.getContext().Idents.get("objects"),
+ &CGM.getContext().Idents.get("count")
};
NonLegacyDispatchMethods.insert(
CGM.getContext().Selectors.getSelector(3, KeyIdents));
@@ -4161,43 +4204,43 @@ enum MetaDataDlags {
/// }
///
llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer(
- unsigned flags,
- unsigned InstanceStart,
- unsigned InstanceSize,
- const ObjCImplementationDecl *ID) {
+ 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[ 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
+ for (ObjCImplementationDecl::classmeth_iterator
i = ID->classmeth_begin(), e = ID->classmeth_end(); i != e; ++i) {
// Class methods should always be defined.
Methods.push_back(GetMethodConstant(*i));
}
} else {
MethodListName += "INSTANCE_METHODS_" + ID->getNameAsString();
- for (ObjCImplementationDecl::instmeth_iterator
+ for (ObjCImplementationDecl::instmeth_iterator
i = ID->instmeth_begin(), e = ID->instmeth_end(); i != e; ++i) {
// Instance methods should always be defined.
Methods.push_back(GetMethodConstant(*i));
}
- for (ObjCImplementationDecl::propimpl_iterator
+ for (ObjCImplementationDecl::propimpl_iterator
i = ID->propimpl_begin(), e = ID->propimpl_end(); 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);
@@ -4207,39 +4250,37 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer(
}
}
}
- Values[ 5] = EmitMethodList(MethodListName,
- "__DATA, __objc_const", Methods);
-
+ Values[ 5] = EmitMethodList(MethodListName,
+ "__DATA, __objc_const", Methods);
+
const ObjCInterfaceDecl *OID = ID->getClassInterface();
assert(OID && "CGObjCNonFragileABIMac::BuildClassRoTInitializer");
- Values[ 6] = EmitProtocolList("\01l_OBJC_CLASS_PROTOCOLS_$_"
+ 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);
+ 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(),
+ 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());
+ new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassRonfABITy, false,
+ llvm::GlobalValue::InternalLinkage,
+ Init,
+ (flags & CLS_META) ?
+ std::string("\01l_OBJC_METACLASS_RO_$_")+ClassName :
+ std::string("\01l_OBJC_CLASS_RO_$_")+ClassName);
CLASS_RO_GV->setAlignment(
CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.ClassRonfABITy));
CLASS_RO_GV->setSection("__DATA, __objc_const");
@@ -4258,20 +4299,20 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer(
/// }
///
llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassMetaData(
- std::string &ClassName,
- llvm::Constant *IsAGV,
- llvm::Constant *SuperClassGV,
- llvm::Constant *ClassRoGV,
- bool HiddenVisibility) {
+ 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[1] = SuperClassGV;
+ if (!Values[1])
+ Values[1] = 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,
+ llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassnfABITy,
Values);
llvm::GlobalVariable *GV = GetClassGlobal(ClassName);
GV->setInitializer(Init);
@@ -4283,7 +4324,7 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassMetaData(
return GV;
}
-bool
+bool
CGObjCNonFragileABIMac::ImplementationIsNonLazy(const ObjCImplDecl *OD) const {
return OD->getClassMethod(GetNullarySelector("load")) != 0;
}
@@ -4291,11 +4332,11 @@ CGObjCNonFragileABIMac::ImplementationIsNonLazy(const ObjCImplDecl *OD) const {
void CGObjCNonFragileABIMac::GetClassSizeInfo(const ObjCImplementationDecl *OID,
uint32_t &InstanceStart,
uint32_t &InstanceSize) {
- const ASTRecordLayout &RL =
+ const ASTRecordLayout &RL =
CGM.getContext().getASTObjCImplementationLayout(OID);
-
+
// InstanceSize is really instance end.
- InstanceSize = llvm::RoundUpToAlignment(RL.getNextOffset(), 8) / 8;
+ InstanceSize = llvm::RoundUpToAlignment(RL.getDataSize(), 8) / 8;
// If there are no fields, the start is the same as the end.
if (!RL.getFieldCount())
@@ -4308,34 +4349,34 @@ 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());
-
+ CGM.getModule(),
+ ObjCTypes.CacheTy,
+ false,
+ llvm::GlobalValue::ExternalLinkage,
+ 0,
+ "_objc_empty_cache");
+
ObjCEmptyVtableVar = new llvm::GlobalVariable(
- ObjCTypes.ImpnfABITy,
- false,
- llvm::GlobalValue::ExternalLinkage,
- 0,
- "_objc_empty_vtable",
- &CGM.getModule());
- }
- assert(ID->getClassInterface() &&
+ CGM.getModule(),
+ ObjCTypes.ImpnfABITy,
+ false,
+ llvm::GlobalValue::ExternalLinkage,
+ 0,
+ "_objc_empty_vtable");
+ }
+ assert(ID->getClassInterface() &&
"CGObjCNonFragileABIMac::GenerateClass - class is 0");
// FIXME: Is this correct (that meta class size is never computed)?
- uint32_t InstanceStart =
+ 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 =
+
+ bool classIsHidden =
CGM.getDeclVisibilityMode(ID->getClassInterface()) == LangOptions::Hidden;
if (classIsHidden)
flags |= OBJC2_CLS_HIDDEN;
@@ -4351,7 +4392,7 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
Root = Super;
IsAGV = GetClassGlobal(ObjCMetaClassName + Root->getNameAsString());
// work on super class metadata symbol.
- std::string SuperClassName =
+ std::string SuperClassName =
ObjCMetaClassName + ID->getClassInterface()->getSuperClass()->getNameAsString();
SuperClassGV = GetClassGlobal(SuperClassName);
}
@@ -4359,7 +4400,7 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
InstanceStart,
InstanceSize,ID);
std::string TClassName = ObjCMetaClassName + ClassName;
- llvm::GlobalVariable *MetaTClass =
+ llvm::GlobalVariable *MetaTClass =
BuildClassMetaData(TClassName, IsAGV, SuperClassGV, CLASS_RO_GV,
classIsHidden);
@@ -4383,11 +4424,11 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
GetClassSizeInfo(ID, InstanceStart, InstanceSize);
CLASS_RO_GV = BuildClassRoTInitializer(flags,
InstanceStart,
- InstanceSize,
+ InstanceSize,
ID);
-
+
TClassName = ObjCClassName + ClassName;
- llvm::GlobalVariable *ClassMD =
+ llvm::GlobalVariable *ClassMD =
BuildClassMetaData(TClassName, MetaTClass, SuperClassGV, CLASS_RO_GV,
classIsHidden);
DefinedClasses.push_back(ClassMD);
@@ -4410,29 +4451,30 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
/// which will hold address of the protocol meta-data.
///
llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CGBuilderTy &Builder,
- const ObjCProtocolDecl *PD) {
-
+ 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);
-
+ 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());
+ CGM.getModule(),
+ Init->getType(), false,
+ llvm::GlobalValue::WeakAnyLinkage,
+ Init,
+ ProtocolName);
PTGV->setSection("__DATA, __objc_protorefs, coalesced, no_dead_strip");
PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
- UsedGlobals.push_back(PTGV);
+ CGM.AddUsedGlobal(PTGV);
return Builder.CreateLoad(PTGV, false, "tmp");
}
@@ -4449,11 +4491,11 @@ llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CGBuilderTy &Builder,
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() +
+ 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
@@ -4461,33 +4503,33 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
Values[1] = ClassGV;
std::vector<llvm::Constant*> Methods;
std::string MethodListName(Prefix);
- MethodListName += "INSTANCE_METHODS_" + Interface->getNameAsString() +
+ MethodListName += "INSTANCE_METHODS_" + Interface->getNameAsString() +
"_$_" + OCD->getNameAsString();
-
- for (ObjCCategoryImplDecl::instmeth_iterator
+
+ for (ObjCCategoryImplDecl::instmeth_iterator
i = OCD->instmeth_begin(), e = OCD->instmeth_end(); i != e; ++i) {
// Instance methods should always be defined.
Methods.push_back(GetMethodConstant(*i));
}
-
- Values[2] = EmitMethodList(MethodListName,
- "__DATA, __objc_const",
+
+ Values[2] = EmitMethodList(MethodListName,
+ "__DATA, __objc_const",
Methods);
MethodListName = Prefix;
MethodListName += "CLASS_METHODS_" + Interface->getNameAsString() + "_$_" +
OCD->getNameAsString();
Methods.clear();
- for (ObjCCategoryImplDecl::classmeth_iterator
+ for (ObjCCategoryImplDecl::classmeth_iterator
i = OCD->classmeth_begin(), e = OCD->classmeth_end(); i != e; ++i) {
// Class methods should always be defined.
Methods.push_back(GetMethodConstant(*i));
}
-
- Values[3] = EmitMethodList(MethodListName,
- "__DATA, __objc_const",
+
+ Values[3] = EmitMethodList(MethodListName,
+ "__DATA, __objc_const",
Methods);
- const ObjCCategoryDecl *Category =
+ const ObjCCategoryDecl *Category =
Interface->FindCategoryDeclaration(OCD->getIdentifier());
if (Category) {
std::string ExtName(Interface->getNameAsString() + "_$_" +
@@ -4500,26 +4542,24 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
Values[5] =
EmitPropertyList(std::string("\01l_OBJC_$_PROP_LIST_") + ExtName,
OCD, Category, ObjCTypes);
- }
- else {
+ } else {
Values[4] = llvm::Constant::getNullValue(ObjCTypes.ProtocolListnfABIPtrTy);
Values[5] = llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy);
}
-
- llvm::Constant *Init =
- llvm::ConstantStruct::get(ObjCTypes.CategorynfABITy,
+
+ llvm::Constant *Init =
+ llvm::ConstantStruct::get(ObjCTypes.CategorynfABITy,
Values);
llvm::GlobalVariable *GCATV
- = new llvm::GlobalVariable(ObjCTypes.CategorynfABITy,
+ = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.CategorynfABITy,
false,
llvm::GlobalValue::InternalLinkage,
Init,
- ExtCatName,
- &CGM.getModule());
+ ExtCatName);
GCATV->setAlignment(
CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.CategorynfABITy));
GCATV->setSection("__DATA, __objc_const");
- UsedGlobals.push_back(GCATV);
+ CGM.AddUsedGlobal(GCATV);
DefinedCategories.push_back(GCATV);
// Determine if this category is also "non-lazy".
@@ -4531,16 +4571,16 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
/// 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) {
+ 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[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);
@@ -4554,13 +4594,13 @@ llvm::Constant *CGObjCNonFragileABIMac::GetMethodConstant(
/// }
///
llvm::Constant *CGObjCNonFragileABIMac::EmitMethodList(
- const std::string &Name,
- const char *Section,
- const ConstantVector &Methods) {
+ 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);
@@ -4570,18 +4610,17 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitMethodList(
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::Constant *Init = llvm::ConstantStruct::get(VMContext, Values, false);
+
llvm::GlobalVariable *GV =
- new llvm::GlobalVariable(Init->getType(), false,
+ new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false,
llvm::GlobalValue::InternalLinkage,
Init,
- Name,
- &CGM.getModule());
+ Name);
GV->setAlignment(
CGM.getTargetData().getPrefTypeAlignment(Init->getType()));
GV->setSection(Section);
- UsedGlobals.push_back(GV);
+ CGM.AddUsedGlobal(GV);
return llvm::ConstantExpr::getBitCast(GV,
ObjCTypes.MethodListnfABIPtrTy);
}
@@ -4589,34 +4628,33 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitMethodList(
/// ObjCIvarOffsetVariable - Returns the ivar offset variable for
/// the given ivar.
llvm::GlobalVariable * CGObjCNonFragileABIMac::ObjCIvarOffsetVariable(
- const ObjCInterfaceDecl *ID,
- const ObjCIvarDecl *Ivar) {
+ const ObjCInterfaceDecl *ID,
+ const ObjCIvarDecl *Ivar) {
// FIXME: We shouldn't need to do this lookup.
unsigned Index;
- const ObjCInterfaceDecl *Container =
+ 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 =
+ llvm::GlobalVariable *IvarOffsetGV =
CGM.getModule().getGlobalVariable(Name);
if (!IvarOffsetGV)
- IvarOffsetGV =
- new llvm::GlobalVariable(ObjCTypes.LongTy,
+ IvarOffsetGV =
+ new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.LongTy,
false,
llvm::GlobalValue::ExternalLinkage,
0,
- Name,
- &CGM.getModule());
+ Name);
return IvarOffsetGV;
}
llvm::Constant * CGObjCNonFragileABIMac::EmitIvarOffsetVar(
- const ObjCInterfaceDecl *ID,
- const ObjCIvarDecl *Ivar,
- unsigned long int Offset) {
+ const ObjCInterfaceDecl *ID,
+ const ObjCIvarDecl *Ivar,
+ unsigned long int Offset) {
llvm::GlobalVariable *IvarOffsetGV = ObjCIvarOffsetVariable(ID, Ivar);
- IvarOffsetGV->setInitializer(llvm::ConstantInt::get(ObjCTypes.LongTy,
+ IvarOffsetGV->setInitializer(llvm::ConstantInt::get(ObjCTypes.LongTy,
Offset));
IvarOffsetGV->setAlignment(
CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.LongTy));
@@ -4651,25 +4689,25 @@ llvm::Constant * CGObjCNonFragileABIMac::EmitIvarOffsetVar(
///
llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList(
- const ObjCImplementationDecl *ID) {
-
+ 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;
CGM.getContext().ShallowCollectObjCIvars(OID, OIvars);
-
+
for (unsigned i = 0, e = OIvars.size(); i != e; ++i) {
ObjCIvarDecl *IVD = OIvars[i];
// Ignore unnamed bit-fields.
if (!IVD->getDeclName())
continue;
- Ivar[0] = EmitIvarOffsetVar(ID->getClassInterface(), IVD,
+ Ivar[0] = EmitIvarOffsetVar(ID->getClassInterface(), IVD,
ComputeIvarBaseOffset(CGM, ID, IVD));
Ivar[1] = GetMethodVarName(IVD->getIdentifier());
Ivar[2] = GetMethodVarType(IVD);
@@ -4677,7 +4715,7 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList(
CGM.getTypes().ConvertTypeForMem(IVD->getType());
unsigned Size = CGM.getTargetData().getTypeAllocSize(FieldTy);
unsigned Align = CGM.getContext().getPreferredTypeAlign(
- IVD->getType().getTypePtr()) >> 3;
+ 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
@@ -4698,41 +4736,37 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList(
llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.IvarnfABITy,
Ivars.size());
Values[2] = llvm::ConstantArray::get(AT, Ivars);
- llvm::Constant *Init = llvm::ConstantStruct::get(Values);
+ llvm::Constant *Init = llvm::ConstantStruct::get(VMContext, Values, false);
const char *Prefix = "\01l_OBJC_$_INSTANCE_VARIABLES_";
llvm::GlobalVariable *GV =
- new llvm::GlobalVariable(Init->getType(), false,
+ new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false,
llvm::GlobalValue::InternalLinkage,
Init,
- Prefix + OID->getNameAsString(),
- &CGM.getModule());
+ Prefix + OID->getNameAsString());
GV->setAlignment(
CGM.getTargetData().getPrefTypeAlignment(Init->getType()));
GV->setSection("__DATA, __objc_const");
-
- UsedGlobals.push_back(GV);
- return llvm::ConstantExpr::getBitCast(GV,
- ObjCTypes.IvarListnfABIPtrTy);
+
+ CGM.AddUsedGlobal(GV);
+ return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.IvarListnfABIPtrTy);
}
llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocolRef(
- const ObjCProtocolDecl *PD) {
+ 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 =
+ new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolnfABITy, false,
+ llvm::GlobalValue::ExternalLinkage,
+ 0,
+ "\01l_OBJC_PROTOCOL_$_" + PD->getNameAsString());
Entry->setSection("__DATA,__datacoal_nt,coalesced");
- UsedGlobals.push_back(Entry);
}
-
+
return Entry;
}
@@ -4754,19 +4788,19 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocolRef(
///
llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
- const ObjCProtocolDecl *PD) {
+ 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
+ for (ObjCProtocolDecl::instmeth_iterator
i = PD->instmeth_begin(), e = PD->instmeth_end(); i != e; ++i) {
ObjCMethodDecl *MD = *i;
llvm::Constant *C = GetMethodDescriptionConstant(MD);
@@ -4774,10 +4808,10 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
OptInstanceMethods.push_back(C);
} else {
InstanceMethods.push_back(C);
- }
+ }
}
-
- for (ObjCProtocolDecl::classmeth_iterator
+
+ for (ObjCProtocolDecl::classmeth_iterator
i = PD->classmeth_begin(), e = PD->classmeth_end(); i != e; ++i) {
ObjCMethodDecl *MD = *i;
llvm::Constant *C = GetMethodDescriptionConstant(MD);
@@ -4785,23 +4819,23 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
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());
-
+ "\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_"
+ Values[4] = EmitMethodList("\01l_OBJC_$_PROTOCOL_CLASS_METHODS_"
+ PD->getNameAsString(),
"__DATA, __objc_const",
ClassMethods);
@@ -4809,50 +4843,50 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
+ PD->getNameAsString(),
"__DATA, __objc_const",
OptInstanceMethods);
- Values[6] = EmitMethodList("\01l_OBJC_$_PROTOCOL_CLASS_METHODS_OPT_"
+ 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 =
+ 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 =
+ new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolnfABITy, false,
+ llvm::GlobalValue::WeakAnyLinkage,
+ Init,
+ std::string("\01l_OBJC_PROTOCOL_$_")+ProtocolName);
Entry->setAlignment(
CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.ProtocolnfABITy));
Entry->setSection("__DATA,__datacoal_nt,coalesced");
}
Entry->setVisibility(llvm::GlobalValue::HiddenVisibility);
-
+ CGM.AddUsedGlobal(Entry);
+
// 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());
+ CGM.getModule(),
+ ObjCTypes.ProtocolnfABIPtrTy, false,
+ llvm::GlobalValue::WeakAnyLinkage,
+ Entry,
+ std::string("\01l_OBJC_LABEL_PROTOCOL_$_")
+ +ProtocolName);
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);
+ CGM.AddUsedGlobal(PTGV);
return Entry;
}
@@ -4866,45 +4900,46 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
///
llvm::Constant *
CGObjCNonFragileABIMac::EmitProtocolList(const std::string &Name,
- ObjCProtocolDecl::protocol_iterator begin,
- ObjCProtocolDecl::protocol_iterator end) {
+ ObjCProtocolDecl::protocol_iterator begin,
+ ObjCProtocolDecl::protocol_iterator end) {
std::vector<llvm::Constant*> ProtocolRefs;
-
+
// Just return null for empty protocol lists
- if (begin == end)
+ 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,
+ 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));
-
+ 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,
+ 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(VMContext, Values, false);
+ GV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false,
llvm::GlobalValue::InternalLinkage,
Init,
- Name,
- &CGM.getModule());
+ Name);
GV->setSection("__DATA, __objc_const");
GV->setAlignment(
CGM.getTargetData().getPrefTypeAlignment(Init->getType()));
- UsedGlobals.push_back(GV);
- return llvm::ConstantExpr::getBitCast(GV,
+ CGM.AddUsedGlobal(GV);
+ return llvm::ConstantExpr::getBitCast(GV,
ObjCTypes.ProtocolListnfABIPtrTy);
}
@@ -4918,8 +4953,9 @@ CGObjCNonFragileABIMac::EmitProtocolList(const std::string &Name,
llvm::Constant *
CGObjCNonFragileABIMac::GetMethodDescriptionConstant(const ObjCMethodDecl *MD) {
std::vector<llvm::Constant*> Desc(3);
- Desc[0] = llvm::ConstantExpr::getBitCast(GetMethodVarName(MD->getSelector()),
- ObjCTypes.SelectorPtrTy);
+ 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);
@@ -4931,46 +4967,46 @@ CGObjCNonFragileABIMac::GetMethodDescriptionConstant(const ObjCMethodDecl *MD) {
/// @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();
+ CodeGen::CodeGenFunction &CGF,
+ QualType ObjectTy,
+ llvm::Value *BaseValue,
+ const ObjCIvarDecl *Ivar,
+ unsigned CVRQualifiers) {
+ const ObjCInterfaceDecl *ID = ObjectTy->getAs<ObjCInterfaceType>()->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),
+ 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) {
+ 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>());
+ const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType,
+ llvm::SmallVector<QualType, 16>());
llvm::Constant *Fn = 0;
std::string Name("\01l_");
if (CGM.ReturnTypeUsesSret(FnInfo)) {
@@ -4981,53 +5017,44 @@ CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend(
// FIXME. Is there a better way of getting these names.
// They are available in RuntimeFunctions vector pair.
Name += "objc_msgSendId_stret_fixup";
- }
- else
+ } else
#endif
- if (IsSuper) {
+ if (IsSuper) {
Fn = ObjCTypes.getMessageSendSuper2StretFixupFn();
Name += "objc_msgSendSuper2_stret_fixup";
- }
- else
- {
- Fn = ObjCTypes.getMessageSendStretFixupFn();
- Name += "objc_msgSend_stret_fixup";
- }
- }
- else if (!IsSuper && ResultType->isFloatingType()) {
+ } else {
+ Fn = ObjCTypes.getMessageSendStretFixupFn();
+ Name += "objc_msgSend_stret_fixup";
+ }
+ } else if (!IsSuper && ResultType->isFloatingType()) {
if (ResultType->isSpecificBuiltinType(BuiltinType::LongDouble)) {
Fn = ObjCTypes.getMessageSendFpretFixupFn();
Name += "objc_msgSend_fpret_fixup";
- }
- else {
+ } else {
Fn = ObjCTypes.getMessageSendFixupFn();
Name += "objc_msgSend_fixup";
}
- }
- else {
+ } 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
+ } else
#endif
- if (IsSuper) {
+ if (IsSuper) {
Fn = ObjCTypes.getMessageSendSuper2FixupFn();
Name += "objc_msgSendSuper2_fixup";
- }
- else
- {
- Fn = ObjCTypes.getMessageSendFixupFn();
- Name += "objc_msgSend_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++)
+ for (unsigned i = 0; i < SelName.size(); i++)
if (SelName[i] == ':')
SelName[i] = '_';
Name += SelName;
@@ -5037,21 +5064,20 @@ CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend(
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::Constant *Init = llvm::ConstantStruct::get(VMContext, Values, false);
+ GV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false,
llvm::GlobalValue::WeakAnyLinkage,
Init,
- Name,
- &CGM.getModule());
+ Name);
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),
+ 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);
@@ -5064,21 +5090,21 @@ CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend(
}
/// 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) {
+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);
+ ? EmitLegacyMessageSend(CGF, ResultType, EmitSelector(CGF.Builder, Sel),
+ Receiver, CGF.getContext().getObjCIdType(),
+ false, CallArgs, Method, ObjCTypes)
+ : EmitMessageSend(CGF, ResultType, Sel,
+ Receiver, CGF.getContext().getObjCIdType(),
+ false, CallArgs);
}
llvm::GlobalVariable *
@@ -5086,85 +5112,82 @@ 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());
+ GV = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABITy,
+ false, llvm::GlobalValue::ExternalLinkage,
+ 0, Name);
}
return GV;
}
-llvm::Value *CGObjCNonFragileABIMac::EmitClassRef(CGBuilderTy &Builder,
- const ObjCInterfaceDecl *ID) {
+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 =
+ new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABIPtrTy,
+ false, llvm::GlobalValue::InternalLinkage,
+ ClassGV,
+ "\01L_OBJC_CLASSLIST_REFERENCES_$_");
Entry->setAlignment(
- CGM.getTargetData().getPrefTypeAlignment(
- ObjCTypes.ClassnfABIPtrTy));
+ CGM.getTargetData().getPrefTypeAlignment(
+ ObjCTypes.ClassnfABIPtrTy));
Entry->setSection("__DATA, __objc_classrefs, regular, no_dead_strip");
- UsedGlobals.push_back(Entry);
+ CGM.AddUsedGlobal(Entry);
}
-
+
return Builder.CreateLoad(Entry, false, "tmp");
}
llvm::Value *
-CGObjCNonFragileABIMac::EmitSuperClassRef(CGBuilderTy &Builder,
+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 =
+ new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABIPtrTy,
+ false, llvm::GlobalValue::InternalLinkage,
+ ClassGV,
+ "\01L_OBJC_CLASSLIST_SUP_REFS_$_");
Entry->setAlignment(
- CGM.getTargetData().getPrefTypeAlignment(
- ObjCTypes.ClassnfABIPtrTy));
+ CGM.getTargetData().getPrefTypeAlignment(
+ ObjCTypes.ClassnfABIPtrTy));
Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip");
- UsedGlobals.push_back(Entry);
+ CGM.AddUsedGlobal(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::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,
+ Entry =
+ new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABIPtrTy, false,
llvm::GlobalValue::InternalLinkage,
- MetaClassGV,
- "\01L_OBJC_CLASSLIST_SUP_REFS_$_",
- &CGM.getModule());
+ MetaClassGV,
+ "\01L_OBJC_CLASSLIST_SUP_REFS_$_");
Entry->setAlignment(
- CGM.getTargetData().getPrefTypeAlignment(
- ObjCTypes.ClassnfABIPtrTy));
-
+ CGM.getTargetData().getPrefTypeAlignment(
+ ObjCTypes.ClassnfABIPtrTy));
+
Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip");
- UsedGlobals.push_back(Entry);
-
+ CGM.AddUsedGlobal(Entry);
+
return Builder.CreateLoad(Entry, false, "tmp");
}
@@ -5180,24 +5203,25 @@ llvm::Value *CGObjCNonFragileABIMac::GetClass(CGBuilderTy &Builder,
/// 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) {
+ QualType ResultType,
+ Selector Sel,
+ const ObjCInterfaceDecl *Class,
+ bool isCategoryImpl,
+ llvm::Value *Receiver,
+ bool IsClassMessage,
+ const CodeGen::CallArgList &CallArgs,
+ const ObjCMethodDecl *Method) {
// ...
// 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) {
@@ -5207,13 +5231,11 @@ CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
Target = EmitClassRef(CGF.Builder, Class);
Target = CGF.Builder.CreateStructGEP(Target, 0);
Target = CGF.Builder.CreateLoad(Target);
- }
- else
+ } else
Target = EmitMetaClassRef(CGF.Builder, Class);
- }
- else
+ } else
Target = EmitSuperClassRef(CGF.Builder, Class);
-
+
// FIXME: We shouldn't need to do this cast, rectify the ASTContext and
// ObjCTypes types.
const llvm::Type *ClassTy =
@@ -5221,42 +5243,41 @@ CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
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);
+ ? EmitLegacyMessageSend(CGF, ResultType,EmitSelector(CGF.Builder, Sel),
+ ObjCSuper, ObjCTypes.SuperPtrCTy,
+ true, CallArgs, Method, ObjCTypes)
+ : EmitMessageSend(CGF, ResultType, Sel,
+ ObjCSuper, ObjCTypes.SuperPtrCTy,
+ true, CallArgs);
}
-llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CGBuilderTy &Builder,
+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());
+ llvm::Constant *Casted =
+ llvm::ConstantExpr::getBitCast(GetMethodVarName(Sel),
+ ObjCTypes.SelectorPtrTy);
+ Entry =
+ new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.SelectorPtrTy, false,
+ llvm::GlobalValue::InternalLinkage,
+ Casted, "\01L_OBJC_SELECTOR_REFERENCES_");
Entry->setSection("__DATA, __objc_selrefs, literal_pointers, no_dead_strip");
- UsedGlobals.push_back(Entry);
+ CGM.AddUsedGlobal(Entry);
}
-
+
return Builder.CreateLoad(Entry, false, "tmp");
}
/// EmitObjCIvarAssign - Code gen for assigning to a __strong object.
-/// objc_assign_ivar (id src, id *dst)
+/// objc_assign_ivar (id src, id *dst, ptrdiff_t)
///
void CGObjCNonFragileABIMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dst)
-{
+ llvm::Value *src,
+ llvm::Value *dst,
+ llvm::Value *ivarOffset) {
const llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
@@ -5267,8 +5288,8 @@ void CGObjCNonFragileABIMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
- CGF.Builder.CreateCall2(ObjCTypes.getGcAssignIvarFn(),
- src, dst, "assignivar");
+ CGF.Builder.CreateCall3(ObjCTypes.getGcAssignIvarFn(),
+ src, dst, ivarOffset);
return;
}
@@ -5276,15 +5297,14 @@ void CGObjCNonFragileABIMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
/// objc_assign_strongCast (id src, id *dst)
///
void CGObjCNonFragileABIMac::EmitObjCStrongCastAssign(
- CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dst)
-{
+ 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));
+ : CGF.Builder.CreateBitCast(src, ObjCTypes.LongTy));
src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
@@ -5294,16 +5314,31 @@ void CGObjCNonFragileABIMac::EmitObjCStrongCastAssign(
return;
}
+void CGObjCNonFragileABIMac::EmitGCMemmoveCollectable(
+ CodeGen::CodeGenFunction &CGF,
+ llvm::Value *DestPtr,
+ llvm::Value *SrcPtr,
+ QualType Ty) {
+ // Get size info for this aggregate.
+ std::pair<uint64_t, unsigned> TypeInfo = CGM.getContext().getTypeInfo(Ty);
+ unsigned long size = TypeInfo.first/8;
+ SrcPtr = CGF.Builder.CreateBitCast(SrcPtr, ObjCTypes.Int8PtrTy);
+ DestPtr = CGF.Builder.CreateBitCast(DestPtr, ObjCTypes.Int8PtrTy);
+ llvm::Value *N = llvm::ConstantInt::get(ObjCTypes.LongTy, size);
+ CGF.Builder.CreateCall3(ObjCTypes.GcMemmoveCollectableFn(),
+ DestPtr, SrcPtr, N);
+ 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)
-{
+ CodeGen::CodeGenFunction &CGF,
+ llvm::Value *AddrWeakObj) {
const llvm::Type* DestTy =
- cast<llvm::PointerType>(AddrWeakObj->getType())->getElementType();
- AddrWeakObj = CGF.Builder.CreateBitCast(AddrWeakObj, ObjCTypes.PtrObjectPtrTy);
+ 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);
@@ -5314,8 +5349,7 @@ llvm::Value * CGObjCNonFragileABIMac::EmitObjCWeakRead(
/// objc_assign_weak (id src, id *dst)
///
void CGObjCNonFragileABIMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dst)
-{
+ llvm::Value *src, llvm::Value *dst) {
const llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
@@ -5335,8 +5369,7 @@ void CGObjCNonFragileABIMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
/// objc_assign_global (id src, id *dst)
///
void CGObjCNonFragileABIMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dst)
-{
+ llvm::Value *src, llvm::Value *dst) {
const llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
@@ -5352,7 +5385,7 @@ void CGObjCNonFragileABIMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
return;
}
-void
+void
CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
const Stmt &S) {
bool isTry = isa<ObjCAtTryStmt>(S);
@@ -5369,7 +5402,7 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
// @synchronized are illegal & this will dominate uses.
llvm::Value *SyncArg = 0;
if (!isTry) {
- SyncArg =
+ SyncArg =
CGF.EmitScalarExpr(cast<ObjCAtSynchronizedStmt>(S).getSynchExpr());
SyncArg = CGF.Builder.CreateBitCast(SyncArg, ObjCTypes.ObjectPtrTy);
CGF.Builder.CreateCall(ObjCTypes.getSyncEnterFn(), SyncArg);
@@ -5382,20 +5415,20 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
CGF.setInvokeDest(TryHandler);
CGF.EmitBlock(TryBlock);
- CGF.EmitStmt(isTry ? cast<ObjCAtTryStmt>(S).getTryBody()
- : cast<ObjCAtSynchronizedStmt>(S).getSynchBody());
+ 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 =
+ 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 *llvm_eh_selector =
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_selector);
+ llvm::Value *llvm_eh_typeid_for =
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for);
llvm::Value *Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc");
llvm::Value *RethrowPtr = CGF.CreateTempAlloca(Exc->getType(), "_rethrow");
@@ -5422,40 +5455,42 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
break;
}
- if (CGF.getContext().isObjCIdType(CatchDecl->getType()) ||
+ if (CatchDecl->getType()->isObjCIdType() ||
CatchDecl->getType()->isObjCQualifiedIdType()) {
- llvm::Value *IDEHType =
+ llvm::Value *IDEHType =
CGM.getModule().getGlobalVariable("OBJC_EHTYPE_id");
if (!IDEHType)
- IDEHType =
- new llvm::GlobalVariable(ObjCTypes.EHTypeTy, false,
+ IDEHType =
+ new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.EHTypeTy,
+ false,
llvm::GlobalValue::ExternalLinkage,
- 0, "OBJC_EHTYPE_id", &CGM.getModule());
+ 0, "OBJC_EHTYPE_id");
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);
+ } else {
+ // All other types should be Objective-C interface pointer types.
+ const ObjCObjectPointerType *PT =
+ CatchDecl->getType()->getAs<ObjCObjectPointerType>();
+ assert(PT && "Invalid @catch type.");
+ const ObjCInterfaceType *IT = PT->getInterfaceType();
+ 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));
+ // Even though this is a cleanup, treat it as a catch all to avoid the C++
+ // personality behavior of terminating the process if only cleanups are
+ // found in the exception handling stack.
+ SelectorArgs.push_back(llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy));
Handlers.push_back(std::make_pair((const ParmVarDecl*) 0, (const Stmt*) 0));
}
-
- llvm::Value *Selector =
- CGF.Builder.CreateCall(llvm_eh_selector_i64,
+
+ llvm::Value *Selector =
+ CGF.Builder.CreateCall(llvm_eh_selector,
SelectorArgs.begin(), SelectorArgs.end(),
"selector");
for (unsigned i = 0, e = Handlers.size(); i != e; ++i) {
@@ -5470,8 +5505,8 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
llvm::BasicBlock *Match = CGF.createBasicBlock("match");
Next = CGF.createBasicBlock("catch.next");
- llvm::Value *Id =
- CGF.Builder.CreateCall(llvm_eh_typeid_for_i64,
+ llvm::Value *Id =
+ CGF.Builder.CreateCall(llvm_eh_typeid_for,
CGF.Builder.CreateBitCast(SelectorArgs[i+2],
ObjCTypes.Int8PtrTy));
CGF.Builder.CreateCondBr(CGF.Builder.CreateICmpEQ(Selector, Id),
@@ -5479,25 +5514,25 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
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 =
+
+ llvm::Value *ExcObject =
CGF.Builder.CreateCall(ObjCTypes.getObjCBeginCatchFn(), Exc);
// Bind the catch parameter if it exists.
if (CatchParam) {
- ExcObject =
- CGF.Builder.CreateBitCast(ExcObject,
+ 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
@@ -5520,22 +5555,22 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
llvm::SmallVector<llvm::Value*, 8> Args;
Args.push_back(Exc);
Args.push_back(ObjCTypes.getEHPersonalityPtr());
- Args.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty,
+ Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
0));
- CGF.Builder.CreateCall(llvm_eh_selector_i64, Args.begin(), Args.end());
+ CGF.Builder.CreateCall(llvm_eh_selector, 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 =
+ llvm::BasicBlock *MatchEndHandler =
CGF.createBasicBlock("match.end.handler");
llvm::BasicBlock *Cont = CGF.createBasicBlock("invoke.cont");
- CGF.Builder.CreateInvoke(ObjCTypes.getObjCEndCatchFn(),
+ CGF.Builder.CreateInvoke(ObjCTypes.getObjCEndCatchFn(),
Cont, MatchEndHandler,
Args.begin(), Args.begin());
@@ -5552,9 +5587,9 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
Args.clear();
Args.push_back(Exc);
Args.push_back(ObjCTypes.getEHPersonalityPtr());
- Args.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty,
+ Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
0));
- CGF.Builder.CreateCall(llvm_eh_selector_i64, Args.begin(), Args.end());
+ CGF.Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end());
CGF.Builder.CreateStore(Exc, RethrowPtr);
CGF.EmitBranchThroughCleanup(FinallyRethrow);
@@ -5576,7 +5611,7 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
CGF.EmitBlock(FinallyBlock);
if (isTry) {
- if (const ObjCAtFinallyStmt* FinallyStmt =
+ if (const ObjCAtFinallyStmt* FinallyStmt =
cast<ObjCAtTryStmt>(S).getFinallyStmt())
CGF.EmitStmt(FinallyStmt->getFinallyBody());
} else {
@@ -5594,26 +5629,26 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
CGF.EmitBranch(FinallyEnd);
CGF.EmitBlock(FinallyRethrow);
- CGF.Builder.CreateCall(ObjCTypes.getUnwindResumeOrRethrowFn(),
+ 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;
+ llvm::Value *Exception;
if (const Expr *ThrowExpr = S.getThrowExpr()) {
Exception = CGF.EmitScalarExpr(ThrowExpr);
} else {
- assert((!CGF.ObjCEHValueStack.empty() && CGF.ObjCEHValueStack.back()) &&
+ assert((!CGF.ObjCEHValueStack.empty() && CGF.ObjCEHValueStack.back()) &&
"Unexpected rethrow outside @catch block.");
Exception = CGF.ObjCEHValueStack.back();
}
- llvm::Value *ExceptionAsObject =
+ llvm::Value *ExceptionAsObject =
CGF.Builder.CreateBitCast(Exception, ObjCTypes.ObjectPtrTy, "tmp");
llvm::BasicBlock *InvokeDest = CGF.getInvokeDest();
if (InvokeDest) {
@@ -5623,7 +5658,7 @@ void CGObjCNonFragileABIMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
&ExceptionAsObject, &ExceptionAsObject + 1);
CGF.EmitBlock(Cont);
} else
- CGF.Builder.CreateCall(ObjCTypes.getExceptionThrowFn(), ExceptionAsObject);
+ CGF.Builder.CreateCall(ObjCTypes.getExceptionThrowFn(), ExceptionAsObject);
CGF.Builder.CreateUnreachable();
// Clear the insertion point to indicate we are in unreachable code.
@@ -5631,7 +5666,7 @@ void CGObjCNonFragileABIMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
}
llvm::Value *
-CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID,
+CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID,
bool ForDefinition) {
llvm::GlobalVariable * &Entry = EHTypeReferences[ID->getIdentifier()];
@@ -5644,44 +5679,44 @@ CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID,
// If this type (or a super class) has the __objc_exception__
// attribute, emit an external reference.
if (hasObjCExceptionAttribute(CGM.getContext(), ID))
- return Entry =
- new llvm::GlobalVariable(ObjCTypes.EHTypeTy, false,
+ return Entry =
+ new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.EHTypeTy, false,
llvm::GlobalValue::ExternalLinkage,
- 0,
- (std::string("OBJC_EHTYPE_$_") +
- ID->getIdentifier()->getName()),
- &CGM.getModule());
+ 0,
+ (std::string("OBJC_EHTYPE_$_") +
+ ID->getIdentifier()->getName()));
}
-
+
// 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 =
+ llvm::GlobalVariable *VTableGV =
CGM.getModule().getGlobalVariable(VTableName);
if (!VTableGV)
- VTableGV = new llvm::GlobalVariable(ObjCTypes.Int8PtrTy, false,
+ VTableGV = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.Int8PtrTy,
+ false,
llvm::GlobalValue::ExternalLinkage,
- 0, VTableName, &CGM.getModule());
+ 0, VTableName);
- llvm::Value *VTableIdx = llvm::ConstantInt::get(llvm::Type::Int32Ty, 2);
+ llvm::Value *VTableIdx = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 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);
+ llvm::Constant *Init =
+ llvm::ConstantStruct::get(ObjCTypes.EHTypeTy, Values);
if (Entry) {
Entry->setInitializer(Init);
} else {
- Entry = new llvm::GlobalVariable(ObjCTypes.EHTypeTy, false,
+ Entry = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.EHTypeTy, false,
llvm::GlobalValue::WeakAnyLinkage,
- Init,
- (std::string("OBJC_EHTYPE_$_") +
- ID->getIdentifier()->getName()),
- &CGM.getModule());
+ Init,
+ (std::string("OBJC_EHTYPE_$_") +
+ ID->getIdentifier()->getName()));
}
if (CGM.getLangOptions().getVisibilityMode() == LangOptions::Hidden)
@@ -5697,7 +5732,7 @@ CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID,
return Entry;
}
-
+
/* *** */
CodeGen::CGObjCRuntime *
diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h
index 0f9cf06..6b45562 100644
--- a/lib/CodeGen/CGObjCRuntime.h
+++ b/lib/CodeGen/CGObjCRuntime.h
@@ -86,7 +86,7 @@ protected:
llvm::Value *BaseValue,
const ObjCIvarDecl *Ivar,
unsigned CVRQualifiers,
- llvm::Value *Offset);
+ llvm::Value *Offset);
public:
virtual ~CGObjCRuntime();
@@ -95,16 +95,13 @@ public:
/// this compilation unit with the runtime library.
virtual llvm::Function *ModuleInitFunction() = 0;
- /// Add metadata globals to the 'used' globals for final output.
- virtual void MergeMetadataGlobals(std::vector<llvm::Constant*> &UsedArray) = 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.
+ /// Get a typed selector.
virtual llvm::Value *GetSelector(CGBuilderTy &Builder,
const ObjCMethodDecl *Method) = 0;
@@ -117,20 +114,26 @@ public:
/// Generate a class stucture for this class.
virtual void GenerateClass(const ObjCImplementationDecl *OID) = 0;
-
- /// Generate an Objective-C message send operation.
- virtual CodeGen::RValue
+
+ /// Generate an Objective-C message send operation.
+ ///
+ /// \param Method - The method being called, this may be null if synthesizing
+ /// a property setter or getter.
+ virtual CodeGen::RValue
GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
QualType ResultType,
Selector Sel,
llvm::Value *Receiver,
bool IsClassMessage,
const CallArgList &CallArgs,
- const ObjCMethodDecl *Method=0) = 0;
+ 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.
+ ///
+ /// \param Method - The method being called, this may be null if synthesizing
+ /// a property setter or getter.
virtual CodeGen::RValue
GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
QualType ResultType,
@@ -139,41 +142,42 @@ public:
bool isCategoryImpl,
llvm::Value *Self,
bool IsClassMessage,
- const CallArgList &CallArgs) = 0;
+ const CallArgList &CallArgs,
+ const ObjCMethodDecl *Method = 0) = 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.
+ /// 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.
+ /// 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,
+ 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,
+ 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,
@@ -185,10 +189,11 @@ public:
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;
+ llvm::Value *src, llvm::Value *dest,
+ llvm::Value *ivarOffset) = 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,
@@ -197,9 +202,13 @@ public:
virtual llvm::Value *EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
const ObjCInterfaceDecl *Interface,
const ObjCIvarDecl *Ivar) = 0;
+ virtual void EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *DestPtr,
+ llvm::Value *SrcPtr,
+ QualType Ty) = 0;
};
-/// Creates an instance of an Objective-C runtime class.
+/// 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);
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp
new file mode 100644
index 0000000..7baf69d
--- /dev/null
+++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -0,0 +1,386 @@
+//===--- CGRecordLayoutBuilder.cpp - Record builder helper ------*- 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 helper class used to build CGRecordLayout objects and LLVM types.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CGRecordLayoutBuilder.h"
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/RecordLayout.h"
+#include "CodeGenTypes.h"
+#include "llvm/DerivedTypes.h"
+#include "llvm/Target/TargetData.h"
+
+
+using namespace clang;
+using namespace CodeGen;
+
+void CGRecordLayoutBuilder::Layout(const RecordDecl *D) {
+ Alignment = Types.getContext().getASTRecordLayout(D).getAlignment() / 8;
+ Packed = D->hasAttr<PackedAttr>();
+
+ if (D->isUnion()) {
+ LayoutUnion(D);
+ return;
+ }
+
+ if (LayoutFields(D))
+ return;
+
+ // We weren't able to layout the struct. Try again with a packed struct
+ Packed = true;
+ AlignmentAsLLVMStruct = 1;
+ NextFieldOffsetInBytes = 0;
+ FieldTypes.clear();
+ LLVMFields.clear();
+ LLVMBitFields.clear();
+
+ LayoutFields(D);
+}
+
+void CGRecordLayoutBuilder::LayoutBitField(const FieldDecl *D,
+ uint64_t FieldOffset) {
+ uint64_t FieldSize =
+ D->getBitWidth()->EvaluateAsInt(Types.getContext()).getZExtValue();
+
+ if (FieldSize == 0)
+ return;
+
+ uint64_t NextFieldOffset = NextFieldOffsetInBytes * 8;
+ unsigned NumBytesToAppend;
+
+ if (FieldOffset < NextFieldOffset) {
+ assert(BitsAvailableInLastField && "Bitfield size mismatch!");
+ assert(NextFieldOffsetInBytes && "Must have laid out at least one byte!");
+
+ // The bitfield begins in the previous bit-field.
+ NumBytesToAppend =
+ llvm::RoundUpToAlignment(FieldSize - BitsAvailableInLastField, 8) / 8;
+ } else {
+ assert(FieldOffset % 8 == 0 && "Field offset not aligned correctly");
+
+ // Append padding if necessary.
+ AppendBytes((FieldOffset - NextFieldOffset) / 8);
+
+ NumBytesToAppend =
+ llvm::RoundUpToAlignment(FieldSize, 8) / 8;
+
+ assert(NumBytesToAppend && "No bytes to append!");
+ }
+
+ const llvm::Type *Ty = Types.ConvertTypeForMemRecursive(D->getType());
+ uint64_t TypeSizeInBits = getTypeSizeInBytes(Ty) * 8;
+
+ LLVMBitFields.push_back(LLVMBitFieldInfo(D, FieldOffset / TypeSizeInBits,
+ FieldOffset % TypeSizeInBits,
+ FieldSize));
+
+ AppendBytes(NumBytesToAppend);
+
+ AlignmentAsLLVMStruct = std::max(AlignmentAsLLVMStruct, getTypeAlignment(Ty));
+
+ BitsAvailableInLastField =
+ NextFieldOffsetInBytes * 8 - (FieldOffset + FieldSize);
+}
+
+bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D,
+ uint64_t FieldOffset) {
+ // If the field is packed, then we need a packed struct.
+ if (!Packed && D->hasAttr<PackedAttr>())
+ return false;
+
+ if (D->isBitField()) {
+ // We must use packed structs for unnamed bit fields since they
+ // don't affect the struct alignment.
+ if (!Packed && !D->getDeclName())
+ return false;
+
+ LayoutBitField(D, FieldOffset);
+ return true;
+ }
+
+ assert(FieldOffset % 8 == 0 && "FieldOffset is not on a byte boundary!");
+ uint64_t FieldOffsetInBytes = FieldOffset / 8;
+
+ const llvm::Type *Ty = Types.ConvertTypeForMemRecursive(D->getType());
+ unsigned TypeAlignment = getTypeAlignment(Ty);
+
+ // If the type alignment is larger then the struct alignment, we must use
+ // a packed struct.
+ if (TypeAlignment > Alignment) {
+ assert(!Packed && "Alignment is wrong even with packed struct!");
+ return false;
+ }
+
+ if (const RecordType *RT = D->getType()->getAs<RecordType>()) {
+ const RecordDecl *RD = cast<RecordDecl>(RT->getDecl());
+ if (const PragmaPackAttr *PPA = RD->getAttr<PragmaPackAttr>()) {
+ if (PPA->getAlignment() != TypeAlignment * 8 && !Packed)
+ return false;
+ }
+ }
+
+ // Round up the field offset to the alignment of the field type.
+ uint64_t AlignedNextFieldOffsetInBytes =
+ llvm::RoundUpToAlignment(NextFieldOffsetInBytes, TypeAlignment);
+
+ if (FieldOffsetInBytes < AlignedNextFieldOffsetInBytes) {
+ assert(!Packed && "Could not place field even with packed struct!");
+ return false;
+ }
+
+ if (AlignedNextFieldOffsetInBytes < FieldOffsetInBytes) {
+ // Even with alignment, the field offset is not at the right place,
+ // insert padding.
+ uint64_t PaddingInBytes = FieldOffsetInBytes - NextFieldOffsetInBytes;
+
+ AppendBytes(PaddingInBytes);
+ }
+
+ // Now append the field.
+ LLVMFields.push_back(LLVMFieldInfo(D, FieldTypes.size()));
+ AppendField(FieldOffsetInBytes, Ty);
+
+ return true;
+}
+
+void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) {
+ assert(D->isUnion() && "Can't call LayoutUnion on a non-union record!");
+
+ const ASTRecordLayout &Layout = Types.getContext().getASTRecordLayout(D);
+
+ const llvm::Type *Ty = 0;
+ uint64_t Size = 0;
+ unsigned Align = 0;
+
+ unsigned FieldNo = 0;
+ for (RecordDecl::field_iterator Field = D->field_begin(),
+ FieldEnd = D->field_end(); Field != FieldEnd; ++Field, ++FieldNo) {
+ assert(Layout.getFieldOffset(FieldNo) == 0 &&
+ "Union field offset did not start at the beginning of record!");
+
+ if (Field->isBitField()) {
+ uint64_t FieldSize =
+ Field->getBitWidth()->EvaluateAsInt(Types.getContext()).getZExtValue();
+
+ // Ignore zero sized bit fields.
+ if (FieldSize == 0)
+ continue;
+
+ // Add the bit field info.
+ Types.addBitFieldInfo(*Field, 0, 0, FieldSize);
+ } else
+ Types.addFieldInfo(*Field, 0);
+
+ const llvm::Type *FieldTy =
+ Types.ConvertTypeForMemRecursive(Field->getType());
+ unsigned FieldAlign = Types.getTargetData().getABITypeAlignment(FieldTy);
+ uint64_t FieldSize = Types.getTargetData().getTypeAllocSize(FieldTy);
+
+ if (FieldAlign < Align)
+ continue;
+
+ if (FieldAlign > Align || FieldSize > Size) {
+ Ty = FieldTy;
+ Align = FieldAlign;
+ Size = FieldSize;
+ }
+ }
+
+ // Now add our field.
+ if (Ty) {
+ AppendField(0, Ty);
+
+ if (getTypeAlignment(Ty) > Layout.getAlignment() / 8) {
+ // We need a packed struct.
+ Packed = true;
+ Align = 1;
+ }
+ }
+
+ // Append tail padding.
+ if (Layout.getSize() / 8 > Size)
+ AppendPadding(Layout.getSize() / 8, Align);
+}
+
+bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
+ assert(!D->isUnion() && "Can't call LayoutFields on a union!");
+ assert(Alignment && "Did not set alignment!");
+
+ const ASTRecordLayout &Layout = Types.getContext().getASTRecordLayout(D);
+
+ unsigned FieldNo = 0;
+
+ for (RecordDecl::field_iterator Field = D->field_begin(),
+ FieldEnd = D->field_end(); Field != FieldEnd; ++Field, ++FieldNo) {
+ if (!LayoutField(*Field, Layout.getFieldOffset(FieldNo))) {
+ assert(!Packed &&
+ "Could not layout fields even with a packed LLVM struct!");
+ return false;
+ }
+ }
+
+ // Append tail padding if necessary.
+ AppendTailPadding(Layout.getSize());
+
+ return true;
+}
+
+void CGRecordLayoutBuilder::AppendTailPadding(uint64_t RecordSize) {
+ assert(RecordSize % 8 == 0 && "Invalid record size!");
+
+ uint64_t RecordSizeInBytes = RecordSize / 8;
+ assert(NextFieldOffsetInBytes <= RecordSizeInBytes && "Size mismatch!");
+
+ unsigned NumPadBytes = RecordSizeInBytes - NextFieldOffsetInBytes;
+ AppendBytes(NumPadBytes);
+}
+
+void CGRecordLayoutBuilder::AppendField(uint64_t FieldOffsetInBytes,
+ const llvm::Type *FieldTy) {
+ AlignmentAsLLVMStruct = std::max(AlignmentAsLLVMStruct,
+ getTypeAlignment(FieldTy));
+
+ uint64_t FieldSizeInBytes = getTypeSizeInBytes(FieldTy);
+
+ FieldTypes.push_back(FieldTy);
+
+ NextFieldOffsetInBytes = FieldOffsetInBytes + FieldSizeInBytes;
+ BitsAvailableInLastField = 0;
+}
+
+void
+CGRecordLayoutBuilder::AppendPadding(uint64_t FieldOffsetInBytes,
+ const llvm::Type *FieldTy) {
+ AppendPadding(FieldOffsetInBytes, getTypeAlignment(FieldTy));
+}
+
+void CGRecordLayoutBuilder::AppendPadding(uint64_t FieldOffsetInBytes,
+ unsigned FieldAlignment) {
+ assert(NextFieldOffsetInBytes <= FieldOffsetInBytes &&
+ "Incorrect field layout!");
+
+ // Round up the field offset to the alignment of the field type.
+ uint64_t AlignedNextFieldOffsetInBytes =
+ llvm::RoundUpToAlignment(NextFieldOffsetInBytes, FieldAlignment);
+
+ if (AlignedNextFieldOffsetInBytes < FieldOffsetInBytes) {
+ // Even with alignment, the field offset is not at the right place,
+ // insert padding.
+ uint64_t PaddingInBytes = FieldOffsetInBytes - NextFieldOffsetInBytes;
+
+ AppendBytes(PaddingInBytes);
+ }
+}
+
+void CGRecordLayoutBuilder::AppendBytes(uint64_t NumBytes) {
+ if (NumBytes == 0)
+ return;
+
+ const llvm::Type *Ty = llvm::Type::getInt8Ty(Types.getLLVMContext());
+ if (NumBytes > 1)
+ Ty = llvm::ArrayType::get(Ty, NumBytes);
+
+ // Append the padding field
+ AppendField(NextFieldOffsetInBytes, Ty);
+}
+
+unsigned CGRecordLayoutBuilder::getTypeAlignment(const llvm::Type *Ty) const {
+ if (Packed)
+ return 1;
+
+ return Types.getTargetData().getABITypeAlignment(Ty);
+}
+
+uint64_t CGRecordLayoutBuilder::getTypeSizeInBytes(const llvm::Type *Ty) const {
+ return Types.getTargetData().getTypeAllocSize(Ty);
+}
+
+void CGRecordLayoutBuilder::CheckForMemberPointer(const FieldDecl *FD) {
+ // This record already contains a member pointer.
+ if (ContainsMemberPointer)
+ return;
+
+ // Can only have member pointers if we're compiling C++.
+ if (!Types.getContext().getLangOptions().CPlusPlus)
+ return;
+
+ QualType Ty = FD->getType();
+
+ if (Ty->isMemberPointerType()) {
+ // We have a member pointer!
+ ContainsMemberPointer = true;
+ return;
+ }
+
+}
+
+static const CXXMethodDecl *GetKeyFunction(const RecordDecl *D) {
+ const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D);
+ if (!RD || !RD->isDynamicClass())
+ return 0;
+
+ for (CXXRecordDecl::method_iterator I = RD->method_begin(),
+ E = RD->method_end(); I != E; ++I) {
+ const CXXMethodDecl *MD = *I;
+
+ if (!MD->isVirtual())
+ continue;
+
+ if (MD->isPure())
+ continue;
+
+ if (MD->getBody())
+ continue;
+
+ // We found it.
+ return MD;
+ }
+
+ return 0;
+}
+
+CGRecordLayout *
+CGRecordLayoutBuilder::ComputeLayout(CodeGenTypes &Types,
+ const RecordDecl *D) {
+ CGRecordLayoutBuilder Builder(Types);
+
+ Builder.Layout(D);
+
+ const llvm::Type *Ty = llvm::StructType::get(Types.getLLVMContext(),
+ Builder.FieldTypes,
+ Builder.Packed);
+ assert(Types.getContext().getASTRecordLayout(D).getSize() / 8 ==
+ Types.getTargetData().getTypeAllocSize(Ty) &&
+ "Type size mismatch!");
+
+ // Add all the field numbers.
+ for (unsigned i = 0, e = Builder.LLVMFields.size(); i != e; ++i) {
+ const FieldDecl *FD = Builder.LLVMFields[i].first;
+ unsigned FieldNo = Builder.LLVMFields[i].second;
+
+ Types.addFieldInfo(FD, FieldNo);
+ }
+
+ // Add bitfield info.
+ for (unsigned i = 0, e = Builder.LLVMBitFields.size(); i != e; ++i) {
+ const LLVMBitFieldInfo &Info = Builder.LLVMBitFields[i];
+
+ Types.addBitFieldInfo(Info.FD, Info.FieldNo, Info.Start, Info.Size);
+ }
+
+ const CXXMethodDecl *KeyFunction = GetKeyFunction(D);
+
+ return new CGRecordLayout(Ty, Builder.ContainsMemberPointer, KeyFunction);
+}
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.h b/lib/CodeGen/CGRecordLayoutBuilder.h
new file mode 100644
index 0000000..d1a13aa
--- /dev/null
+++ b/lib/CodeGen/CGRecordLayoutBuilder.h
@@ -0,0 +1,134 @@
+//===--- CGRecordLayoutBuilder.h - Record builder helper --------*- 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 helper class used to build CGRecordLayout objects and LLVM types.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_CODEGEN_CGRECORDLAYOUTBUILDER_H
+#define CLANG_CODEGEN_CGRECORDLAYOUTBUILDER_H
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/DataTypes.h"
+#include <vector>
+
+namespace llvm {
+ class Type;
+}
+
+namespace clang {
+ class FieldDecl;
+ class RecordDecl;
+
+namespace CodeGen {
+ class CGRecordLayout;
+ class CodeGenTypes;
+
+class CGRecordLayoutBuilder {
+ CodeGenTypes &Types;
+
+ /// Packed - Whether the resulting LLVM struct will be packed or not.
+ bool Packed;
+
+ /// ContainsMemberPointer - Whether one of the fields is a member pointer
+ /// or is a struct that contains a member pointer.
+ bool ContainsMemberPointer;
+
+ /// Alignment - Contains the alignment of the RecordDecl.
+ unsigned Alignment;
+
+ /// AlignmentAsLLVMStruct - Will contain the maximum alignment of all the
+ /// LLVM types.
+ unsigned AlignmentAsLLVMStruct;
+
+ /// BitsAvailableInLastField - If a bit field spans only part of a LLVM field,
+ /// this will have the number of bits still available in the field.
+ char BitsAvailableInLastField;
+
+ /// NextFieldOffsetInBytes - Holds the next field offset in bytes.
+ uint64_t NextFieldOffsetInBytes;
+
+ /// FieldTypes - Holds the LLVM types that the struct is created from.
+ std::vector<const llvm::Type *> FieldTypes;
+
+ /// LLVMFieldInfo - Holds a field and its corresponding LLVM field number.
+ typedef std::pair<const FieldDecl *, unsigned> LLVMFieldInfo;
+ llvm::SmallVector<LLVMFieldInfo, 16> LLVMFields;
+
+ /// LLVMBitFieldInfo - Holds location and size information about a bit field.
+ struct LLVMBitFieldInfo {
+ LLVMBitFieldInfo(const FieldDecl *FD, unsigned FieldNo, unsigned Start,
+ unsigned Size)
+ : FD(FD), FieldNo(FieldNo), Start(Start), Size(Size) { }
+
+ const FieldDecl *FD;
+
+ unsigned FieldNo;
+ unsigned Start;
+ unsigned Size;
+ };
+ llvm::SmallVector<LLVMBitFieldInfo, 16> LLVMBitFields;
+
+ CGRecordLayoutBuilder(CodeGenTypes &Types)
+ : Types(Types), Packed(false), ContainsMemberPointer(false)
+ , Alignment(0), AlignmentAsLLVMStruct(1)
+ , BitsAvailableInLastField(0), NextFieldOffsetInBytes(0) { }
+
+ /// Layout - Will layout a RecordDecl.
+ void Layout(const RecordDecl *D);
+
+ /// LayoutUnion - Will layout a union RecordDecl.
+ void LayoutUnion(const RecordDecl *D);
+
+ /// LayoutField - try to layout all fields in the record decl.
+ /// Returns false if the operation failed because the struct is not packed.
+ bool LayoutFields(const RecordDecl *D);
+
+ /// LayoutField - layout a single field. Returns false if the operation failed
+ /// because the current struct is not packed.
+ bool LayoutField(const FieldDecl *D, uint64_t FieldOffset);
+
+ /// LayoutBitField - layout a single bit field.
+ void LayoutBitField(const FieldDecl *D, uint64_t FieldOffset);
+
+ /// AppendField - Appends a field with the given offset and type.
+ void AppendField(uint64_t FieldOffsetInBytes, const llvm::Type *FieldTy);
+
+ /// AppendPadding - Appends enough padding bytes so that the total struct
+ /// size matches the alignment of the passed in type.
+ void AppendPadding(uint64_t FieldOffsetInBytes, const llvm::Type *FieldTy);
+
+ /// AppendPadding - Appends enough padding bytes so that the total
+ /// struct size is a multiple of the field alignment.
+ void AppendPadding(uint64_t FieldOffsetInBytes, unsigned FieldAlignment);
+
+ /// AppendBytes - Append a given number of bytes to the record.
+ void AppendBytes(uint64_t NumBytes);
+
+ /// AppendTailPadding - Append enough tail padding so that the type will have
+ /// the passed size.
+ void AppendTailPadding(uint64_t RecordSize);
+
+ unsigned getTypeAlignment(const llvm::Type *Ty) const;
+ uint64_t getTypeSizeInBytes(const llvm::Type *Ty) const;
+
+ /// CheckForMemberPointer - Check if the field contains a member pointer.
+ void CheckForMemberPointer(const FieldDecl *FD);
+
+public:
+ /// ComputeLayout - Return the right record layout for a given record decl.
+ static CGRecordLayout *ComputeLayout(CodeGenTypes &Types,
+ const RecordDecl *D);
+};
+
+} // end namespace CodeGen
+} // end namespace clang
+
+
+#endif
diff --git a/lib/CodeGen/CGRtti.cpp b/lib/CodeGen/CGRtti.cpp
new file mode 100644
index 0000000..7bc774f
--- /dev/null
+++ b/lib/CodeGen/CGRtti.cpp
@@ -0,0 +1,47 @@
+//===--- CGCXXRtti.cpp - Emit LLVM Code for C++ RTTI descriptors ----------===//
+//
+// 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 of RTTI descriptors.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CodeGenModule.h"
+using namespace clang;
+using namespace CodeGen;
+
+llvm::Constant *CodeGenModule::GenerateRtti(const CXXRecordDecl *RD) {
+ llvm::Type *Ptr8Ty;
+ Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0);
+ llvm::Constant *Rtti = llvm::Constant::getNullValue(Ptr8Ty);
+
+ if (!getContext().getLangOptions().Rtti)
+ return Rtti;
+
+ llvm::SmallString<256> OutName;
+ llvm::raw_svector_ostream Out(OutName);
+ mangleCXXRtti(getMangleContext(), RD, Out);
+
+ llvm::GlobalVariable::LinkageTypes linktype;
+ linktype = llvm::GlobalValue::WeakAnyLinkage;
+ std::vector<llvm::Constant *> info;
+ // assert(0 && "FIXME: implement rtti descriptor");
+ // FIXME: descriptor
+ info.push_back(llvm::Constant::getNullValue(Ptr8Ty));
+ // assert(0 && "FIXME: implement rtti ts");
+ // FIXME: TS
+ info.push_back(llvm::Constant::getNullValue(Ptr8Ty));
+
+ llvm::Constant *C;
+ llvm::ArrayType *type = llvm::ArrayType::get(Ptr8Ty, info.size());
+ C = llvm::ConstantArray::get(type, info);
+ Rtti = new llvm::GlobalVariable(getModule(), type, true, linktype, C,
+ Out.str());
+ Rtti = llvm::ConstantExpr::getBitCast(Rtti, Ptr8Ty);
+ return Rtti;
+}
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index b67996c..f58b579 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -43,13 +43,24 @@ void CodeGenFunction::EmitStmt(const Stmt *S) {
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();
-
+ // Check if we are generating unreachable code.
+ if (!HaveInsertPoint()) {
+ // If so, and the statement doesn't contain a label, then we do not need to
+ // generate actual code. This is safe because (1) the current point is
+ // unreachable, so we don't need to execute the code, and (2) we've already
+ // handled the statements which update internal data structures (like the
+ // local variable map) which could be used by subsequent statements.
+ if (!ContainsLabel(S)) {
+ // Verify that any decl statements were handled as simple, they may be in
+ // scope of subsequent reachable statements.
+ assert(!isa<DeclStmt>(*S) && "Unexpected DeclStmt!");
+ return;
+ }
+
+ // Otherwise, make a new block to hold the code.
+ EnsureInsertPoint();
+ }
+
// Generate a stoppoint if we are emitting debug info.
EmitStopPoint(S);
@@ -57,29 +68,37 @@ void CodeGenFunction::EmitStmt(const Stmt *S) {
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 {
+ if (!isa<Expr>(S))
ErrorUnsupported(S, "statement");
+
+ EmitAnyExpr(cast<Expr>(S), 0, false, true);
+
+ // Expression emitters don't handle unreachable blocks yet, so look for one
+ // explicitly here. This handles the common case of a call to a noreturn
+ // function.
+ if (llvm::BasicBlock *CurBB = Builder.GetInsertBlock()) {
+ if (CurBB->empty() && CurBB->use_empty()) {
+ CurBB->eraseFromParent();
+ Builder.ClearInsertionPoint();
+ }
}
break;
- case Stmt::IndirectGotoStmtClass:
+ 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;
+ break;
case Stmt::ObjCAtCatchStmtClass:
assert(0 && "@catch statements should be handled by EmitObjCAtTryStmt");
break;
@@ -92,9 +111,13 @@ void CodeGenFunction::EmitStmt(const Stmt *S) {
case Stmt::ObjCAtSynchronizedStmtClass:
EmitObjCAtSynchronizedStmt(cast<ObjCAtSynchronizedStmt>(*S));
break;
- case Stmt::ObjCForCollectionStmtClass:
+ case Stmt::ObjCForCollectionStmtClass:
EmitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(*S));
break;
+
+ case Stmt::CXXTryStmtClass:
+ EmitCXXTryStmt(cast<CXXTryStmt>(*S));
+ break;
}
}
@@ -103,6 +126,7 @@ bool CodeGenFunction::EmitSimpleStmt(const Stmt *S) {
default: return false;
case Stmt::NullStmtClass: break;
case Stmt::CompoundStmtClass: EmitCompoundStmt(cast<CompoundStmt>(*S)); break;
+ case Stmt::DeclStmtClass: EmitDeclStmt(cast<DeclStmt>(*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;
@@ -121,41 +145,42 @@ 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) {
+#ifdef ATTACH_DEBUG_INFO_TO_AN_INSN
+ DI->setLocation(S.getLBracLoc());
+ DI->EmitRegionStart(CurFn, Builder);
+#else
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);
+#endif
}
// 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) {
+#ifdef ATTACH_DEBUG_INFO_TO_AN_INSN
+ DI->setLocation(S.getLBracLoc());
+ DI->EmitRegionEnd(CurFn, Builder);
+#else
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);
+ DI->setLocation(S.getLBracLoc());
+#endif
}
RValue RV;
- if (!GetLast)
+ if (!GetLast)
RV = RValue::get(0);
else {
- // We have to special case labels here. They are statements, but when put
+ // 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.
@@ -164,22 +189,22 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast,
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).
@@ -215,7 +240,7 @@ void CodeGenFunction::EmitBlock(llvm::BasicBlock *BB, bool IsFinished) {
CleanupEntries.back().Blocks.push_back(BB);
}
}
-
+
CurFn->getBasicBlockList().push_back(BB);
Builder.SetInsertPoint(BB);
}
@@ -257,24 +282,31 @@ void CodeGenFunction::EmitGotoStmt(const GotoStmt &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,
+ llvm::Type::getInt32Ty(VMContext),
"addr");
- llvm::SwitchInst *I = Builder.CreateSwitch(V, Builder.GetInsertBlock());
- IndirectSwitches.push_back(I);
+ llvm::BasicBlock *CurBB = Builder.GetInsertBlock();
+
- // Clear the insertion point to indicate we are in unreachable code.
- Builder.ClearInsertionPoint();
+ // Get the basic block for the indirect goto.
+ llvm::BasicBlock *IndGotoBB = GetIndirectGotoBlock();
+
+ // The first instruction in the block has to be the PHI for the switch dest,
+ // add an entry for this branch.
+ cast<llvm::PHINode>(IndGotoBB->begin())->addIncoming(V, CurBB);
+
+ EmitBranch(IndGotoBB);
}
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())) {
@@ -282,7 +314,7 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
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)) {
@@ -300,19 +332,19 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
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);
}
@@ -330,7 +362,7 @@ void CodeGenFunction::EmitWhileStmt(const WhileStmt &S) {
// 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.
@@ -339,23 +371,23 @@ void CodeGenFunction::EmitWhileStmt(const WhileStmt &S) {
// 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 (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();
-
+ BreakContinueStack.pop_back();
+
// Cycle to the condition.
EmitBranch(LoopHeader);
-
+
// Emit the exit block.
EmitBlock(ExitBlock, true);
@@ -373,20 +405,20 @@ void CodeGenFunction::EmitDoStmt(const DoStmt &S) {
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.
@@ -395,14 +427,14 @@ void CodeGenFunction::EmitDoStmt(const DoStmt &S) {
// "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 (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);
@@ -431,41 +463,54 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) {
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);
+
+ 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
+ // 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;
-
+ 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.
+#ifdef ATTACH_DEBUG_INFO_TO_AN_INSN
+ CGDebugInfo *DI = getDebugInfo();
+ if (DI) {
+ DI->setLocation(S.getSourceRange().getBegin());
+ DI->EmitRegionStart(CurFn, Builder);
+ }
+#endif
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);
+#ifdef ATTACH_DEBUG_INFO_TO_AN_INSN
+ if (DI) {
+ DI->setLocation(S.getSourceRange().getEnd());
+ DI->EmitRegionEnd(CurFn, Builder);
+ }
+#endif
// Emit the fall-through block.
EmitBlock(AfterFor, true);
@@ -488,7 +533,7 @@ void CodeGenFunction::EmitReturnOfRValue(RValue RV, QualType Ty) {
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) {
@@ -514,6 +559,13 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
}
void CodeGenFunction::EmitDeclStmt(const DeclStmt &S) {
+ // As long as debug info is modeled with instructions, we have to ensure we
+ // have a place to insert here and write the stop point here.
+ if (getDebugInfo()) {
+ EnsureInsertPoint();
+ EmitStopPoint(&S);
+ }
+
for (DeclStmt::const_decl_iterator I = S.decl_begin(), E = S.decl_end();
I != E; ++I)
EmitDecl(**I);
@@ -570,12 +622,12 @@ void CodeGenFunction::EmitCaseStmtRange(const CaseStmt &S) {
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);
+ SwitchInsn->addCase(llvm::ConstantInt::get(VMContext, 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();
@@ -590,11 +642,12 @@ void CodeGenFunction::EmitCaseStmtRange(const CaseStmt &S) {
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");
+ llvm::Value *Diff =
+ Builder.CreateSub(SwitchInsn->getCondition(),
+ llvm::ConstantInt::get(VMContext, LHS), "tmp");
+ llvm::Value *Cond =
+ Builder.CreateICmpULE(Diff,
+ llvm::ConstantInt::get(VMContext, Range), "tmp");
Builder.CreateCondBr(Cond, CaseDest, FalseDest);
// Restore the appropriate insertion point.
@@ -609,12 +662,12 @@ void CodeGenFunction::EmitCaseStmt(const CaseStmt &S) {
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);
-
+ SwitchInsn->addCase(llvm::ConstantInt::get(VMContext, 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:
@@ -631,18 +684,18 @@ void CodeGenFunction::EmitCaseStmt(const CaseStmt &S) {
while (NextCase && NextCase->getRHS() == 0) {
CurCase = NextCase;
CaseVal = CurCase->getLHS()->EvaluateAsInt(getContext());
- SwitchInsn->addCase(llvm::ConstantInt::get(CaseVal), CaseDest);
+ SwitchInsn->addCase(llvm::ConstantInt::get(VMContext, 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() &&
+ assert(DefaultBlock->empty() &&
"EmitDefaultStmt: Default block already defined?");
EmitBlock(DefaultBlock);
EmitStmt(S.getSubStmt());
@@ -678,13 +731,13 @@ void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) {
// 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()) {
@@ -703,7 +756,7 @@ static std::string
SimplifyConstraint(const char *Constraint, TargetInfo &Target,
llvm::SmallVectorImpl<TargetInfo::ConstraintInfo> *OutCons=0) {
std::string Result;
-
+
while (*Constraint) {
switch (*Constraint) {
default:
@@ -721,7 +774,7 @@ SimplifyConstraint(const char *Constraint, TargetInfo &Target,
assert(OutCons &&
"Must pass output names to constraints with a symbolic name");
unsigned Index;
- bool result = Target.resolveSymbolicName(Constraint,
+ bool result = Target.resolveSymbolicName(Constraint,
&(*OutCons)[0],
OutCons->size(), Index);
assert(result && "Could not resolve symbolic name"); result=result;
@@ -729,10 +782,10 @@ SimplifyConstraint(const char *Constraint, TargetInfo &Target,
break;
}
}
-
+
Constraint++;
}
-
+
return Result;
}
@@ -741,9 +794,9 @@ llvm::Value* CodeGenFunction::EmitAsmInput(const AsmStmt &S,
const Expr *InputExpr,
std::string &ConstraintStr) {
llvm::Value *Arg;
- if (Info.allowsRegister() || !Info.allowsMemory()) {
+ if (Info.allowsRegister() || !Info.allowsMemory()) {
const llvm::Type *Ty = ConvertType(InputExpr->getType());
-
+
if (Ty->isSingleValueType()) {
Arg = EmitScalarExpr(InputExpr);
} else {
@@ -752,9 +805,9 @@ llvm::Value* CodeGenFunction::EmitAsmInput(const AsmStmt &S,
uint64_t Size = CGM.getTargetData().getTypeSizeInBits(Ty);
if (Size <= 64 && llvm::isPowerOf2_64(Size)) {
- Ty = llvm::IntegerType::get(Size);
+ Ty = llvm::IntegerType::get(VMContext, Size);
Ty = llvm::PointerType::getUnqual(Ty);
-
+
Arg = Builder.CreateLoad(Builder.CreateBitCast(Dest.getAddress(), Ty));
} else {
Arg = Dest.getAddress();
@@ -767,7 +820,7 @@ llvm::Value* CodeGenFunction::EmitAsmInput(const AsmStmt &S,
Arg = Dest.getAddress();
ConstraintStr += '*';
}
-
+
return Arg;
}
@@ -777,7 +830,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
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) {
@@ -789,19 +842,19 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
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++) {
+ 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));
@@ -811,9 +864,9 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
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;
@@ -826,16 +879,16 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
std::vector<llvm::Value*> InOutArgs;
std::vector<const llvm::Type*> InOutArgTypes;
- for (unsigned i = 0, e = S.getNumOutputs(); i != e; i++) {
+ 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 += ',';
@@ -848,7 +901,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
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.
@@ -861,30 +914,29 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
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);
+ ResultRegTypes.back() = llvm::IntegerType::get(VMContext, (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
@@ -894,9 +946,9 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
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);
@@ -904,14 +956,14 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
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
@@ -921,46 +973,46 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
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));
+ llvm::IntegerType::get(VMContext, LLVMPointerWidth));
unsigned OutputSize = (unsigned)getContext().getTypeSize(OutputTy);
- Arg = Builder.CreateZExt(Arg, llvm::IntegerType::get(OutputSize));
+ Arg = Builder.CreateZExt(Arg, llvm::IntegerType::get(VMContext, 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()) {
@@ -971,22 +1023,22 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
const llvm::Type *ResultType;
if (ResultRegTypes.empty())
- ResultType = llvm::Type::VoidTy;
+ ResultType = llvm::Type::getVoidTy(VMContext);
else if (ResultRegTypes.size() == 1)
ResultType = ResultRegTypes[0];
else
- ResultType = llvm::StructType::get(ResultRegTypes);
-
- const llvm::FunctionType *FTy =
+ ResultType = llvm::StructType::get(VMContext, ResultRegTypes);
+
+ const llvm::FunctionType *FTy =
llvm::FunctionType::get(ResultType, ArgTypes, false);
-
- llvm::InlineAsm *IA =
- llvm::InlineAsm::get(FTy, AsmString, Constraints,
+
+ 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) {
@@ -997,10 +1049,10 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
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]) {
@@ -1008,14 +1060,14 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
// 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));
-
+ Tmp = Builder.CreateTrunc(Tmp, llvm::IntegerType::get(VMContext, (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
index 820e1bd6..2a06f51 100644
--- a/lib/CodeGen/CGValue.h
+++ b/lib/CodeGen/CGValue.h
@@ -24,7 +24,7 @@ namespace llvm {
namespace clang {
class ObjCPropertyRefExpr;
- class ObjCKVCRefExpr;
+ class ObjCImplicitSetterGetterRefExpr;
namespace CodeGen {
@@ -37,14 +37,14 @@ class RValue {
// 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.
@@ -58,13 +58,13 @@ public:
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;
@@ -106,7 +106,7 @@ public:
/// 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*
@@ -118,21 +118,15 @@ class LValue {
// 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;
@@ -143,16 +137,18 @@ class LValue {
// Obj-C property reference expression
const ObjCPropertyRefExpr *PropertyRefExpr;
// ObjC 'implicit' property reference expression
- const ObjCKVCRefExpr *KVCRefExpr;
+ const ObjCImplicitSetterGetterRefExpr *KVCRefExpr;
};
- bool Volatile:1;
- // FIXME: set but never used, what effect should it have?
- bool Restrict:1;
+ // 'const' is unused here
+ Qualifiers Quals;
// objective-c's ivar
bool Ivar:1;
+ // objective-c's ivar is an array
+ bool ObjIsArray:1;
+
// LValue is non-gc'able for any reason, including being a parameter or local
// variable.
bool NonGC: 1;
@@ -160,21 +156,17 @@ class LValue {
// Lvalue is a global reference of an objective-c object
bool GlobalObjCRef : 1;
- // objective-c's gc attributes
- unsigned ObjCType : 2;
-
-
-
+ Expr *BaseIvarExp;
private:
- static void SetQualifiers(unsigned Qualifiers, LValue& R) {
- R.Volatile = (Qualifiers&QualType::Volatile)!=0;
- R.Restrict = (Qualifiers&QualType::Restrict)!=0;
+ void SetQualifiers(Qualifiers Quals) {
+ this->Quals = Quals;
+
// 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;
+ this->Ivar = this->ObjIsArray = this->NonGC = this->GlobalObjCRef = false;
+ this->BaseIvarExp = 0;
}
-
+
public:
bool isSimple() const { return LVType == Simple; }
bool isVectorElt() const { return LVType == VectorElt; }
@@ -183,39 +175,38 @@ public:
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 isVolatileQualified() const { return Quals.hasVolatile(); }
+ bool isRestrictQualified() const { return Quals.hasRestrict(); }
+ unsigned getVRQualifiers() const {
+ return Quals.getCVRQualifiers() & ~Qualifiers::Const;
}
-
+
bool isObjCIvar() const { return Ivar; }
+ bool isObjCArray() const { return ObjIsArray; }
bool isNonGC () const { return NonGC; }
bool isGlobalObjCRef() const { return GlobalObjCRef; }
- bool isObjCWeak() const { return ObjCType == Weak; }
- bool isObjCStrong() const { return ObjCType == Strong; }
+ bool isObjCWeak() const { return Quals.getObjCGCAttr() == Qualifiers::Weak; }
+ bool isObjCStrong() const { return Quals.getObjCGCAttr() == Qualifiers::Strong; }
+ Expr *getBaseIvarExp() const { return BaseIvarExp; }
+ void setBaseIvarExp(Expr *V) { BaseIvarExp = V; }
+
+ unsigned getAddressSpace() const { return Quals.getAddressSpace(); }
+
static void SetObjCIvar(LValue& R, bool iValue) {
R.Ivar = iValue;
}
-
+ static void SetObjCArray(LValue& R, bool iValue) {
+ R.ObjIsArray = 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
@@ -248,51 +239,49 @@ public:
}
// 'implicit' property ref lvalue
- const ObjCKVCRefExpr *getKVCRefExpr() const {
+ const ObjCImplicitSetterGetterRefExpr *getKVCRefExpr() const {
assert(isKVCRef());
return KVCRefExpr;
}
- static LValue MakeAddr(llvm::Value *V, unsigned Qualifiers,
- QualType::GCAttrTypes GCAttrs = QualType::GCNone) {
+ static LValue MakeAddr(llvm::Value *V, Qualifiers Quals) {
LValue R;
R.LVType = Simple;
R.V = V;
- SetQualifiers(Qualifiers,R);
- SetObjCType(GCAttrs, R);
+ R.SetQualifiers(Quals);
return R;
}
-
+
static LValue MakeVectorElt(llvm::Value *Vec, llvm::Value *Idx,
- unsigned Qualifiers) {
+ unsigned CVR) {
LValue R;
R.LVType = VectorElt;
R.V = Vec;
R.VectorIdx = Idx;
- SetQualifiers(Qualifiers,R);
+ R.SetQualifiers(Qualifiers::fromCVRMask(CVR));
return R;
}
-
+
static LValue MakeExtVectorElt(llvm::Value *Vec, llvm::Constant *Elts,
- unsigned Qualifiers) {
+ unsigned CVR) {
LValue R;
R.LVType = ExtVectorElt;
R.V = Vec;
R.VectorElts = Elts;
- SetQualifiers(Qualifiers,R);
+ R.SetQualifiers(Qualifiers::fromCVRMask(CVR));
return R;
}
static LValue MakeBitfield(llvm::Value *V, unsigned short StartBit,
unsigned short Size, bool IsSigned,
- unsigned Qualifiers) {
+ unsigned CVR) {
LValue R;
R.LVType = BitField;
R.V = V;
R.BitfieldData.StartBit = StartBit;
R.BitfieldData.Size = Size;
R.BitfieldData.IsSigned = IsSigned;
- SetQualifiers(Qualifiers,R);
+ R.SetQualifiers(Qualifiers::fromCVRMask(CVR));
return R;
}
@@ -300,19 +289,20 @@ public:
// 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) {
+ unsigned CVR) {
LValue R;
R.LVType = PropertyRef;
R.PropertyRefExpr = E;
- SetQualifiers(Qualifiers,R);
+ R.SetQualifiers(Qualifiers::fromCVRMask(CVR));
return R;
}
-
- static LValue MakeKVCRef(const ObjCKVCRefExpr *E, unsigned Qualifiers) {
+
+ static LValue MakeKVCRef(const ObjCImplicitSetterGetterRefExpr *E,
+ unsigned CVR) {
LValue R;
R.LVType = KVCRef;
R.KVCRefExpr = E;
- SetQualifiers(Qualifiers,R);
+ R.SetQualifiers(Qualifiers::fromCVRMask(CVR));
return R;
}
};
diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp
new file mode 100644
index 0000000..41f7eef
--- /dev/null
+++ b/lib/CodeGen/CGVtable.cpp
@@ -0,0 +1,557 @@
+//===--- CGVtable.cpp - Emit LLVM Code for C++ vtables --------------------===//
+//
+// 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 of virtual tables.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CodeGenModule.h"
+#include "CodeGenFunction.h"
+
+#include "clang/AST/RecordLayout.h"
+
+using namespace clang;
+using namespace CodeGen;
+
+class VtableBuilder {
+public:
+ /// Index_t - Vtable index type.
+ typedef uint64_t Index_t;
+private:
+ std::vector<llvm::Constant *> &methods;
+ std::vector<llvm::Constant *> submethods;
+ llvm::Type *Ptr8Ty;
+ /// Class - The most derived class that this vtable is being built for.
+ const CXXRecordDecl *Class;
+ /// BLayout - Layout for the most derived class that this vtable is being
+ /// built for.
+ const ASTRecordLayout &BLayout;
+ llvm::SmallSet<const CXXRecordDecl *, 32> IndirectPrimary;
+ llvm::SmallSet<const CXXRecordDecl *, 32> SeenVBase;
+ llvm::Constant *rtti;
+ llvm::LLVMContext &VMContext;
+ CodeGenModule &CGM; // Per-module state.
+ /// Index - Maps a method decl into a vtable index. Useful for virtual
+ /// dispatch codegen.
+ llvm::DenseMap<const CXXMethodDecl *, Index_t> Index;
+ llvm::DenseMap<const CXXMethodDecl *, Index_t> VCall;
+ llvm::DenseMap<const CXXMethodDecl *, Index_t> VCallOffset;
+ llvm::DenseMap<const CXXRecordDecl *, Index_t> VBIndex;
+ typedef std::pair<Index_t, Index_t> CallOffset;
+ typedef llvm::DenseMap<const CXXMethodDecl *, CallOffset> Thunks_t;
+ Thunks_t Thunks;
+ typedef llvm::DenseMap<const CXXMethodDecl *,
+ std::pair<std::pair<CallOffset, CallOffset>,
+ CanQualType> > CovariantThunks_t;
+ CovariantThunks_t CovariantThunks;
+ std::vector<Index_t> VCalls;
+ typedef CXXRecordDecl::method_iterator method_iter;
+ // FIXME: Linkage should follow vtable
+ const bool Extern;
+ const uint32_t LLVMPointerWidth;
+ Index_t extra;
+public:
+ VtableBuilder(std::vector<llvm::Constant *> &meth,
+ const CXXRecordDecl *c,
+ CodeGenModule &cgm)
+ : methods(meth), Class(c), BLayout(cgm.getContext().getASTRecordLayout(c)),
+ rtti(cgm.GenerateRtti(c)), VMContext(cgm.getModule().getContext()),
+ CGM(cgm), Extern(true),
+ LLVMPointerWidth(cgm.getContext().Target.getPointerWidth(0)) {
+ Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0);
+ }
+
+ llvm::DenseMap<const CXXMethodDecl *, Index_t> &getIndex() { return Index; }
+ llvm::DenseMap<const CXXRecordDecl *, Index_t> &getVBIndex()
+ { return VBIndex; }
+
+ llvm::Constant *wrap(Index_t i) {
+ llvm::Constant *m;
+ m = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), i);
+ return llvm::ConstantExpr::getIntToPtr(m, Ptr8Ty);
+ }
+
+ llvm::Constant *wrap(llvm::Constant *m) {
+ return llvm::ConstantExpr::getBitCast(m, Ptr8Ty);
+ }
+
+ void GenerateVBaseOffsets(std::vector<llvm::Constant *> &offsets,
+ const CXXRecordDecl *RD, uint64_t Offset,
+ bool updateVBIndex, Index_t current_vbindex) {
+ for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
+ e = RD->bases_end(); i != e; ++i) {
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+ Index_t next_vbindex = current_vbindex;
+ if (i->isVirtual() && !SeenVBase.count(Base)) {
+ SeenVBase.insert(Base);
+ int64_t BaseOffset = -(Offset/8) + BLayout.getVBaseClassOffset(Base)/8;
+ llvm::Constant *m = wrap(BaseOffset);
+ m = wrap((0?700:0) + BaseOffset);
+ if (updateVBIndex) {
+ next_vbindex = (ssize_t)(-(offsets.size()*LLVMPointerWidth/8)
+ - 3*LLVMPointerWidth/8);
+ VBIndex[Base] = next_vbindex;
+ }
+ offsets.push_back(m);
+ }
+ // We also record offsets for non-virtual bases to closest enclosing
+ // virtual base. We do this so that we don't have to search
+ // for the nearst virtual base class when generating thunks.
+ if (updateVBIndex && VBIndex.count(Base) == 0)
+ VBIndex[Base] = next_vbindex;
+ GenerateVBaseOffsets(offsets, Base, Offset, updateVBIndex, next_vbindex);
+ }
+ }
+
+ void StartNewTable() {
+ SeenVBase.clear();
+ }
+
+ Index_t VBlookup(CXXRecordDecl *D, CXXRecordDecl *B);
+
+ /// getVbaseOffset - Returns the index into the vtable for the virtual base
+ /// offset for the given (B) virtual base of the derived class D.
+ Index_t getVbaseOffset(QualType qB, QualType qD) {
+ qD = qD->getAs<PointerType>()->getPointeeType();
+ qB = qB->getAs<PointerType>()->getPointeeType();
+ CXXRecordDecl *D = cast<CXXRecordDecl>(qD->getAs<RecordType>()->getDecl());
+ CXXRecordDecl *B = cast<CXXRecordDecl>(qB->getAs<RecordType>()->getDecl());
+ if (D != Class)
+ return VBlookup(D, B);
+ llvm::DenseMap<const CXXRecordDecl *, Index_t>::iterator i;
+ i = VBIndex.find(B);
+ if (i != VBIndex.end())
+ return i->second;
+
+ assert(false && "FIXME: Base not found");
+ return 0;
+ }
+
+ bool OverrideMethod(const CXXMethodDecl *MD, llvm::Constant *m,
+ bool MorallyVirtual, Index_t Offset) {
+ typedef CXXMethodDecl::method_iterator meth_iter;
+
+ // FIXME: Don't like the nested loops. For very large inheritance
+ // heirarchies we could have a table on the side with the final overridder
+ // and just replace each instance of an overridden method once. Would be
+ // nice to measure the cost/benefit on real code.
+
+ for (meth_iter mi = MD->begin_overridden_methods(),
+ e = MD->end_overridden_methods();
+ mi != e; ++mi) {
+ const CXXMethodDecl *OMD = *mi;
+ llvm::Constant *om;
+ om = CGM.GetAddrOfFunction(OMD, Ptr8Ty);
+ om = llvm::ConstantExpr::getBitCast(om, Ptr8Ty);
+
+ for (Index_t i = 0, e = submethods.size();
+ i != e; ++i) {
+ // FIXME: begin_overridden_methods might be too lax, covariance */
+ if (submethods[i] != om)
+ continue;
+ QualType nc_oret = OMD->getType()->getAs<FunctionType>()->getResultType();
+ CanQualType oret = CGM.getContext().getCanonicalType(nc_oret);
+ QualType nc_ret = MD->getType()->getAs<FunctionType>()->getResultType();
+ CanQualType ret = CGM.getContext().getCanonicalType(nc_ret);
+ CallOffset ReturnOffset = std::make_pair(0, 0);
+ if (oret != ret) {
+ // FIXME: calculate offsets for covariance
+ Index_t nv = 0;
+ if (CovariantThunks.count(OMD)) {
+ oret = CovariantThunks[OMD].second;
+ CovariantThunks.erase(OMD);
+ }
+ ReturnOffset = std::make_pair(nv, getVbaseOffset(oret, ret));
+ }
+ Index[MD] = i;
+ submethods[i] = m;
+
+ Thunks.erase(OMD);
+ if (MorallyVirtual) {
+ Index_t &idx = VCall[OMD];
+ if (idx == 0) {
+ VCallOffset[MD] = Offset/8;
+ idx = VCalls.size()+1;
+ VCalls.push_back(0);
+ } else {
+ VCallOffset[MD] = VCallOffset[OMD];
+ VCalls[idx-1] = -VCallOffset[OMD] + Offset/8;
+ }
+ VCall[MD] = idx;
+ CallOffset ThisOffset;
+ // FIXME: calculate non-virtual offset
+ ThisOffset = std::make_pair(0, -((idx+extra+2)*LLVMPointerWidth/8));
+ if (ReturnOffset.first || ReturnOffset.second)
+ CovariantThunks[MD] = std::make_pair(std::make_pair(ThisOffset,
+ ReturnOffset),
+ oret);
+ else
+ Thunks[MD] = ThisOffset;
+ return true;
+ }
+
+ // FIXME: finish off
+ int64_t O = VCallOffset[OMD] - Offset/8;
+ if (O || ReturnOffset.first || ReturnOffset.second) {
+ CallOffset ThisOffset = std::make_pair(O, 0);
+
+ if (ReturnOffset.first || ReturnOffset.second)
+ CovariantThunks[MD] = std::make_pair(std::make_pair(ThisOffset,
+ ReturnOffset),
+ oret);
+ else
+ Thunks[MD] = ThisOffset;
+ }
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ void InstallThunks() {
+ for (Thunks_t::iterator i = Thunks.begin(), e = Thunks.end();
+ i != e; ++i) {
+ const CXXMethodDecl *MD = i->first;
+ Index_t idx = Index[MD];
+ Index_t nv_O = i->second.first;
+ Index_t v_O = i->second.second;
+ submethods[idx] = CGM.BuildThunk(MD, Extern, nv_O, v_O);
+ }
+ Thunks.clear();
+ for (CovariantThunks_t::iterator i = CovariantThunks.begin(),
+ e = CovariantThunks.end();
+ i != e; ++i) {
+ const CXXMethodDecl *MD = i->first;
+ Index_t idx = Index[MD];
+ Index_t nv_t = i->second.first.first.first;
+ Index_t v_t = i->second.first.first.second;
+ Index_t nv_r = i->second.first.second.first;
+ Index_t v_r = i->second.first.second.second;
+ submethods[idx] = CGM.BuildCovariantThunk(MD, Extern, nv_t, v_t, nv_r,
+ v_r);
+ }
+ CovariantThunks.clear();
+ }
+
+ void OverrideMethods(std::vector<std::pair<const CXXRecordDecl *,
+ int64_t> > *Path, bool MorallyVirtual) {
+ for (std::vector<std::pair<const CXXRecordDecl *,
+ int64_t> >::reverse_iterator i =Path->rbegin(),
+ e = Path->rend(); i != e; ++i) {
+ const CXXRecordDecl *RD = i->first;
+ int64_t Offset = i->second;
+ for (method_iter mi = RD->method_begin(), me = RD->method_end(); mi != me;
+ ++mi) {
+ if (!mi->isVirtual())
+ continue;
+
+ const CXXMethodDecl *MD = *mi;
+ llvm::Constant *m = 0;
+ if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(MD))
+ m = wrap(CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete));
+ else {
+ const FunctionProtoType *FPT =
+ MD->getType()->getAs<FunctionProtoType>();
+ const llvm::Type *Ty =
+ CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
+ FPT->isVariadic());
+
+ m = wrap(CGM.GetAddrOfFunction(MD, Ty));
+ }
+
+ OverrideMethod(MD, m, MorallyVirtual, Offset);
+ }
+ }
+ }
+
+ void AddMethod(const CXXMethodDecl *MD, bool MorallyVirtual, Index_t Offset) {
+ llvm::Constant *m = 0;
+ if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(MD))
+ m = wrap(CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete));
+ else {
+ const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
+ const llvm::Type *Ty =
+ CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
+ FPT->isVariadic());
+
+ m = wrap(CGM.GetAddrOfFunction(MD, Ty));
+ }
+
+ // If we can find a previously allocated slot for this, reuse it.
+ if (OverrideMethod(MD, m, MorallyVirtual, Offset))
+ return;
+
+ // else allocate a new slot.
+ Index[MD] = submethods.size();
+ submethods.push_back(m);
+ if (MorallyVirtual) {
+ VCallOffset[MD] = Offset/8;
+ Index_t &idx = VCall[MD];
+ // Allocate the first one, after that, we reuse the previous one.
+ if (idx == 0) {
+ idx = VCalls.size()+1;
+ VCalls.push_back(0);
+ }
+ }
+ }
+
+ void AddMethods(const CXXRecordDecl *RD, bool MorallyVirtual,
+ Index_t Offset) {
+ for (method_iter mi = RD->method_begin(), me = RD->method_end(); mi != me;
+ ++mi)
+ if (mi->isVirtual())
+ AddMethod(*mi, MorallyVirtual, Offset);
+ }
+
+ void NonVirtualBases(const CXXRecordDecl *RD, const ASTRecordLayout &Layout,
+ const CXXRecordDecl *PrimaryBase,
+ bool PrimaryBaseWasVirtual, bool MorallyVirtual,
+ int64_t Offset) {
+ for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
+ e = RD->bases_end(); i != e; ++i) {
+ if (i->isVirtual())
+ continue;
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+ if (Base != PrimaryBase || PrimaryBaseWasVirtual) {
+ uint64_t o = Offset + Layout.getBaseClassOffset(Base);
+ StartNewTable();
+ std::vector<std::pair<const CXXRecordDecl *,
+ int64_t> > S;
+ S.push_back(std::make_pair(RD, Offset));
+ GenerateVtableForBase(Base, MorallyVirtual, o, false, &S);
+ }
+ }
+ }
+
+ Index_t end(const CXXRecordDecl *RD, std::vector<llvm::Constant *> &offsets,
+ const ASTRecordLayout &Layout,
+ const CXXRecordDecl *PrimaryBase,
+ bool PrimaryBaseWasVirtual, bool MorallyVirtual,
+ int64_t Offset, bool ForVirtualBase) {
+ StartNewTable();
+ extra = 0;
+ // FIXME: Cleanup.
+ if (!ForVirtualBase) {
+ // then virtual base offsets...
+ for (std::vector<llvm::Constant *>::reverse_iterator i = offsets.rbegin(),
+ e = offsets.rend(); i != e; ++i)
+ methods.push_back(*i);
+ }
+
+ // The vcalls come first...
+ for (std::vector<Index_t>::reverse_iterator i=VCalls.rbegin(),
+ e=VCalls.rend();
+ i != e; ++i)
+ methods.push_back(wrap((0?600:0) + *i));
+ VCalls.clear();
+
+ if (ForVirtualBase) {
+ // then virtual base offsets...
+ for (std::vector<llvm::Constant *>::reverse_iterator i = offsets.rbegin(),
+ e = offsets.rend(); i != e; ++i)
+ methods.push_back(*i);
+ }
+
+ methods.push_back(wrap(-(Offset/8)));
+ methods.push_back(rtti);
+ Index_t AddressPoint = methods.size();
+
+ InstallThunks();
+ methods.insert(methods.end(), submethods.begin(), submethods.end());
+ submethods.clear();
+
+ // and then the non-virtual bases.
+ NonVirtualBases(RD, Layout, PrimaryBase, PrimaryBaseWasVirtual,
+ MorallyVirtual, Offset);
+ return AddressPoint;
+ }
+
+ void Primaries(const CXXRecordDecl *RD, bool MorallyVirtual, int64_t Offset) {
+ if (!RD->isDynamicClass())
+ return;
+
+ const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
+ const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
+ const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual();
+
+ // vtables are composed from the chain of primaries.
+ if (PrimaryBase) {
+ if (PrimaryBaseWasVirtual)
+ IndirectPrimary.insert(PrimaryBase);
+ Primaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset);
+ }
+
+ // And add the virtuals for the class to the primary vtable.
+ AddMethods(RD, MorallyVirtual, Offset);
+ }
+
+ int64_t GenerateVtableForBase(const CXXRecordDecl *RD,
+ bool MorallyVirtual = false, int64_t Offset = 0,
+ bool ForVirtualBase = false,
+ std::vector<std::pair<const CXXRecordDecl *,
+ int64_t> > *Path = 0) {
+ if (!RD->isDynamicClass())
+ return 0;
+
+ const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
+ const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
+ const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual();
+
+ std::vector<llvm::Constant *> offsets;
+ extra = 0;
+ GenerateVBaseOffsets(offsets, RD, Offset, !ForVirtualBase, 0);
+ if (ForVirtualBase)
+ extra = offsets.size();
+
+ // vtables are composed from the chain of primaries.
+ if (PrimaryBase) {
+ if (PrimaryBaseWasVirtual)
+ IndirectPrimary.insert(PrimaryBase);
+ Primaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset);
+ }
+
+ // And add the virtuals for the class to the primary vtable.
+ AddMethods(RD, MorallyVirtual, Offset);
+
+ if (Path)
+ OverrideMethods(Path, MorallyVirtual);
+
+ return end(RD, offsets, Layout, PrimaryBase, PrimaryBaseWasVirtual,
+ MorallyVirtual, Offset, ForVirtualBase);
+ }
+
+ void GenerateVtableForVBases(const CXXRecordDecl *RD,
+ int64_t Offset = 0,
+ std::vector<std::pair<const CXXRecordDecl *,
+ int64_t> > *Path = 0) {
+ bool alloc = false;
+ if (Path == 0) {
+ alloc = true;
+ Path = new std::vector<std::pair<const CXXRecordDecl *,
+ int64_t> >;
+ }
+ // FIXME: We also need to override using all paths to a virtual base,
+ // right now, we just process the first path
+ Path->push_back(std::make_pair(RD, Offset));
+ for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
+ e = RD->bases_end(); i != e; ++i) {
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+ if (i->isVirtual() && !IndirectPrimary.count(Base)) {
+ // Mark it so we don't output it twice.
+ IndirectPrimary.insert(Base);
+ StartNewTable();
+ int64_t BaseOffset = BLayout.getVBaseClassOffset(Base);
+ GenerateVtableForBase(Base, true, BaseOffset, true, Path);
+ }
+ int64_t BaseOffset = Offset;
+ if (i->isVirtual())
+ BaseOffset = BLayout.getVBaseClassOffset(Base);
+ if (Base->getNumVBases())
+ GenerateVtableForVBases(Base, BaseOffset, Path);
+ }
+ Path->pop_back();
+ if (alloc)
+ delete Path;
+ }
+};
+
+
+VtableBuilder::Index_t VtableBuilder::VBlookup(CXXRecordDecl *D,
+ CXXRecordDecl *B) {
+ return CGM.getVtableInfo().getVirtualBaseOffsetIndex(D, B);
+}
+
+int64_t CGVtableInfo::getMethodVtableIndex(const CXXMethodDecl *MD) {
+ MD = MD->getCanonicalDecl();
+
+ MethodVtableIndicesTy::iterator I = MethodVtableIndices.find(MD);
+ if (I != MethodVtableIndices.end())
+ return I->second;
+
+ const CXXRecordDecl *RD = MD->getParent();
+
+ std::vector<llvm::Constant *> methods;
+ // FIXME: This seems expensive. Can we do a partial job to get
+ // just this data.
+ VtableBuilder b(methods, RD, CGM);
+ b.GenerateVtableForBase(RD);
+ b.GenerateVtableForVBases(RD);
+
+ MethodVtableIndices.insert(b.getIndex().begin(),
+ b.getIndex().end());
+
+ I = MethodVtableIndices.find(MD);
+ assert(I != MethodVtableIndices.end() && "Did not find index!");
+ return I->second;
+}
+
+int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD,
+ const CXXRecordDecl *VBase) {
+ ClassPairTy ClassPair(RD, VBase);
+
+ VirtualBaseClassIndiciesTy::iterator I =
+ VirtualBaseClassIndicies.find(ClassPair);
+ if (I != VirtualBaseClassIndicies.end())
+ return I->second;
+
+ std::vector<llvm::Constant *> methods;
+ // FIXME: This seems expensive. Can we do a partial job to get
+ // just this data.
+ VtableBuilder b(methods, RD, CGM);
+ b.GenerateVtableForBase(RD);
+ b.GenerateVtableForVBases(RD);
+
+ for (llvm::DenseMap<const CXXRecordDecl *, uint64_t>::iterator I =
+ b.getVBIndex().begin(), E = b.getVBIndex().end(); I != E; ++I) {
+ // Insert all types.
+ ClassPairTy ClassPair(RD, I->first);
+
+ VirtualBaseClassIndicies.insert(std::make_pair(ClassPair, I->second));
+ }
+
+ I = VirtualBaseClassIndicies.find(ClassPair);
+ assert(I != VirtualBaseClassIndicies.end() && "Did not find index!");
+
+ return I->second;
+}
+
+llvm::Value *CodeGenFunction::GenerateVtable(const CXXRecordDecl *RD) {
+ llvm::SmallString<256> OutName;
+ llvm::raw_svector_ostream Out(OutName);
+ mangleCXXVtable(CGM.getMangleContext(), RD, Out);
+
+ llvm::GlobalVariable::LinkageTypes linktype;
+ linktype = llvm::GlobalValue::WeakAnyLinkage;
+ std::vector<llvm::Constant *> methods;
+ llvm::Type *Ptr8Ty=llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),0);
+ int64_t AddressPoint;
+
+ VtableBuilder b(methods, RD, CGM);
+
+ // First comes the vtables for all the non-virtual bases...
+ AddressPoint = b.GenerateVtableForBase(RD);
+
+ // then the vtables for all the virtual bases.
+ b.GenerateVtableForVBases(RD);
+
+ llvm::Constant *C;
+ llvm::ArrayType *type = llvm::ArrayType::get(Ptr8Ty, methods.size());
+ C = llvm::ConstantArray::get(type, methods);
+ llvm::Value *vtable = new llvm::GlobalVariable(CGM.getModule(), type, true,
+ linktype, C, Out.str());
+ vtable = Builder.CreateBitCast(vtable, Ptr8Ty);
+ vtable = Builder.CreateGEP(vtable,
+ llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
+ AddressPoint*LLVMPointerWidth/8));
+ return vtable;
+}
diff --git a/lib/CodeGen/CGVtable.h b/lib/CodeGen/CGVtable.h
new file mode 100644
index 0000000..69fb1f1
--- /dev/null
+++ b/lib/CodeGen/CGVtable.h
@@ -0,0 +1,61 @@
+//===--- CGVtable.h - Emit LLVM Code for C++ vtables ----------------------===//
+//
+// 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 of virtual tables.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_CODEGEN_CGVTABLE_H
+#define CLANG_CODEGEN_CGVTABLE_H
+
+#include "llvm/ADT/DenseMap.h"
+
+namespace clang {
+ class CXXMethodDecl;
+ class CXXRecordDecl;
+
+namespace CodeGen {
+ class CodeGenModule;
+
+class CGVtableInfo {
+ CodeGenModule &CGM;
+
+ /// MethodVtableIndices - Contains the index (relative to the vtable address
+ /// point) where the function pointer for a virtual function is stored.
+ typedef llvm::DenseMap<const CXXMethodDecl *, int64_t> MethodVtableIndicesTy;
+ MethodVtableIndicesTy MethodVtableIndices;
+
+ typedef std::pair<const CXXRecordDecl *,
+ const CXXRecordDecl *> ClassPairTy;
+
+ /// VirtualBaseClassIndicies - Contains the index into the vtable where the
+ /// offsets for virtual bases of a class are stored.
+ typedef llvm::DenseMap<ClassPairTy, int64_t> VirtualBaseClassIndiciesTy;
+ VirtualBaseClassIndiciesTy VirtualBaseClassIndicies;
+public:
+ CGVtableInfo(CodeGenModule &CGM)
+ : CGM(CGM) { }
+
+ /// getMethodVtableIndex - Return the index (relative to the vtable address
+ /// point) where the function pointer for the given virtual function is
+ /// stored.
+ int64_t getMethodVtableIndex(const CXXMethodDecl *MD);
+
+ /// getVirtualBaseOffsetIndex - Return the index (relative to the vtable
+ /// address point) where the offset of the virtual base that contains the
+ /// given Base is stored, otherwise, if no virtual base contains the given
+ /// class, return 0. Base must be a virtual base class or an unambigious
+ /// base.
+ int64_t getVirtualBaseOffsetIndex(const CXXRecordDecl *RD,
+ const CXXRecordDecl *VBase);
+};
+
+}
+}
+#endif
diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt
index c206a3b..2f46313 100644
--- a/lib/CodeGen/CMakeLists.txt
+++ b/lib/CodeGen/CMakeLists.txt
@@ -1,22 +1,27 @@
set(LLVM_NO_RTTI 1)
add_clang_library(clangCodeGen
- CGBuiltin.cpp
CGBlocks.cpp
- CGCall.cpp
+ CGBuiltin.cpp
CGCXX.cpp
+ CGCXXClass.cpp
+ CGCXXExpr.cpp
CGCXXTemp.cpp
+ CGCall.cpp
CGDebugInfo.cpp
CGDecl.cpp
+ CGExpr.cpp
CGExprAgg.cpp
CGExprComplex.cpp
CGExprConstant.cpp
- CGExpr.cpp
CGExprScalar.cpp
CGObjC.cpp
CGObjCGNU.cpp
CGObjCMac.cpp
+ CGRecordLayoutBuilder.cpp
+ CGRtti.cpp
CGStmt.cpp
+ CGVtable.cpp
CodeGenFunction.cpp
CodeGenModule.cpp
CodeGenTypes.cpp
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index c3f9364..5206f44 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -19,15 +19,16 @@
#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)
+CodeGenFunction::CodeGenFunction(CodeGenModule &cgm)
: BlockFunction(cgm, *this, Builder), CGM(cgm),
Target(CGM.getContext().Target),
- DebugInfo(0), SwitchInsn(0), CaseRangeBlock(0), InvokeDest(0),
+ Builder(cgm.getModule().getContext()),
+ DebugInfo(0), IndirectGotoSwitch(0),
+ SwitchInsn(0), CaseRangeBlock(0), InvokeDest(0),
CXXThisDecl(0) {
LLVMIntTy = ConvertType(getContext().IntTy);
LLVMPointerWidth = Target.getPointerWidth(0);
@@ -41,7 +42,7 @@ ASTContext &CodeGenFunction::getContext() const {
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());
}
@@ -66,11 +67,8 @@ const llvm::Type *CodeGenFunction::ConvertType(QualType 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();
+ return T->isRecordType() || T->isArrayType() || T->isAnyComplexType() ||
+ T->isMemberFunctionPointerType();
}
void CodeGenFunction::EmitReturnBlock() {
@@ -81,11 +79,12 @@ void CodeGenFunction::EmitReturnBlock() {
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())
+ // We have a valid insert point, reuse it if it is empty or there are no
+ // explicit jumps to the return block.
+ if (CurBB->empty() || ReturnBlock->use_empty()) {
+ ReturnBlock->replaceAllUsesWith(CurBB);
delete ReturnBlock;
- else
+ } else
EmitBlock(ReturnBlock);
return;
}
@@ -94,7 +93,7 @@ void CodeGenFunction::EmitReturnBlock() {
// 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 =
+ 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.
@@ -113,17 +112,14 @@ void CodeGenFunction::EmitReturnBlock() {
}
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).
+
+ // Emit function epilog (to return).
EmitReturnBlock();
// Emit debug descriptor for function end.
@@ -140,10 +136,12 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
Ptr->eraseFromParent();
}
-void CodeGenFunction::StartFunction(const Decl *D, QualType RetTy,
+void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
llvm::Function *Fn,
const FunctionArgList &Args,
SourceLocation StartLoc) {
+ const Decl *D = GD.getDecl();
+
DidCallStackSave = false;
CurCodeDecl = CurFuncDecl = D;
FnRetTy = RetTy;
@@ -155,28 +153,31 @@ void CodeGenFunction::StartFunction(const Decl *D, QualType RetTy,
// 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, "",
+ llvm::Value *Undef = llvm::UndefValue::get(llvm::Type::getInt32Ty(VMContext));
+ AllocaInsertPt = new llvm::BitCastInst(Undef,
+ llvm::Type::getInt32Ty(VMContext), "",
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);
+ if (isa<FunctionDecl>(D)) {
+ DI->EmitFunctionStart(CGM.getMangledName(GD), RetTy, CurFn, Builder);
} else {
// Just use LLVM function name.
- DI->EmitFunctionStart(Fn->getName().c_str(),
+
+ // FIXME: Remove unnecessary conversion to std::string when API settles.
+ DI->EmitFunctionStart(std::string(Fn->getName()).c_str(),
RetTy, CurFn, Builder);
}
}
@@ -184,7 +185,7 @@ void CodeGenFunction::StartFunction(const Decl *D, QualType RetTy,
// 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();
@@ -196,40 +197,96 @@ void CodeGenFunction::StartFunction(const Decl *D, QualType RetTy,
}
}
-void CodeGenFunction::GenerateCode(const FunctionDecl *FD,
+void CodeGenFunction::GenerateCode(GlobalDecl GD,
llvm::Function *Fn) {
+ const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
+
// Check if we should generate debug info for this function.
- if (CGM.getDebugInfo() && !FD->hasAttr<NodebugAttr>())
+ 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"),
+ &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();
+ const FunctionProtoType* FProto = FD->getType()->getAs<FunctionProtoType>();
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),
+ Args.push_back(std::make_pair(FD->getParamDecl(i),
FProto->getArgType(i)));
}
// FIXME: Support CXXTryStmt here, too.
if (const CompoundStmt *S = FD->getCompoundBody()) {
- StartFunction(FD, FD->getResultType(), Fn, Args, S->getLBracLoc());
+ StartFunction(GD, FD->getResultType(), Fn, Args, S->getLBracLoc());
+ const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(FD);
+ llvm::BasicBlock *DtorEpilogue = 0;
+ if (DD) {
+ DtorEpilogue = createBasicBlock("dtor.epilogue");
+
+ PushCleanupBlock(DtorEpilogue);
+ }
+
+ if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD))
+ EmitCtorPrologue(CD, GD.getCtorType());
EmitStmt(S);
+
+ if (DD) {
+ CleanupBlockInfo Info = PopCleanupBlock();
+
+ assert(Info.CleanupBlock == DtorEpilogue && "Block mismatch!");
+ EmitBlock(DtorEpilogue);
+ EmitDtorEpilogue(DD, GD.getDtorType());
+
+ if (Info.SwitchBlock)
+ EmitBlock(Info.SwitchBlock);
+ if (Info.EndBlock)
+ EmitBlock(Info.EndBlock);
+ }
FinishFunction(S->getRBracLoc());
+ } else if (FD->isImplicit()) {
+ const CXXRecordDecl *ClassDecl =
+ cast<CXXRecordDecl>(FD->getDeclContext());
+ (void) ClassDecl;
+ if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) {
+ // FIXME: For C++0x, we want to look for implicit *definitions* of
+ // these special member functions, rather than implicit *declarations*.
+ if (CD->isCopyConstructor(getContext())) {
+ assert(!ClassDecl->hasUserDeclaredCopyConstructor() &&
+ "Cannot synthesize a non-implicit copy constructor");
+ SynthesizeCXXCopyConstructor(CD, GD.getCtorType(), Fn, Args);
+ } else if (CD->isDefaultConstructor()) {
+ assert(!ClassDecl->hasUserDeclaredConstructor() &&
+ "Cannot synthesize a non-implicit default constructor.");
+ SynthesizeDefaultConstructor(CD, GD.getCtorType(), Fn, Args);
+ } else {
+ assert(false && "Implicit constructor cannot be synthesized");
+ }
+ } else if (const CXXDestructorDecl *CD = dyn_cast<CXXDestructorDecl>(FD)) {
+ assert(!ClassDecl->hasUserDeclaredDestructor() &&
+ "Cannot synthesize a non-implicit destructor");
+ SynthesizeDefaultDestructor(CD, GD.getDtorType(), Fn, Args);
+ } else if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
+ assert(MD->isCopyAssignment() &&
+ !ClassDecl->hasUserDeclaredCopyAssignment() &&
+ "Cannot synthesize a method that is not an implicit-defined "
+ "copy constructor");
+ SynthesizeCXXCopyAssignment(MD, Fn, Args);
+ } else {
+ assert(false && "Cannot synthesize unknown implicit function");
+ }
}
// Destroy the 'this' declaration.
@@ -243,27 +300,27 @@ void CodeGenFunction::GenerateCode(const FunctionDecl *FD,
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;
}
@@ -276,13 +333,13 @@ 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() ||
+ 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;
}
@@ -296,7 +353,7 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond,
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) {
@@ -306,20 +363,20 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond,
// 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) {
@@ -329,31 +386,31 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond,
// 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.
@@ -376,15 +433,6 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *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,
@@ -392,13 +440,8 @@ void CodeGenFunction::ErrorUnsupported(const Stmt *S, const char *Type,
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);
+ const llvm::Type *BP = llvm::Type::getInt8PtrTy(VMContext);
if (DestPtr->getType() != BP)
DestPtr = Builder.CreateBitCast(DestPtr, BP, "tmp");
@@ -408,93 +451,141 @@ void CodeGenFunction::EmitMemSetToZero(llvm::Value *DestPtr, QualType 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);
+ const llvm::Type *IntPtr = llvm::IntegerType::get(VMContext,
+ LLVMPointerWidth);
Builder.CreateCall4(CGM.getMemSetFn(), DestPtr,
- llvm::ConstantInt::getNullValue(llvm::Type::Int8Ty),
+ llvm::Constant::getNullValue(llvm::Type::getInt8Ty(VMContext)),
// TypeInfo.first describes size in bits.
llvm::ConstantInt::get(IntPtr, TypeInfo.first/8),
- llvm::ConstantInt::get(llvm::Type::Int32Ty,
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
TypeInfo.second/8));
}
-void CodeGenFunction::EmitIndirectSwitches() {
- llvm::BasicBlock *Default;
+unsigned CodeGenFunction::GetIDForAddrOfLabel(const LabelStmt *L) {
+ // Use LabelIDs.size()+1 as the new ID if one hasn't been assigned.
+ unsigned &Entry = LabelIDs[L];
+ if (Entry) return Entry;
+
+ Entry = LabelIDs.size();
+
+ // If this is the first "address taken" of a label and the indirect goto has
+ // already been seen, add this to it.
+ if (IndirectGotoSwitch) {
+ // If this is the first address-taken label, set it as the default dest.
+ if (Entry == 1)
+ IndirectGotoSwitch->setSuccessor(0, getBasicBlockForLabel(L));
+ else {
+ // Otherwise add it to the switch as a new dest.
+ const llvm::IntegerType *Int32Ty = llvm::Type::getInt32Ty(VMContext);
+ IndirectGotoSwitch->addCase(llvm::ConstantInt::get(Int32Ty, Entry),
+ getBasicBlockForLabel(L));
+ }
+ }
- if (IndirectSwitches.empty())
- return;
+ return Entry;
+}
+
+llvm::BasicBlock *CodeGenFunction::GetIndirectGotoBlock() {
+ // If we already made the switch stmt for indirect goto, return its block.
+ if (IndirectGotoSwitch) return IndirectGotoSwitch->getParent();
+
+ EmitBlock(createBasicBlock("indirectgoto"));
+
+ // Create the PHI node that indirect gotos will add entries to.
+ llvm::Value *DestVal =
+ Builder.CreatePHI(llvm::Type::getInt32Ty(VMContext), "indirect.goto.dest");
+
+ // Create the switch instruction. For now, set the insert block to this block
+ // which will be fixed as labels are added.
+ IndirectGotoSwitch = Builder.CreateSwitch(DestVal, Builder.GetInsertBlock());
+
+ // Clear the insertion point to indicate we are in unreachable code.
+ Builder.ClearInsertionPoint();
+ // If we already have labels created, add them.
if (!LabelIDs.empty()) {
- Default = getBasicBlockForLabel(LabelIDs.begin()->first);
+ // Invert LabelID's so that the order is determinstic.
+ std::vector<const LabelStmt*> AddrTakenLabelsByID;
+ AddrTakenLabelsByID.resize(LabelIDs.size());
+
+ for (std::map<const LabelStmt*,unsigned>::iterator
+ LI = LabelIDs.begin(), LE = LabelIDs.end(); LI != LE; ++LI) {
+ assert(LI->second-1 < AddrTakenLabelsByID.size() &&
+ "Numbering inconsistent");
+ AddrTakenLabelsByID[LI->second-1] = LI->first;
+ }
+
+ // Set the default entry as the first block.
+ IndirectGotoSwitch->setSuccessor(0,
+ getBasicBlockForLabel(AddrTakenLabelsByID[0]));
+
+ const llvm::IntegerType *Int32Ty = llvm::Type::getInt32Ty(VMContext);
+
+ // FIXME: The iteration order of this is nondeterminstic!
+ for (unsigned i = 1, e = AddrTakenLabelsByID.size(); i != e; ++i)
+ IndirectGotoSwitch->addCase(llvm::ConstantInt::get(Int32Ty, i+1),
+ getBasicBlockForLabel(AddrTakenLabelsByID[i]));
} else {
- // No possible targets for indirect goto, just emit an infinite
- // loop.
- Default = createBasicBlock("indirectgoto.loop", CurFn);
- llvm::BranchInst::Create(Default, Default);
+ // Otherwise, create a dead block and set it as the default dest. This will
+ // be removed by the optimizers after the indirect goto is set up.
+ llvm::BasicBlock *Dummy = createBasicBlock("indgoto.dummy");
+ EmitBlock(Dummy);
+ IndirectGotoSwitch->setSuccessor(0, Dummy);
+ Builder.CreateUnreachable();
+ Builder.ClearInsertionPoint();
}
- 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));
- }
- }
+ return IndirectGotoSwitch->getParent();
}
-llvm::Value *CodeGenFunction::GetVLASize(const VariableArrayType *VAT)
-{
- llvm::Value *&SizeEntry = VLASizeMap[VAT];
-
+llvm::Value *CodeGenFunction::GetVLASize(const VariableArrayType *VAT) {
+ llvm::Value *&SizeEntry = VLASizeMap[VAT->getSizeExpr()];
+
assert(SizeEntry && "Did not emit size for type");
return SizeEntry;
}
-llvm::Value *CodeGenFunction::EmitVLASize(QualType Ty)
-{
+llvm::Value *CodeGenFunction::EmitVLASize(QualType Ty) {
assert(Ty->isVariablyModifiedType() &&
"Must pass variably modified type to EmitVLASizes!");
-
+
+ EnsureInsertPoint();
+
if (const VariableArrayType *VAT = getContext().getAsVariableArrayType(Ty)) {
- llvm::Value *&SizeEntry = VLASizeMap[VAT];
-
+ llvm::Value *&SizeEntry = VLASizeMap[VAT->getSizeExpr()];
+
if (!SizeEntry) {
+ const llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
+
// Get the element size;
- llvm::Value *ElemSize;
-
QualType ElemTy = VAT->getElementType();
-
- const llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
-
+ llvm::Value *ElemSize;
if (ElemTy->isVariableArrayType())
ElemSize = EmitVLASize(ElemTy);
- else {
+ 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)) {
+ }
+
+ 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;
}
-
+
+ const PointerType *PT = Ty->getAs<PointerType>();
+ assert(PT && "unknown VM type!");
+ EmitVLASize(PT->getPointeeType());
return 0;
}
@@ -505,32 +596,29 @@ llvm::Value* CodeGenFunction::EmitVAListRef(const Expr* E) {
return EmitLValue(E).getAddress();
}
-void CodeGenFunction::PushCleanupBlock(llvm::BasicBlock *CleanupBlock)
-{
+void CodeGenFunction::PushCleanupBlock(llvm::BasicBlock *CleanupBlock) {
CleanupEntries.push_back(CleanupEntry(CleanupBlock));
}
-void CodeGenFunction::EmitCleanupBlocks(size_t OldCleanupStackSize)
-{
- assert(CleanupEntries.size() >= OldCleanupStackSize &&
+void CodeGenFunction::EmitCleanupBlocks(size_t OldCleanupStackSize) {
+ assert(CleanupEntries.size() >= OldCleanupStackSize &&
"Cleanup stack mismatch!");
-
+
while (CleanupEntries.size() > OldCleanupStackSize)
EmitCleanupBlock();
}
-CodeGenFunction::CleanupBlockInfo CodeGenFunction::PopCleanupBlock()
-{
+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,
@@ -538,12 +626,12 @@ CodeGenFunction::CleanupBlockInfo CodeGenFunction::PopCleanupBlock()
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();
@@ -553,32 +641,32 @@ CodeGenFunction::CleanupBlockInfo CodeGenFunction::PopCleanupBlock()
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,
+ llvm::Value *DestCodePtr = CreateTempAlloca(llvm::Type::getInt32Ty(VMContext),
"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,
+ 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),
+ Builder.CreateStore(llvm::Constant::getNullValue(llvm::Type::getInt32Ty(VMContext)),
DestCodePtr);
} else
Builder.ClearInsertionPoint();
@@ -586,39 +674,39 @@ CodeGenFunction::CleanupBlockInfo CodeGenFunction::PopCleanupBlock()
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);
+ ID = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 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,
+ ID = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
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,
+ llvm::ConstantInt *ID = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
SI->getNumSuccessors());
// Store the jump destination before the branch instruction.
@@ -626,89 +714,86 @@ CodeGenFunction::CleanupBlockInfo CodeGenFunction::PopCleanupBlock()
// 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()
-{
+void CodeGenFunction::EmitCleanupBlock() {
CleanupBlockInfo Info = PopCleanupBlock();
-
+
llvm::BasicBlock *CurBB = Builder.GetInsertBlock();
- if (CurBB && !CurBB->getTerminator() &&
+ if (CurBB && !CurBB->getTerminator() &&
Info.CleanupBlock->getNumUses() == 0) {
CurBB->getInstList().splice(CurBB->end(), Info.CleanupBlock->getInstList());
delete Info.CleanupBlock;
- } else
+ } 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() &&
+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)
-{
+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
index 72c4aa4..722d002 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -22,6 +22,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/ValueHandle.h"
#include <map>
+#include "CodeGenModule.h"
#include "CGBlocks.h"
#include "CGBuilder.h"
#include "CGCall.h"
@@ -30,6 +31,7 @@
namespace llvm {
class BasicBlock;
+ class LLVMContext;
class Module;
class SwitchInst;
class Value;
@@ -38,6 +40,7 @@ namespace llvm {
namespace clang {
class ASTContext;
class CXXDestructorDecl;
+ class CXXTryStmt;
class Decl;
class EnumConstantDecl;
class FunctionDecl;
@@ -145,7 +148,11 @@ public:
~CleanupScope() {
CGF.PushCleanupBlock(CleanupBB);
- CGF.Builder.SetInsertPoint(CurBB);
+ // FIXME: This is silly, move this into the builder.
+ if (CurBB)
+ CGF.Builder.SetInsertPoint(CurBB);
+ else
+ CGF.Builder.ClearInsertionPoint();
}
};
@@ -160,20 +167,20 @@ public:
/// this behavior for branches?
void EmitBranchThroughCleanup(llvm::BasicBlock *Dest);
- /// PushConditionalTempDestruction - Should be called before a conditional
+ /// PushConditionalTempDestruction - Should be called before a conditional
/// part of an expression is emitted. For example, before the RHS of the
/// expression below is emitted:
- ///
+ ///
/// b && f(T());
///
/// This is used to make sure that any temporaryes created in the conditional
/// branch are only destroyed if the branch is taken.
void PushConditionalTempDestruction();
-
- /// PopConditionalTempDestruction - Should be called after a conditional
+
+ /// PopConditionalTempDestruction - Should be called after a conditional
/// part of an expression has been emitted.
void PopConditionalTempDestruction();
-
+
private:
CGDebugInfo* DebugInfo;
@@ -182,10 +189,12 @@ private:
/// 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;
+ /// IndirectGotoSwitch - The first time an indirect goto is seen we create a
+ /// block with the switch for the indirect gotos. Every time we see the
+ /// address of a label taken, we add the label to the indirect goto. Every
+ /// subsequent indirect goto is codegen'd as a jump to the
+ /// IndirectGotoSwitch's basic block.
+ llvm::SwitchInst *IndirectGotoSwitch;
/// LocalDeclMap - This keeps track of the LLVM allocas or globals for local C
/// decls.
@@ -218,9 +227,12 @@ private:
llvm::BasicBlock *InvokeDest;
// VLASizeMap - This keeps track of the associated size for each VLA type.
+ // We track this by the size expression rather than the type itself because
+ // in certain situations, like a const qualifier applied to an VLA typedef,
+ // multiple VLA types can share the same size expression.
// 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;
+ llvm::DenseMap<const Expr*, llvm::Value*> VLASizeMap;
/// DidCallStackSave - Whether llvm.stacksave has been called. Used to avoid
/// calling llvm.stacksave for multiple VLAs in the same scope.
@@ -252,36 +264,46 @@ private:
/// CXXThisDecl - When parsing an C++ function, this will hold the implicit
/// 'this' declaration.
ImplicitParamDecl *CXXThisDecl;
-
+
/// CXXLiveTemporaryInfo - Holds information about a live C++ temporary.
struct CXXLiveTemporaryInfo {
/// Temporary - The live temporary.
const CXXTemporary *Temporary;
-
+
/// ThisPtr - The pointer to the temporary.
llvm::Value *ThisPtr;
-
+
/// DtorBlock - The destructor block.
llvm::BasicBlock *DtorBlock;
-
+
/// CondPtr - If this is a conditional temporary, this is the pointer to
/// the condition variable that states whether the destructor should be
/// called or not.
llvm::Value *CondPtr;
-
+
CXXLiveTemporaryInfo(const CXXTemporary *temporary,
llvm::Value *thisptr, llvm::BasicBlock *dtorblock,
llvm::Value *condptr)
- : Temporary(temporary), ThisPtr(thisptr), DtorBlock(dtorblock),
+ : Temporary(temporary), ThisPtr(thisptr), DtorBlock(dtorblock),
CondPtr(condptr) { }
};
-
+
llvm::SmallVector<CXXLiveTemporaryInfo, 4> LiveTemporaries;
- /// ConditionalTempDestructionStack - Contains the number of live temporaries
+ /// ConditionalTempDestructionStack - Contains the number of live temporaries
/// when PushConditionalTempDestruction was called. This is used so that
/// we know how many temporaries were created by a certain expression.
llvm::SmallVector<size_t, 4> ConditionalTempDestructionStack;
+
+
+ /// ByrefValueInfoMap - For each __block variable, contains a pair of the LLVM
+ /// type as well as the field number that contains the actual data.
+ llvm::DenseMap<const ValueDecl *, std::pair<const llvm::Type *,
+ unsigned> > ByRefValueInfo;
+
+ /// getByrefValueFieldNumber - Given a declaration, returns the LLVM field
+ /// number that holds the value.
+ unsigned getByRefValueLLVMField(const ValueDecl *VD) const;
public:
CodeGenFunction(CodeGenModule &cgm);
@@ -292,6 +314,8 @@ public:
llvm::BasicBlock *getInvokeDest() { return InvokeDest; }
void setInvokeDest(llvm::BasicBlock *B) { InvokeDest = B; }
+ llvm::LLVMContext &getLLVMContext() { return VMContext; }
+
//===--------------------------------------------------------------------===//
// Objective-C
//===--------------------------------------------------------------------===//
@@ -332,12 +356,10 @@ public:
llvm::Value *LoadBlockStruct();
llvm::Value *GetAddrOfBlockDecl(const BlockDeclRefExpr *E);
+ const llvm::Type *BuildByRefType(const ValueDecl *D);
- const llvm::Type *BuildByRefType(QualType Ty, uint64_t Align);
-
- void GenerateCode(const FunctionDecl *FD,
- llvm::Function *Fn);
- void StartFunction(const Decl *D, QualType RetTy,
+ void GenerateCode(GlobalDecl GD, llvm::Function *Fn);
+ void StartFunction(GlobalDecl GD, QualType RetTy,
llvm::Function *Fn,
const FunctionArgList &Args,
SourceLocation StartLoc);
@@ -350,6 +372,44 @@ public:
/// legal to call this function even if there is no current insertion point.
void FinishFunction(SourceLocation EndLoc=SourceLocation());
+ /// GenerateVtable - Generate the vtable for the given type.
+ llvm::Value *GenerateVtable(const CXXRecordDecl *RD);
+
+ /// GenerateThunk - Generate a thunk for the given method
+ llvm::Constant *GenerateThunk(llvm::Function *Fn, const CXXMethodDecl *MD,
+ bool Extern, int64_t nv, int64_t v);
+ llvm::Constant *GenerateCovariantThunk(llvm::Function *Fn,
+ const CXXMethodDecl *MD, bool Extern,
+ int64_t nv_t, int64_t v_t,
+ int64_t nv_r, int64_t v_r);
+
+ void EmitCtorPrologue(const CXXConstructorDecl *CD, CXXCtorType Type);
+
+ void SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor,
+ CXXCtorType Type,
+ llvm::Function *Fn,
+ const FunctionArgList &Args);
+
+ void SynthesizeCXXCopyAssignment(const CXXMethodDecl *CD,
+ llvm::Function *Fn,
+ const FunctionArgList &Args);
+
+ void SynthesizeDefaultConstructor(const CXXConstructorDecl *Ctor,
+ CXXCtorType Type,
+ llvm::Function *Fn,
+ const FunctionArgList &Args);
+
+ void SynthesizeDefaultDestructor(const CXXDestructorDecl *Dtor,
+ CXXDtorType Type,
+ llvm::Function *Fn,
+ const FunctionArgList &Args);
+
+ /// EmitDtorEpilogue - Emit all code that comes at the end of class's
+ /// destructor. This is to call destructors on members and base classes
+ /// in reverse order of their construction.
+ void EmitDtorEpilogue(const CXXDestructorDecl *Dtor,
+ CXXDtorType Type);
+
/// 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.
@@ -380,9 +440,9 @@ public:
llvm::Function *Parent=0,
llvm::BasicBlock *InsertBefore=0) {
#ifdef NDEBUG
- return llvm::BasicBlock::Create("", Parent, InsertBefore);
+ return llvm::BasicBlock::Create(VMContext, "", Parent, InsertBefore);
#else
- return llvm::BasicBlock::Create(Name, Parent, InsertBefore);
+ return llvm::BasicBlock::Create(VMContext, Name, Parent, InsertBefore);
#endif
}
@@ -439,6 +499,12 @@ public:
// Helpers
//===--------------------------------------------------------------------===//
+ Qualifiers MakeQualifiers(QualType T) {
+ Qualifiers Quals = T.getQualifiers();
+ Quals.setObjCGCAttr(getContext().getObjCGCAttrKind(T));
+ return Quals;
+ }
+
/// CreateTempAlloca - This creates a alloca and inserts it into the entry
/// block.
llvm::AllocaInst *CreateTempAlloca(const llvm::Type *Ty,
@@ -455,7 +521,8 @@ public:
///
/// \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);
+ bool IsAggLocVolatile = false, bool IgnoreResult = false,
+ bool IsInitializer = 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.
@@ -463,8 +530,8 @@ public:
/// 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);
+ RValue EmitAnyExprToTemp(const Expr *E, bool IsAggLocVolatile = false,
+ bool IsInitializer = false);
/// EmitAggregateCopy - Emit an aggrate copy.
///
@@ -479,9 +546,6 @@ public:
/// 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);
@@ -493,6 +557,7 @@ public:
static unsigned getAccessedFieldNo(unsigned Idx, const llvm::Constant *Elts);
unsigned GetIDForAddrOfLabel(const LabelStmt *L);
+ llvm::BasicBlock *GetIndirectGotoBlock();
/// EmitMemSetToZero - Generate code to memset a value of the given type to 0.
void EmitMemSetToZero(llvm::Value *DestPtr, QualType Ty);
@@ -506,6 +571,8 @@ public:
// 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.
+ ///
+ /// This function can be called with a null (unreachable) insert point.
llvm::Value *EmitVLASize(QualType Ty);
// GetVLASize - Returns an LLVM value that corresponds to the size in bytes
@@ -515,27 +582,87 @@ public:
/// LoadCXXThis - Load the value of 'this'. This function is only valid while
/// generating code for an C++ member function.
llvm::Value *LoadCXXThis();
+
+ /// GetAddressCXXOfBaseClass - This function will add the necessary delta
+ /// to the load of 'this' and returns address of the base class.
+ // FIXME. This currently only does a derived to non-virtual base conversion.
+ // Other kinds of conversions will come later.
+ llvm::Value *GetAddressCXXOfBaseClass(llvm::Value *BaseValue,
+ const CXXRecordDecl *ClassDecl,
+ const CXXRecordDecl *BaseClassDecl,
+ bool NullCheckValue);
- void EmitCXXConstructorCall(const CXXConstructorDecl *D, CXXCtorType Type,
+ llvm::Value *
+ GetVirtualCXXBaseClassOffset(llvm::Value *This,
+ const CXXRecordDecl *ClassDecl,
+ const CXXRecordDecl *BaseClassDecl);
+
+ void EmitClassAggrMemberwiseCopy(llvm::Value *DestValue,
+ llvm::Value *SrcValue,
+ const ArrayType *Array,
+ const CXXRecordDecl *BaseClassDecl,
+ QualType Ty);
+
+ void EmitClassAggrCopyAssignment(llvm::Value *DestValue,
+ llvm::Value *SrcValue,
+ const ArrayType *Array,
+ const CXXRecordDecl *BaseClassDecl,
+ QualType Ty);
+
+ void EmitClassMemberwiseCopy(llvm::Value *DestValue, llvm::Value *SrcValue,
+ const CXXRecordDecl *ClassDecl,
+ const CXXRecordDecl *BaseClassDecl,
+ QualType Ty);
+
+ void EmitClassCopyAssignment(llvm::Value *DestValue, llvm::Value *SrcValue,
+ const CXXRecordDecl *ClassDecl,
+ const CXXRecordDecl *BaseClassDecl,
+ QualType Ty);
+
+ void EmitCXXConstructorCall(const CXXConstructorDecl *D, CXXCtorType Type,
llvm::Value *This,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd);
+ void EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
+ const ConstantArrayType *ArrayTy,
+ llvm::Value *ArrayPtr);
+ void EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
+ llvm::Value *NumElements,
+ llvm::Value *ArrayPtr);
+
+ void EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
+ const ArrayType *Array,
+ llvm::Value *This);
+
void EmitCXXDestructorCall(const CXXDestructorDecl *D, CXXDtorType Type,
llvm::Value *This);
-
+
void PushCXXTemporary(const CXXTemporary *Temporary, llvm::Value *Ptr);
void PopCXXTemporary();
-
+
llvm::Value *EmitCXXNewExpr(const CXXNewExpr *E);
-
+ void EmitCXXDeleteExpr(const CXXDeleteExpr *E);
+
//===--------------------------------------------------------------------===//
// Declaration Emission
//===--------------------------------------------------------------------===//
+ /// EmitDecl - Emit a declaration.
+ ///
+ /// This function can be called with a null (unreachable) insert point.
void EmitDecl(const Decl &D);
+
+ /// EmitBlockVarDecl - Emit a block variable declaration.
+ ///
+ /// This function can be called with a null (unreachable) insert point.
void EmitBlockVarDecl(const VarDecl &D);
+
+ /// EmitLocalBlockVarDecl - Emit a local block variable declaration.
+ ///
+ /// This function can be called with a null (unreachable) insert point.
void EmitLocalBlockVarDecl(const VarDecl &D);
+
void EmitStaticBlockVarDecl(const VarDecl &D);
/// EmitParmDecl - Emit a ParmVarDecl or an ImplicitParamDecl.
@@ -593,6 +720,8 @@ public:
void EmitObjCAtThrowStmt(const ObjCAtThrowStmt &S);
void EmitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt &S);
+ void EmitCXXTryStmt(const CXXTryStmt &S);
+
//===--------------------------------------------------------------------===//
// LValue Expression Emission
//===--------------------------------------------------------------------===//
@@ -685,7 +814,7 @@ public:
LValue EmitExtVectorElementExpr(const ExtVectorElementExpr *E);
LValue EmitMemberExpr(const MemberExpr *E);
LValue EmitCompoundLiteralLValue(const CompoundLiteralExpr *E);
- LValue EmitConditionalOperator(const ConditionalOperator *E);
+ LValue EmitConditionalOperatorLValue(const ConditionalOperator *E);
LValue EmitCastLValue(const CastExpr *E);
llvm::Value *EmitIvarOffset(const ObjCInterfaceDecl *Interface,
@@ -704,11 +833,12 @@ public:
LValue EmitCXXConditionDeclLValue(const CXXConditionDeclExpr *E);
LValue EmitCXXConstructLValue(const CXXConstructExpr *E);
LValue EmitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *E);
+ LValue EmitCXXExprWithTemporariesLValue(const CXXExprWithTemporaries *E);
LValue EmitObjCMessageExprLValue(const ObjCMessageExpr *E);
LValue EmitObjCIvarRefLValue(const ObjCIvarRefExpr *E);
LValue EmitObjCPropertyRefLValue(const ObjCPropertyRefExpr *E);
- LValue EmitObjCKVCRefLValue(const ObjCKVCRefExpr *E);
+ LValue EmitObjCKVCRefLValue(const ObjCImplicitSetterGetterRefExpr *E);
LValue EmitObjCSuperExprLValue(const ObjCSuperExpr *E);
LValue EmitStmtExprLValue(const StmtExpr *E);
@@ -727,24 +857,28 @@ public:
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);
-
+
+ llvm::Value *BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *&This,
+ const llvm::Type *Ty);
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 EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E);
RValue EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E,
const CXXMethodDecl *MD);
+
- RValue EmitBuiltinExpr(const FunctionDecl *FD,
+ RValue EmitBuiltinExpr(const FunctionDecl *FD,
unsigned BuiltinID, const CallExpr *E);
RValue EmitBlockCallExpr(const CallExpr *E);
@@ -772,8 +906,9 @@ public:
/// 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);
-
+ RValue EmitReferenceBindingToExpr(const Expr* E, QualType DestType,
+ bool IsInitializer = false);
+
//===--------------------------------------------------------------------===//
// Expression Emission
//===--------------------------------------------------------------------===//
@@ -782,7 +917,7 @@ public:
/// EmitScalarExpr - Emit the computation of the specified expression of LLVM
/// scalar type, returning the result.
- llvm::Value *EmitScalarExpr(const Expr *E , bool IgnoreResultAssign=false);
+ 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.
@@ -800,7 +935,13 @@ public:
/// 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);
+ bool IgnoreResult = false, bool IsInitializer = false,
+ bool RequiresGCollection = false);
+
+ /// EmitGCMemmoveCollectable - Emit special API for structs with object
+ /// pointers.
+ void EmitGCMemmoveCollectable(llvm::Value *DestPtr, llvm::Value *SrcPtr,
+ QualType Ty);
/// EmitComplexExpr - Emit the computation of the specified expression of
/// complex type, returning the result.
@@ -827,17 +968,33 @@ public:
llvm::GlobalValue::LinkageTypes
Linkage);
- /// GenerateStaticCXXBlockVarDecl - Create the initializer for a C++
+ /// EmitStaticCXXBlockVarDeclInit - Create the initializer for a C++
/// runtime initialized static block var decl.
- void GenerateStaticCXXBlockVarDeclInit(const VarDecl &D,
- llvm::GlobalVariable *GV);
+ void EmitStaticCXXBlockVarDeclInit(const VarDecl &D,
+ llvm::GlobalVariable *GV);
+
+ /// EmitCXXGlobalVarDeclInit - Create the initializer for a C++
+ /// variable with global storage.
+ void EmitCXXGlobalVarDeclInit(const VarDecl &D, llvm::Constant *DeclPtr);
+
+ /// EmitCXXGlobalDtorRegistration - Emits a call to register the global ptr
+ /// with the C++ runtime so that its destructor will be called at exit.
+ void EmitCXXGlobalDtorRegistration(const CXXDestructorDecl *Dtor,
+ llvm::Constant *DeclPtr);
+
+ /// GenerateCXXGlobalInitFunc - Generates code for initializing global
+ /// variables.
+ void GenerateCXXGlobalInitFunc(llvm::Function *Fn,
+ const VarDecl **Decls,
+ unsigned NumDecls);
void EmitCXXConstructExpr(llvm::Value *Dest, const CXXConstructExpr *E);
-
+
RValue EmitCXXExprWithTemporaries(const CXXExprWithTemporaries *E,
- llvm::Value *AggLoc = 0,
- bool isAggLocVolatile = false);
-
+ llvm::Value *AggLoc = 0,
+ bool IsAggLocVolatile = false,
+ bool IsInitializer = false);
+
//===--------------------------------------------------------------------===//
// Internal Helpers
//===--------------------------------------------------------------------===//
@@ -860,10 +1017,6 @@ public:
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
@@ -882,7 +1035,7 @@ private:
void ExpandTypeToArgs(QualType Ty, RValue Src,
llvm::SmallVector<llvm::Value*, 16> &Args);
- llvm::Value* EmitAsmInput(const AsmStmt &S,
+ llvm::Value* EmitAsmInput(const AsmStmt &S,
const TargetInfo::ConstraintInfo &Info,
const Expr *InputExpr, std::string &ConstraintStr);
@@ -895,9 +1048,9 @@ private:
/// 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
+ /// 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,
@@ -912,21 +1065,21 @@ private:
QualType ArgType = *I;
assert(getContext().getCanonicalType(ArgType.getNonReferenceType()).
- getTypePtr() ==
- getContext().getCanonicalType(Arg->getType()).getTypePtr() &&
+ getTypePtr() ==
+ getContext().getCanonicalType(Arg->getType()).getTypePtr() &&
"type mismatch in call argument!");
-
- Args.push_back(std::make_pair(EmitCallArg(*Arg, ArgType),
+
+ 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
+
+ // Either we've emitted all the call args, or we have a call to a
// variadic function.
- assert((Arg == ArgEnd || CallArgTypeInfo->isVariadic()) &&
+ 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();
@@ -935,7 +1088,7 @@ private:
}
}
};
-
+
} // end namespace CodeGen
} // end namespace clang
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index d88a37a..36ad7f5 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -39,8 +39,10 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CompileOptions &compileOpts,
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) {
+ TheTargetData(TD), Diags(diags), Types(C, M, TD), MangleCtx(C),
+ VtableInfo(*this), Runtime(0),
+ MemCpyFn(0), MemMoveFn(0), MemSetFn(0), CFConstantStringClassRef(0),
+ VMContext(M.getContext()) {
if (!Features.ObjC1)
Runtime = 0;
@@ -61,6 +63,9 @@ CodeGenModule::~CodeGenModule() {
}
void CodeGenModule::Release() {
+ // We need to call this first because it can add deferred declarations.
+ EmitCXXGlobalInitFunc();
+
EmitDeferred();
if (Runtime)
if (llvm::Function *ObjCInitFunction = Runtime->ModuleInitFunction())
@@ -77,7 +82,7 @@ void CodeGenModule::ErrorUnsupported(const Stmt *S, const char *Type,
bool OmitOnError) {
if (OmitOnError && getDiags().hasErrorOccurred())
return;
- unsigned DiagID = getDiags().getCustomDiagID(Diagnostic::Error,
+ unsigned DiagID = getDiags().getCustomDiagID(Diagnostic::Error,
"cannot compile this %0 yet");
std::string Msg = Type;
getDiags().Report(Context.getFullLoc(S->getLocStart()), DiagID)
@@ -90,13 +95,13 @@ void CodeGenModule::ErrorUnsupported(const Decl *D, const char *Type,
bool OmitOnError) {
if (OmitOnError && getDiags().hasErrorOccurred())
return;
- unsigned DiagID = getDiags().getCustomDiagID(Diagnostic::Error,
+ unsigned DiagID = getDiags().getCustomDiagID(Diagnostic::Error,
"cannot compile this %0 yet");
std::string Msg = Type;
getDiags().Report(Context.getFullLoc(D->getLocation()), DiagID) << Msg;
}
-LangOptions::VisibilityMode
+LangOptions::VisibilityMode
CodeGenModule::getDeclVisibilityMode(const Decl *D) const {
if (const VarDecl *VD = dyn_cast<VarDecl>(D))
if (VD->getStorageClass() == VarDecl::PrivateExtern)
@@ -105,7 +110,7 @@ CodeGenModule::getDeclVisibilityMode(const Decl *D) const {
if (const VisibilityAttr *attr = D->getAttr<VisibilityAttr>()) {
switch (attr->getVisibility()) {
default: assert(0 && "Unknown visibility!");
- case VisibilityAttr::DefaultVisibility:
+ case VisibilityAttr::DefaultVisibility:
return LangOptions::Default;
case VisibilityAttr::HiddenVisibility:
return LangOptions::Hidden;
@@ -117,7 +122,7 @@ CodeGenModule::getDeclVisibilityMode(const Decl *D) const {
return getLangOptions().getVisibilityMode();
}
-void CodeGenModule::setGlobalVisibility(llvm::GlobalValue *GV,
+void CodeGenModule::setGlobalVisibility(llvm::GlobalValue *GV,
const Decl *D) const {
// Internal definitions always have default visibility.
if (GV->hasLocalLinkage()) {
@@ -137,13 +142,13 @@ void CodeGenModule::setGlobalVisibility(llvm::GlobalValue *GV,
}
const char *CodeGenModule::getMangledName(const GlobalDecl &GD) {
- const NamedDecl *ND = GD.getDecl();
-
+ const NamedDecl *ND = cast<NamedDecl>(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);
}
@@ -159,10 +164,10 @@ const char *CodeGenModule::getMangledName(const NamedDecl *ND) {
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)) {
+ if (!mangleName(getMangleContext(), ND, Out)) {
assert(ND->getIdentifier() && "Attempt to mangle unnamed decl.");
return ND->getNameAsCString();
}
@@ -174,7 +179,7 @@ const char *CodeGenModule::getMangledName(const NamedDecl *ND) {
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();
}
@@ -195,32 +200,32 @@ void CodeGenModule::AddGlobalDtor(llvm::Function * Dtor, int Priority) {
void CodeGenModule::EmitCtorList(const CtorList &Fns, const char *GlobalName) {
// Ctor function type is void()*.
llvm::FunctionType* CtorFTy =
- llvm::FunctionType::get(llvm::Type::VoidTy,
+ llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
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::StructType* CtorStructTy =
+ llvm::StructType::get(VMContext, llvm::Type::getInt32Ty(VMContext),
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::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
+ 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,
+ new llvm::GlobalVariable(TheModule, AT, false,
llvm::GlobalValue::AppendingLinkage,
llvm::ConstantArray::get(AT, Ctors),
- GlobalName,
- &TheModule);
+ GlobalName);
}
}
@@ -233,67 +238,56 @@ void CodeGenModule::EmitAnnotations() {
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);
+ llvm::GlobalValue *gv =
+ new llvm::GlobalVariable(TheModule, Array->getType(), false,
+ llvm::GlobalValue::AppendingLinkage, Array,
+ "llvm.global.annotations");
gv->setSection("llvm.metadata");
}
static CodeGenModule::GVALinkage
-GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD,
+GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD,
const LangOptions &Features) {
+ // Everything located semantically within an anonymous namespace is
+ // always internal.
+ if (FD->isInAnonymousNamespace())
+ return CodeGenModule::GVA_Internal;
+
// The kind of external linkage this function will have, if it is not
// inline or static.
CodeGenModule::GVALinkage External = CodeGenModule::GVA_StrongExternal;
if (Context.getLangOptions().CPlusPlus &&
- (FD->getPrimaryTemplate() || FD->getInstantiatedFromMemberFunction()) &&
- !FD->isExplicitSpecialization())
+ FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
External = CodeGenModule::GVA_TemplateInstantiation;
-
+
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
// C++ member functions defined inside the class are always inline.
if (MD->isInline() || !MD->isOutOfLine())
return CodeGenModule::GVA_CXXInline;
-
+
return External;
}
-
+
// "static" functions get internal linkage.
if (FD->getStorageClass() == FunctionDecl::Static)
return CodeGenModule::GVA_Internal;
if (!FD->isInline())
return External;
-
- // 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(Context)) {
- // GCC in C99 mode seems to use a different decision-making
- // process for extern inline, which factors in previous
- // declarations.
- if (FD->isExternGNUInline(Context))
- return CodeGenModule::GVA_C99Inline;
- // Normal inline is a strong symbol.
- return External;
- }
- // 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())
+ if (!Features.CPlusPlus || FD->hasAttr<GNUInlineAttr>()) {
+ // GNU or C99 inline semantics. Determine whether this symbol should be
+ // externally visible.
+ if (FD->isInlineDefinitionExternallyVisible())
+ return External;
+
+ // C99 inline semantics, where the symbol is not externally visible.
return CodeGenModule::GVA_C99Inline;
+ }
- return CodeGenModule::GVA_StrongExternal;
+ // C++ inline semantics
+ assert(Features.CPlusPlus && "Must be in C++ mode");
+ return CodeGenModule::GVA_CXXInline;
}
/// SetFunctionDefinitionAttributes - Set attributes for a global.
@@ -332,35 +326,35 @@ void CodeGenModule::SetFunctionDefinitionAttributes(const FunctionDecl *D,
}
void CodeGenModule::SetLLVMFunctionAttributes(const Decl *D,
- const CGFunctionInfo &Info,
+ const CGFunctionInfo &Info,
llvm::Function *F) {
+ unsigned CallingConv;
AttributeListType AttributeList;
- ConstructAttributeList(Info, D, AttributeList);
-
+ ConstructAttributeList(Info, D, AttributeList, CallingConv);
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);
+ AttributeList.size()));
+ F->setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv));
}
void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
llvm::Function *F) {
if (!Features.Exceptions && !Features.ObjCNonFragileABI)
- F->addFnAttr(llvm::Attribute::NoUnwind);
+ F->addFnAttr(llvm::Attribute::NoUnwind);
if (D->hasAttr<AlwaysInlineAttr>())
F->addFnAttr(llvm::Attribute::AlwaysInline);
-
- if (D->hasAttr<NoinlineAttr>())
+
+ if (D->hasAttr<NoInlineAttr>())
F->addFnAttr(llvm::Attribute::NoInline);
+
+ if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
+ F->setAlignment(AA->getAlignment()/8);
+ // C++ ABI requires 2-byte alignment for member functions.
+ if (F->getAlignment() < 2 && isa<CXXMethodDecl>(D))
+ F->setAlignment(2);
}
-void CodeGenModule::SetCommonAttributes(const Decl *D,
+void CodeGenModule::SetCommonAttributes(const Decl *D,
llvm::GlobalValue *GV) {
setGlobalVisibility(GV, D);
@@ -387,19 +381,19 @@ void CodeGenModule::SetFunctionAttributes(const FunctionDecl *FD,
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>() ||
+ } else if (FD->hasAttr<WeakAttr>() ||
FD->hasAttr<WeakImportAttr>()) {
// "extern_weak" is overloaded in LLVM; we probably should have
- // separate linkage types for this.
+ // separate linkage types for this.
F->setLinkage(llvm::Function::ExternalWeakLinkage);
} else {
- F->setLinkage(llvm::Function::ExternalLinkage);
+ F->setLinkage(llvm::Function::ExternalLinkage);
}
if (const SectionAttr *SA = FD->getAttr<SectionAttr>())
@@ -407,39 +401,36 @@ void CodeGenModule::SetFunctionAttributes(const FunctionDecl *FD,
}
void CodeGenModule::AddUsedGlobal(llvm::GlobalValue *GV) {
- assert(!GV->isDeclaration() &&
+ 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.
- // FIXME. Runtime indicates that there might be more 'used' symbols; but not
- // necessariy. So, this test is not accurate for emptiness.
- if (LLVMUsed.empty() && !Runtime)
+ if (LLVMUsed.empty())
return;
- llvm::Type *i8PTy = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
-
+ const llvm::Type *i8PTy = llvm::Type::getInt8PtrTy(VMContext);
+
// 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);
+ UsedArray[i] =
+ llvm::ConstantExpr::getBitCast(cast<llvm::Constant>(&*LLVMUsed[i]),
+ i8PTy);
}
-
- if (Runtime)
- Runtime->MergeMetadataGlobals(UsedArray);
+
if (UsedArray.empty())
return;
llvm::ArrayType *ATy = llvm::ArrayType::get(i8PTy, UsedArray.size());
-
- llvm::GlobalVariable *GV =
- new llvm::GlobalVariable(ATy, false,
+
+ llvm::GlobalVariable *GV =
+ new llvm::GlobalVariable(getModule(), ATy, false,
llvm::GlobalValue::AppendingLinkage,
llvm::ConstantArray::get(ATy, UsedArray),
- "llvm.used", &getModule());
+ "llvm.used");
GV->setSection("llvm.metadata");
}
@@ -458,59 +449,60 @@ void CodeGenModule::EmitDeferred() {
// 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
+/// 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
+/// {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,
+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(),
+ const llvm::Type *SBP = llvm::Type::getInt8PtrTy(VMContext);
+ llvm::Constant *anno = llvm::ConstantArray::get(VMContext,
+ AA->getAnnotation(), true);
+ llvm::Constant *unit = llvm::ConstantArray::get(VMContext,
+ M->getModuleIdentifier(),
true);
// Get the two global values corresponding to the ConstantArrays we just
// created to hold the bytes of the strings.
- const char *StringPrefix = getContext().Target.getStringSymbolPrefix(true);
- llvm::GlobalValue *annoGV =
- new llvm::GlobalVariable(anno->getType(), false,
- llvm::GlobalValue::InternalLinkage, anno,
- GV->getName() + StringPrefix, M);
+ llvm::GlobalValue *annoGV =
+ new llvm::GlobalVariable(*M, anno->getType(), false,
+ llvm::GlobalValue::PrivateLinkage, anno,
+ GV->getName());
// translation unit name string, emitted into the llvm.metadata section.
llvm::GlobalValue *unitGV =
- new llvm::GlobalVariable(unit->getType(), false,
- llvm::GlobalValue::InternalLinkage, unit,
- StringPrefix, M);
+ new llvm::GlobalVariable(*M, unit->getType(), false,
+ llvm::GlobalValue::PrivateLinkage, unit,
+ ".str");
// 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)
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), LineNo)
};
- return llvm::ConstantStruct::get(Fields, 4, false);
+ return llvm::ConstantStruct::get(VMContext, Fields, 4, false);
}
bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) {
@@ -521,12 +513,12 @@ bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) {
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Global)) {
// Constructors and destructors should never be deferred.
- if (FD->hasAttr<ConstructorAttr>() ||
+ if (FD->hasAttr<ConstructorAttr>() ||
FD->hasAttr<DestructorAttr>())
return false;
GVALinkage Linkage = GetLinkageForFunction(getContext(), 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 ||
@@ -534,16 +526,27 @@ bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) {
return true;
return false;
}
-
+
const VarDecl *VD = cast<VarDecl>(Global);
assert(VD->isFileVarDecl() && "Invalid decl");
+ // We never want to defer structs that have non-trivial constructors or
+ // destructors.
+
+ // FIXME: Handle references.
+ if (const RecordType *RT = VD->getType()->getAs<RecordType>()) {
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
+ if (!RD->hasTrivialConstructor() || !RD->hasTrivialDestructor())
+ return false;
+ }
+ }
+
return VD->getStorageClass() == VarDecl::Static;
}
void CodeGenModule::EmitGlobal(GlobalDecl GD) {
- const ValueDecl *Global = GD.getDecl();
-
+ const ValueDecl *Global = cast<ValueDecl>(GD.getDecl());
+
// If this is an alias definition (which otherwise looks like a declaration)
// emit it now.
if (Global->hasAttr<AliasAttr>())
@@ -560,8 +563,8 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
// In C++, if this is marked "extern", defer code generation.
if (getLangOptions().CPlusPlus && !VD->getInit() &&
- (VD->getStorageClass() == VarDecl::Extern ||
- VD->isExternC(getContext())))
+ (VD->getStorageClass() == VarDecl::Extern ||
+ VD->isExternC()))
return;
// In C, if this isn't a definition, defer code generation.
@@ -591,8 +594,8 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
}
void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) {
- const ValueDecl *D = GD.getDecl();
-
+ const ValueDecl *D = cast<ValueDecl>(GD.getDecl());
+
if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(D))
EmitCXXConstructor(CD, GD.getCtorType());
else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(D))
@@ -621,16 +624,16 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(const char *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 =
+ llvm::DenseMap<const char*, GlobalDecl>::iterator DDI =
DeferredDecls.find(MangledName);
if (DDI != DeferredDecls.end()) {
// Move the potentially referenced deferred decl to the DeferredDeclsToEmit
@@ -643,18 +646,33 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(const char *MangledName,
// top-level declarations.
if (FD->isThisDeclarationADefinition() && MayDeferGeneration(FD))
DeferredDeclsToEmit.push_back(D);
+ // A called constructor which has no definition or declaration need be
+ // synthesized.
+ else if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) {
+ const CXXRecordDecl *ClassDecl =
+ cast<CXXRecordDecl>(CD->getDeclContext());
+ if (CD->isCopyConstructor(getContext()))
+ DeferredCopyConstructorToEmit(D);
+ else if (!ClassDecl->hasUserDeclaredConstructor())
+ DeferredDeclsToEmit.push_back(D);
+ }
+ else if (isa<CXXDestructorDecl>(FD))
+ DeferredDestructorToEmit(D);
+ else if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD))
+ if (MD->isCopyAssignment())
+ DeferredCopyAssignmentToEmit(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,
+ Ty = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
std::vector<const llvm::Type*>(), false);
IsIncompleteFunction = true;
}
- llvm::Function *F = llvm::Function::Create(cast<llvm::FunctionType>(Ty),
+ llvm::Function *F = llvm::Function::Create(cast<llvm::FunctionType>(Ty),
llvm::Function::ExternalLinkage,
"", &getModule());
F->setName(MangledName);
@@ -665,6 +683,126 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(const char *MangledName,
return F;
}
+/// Defer definition of copy constructor(s) which need be implicitly defined.
+void CodeGenModule::DeferredCopyConstructorToEmit(GlobalDecl CopyCtorDecl) {
+ const CXXConstructorDecl *CD =
+ cast<CXXConstructorDecl>(CopyCtorDecl.getDecl());
+ const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(CD->getDeclContext());
+ if (ClassDecl->hasTrivialCopyConstructor() ||
+ ClassDecl->hasUserDeclaredCopyConstructor())
+ return;
+
+ // First make sure all direct base classes and virtual bases and non-static
+ // data mebers which need to have their copy constructors implicitly defined
+ // are defined. 12.8.p7
+ for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin();
+ Base != ClassDecl->bases_end(); ++Base) {
+ CXXRecordDecl *BaseClassDecl
+ = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ if (CXXConstructorDecl *BaseCopyCtor =
+ BaseClassDecl->getCopyConstructor(Context, 0))
+ GetAddrOfCXXConstructor(BaseCopyCtor, Ctor_Complete);
+ }
+
+ for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
+ FieldEnd = ClassDecl->field_end();
+ Field != FieldEnd; ++Field) {
+ QualType FieldType = Context.getCanonicalType((*Field)->getType());
+ if (const ArrayType *Array = Context.getAsArrayType(FieldType))
+ FieldType = Array->getElementType();
+ if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
+ if ((*Field)->isAnonymousStructOrUnion())
+ continue;
+ CXXRecordDecl *FieldClassDecl
+ = cast<CXXRecordDecl>(FieldClassType->getDecl());
+ if (CXXConstructorDecl *FieldCopyCtor =
+ FieldClassDecl->getCopyConstructor(Context, 0))
+ GetAddrOfCXXConstructor(FieldCopyCtor, Ctor_Complete);
+ }
+ }
+ DeferredDeclsToEmit.push_back(CopyCtorDecl);
+}
+
+/// Defer definition of copy assignments which need be implicitly defined.
+void CodeGenModule::DeferredCopyAssignmentToEmit(GlobalDecl CopyAssignDecl) {
+ const CXXMethodDecl *CD = cast<CXXMethodDecl>(CopyAssignDecl.getDecl());
+ const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(CD->getDeclContext());
+
+ if (ClassDecl->hasTrivialCopyAssignment() ||
+ ClassDecl->hasUserDeclaredCopyAssignment())
+ return;
+
+ // First make sure all direct base classes and virtual bases and non-static
+ // data mebers which need to have their copy assignments implicitly defined
+ // are defined. 12.8.p12
+ for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin();
+ Base != ClassDecl->bases_end(); ++Base) {
+ CXXRecordDecl *BaseClassDecl
+ = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ const CXXMethodDecl *MD = 0;
+ if (!BaseClassDecl->hasTrivialCopyAssignment() &&
+ !BaseClassDecl->hasUserDeclaredCopyAssignment() &&
+ BaseClassDecl->hasConstCopyAssignment(getContext(), MD))
+ GetAddrOfFunction(MD, 0);
+ }
+
+ for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
+ FieldEnd = ClassDecl->field_end();
+ Field != FieldEnd; ++Field) {
+ QualType FieldType = Context.getCanonicalType((*Field)->getType());
+ if (const ArrayType *Array = Context.getAsArrayType(FieldType))
+ FieldType = Array->getElementType();
+ if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
+ if ((*Field)->isAnonymousStructOrUnion())
+ continue;
+ CXXRecordDecl *FieldClassDecl
+ = cast<CXXRecordDecl>(FieldClassType->getDecl());
+ const CXXMethodDecl *MD = 0;
+ if (!FieldClassDecl->hasTrivialCopyAssignment() &&
+ !FieldClassDecl->hasUserDeclaredCopyAssignment() &&
+ FieldClassDecl->hasConstCopyAssignment(getContext(), MD))
+ GetAddrOfFunction(MD, 0);
+ }
+ }
+ DeferredDeclsToEmit.push_back(CopyAssignDecl);
+}
+
+void CodeGenModule::DeferredDestructorToEmit(GlobalDecl DtorDecl) {
+ const CXXDestructorDecl *DD = cast<CXXDestructorDecl>(DtorDecl.getDecl());
+ const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(DD->getDeclContext());
+ if (ClassDecl->hasTrivialDestructor() ||
+ ClassDecl->hasUserDeclaredDestructor())
+ return;
+
+ for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin();
+ Base != ClassDecl->bases_end(); ++Base) {
+ CXXRecordDecl *BaseClassDecl
+ = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ if (const CXXDestructorDecl *BaseDtor =
+ BaseClassDecl->getDestructor(Context))
+ GetAddrOfCXXDestructor(BaseDtor, Dtor_Complete);
+ }
+
+ for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
+ FieldEnd = ClassDecl->field_end();
+ Field != FieldEnd; ++Field) {
+ QualType FieldType = Context.getCanonicalType((*Field)->getType());
+ if (const ArrayType *Array = Context.getAsArrayType(FieldType))
+ FieldType = Array->getElementType();
+ if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
+ if ((*Field)->isAnonymousStructOrUnion())
+ continue;
+ CXXRecordDecl *FieldClassDecl
+ = cast<CXXRecordDecl>(FieldClassType->getDecl());
+ if (const CXXDestructorDecl *FieldDtor =
+ FieldClassDecl->getDestructor(Context))
+ GetAddrOfCXXDestructor(FieldDtor, Dtor_Complete);
+ }
+ }
+ DeferredDeclsToEmit.push_back(DtorDecl);
+}
+
+
/// 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).
@@ -672,8 +810,8 @@ 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);
+ Ty = getTypes().ConvertType(cast<ValueDecl>(GD.getDecl())->getType());
+ return GetOrCreateLLVMFunction(getMangledName(GD), Ty, GD);
}
/// CreateRuntimeFunction - Create a new runtime function with the specified
@@ -701,15 +839,15 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMGlobal(const char *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 =
+ llvm::DenseMap<const char*, GlobalDecl>::iterator DDI =
DeferredDecls.find(MangledName);
if (DDI != DeferredDecls.end()) {
// Move the potentially referenced deferred decl to the DeferredDeclsToEmit
@@ -717,11 +855,11 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMGlobal(const char *MangledName,
DeferredDeclsToEmit.push_back(DDI->second);
DeferredDecls.erase(DDI);
}
-
- llvm::GlobalVariable *GV =
- new llvm::GlobalVariable(Ty->getElementType(), false,
+
+ llvm::GlobalVariable *GV =
+ new llvm::GlobalVariable(getModule(), Ty->getElementType(), false,
llvm::GlobalValue::ExternalLinkage,
- 0, "", &getModule(),
+ 0, "", 0,
false, Ty->getAddressSpace());
GV->setName(MangledName);
@@ -735,13 +873,13 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMGlobal(const char *MangledName,
if (D->getStorageClass() == VarDecl::PrivateExtern)
GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
- if (D->hasAttr<WeakAttr>() ||
+ if (D->hasAttr<WeakAttr>() ||
D->hasAttr<WeakImportAttr>())
GV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
GV->setThreadLocal(D->isThreadSpecified());
}
-
+
return Entry = GV;
}
@@ -756,8 +894,8 @@ llvm::Constant *CodeGenModule::GetAddrOfGlobalVar(const VarDecl *D,
QualType ASTTy = D->getType();
if (Ty == 0)
Ty = getTypes().ConvertTypeForMem(ASTTy);
-
- const llvm::PointerType *PTy =
+
+ const llvm::PointerType *PTy =
llvm::PointerType::get(Ty, ASTTy.getAddressSpace());
return GetOrCreateLLVMGlobal(getMangledName(D), PTy, D);
}
@@ -781,7 +919,7 @@ void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) {
// later.
const char *MangledName = getMangledName(D);
if (GlobalDeclMap.count(MangledName) == 0) {
- DeferredDecls[MangledName] = GlobalDecl(D);
+ DeferredDecls[MangledName] = D;
return;
}
}
@@ -793,7 +931,7 @@ void CodeGenModule::EmitTentativeDefinition(const VarDecl *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 }.
@@ -805,28 +943,36 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
// 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));
+ Init = EmitNullConstant(D->getType());
} 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));
+ if (getLangOptions().CPlusPlus) {
+ CXXGlobalInits.push_back(D);
+ Init = EmitNullConstant(T);
+ } else {
+ ErrorUnsupported(D, "static initializer");
+ 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);
+ assert(CE->getOpcode() == llvm::Instruction::BitCast ||
+ // all zero index gep.
+ CE->getOpcode() == llvm::Instruction::GetElementPtr);
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*
@@ -839,7 +985,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
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));
@@ -848,7 +994,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
GV->takeName(cast<llvm::GlobalValue>(Entry));
// Replace all uses of the old global with the new global
- llvm::Constant *NewPtrForOldDecl =
+ llvm::Constant *NewPtrForOldDecl =
llvm::ConstantExpr::getBitCast(GV, Entry->getType());
Entry->replaceAllUsesWith(NewPtrForOldDecl);
@@ -863,22 +1009,38 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
}
GV->setInitializer(Init);
- GV->setConstant(D->getType().isConstant(Context));
+
+ // If it is safe to mark the global 'constant', do so now.
+ GV->setConstant(false);
+ if (D->getType().isConstant(Context)) {
+ // FIXME: In C++, if the variable has a non-trivial ctor/dtor or any mutable
+ // members, it cannot be declared "LLVM const".
+ GV->setConstant(true);
+ }
+
GV->setAlignment(getContext().getDeclAlignInBytes(D));
// Set the llvm linkage type as appropriate.
- if (D->getStorageClass() == VarDecl::Static)
+ if (D->isInAnonymousNamespace())
+ GV->setLinkage(llvm::Function::InternalLinkage);
+ else 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>())
- GV->setLinkage(llvm::GlobalVariable::WeakAnyLinkage);
- else if (!CompileOpts.NoCommon &&
- (!D->hasExternalStorage() && !D->getInit()))
+ else if (D->hasAttr<WeakAttr>()) {
+ if (GV->isConstant())
+ GV->setLinkage(llvm::GlobalVariable::WeakODRLinkage);
+ else
+ GV->setLinkage(llvm::GlobalVariable::WeakAnyLinkage);
+ } else if (!CompileOpts.NoCommon &&
+ !D->hasExternalStorage() && !D->getInit() &&
+ !D->getAttr<SectionAttr>()) {
GV->setLinkage(llvm::GlobalVariable::CommonLinkage);
- else
+ // common vars aren't constant even if declared const.
+ GV->setConstant(false);
+ } else
GV->setLinkage(llvm::GlobalVariable::ExternalLinkage);
SetCommonAttributes(D, GV);
@@ -904,7 +1066,7 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
// 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;
@@ -914,7 +1076,7 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
unsigned OpNo = UI.getOperandNo();
llvm::CallInst *CI = dyn_cast<llvm::CallInst>(*UI++);
if (!CI || OpNo != 0) 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())
@@ -935,21 +1097,26 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
}
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)
+ if (!NewCall->getType()->isVoidTy())
NewCall->takeName(CI);
- NewCall->setCallingConv(CI->getCallingConv());
NewCall->setAttributes(CI->getAttributes());
+ NewCall->setCallingConv(CI->getCallingConv());
// Finally, remove the old call, replacing any uses with the new one.
if (!CI->use_empty())
CI->replaceAllUsesWith(NewCall);
+
+ // Copy any custom metadata attached with CI.
+ llvm::MetadataContext &TheMetadata = CI->getContext().getMetadata();
+ TheMetadata.copyMD(CI, NewCall);
+
CI->eraseFromParent();
}
}
@@ -958,21 +1125,21 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
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();
-
+ bool isVariadic = D->getType()->getAs<FunctionProtoType>()->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
+ // 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);
@@ -981,17 +1148,17 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) {
// 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");
@@ -1007,7 +1174,7 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) {
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
@@ -1015,27 +1182,27 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) {
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::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>())
@@ -1047,7 +1214,7 @@ void CodeGenModule::EmitAliasDefinition(const ValueDecl *D) {
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();
@@ -1062,22 +1229,22 @@ void CodeGenModule::EmitAliasDefinition(const ValueDecl *D) {
llvm::PointerType::getUnqual(DeclTy), 0);
// Create the new alias itself, but don't set a name yet.
- llvm::GlobalValue *GA =
+ 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:
@@ -1086,12 +1253,12 @@ void CodeGenModule::EmitAliasDefinition(const ValueDecl *D) {
// 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);
@@ -1107,7 +1274,7 @@ void CodeGenModule::EmitAliasDefinition(const ValueDecl *D) {
} else {
GA->setLinkage(llvm::Function::DLLExportLinkage);
}
- } else if (D->hasAttr<WeakAttr>() ||
+ } else if (D->hasAttr<WeakAttr>() ||
D->hasAttr<WeakImportAttr>()) {
GA->setLinkage(llvm::Function::WeakAnyLinkage);
}
@@ -1117,28 +1284,28 @@ void CodeGenModule::EmitAliasDefinition(const ValueDecl *D) {
/// getBuiltinLibFunction - Given a builtin id for a function like
/// "__builtin_fabsf", return a Function* for "fabsf".
-llvm::Value *CodeGenModule::getBuiltinLibFunction(unsigned BuiltinID) {
+llvm::Value *CodeGenModule::getBuiltinLibFunction(const FunctionDecl *FD,
+ unsigned BuiltinID) {
assert((Context.BuiltinInfo.isLibFunction(BuiltinID) ||
- Context.BuiltinInfo.isPredefinedLibFunction(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.
ASTContext::GetBuiltinTypeError Error;
QualType Type = Context.GetBuiltinType(BuiltinID, Error);
assert(Error == ASTContext::GE_None && "Can't get builtin type");
- const llvm::FunctionType *Ty =
+ 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());
+ return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl(FD));
}
llvm::Function *CodeGenModule::getIntrinsic(unsigned IID,const llvm::Type **Tys,
@@ -1149,186 +1316,167 @@ llvm::Function *CodeGenModule::getIntrinsic(unsigned IID,const llvm::Type **Tys,
llvm::Function *CodeGenModule::getMemCpyFn() {
if (MemCpyFn) return MemCpyFn;
- const llvm::Type *IntPtr = TheTargetData.getIntPtrType();
+ const llvm::Type *IntPtr = TheTargetData.getIntPtrType(VMContext);
return MemCpyFn = getIntrinsic(llvm::Intrinsic::memcpy, &IntPtr, 1);
}
llvm::Function *CodeGenModule::getMemMoveFn() {
if (MemMoveFn) return MemMoveFn;
- const llvm::Type *IntPtr = TheTargetData.getIntPtrType();
+ const llvm::Type *IntPtr = TheTargetData.getIntPtrType(VMContext);
return MemMoveFn = getIntrinsic(llvm::Intrinsic::memmove, &IntPtr, 1);
}
llvm::Function *CodeGenModule::getMemSetFn() {
if (MemSetFn) return MemSetFn;
- const llvm::Type *IntPtr = TheTargetData.getIntPtrType();
+ const llvm::Type *IntPtr = TheTargetData.getIntPtrType(VMContext);
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);
+static llvm::StringMapEntry<llvm::Constant*> &
+GetConstantCFStringEntry(llvm::StringMap<llvm::Constant*> &Map,
+ const StringLiteral *Literal,
+ bool TargetIsLSB,
+ bool &IsUTF16,
+ unsigned &StringLength) {
+ unsigned NumBytes = Literal->getByteLength();
+
+ // Check for simple case.
+ if (!Literal->containsNonAsciiOrNull()) {
+ StringLength = NumBytes;
+ return Map.GetOrCreateValue(llvm::StringRef(Literal->getStrData(),
+ StringLength));
}
-
- // Append padding
- for (int i = StructFieldNo + 1; i < NextStructFieldNo; i++) {
- llvm::Constant *C =
- llvm::Constant::getNullValue(STy->getElementType(StructFieldNo + 1));
-
- Fields.push_back(C);
+
+ // Otherwise, convert the UTF8 literals into a byte string.
+ llvm::SmallVector<UTF16, 128> ToBuf(NumBytes);
+ const UTF8 *FromPtr = (UTF8 *)Literal->getStrData();
+ UTF16 *ToPtr = &ToBuf[0];
+
+ ConversionResult Result = ConvertUTF8toUTF16(&FromPtr, FromPtr + NumBytes,
+ &ToPtr, ToPtr + NumBytes,
+ strictConversion);
+
+ // Check for conversion failure.
+ if (Result != conversionOK) {
+ // FIXME: Have Sema::CheckObjCString() validate the UTF-8 string and remove
+ // this duplicate code.
+ assert(Result == sourceIllegal && "UTF-8 to UTF-16 conversion failed");
+ StringLength = NumBytes;
+ return Map.GetOrCreateValue(llvm::StringRef(Literal->getStrData(),
+ StringLength));
}
+
+ // ConvertUTF8toUTF16 returns the length in ToPtr.
+ StringLength = ToPtr - &ToBuf[0];
+
+ // Render the UTF-16 string into a byte array and convert to the target byte
+ // order.
+ //
+ // FIXME: This isn't something we should need to do here.
+ llvm::SmallString<128> AsBytes;
+ AsBytes.reserve(StringLength * 2);
+ for (unsigned i = 0; i != StringLength; ++i) {
+ unsigned short Val = ToBuf[i];
+ if (TargetIsLSB) {
+ AsBytes.push_back(Val & 0xFF);
+ AsBytes.push_back(Val >> 8);
+ } else {
+ AsBytes.push_back(Val >> 8);
+ AsBytes.push_back(Val & 0xFF);
+ }
+ }
+ // Append one extra null character, the second is automatically added by our
+ // caller.
+ AsBytes.push_back(0);
+
+ IsUTF16 = true;
+ return Map.GetOrCreateValue(llvm::StringRef(AsBytes.data(), AsBytes.size()));
}
-llvm::Constant *CodeGenModule::
-GetAddrOfConstantCFString(const StringLiteral *Literal) {
- std::string str;
+llvm::Constant *
+CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
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()]);
-
+ llvm::StringMapEntry<llvm::Constant*> &Entry =
+ GetConstantCFStringEntry(CFConstantStringMap, Literal,
+ getTargetData().isLittleEndian(),
+ isUTF16, StringLength);
+
if (llvm::Constant *C = Entry.getValue())
return C;
-
- llvm::Constant *Zero = llvm::Constant::getNullValue(llvm::Type::Int32Ty);
+
+ llvm::Constant *Zero =
+ llvm::Constant::getNullValue(llvm::Type::getInt32Ty(VMContext));
llvm::Constant *Zeros[] = { Zero, Zero };
-
+
+ // If we don't already have it, get __CFConstantStringClassReference.
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());
-
+ llvm::Constant *GV = CreateRuntimeVariable(Ty,
+ "__CFConstantStringClassReference");
// Decay array -> ptr
CFConstantStringClassRef =
llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2);
}
-
+
QualType CFTy = getContext().getCFConstantStringType();
- RecordDecl *CFRD = CFTy->getAsRecordType()->getDecl();
- const llvm::StructType *STy =
+ const llvm::StructType *STy =
cast<llvm::StructType>(getTypes().ConvertType(CFTy));
- std::vector<llvm::Constant*> Fields;
- RecordDecl::field_iterator Field = CFRD->field_begin();
+ std::vector<llvm::Constant*> Fields(4);
// Class pointer.
- FieldDecl *CurField = *Field++;
- FieldDecl *NextField = *Field++;
- appendFieldAndPadding(*this, Fields, CurField, NextField,
- CFConstantStringClassRef, CFRD, STy);
-
+ Fields[0] = CFConstantStringClassRef;
+
// 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);
-
+ Fields[1] = isUTF16 ? llvm::ConstantInt::get(Ty, 0x07d0) :
+ llvm::ConstantInt::get(Ty, 0x07C8);
+
// String pointer.
- CurField = NextField;
- NextField = *Field++;
- llvm::Constant *C = llvm::ConstantArray::get(str);
+ llvm::Constant *C = llvm::ConstantArray::get(VMContext, Entry.getKey().str());
- const char *Sect, *Prefix;
+ const char *Sect = 0;
+ llvm::GlobalValue::LinkageTypes Linkage;
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.
+ // FIXME: why do utf strings get "_" labels instead of "L" labels?
+ Linkage = llvm::GlobalValue::InternalLinkage;
+ // Note: -fwritable-strings doesn't make unicode CFStrings writable, but
+ // does make plain ascii ones writable.
isConstant = true;
+ } else {
+ Linkage = llvm::GlobalValue::PrivateLinkage;
+ isConstant = !Features.WritableStrings;
}
- llvm::GlobalVariable *GV =
- new llvm::GlobalVariable(C->getType(), isConstant,
- llvm::GlobalValue::InternalLinkage,
- C, Prefix, &getModule());
+
+ llvm::GlobalVariable *GV =
+ new llvm::GlobalVariable(getModule(), C->getType(), isConstant, Linkage, C,
+ ".str");
if (Sect)
GV->setSection(Sect);
if (isUTF16) {
unsigned Align = getContext().getTypeAlign(getContext().ShortTy)/8;
- GV->setAlignment(Align);
+ GV->setAlignment(Align);
}
- appendFieldAndPadding(*this, Fields, CurField, NextField,
- llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2),
- CFRD, STy);
-
+ Fields[2] = llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2);
+
// String length.
- CurField = NextField;
- NextField = 0;
Ty = getTypes().ConvertType(getContext().LongTy);
- appendFieldAndPadding(*this, Fields, CurField, NextField,
- llvm::ConstantInt::get(Ty, StringLength), CFRD, STy);
-
+ Fields[3] = llvm::ConstantInt::get(Ty, StringLength);
+
// The struct.
C = llvm::ConstantStruct::get(STy, Fields);
- GV = new llvm::GlobalVariable(C->getType(), true,
- llvm::GlobalVariable::InternalLinkage, C,
- getContext().Target.getCFStringSymbolPrefix(),
- &getModule());
+ GV = new llvm::GlobalVariable(getModule(), C->getType(), true,
+ llvm::GlobalVariable::PrivateLinkage, C,
+ "_unnamed_cfstring_");
if (const char *Sect = getContext().Target.getCFStringSection())
GV->setSection(Sect);
Entry.setValue(GV);
-
+
return GV;
}
@@ -1341,16 +1489,16 @@ std::string CodeGenModule::GetStringForStringLiteral(const StringLiteral *E) {
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;
}
@@ -1374,17 +1522,18 @@ CodeGenModule::GetAddrOfConstantStringFromObjCEncode(const ObjCEncodeExpr *E) {
/// GenerateWritableString -- Creates storage for a string literal.
-static llvm::Constant *GenerateStringLiteral(const std::string &str,
+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);
-
+ llvm::Constant *C =
+ llvm::ConstantArray::get(CGM.getLLVMContext(), str, false);
+
// Create a global variable for this string
- return new llvm::GlobalVariable(C->getType(), constant,
- llvm::GlobalValue::InternalLinkage,
- C, GlobalName, &CGM.getModule());
+ return new llvm::GlobalVariable(CGM.getModule(), C->getType(), constant,
+ llvm::GlobalValue::PrivateLinkage,
+ C, GlobalName);
}
/// GetAddrOfConstantString - Returns a pointer to a character array
@@ -1401,14 +1550,14 @@ llvm::Constant *CodeGenModule::GetAddrOfConstantString(const std::string &str,
// Get the default prefix if a name wasn't specified.
if (!GlobalName)
- GlobalName = getContext().Target.getStringSymbolPrefix(IsConstant);
+ GlobalName = ".str";
// 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()]);
+
+ llvm::StringMapEntry<llvm::Constant *> &Entry =
+ ConstantStringMap.GetOrCreateValue(&str[0], &str[str.length()]);
if (Entry.getValue())
return Entry.getValue();
@@ -1429,12 +1578,12 @@ llvm::Constant *CodeGenModule::GetAddrOfConstantCString(const std::string &str,
/// EmitObjCPropertyImplementations - Emit information for synthesized
/// properties for an implementation.
-void CodeGenModule::EmitObjCPropertyImplementations(const
+void CodeGenModule::EmitObjCPropertyImplementations(const
ObjCImplementationDecl *D) {
- for (ObjCImplementationDecl::propimpl_iterator
+ for (ObjCImplementationDecl::propimpl_iterator
i = D->propimpl_begin(), e = D->propimpl_end(); i != e; ++i) {
ObjCPropertyImplDecl *PID = *i;
-
+
// Dynamic is just for type-checking.
if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) {
ObjCPropertyDecl *PD = PID->getPropertyDecl();
@@ -1464,7 +1613,8 @@ void CodeGenModule::EmitNamespace(const NamespaceDecl *ND) {
// EmitLinkageSpec - Emit all declarations in a linkage spec.
void CodeGenModule::EmitLinkageSpec(const LinkageSpecDecl *LSD) {
- if (LSD->getLanguage() != LinkageSpecDecl::lang_c) {
+ if (LSD->getLanguage() != LinkageSpecDecl::lang_c &&
+ LSD->getLanguage() != LinkageSpecDecl::lang_cxx) {
ErrorUnsupported(LSD, "linkage spec");
return;
}
@@ -1485,18 +1635,20 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
// Ignore dependent declarations.
if (D->getDeclContext() && D->getDeclContext()->isDependentContext())
return;
-
+
switch (D->getKind()) {
+ case Decl::CXXConversion:
case Decl::CXXMethod:
case Decl::Function:
// Skip function templates
if (cast<FunctionDecl>(D)->getDescribedFunctionTemplate())
return;
+
+ EmitGlobal(cast<FunctionDecl>(D));
+ break;
- // Fall through
-
case Decl::Var:
- EmitGlobal(GlobalDecl(cast<ValueDecl>(D)));
+ EmitGlobal(cast<VarDecl>(D));
break;
// C++ Decls
@@ -1505,8 +1657,10 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
break;
// No code generation needed.
case Decl::Using:
+ case Decl::UsingDirective:
case Decl::ClassTemplate:
case Decl::FunctionTemplate:
+ case Decl::NamespaceAlias:
break;
case Decl::CXXConstructor:
EmitCXXConstructors(cast<CXXConstructorDecl>(D));
@@ -1520,7 +1674,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
break;
// Objective-C Decls
-
+
// Forward declarations, no (immediate) code generation.
case Decl::ObjCClass:
case Decl::ObjCForwardProtocol:
@@ -1543,7 +1697,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
EmitObjCPropertyImplementations(OMD);
Runtime->GenerateClass(OMD);
break;
- }
+ }
case Decl::ObjCMethod: {
ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(D);
// If this is not a prototype, emit the body.
@@ -1551,7 +1705,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
CodeGenFunction(*this).GenerateObjCMethod(OMD);
break;
}
- case Decl::ObjCCompatibleAlias:
+ case Decl::ObjCCompatibleAlias:
// compatibility-alias is a directive and has no code gen.
break;
@@ -1563,7 +1717,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
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);
@@ -1571,8 +1725,8 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
getModule().setModuleInlineAsm(S + '\n' + AsmString);
break;
}
-
- default:
+
+ 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.
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index ba9f1b2..2e58337 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -17,16 +17,22 @@
#include "clang/Basic/LangOptions.h"
#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
#include "CGBlocks.h"
#include "CGCall.h"
#include "CGCXX.h"
+#include "CGVtable.h"
#include "CodeGenTypes.h"
+#include "Mangle.h"
+#include "llvm/Module.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/ValueHandle.h"
#include <list>
+#define ATTACH_DEBUG_INFO_TO_AN_INSN 1
+
namespace llvm {
class Module;
class Constant;
@@ -34,6 +40,7 @@ namespace llvm {
class GlobalValue;
class TargetData;
class FunctionType;
+ class LLVMContext;
}
namespace clang {
@@ -68,42 +75,50 @@ namespace CodeGen {
/// 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.
+/// a VarDecl, a FunctionDecl or a BlockDecl.
class GlobalDecl {
- llvm::PointerIntPair<const ValueDecl*, 2> Value;
+ llvm::PointerIntPair<const Decl*, 2> Value;
+
+ void Init(const Decl *D) {
+ assert(!isa<CXXConstructorDecl>(D) && "Use other ctor with ctor decls!");
+ assert(!isa<CXXDestructorDecl>(D) && "Use other ctor with dtor decls!");
+
+ Value.setPointer(D);
+ }
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)
+
+ GlobalDecl(const VarDecl *D) { Init(D);}
+ GlobalDecl(const FunctionDecl *D) { Init(D); }
+ GlobalDecl(const BlockDecl *D) { Init(D); }
+ GlobalDecl(const ObjCMethodDecl *D) { Init(D); }
+
+ 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(); }
-
+
+ const Decl *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;
+ typedef std::vector<std::pair<llvm::Constant*, int> > CtorList;
ASTContext &Context;
const LangOptions &Features;
@@ -112,9 +127,14 @@ class CodeGenModule : public BlockModule {
const llvm::TargetData &TheTargetData;
Diagnostic &Diags;
CodeGenTypes Types;
+ MangleContext MangleCtx;
+
+ /// VtableInfo - Holds information about C++ vtables.
+ CGVtableInfo VtableInfo;
+
CGObjCRuntime* Runtime;
CGDebugInfo* DebugInfo;
-
+
llvm::Function *MemCpyFn;
llvm::Function *MemMoveFn;
llvm::Function *MemSetFn;
@@ -171,9 +191,15 @@ class CodeGenModule : public BlockModule {
llvm::StringMap<llvm::Constant*> CFConstantStringMap;
llvm::StringMap<llvm::Constant*> ConstantStringMap;
+ /// CXXGlobalInits - Variables with global initializers that need to run
+ /// before main.
+ std::vector<const VarDecl*> CXXGlobalInits;
+
/// 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;
+
+ llvm::LLVMContext &VMContext;
public:
CodeGenModule(ASTContext &C, const CompileOptions &CompileOpts,
llvm::Module &M, const llvm::TargetData &TD, Diagnostic &Diags);
@@ -200,8 +226,11 @@ public:
const LangOptions &getLangOptions() const { return Features; }
llvm::Module &getModule() const { return TheModule; }
CodeGenTypes &getTypes() { return Types; }
+ MangleContext &getMangleContext() { return MangleCtx; }
+ CGVtableInfo &getVtableInfo() { return VtableInfo; }
Diagnostic &getDiags() const { return Diags; }
const llvm::TargetData &getTargetData() const { return TheTargetData; }
+ llvm::LLVMContext &getLLVMContext() { return VMContext; }
/// getDeclVisibilityMode - Compute the visibility of the decl \arg D.
LangOptions::VisibilityMode getDeclVisibilityMode(const Decl *D) const;
@@ -223,6 +252,22 @@ public:
llvm::Constant *GetAddrOfFunction(GlobalDecl GD,
const llvm::Type *Ty = 0);
+ /// GenerateRtti - Generate the rtti information for the given type.
+ llvm::Constant *GenerateRtti(const CXXRecordDecl *RD);
+
+ /// BuildThunk - Build a thunk for the given method
+ llvm::Constant *BuildThunk(const CXXMethodDecl *MD, bool Extern, int64_t nv,
+ int64_t v);
+ /// BuildCoVariantThunk - Build a thunk for the given method
+ llvm::Constant *BuildCovariantThunk(const CXXMethodDecl *MD, bool Extern,
+ int64_t nv_t, int64_t v_t,
+ int64_t nv_r, int64_t v_r);
+
+ /// GetCXXBaseClassOffset - Returns the offset from a derived class to its
+ /// base class. Returns null if the offset is 0.
+ llvm::Constant *GetCXXBaseClassOffset(const CXXRecordDecl *ClassDecl,
+ const CXXRecordDecl *BaseClassDecl);
+
/// 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.
@@ -239,7 +284,7 @@ public:
/// 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
@@ -264,17 +309,18 @@ public:
/// GetAddrOfCXXConstructor - Return the address of the constructor of the
/// given type.
- llvm::Function *GetAddrOfCXXConstructor(const CXXConstructorDecl *D,
+ 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,
+ 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::Value *getBuiltinLibFunction(const FunctionDecl *FD,
+ unsigned BuiltinID);
llvm::Function *getMemCpyFn();
llvm::Function *getMemMoveFn();
@@ -355,20 +401,30 @@ public:
/// as a return type.
bool ReturnTypeUsesSret(const CGFunctionInfo &FI);
+ /// ConstructAttributeList - Get the LLVM attributes and calling convention to
+ /// use for a particular function type.
+ ///
+ /// \param Info - The function type information.
+ /// \param TargetDecl - The decl these attributes are being constructed
+ /// for. If supplied the attributes applied to this decl may contribute to the
+ /// function attributes and calling convention.
+ /// \param PAL [out] - On return, the attribute list to use.
+ /// \param CallingConv [out] - On return, the LLVM calling convention to use.
void ConstructAttributeList(const CGFunctionInfo &Info,
const Decl *TargetDecl,
- AttributeListType &PAL);
+ AttributeListType &PAL,
+ unsigned &CallingConv);
const char *getMangledName(const GlobalDecl &D);
const char *getMangledName(const NamedDecl *ND);
- const char *getMangledCXXCtorName(const CXXConstructorDecl *D,
+ const char *getMangledCXXCtorName(const CXXConstructorDecl *D,
CXXCtorType Type);
- const char *getMangledCXXDtorName(const CXXDestructorDecl *D,
+ const char *getMangledCXXDtorName(const CXXDestructorDecl *D,
CXXDtorType Type);
void EmitTentativeDefinition(const VarDecl *D);
-
+
enum GVALinkage {
GVA_Internal,
GVA_C99Inline,
@@ -376,19 +432,22 @@ public:
GVA_StrongExternal,
GVA_TemplateInstantiation
};
-
+
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);
-
+ void DeferredCopyConstructorToEmit(GlobalDecl D);
+ void DeferredCopyAssignmentToEmit(GlobalDecl D);
+ void DeferredDestructorToEmit(GlobalDecl D);
+
/// SetCommonAttributes - Set attributes which are common to any
/// form of a global definition (alias, Objective-C method,
/// function, global variable).
@@ -397,9 +456,9 @@ private:
void SetCommonAttributes(const Decl *D, llvm::GlobalValue *GV);
/// SetFunctionDefinitionAttributes - Set attributes for a global definition.
- void SetFunctionDefinitionAttributes(const FunctionDecl *D,
+ void SetFunctionDefinitionAttributes(const FunctionDecl *D,
llvm::GlobalValue *GV);
-
+
/// SetFunctionAttributes - Set function attributes for a function
/// declaration.
void SetFunctionAttributes(const FunctionDecl *FD,
@@ -418,26 +477,29 @@ private:
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
+
+ /// 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);
-
+
+ /// EmitCXXGlobalInitFunc - Emit a function that initializes C++ globals.
+ void EmitCXXGlobalInitFunc();
+
// FIXME: Hardcoding priority here is gross.
void AddGlobalCtor(llvm::Function *Ctor, int Priority=65535);
void AddGlobalDtor(llvm::Function *Dtor, int Priority=65535);
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index 1a30ea3..dedf824 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -7,13 +7,14 @@
//
//===----------------------------------------------------------------------===//
//
-// This is the code that handles AST -> LLVM type lowering.
+// 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/DeclCXX.h"
#include "clang/AST/Expr.h"
#include "clang/AST/RecordLayout.h"
#include "llvm/DerivedTypes.h"
@@ -21,47 +22,11 @@
#include "llvm/Target/TargetData.h"
#include "CGCall.h"
+#include "CGRecordLayoutBuilder.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),
@@ -69,8 +34,8 @@ CodeGenTypes::CodeGenTypes(ASTContext &Ctx, llvm::Module& M,
}
CodeGenTypes::~CodeGenTypes() {
- for(llvm::DenseMap<const Type *, CGRecordLayout *>::iterator
- I = CGRecordLayouts.begin(), E = CGRecordLayouts.end();
+ for (llvm::DenseMap<const Type *, CGRecordLayout *>::iterator
+ I = CGRecordLayouts.begin(), E = CGRecordLayouts.end();
I != E; ++I)
delete I->second;
CGRecordLayouts.clear();
@@ -100,7 +65,7 @@ const llvm::Type *CodeGenTypes::ConvertType(QualType T) {
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());
@@ -110,15 +75,16 @@ const llvm::Type *CodeGenTypes::ConvertTypeRecursive(QualType T) {
return I->second.get();
const llvm::Type *ResultType = ConvertNewType(T);
- TypeCache.insert(std::make_pair(T.getTypePtr(),
+ 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));
+ if (ResultType == llvm::Type::getInt1Ty(getLLVMContext()))
+ return llvm::IntegerType::get(getLLVMContext(),
+ (unsigned)Context.getTypeSize(T));
return ResultType;
}
@@ -128,26 +94,27 @@ const llvm::Type *CodeGenTypes::ConvertTypeForMemRecursive(QualType T) {
/// 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)
+ if (R != llvm::Type::getInt1Ty(getLLVMContext()))
return R;
-
+
// Otherwise, return an integer of the target-specified size.
- return llvm::IntegerType::get((unsigned)Context.getTypeSize(T));
-
+ return llvm::IntegerType::get(getLLVMContext(),
+ (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 (const TagType* TT = FT->getResultType()->getAs<TagType>())
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 (const TagType* TT = FPT->getArgType(i)->getAs<TagType>())
if (!TT->getDecl()->isDefinition())
return TT;
return 0;
@@ -156,17 +123,16 @@ static const TagType *VerifyFuncTypeComplete(const Type* T) {
/// 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 =
+ const Type *Key = Context.getTagDeclType(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);
@@ -197,24 +163,25 @@ void CodeGenTypes::UpdateCompletedType(const TagDecl *TD) {
}
}
-static const llvm::Type* getTypeForFormat(const llvm::fltSemantics &format) {
+static const llvm::Type* getTypeForFormat(llvm::LLVMContext &VMContext,
+ const llvm::fltSemantics &format) {
if (&format == &llvm::APFloat::IEEEsingle)
- return llvm::Type::FloatTy;
+ return llvm::Type::getFloatTy(VMContext);
if (&format == &llvm::APFloat::IEEEdouble)
- return llvm::Type::DoubleTy;
+ return llvm::Type::getDoubleTy(VMContext);
if (&format == &llvm::APFloat::IEEEquad)
- return llvm::Type::FP128Ty;
+ return llvm::Type::getFP128Ty(VMContext);
if (&format == &llvm::APFloat::PPCDoubleDouble)
- return llvm::Type::PPC_FP128Ty;
+ return llvm::Type::getPPC_FP128Ty(VMContext);
if (&format == &llvm::APFloat::x87DoubleExtended)
- return llvm::Type::X86_FP80Ty;
+ return llvm::Type::getX86_FP80Ty(VMContext);
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)
@@ -228,14 +195,16 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
switch (cast<BuiltinType>(Ty).getKind()) {
default: assert(0 && "Unknown builtin type!");
case BuiltinType::Void:
+ case BuiltinType::ObjCId:
+ case BuiltinType::ObjCClass:
// 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);
+ return llvm::IntegerType::get(getLLVMContext(), 8);
case BuiltinType::Bool:
// Note that we always return bool as i1 for use as a scalar type.
- return llvm::Type::Int1Ty;
-
+ return llvm::Type::getInt1Ty(getLLVMContext());
+
case BuiltinType::Char_S:
case BuiltinType::Char_U:
case BuiltinType::SChar:
@@ -249,46 +218,56 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
case BuiltinType::LongLong:
case BuiltinType::ULongLong:
case BuiltinType::WChar:
- return llvm::IntegerType::get(
+ case BuiltinType::Char16:
+ case BuiltinType::Char32:
+ return llvm::IntegerType::get(getLLVMContext(),
static_cast<unsigned>(Context.getTypeSize(T)));
-
+
case BuiltinType::Float:
case BuiltinType::Double:
case BuiltinType::LongDouble:
- return getTypeForFormat(Context.getFloatTypeSemantics(T));
-
+ return getTypeForFormat(getLLVMContext(),
+ Context.getFloatTypeSemantics(T));
+
+ case BuiltinType::NullPtr: {
+ // Model std::nullptr_t as i8*
+ const llvm::Type *Ty = llvm::IntegerType::get(getLLVMContext(), 8);
+ return llvm::PointerType::getUnqual(Ty);
+ }
+
case BuiltinType::UInt128:
case BuiltinType::Int128:
- return llvm::IntegerType::get(128);
+ return llvm::IntegerType::get(getLLVMContext(), 128);
}
break;
}
case Type::FixedWidthInt:
- return llvm::IntegerType::get(cast<FixedWidthIntType>(T)->getWidth());
+ return llvm::IntegerType::get(getLLVMContext(),
+ cast<FixedWidthIntType>(T)->getWidth());
case Type::Complex: {
- const llvm::Type *EltTy =
+ const llvm::Type *EltTy =
ConvertTypeRecursive(cast<ComplexType>(Ty).getElementType());
- return llvm::StructType::get(EltTy, EltTy, NULL);
+ return llvm::StructType::get(TheModule.getContext(), 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();
+ llvm::OpaqueType *PointeeType = llvm::OpaqueType::get(getLLVMContext());
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();
+ llvm::OpaqueType *PointeeType = llvm::OpaqueType::get(getLLVMContext());
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 &&
+ assert(A.getIndexTypeCVRQualifiers() == 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.
@@ -296,7 +275,7 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
}
case Type::IncompleteArray: {
const IncompleteArrayType &A = cast<IncompleteArrayType>(Ty);
- assert(A.getIndexTypeQualifier() == 0 &&
+ assert(A.getIndexTypeCVRQualifiers() == 0 &&
"FIXME: We only handle trivial array types so far!");
// int X[] -> [0 x int]
return llvm::ArrayType::get(ConvertTypeForMemRecursive(A.getElementType()), 0);
@@ -320,7 +299,7 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
// 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();
+ llvm::Type *ResultType = llvm::OpaqueType::get(getLLVMContext());
FunctionTypes.insert(std::make_pair(&Ty, ResultType));
return ResultType;
}
@@ -332,55 +311,57 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
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();
+ T = llvm::OpaqueType::get(getLLVMContext());
return T;
}
-
- case Type::ObjCObjectPointer:
- // Protocols don't influence the LLVM type.
- return ConvertTypeRecursive(Context.getObjCIdType());
+
+ case Type::ObjCObjectPointer: {
+ // Protocol qualifications do not influence the LLVM type, we just return a
+ // pointer to the underlying interface type. We don't need to worry about
+ // recursive conversion.
+ const llvm::Type *T =
+ ConvertTypeRecursive(cast<ObjCObjectPointerType>(Ty).getPointeeType());
+ return llvm::PointerType::getUnqual(T);
+ }
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();
+ // FIXME: We should not have to check for a null decl context here.
+ // Right now we do it because the implicit Obj-C decls don't have one.
+ TypeName += TD->getDeclContext() ? TD->getQualifiedNameAsString() :
+ TD->getNameAsString();
else if (const TypedefType *TdT = dyn_cast<TypedefType>(T))
- TypeName += TdT->getDecl()->getNameAsString();
+ // FIXME: We should not have to check for a null decl context here.
+ // Right now we do it because the implicit Obj-C decls don't have one.
+ TypeName += TdT->getDecl()->getDeclContext() ?
+ TdT->getDecl()->getQualifiedNameAsString() :
+ TdT->getDecl()->getNameAsString();
else
TypeName += "anon";
-
- TheModule.addTypeName(TypeName, Res);
+
+ TheModule.addTypeName(TypeName, Res);
return Res;
}
case Type::BlockPointer: {
const QualType FTy = cast<BlockPointerType>(Ty).getPointeeType();
- llvm::OpaqueType *PointeeType = llvm::OpaqueType::get();
+ llvm::OpaqueType *PointeeType = llvm::OpaqueType::get(getLLVMContext());
PointersToResolve.push_back(std::make_pair(FTy, PointeeType));
return llvm::PointerType::get(PointeeType, FTy.getAddressSpace());
}
@@ -392,7 +373,8 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
QualType ETy = cast<MemberPointerType>(Ty).getPointeeType();
if (ETy->isFunctionType()) {
- return llvm::StructType::get(ConvertType(Context.getPointerDiffType()),
+ return llvm::StructType::get(TheModule.getContext(),
+ ConvertType(Context.getPointerDiffType()),
ConvertType(Context.getPointerDiffType()),
NULL);
} else
@@ -402,85 +384,85 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
case Type::TemplateSpecialization:
assert(false && "Dependent types can't get here");
}
-
+
// FIXME: implement.
- return llvm::OpaqueType::get();
+ return llvm::OpaqueType::get(getLLVMContext());
}
/// ConvertTagDeclType - Lay out a tagged decl type like struct or union or
/// enum.
const llvm::Type *CodeGenTypes::ConvertTagDeclType(const TagDecl *TD) {
+
+ // FIXME. This may have to move to a better place.
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(TD)) {
+ for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
+ e = RD->bases_end(); i != e; ++i) {
+ if (!i->isVirtual()) {
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+ ConvertTagDeclType(Base);
+ }
+ }
+ }
+
// 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 =
+ const Type *Key =
+ Context.getTagDeclType(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();
+ llvm::Type *ResultType = llvm::OpaqueType::get(getLLVMContext());
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();
+ llvm::PATypeHolder ResultHolder = llvm::OpaqueType::get(getLLVMContext());
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()) {
- 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();
- }
-
+ // Layout fields.
+ CGRecordLayout *Layout =
+ CGRecordLayoutBuilder::ComputeLayout(*this, RD);
+
+ CGRecordLayouts[Key] = Layout;
+ ResultType = Layout->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) {
+ assert(!FD->isBitField() && "Don't use getLLVMFieldNo on bit fields!");
+
llvm::DenseMap<const FieldDecl*, unsigned>::iterator I = FieldInfo.find(FD);
assert (I != FieldInfo.end() && "Unable to find field info");
return I->second;
@@ -500,115 +482,19 @@ CodeGenTypes::BitFieldInfo CodeGenTypes::getBitFieldInfo(const FieldDecl *FD) {
}
/// 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)));
+void CodeGenTypes::addBitFieldInfo(const FieldDecl *FD, unsigned FieldNo,
+ unsigned Start, unsigned Size) {
+ BitFields.insert(std::make_pair(FD, BitFieldInfo(FieldNo, Start, Size)));
}
/// getCGRecordLayout - Return record layout info for the given llvm::Type.
-const CGRecordLayout *
+const CGRecordLayout &
CodeGenTypes::getCGRecordLayout(const TagDecl *TD) const {
- const Type *Key =
- Context.getTagDeclType(const_cast<TagDecl*>(TD)).getTypePtr();
+ const Type *Key =
+ Context.getTagDeclType(TD).getTypePtr();
llvm::DenseMap<const Type*, CGRecordLayout *>::iterator I
= CGRecordLayouts.find(Key);
- assert (I != CGRecordLayouts.end()
+ 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(),
- FieldEnd = RD.field_end();
- 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(),
- FieldEnd = RD.field_end();
- 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());
+ return *I->second;
}
diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h
index b72d8e9..a92a019 100644
--- a/lib/CodeGen/CodeGenTypes.h
+++ b/lib/CodeGen/CodeGenTypes.h
@@ -7,13 +7,14 @@
//
//===----------------------------------------------------------------------===//
//
-// This is the code that handles AST -> LLVM type lowering.
+// This is the code that handles AST -> LLVM type lowering.
//
//===----------------------------------------------------------------------===//
#ifndef CLANG_CODEGEN_CODEGENTYPES_H
#define CLANG_CODEGEN_CODEGENTYPES_H
+#include "llvm/Module.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallSet.h"
#include <vector>
@@ -27,6 +28,7 @@ namespace llvm {
class PATypeHolder;
class TargetData;
class Type;
+ class LLVMContext;
}
namespace clang {
@@ -47,35 +49,44 @@ namespace clang {
namespace CodeGen {
class CodeGenTypes;
- /// CGRecordLayout - This class handles struct and union layout info while
+ /// CGRecordLayout - This class handles struct and union layout info while
/// lowering AST types to LLVM types.
class CGRecordLayout {
CGRecordLayout(); // DO NOT IMPLEMENT
+
+ /// LLVMType - The LLVMType corresponding to this record layout.
+ const llvm::Type *LLVMType;
+
+ /// ContainsMemberPointer - Whether one of the fields in this record layout
+ /// is a member pointer, or a struct that contains a member pointer.
+ bool ContainsMemberPointer;
+
+ /// KeyFunction - The key function of the record layout (if one exists),
+ /// which is the first non-pure virtual function that is not inline at the
+ /// point of class definition.
+ /// See http://www.codesourcery.com/public/cxx-abi/abi.html#vague-vtable.
+ const CXXMethodDecl *KeyFunction;
+
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.)
- }
+ CGRecordLayout(const llvm::Type *T, bool ContainsMemberPointer,
+ const CXXMethodDecl *KeyFunction)
+ : LLVMType(T), ContainsMemberPointer(ContainsMemberPointer),
+ KeyFunction(KeyFunction) { }
/// getLLVMType - Return llvm type associated with this record.
- llvm::Type *getLLVMType() const {
- return STy;
+ const llvm::Type *getLLVMType() const {
+ return LLVMType;
}
- bool isPaddingField(unsigned No) const {
- return PaddingFields.count(No) != 0;
+ bool containsMemberPointer() const {
+ return ContainsMemberPointer;
}
- unsigned getNumPaddingFields() {
- return PaddingFields.size();
+ const CXXMethodDecl *getKeyFunction() const {
+ return KeyFunction;
}
-
- 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 {
@@ -84,7 +95,7 @@ class CodeGenTypes {
llvm::Module& TheModule;
const llvm::TargetData& TheTargetData;
mutable const ABIInfo* TheABIInfo;
-
+
llvm::SmallVector<std::pair<QualType,
llvm::OpaqueType *>, 8> PointersToResolve;
@@ -98,9 +109,9 @@ class CodeGenTypes {
/// 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
+ /// 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;
@@ -112,13 +123,15 @@ class CodeGenTypes {
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;
+ struct BitFieldInfo {
+ BitFieldInfo(unsigned FieldNo,
+ unsigned Start,
+ unsigned Size)
+ : FieldNo(FieldNo), Start(Start), Size(Size) {}
+
+ unsigned FieldNo;
+ unsigned Start;
+ unsigned Size;
};
private:
@@ -126,7 +139,7 @@ private:
/// 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
+ /// 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;
@@ -138,16 +151,17 @@ private:
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;
+ llvm::LLVMContext &getLLVMContext() { return TheModule.getContext(); }
- /// ConvertType - Convert type T into a llvm::Type.
+ /// 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
@@ -158,39 +172,51 @@ public:
/// GetFunctionType - Get the LLVM function type for \arg Info.
const llvm::FunctionType *GetFunctionType(const CGFunctionInfo &Info,
bool IsVariadic);
-
- const CGRecordLayout *getCGRecordLayout(const TagDecl*) const;
-
+
+ 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);
-
+private:
const CGFunctionInfo &getFunctionInfo(const FunctionNoProtoType *FTNP);
const CGFunctionInfo &getFunctionInfo(const FunctionProtoType *FTP);
+
+public:
+ /// getFunctionInfo - Get the function info for the specified function decl.
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);
+ // getFunctionInfo - Get the function info for a member function.
+ const CGFunctionInfo &getFunctionInfo(const CXXRecordDecl *RD,
+ const FunctionProtoType *FTP);
+
+ /// getFunctionInfo - Get the function info for a function described by a
+ /// return type and argument types. If the calling convention is not
+ /// specified, the "C" calling convention will be used.
+ const CGFunctionInfo &getFunctionInfo(QualType ResTy,
+ const CallArgList &Args,
+ unsigned CallingConvention = 0);
+ const CGFunctionInfo &getFunctionInfo(QualType ResTy,
+ const FunctionArgList &Args,
+ unsigned CallingConvention = 0);
+ const CGFunctionInfo &getFunctionInfo(QualType RetTy,
+ const llvm::SmallVector<QualType, 16> &ArgTys,
+ unsigned CallingConvention = 0);
+
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);
+ void addFieldInfo(const FieldDecl *FD, unsigned FieldNo);
/// addBitFieldInfo - Assign a start bit and a size to field FD.
- void addBitFieldInfo(const FieldDecl *FD, unsigned Begin, unsigned Size);
+ void addBitFieldInfo(const FieldDecl *FD, unsigned FieldNo,
+ unsigned Start, unsigned Size);
/// getBitFieldInfo - Return the BitFieldInfo that corresponds to the field
/// FD.
diff --git a/lib/CodeGen/Makefile b/lib/CodeGen/Makefile
index e716fe7..108490b 100644
--- a/lib/CodeGen/Makefile
+++ b/lib/CodeGen/Makefile
@@ -18,6 +18,9 @@ BUILD_ARCHIVE = 1
CXXFLAGS = -fno-rtti
CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
+ifdef CLANG_VENDOR
+CPPFLAGS += -DCLANG_VENDOR='"$(CLANG_VENDOR) "'
+endif
include $(LEVEL)/Makefile.common
diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp
index 8018b4f..fd77274 100644
--- a/lib/CodeGen/Mangle.cpp
+++ b/lib/CodeGen/Mangle.cpp
@@ -20,85 +20,125 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/ErrorHandling.h"
using namespace clang;
namespace {
class VISIBILITY_HIDDEN CXXNameMangler {
- ASTContext &Context;
+ MangleContext &Context;
llvm::raw_ostream &Out;
const CXXMethodDecl *Structor;
unsigned StructorType;
CXXCtorType CtorType;
+
+ llvm::DenseMap<uintptr_t, unsigned> Substitutions;
public:
- CXXNameMangler(ASTContext &C, llvm::raw_ostream &os)
+ CXXNameMangler(MangleContext &C, llvm::raw_ostream &os)
: Context(C), Out(os), Structor(0), StructorType(0) { }
bool mangle(const NamedDecl *D);
+ void mangleCalloffset(int64_t nv, int64_t v);
+ void mangleThunk(const FunctionDecl *FD, int64_t nv, int64_t v);
+ void mangleCovariantThunk(const FunctionDecl *FD,
+ int64_t nv_t, int64_t v_t,
+ int64_t nv_r, int64_t v_r);
void mangleGuardVariable(const VarDecl *D);
-
+
+ void mangleCXXVtable(const CXXRecordDecl *RD);
+ void mangleCXXRtti(const CXXRecordDecl *RD);
void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type);
void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type);
private:
- bool mangleFunctionDecl(const FunctionDecl *FD);
+ bool mangleSubstitution(const NamedDecl *ND);
+ bool mangleSubstitution(QualType T);
+ bool mangleSubstitution(uintptr_t Ptr);
+
+ bool mangleStandardSubstitution(const NamedDecl *ND);
+ void addSubstitution(const NamedDecl *ND) {
+ addSubstitution(reinterpret_cast<uintptr_t>(ND));
+ }
+ void addSubstitution(QualType T);
+ void addSubstitution(uintptr_t Ptr);
+
+ bool mangleFunctionDecl(const FunctionDecl *FD);
+
void mangleFunctionEncoding(const FunctionDecl *FD);
void mangleName(const NamedDecl *ND);
+ void mangleName(const TemplateDecl *TD,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs);
void mangleUnqualifiedName(const NamedDecl *ND);
+ void mangleUnscopedName(const NamedDecl *ND);
+ void mangleUnscopedTemplateName(const TemplateDecl *ND);
void mangleSourceName(const IdentifierInfo *II);
void mangleLocalName(const NamedDecl *ND);
void mangleNestedName(const NamedDecl *ND);
+ void mangleNestedName(const TemplateDecl *TD,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs);
void manglePrefix(const DeclContext *DC);
+ void mangleTemplatePrefix(const TemplateDecl *ND);
void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity);
- void mangleCVQualifiers(unsigned Quals);
+ void mangleQualifiers(Qualifiers 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);
+
+ // Declare manglers for every type class.
+#define ABSTRACT_TYPE(CLASS, PARENT)
+#define NON_CANONICAL_TYPE(CLASS, PARENT)
+#define TYPE(CLASS, PARENT) void mangleType(const CLASS##Type *T);
+#include "clang/AST/TypeNodes.def"
+
+ void mangleType(const TagType*);
+ void mangleBareFunctionType(const FunctionType *T,
+ bool MangleReturnType);
+ void mangleExpression(const Expr *E);
void mangleCXXCtorType(CXXCtorType T);
void mangleCXXDtorType(CXXDtorType T);
-
+
+ void mangleTemplateArgs(const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs);
void mangleTemplateArgumentList(const TemplateArgumentList &L);
void mangleTemplateArgument(const TemplateArgument &A);
+
+ void mangleTemplateParameter(unsigned Index);
};
}
static bool isInCLinkageSpecification(const Decl *D) {
- for (const DeclContext *DC = D->getDeclContext();
+ for (const DeclContext *DC = D->getDeclContext();
!DC->isTranslationUnit(); DC = DC->getParent()) {
- if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC))
+ 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).
+ // Clang's "overloadable" attribute extension to C/C++ implies name mangling
+ // (always).
if (!FD->hasAttr<OverloadableAttr>()) {
// C functions are not mangled, and "main" is never mangled.
- if (!Context.getLangOptions().CPlusPlus || FD->isMain())
+ if (!Context.getASTContext().getLangOptions().CPlusPlus || FD->isMain())
return false;
-
- // No mangling in an "implicit extern C" header.
+
+ // No mangling in an "implicit extern C" header.
if (FD->getLocation().isValid() &&
- Context.getSourceManager().isInExternCSystemHeader(FD->getLocation()))
+ Context.getASTContext().getSourceManager().
+ isInExternCSystemHeader(FD->getLocation()))
return false;
-
+
// No name mangling in a C linkage specification.
- if (isInCLinkageSpecification(FD))
+ if (!isa<CXXMethodDecl>(FD) && isInCLinkageSpecification(FD))
return false;
}
@@ -109,15 +149,15 @@ bool CXXNameMangler::mangleFunctionDecl(const FunctionDecl *FD) {
}
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.
+ // 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>
@@ -125,43 +165,54 @@ bool CXXNameMangler::mangle(const NamedDecl *D) {
// 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 ||
+ if (!Context.getASTContext().getLangOptions().CPlusPlus ||
isInCLinkageSpecification(D) ||
D->getDeclContext()->isTranslationUnit())
return false;
-
+
Out << "_Z";
mangleName(VD);
return true;
}
-
+
return false;
}
-void CXXNameMangler::mangleCXXCtor(const CXXConstructorDecl *D,
+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,
+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
+void CXXNameMangler::mangleCXXVtable(const CXXRecordDecl *RD) {
+ // <special-name> ::= TV <type> # virtual table
+ Out << "_ZTV";
+ mangleName(RD);
+}
+
+void CXXNameMangler::mangleCXXRtti(const CXXRecordDecl *RD) {
+ // <special-name> ::= TI <type> # typeinfo structure
+ Out << "_ZTI";
+ mangleName(RD);
+}
+
+void CXXNameMangler::mangleGuardVariable(const VarDecl *D) {
+ // <special-name> ::= GV <object name> # Guard variable for one-time
+ // # initialization
Out << "_ZGV";
mangleName(D);
@@ -170,29 +221,34 @@ void CXXNameMangler::mangleGuardVariable(const VarDecl *D)
void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) {
// <encoding> ::= <function name> <bare-function-type>
mangleName(FD);
-
- // Whether the mangling of a function type includes the return type depends
- // on the context and the nature of the function. The rules for deciding
- // whether the return type is included are:
- //
+
+ // Whether the mangling of a function type includes the return type depends on
+ // the context and the nature of the function. The rules for deciding whether
+ // the return type is included are:
+ //
// 1. Template functions (names or types) have return types encoded, with
// the exceptions listed below.
- // 2. Function types not appearing as part of a function name mangling,
+ // 2. Function types not appearing as part of a function name mangling,
// e.g. parameters, pointer types, etc., have return type encoded, with the
// exceptions listed below.
// 3. Non-template function names do not have return types encoded.
//
- // The exceptions mentioned in (1) and (2) above, for which the return
- // type is never included, are
+ // The exceptions mentioned in (1) and (2) above, for which the return type is
+ // never included, are
// 1. Constructors.
// 2. Destructors.
// 3. Conversion operator functions, e.g. operator int.
bool MangleReturnType = false;
- if (FD->getPrimaryTemplate() &&
- !(isa<CXXConstructorDecl>(FD) || isa<CXXDestructorDecl>(FD) ||
- isa<CXXConversionDecl>(FD)))
- MangleReturnType = true;
- mangleBareFunctionType(FD->getType()->getAsFunctionType(), MangleReturnType);
+ if (FunctionTemplateDecl *PrimaryTemplate = FD->getPrimaryTemplate()) {
+ if (!(isa<CXXConstructorDecl>(FD) || isa<CXXDestructorDecl>(FD) ||
+ isa<CXXConversionDecl>(FD)))
+ MangleReturnType = true;
+
+ // Mangle the type of the primary template.
+ FD = PrimaryTemplate->getTemplatedDecl();
+ }
+
+ mangleBareFunctionType(FD->getType()->getAs<FunctionType>(), MangleReturnType);
}
static bool isStdNamespace(const DeclContext *DC) {
@@ -200,37 +256,196 @@ static bool isStdNamespace(const DeclContext *DC) {
return false;
const NamespaceDecl *NS = cast<NamespaceDecl>(DC);
- return NS->getOriginalNamespace()->getIdentifier()->isStr("std");
+ const IdentifierInfo *II = NS->getOriginalNamespace()->getIdentifier();
+ return II && II->isStr("std");
+}
+
+static const TemplateDecl *
+isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) {
+ // Check if we have a function template.
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)){
+ if (const TemplateDecl *TD = FD->getPrimaryTemplate()) {
+ TemplateArgs = FD->getTemplateSpecializationArgs();
+ return TD;
+ }
+ }
+
+ // Check if we have a class template.
+ if (const ClassTemplateSpecializationDecl *Spec =
+ dyn_cast<ClassTemplateSpecializationDecl>(ND)) {
+ TemplateArgs = &Spec->getTemplateArgs();
+ return Spec->getSpecializedTemplate();
+ }
+
+ return 0;
}
void CXXNameMangler::mangleName(const NamedDecl *ND) {
// <name> ::= <nested-name>
// ::= <unscoped-name>
// ::= <unscoped-template-name> <template-args>
- // ::= <local-name> # See Scope Encoding below
+ // ::= <local-name>
//
+ const DeclContext *DC = ND->getDeclContext();
+ while (isa<LinkageSpecDecl>(DC))
+ DC = DC->getParent();
+
+ if (DC->isTranslationUnit() || isStdNamespace(DC)) {
+ // Check if we have a template.
+ const TemplateArgumentList *TemplateArgs = 0;
+ if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
+ mangleUnscopedTemplateName(TD);
+ mangleTemplateArgumentList(*TemplateArgs);
+ return;
+ }
+
+ mangleUnscopedName(ND);
+ return;
+ }
+
+ if (isa<FunctionDecl>(DC)) {
+ mangleLocalName(ND);
+ return;
+ }
+
+ mangleNestedName(ND);
+}
+void CXXNameMangler::mangleName(const TemplateDecl *TD,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs) {
+ const DeclContext *DC = TD->getDeclContext();
+ while (isa<LinkageSpecDecl>(DC)) {
+ assert(cast<LinkageSpecDecl>(DC)->getLanguage() ==
+ LinkageSpecDecl::lang_cxx && "Unexpected linkage decl!");
+ DC = DC->getParent();
+ }
+
+ if (DC->isTranslationUnit() || isStdNamespace(DC)) {
+ mangleUnscopedTemplateName(TD);
+ mangleTemplateArgs(TemplateArgs, NumTemplateArgs);
+ } else {
+ mangleNestedName(TD, TemplateArgs, NumTemplateArgs);
+ }
+}
+
+void CXXNameMangler::mangleUnscopedName(const NamedDecl *ND) {
// <unscoped-name> ::= <unqualified-name>
// ::= St <unqualified-name> # ::std::
- if (ND->getDeclContext()->isTranslationUnit())
- mangleUnqualifiedName(ND);
- else if (isStdNamespace(ND->getDeclContext())) {
+ if (isStdNamespace(ND->getDeclContext()))
Out << "St";
- mangleUnqualifiedName(ND);
- } else if (isa<FunctionDecl>(ND->getDeclContext()))
- mangleLocalName(ND);
- else
- mangleNestedName(ND);
+
+ mangleUnqualifiedName(ND);
+}
+
+void CXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *ND) {
+ // <unscoped-template-name> ::= <unscoped-name>
+ // ::= <substitution>
+ if (mangleSubstitution(ND))
+ return;
+
+ mangleUnscopedName(ND->getTemplatedDecl());
+ addSubstitution(ND);
+}
+
+void CXXNameMangler::mangleCalloffset(int64_t nv, int64_t v) {
+ // <call-offset> ::= h <nv-offset> _
+ // ::= v <v-offset> _
+ // <nv-offset> ::= <offset number> # non-virtual base override
+ // <v-offset> ::= <offset nubmer> _ <virtual offset number>
+ // # virtual base override, with vcall offset
+ if (v == 0) {
+ Out << "h";
+ if (nv < 0) {
+ Out << "n";
+ nv = -nv;
+ }
+ Out << nv;
+ } else {
+ Out << "v";
+ if (nv < 0) {
+ Out << "n";
+ nv = -nv;
+ }
+ Out << nv;
+ Out << "_";
+ if (v < 0) {
+ Out << "n";
+ v = -v;
+ }
+ Out << v;
+ }
+ Out << "_";
+}
+
+void CXXNameMangler::mangleThunk(const FunctionDecl *FD, int64_t nv,
+ int64_t v) {
+ // <special-name> ::= T <call-offset> <base encoding>
+ // # base is the nominal target function of thunk
+ Out << "_ZT";
+ mangleCalloffset(nv, v);
+ mangleFunctionEncoding(FD);
+}
+
+ void CXXNameMangler::mangleCovariantThunk(const FunctionDecl *FD,
+ int64_t nv_t, int64_t v_t,
+ int64_t nv_r, int64_t v_r) {
+ // <special-name> ::= Tc <call-offset> <call-offset> <base encoding>
+ // # base is the nominal target function of thunk
+ // # first call-offset is 'this' adjustment
+ // # second call-offset is result adjustment
+ Out << "_ZTc";
+ mangleCalloffset(nv_t, v_t);
+ mangleCalloffset(nv_r, v_r);
+ mangleFunctionEncoding(FD);
}
void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND) {
// <unqualified-name> ::= <operator-name>
- // ::= <ctor-dtor-name>
- // ::= <source-name>
+ // ::= <ctor-dtor-name>
+ // ::= <source-name>
DeclarationName Name = ND->getDeclName();
switch (Name.getNameKind()) {
- case DeclarationName::Identifier:
- mangleSourceName(Name.getAsIdentifierInfo());
+ case DeclarationName::Identifier: {
+ if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) {
+ if (NS->isAnonymousNamespace()) {
+ // This is how gcc mangles these names. It's apparently
+ // always '1', no matter how many different anonymous
+ // namespaces appear in a context.
+ Out << "12_GLOBAL__N_1";
+ break;
+ }
+ }
+
+ if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) {
+ mangleSourceName(II);
+ break;
+ }
+
+ // We must have an anonymous struct.
+ const TagDecl *TD = cast<TagDecl>(ND);
+ if (const TypedefDecl *D = TD->getTypedefForAnonDecl()) {
+ assert(TD->getDeclContext() == D->getDeclContext() &&
+ "Typedef should not be in another decl context!");
+ assert(D->getDeclName().getAsIdentifierInfo() &&
+ "Typedef was not named!");
+ mangleSourceName(D->getDeclName().getAsIdentifierInfo());
+ break;
+ }
+
+ // Get a unique id for the anonymous struct.
+ uint64_t AnonStructId = Context.getAnonymousStructId(TD);
+
+ // Mangle it as a source name in the form
+ // [n] $_<id>
+ // where n is the length of the string.
+ llvm::SmallString<8> Str;
+ Str += "$_";
+ Str += llvm::utostr(AnonStructId);
+
+ Out << Str.size();
+ Out << Str.str();
break;
+ }
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
@@ -240,8 +455,8 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND) {
case DeclarationName::CXXConstructorName:
if (ND == Structor)
- // If the named decl is the C++ constructor we're mangling, use the
- // type we were given.
+ // 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
@@ -251,8 +466,8 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND) {
case DeclarationName::CXXDestructorName:
if (ND == Structor)
- // If the named decl is the C++ destructor we're mangling, use the
- // type we were given.
+ // 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
@@ -261,9 +476,9 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND) {
break;
case DeclarationName::CXXConversionFunctionName:
- // <operator-name> ::= cv <type> # (cast)
+ // <operator-name> ::= cv <type> # (cast)
Out << "cv";
- mangleType(Context.getCanonicalType(Name.getCXXNameType()));
+ mangleType(Context.getASTContext().getCanonicalType(Name.getCXXNameType()));
break;
case DeclarationName::CXXOperatorName:
@@ -275,12 +490,6 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND) {
assert(false && "Can't mangle a using directive name!");
break;
}
-
- if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(ND)) {
- if (const TemplateArgumentList *TemplateArgs
- = Function->getTemplateSpecializationArgs())
- mangleTemplateArgumentList(*TemplateArgs);
- }
}
void CXXNameMangler::mangleSourceName(const IdentifierInfo *II) {
@@ -293,19 +502,40 @@ void CXXNameMangler::mangleSourceName(const IdentifierInfo *II) {
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);
+ mangleQualifiers(Qualifiers::fromCVRMask(Method->getTypeQualifiers()));
+
+ // Check if we have a template.
+ const TemplateArgumentList *TemplateArgs = 0;
+ if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
+ mangleTemplatePrefix(TD);
+ mangleTemplateArgumentList(*TemplateArgs);
+ } else {
+ manglePrefix(ND->getDeclContext());
+ mangleUnqualifiedName(ND);
+ }
+
+ Out << 'E';
+}
+void CXXNameMangler::mangleNestedName(const TemplateDecl *TD,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs) {
+ // <nested-name> ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
+
+ Out << 'N';
+
+ mangleTemplatePrefix(TD);
+ mangleTemplateArgs(TemplateArgs, NumTemplateArgs);
+
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>
+ // <discriminator> := _ <non-negative number>
Out << 'Z';
mangleFunctionEncoding(cast<FunctionDecl>(ND->getDeclContext()));
Out << 'E';
@@ -319,21 +549,46 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC) {
// ::= # 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());
+ while (isa<LinkageSpecDecl>(DC))
+ DC = DC->getParent();
+
+ if (DC->isTranslationUnit())
+ return;
+
+ if (mangleSubstitution(cast<NamedDecl>(DC)))
+ return;
+
+ // Check if we have a template.
+ const TemplateArgumentList *TemplateArgs = 0;
+ if (const TemplateDecl *TD = isTemplate(cast<NamedDecl>(DC), TemplateArgs)) {
+ mangleTemplatePrefix(TD);
+ mangleTemplateArgumentList(*TemplateArgs);
+ } else {
+ manglePrefix(DC->getParent());
+ mangleUnqualifiedName(cast<NamedDecl>(DC));
}
+
+ addSubstitution(cast<NamedDecl>(DC));
+}
+
+void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND) {
+ // <template-prefix> ::= <prefix> <template unqualified-name>
+ // ::= <template-param>
+ // ::= <substitution>
+
+ if (mangleSubstitution(ND))
+ return;
+
+ // FIXME: <template-param>
+
+ manglePrefix(ND->getDeclContext());
+ mangleUnqualifiedName(ND->getTemplatedDecl());
+
+ addSubstitution(ND);
}
-void
+void
CXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity) {
switch (OO) {
// <operator-name> ::= nw # new
@@ -429,88 +684,58 @@ CXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity) {
case OO_None:
case OO_Conditional:
case NUM_OVERLOADED_OPERATORS:
- assert(false && "Not an overloaded operator");
+ 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)
+void CXXNameMangler::mangleQualifiers(Qualifiers Quals) {
+ // <CV-qualifiers> ::= [r] [V] [K] # restrict (C99), volatile, const
+ if (Quals.hasRestrict())
Out << 'r';
- if (Quals & QualType::Volatile)
+ if (Quals.hasVolatile())
Out << 'V';
- if (Quals & QualType::Const)
+ if (Quals.hasConst())
Out << 'K';
+
+ // FIXME: For now, just drop all extension qualifiers on the floor.
}
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");
+ T = Context.getASTContext().getCanonicalType(T);
+
+ bool IsSubstitutable = !isa<BuiltinType>(T);
+ if (IsSubstitutable && mangleSubstitution(T))
+ return;
+
+ if (Qualifiers Quals = T.getQualifiers()) {
+ mangleQualifiers(Quals);
+ // Recurse: even if the qualified type isn't yet substitutable,
+ // the unqualified type might be.
+ mangleType(T.getUnqualifiedType());
+ } else {
+ switch (T->getTypeClass()) {
+#define ABSTRACT_TYPE(CLASS, PARENT)
+#define NON_CANONICAL_TYPE(CLASS, PARENT) \
+ case Type::CLASS: \
+ llvm::llvm_unreachable("can't mangle non-canonical type " #CLASS "Type"); \
+ return;
+#define TYPE(CLASS, PARENT) \
+ case Type::CLASS: \
+ mangleType(static_cast<const CLASS##Type*>(T.getTypePtr())); \
+ break;
+#include "clang/AST/TypeNodes.def"
+ }
+ }
+
+ // Add the substitution.
+ if (IsSubstitutable)
+ addSubstitution(T);
}
void CXXNameMangler::mangleType(const BuiltinType *T) {
+ // <type> ::= <builtin-type>
// <builtin-type> ::= v # void
// ::= w # wchar_t
// ::= b # bool
@@ -535,8 +760,8 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
// 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
+ // ::= Di # char32_t
+ // ::= 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.
@@ -552,6 +777,8 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
case BuiltinType::UInt128: Out << 'o'; break;
case BuiltinType::SChar: Out << 'a'; break;
case BuiltinType::WChar: Out << 'w'; break;
+ case BuiltinType::Char16: Out << "Ds"; break;
+ case BuiltinType::Char32: Out << "Di"; break;
case BuiltinType::Short: Out << 's'; break;
case BuiltinType::Int: Out << 'i'; break;
case BuiltinType::Long: Out << 'l'; break;
@@ -564,40 +791,45 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
case BuiltinType::Overload:
case BuiltinType::Dependent:
- assert(false &&
+ assert(false &&
"Overloaded and dependent types shouldn't get to name mangling");
break;
case BuiltinType::UndeducedAuto:
assert(0 && "Should not see undeduced auto here");
break;
+ case BuiltinType::ObjCId: Out << "11objc_object"; break;
+ case BuiltinType::ObjCClass: Out << "10objc_class"; break;
}
}
-void CXXNameMangler::mangleType(const FunctionType *T) {
- // <function-type> ::= F [Y] <bare-function-type> E
+// <type> ::= <function-type>
+// <function-type> ::= F [Y] <bare-function-type> E
+void CXXNameMangler::mangleType(const FunctionProtoType *T) {
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::mangleType(const FunctionNoProtoType *T) {
+ llvm::llvm_unreachable("Can't mangle K&R function prototypes");
+}
void CXXNameMangler::mangleBareFunctionType(const FunctionType *T,
bool MangleReturnType) {
+ // We should never be mangling something without a prototype.
+ const FunctionProtoType *Proto = cast<FunctionProtoType>(T);
+
// <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");
+ mangleType(Proto->getResultType());
if (Proto->getNumArgs() == 0) {
Out << 'v';
return;
}
-
+
for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(),
- ArgEnd = Proto->arg_type_end();
+ ArgEnd = Proto->arg_type_end();
Arg != ArgEnd; ++Arg)
mangleType(*Arg);
@@ -606,66 +838,207 @@ void CXXNameMangler::mangleBareFunctionType(const FunctionType *T,
Out << 'z';
}
+// <type> ::= <class-enum-type>
+// <class-enum-type> ::= <name>
+void CXXNameMangler::mangleType(const EnumType *T) {
+ mangleType(static_cast<const TagType*>(T));
+}
+void CXXNameMangler::mangleType(const RecordType *T) {
+ mangleType(static_cast<const TagType*>(T));
+}
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>
+// <type> ::= <array-type>
+// <array-type> ::= A <positive dimension number> _ <element type>
+// ::= A [<dimension expression>] _ <element type>
+void CXXNameMangler::mangleType(const ConstantArrayType *T) {
+ Out << 'A' << T->getSize() << '_';
+ mangleType(T->getElementType());
+}
+void CXXNameMangler::mangleType(const VariableArrayType *T) {
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());
-
+ mangleExpression(T->getSizeExpr());
Out << '_';
mangleType(T->getElementType());
}
+void CXXNameMangler::mangleType(const DependentSizedArrayType *T) {
+ Out << 'A';
+ mangleExpression(T->getSizeExpr());
+ Out << '_';
+ mangleType(T->getElementType());
+}
+void CXXNameMangler::mangleType(const IncompleteArrayType *T) {
+ Out << 'A' << '_';
+ mangleType(T->getElementType());
+}
+// <type> ::= <pointer-to-member-type>
+// <pointer-to-member-type> ::= M <class type> <member type>
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());
+ mangleQualifiers(Qualifiers::fromCVRMask(FPT->getTypeQuals()));
mangleType(FPT);
- } else
+ } else
mangleType(PointeeType);
}
+// <type> ::= <template-param>
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) << '_';
+ mangleTemplateParameter(T->getIndex());
+}
+
+// FIXME: <type> ::= <template-template-param> <template-args>
+
+// <type> ::= P <type> # pointer-to
+void CXXNameMangler::mangleType(const PointerType *T) {
+ Out << 'P';
+ mangleType(T->getPointeeType());
+}
+void CXXNameMangler::mangleType(const ObjCObjectPointerType *T) {
+ Out << 'P';
+ mangleType(T->getPointeeType());
+}
+
+// <type> ::= R <type> # reference-to
+void CXXNameMangler::mangleType(const LValueReferenceType *T) {
+ Out << 'R';
+ mangleType(T->getPointeeType());
+}
+
+// <type> ::= O <type> # rvalue reference-to (C++0x)
+void CXXNameMangler::mangleType(const RValueReferenceType *T) {
+ Out << 'O';
+ mangleType(T->getPointeeType());
+}
+
+// <type> ::= C <type> # complex pair (C 2000)
+void CXXNameMangler::mangleType(const ComplexType *T) {
+ Out << 'C';
+ mangleType(T->getElementType());
+}
+
+// GNU extension: vector types
+void CXXNameMangler::mangleType(const VectorType *T) {
+ Out << "U8__vector";
+ mangleType(T->getElementType());
+}
+void CXXNameMangler::mangleType(const ExtVectorType *T) {
+ mangleType(static_cast<const VectorType*>(T));
+}
+void CXXNameMangler::mangleType(const DependentSizedExtVectorType *T) {
+ Out << "U8__vector";
+ mangleType(T->getElementType());
}
void CXXNameMangler::mangleType(const ObjCInterfaceType *T) {
mangleSourceName(T->getDecl()->getIdentifier());
}
-void CXXNameMangler::mangleExpression(Expr *E) {
- assert(false && "Cannot mangle expressions yet");
+void CXXNameMangler::mangleType(const BlockPointerType *T) {
+ assert(false && "can't mangle block pointer types yet");
}
+void CXXNameMangler::mangleType(const FixedWidthIntType *T) {
+ assert(false && "can't mangle arbitary-precision integer type yet");
+}
+
+void CXXNameMangler::mangleType(const TemplateSpecializationType *T) {
+ TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl();
+ assert(TD && "FIXME: Support dependent template names!");
+
+ mangleName(TD, T->getArgs(), T->getNumArgs());
+}
+
+void CXXNameMangler::mangleType(const TypenameType *T) {
+ // Typename types are always nested
+ Out << 'N';
+
+ const Type *QTy = T->getQualifier()->getAsType();
+ if (const TemplateSpecializationType *TST =
+ dyn_cast<TemplateSpecializationType>(QTy)) {
+ if (!mangleSubstitution(QualType(TST, 0))) {
+ TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl();
+
+ mangleTemplatePrefix(TD);
+ mangleTemplateArgs(TST->getArgs(), TST->getNumArgs());
+ addSubstitution(QualType(TST, 0));
+ }
+ } else if (const TemplateTypeParmType *TTPT =
+ dyn_cast<TemplateTypeParmType>(QTy)) {
+ // We use the QualType mangle type variant here because it handles
+ // substitutions.
+ mangleType(QualType(TTPT, 0));
+ } else
+ assert(false && "Unhandled type!");
+
+ mangleSourceName(T->getIdentifier());
+
+ Out << 'E';
+}
+
+void CXXNameMangler::mangleExpression(const Expr *E) {
+ // <expression> ::= <unary operator-name> <expression>
+ // ::= <binary operator-name> <expression> <expression>
+ // ::= <trinary operator-name> <expression> <expression> <expression>
+ // ::= cl <expression>* E # call
+ // ::= cv <type> expression # conversion with one argument
+ // ::= cv <type> _ <expression>* E # conversion with a different number of arguments
+ // ::= st <type> # sizeof (a type)
+ // ::= at <type> # alignof (a type)
+ // ::= <template-param>
+ // ::= <function-param>
+ // ::= sr <type> <unqualified-name> # dependent name
+ // ::= sr <type> <unqualified-name> <template-args> # dependent template-id
+ // ::= sZ <template-param> # size of a parameter pack
+ // ::= <expr-primary>
+ switch (E->getStmtClass()) {
+ default: assert(false && "Unhandled expression kind!");
+ case Expr::DeclRefExprClass: {
+ const Decl *D = cast<DeclRefExpr>(E)->getDecl();
+
+ switch (D->getKind()) {
+ default: assert(false && "Unhandled decl kind!");
+ case Decl::NonTypeTemplateParm: {
+ const NonTypeTemplateParmDecl *PD = cast<NonTypeTemplateParmDecl>(D);
+ mangleTemplateParameter(PD->getIndex());
+ break;
+ }
+
+ }
+
+ break;
+ }
+
+ case Expr::UnresolvedDeclRefExprClass: {
+ const UnresolvedDeclRefExpr *DRE = cast<UnresolvedDeclRefExpr>(E);
+ const Type *QTy = DRE->getQualifier()->getAsType();
+ assert(QTy && "Qualifier was not type!");
+
+ // ::= sr <type> <unqualified-name> # dependent name
+ Out << "sr";
+ mangleType(QualType(QTy, 0));
+
+ assert(DRE->getDeclName().getNameKind() == DeclarationName::Identifier &&
+ "Unhandled decl name kind!");
+ mangleSourceName(DRE->getDeclName().getAsIdentifierInfo());
+
+ break;
+ }
+
+ }
+}
+
+// FIXME: <type> ::= G <type> # imaginary (C 2000)
+// FIXME: <type> ::= U <source-name> <type> # vendor extended type qualifier
+
void CXXNameMangler::mangleCXXCtorType(CXXCtorType T) {
// <ctor-dtor-name> ::= C1 # complete object constructor
// ::= C2 # base object constructor
@@ -705,18 +1078,30 @@ void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
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::mangleTemplateArgs(const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs) {
+ // <template-args> ::= I <template-arg>+ E
+ Out << "I";
+
+ for (unsigned i = 0; i != NumTemplateArgs; ++i) {
+ mangleTemplateArgument(TemplateArgs[i]);
+ }
Out << "E";
}
void CXXNameMangler::mangleTemplateArgument(const TemplateArgument &A) {
- // <template-arg> ::= <type> # type or template
+ // <template-arg> ::= <type> # type or template
// ::= X <expression> E # expression
// ::= <expr-primary> # simple expressions
// ::= I <template-arg>* E # argument pack
@@ -727,13 +1112,18 @@ void CXXNameMangler::mangleTemplateArgument(const TemplateArgument &A) {
case TemplateArgument::Type:
mangleType(A.getAsType());
break;
+ case TemplateArgument::Expression:
+ Out << 'X';
+ mangleExpression(A.getAsExpr());
+ Out << 'E';
+ 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.
@@ -743,62 +1133,300 @@ void CXXNameMangler::mangleTemplateArgument(const TemplateArgument &A) {
Out << 'n';
Integral->abs().print(Out, false);
}
-
+
Out << 'E';
break;
}
}
+void CXXNameMangler::mangleTemplateParameter(unsigned Index) {
+ // <template-param> ::= T_ # first template parameter
+ // ::= T <parameter-2 non-negative number> _
+ if (Index == 0)
+ Out << "T_";
+ else
+ Out << 'T' << (Index - 1) << '_';
+}
+
+// <substitution> ::= S <seq-id> _
+// ::= S_
+bool CXXNameMangler::mangleSubstitution(const NamedDecl *ND) {
+ // Try one of the standard substitutions first.
+ if (mangleStandardSubstitution(ND))
+ return true;
+
+ return mangleSubstitution(reinterpret_cast<uintptr_t>(ND));
+}
+
+bool CXXNameMangler::mangleSubstitution(QualType T) {
+ if (!T.getCVRQualifiers()) {
+ if (const RecordType *RT = T->getAs<RecordType>())
+ return mangleSubstitution(RT->getDecl());
+ }
+
+ uintptr_t TypePtr = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
+
+ return mangleSubstitution(TypePtr);
+}
+
+bool CXXNameMangler::mangleSubstitution(uintptr_t Ptr) {
+ llvm::DenseMap<uintptr_t, unsigned>::iterator I =
+ Substitutions.find(Ptr);
+ if (I == Substitutions.end())
+ return false;
+
+ unsigned SeqID = I->second;
+ if (SeqID == 0)
+ Out << "S_";
+ else {
+ SeqID--;
+
+ // <seq-id> is encoded in base-36, using digits and upper case letters.
+ char Buffer[10];
+ char *BufferPtr = Buffer + 9;
+
+ *BufferPtr = 0;
+ if (SeqID == 0) *--BufferPtr = '0';
+
+ while (SeqID) {
+ assert(BufferPtr > Buffer && "Buffer overflow!");
+
+ unsigned char c = static_cast<unsigned char>(SeqID) % 36;
+
+ *--BufferPtr = (c < 10 ? '0' + c : 'A' + c - 10);
+ SeqID /= 36;
+ }
+
+ Out << 'S' << BufferPtr << '_';
+ }
+
+ return true;
+}
+
+static bool isCharType(QualType T) {
+ if (T.isNull())
+ return false;
+
+ return T->isSpecificBuiltinType(BuiltinType::Char_S) ||
+ T->isSpecificBuiltinType(BuiltinType::Char_U);
+}
+
+/// isCharSpecialization - Returns whether a given type is a template
+/// specialization of a given name with a single argument of type char.
+static bool isCharSpecialization(QualType T, const char *Name) {
+ if (T.isNull())
+ return false;
+
+ const RecordType *RT = T->getAs<RecordType>();
+ if (!RT)
+ return false;
+
+ const ClassTemplateSpecializationDecl *SD =
+ dyn_cast<ClassTemplateSpecializationDecl>(RT->getDecl());
+ if (!SD)
+ return false;
+
+ if (!isStdNamespace(SD->getDeclContext()))
+ return false;
+
+ const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs();
+ if (TemplateArgs.size() != 1)
+ return false;
+
+ if (!isCharType(TemplateArgs[0].getAsType()))
+ return false;
+
+ if (strcmp(SD->getIdentifier()->getName(), Name) != 0)
+ return false;
+
+ return true;
+}
+
+bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) {
+ // <substitution> ::= St # ::std::
+ if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) {
+ if (isStdNamespace(NS)) {
+ Out << "St";
+ return true;
+ }
+ }
+
+ if (const ClassTemplateDecl *TD = dyn_cast<ClassTemplateDecl>(ND)) {
+ if (!isStdNamespace(TD->getDeclContext()))
+ return false;
+
+ // <substitution> ::= Sa # ::std::allocator
+ if (TD->getIdentifier()->isStr("allocator")) {
+ Out << "Sa";
+ return true;
+ }
+
+ // <<substitution> ::= Sb # ::std::basic_string
+ if (TD->getIdentifier()->isStr("basic_string")) {
+ Out << "Sb";
+ return true;
+ }
+ }
+
+ if (const ClassTemplateSpecializationDecl *SD =
+ dyn_cast<ClassTemplateSpecializationDecl>(ND)) {
+ // <substitution> ::= Ss # ::std::basic_string<char,
+ // ::std::char_traits<char>,
+ // ::std::allocator<char> >
+ if (SD->getIdentifier()->isStr("basic_string")) {
+ const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs();
+
+ if (TemplateArgs.size() != 3)
+ return false;
+
+ if (!isCharType(TemplateArgs[0].getAsType()))
+ return false;
+
+ if (!isCharSpecialization(TemplateArgs[1].getAsType(), "char_traits"))
+ return false;
+
+ if (!isCharSpecialization(TemplateArgs[2].getAsType(), "allocator"))
+ return false;
+
+ Out << "Ss";
+ return true;
+ }
+
+ // <substitution> ::= So # ::std::basic_ostream<char,
+ // ::std::char_traits<char> >
+ if (SD->getIdentifier()->isStr("basic_ostream")) {
+ const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs();
+
+ if (TemplateArgs.size() != 2)
+ return false;
+
+ if (!isCharType(TemplateArgs[0].getAsType()))
+ return false;
+
+ if (!isCharSpecialization(TemplateArgs[1].getAsType(), "char_traits"))
+ return false;
+
+ Out << "So";
+ return true;
+ }
+ }
+ return false;
+}
+
+void CXXNameMangler::addSubstitution(QualType T) {
+ if (!T.getCVRQualifiers()) {
+ if (const RecordType *RT = T->getAs<RecordType>()) {
+ addSubstitution(RT->getDecl());
+ return;
+ }
+ }
+
+ uintptr_t TypePtr = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
+ addSubstitution(TypePtr);
+}
+
+void CXXNameMangler::addSubstitution(uintptr_t Ptr) {
+ unsigned SeqID = Substitutions.size();
+
+ assert(!Substitutions.count(Ptr) && "Substitution already exists!");
+ Substitutions[Ptr] = SeqID;
+}
+
namespace clang {
- /// \brief Mangles the name of the declaration D and emits that name
- /// to the given output stream.
+ /// \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,
+ /// 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(MangleContext &Context, const NamedDecl *D,
llvm::raw_ostream &os) {
assert(!isa<CXXConstructorDecl>(D) &&
"Use mangleCXXCtor for constructor decls!");
assert(!isa<CXXDestructorDecl>(D) &&
"Use mangleCXXDtor for destructor decls!");
+
+ PrettyStackTraceDecl CrashInfo(const_cast<NamedDecl *>(D), SourceLocation(),
+ Context.getASTContext().getSourceManager(),
+ "Mangling declaration");
CXXNameMangler Mangler(Context, os);
- if (!Mangler.mangle(D))
+ if (!Mangler.mangle(cast<NamedDecl>(D->getCanonicalDecl())))
return false;
-
+
os.flush();
return true;
}
-
+
+ /// \brief Mangles the a thunk with the offset n for the declaration D and
+ /// emits that name to the given output stream.
+ void mangleThunk(MangleContext &Context, const FunctionDecl *FD,
+ int64_t nv, int64_t v, llvm::raw_ostream &os) {
+ // FIXME: Hum, we might have to thunk these, fix.
+ assert(!isa<CXXDestructorDecl>(FD) &&
+ "Use mangleCXXDtor for destructor decls!");
+
+ CXXNameMangler Mangler(Context, os);
+ Mangler.mangleThunk(FD, nv, v);
+ os.flush();
+ }
+
+ /// \brief Mangles the a covariant thunk for the declaration D and emits that
+ /// name to the given output stream.
+ void mangleCovariantThunk(MangleContext &Context, const FunctionDecl *FD,
+ int64_t nv_t, int64_t v_t,
+ int64_t nv_r, int64_t v_r,
+ llvm::raw_ostream &os) {
+ // FIXME: Hum, we might have to thunk these, fix.
+ assert(!isa<CXXDestructorDecl>(FD) &&
+ "Use mangleCXXDtor for destructor decls!");
+
+ CXXNameMangler Mangler(Context, os);
+ Mangler.mangleCovariantThunk(FD, nv_t, v_t, nv_r, v_r);
+ os.flush();
+ }
+
/// mangleGuardVariable - Returns the mangled name for a guard variable
/// for the passed in VarDecl.
- void mangleGuardVariable(const VarDecl *D, ASTContext &Context,
+ void mangleGuardVariable(MangleContext &Context, const VarDecl *D,
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) {
+
+ void mangleCXXCtor(MangleContext &Context, const CXXConstructorDecl *D,
+ CXXCtorType Type, 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) {
+
+ void mangleCXXDtor(MangleContext &Context, const CXXDestructorDecl *D,
+ CXXDtorType Type, llvm::raw_ostream &os) {
CXXNameMangler Mangler(Context, os);
Mangler.mangleCXXDtor(D, Type);
-
+
os.flush();
}
-
-
-}
+ void mangleCXXVtable(MangleContext &Context, const CXXRecordDecl *RD,
+ llvm::raw_ostream &os) {
+ CXXNameMangler Mangler(Context, os);
+ Mangler.mangleCXXVtable(RD);
+
+ os.flush();
+ }
+
+ void mangleCXXRtti(MangleContext &Context, const CXXRecordDecl *RD,
+ llvm::raw_ostream &os) {
+ CXXNameMangler Mangler(Context, os);
+ Mangler.mangleCXXRtti(RD);
+
+ os.flush();
+ }
+}
diff --git a/lib/CodeGen/Mangle.h b/lib/CodeGen/Mangle.h
index 77cbd97..2cdb4e2 100644
--- a/lib/CodeGen/Mangle.h
+++ b/lib/CodeGen/Mangle.h
@@ -19,6 +19,8 @@
#define LLVM_CLANG_CODEGEN_MANGLE_H
#include "CGCXX.h"
+#include "clang/AST/Type.h"
+#include "llvm/ADT/DenseMap.h"
namespace llvm {
class raw_ostream;
@@ -28,17 +30,47 @@ namespace clang {
class ASTContext;
class CXXConstructorDecl;
class CXXDestructorDecl;
+ class FunctionDecl;
class NamedDecl;
class VarDecl;
-
- bool mangleName(const NamedDecl *D, ASTContext &Context,
+
+ class MangleContext {
+ ASTContext &Context;
+
+ llvm::DenseMap<const TagDecl *, uint64_t> AnonStructIds;
+
+ public:
+ explicit MangleContext(ASTContext &Context)
+ : Context(Context) { }
+
+ ASTContext &getASTContext() const { return Context; }
+
+ uint64_t getAnonymousStructId(const TagDecl *TD) {
+ std::pair<llvm::DenseMap<const TagDecl *,
+ uint64_t>::iterator, bool> Result =
+ AnonStructIds.insert(std::make_pair(TD, AnonStructIds.size()));
+ return Result.first->second;
+ }
+ };
+
+ bool mangleName(MangleContext &Context, const NamedDecl *D,
llvm::raw_ostream &os);
- void mangleGuardVariable(const VarDecl *D, ASTContext &Context,
+ void mangleThunk(MangleContext &Context, const FunctionDecl *FD,
+ int64_t n, int64_t vn, llvm::raw_ostream &os);
+ void mangleCovariantThunk(MangleContext &Context, const FunctionDecl *FD,
+ int64_t nv_t, int64_t v_t,
+ int64_t nv_r, int64_t v_r,
+ llvm::raw_ostream &os);
+ void mangleGuardVariable(MangleContext &Context, const VarDecl *D,
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);
+ void mangleCXXVtable(MangleContext &Context, const CXXRecordDecl *RD,
+ llvm::raw_ostream &os);
+ void mangleCXXRtti(MangleContext &Context, const CXXRecordDecl *RD,
+ llvm::raw_ostream &os);
+ void mangleCXXCtor(MangleContext &Context, const CXXConstructorDecl *D,
+ CXXCtorType Type, llvm::raw_ostream &os);
+ void mangleCXXDtor(MangleContext &Context, const CXXDestructorDecl *D,
+ CXXDtorType Type, llvm::raw_ostream &os);
}
-#endif
+#endif
diff --git a/lib/CodeGen/ModuleBuilder.cpp b/lib/CodeGen/ModuleBuilder.cpp
index 4835454..c8f686a 100644
--- a/lib/CodeGen/ModuleBuilder.cpp
+++ b/lib/CodeGen/ModuleBuilder.cpp
@@ -40,27 +40,27 @@ namespace {
CodeGeneratorImpl(Diagnostic &diags, const std::string& ModuleName,
const CompileOptions &CO, llvm::LLVMContext& C)
: Diags(diags), CompileOpts(CO), M(new llvm::Module(ModuleName, C)) {}
-
+
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->setTargetTriple(Ctx->Target.getTriple().getTriple());
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)
@@ -94,7 +94,7 @@ namespace {
};
}
-CodeGenerator *clang::CreateLLVMCodeGen(Diagnostic &Diags,
+CodeGenerator *clang::CreateLLVMCodeGen(Diagnostic &Diags,
const std::string& ModuleName,
const CompileOptions &CO,
llvm::LLVMContext& C) {
diff --git a/lib/CodeGen/README.txt b/lib/CodeGen/README.txt
index f60cd03..e6d6109 100644
--- a/lib/CodeGen/README.txt
+++ b/lib/CodeGen/README.txt
@@ -45,21 +45,3 @@ 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/CodeGen/TargetABIInfo.cpp b/lib/CodeGen/TargetABIInfo.cpp
index 896dbd6..59f579f 100644
--- a/lib/CodeGen/TargetABIInfo.cpp
+++ b/lib/CodeGen/TargetABIInfo.cpp
@@ -16,6 +16,8 @@
#include "CodeGenFunction.h"
#include "clang/AST/RecordLayout.h"
#include "llvm/Type.h"
+#include "llvm/ADT/Triple.h"
+#include <cstdio>
using namespace clang;
using namespace CodeGen;
@@ -48,27 +50,30 @@ void ABIArgInfo::dump() const {
fprintf(stderr, ")\n");
}
-static bool isEmptyRecord(ASTContext &Context, QualType T);
+static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays);
/// 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) {
+static bool isEmptyField(ASTContext &Context, const FieldDecl *FD,
+ bool AllowArrays) {
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);
+ // Constant arrays of empty records count as empty, strip them off.
+ if (AllowArrays)
+ while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT))
+ FT = AT->getElementType();
+
+ return isEmptyRecord(Context, FT, AllowArrays);
}
/// 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();
+static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays) {
+ const RecordType *RT = T->getAs<RecordType>();
if (!RT)
return 0;
const RecordDecl *RD = RT->getDecl();
@@ -76,11 +81,32 @@ static bool isEmptyRecord(ASTContext &Context, QualType T) {
return false;
for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
i != e; ++i)
- if (!isEmptyField(Context, *i))
+ if (!isEmptyField(Context, *i, AllowArrays))
return false;
return true;
}
+/// hasNonTrivialDestructorOrCopyConstructor - Determine if a type has either
+/// a non-trivial destructor or a non-trivial copy constructor.
+static bool hasNonTrivialDestructorOrCopyConstructor(const RecordType *RT) {
+ const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
+ if (!RD)
+ return false;
+
+ return !RD->hasTrivialDestructor() || !RD->hasTrivialCopyConstructor();
+}
+
+/// isRecordWithNonTrivialDestructorOrCopyConstructor - Determine if a type is
+/// a record type with either a non-trivial destructor or a non-trivial copy
+/// constructor.
+static bool isRecordWithNonTrivialDestructorOrCopyConstructor(QualType T) {
+ const RecordType *RT = T->getAs<RecordType>();
+ if (!RT)
+ return false;
+
+ return hasNonTrivialDestructorOrCopyConstructor(RT);
+}
+
/// 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
@@ -105,7 +131,7 @@ static const Type *isSingleElementStruct(QualType T, ASTContext &Context) {
QualType FT = FD->getType();
// Ignore empty fields.
- if (isEmptyField(Context, FD))
+ if (isEmptyField(Context, FD, true))
continue;
// If we already found an element then this isn't a single-element
@@ -133,7 +159,9 @@ static const Type *isSingleElementStruct(QualType T, ASTContext &Context) {
}
static bool is32Or64BitBasicType(QualType Ty, ASTContext &Context) {
- if (!Ty->getAsBuiltinType() && !Ty->isPointerType())
+ if (!Ty->getAs<BuiltinType>() && !Ty->isAnyPointerType() &&
+ !Ty->isAnyComplexType() && !Ty->isEnumeralType() &&
+ !Ty->isBlockPointerType())
return false;
uint64_t Size = Context.getTypeSize(Ty);
@@ -168,7 +196,7 @@ static bool typeContainsSSEVector(const RecordDecl *RD, ASTContext &Context) {
Context.getTypeSize(FD->getType()) >= 128)
return true;
- if (const RecordType* RT = FD->getType()->getAsRecordType())
+ if (const RecordType* RT = FD->getType()->getAs<RecordType>())
if (typeContainsSSEVector(RT->getDecl(), Context))
return true;
}
@@ -183,16 +211,20 @@ namespace {
/// conform to any particular ABI.
class DefaultABIInfo : public ABIInfo {
ABIArgInfo classifyReturnType(QualType RetTy,
- ASTContext &Context) const;
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const;
ABIArgInfo classifyArgumentType(QualType RetTy,
- ASTContext &Context) const;
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const;
- virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context) const {
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context);
+ virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context,
+ VMContext);
for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
it != ie; ++it)
- it->info = classifyArgumentType(it->type, Context);
+ it->info = classifyArgumentType(it->type, Context, VMContext);
}
virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
@@ -202,7 +234,8 @@ class DefaultABIInfo : public ABIInfo {
/// X86_32ABIInfo - The X86-32 ABI information.
class X86_32ABIInfo : public ABIInfo {
ASTContext &Context;
- bool IsDarwin;
+ bool IsDarwinVectorABI;
+ bool IsSmallStructInRegABI;
static bool isRegisterSize(unsigned Size) {
return (Size == 8 || Size == 16 || Size == 32 || Size == 64);
@@ -215,23 +248,28 @@ class X86_32ABIInfo : public ABIInfo {
public:
ABIArgInfo classifyReturnType(QualType RetTy,
- ASTContext &Context) const;
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const;
ABIArgInfo classifyArgumentType(QualType RetTy,
- ASTContext &Context) const;
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const;
- virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context) const {
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context);
+ virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context,
+ VMContext);
for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
it != ie; ++it)
- it->info = classifyArgumentType(it->type, Context);
+ it->info = classifyArgumentType(it->type, Context, VMContext);
}
virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
CodeGenFunction &CGF) const;
- X86_32ABIInfo(ASTContext &Context, bool d)
- : ABIInfo(), Context(Context), IsDarwin(d) {}
+ X86_32ABIInfo(ASTContext &Context, bool d, bool p)
+ : ABIInfo(), Context(Context), IsDarwinVectorABI(d),
+ IsSmallStructInRegABI(p) {}
};
}
@@ -255,8 +293,10 @@ bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty,
return true;
}
- // If this is a builtin, pointer, or complex type, it is ok.
- if (Ty->getAsBuiltinType() || Ty->isPointerType() || Ty->isAnyComplexType())
+ // If this is a builtin, pointer, enum, or complex type, it is ok.
+ if (Ty->getAs<BuiltinType>() || Ty->isAnyPointerType() ||
+ Ty->isAnyComplexType() || Ty->isEnumeralType() ||
+ Ty->isBlockPointerType())
return true;
// Arrays are treated like records.
@@ -264,7 +304,7 @@ bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty,
return shouldReturnTypeInRegister(AT->getElementType(), Context);
// Otherwise, it must be a record type.
- const RecordType *RT = Ty->getAsRecordType();
+ const RecordType *RT = Ty->getAs<RecordType>();
if (!RT) return false;
// Structure types are passed in register if all fields would be
@@ -274,7 +314,7 @@ bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty,
const FieldDecl *FD = *i;
// Empty fields are ignored.
- if (isEmptyField(Context, FD))
+ if (isEmptyField(Context, FD, true))
continue;
// Check fields recursively.
@@ -286,26 +326,27 @@ bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty,
}
ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy,
- ASTContext &Context) const {
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
if (RetTy->isVoidType()) {
return ABIArgInfo::getIgnore();
- } else if (const VectorType *VT = RetTy->getAsVectorType()) {
+ } else if (const VectorType *VT = RetTy->getAs<VectorType>()) {
// On Darwin, some vectors are returned in registers.
- if (IsDarwin) {
+ if (IsDarwinVectorABI) {
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));
+ return ABIArgInfo::getCoerce(llvm::VectorType::get(
+ llvm::Type::getInt64Ty(VMContext), 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::getCoerce(llvm::IntegerType::get(VMContext, Size));
return ABIArgInfo::getIndirect(0);
}
@@ -317,33 +358,33 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy,
if (RT->getDecl()->hasFlexibleArrayMember())
return ABIArgInfo::getIndirect(0);
- // Outside of Darwin, structs and unions are always indirect.
- if (!IsDarwin && !RetTy->isAnyComplexType())
+ // If specified, structs and unions are always indirect.
+ if (!IsSmallStructInRegABI && !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 (const BuiltinType *BT = SeltTy->getAs<BuiltinType>()) {
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));
+ return ABIArgInfo::getCoerce(
+ llvm::IntegerType::get(VMContext, (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);
+ return ABIArgInfo::getCoerce(llvm::Type::getFloatTy(VMContext));
} else if (BT->getKind() == BuiltinType::Double) {
assert(Context.getTypeSize(RetTy) == Context.getTypeSize(SeltTy) &&
"Unexpect single element structure size!");
- return ABIArgInfo::getCoerce(llvm::Type::DoubleTy);
+ return ABIArgInfo::getCoerce(llvm::Type::getDoubleTy(VMContext));
}
} 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);
+ const llvm::Type *PtrTy = llvm::Type::getInt8PtrTy(VMContext);
return ABIArgInfo::getCoerce(PtrTy);
} else if (SeltTy->isVectorType()) {
// 64- and 128-bit vectors are never returned in a
@@ -352,7 +393,7 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy,
if (Size == 64 || Size == 128)
return ABIArgInfo::getIndirect(0);
- return classifyReturnType(QualType(SeltTy, 0), Context);
+ return classifyReturnType(QualType(SeltTy, 0), Context, VMContext);
}
}
@@ -360,7 +401,7 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy,
// in a register.
if (X86_32ABIInfo::shouldReturnTypeInRegister(RetTy, Context)) {
uint64_t Size = Context.getTypeSize(RetTy);
- return ABIArgInfo::getCoerce(llvm::IntegerType::get(Size));
+ return ABIArgInfo::getCoerce(llvm::IntegerType::get(VMContext, Size));
}
return ABIArgInfo::getIndirect(0);
@@ -374,20 +415,21 @@ unsigned X86_32ABIInfo::getIndirectArgumentAlignment(QualType Ty,
ASTContext &Context) {
unsigned Align = Context.getTypeAlign(Ty);
if (Align < 128) return 0;
- if (const RecordType* RT = Ty->getAsRecordType())
+ if (const RecordType* RT = Ty->getAs<RecordType>())
if (typeContainsSSEVector(RT->getDecl(), Context))
return 16;
return 0;
}
ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
- ASTContext &Context) const {
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) 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(getIndirectArgumentAlignment(Ty,
+ return ABIArgInfo::getIndirect(getIndirectArgumentAlignment(Ty,
Context));
// Ignore empty structs.
@@ -412,7 +454,7 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
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 *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
const llvm::Type *BPP = llvm::PointerType::getUnqual(BP);
CGBuilderTy &Builder = CGF.Builder;
@@ -426,8 +468,8 @@ llvm::Value *X86_32ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
uint64_t Offset =
llvm::RoundUpToAlignment(CGF.getContext().getTypeSize(Ty) / 8, 4);
llvm::Value *NextAddr =
- Builder.CreateGEP(Addr,
- llvm::ConstantInt::get(llvm::Type::Int32Ty, Offset),
+ Builder.CreateGEP(Addr, llvm::ConstantInt::get(
+ llvm::Type::getInt32Ty(CGF.getLLVMContext()), Offset),
"ap.next");
Builder.CreateStore(NextAddr, VAListAddrAsBPP);
@@ -502,15 +544,18 @@ class X86_64ABIInfo : public ABIInfo {
ASTContext &Context) const;
ABIArgInfo classifyReturnType(QualType RetTy,
- ASTContext &Context) const;
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const;
ABIArgInfo classifyArgumentType(QualType Ty,
ASTContext &Context,
+ llvm::LLVMContext &VMContext,
unsigned &neededInt,
unsigned &neededSSE) const;
public:
- virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context) const;
+ virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context,
+ llvm::LLVMContext &VMContext) const;
virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
CodeGenFunction &CGF) const;
@@ -576,7 +621,7 @@ void X86_64ABIInfo::classify(QualType Ty,
Class &Current = OffsetBase < 64 ? Lo : Hi;
Current = Memory;
- if (const BuiltinType *BT = Ty->getAsBuiltinType()) {
+ if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) {
BuiltinType::Kind k = BT->getKind();
if (k == BuiltinType::Void) {
@@ -594,12 +639,12 @@ void X86_64ABIInfo::classify(QualType Ty,
}
// FIXME: _Decimal32 and _Decimal64 are SSE.
// FIXME: _float128 and _Decimal128 are (SSE, SSEUp).
- } else if (const EnumType *ET = Ty->getAsEnumType()) {
+ } else if (const EnumType *ET = Ty->getAs<EnumType>()) {
// 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()) {
+ } else if (const VectorType *VT = Ty->getAs<VectorType>()) {
uint64_t Size = Context.getTypeSize(VT);
if (Size == 32) {
// gcc passes all <4 x char>, <2 x short>, <1 x int>, <1 x
@@ -631,7 +676,7 @@ void X86_64ABIInfo::classify(QualType Ty,
Lo = SSE;
Hi = SSEUp;
}
- } else if (const ComplexType *CT = Ty->getAsComplexType()) {
+ } else if (const ComplexType *CT = Ty->getAs<ComplexType>()) {
QualType ET = Context.getCanonicalType(CT->getElementType());
uint64_t Size = Context.getTypeSize(Ty);
@@ -688,7 +733,7 @@ void X86_64ABIInfo::classify(QualType Ty,
if (Hi == Memory)
Lo = Memory;
assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp array classification.");
- } else if (const RecordType *RT = Ty->getAsRecordType()) {
+ } else if (const RecordType *RT = Ty->getAs<RecordType>()) {
uint64_t Size = Context.getTypeSize(Ty);
// AMD64-ABI 3.2.3p2: Rule 1. If the size of an object is larger
@@ -696,6 +741,12 @@ void X86_64ABIInfo::classify(QualType Ty,
if (Size > 128)
return;
+ // AMD64-ABI 3.2.3p2: Rule 2. If a C++ object has either a non-trivial
+ // copy constructor or a non-trivial destructor, it is passed by invisible
+ // reference.
+ if (hasNonTrivialDestructorOrCopyConstructor(RT))
+ return;
+
const RecordDecl *RD = RT->getDecl();
// Assume variable sized types are passed in memory.
@@ -781,13 +832,13 @@ void X86_64ABIInfo::classify(QualType Ty,
ABIArgInfo X86_64ABIInfo::getCoerceResult(QualType Ty,
const llvm::Type *CoerceTo,
ASTContext &Context) const {
- if (CoerceTo == llvm::Type::Int64Ty) {
+ if (CoerceTo == llvm::Type::getInt64Ty(CoerceTo->getContext())) {
// Integer and pointer types will end up in a general purpose
// register.
- if (Ty->isIntegralType() || Ty->isPointerType())
+ if (Ty->isIntegralType() || Ty->hasPointerRepresentation())
return (Ty->isPromotableIntegerType() ?
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
- } else if (CoerceTo == llvm::Type::DoubleTy) {
+ } else if (CoerceTo == llvm::Type::getDoubleTy(CoerceTo->getContext())) {
// FIXME: It would probably be better to make CGFunctionInfo only map using
// canonical types than to canonize here.
QualType CTy = Context.getCanonicalType(Ty);
@@ -809,12 +860,15 @@ ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty,
return (Ty->isPromotableIntegerType() ?
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+ bool ByVal = !isRecordWithNonTrivialDestructorOrCopyConstructor(Ty);
+
// FIXME: Set alignment correctly.
- return ABIArgInfo::getIndirect(0);
+ return ABIArgInfo::getIndirect(0, ByVal);
}
ABIArgInfo X86_64ABIInfo::classifyReturnType(QualType RetTy,
- ASTContext &Context) const {
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
// AMD64-ABI 3.2.3p4: Rule 1. Classify the return type with the
// classification algorithm.
X86_64ABIInfo::Class Lo, Hi;
@@ -842,25 +896,25 @@ ABIArgInfo X86_64ABIInfo::classifyReturnType(QualType RetTy,
// 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;
+ ResType = llvm::Type::getInt64Ty(VMContext); 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;
+ ResType = llvm::Type::getDoubleTy(VMContext); 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;
+ ResType = llvm::Type::getX86_FP80Ty(VMContext); 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,
+ ResType = llvm::StructType::get(VMContext, llvm::Type::getX86_FP80Ty(VMContext),
+ llvm::Type::getX86_FP80Ty(VMContext),
NULL);
break;
}
@@ -876,10 +930,12 @@ ABIArgInfo X86_64ABIInfo::classifyReturnType(QualType RetTy,
case NoClass: break;
case Integer:
- ResType = llvm::StructType::get(ResType, llvm::Type::Int64Ty, NULL);
+ ResType = llvm::StructType::get(VMContext, ResType,
+ llvm::Type::getInt64Ty(VMContext), NULL);
break;
case SSE:
- ResType = llvm::StructType::get(ResType, llvm::Type::DoubleTy, NULL);
+ ResType = llvm::StructType::get(VMContext, ResType,
+ llvm::Type::getDoubleTy(VMContext), NULL);
break;
// AMD64-ABI 3.2.3p4: Rule 5. If the class is SSEUP, the eightbyte
@@ -888,7 +944,7 @@ ABIArgInfo X86_64ABIInfo::classifyReturnType(QualType RetTy,
// 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);
+ ResType = llvm::VectorType::get(llvm::Type::getDoubleTy(VMContext), 2);
break;
// AMD64-ABI 3.2.3p4: Rule 7. If the class is X87UP, the value is
@@ -899,7 +955,8 @@ ABIArgInfo X86_64ABIInfo::classifyReturnType(QualType RetTy,
// 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);
+ ResType = llvm::StructType::get(VMContext, ResType,
+ llvm::Type::getDoubleTy(VMContext), NULL);
break;
}
@@ -907,6 +964,7 @@ ABIArgInfo X86_64ABIInfo::classifyReturnType(QualType RetTy,
}
ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, ASTContext &Context,
+ llvm::LLVMContext &VMContext,
unsigned &neededInt,
unsigned &neededSSE) const {
X86_64ABIInfo::Class Lo, Hi;
@@ -944,7 +1002,7 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, ASTContext &Context,
// and %r9 is used.
case Integer:
++neededInt;
- ResType = llvm::Type::Int64Ty;
+ ResType = llvm::Type::getInt64Ty(VMContext);
break;
// AMD64-ABI 3.2.3p3: Rule 3. If the class is SSE, the next
@@ -952,7 +1010,7 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, ASTContext &Context,
// order from %xmm0 to %xmm7.
case SSE:
++neededSSE;
- ResType = llvm::Type::DoubleTy;
+ ResType = llvm::Type::getDoubleTy(VMContext);
break;
}
@@ -968,7 +1026,8 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, ASTContext &Context,
case NoClass: break;
case Integer:
- ResType = llvm::StructType::get(ResType, llvm::Type::Int64Ty, NULL);
+ ResType = llvm::StructType::get(VMContext, ResType,
+ llvm::Type::getInt64Ty(VMContext), NULL);
++neededInt;
break;
@@ -976,7 +1035,8 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, ASTContext &Context,
// memory), except in situations involving unions.
case X87Up:
case SSE:
- ResType = llvm::StructType::get(ResType, llvm::Type::DoubleTy, NULL);
+ ResType = llvm::StructType::get(VMContext, ResType,
+ llvm::Type::getDoubleTy(VMContext), NULL);
++neededSSE;
break;
@@ -985,15 +1045,17 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, ASTContext &Context,
// register.
case SSEUp:
assert(Lo == SSE && "Unexpected SSEUp classification.");
- ResType = llvm::VectorType::get(llvm::Type::DoubleTy, 2);
+ ResType = llvm::VectorType::get(llvm::Type::getDoubleTy(VMContext), 2);
break;
}
return getCoerceResult(Ty, ResType, Context);
}
-void X86_64ABIInfo::computeInfo(CGFunctionInfo &FI, ASTContext &Context) const {
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context);
+void X86_64ABIInfo::computeInfo(CGFunctionInfo &FI, ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType(),
+ Context, VMContext);
// Keep track of the number of assigned registers.
unsigned freeIntRegs = 6, freeSSERegs = 8;
@@ -1008,7 +1070,8 @@ void X86_64ABIInfo::computeInfo(CGFunctionInfo &FI, ASTContext &Context) const {
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);
+ it->info = classifyArgumentType(it->type, Context, VMContext,
+ 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
@@ -1040,11 +1103,13 @@ static llvm::Value *EmitVAArgFromMemory(llvm::Value *VAListAddr,
// shouldn't ever matter in practice.
// overflow_arg_area = (overflow_arg_area + 15) & ~15;
- llvm::Value *Offset = llvm::ConstantInt::get(llvm::Type::Int32Ty, 15);
+ llvm::Value *Offset =
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(CGF.getLLVMContext()), 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);
+ llvm::Type::getInt64Ty(CGF.getLLVMContext()));
+ llvm::Value *Mask = llvm::ConstantInt::get(
+ llvm::Type::getInt64Ty(CGF.getLLVMContext()), ~15LL);
overflow_arg_area =
CGF.Builder.CreateIntToPtr(CGF.Builder.CreateAnd(AsInt, Mask),
overflow_arg_area->getType(),
@@ -1063,7 +1128,8 @@ static llvm::Value *EmitVAArgFromMemory(llvm::Value *VAListAddr,
// an 8 byte boundary.
uint64_t SizeInBytes = (CGF.getContext().getTypeSize(Ty) + 7) / 8;
- llvm::Value *Offset = llvm::ConstantInt::get(llvm::Type::Int32Ty,
+ llvm::Value *Offset =
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(CGF.getLLVMContext()),
(SizeInBytes + 7) & ~7);
overflow_arg_area = CGF.Builder.CreateGEP(overflow_arg_area, Offset,
"overflow_arg_area.next");
@@ -1075,6 +1141,10 @@ static llvm::Value *EmitVAArgFromMemory(llvm::Value *VAListAddr,
llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
CodeGenFunction &CGF) const {
+ llvm::LLVMContext &VMContext = CGF.getLLVMContext();
+ const llvm::Type *i32Ty = llvm::Type::getInt32Ty(VMContext);
+ const llvm::Type *DoubleTy = llvm::Type::getDoubleTy(VMContext);
+
// Assume that va_list type is correct; should be pointer to LLVM type:
// struct {
// i32 gp_offset;
@@ -1083,7 +1153,7 @@ llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
// i8* reg_save_area;
// };
unsigned neededInt, neededSSE;
- ABIArgInfo AI = classifyArgumentType(Ty, CGF.getContext(),
+ ABIArgInfo AI = classifyArgumentType(Ty, CGF.getContext(), VMContext,
neededInt, neededSSE);
// AMD64-ABI 3.5.7p5: Step 1. Determine whether type may be passed
@@ -1110,7 +1180,7 @@ llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
gp_offset = CGF.Builder.CreateLoad(gp_offset_p, "gp_offset");
InRegs =
CGF.Builder.CreateICmpULE(gp_offset,
- llvm::ConstantInt::get(llvm::Type::Int32Ty,
+ llvm::ConstantInt::get(i32Ty,
48 - neededInt * 8),
"fits_in_gp");
}
@@ -1120,7 +1190,7 @@ llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
fp_offset = CGF.Builder.CreateLoad(fp_offset_p, "fp_offset");
llvm::Value *FitsInFP =
CGF.Builder.CreateICmpULE(fp_offset,
- llvm::ConstantInt::get(llvm::Type::Int32Ty,
+ llvm::ConstantInt::get(i32Ty,
176 - neededSSE * 16),
"fits_in_fp");
InRegs = InRegs ? CGF.Builder.CreateAnd(InRegs, FitsInFP) : FitsInFP;
@@ -1171,7 +1241,8 @@ llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
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));
+ RegAddr = CGF.Builder.CreateBitCast(Tmp,
+ llvm::PointerType::getUnqual(LTy));
} else if (neededInt) {
RegAddr = CGF.Builder.CreateGEP(RegAddr, gp_offset);
RegAddr = CGF.Builder.CreateBitCast(RegAddr,
@@ -1188,12 +1259,11 @@ llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
llvm::Value *RegAddrLo = CGF.Builder.CreateGEP(RegAddr, fp_offset);
llvm::Value *RegAddrHi =
CGF.Builder.CreateGEP(RegAddrLo,
- llvm::ConstantInt::get(llvm::Type::Int32Ty, 16));
+ llvm::ConstantInt::get(i32Ty, 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::PointerType::getUnqual(DoubleTy);
+ const llvm::StructType *ST = llvm::StructType::get(VMContext, DoubleTy,
+ DoubleTy, NULL);
llvm::Value *V, *Tmp = CGF.CreateTempAlloca(ST);
V = CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegAddrLo,
DblPtrTy));
@@ -1210,14 +1280,12 @@ llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
// 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);
+ llvm::Value *Offset = llvm::ConstantInt::get(i32Ty, 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);
+ llvm::Value *Offset = llvm::ConstantInt::get(i32Ty, neededSSE * 16);
CGF.Builder.CreateStore(CGF.Builder.CreateAdd(fp_offset, Offset),
fp_offset_p);
}
@@ -1240,28 +1308,37 @@ llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
return ResAddr;
}
-// ABI Info for PIC16
+// PIC16 ABI Implementation
+
+namespace {
+
class PIC16ABIInfo : public ABIInfo {
ABIArgInfo classifyReturnType(QualType RetTy,
- ASTContext &Context) const;
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const;
ABIArgInfo classifyArgumentType(QualType RetTy,
- ASTContext &Context) const;
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const;
- virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context) const {
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context);
+ virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context,
+ VMContext);
for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
it != ie; ++it)
- it->info = classifyArgumentType(it->type, Context);
+ it->info = classifyArgumentType(it->type, Context, VMContext);
}
virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
CodeGenFunction &CGF) const;
-
};
+}
+
ABIArgInfo PIC16ABIInfo::classifyReturnType(QualType RetTy,
- ASTContext &Context) const {
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
if (RetTy->isVoidType()) {
return ABIArgInfo::getIgnore();
} else {
@@ -1270,7 +1347,8 @@ ABIArgInfo PIC16ABIInfo::classifyReturnType(QualType RetTy,
}
ABIArgInfo PIC16ABIInfo::classifyArgumentType(QualType Ty,
- ASTContext &Context) const {
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
return ABIArgInfo::getDirect();
}
@@ -1279,72 +1357,238 @@ llvm::Value *PIC16ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
return 0;
}
+// ARM ABI Implementation
+
+namespace {
+
class ARMABIInfo : public ABIInfo {
+public:
+ enum ABIKind {
+ APCS = 0,
+ AAPCS = 1,
+ AAPCS_VFP
+ };
+
+private:
+ ABIKind Kind;
+
+public:
+ ARMABIInfo(ABIKind _Kind) : Kind(_Kind) {}
+
+private:
+ ABIKind getABIKind() const { return Kind; }
+
ABIArgInfo classifyReturnType(QualType RetTy,
- ASTContext &Context) const;
+ ASTContext &Context,
+ llvm::LLVMContext &VMCOntext) const;
ABIArgInfo classifyArgumentType(QualType RetTy,
- ASTContext &Context) const;
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const;
- virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context) const;
+ virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context,
+ llvm::LLVMContext &VMContext) 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);
+}
+
+void ARMABIInfo::computeInfo(CGFunctionInfo &FI, ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context,
+ VMContext);
for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
it != ie; ++it) {
- it->info = classifyArgumentType(it->type, Context);
+ it->info = classifyArgumentType(it->type, Context, VMContext);
+ }
+
+ // ARM always overrides the calling convention.
+ switch (getABIKind()) {
+ case APCS:
+ FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_APCS);
+ break;
+
+ case AAPCS:
+ FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_AAPCS);
+ break;
+
+ case AAPCS_VFP:
+ FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_AAPCS_VFP);
+ break;
}
}
ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty,
- ASTContext &Context) const {
- if (!CodeGenFunction::hasAggregateLLVMType(Ty)) {
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ if (!CodeGenFunction::hasAggregateLLVMType(Ty))
return (Ty->isPromotableIntegerType() ?
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
- }
+
+ // Ignore empty records.
+ if (isEmptyRecord(Context, Ty, true))
+ return ABIArgInfo::getIgnore();
+
// 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;
+ ElemTy = llvm::Type::getInt64Ty(VMContext);
SizeRegs = (Context.getTypeSize(Ty) + 63) / 64;
} else {
- ElemTy = llvm::Type::Int32Ty;
+ ElemTy = llvm::Type::getInt32Ty(VMContext);
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);
+ const llvm::Type* STy = llvm::StructType::get(VMContext, LLVMFields, true);
return ABIArgInfo::getCoerce(STy);
}
+static bool isIntegerLikeType(QualType Ty,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) {
+ // APCS, C Language Calling Conventions, Non-Simple Return Values: A structure
+ // is called integer-like if its size is less than or equal to one word, and
+ // the offset of each of its addressable sub-fields is zero.
+
+ uint64_t Size = Context.getTypeSize(Ty);
+
+ // Check that the type fits in a word.
+ if (Size > 32)
+ return false;
+
+ // FIXME: Handle vector types!
+ if (Ty->isVectorType())
+ return false;
+
+ // Float types are never treated as "integer like".
+ if (Ty->isRealFloatingType())
+ return false;
+
+ // If this is a builtin or pointer type then it is ok.
+ if (Ty->getAs<BuiltinType>() || Ty->isPointerType())
+ return true;
+
+ // Complex types "should" be ok by the definition above, but they are not.
+ if (Ty->isAnyComplexType())
+ return false;
+
+ // Single element and zero sized arrays should be allowed, by the definition
+ // above, but they are not.
+
+ // Otherwise, it must be a record type.
+ const RecordType *RT = Ty->getAs<RecordType>();
+ if (!RT) return false;
+
+ // Ignore records with flexible arrays.
+ const RecordDecl *RD = RT->getDecl();
+ if (RD->hasFlexibleArrayMember())
+ return false;
+
+ // Check that all sub-fields are at offset 0, and are themselves "integer
+ // like".
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+
+ bool HadField = false;
+ unsigned idx = 0;
+ for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
+ i != e; ++i, ++idx) {
+ const FieldDecl *FD = *i;
+
+ // Check if this field is at offset 0.
+ uint64_t Offset = Layout.getFieldOffset(idx);
+ if (Offset != 0) {
+ // Allow padding bit-fields, but only if they are all at the end of the
+ // structure (despite the wording above, this matches gcc).
+ if (FD->isBitField() &&
+ !FD->getBitWidth()->EvaluateAsInt(Context).getZExtValue()) {
+ for (; i != e; ++i)
+ if (!i->isBitField() ||
+ i->getBitWidth()->EvaluateAsInt(Context).getZExtValue())
+ return false;
+
+ // All remaining fields are padding, allow this.
+ return true;
+ }
+
+ return false;
+ }
+
+ if (!isIntegerLikeType(FD->getType(), Context, VMContext))
+ return false;
+
+ // Only allow at most one field in a structure. Again this doesn't match the
+ // wording above, but follows gcc.
+ if (!RD->isUnion()) {
+ if (HadField)
+ return false;
+
+ HadField = true;
+ }
+ }
+
+ return true;
+}
+
ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy,
- ASTContext &Context) const {
- if (RetTy->isVoidType()) {
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) 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 {
+
+ if (!CodeGenFunction::hasAggregateLLVMType(RetTy))
return (RetTy->isPromotableIntegerType() ?
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+
+ // Are we following APCS?
+ if (getABIKind() == APCS) {
+ if (isEmptyRecord(Context, RetTy, false))
+ return ABIArgInfo::getIgnore();
+
+ // Integer like structures are returned in r0.
+ if (isIntegerLikeType(RetTy, Context, VMContext)) {
+ // Return in the smallest viable integer type.
+ uint64_t Size = Context.getTypeSize(RetTy);
+ if (Size <= 8)
+ return ABIArgInfo::getCoerce(llvm::Type::getInt8Ty(VMContext));
+ if (Size <= 16)
+ return ABIArgInfo::getCoerce(llvm::Type::getInt16Ty(VMContext));
+ return ABIArgInfo::getCoerce(llvm::Type::getInt32Ty(VMContext));
+ }
+
+ // Otherwise return in memory.
+ return ABIArgInfo::getIndirect(0);
}
+
+ // Otherwise this is an AAPCS variant.
+
+ if (isEmptyRecord(Context, RetTy, true))
+ return ABIArgInfo::getIgnore();
+
+ // Aggregates <= 4 bytes are returned in r0; other aggregates
+ // are returned indirectly.
+ uint64_t Size = Context.getTypeSize(RetTy);
+ if (Size <= 32) {
+ // Return in the smallest viable integer type.
+ if (Size <= 8)
+ return ABIArgInfo::getCoerce(llvm::Type::getInt8Ty(VMContext));
+ if (Size <= 16)
+ return ABIArgInfo::getCoerce(llvm::Type::getInt16Ty(VMContext));
+ return ABIArgInfo::getCoerce(llvm::Type::getInt32Ty(VMContext));
+ }
+
+ return ABIArgInfo::getIndirect(0);
}
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 *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
const llvm::Type *BPP = llvm::PointerType::getUnqual(BP);
CGBuilderTy &Builder = CGF.Builder;
@@ -1358,8 +1602,8 @@ llvm::Value *ARMABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
uint64_t Offset =
llvm::RoundUpToAlignment(CGF.getContext().getTypeSize(Ty) / 8, 4);
llvm::Value *NextAddr =
- Builder.CreateGEP(Addr,
- llvm::ConstantInt::get(llvm::Type::Int32Ty, Offset),
+ Builder.CreateGEP(Addr, llvm::ConstantInt::get(
+ llvm::Type::getInt32Ty(CGF.getLLVMContext()), Offset),
"ap.next");
Builder.CreateStore(NextAddr, VAListAddrAsBPP);
@@ -1367,7 +1611,8 @@ llvm::Value *ARMABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
}
ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy,
- ASTContext &Context) const {
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
if (RetTy->isVoidType()) {
return ABIArgInfo::getIgnore();
} else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) {
@@ -1378,8 +1623,88 @@ ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy,
}
}
+// SystemZ ABI Implementation
+
+namespace {
+
+class SystemZABIInfo : public ABIInfo {
+ bool isPromotableIntegerType(QualType Ty) const;
+
+ ABIArgInfo classifyReturnType(QualType RetTy, ASTContext &Context,
+ llvm::LLVMContext &VMContext) const;
+
+ ABIArgInfo classifyArgumentType(QualType RetTy, ASTContext &Context,
+ llvm::LLVMContext &VMContext) const;
+
+ virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType(),
+ Context, VMContext);
+ for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
+ it != ie; ++it)
+ it->info = classifyArgumentType(it->type, Context, VMContext);
+ }
+
+ virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const;
+};
+
+}
+
+bool SystemZABIInfo::isPromotableIntegerType(QualType Ty) const {
+ // SystemZ ABI requires all 8, 16 and 32 bit quantities to be extended.
+ if (const BuiltinType *BT = Ty->getAs<BuiltinType>())
+ 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:
+ case BuiltinType::Int:
+ case BuiltinType::UInt:
+ return true;
+ default:
+ return false;
+ }
+ return false;
+}
+
+llvm::Value *SystemZABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const {
+ // FIXME: Implement
+ return 0;
+}
+
+
+ABIArgInfo SystemZABIInfo::classifyReturnType(QualType RetTy,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ if (RetTy->isVoidType()) {
+ return ABIArgInfo::getIgnore();
+ } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) {
+ return ABIArgInfo::getIndirect(0);
+ } else {
+ return (isPromotableIntegerType(RetTy) ?
+ ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+ }
+}
+
+ABIArgInfo SystemZABIInfo::classifyArgumentType(QualType Ty,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ if (CodeGenFunction::hasAggregateLLVMType(Ty)) {
+ return ABIArgInfo::getIndirect(0);
+ } else {
+ return (isPromotableIntegerType(Ty) ?
+ ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+ }
+}
+
ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty,
- ASTContext &Context) const {
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
if (CodeGenFunction::hasAggregateLLVMType(Ty)) {
return ABIArgInfo::getIndirect(0);
} else {
@@ -1397,23 +1722,45 @@ 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) {
+ // For now we just cache the ABIInfo in CodeGenTypes and don't free it.
+
+ const llvm::Triple &Triple(getContext().Target.getTriple());
+ switch (Triple.getArch()) {
+ default:
+ return *(TheABIInfo = new DefaultABIInfo);
+
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ // FIXME: We want to know the float calling convention as well.
+ if (strcmp(getContext().Target.getABI(), "apcs-gnu") == 0)
+ return *(TheABIInfo = new ARMABIInfo(ARMABIInfo::APCS));
+
+ return *(TheABIInfo = new ARMABIInfo(ARMABIInfo::AAPCS));
+
+ case llvm::Triple::pic16:
return *(TheABIInfo = new PIC16ABIInfo());
- }
- return *(TheABIInfo = new DefaultABIInfo);
+ case llvm::Triple::systemz:
+ return *(TheABIInfo = new SystemZABIInfo());
+
+ case llvm::Triple::x86:
+ if (Triple.getOS() == llvm::Triple::Darwin)
+ return *(TheABIInfo = new X86_32ABIInfo(Context, true, true));
+
+ switch (Triple.getOS()) {
+ case llvm::Triple::Cygwin:
+ case llvm::Triple::DragonFly:
+ case llvm::Triple::MinGW32:
+ case llvm::Triple::MinGW64:
+ case llvm::Triple::FreeBSD:
+ case llvm::Triple::OpenBSD:
+ return *(TheABIInfo = new X86_32ABIInfo(Context, false, true));
+
+ default:
+ return *(TheABIInfo = new X86_32ABIInfo(Context, false, false));
+ }
+
+ case llvm::Triple::x86_64:
+ return *(TheABIInfo = new X86_64ABIInfo());
+ }
}
diff --git a/lib/Driver/Action.cpp b/lib/Driver/Action.cpp
index cabc33e..6243489 100644
--- a/lib/Driver/Action.cpp
+++ b/lib/Driver/Action.cpp
@@ -29,16 +29,16 @@ const char *Action::getClassName(ActionClass AC) {
case LinkJobClass: return "linker";
case LipoJobClass: return "lipo";
}
-
+
assert(0 && "invalid class");
return 0;
}
-InputAction::InputAction(const Arg &_Input, types::ID _Type)
+InputAction::InputAction(const Arg &_Input, types::ID _Type)
: Action(InputClass, _Type), Input(_Input) {
}
-BindArchAction::BindArchAction(Action *Input, const char *_ArchName)
+BindArchAction::BindArchAction(Action *Input, const char *_ArchName)
: Action(BindArchClass, Input, Input->getType()), ArchName(_ArchName) {
}
@@ -46,7 +46,7 @@ JobAction::JobAction(ActionClass Kind, Action *Input, types::ID Type)
: Action(Kind, Input, Type) {
}
-JobAction::JobAction(ActionClass Kind, const ActionList &Inputs, types::ID Type)
+JobAction::JobAction(ActionClass Kind, const ActionList &Inputs, types::ID Type)
: Action(Kind, Inputs, Type) {
}
@@ -70,10 +70,10 @@ AssembleJobAction::AssembleJobAction(Action *Input, types::ID OutputType)
: JobAction(AssembleJobClass, Input, OutputType) {
}
-LinkJobAction::LinkJobAction(ActionList &Inputs, types::ID Type)
+LinkJobAction::LinkJobAction(ActionList &Inputs, types::ID Type)
: JobAction(LinkJobClass, Inputs, Type) {
}
-LipoJobAction::LipoJobAction(ActionList &Inputs, types::ID Type)
+LipoJobAction::LipoJobAction(ActionList &Inputs, types::ID Type)
: JobAction(LipoJobClass, Inputs, Type) {
}
diff --git a/lib/Driver/Arg.cpp b/lib/Driver/Arg.cpp
index e227d7e..a09ba09 100644
--- a/lib/Driver/Arg.cpp
+++ b/lib/Driver/Arg.cpp
@@ -14,10 +14,9 @@
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(ArgClass _Kind, const Option *_Opt, unsigned _Index,
+ const Arg *_BaseArg)
+ : Kind(_Kind), Opt(_Opt), BaseArg(_BaseArg), Index(_Index), Claimed(false) {
}
Arg::~Arg() { }
@@ -54,7 +53,7 @@ std::string Arg::getAsString(const ArgList &Args) const {
ArgStringList ASL;
render(Args, ASL);
- for (ArgStringList::iterator
+ for (ArgStringList::iterator
it = ASL.begin(), ie = ASL.end(); it != ie; ++it) {
if (it != ASL.begin())
OS << ' ';
@@ -87,7 +86,7 @@ const char *FlagArg::getValue(const ArgList &Args, unsigned N) const {
return 0;
}
-PositionalArg::PositionalArg(const Option *Opt, unsigned Index,
+PositionalArg::PositionalArg(const Option *Opt, unsigned Index,
const Arg *BaseArg)
: Arg(PositionalClass, Opt, Index, BaseArg) {
}
@@ -120,10 +119,10 @@ const char *JoinedArg::getValue(const ArgList &Args, unsigned N) const {
return Args.getArgString(getIndex()) + strlen(getOption().getName());
}
-CommaJoinedArg::CommaJoinedArg(const Option *Opt, unsigned Index,
+CommaJoinedArg::CommaJoinedArg(const Option *Opt, unsigned Index,
const char *Str, const Arg *BaseArg)
: Arg(CommaJoinedClass, Opt, Index, BaseArg) {
- const char *Prev = Str;
+ const char *Prev = Str;
for (;; ++Str) {
char c = *Str;
@@ -167,23 +166,23 @@ void SeparateArg::render(const ArgList &Args, ArgStringList &Output) const {
}
}
-const char *SeparateArg::getValue(const ArgList &Args, unsigned N) const {
+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,
+JoinedAndSeparateArg::JoinedAndSeparateArg(const Option *Opt, unsigned Index,
const Arg *BaseArg)
: Arg(JoinedAndSeparateClass, Opt, Index, BaseArg) {
}
-void JoinedAndSeparateArg::render(const ArgList &Args,
+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,
+const char *JoinedAndSeparateArg::getValue(const ArgList &Args,
unsigned N) const {
assert(N < getNumValues() && "Invalid index.");
if (N == 0)
diff --git a/lib/Driver/ArgList.cpp b/lib/Driver/ArgList.cpp
index 54dd4bb..8d2138d 100644
--- a/lib/Driver/ArgList.cpp
+++ b/lib/Driver/ArgList.cpp
@@ -11,6 +11,10 @@
#include "clang/Driver/Arg.h"
#include "clang/Driver/Option.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/raw_ostream.h"
+
using namespace clang::driver;
ArgList::ArgList(arglist_type &_Args) : Args(_Args) {
@@ -31,13 +35,13 @@ Arg *ArgList::getLastArg(options::ID Id, bool Claim) const {
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
@@ -102,7 +106,7 @@ void ArgList::AddAllArgs(ArgStringList &Output, options::ID Id0) const {
}
}
-void ArgList::AddAllArgs(ArgStringList &Output, options::ID Id0,
+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) {
@@ -114,7 +118,7 @@ void ArgList::AddAllArgs(ArgStringList &Output, options::ID Id0,
}
}
-void ArgList::AddAllArgs(ArgStringList &Output, options::ID Id0,
+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) {
@@ -139,7 +143,7 @@ void ArgList::AddAllArgValues(ArgStringList &Output, options::ID Id0) const {
}
}
-void ArgList::AddAllArgValues(ArgStringList &Output, options::ID Id0,
+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) {
@@ -182,11 +186,16 @@ void ArgList::ClaimAllArgs(options::ID Id0) const {
}
}
+const char *ArgList::MakeArgString(const llvm::Twine &T) const {
+ llvm::SmallString<256> Str;
+ T.toVector(Str);
+ return MakeArgString(Str.str());
+}
+
//
-InputArgList::InputArgList(const char **ArgBegin, const char **ArgEnd)
- : ArgList(ActualArgs), NumInputArgStrings(ArgEnd - ArgBegin)
-{
+InputArgList::InputArgList(const char **ArgBegin, const char **ArgEnd)
+ : ArgList(ActualArgs), NumInputArgStrings(ArgEnd - ArgBegin) {
ArgStrings.append(ArgBegin, ArgEnd);
}
@@ -196,7 +205,7 @@ InputArgList::~InputArgList() {
delete *it;
}
-unsigned InputArgList::MakeIndex(const char *String0) const {
+unsigned InputArgList::MakeIndex(llvm::StringRef String0) const {
unsigned Index = ArgStrings.size();
// Tuck away so we have a reliable const char *.
@@ -206,8 +215,8 @@ unsigned InputArgList::MakeIndex(const char *String0) const {
return Index;
}
-unsigned InputArgList::MakeIndex(const char *String0,
- const char *String1) const {
+unsigned InputArgList::MakeIndex(llvm::StringRef String0,
+ llvm::StringRef String1) const {
unsigned Index0 = MakeIndex(String0);
unsigned Index1 = MakeIndex(String1);
assert(Index0 + 1 == Index1 && "Unexpected non-consecutive indices!");
@@ -215,7 +224,7 @@ unsigned InputArgList::MakeIndex(const char *String0,
return Index0;
}
-const char *InputArgList::MakeArgString(const char *Str) const {
+const char *InputArgList::MakeArgString(llvm::StringRef Str) const {
return getArgString(MakeIndex(Str));
}
@@ -223,18 +232,17 @@ const char *InputArgList::MakeArgString(const char *Str) const {
DerivedArgList::DerivedArgList(InputArgList &_BaseArgs, bool _OnlyProxy)
: ArgList(_OnlyProxy ? _BaseArgs.getArgs() : ActualArgs),
- BaseArgs(_BaseArgs), OnlyProxy(_OnlyProxy)
-{
+ BaseArgs(_BaseArgs), OnlyProxy(_OnlyProxy) {
}
DerivedArgList::~DerivedArgList() {
// We only own the arguments we explicitly synthesized.
- for (iterator it = SynthesizedArgs.begin(), ie = SynthesizedArgs.end();
+ for (iterator it = SynthesizedArgs.begin(), ie = SynthesizedArgs.end();
it != ie; ++it)
delete *it;
}
-const char *DerivedArgList::MakeArgString(const char *Str) const {
+const char *DerivedArgList::MakeArgString(llvm::StringRef Str) const {
return BaseArgs.MakeArgString(Str);
}
@@ -242,19 +250,19 @@ 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 {
+Arg *DerivedArgList::MakePositionalArg(const Arg *BaseArg, const Option *Opt,
+ llvm::StringRef 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,
+Arg *DerivedArgList::MakeSeparateArg(const Arg *BaseArg, const Option *Opt,
+ llvm::StringRef 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 {
+Arg *DerivedArgList::MakeJoinedArg(const Arg *BaseArg, const Option *Opt,
+ llvm::StringRef Value) const {
std::string Joined(Opt->getName());
Joined += Value;
return new JoinedArg(Opt, BaseArgs.MakeIndex(Joined.c_str()), BaseArg);
diff --git a/lib/Driver/Compilation.cpp b/lib/Driver/Compilation.cpp
index 7e29b67..c12f5aa 100644
--- a/lib/Driver/Compilation.cpp
+++ b/lib/Driver/Compilation.cpp
@@ -23,36 +23,38 @@ using namespace clang::driver;
Compilation::Compilation(const Driver &D,
const ToolChain &_DefaultToolChain,
- InputArgList *_Args)
+ InputArgList *_Args)
: TheDriver(D), DefaultToolChain(_DefaultToolChain), Args(_Args) {
}
-Compilation::~Compilation() {
+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)
+ for (llvm::DenseMap<std::pair<const ToolChain*, const char*>,
+ 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();
+ for (ActionList::iterator it = Actions.begin(), ie = Actions.end();
it != ie; ++it)
delete *it;
}
-const DerivedArgList &Compilation::getArgsForToolChain(const ToolChain *TC) {
+const DerivedArgList &Compilation::getArgsForToolChain(const ToolChain *TC,
+ const char *BoundArch) {
if (!TC)
TC = &DefaultToolChain;
- DerivedArgList *&Entry = TCArgs[TC];
+ DerivedArgList *&Entry = TCArgs[std::make_pair(TC, BoundArch)];
if (!Entry)
- Entry = TC->TranslateArgs(*Args);
+ Entry = TC->TranslateArgs(*Args, BoundArch);
return *Entry;
}
-void Compilation::PrintJob(llvm::raw_ostream &OS, const Job &J,
+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() << '"';
@@ -65,22 +67,22 @@ void Compilation::PrintJob(llvm::raw_ostream &OS, const Job &J,
}
OS << Terminator;
} else if (const PipedJob *PJ = dyn_cast<PipedJob>(&J)) {
- for (PipedJob::const_iterator
+ 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
+ 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 Compilation::CleanupFileList(const ArgStringList &Files,
bool IssueErrors) const {
bool Success = true;
- for (ArgStringList::const_iterator
+ for (ArgStringList::const_iterator
it = Files.begin(), ie = Files.end(); it != ie; ++it) {
llvm::sys::Path P(*it);
std::string Error;
@@ -92,7 +94,7 @@ bool Compilation::CleanupFileList(const ArgStringList &Files,
// FIXME: Grumble, P.exists() is broken. PR3837.
struct stat buf;
- if (::stat(P.c_str(), &buf) == 0
+ if (::stat(P.c_str(), &buf) == 0
|| errno != ENOENT) {
if (IssueErrors)
getDriver().Diag(clang::diag::err_drv_unable_to_remove_file)
@@ -112,12 +114,12 @@ int Compilation::ExecuteCommand(const Command &C,
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 =
+ int Res =
llvm::sys::Program::ExecuteAndWait(Prog, Argv,
/*env*/0, /*redirects*/0,
/*secondsToWait*/0, /*memoryLimit*/0,
@@ -126,7 +128,7 @@ int Compilation::ExecuteCommand(const Command &C,
assert(Res && "Error string set with 0 result code!");
getDriver().Diag(clang::diag::err_drv_command_failure) << Error;
}
-
+
if (Res)
FailingCommand = &C;
@@ -134,7 +136,7 @@ int Compilation::ExecuteCommand(const Command &C,
return Res;
}
-int Compilation::ExecuteJob(const Job &J,
+int Compilation::ExecuteJob(const Job &J,
const Command *&FailingCommand) const {
if (const Command *C = dyn_cast<Command>(&J)) {
return ExecuteCommand(*C, FailingCommand);
@@ -142,13 +144,13 @@ int Compilation::ExecuteJob(const Job &J,
// Piped commands with a single job are easy.
if (PJ->size() == 1)
return ExecuteCommand(**PJ->begin(), FailingCommand);
-
+
FailingCommand = *PJ->begin();
getDriver().Diag(clang::diag::err_drv_unsupported_opt) << "-pipe";
return 1;
} else {
const JobList *Jobs = cast<JobList>(&J);
- for (JobList::const_iterator
+ for (JobList::const_iterator
it = Jobs->begin(), ie = Jobs->end(); it != ie; ++it)
if (int Res = ExecuteJob(**it, FailingCommand))
return Res;
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 1b0b561..b4693f2 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -37,22 +37,34 @@
using namespace clang::driver;
using namespace clang;
+// Used to set values for "production" clang, for releases.
+// #define USE_PRODUCTION_CLANG
+
Driver::Driver(const char *_Name, const char *_Dir,
const char *_DefaultHostTriple,
const char *_DefaultImageName,
- Diagnostic &_Diags)
- : Opts(new OptTable()), Diags(_Diags),
+ bool IsProduction, 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");
+ CCCGenericGCCName("gcc"), CCCUseClang(true),
+ CCCUseClangCXX(true), CCCUseClangCPP(true), CCCUsePCH(true),
+ SuppressMissingInputWarning(false) {
+ if (IsProduction) {
+ // In a "production" build, only use clang on architectures we expect to
+ // work, and don't use clang C++.
+ //
+ // During development its more convenient to always have the driver use
+ // clang, but we don't want users to be confused when things don't work, or
+ // to file bugs for things we don't support.
+ CCCClangArchs.insert(llvm::Triple::x86);
+ CCCClangArchs.insert(llvm::Triple::x86_64);
+ CCCClangArchs.insert(llvm::Triple::arm);
+
+ CCCUseClangCXX = false;
+ }
}
Driver::~Driver() {
@@ -60,20 +72,20 @@ Driver::~Driver() {
delete Host;
}
-InputArgList *Driver::ParseArgStrings(const char **ArgBegin,
+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. :)
+ // 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).
+ // We just ignore them here (note that other things may still take them as
+ // arguments).
if (Args->getArgString(Index)[0] == '\0') {
++Index;
continue;
@@ -105,28 +117,27 @@ InputArgList *Driver::ParseArgStrings(const char **ArgBegin,
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: Handle environment options which effect driver behavior, somewhere
+ // (client?). GCC_EXEC_PREFIX, COMPILER_PATH, LIBRARY_PATH, LPATH,
+ // CC_PRINT_OPTIONS.
// FIXME: What are we going to do with -V and -b?
- // FIXME: This stuff needs to go into the Compilation, not the
- // driver.
+ // 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.
+ // 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.
+ // 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")) {
@@ -137,13 +148,15 @@ Compilation *Driver::BuildCompilation(int argc, const char **argv) {
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, "no-clang-cxx")) {
+ CCCUseClangCXX = false;
} else if (!strcmp(Opt, "pch-is-pch")) {
CCCUsePCH = true;
} else if (!strcmp(Opt, "pch-is-pth")) {
@@ -154,27 +167,35 @@ Compilation *Driver::BuildCompilation(int argc, const char **argv) {
CCCUseClangCPP = false;
} else if (!strcmp(Opt, "clang-archs")) {
assert(Start+1 < End && "FIXME: -ccc- argument handling.");
- const char *Cur = *++Start;
-
+ llvm::StringRef Cur = *++Start;
+
CCCClangArchs.clear();
- for (;;) {
- const char *Next = strchr(Cur, ',');
+ while (!Cur.empty()) {
+ std::pair<llvm::StringRef, llvm::StringRef> Split = Cur.split(',');
- if (Next) {
- if (Cur != Next)
- CCCClangArchs.insert(std::string(Cur, Next));
- Cur = Next + 1;
- } else {
- if (*Cur != '\0')
- CCCClangArchs.insert(std::string(Cur));
- break;
+ if (!Split.first.empty()) {
+ llvm::Triple::ArchType Arch =
+ llvm::Triple(Split.first, "", "").getArch();
+
+ if (Arch == llvm::Triple::UnknownArch) {
+ // FIXME: Error handling.
+ llvm::errs() << "invalid arch name: " << Split.first << "\n";
+ exit(1);
+ }
+
+ CCCClangArchs.insert(Arch);
}
- }
+ Cur = Split.second;
+ }
} else if (!strcmp(Opt, "host-triple")) {
assert(Start+1 < End && "FIXME: -ccc- argument handling.");
HostTriple = *++Start;
+ } else if (!strcmp(Opt, "install-dir")) {
+ assert(Start+1 < End && "FIXME: -ccc- argument handling.");
+ Dir = *++Start;
+
} else {
// FIXME: Error handling.
llvm::errs() << "invalid option: " << *Start << "\n";
@@ -187,7 +208,7 @@ Compilation *Driver::BuildCompilation(int argc, const char **argv) {
Host = GetHostInfo(HostTriple);
// The compilation takes ownership of Args.
- Compilation *C = new Compilation(*this, *Host->getToolChain(*Args), Args);
+ Compilation *C = new Compilation(*this, *Host->CreateToolChain(*Args), Args);
// FIXME: This behavior shouldn't be here.
if (CCCPrintOptions) {
@@ -198,10 +219,10 @@ Compilation *Driver::BuildCompilation(int argc, const char **argv) {
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).
+ // 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
@@ -230,7 +251,7 @@ int Driver::ExecuteCompilation(const Compilation &C) const {
const Command *FailingCommand = 0;
int Res = C.ExecuteJob(C.getJobs(), FailingCommand);
-
+
// Remove temp files.
C.CleanupFileList(C.getTempFiles());
@@ -254,10 +275,10 @@ int Driver::ExecuteCompilation(const Compilation &C) const {
if (!IsFriendlyTool || Res != 1) {
// FIXME: See FIXME above regarding result code interpretation.
if (Res < 0)
- Diag(clang::diag::err_drv_command_signalled)
+ Diag(clang::diag::err_drv_command_signalled)
<< Source.getClassName() << -Res;
else
- Diag(clang::diag::err_drv_command_failed)
+ Diag(clang::diag::err_drv_command_failed)
<< Source.getClassName() << Res;
}
}
@@ -267,7 +288,7 @@ int Driver::ExecuteCompilation(const Compilation &C) const {
void Driver::PrintOptions(const ArgList &Args) const {
unsigned i = 0;
- for (ArgList::const_iterator it = Args.begin(), ie = Args.end();
+ for (ArgList::const_iterator it = Args.begin(), ie = Args.end();
it != ie; ++it, ++i) {
Arg *A = *it;
llvm::errs() << "Option " << i << " - "
@@ -284,10 +305,10 @@ void Driver::PrintOptions(const ArgList &Args) const {
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:
+ case Option::GroupClass: case Option::InputClass: case Option::UnknownClass:
assert(0 && "Invalid option with help text.");
case Option::MultiArgClass: case Option::JoinedAndSeparateClass:
@@ -333,11 +354,13 @@ void Driver::PrintHelp(bool ShowHidden) const {
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++"));
+ "Enable the clang compiler for C++"));
+ OptionHelp.push_back(std::make_pair("-ccc-no-clang-cxx",
+ "Disable the clang compiler for C++"));
OptionHelp.push_back(std::make_pair("-ccc-no-clang",
- "Never use the clang compiler"));
+ "Disable the clang compiler"));
OptionHelp.push_back(std::make_pair("-ccc-no-clang-cpp",
- "Never use the clang preprocessor"));
+ "Disable the clang preprocessor"));
OptionHelp.push_back(std::make_pair("-ccc-clang-archs",
"Comma separate list of architectures "
"to use the clang compiler for"));
@@ -348,7 +371,9 @@ void Driver::PrintHelp(bool ShowHidden) const {
OptionHelp.push_back(std::make_pair("\nDEBUG/DEVELOPMENT OPTIONS:",""));
OptionHelp.push_back(std::make_pair("-ccc-host-triple",
- "Simulate running on the given target"));
+ "Simulate running on the given target"));
+ OptionHelp.push_back(std::make_pair("-ccc-install-dir",
+ "Simulate installation in the given directory"));
OptionHelp.push_back(std::make_pair("-ccc-print-options",
"Dump parsed command line arguments"));
OptionHelp.push_back(std::make_pair("-ccc-print-phases",
@@ -360,15 +385,14 @@ void Driver::PrintHelp(bool ShowHidden) const {
"arguments to prepend to the command line"));
}
- // Find the maximum option length.
+ // 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.
+ // 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);
@@ -385,60 +409,51 @@ void Driver::PrintHelp(bool ShowHidden) const {
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 = "";
+void Driver::PrintVersion(const Compilation &C, llvm::raw_ostream &OS) const {
+ // FIXME: The following handlers should use a callback mechanism, we don't
+ // know what the client would like to do.
+#ifdef CLANG_VENDOR
+ OS << CLANG_VENDOR;
#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';
+ OS << "clang version " CLANG_VERSION_STRING " ("
+ << getClangSubversionPath();
+ if (unsigned Revision = getClangSubversionRevision())
+ OS << " " << Revision;
+ OS << ")" << '\n';
const ToolChain &TC = C.getDefaultToolChain();
- llvm::errs() << "Target: " << TC.getTripleString() << '\n';
+ OS << "Target: " << TC.getTripleString() << '\n';
// Print the threading model.
//
// FIXME: Implement correctly.
- llvm::errs() << "Thread model: " << "posix" << '\n';
+ OS << "Thread model: " << "posix" << '\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.
+ // 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) ||
+ 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);
+ // Follow gcc behavior and use stdout for --version and stderr for -v.
+ PrintVersion(C, llvm::outs());
return false;
}
- if (C.getArgs().hasArg(options::OPT_v) ||
+ if (C.getArgs().hasArg(options::OPT_v) ||
C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)) {
- PrintVersion(C);
+ PrintVersion(C, llvm::errs());
SuppressMissingInputWarning = true;
}
@@ -453,7 +468,7 @@ bool Driver::HandleImmediateArgs(const Compilation &C) {
}
llvm::outs() << "\n";
llvm::outs() << "libraries: =";
- for (ToolChain::path_list::const_iterator it = TC.getFilePaths().begin(),
+ for (ToolChain::path_list::const_iterator it = TC.getFilePaths().begin(),
ie = TC.getFilePaths().end(); it != ie; ++it) {
if (it != TC.getFilePaths().begin())
llvm::outs() << ':';
@@ -463,22 +478,20 @@ bool Driver::HandleImmediateArgs(const Compilation &C) {
return false;
}
- // FIXME: The following handlers should use a callback mechanism, we
- // don't know what the client would like to do.
+ // 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";
+ llvm::outs() << GetFilePath(A->getValue(C.getArgs()), TC) << "\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";
+ llvm::outs() << GetProgramPath(A->getValue(C.getArgs()), TC) << "\n";
return false;
}
if (C.getArgs().hasArg(options::OPT_print_libgcc_file_name)) {
- llvm::outs() << GetFilePath("libgcc.a", TC).toString() << "\n";
+ llvm::outs() << GetFilePath("libgcc.a", TC) << "\n";
return false;
}
@@ -489,7 +502,7 @@ bool Driver::HandleImmediateArgs(const Compilation &C) {
switch (C.getDefaultToolChain().getTriple().getArch()) {
default:
break;
-
+
case llvm::Triple::x86_64:
llvm::outs() << "x86_64;@m64" << "\n";
break;
@@ -511,7 +524,7 @@ bool Driver::HandleImmediateArgs(const Compilation &C) {
case llvm::Triple::ppc:
llvm::outs() << "." << "\n";
break;
-
+
case llvm::Triple::x86_64:
llvm::outs() << "x86_64" << "\n";
break;
@@ -526,20 +539,19 @@ bool Driver::HandleImmediateArgs(const Compilation &C) {
return true;
}
-static unsigned PrintActions1(const Compilation &C,
- Action *A,
+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)) {
+ 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() :
+ os << '"' << (BIA->getArchName() ? BIA->getArchName() :
C.getDefaultToolChain().getArchName()) << '"'
<< ", {" << PrintActions1(C, *BIA->begin(), Ids) << "}";
} else {
@@ -555,7 +567,7 @@ static unsigned PrintActions1(const Compilation &C,
unsigned Id = Ids.size();
Ids[A] = Id;
- llvm::errs() << Id << ": " << os.str() << ", "
+ llvm::errs() << Id << ": " << os.str() << ", "
<< types::getTypeName(A->getType()) << "\n";
return Id;
@@ -563,65 +575,66 @@ static unsigned PrintActions1(const Compilation &C,
void Driver::PrintActions(const Compilation &C) const {
std::map<Action*, unsigned> Ids;
- for (ActionList::const_iterator it = C.getActions().begin(),
+ 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,
+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::PrettyStackTraceString CrashInfo("Building universal build actions");
+ // Collect the list of architectures. Duplicates are allowed, but should only
+ // be handled once (in the order seen).
llvm::StringSet<> ArchNames;
llvm::SmallVector<const char *, 4> Archs;
- for (ArgList::const_iterator it = Args.begin(), ie = Args.end();
+ 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?
+ // Validate the option here; we don't save the type here because its
+ // particular spelling may participate in other driver choices.
+ llvm::Triple::ArchType Arch =
+ llvm::Triple::getArchTypeForDarwinArchName(A->getValue(Args));
+ if (Arch == llvm::Triple::UnknownArch) {
+ Diag(clang::diag::err_drv_invalid_arch_name)
+ << A->getAsString(Args);
+ continue;
+ }
A->claim();
- if (ArchNames.insert(Name))
- Archs.push_back(Name);
+ if (ArchNames.insert(A->getValue(Args)))
+ Archs.push_back(A->getValue(Args));
}
}
- // 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.
+ // 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.
+ // 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)
+ 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.
+ // 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
+ // 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()))
@@ -632,8 +645,8 @@ void Driver::BuildUniversalActions(const ArgList &Args,
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.
+ // 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
@@ -645,15 +658,14 @@ 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.
+ // 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();
+ for (ArgList::const_iterator it = Args.begin(), ie = Args.end();
it != ie; ++it) {
Arg *A = *it;
@@ -669,19 +681,18 @@ void Driver::BuildActions(const ArgList &Args, ActionList &Actions) const {
// 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.
+ // 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).
+ // 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.
+ // 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);
@@ -692,7 +703,7 @@ void Driver::BuildActions(const ArgList &Args, ActionList &Actions) const {
// -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))
@@ -706,28 +717,26 @@ void Driver::BuildActions(const ArgList &Args, ActionList &Actions) const {
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.
+ // 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.
+ // 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;
+ 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.
+ // 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;
@@ -740,9 +749,9 @@ void Driver::BuildActions(const ArgList &Args, ActionList &Actions) const {
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.
+ // 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;
@@ -751,24 +760,25 @@ void Driver::BuildActions(const ArgList &Args, ActionList &Actions) const {
(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.
+
+ // -{fsyntax-only,-analyze,emit-ast,S} only run up to the compiler.
} else if ((FinalPhaseArg = Args.getLastArg(options::OPT_fsyntax_only)) ||
(FinalPhaseArg = Args.getLastArg(options::OPT__analyze,
options::OPT__analyze_auto)) ||
+ (FinalPhaseArg = Args.getLastArg(options::OPT_emit_ast)) ||
(FinalPhaseArg = Args.getLastArg(options::OPT_S))) {
FinalPhase = phases::Compile;
// -c only runs up to the assembler.
} else if ((FinalPhaseArg = Args.getLastArg(options::OPT_c))) {
FinalPhase = phases::Assemble;
-
+
// Otherwise do everything.
} else
FinalPhase = phases::Link;
- // Reject -Z* at the top level, these options should never have been
- // exposed by gcc.
+ // 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);
@@ -781,19 +791,28 @@ void Driver::BuildActions(const ArgList &Args, ActionList &Actions) const {
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.
+ // 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();
+
+ // Special case '-E' warning on a previously preprocessed file to make
+ // more sense.
+ if (InitialPhase == phases::Compile && FinalPhase == phases::Preprocess &&
+ getPreprocessedType(InputType) == types::TY_INVALID)
+ Diag(clang::diag::warn_drv_preprocessed_input_file_unused)
+ << InputArg->getAsString(Args)
+ << FinalPhaseArg->getOption().getName();
+ else
+ 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) {
@@ -811,9 +830,9 @@ void Driver::BuildActions(const ArgList &Args, ActionList &Actions) const {
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.
+ // 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;
@@ -852,16 +871,18 @@ Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase,
return new PreprocessJobAction(Input, OutputTy);
}
case phases::Precompile:
- return new PrecompileJobAction(Input, types::TY_PCH);
+ 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_ast)) {
+ return new CompileJobAction(Input, types::TY_AST);
} else if (Args.hasArg(options::OPT_emit_llvm) ||
Args.hasArg(options::OPT_flto) ||
Args.hasArg(options::OPT_O4)) {
- types::ID Output =
+ types::ID Output =
Args.hasArg(options::OPT_S) ? types::TY_LLVMAsm : types::TY_LLVMBC;
return new CompileJobAction(Input, Output);
} else {
@@ -881,11 +902,10 @@ void Driver::BuildJobs(Compilation &C) const {
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.
+ // 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);
@@ -894,32 +914,31 @@ void Driver::BuildJobs(Compilation &C) const {
Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o);
- // It is an error to provide a -o option if we are making multiple
- // output files.
+ // 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(),
+ 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(),
+ 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.
+ // 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.
+ // 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)
@@ -929,41 +948,41 @@ void Driver::BuildJobs(Compilation &C) const {
}
InputInfo II;
- BuildJobsForAction(C, A, &C.getDefaultToolChain(),
+ BuildJobsForAction(C, A, &C.getDefaultToolChain(),
+ /*BoundArch*/0,
/*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() ||
+ // 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.
+ // 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.
+ // 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(),
+ 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;
@@ -975,7 +994,7 @@ void Driver::BuildJobs(Compilation &C) const {
continue;
}
- Diag(clang::diag::warn_drv_unused_argument)
+ Diag(clang::diag::warn_drv_unused_argument)
<< A->getAsString(C.getArgs());
}
}
@@ -984,21 +1003,21 @@ void Driver::BuildJobs(Compilation &C) const {
void Driver::BuildJobsForAction(Compilation &C,
const Action *A,
const ToolChain *TC,
+ const char *BoundArch,
bool CanAcceptPipe,
bool AtTopLevel,
const char *LinkingOutput,
InputInfo &Result) const {
- llvm::PrettyStackTraceString CrashInfo("Building compilation jobs for action");
+ llvm::PrettyStackTraceString CrashInfo("Building compilation jobs");
bool UsePipes = C.getArgs().hasArg(options::OPT_pipe);
- // FIXME: Pipes are forcibly disabled until we support executing
- // them.
+ // 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?
+ // 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)) {
@@ -1010,28 +1029,23 @@ void Driver::BuildJobsForAction(Compilation &C,
}
if (const BindArchAction *BAA = dyn_cast<BindArchAction>(A)) {
- const char *ArchName = BAA->getArchName();
+ const ToolChain *TC = &C.getDefaultToolChain();
+
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);
+ if (BAA->getArchName())
+ TC = Host->CreateToolChain(C.getArgs(), BAA->getArchName());
+
+ BuildJobsForAction(C, *BAA->begin(), TC, BAA->getArchName(),
+ 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).
+
+ // 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())) {
@@ -1050,18 +1064,16 @@ void Driver::BuildJobsForAction(Compilation &C,
for (ActionList::const_iterator it = Inputs->begin(), ie = Inputs->end();
it != ie; ++it) {
InputInfo II;
- BuildJobsForAction(C, *it, TC, TryToUsePipeInput,
- /*AtTopLevel*/false,
- LinkingOutput,
- II);
+ BuildJobsForAction(C, *it, TC, BoundArch, 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.
+ // 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) {
@@ -1082,8 +1094,8 @@ void Driver::BuildJobsForAction(Compilation &C,
// 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.
+ // 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) {
@@ -1091,8 +1103,8 @@ void Driver::BuildJobsForAction(Compilation &C,
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.
+ // 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;
@@ -1113,12 +1125,12 @@ void Driver::BuildJobsForAction(Compilation &C,
}
llvm::errs() << "], output: " << Result.getAsString() << "\n";
} else {
- T.ConstructJob(C, *JA, *Dest, Result, InputInfos,
- C.getArgsForToolChain(TC), LinkingOutput);
+ T.ConstructJob(C, *JA, *Dest, Result, InputInfos,
+ C.getArgsForToolChain(TC, BoundArch), LinkingOutput);
}
}
-const char *Driver::GetNamedOutputPath(Compilation &C,
+const char *Driver::GetNamedOutputPath(Compilation &C,
const JobAction &JA,
const char *BaseInput,
bool AtTopLevel) const {
@@ -1131,7 +1143,7 @@ const char *Driver::GetNamedOutputPath(Compilation &C,
// Output to a temporary file?
if (!AtTopLevel && !C.getArgs().hasArg(options::OPT_save_temps)) {
- std::string TmpName =
+ std::string TmpName =
GetTemporaryPath(types::getTypeTempSuffix(JA.getType()));
return C.addTempFile(C.getArgs().MakeArgString(TmpName.c_str()));
}
@@ -1156,8 +1168,7 @@ const char *Driver::GetNamedOutputPath(Compilation &C,
NamedOutput = C.getArgs().MakeArgString(Suffixed.c_str());
}
- // As an annoying special case, PCH generation doesn't strip the
- // pathname.
+ // As an annoying special case, PCH generation doesn't strip the pathname.
if (JA.getType() == types::TY_PCH) {
BasePath.eraseComponent();
if (BasePath.isEmpty())
@@ -1170,43 +1181,41 @@ const char *Driver::GetNamedOutputPath(Compilation &C,
}
}
-llvm::sys::Path Driver::GetFilePath(const char *Name,
- const ToolChain &TC) const {
+std::string Driver::GetFilePath(const char *Name, const ToolChain &TC) const {
const ToolChain::path_list &List = TC.getFilePaths();
- for (ToolChain::path_list::const_iterator
+ 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 P.str();
}
- return llvm::sys::Path(Name);
+ return Name;
}
-llvm::sys::Path Driver::GetProgramPath(const char *Name,
- const ToolChain &TC,
- bool WantFile) const {
+std::string Driver::GetProgramPath(const char *Name, const ToolChain &TC,
+ bool WantFile) const {
const ToolChain::path_list &List = TC.getProgramPaths();
- for (ToolChain::path_list::const_iterator
+ 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;
+ return P.str();
}
// If all else failed, search the path.
llvm::sys::Path P(llvm::sys::Program::FindProgramByName(Name));
if (!P.empty())
- return P;
+ return P.str();
- return llvm::sys::Path(Name);
+ return 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).
+ // 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)
@@ -1222,33 +1231,20 @@ std::string Driver::GetTemporaryPath(const char *Suffix) const {
return "";
}
- // FIXME: Grumble, makeUnique sometimes leaves the file around!?
- // PR3837.
+ // FIXME: Grumble, makeUnique sometimes leaves the file around!? PR3837.
P.eraseFromDisk(false, 0);
P.appendSuffix(Suffix);
- return P.toString();
+ return P.str();
}
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::AuroraUX:
+ return createAuroraUXHostInfo(*this, Triple);
case llvm::Triple::Darwin:
return createDarwinHostInfo(*this, Triple);
case llvm::Triple::DragonFly:
@@ -1265,17 +1261,10 @@ const HostInfo *Driver::GetHostInfo(const char *TripleStr) const {
}
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 ||
+ const llvm::Triple &Triple) const {
+ // Check if user requested no clang, or clang doesn't understand this type (we
+ // only handle single inputs for now).
+ if (!CCCUseClang || JA.size() != 1 ||
!types::isAcceptedByClang((*JA.begin())->getType()))
return false;
@@ -1294,35 +1283,32 @@ bool Driver::ShouldUseClangCompiler(const Compilation &C, const JobAction &JA,
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))
+ // Always use clang for precompiling and AST generation, regardless of archs.
+ if (isa<PrecompileJobAction>(JA) || JA.getType() == types::TY_AST)
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;
+ // Finally, don't use clang if this isn't one of the user specified archs to
+ // build.
+ if (!CCCClangArchs.empty() && !CCCClangArchs.count(Triple.getArch())) {
+ Diag(clang::diag::warn_drv_not_using_clang_arch) << Triple.getArchName();
return false;
}
return true;
}
-/// GetReleaseVersion - Parse (([0-9]+)(.([0-9]+)(.([0-9]+)?))?)? and
-/// return the grouped values as integers. Numbers which are not
-/// provided are set to 0.
+/// 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,
+/// \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')
+ if (*Str == '\0')
return true;
char *End;
@@ -1331,7 +1317,7 @@ bool Driver::GetReleaseVersion(const char *Str, unsigned &Major,
return true;
if (*End != '.')
return false;
-
+
Str = End+1;
Minor = (unsigned) strtol(Str, &End, 10);
if (*Str != '\0' && *End == '\0')
diff --git a/lib/Driver/HostInfo.cpp b/lib/Driver/HostInfo.cpp
index 602a977..08c4ef4 100644
--- a/lib/Driver/HostInfo.cpp
+++ b/lib/Driver/HostInfo.cpp
@@ -22,13 +22,11 @@
#include "ToolChains.h"
#include <cassert>
-
+
using namespace clang::driver;
HostInfo::HostInfo(const Driver &D, const llvm::Triple &_Triple)
- : TheDriver(D), Triple(_Triple)
-{
-
+ : TheDriver(D), Triple(_Triple) {
}
HostInfo::~HostInfo() {
@@ -47,7 +45,7 @@ class DarwinHostInfo : public HostInfo {
unsigned GCCVersion[3];
/// Cache of tool chains we have created.
- mutable llvm::StringMap<ToolChain *> ToolChains;
+ mutable llvm::DenseMap<unsigned, ToolChain*> ToolChains;
public:
DarwinHostInfo(const Driver &D, const llvm::Triple &Triple);
@@ -66,28 +64,22 @@ public:
return Ty;
}
- virtual ToolChain *getToolChain(const ArgList &Args,
- const char *ArchName) const;
+ virtual ToolChain *CreateToolChain(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(Triple.getArch() != llvm::Triple::UnknownArch && "Invalid 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();
- }
-
+ 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;
@@ -95,73 +87,71 @@ DarwinHostInfo::DarwinHostInfo(const Driver &D, const llvm::Triple& Triple)
}
DarwinHostInfo::~DarwinHostInfo() {
- for (llvm::StringMap<ToolChain*>::iterator
+ for (llvm::DenseMap<unsigned, ToolChain*>::iterator
it = ToolChains.begin(), ie = ToolChains.end(); it != ie; ++it)
delete it->second;
}
-bool DarwinHostInfo::useDriverDriver() const {
+bool DarwinHostInfo::useDriverDriver() const {
return true;
}
-ToolChain *DarwinHostInfo::getToolChain(const ArgList &Args,
- const char *ArchName) const {
- std::string Arch;
+ToolChain *DarwinHostInfo::CreateToolChain(const ArgList &Args,
+ const char *ArchName) const {
+ llvm::Triple::ArchType Arch;
+
if (!ArchName) {
// If we aren't looking for a specific arch, infer the default architecture
// based on -arch and -m32/-m64 command line options.
if (Arg *A = Args.getLastArg(options::OPT_arch)) {
// The gcc driver behavior with multiple -arch flags wasn't consistent for
// things which rely on a default architecture. We just use the last -arch
- // to find the default tool chain.
- Arch = A->getValue(Args);
-
- // 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 (Arch == "ppc")
- Arch = "powerpc";
- else if (Arch == "ppc64")
- Arch = "powerpc64";
+ // to find the default tool chain (assuming it is valid..
+ Arch = llvm::Triple::getArchTypeForDarwinArchName(A->getValue(Args));
+
+ // If it was invalid just use the host, we will reject this command line
+ // later.
+ if (Arch == llvm::Triple::UnknownArch)
+ Arch = getTriple().getArch();
} else {
// Otherwise default to the arch of the host.
- Arch = getArchName();
+ Arch = getTriple().getArch();
}
- ArchName = Arch.c_str();
-
+
// Honor -m32 and -m64 when finding the default tool chain.
+ //
+ // FIXME: Should this information be in llvm::Triple?
if (Arg *A = Args.getLastArg(options::OPT_m32, options::OPT_m64)) {
- if (Arch == "i386" || Arch == "x86_64") {
- ArchName = (A->getOption().getId() == options::OPT_m32) ? "i386" :
- "x86_64";
- } else if (Arch == "powerpc" || Arch == "powerpc64") {
- ArchName = (A->getOption().getId() == options::OPT_m32) ? "powerpc" :
- "powerpc64";
+ if (A->getOption().getId() == options::OPT_m32) {
+ if (Arch == llvm::Triple::x86_64)
+ Arch = llvm::Triple::x86;
+ if (Arch == llvm::Triple::ppc64)
+ Arch = llvm::Triple::ppc;
+ } else {
+ if (Arch == llvm::Triple::x86)
+ Arch = llvm::Triple::x86_64;
+ if (Arch == llvm::Triple::ppc)
+ Arch = llvm::Triple::ppc64;
}
- }
- } 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";
- }
+ }
+ } else
+ Arch = llvm::Triple::getArchTypeForDarwinArchName(ArchName);
- ToolChain *&TC = ToolChains[ArchName];
+ assert(Arch != llvm::Triple::UnknownArch && "Unexpected arch!");
+ ToolChain *&TC = ToolChains[Arch];
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);
+ TCTriple.setArch(Arch);
+
+ // If we recognized the arch, match it to the toolchains we support.
+ if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64) {
+ // We still use the legacy DarwinGCC toolchain on X86.
+ TC = new toolchains::DarwinGCC(*this, TCTriple, DarwinVersion, GCCVersion,
+ false);
+ } else if (Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb)
+ TC = new toolchains::DarwinClang(*this, TCTriple, DarwinVersion, true);
else
- TC = new toolchains::Darwin_GCC(*this, TCTriple);
+ TC = new toolchains::Darwin_Generic_GCC(*this, TCTriple);
}
return TC;
@@ -185,11 +175,11 @@ public:
return types::lookupTypeForExtension(Ext);
}
- virtual ToolChain *getToolChain(const ArgList &Args,
- const char *ArchName) const;
+ virtual ToolChain *CreateToolChain(const ArgList &Args,
+ const char *ArchName) const;
};
-UnknownHostInfo::UnknownHostInfo(const Driver &D, const llvm::Triple& Triple)
+UnknownHostInfo::UnknownHostInfo(const Driver &D, const llvm::Triple& Triple)
: HostInfo(D, Triple) {
}
@@ -199,15 +189,15 @@ UnknownHostInfo::~UnknownHostInfo() {
delete it->second;
}
-bool UnknownHostInfo::useDriverDriver() const {
+bool UnknownHostInfo::useDriverDriver() const {
return false;
}
-ToolChain *UnknownHostInfo::getToolChain(const ArgList &Args,
- const char *ArchName) const {
- assert(!ArchName &&
+ToolChain *UnknownHostInfo::CreateToolChain(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();
@@ -221,8 +211,8 @@ ToolChain *UnknownHostInfo::getToolChain(const ArgList &Args,
ArchName =
(A->getOption().getId() == options::OPT_m32) ? "powerpc" : "powerpc64";
}
- }
-
+ }
+
ToolChain *&TC = ToolChains[ArchName];
if (!TC) {
llvm::Triple TCTriple(getTriple());
@@ -242,7 +232,7 @@ class OpenBSDHostInfo : public HostInfo {
mutable llvm::StringMap<ToolChain*> ToolChains;
public:
- OpenBSDHostInfo(const Driver &D, const llvm::Triple& Triple)
+ OpenBSDHostInfo(const Driver &D, const llvm::Triple& Triple)
: HostInfo(D, Triple) {}
~OpenBSDHostInfo();
@@ -252,8 +242,8 @@ public:
return types::lookupTypeForExtension(Ext);
}
- virtual ToolChain *getToolChain(const ArgList &Args,
- const char *ArchName) const;
+ virtual ToolChain *CreateToolChain(const ArgList &Args,
+ const char *ArchName) const;
};
OpenBSDHostInfo::~OpenBSDHostInfo() {
@@ -262,18 +252,18 @@ OpenBSDHostInfo::~OpenBSDHostInfo() {
delete it->second;
}
-bool OpenBSDHostInfo::useDriverDriver() const {
+bool OpenBSDHostInfo::useDriverDriver() const {
return false;
}
-ToolChain *OpenBSDHostInfo::getToolChain(const ArgList &Args,
- const char *ArchName) const {
- assert(!ArchName &&
+ToolChain *OpenBSDHostInfo::CreateToolChain(const ArgList &Args,
+ const char *ArchName) const {
+ assert(!ArchName &&
"Unexpected arch name on platform without driver driver support.");
-
+
std::string Arch = getArchName();
ArchName = Arch.c_str();
-
+
ToolChain *&TC = ToolChains[ArchName];
if (!TC) {
llvm::Triple TCTriple(getTriple());
@@ -285,6 +275,55 @@ ToolChain *OpenBSDHostInfo::getToolChain(const ArgList &Args,
return TC;
}
+// AuroraUX Host Info
+
+/// AuroraUXHostInfo - AuroraUX host information implementation.
+class AuroraUXHostInfo : public HostInfo {
+ /// Cache of tool chains we have created.
+ mutable llvm::StringMap<ToolChain*> ToolChains;
+
+public:
+ AuroraUXHostInfo(const Driver &D, const llvm::Triple& Triple)
+ : HostInfo(D, Triple) {}
+ ~AuroraUXHostInfo();
+
+ virtual bool useDriverDriver() const;
+
+ virtual types::ID lookupTypeForExtension(const char *Ext) const {
+ return types::lookupTypeForExtension(Ext);
+ }
+
+ virtual ToolChain *CreateToolChain(const ArgList &Args,
+ const char *ArchName) const;
+};
+
+AuroraUXHostInfo::~AuroraUXHostInfo() {
+ for (llvm::StringMap<ToolChain*>::iterator
+ it = ToolChains.begin(), ie = ToolChains.end(); it != ie; ++it)
+ delete it->second;
+}
+
+bool AuroraUXHostInfo::useDriverDriver() const {
+ return false;
+}
+
+ToolChain *AuroraUXHostInfo::CreateToolChain(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::AuroraUX(*this, TCTriple);
+ }
+
+ return TC;
+}
+
// FreeBSD Host Info
/// FreeBSDHostInfo - FreeBSD host information implementation.
@@ -293,7 +332,7 @@ class FreeBSDHostInfo : public HostInfo {
mutable llvm::StringMap<ToolChain*> ToolChains;
public:
- FreeBSDHostInfo(const Driver &D, const llvm::Triple& Triple)
+ FreeBSDHostInfo(const Driver &D, const llvm::Triple& Triple)
: HostInfo(D, Triple) {}
~FreeBSDHostInfo();
@@ -303,8 +342,8 @@ public:
return types::lookupTypeForExtension(Ext);
}
- virtual ToolChain *getToolChain(const ArgList &Args,
- const char *ArchName) const;
+ virtual ToolChain *CreateToolChain(const ArgList &Args,
+ const char *ArchName) const;
};
FreeBSDHostInfo::~FreeBSDHostInfo() {
@@ -313,17 +352,17 @@ FreeBSDHostInfo::~FreeBSDHostInfo() {
delete it->second;
}
-bool FreeBSDHostInfo::useDriverDriver() const {
+bool FreeBSDHostInfo::useDriverDriver() const {
return false;
}
-ToolChain *FreeBSDHostInfo::getToolChain(const ArgList &Args,
- const char *ArchName) const {
+ToolChain *FreeBSDHostInfo::CreateToolChain(const ArgList &Args,
+ const char *ArchName) const {
bool Lib32 = false;
- assert(!ArchName &&
+ 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.
@@ -332,8 +371,8 @@ ToolChain *FreeBSDHostInfo::getToolChain(const ArgList &Args,
if (Args.hasArg(options::OPT_m32) && getArchName() == "x86_64") {
ArchName = "i386";
Lib32 = true;
- }
-
+ }
+
ToolChain *&TC = ToolChains[ArchName];
if (!TC) {
llvm::Triple TCTriple(getTriple());
@@ -363,8 +402,8 @@ public:
return types::lookupTypeForExtension(Ext);
}
- virtual ToolChain *getToolChain(const ArgList &Args,
- const char *ArchName) const;
+ virtual ToolChain *CreateToolChain(const ArgList &Args,
+ const char *ArchName) const;
};
DragonFlyHostInfo::~DragonFlyHostInfo() {
@@ -373,13 +412,13 @@ DragonFlyHostInfo::~DragonFlyHostInfo() {
delete it->second;
}
-bool DragonFlyHostInfo::useDriverDriver() const {
+bool DragonFlyHostInfo::useDriverDriver() const {
return false;
}
-ToolChain *DragonFlyHostInfo::getToolChain(const ArgList &Args,
- const char *ArchName) const {
- assert(!ArchName &&
+ToolChain *DragonFlyHostInfo::CreateToolChain(const ArgList &Args,
+ const char *ArchName) const {
+ assert(!ArchName &&
"Unexpected arch name on platform without driver driver support.");
ToolChain *&TC = ToolChains[getArchName()];
@@ -412,8 +451,8 @@ public:
return types::lookupTypeForExtension(Ext);
}
- virtual ToolChain *getToolChain(const ArgList &Args,
- const char *ArchName) const;
+ virtual ToolChain *CreateToolChain(const ArgList &Args,
+ const char *ArchName) const;
};
LinuxHostInfo::~LinuxHostInfo() {
@@ -422,14 +461,14 @@ LinuxHostInfo::~LinuxHostInfo() {
delete it->second;
}
-bool LinuxHostInfo::useDriverDriver() const {
+bool LinuxHostInfo::useDriverDriver() const {
return false;
}
-ToolChain *LinuxHostInfo::getToolChain(const ArgList &Args,
- const char *ArchName) const {
+ToolChain *LinuxHostInfo::CreateToolChain(const ArgList &Args,
+ const char *ArchName) const {
- assert(!ArchName &&
+ assert(!ArchName &&
"Unexpected arch name on platform without driver driver support.");
// Automatically handle some instances of -m32/-m64 we know about.
@@ -462,19 +501,25 @@ ToolChain *LinuxHostInfo::getToolChain(const ArgList &Args,
}
const HostInfo *
+clang::driver::createAuroraUXHostInfo(const Driver &D,
+ const llvm::Triple& Triple){
+ return new AuroraUXHostInfo(D, Triple);
+}
+
+const HostInfo *
clang::driver::createDarwinHostInfo(const Driver &D,
const llvm::Triple& Triple){
return new DarwinHostInfo(D, Triple);
}
const HostInfo *
-clang::driver::createOpenBSDHostInfo(const Driver &D,
+clang::driver::createOpenBSDHostInfo(const Driver &D,
const llvm::Triple& Triple) {
return new OpenBSDHostInfo(D, Triple);
}
const HostInfo *
-clang::driver::createFreeBSDHostInfo(const Driver &D,
+clang::driver::createFreeBSDHostInfo(const Driver &D,
const llvm::Triple& Triple) {
return new FreeBSDHostInfo(D, Triple);
}
diff --git a/lib/Driver/Job.cpp b/lib/Driver/Job.cpp
index 1b0ea18..280e7c4 100644
--- a/lib/Driver/Job.cpp
+++ b/lib/Driver/Job.cpp
@@ -14,9 +14,9 @@ using namespace clang::driver;
Job::~Job() {}
-Command::Command(const Action &_Source, const char *_Executable,
+Command::Command(const Action &_Source, const char *_Executable,
const ArgStringList &_Arguments)
- : Job(CommandClass), Source(_Source), Executable(_Executable),
+ : Job(CommandClass), Source(_Source), Executable(_Executable),
Arguments(_Arguments) {
}
@@ -30,4 +30,4 @@ void Job::addCommand(Command *C) {
else
cast<JobList>(this)->addJob(C);
}
-
+
diff --git a/lib/Driver/Makefile b/lib/Driver/Makefile
index d163f0f..4c3ca5c 100644
--- a/lib/Driver/Makefile
+++ b/lib/Driver/Makefile
@@ -12,17 +12,9 @@ LIBRARYNAME := clangDriver
BUILD_ARCHIVE = 1
CXXFLAGS = -fno-rtti
+CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
+ifdef CLANG_VENDOR
+CPPFLAGS += -DCLANG_VENDOR='"$(CLANG_VENDOR) "'
+endif
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
index 7ea6a8b..affd1c5 100644
--- a/lib/Driver/OptTable.cpp
+++ b/lib/Driver/OptTable.cpp
@@ -77,7 +77,7 @@ static Info OptionInfos[] = {
{ "<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, \
@@ -91,7 +91,11 @@ static Info &getInfo(unsigned id) {
return OptionInfos[id - 1];
}
-OptTable::OptTable() : Options(new Option*[numOptions]()) {
+OptTable::OptTable() : Options(new Option*[numOptions]) {
+ // Explicitly zero initialize the error to work around a bug in array
+ // value-initialization on MinGW with gcc 4.3.5.
+ memset(Options, 0, sizeof(*Options) * numOptions);
+
// Find start of normal options.
FirstSearchableOption = 0;
for (unsigned i = OPT_UNKNOWN + 1; i < LastOption; ++i) {
@@ -120,10 +124,10 @@ OptTable::OptTable() : Options(new Option*[numOptions]()) {
assert(0 && "Options are not in order!");
}
}
-#endif
+#endif
}
-OptTable::~OptTable() {
+OptTable::~OptTable() {
for (unsigned i = 0; i < numOptions; ++i)
delete Options[i];
delete[] Options;
@@ -164,7 +168,7 @@ const Option *OptTable::getOption(options::ID id) const {
Option *OptTable::constructOption(options::ID id) const {
Info &info = getInfo(id);
- const OptionGroup *Group =
+ const OptionGroup *Group =
cast_or_null<OptionGroup>(getOption((options::ID) info.GroupID));
const Option *Alias = getOption((options::ID) info.AliasID);
@@ -195,10 +199,10 @@ Option *OptTable::constructOption(options::ID id) const {
for (const char *s = info.Flags; *s; ++s) {
switch (*s) {
default: assert(0 && "Invalid option flag.");
- case 'J':
+ case 'J':
assert(info.Kind == Option::SeparateClass && "Invalid option.");
Opt->setForceJoinedRender(true); break;
- case 'S':
+ case 'S':
assert(info.Kind == Option::JoinedClass && "Invalid option.");
Opt->setForceSeparateRender(true); break;
case 'd': Opt->setDriverOption(true); break;
diff --git a/lib/Driver/Option.cpp b/lib/Driver/Option.cpp
index cad2bbf..c2ace05 100644
--- a/lib/Driver/Option.cpp
+++ b/lib/Driver/Option.cpp
@@ -17,18 +17,17 @@
using namespace clang::driver;
Option::Option(OptionClass _Kind, options::ID _ID, const char *_Name,
- const OptionGroup *_Group, const Option *_Alias)
+ 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)
-{
+ 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.");
+ "Multi-level aliases and aliases with groups are unsupported.");
}
Option::~Option() {
@@ -59,12 +58,12 @@ void Option::dump() const {
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();
@@ -77,10 +76,10 @@ bool Option::matches(const Option *Opt) const {
return matches(Opt->getAlias());
if (Alias)
return Alias->matches(Opt);
-
+
if (this == Opt)
return true;
-
+
if (Group)
return Group->matches(Opt);
return false;
@@ -93,16 +92,16 @@ bool Option::matches(options::ID Id) const {
// 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,
+OptionGroup::OptionGroup(options::ID ID, const char *Name,
const OptionGroup *Group)
: Option(Option::GroupClass, ID, Name, Group, 0) {
}
@@ -130,13 +129,13 @@ Arg *UnknownOption::accept(const InputArgList &Args, unsigned &Index) const {
return 0;
}
-FlagOption::FlagOption(options::ID ID, const char *Name,
+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.
+ // Matches iff this is an exact match.
// FIXME: Avoid strlen.
if (strlen(getName()) != strlen(Args.getArgString(Index)))
return 0;
@@ -144,7 +143,7 @@ Arg *FlagOption::accept(const InputArgList &Args, unsigned &Index) const {
return new FlagArg(this, Index++);
}
-JoinedOption::JoinedOption(options::ID ID, const char *Name,
+JoinedOption::JoinedOption(options::ID ID, const char *Name,
const OptionGroup *Group, const Option *Alias)
: Option(Option::JoinedClass, ID, Name, Group, Alias) {
}
@@ -154,30 +153,30 @@ Arg *JoinedOption::accept(const InputArgList &Args, unsigned &Index) const {
return new JoinedArg(this, Index++);
}
-CommaJoinedOption::CommaJoinedOption(options::ID ID, const char *Name,
- const OptionGroup *Group,
+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,
+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,
+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.
+ // Matches iff this is an exact match.
// FIXME: Avoid strlen.
if (strlen(getName()) != strlen(Args.getArgString(Index)))
return 0;
@@ -189,15 +188,15 @@ Arg *SeparateOption::accept(const InputArgList &Args, unsigned &Index) const {
return new SeparateArg(this, Index - 2, 1);
}
-MultiArgOption::MultiArgOption(options::ID ID, const char *Name,
- const OptionGroup *Group, const Option *Alias,
+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.
+ // Matches iff this is an exact match.
// FIXME: Avoid strlen.
if (strlen(getName()) != strlen(Args.getArgString(Index)))
return 0;
@@ -210,12 +209,12 @@ Arg *MultiArgOption::accept(const InputArgList &Args, unsigned &Index) const {
}
JoinedOrSeparateOption::JoinedOrSeparateOption(options::ID ID, const char *Name,
- const OptionGroup *Group,
+ const OptionGroup *Group,
const Option *Alias)
: Option(Option::JoinedOrSeparateClass, ID, Name, Group, Alias) {
}
-Arg *JoinedOrSeparateOption::accept(const InputArgList &Args,
+Arg *JoinedOrSeparateOption::accept(const InputArgList &Args,
unsigned &Index) const {
// If this is not an exact match, it is a joined arg.
// FIXME: Avoid strlen.
@@ -227,17 +226,17 @@ Arg *JoinedOrSeparateOption::accept(const InputArgList &Args,
if (Index > Args.getNumInputArgStrings())
return 0;
- return new SeparateArg(this, Index - 2, 1);
+ return new SeparateArg(this, Index - 2, 1);
}
JoinedAndSeparateOption::JoinedAndSeparateOption(options::ID ID,
- const char *Name,
- const OptionGroup *Group,
+ const char *Name,
+ const OptionGroup *Group,
const Option *Alias)
: Option(Option::JoinedAndSeparateClass, ID, Name, Group, Alias) {
}
-Arg *JoinedAndSeparateOption::accept(const InputArgList &Args,
+Arg *JoinedAndSeparateOption::accept(const InputArgList &Args,
unsigned &Index) const {
// Always matches.
diff --git a/lib/Driver/Tool.cpp b/lib/Driver/Tool.cpp
index 6f6589a..781e0a7 100644
--- a/lib/Driver/Tool.cpp
+++ b/lib/Driver/Tool.cpp
@@ -11,7 +11,7 @@
using namespace clang::driver;
-Tool::Tool(const char *_Name, const ToolChain &TC) : Name(_Name),
+Tool::Tool(const char *_Name, const ToolChain &TC) : Name(_Name),
TheToolChain(TC) {
}
diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp
index 20ed31b..abe9c81 100644
--- a/lib/Driver/ToolChain.cpp
+++ b/lib/Driver/ToolChain.cpp
@@ -22,14 +22,14 @@ ToolChain::ToolChain(const HostInfo &_Host, const llvm::Triple &_Triple)
ToolChain::~ToolChain() {
}
-llvm::sys::Path ToolChain::GetFilePath(const Compilation &C,
- const char *Name) const {
+std::string 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 {
+std::string 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
index f663ed4..a5a48ad 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -17,6 +17,7 @@
#include "clang/Driver/Option.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/System/Path.h"
@@ -25,21 +26,34 @@
using namespace clang::driver;
using namespace clang::driver::toolchains;
-/// Darwin_X86 - Darwin tool chain for i386 and x86_64.
+/// Darwin - 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) {
+Darwin::Darwin(const HostInfo &Host, const llvm::Triple& Triple,
+ const unsigned (&_DarwinVersion)[3], bool _IsIPhoneOS)
+ : ToolChain(Host, Triple),
+ IsIPhoneOS(_IsIPhoneOS)
+{
DarwinVersion[0] = _DarwinVersion[0];
DarwinVersion[1] = _DarwinVersion[1];
DarwinVersion[2] = _DarwinVersion[2];
+
+ llvm::raw_string_ostream(MacosxVersionMin)
+ << "10." << DarwinVersion[0] - 4 << '.' << DarwinVersion[1];
+
+ // FIXME: Lift default up.
+ IPhoneOSVersionMin = "3.0";
+}
+
+DarwinGCC::DarwinGCC(const HostInfo &Host, const llvm::Triple& Triple,
+ const unsigned (&DarwinVersion)[3],
+ const unsigned (&_GCCVersion)[3], bool IsIPhoneOS)
+ : Darwin(Host, Triple, DarwinVersion, IsIPhoneOS)
+{
GCCVersion[0] = _GCCVersion[0];
GCCVersion[1] = _GCCVersion[1];
GCCVersion[2] = _GCCVersion[2];
- llvm::raw_string_ostream(MacosxVersionMin)
- << "10." << DarwinVersion[0] - 4 << '.' << DarwinVersion[1];
+ // Set up the tool chain paths to match gcc.
ToolChainDir = "i686-apple-darwin";
ToolChainDir += llvm::utostr(DarwinVersion[0]);
@@ -54,32 +68,32 @@ Darwin_X86::Darwin_X86(const HostInfo &Host, const llvm::Triple& Triple,
if (getArchName() == "x86_64") {
Path = getHost().getDriver().Dir;
Path += "/../lib/gcc/";
- Path += getToolChainDir();
+ Path += ToolChainDir;
Path += "/x86_64";
getFilePaths().push_back(Path);
Path = "/usr/lib/gcc/";
- Path += getToolChainDir();
+ Path += ToolChainDir;
Path += "/x86_64";
getFilePaths().push_back(Path);
}
-
+
Path = getHost().getDriver().Dir;
Path += "/../lib/gcc/";
- Path += getToolChainDir();
+ Path += ToolChainDir;
getFilePaths().push_back(Path);
Path = "/usr/lib/gcc/";
- Path += getToolChainDir();
+ Path += ToolChainDir;
getFilePaths().push_back(Path);
Path = getHost().getDriver().Dir;
Path += "/../libexec/gcc/";
- Path += getToolChainDir();
+ Path += ToolChainDir;
getProgramPaths().push_back(Path);
Path = "/usr/libexec/gcc/";
- Path += getToolChainDir();
+ Path += ToolChainDir;
getProgramPaths().push_back(Path);
Path = getHost().getDriver().Dir;
@@ -89,17 +103,16 @@ Darwin_X86::Darwin_X86(const HostInfo &Host, const llvm::Triple& Triple,
getProgramPaths().push_back(getHost().getDriver().Dir);
}
-Darwin_X86::~Darwin_X86() {
+Darwin::~Darwin() {
// 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 {
+Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA) const {
Action::ActionClass Key;
- if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getArchName()))
+ if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
Key = Action::AnalyzeJobClass;
else
Key = JA.getKind();
@@ -120,7 +133,7 @@ Tool &Darwin_X86::SelectTool(const Compilation &C,
case Action::AssembleJobClass:
T = new tools::darwin::Assemble(*this); break;
case Action::LinkJobClass:
- T = new tools::darwin::Link(*this, MacosxVersionMin.c_str()); break;
+ T = new tools::darwin::Link(*this); break;
case Action::LipoJobClass:
T = new tools::darwin::Lipo(*this); break;
}
@@ -129,7 +142,136 @@ Tool &Darwin_X86::SelectTool(const Compilation &C,
return *T;
}
-DerivedArgList *Darwin_X86::TranslateArgs(InputArgList &Args) const {
+void DarwinGCC::AddLinkSearchPathArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ // FIXME: Derive these correctly.
+ if (getArchName() == "x86_64") {
+ CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir +
+ "/x86_64"));
+ // Intentionally duplicated for (temporary) gcc bug compatibility.
+ CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir +
+ "/x86_64"));
+ }
+ CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/" + ToolChainDir));
+ CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir));
+ // Intentionally duplicated for (temporary) gcc bug compatibility.
+ CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir));
+ CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir +
+ "/../../../" + ToolChainDir));
+ CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir +
+ "/../../.."));
+}
+
+void DarwinGCC::AddLinkRuntimeLibArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ unsigned MacosxVersionMin[3];
+ getMacosxVersionMin(Args, MacosxVersionMin);
+
+ // 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.
+ if (isIPhoneOS()) {
+ CmdArgs.push_back("-lgcc_s.1");
+ } else {
+ CmdArgs.push_back("-lgcc_s.10.5");
+ }
+ } else if (Args.hasArg(options::OPT_shared_libgcc) ||
+ // FIXME: -fexceptions -fno-exceptions means no exceptions
+ Args.hasArg(options::OPT_fexceptions) ||
+ Args.hasArg(options::OPT_fgnu_runtime)) {
+ // FIXME: This is probably broken on 10.3?
+ if (isMacosxVersionLT(MacosxVersionMin, 10, 5))
+ CmdArgs.push_back("-lgcc_s.10.4");
+ else if (isMacosxVersionLT(MacosxVersionMin, 10, 6))
+ CmdArgs.push_back("-lgcc_s.10.5");
+ } else {
+ if (isMacosxVersionLT(MacosxVersionMin, 10, 3, 9))
+ ; // Do nothing.
+ else if (isMacosxVersionLT(MacosxVersionMin, 10, 5))
+ CmdArgs.push_back("-lgcc_s.10.4");
+ else if (isMacosxVersionLT(MacosxVersionMin, 10, 6))
+ CmdArgs.push_back("-lgcc_s.10.5");
+ }
+
+ if (isIPhoneOS() || isMacosxVersionLT(MacosxVersionMin, 10, 6)) {
+ CmdArgs.push_back("-lgcc");
+ CmdArgs.push_back("-lSystem");
+ } else {
+ CmdArgs.push_back("-lSystem");
+ CmdArgs.push_back("-lgcc");
+ }
+ }
+}
+
+DarwinClang::DarwinClang(const HostInfo &Host, const llvm::Triple& Triple,
+ const unsigned (&DarwinVersion)[3],
+ bool IsIPhoneOS)
+ : Darwin(Host, Triple, DarwinVersion, IsIPhoneOS)
+{
+ // Add the relative libexec dir (for clang-cc).
+ //
+ // FIXME: We should sink clang-cc into libexec/clang/<version>/.
+ std::string Path = getHost().getDriver().Dir;
+ Path += "/../libexec";
+ getProgramPaths().push_back(Path);
+
+ // We expect 'as', 'ld', etc. to be adjacent to our install dir.
+ getProgramPaths().push_back(getHost().getDriver().Dir);
+}
+
+void DarwinClang::AddLinkSearchPathArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ // The Clang toolchain uses explicit paths for internal libraries.
+}
+
+void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ // Check for static linking.
+ if (Args.hasArg(options::OPT_static)) {
+ // FIXME: We need to have compiler-rt available (perhaps as
+ // libclang_static.a) to link against.
+ return;
+ }
+
+ // Reject -static-libgcc for now, we can deal with this when and if someone
+ // cares. This is useful in situations where someone wants to statically link
+ // something like libstdc++, and needs its runtime support routines.
+ if (const Arg *A = Args.getLastArg(options::OPT_static_libgcc)) {
+ getHost().getDriver().Diag(clang::diag::err_drv_unsupported_opt)
+ << A->getAsString(Args);
+ return;
+ }
+
+ // Otherwise link libSystem, which should have the support routines.
+ //
+ // FIXME: This is only true for 10.6 and beyond. Legacy support isn't
+ // critical, but it should work... we should just link in the static
+ // compiler-rt library.
+ CmdArgs.push_back("-lSystem");
+}
+
+void Darwin::getMacosxVersionMin(const ArgList &Args,
+ unsigned (&Res)[3]) const {
+ if (Arg *A = Args.getLastArg(options::OPT_mmacosx_version_min_EQ)) {
+ bool HadExtra;
+ if (!Driver::GetReleaseVersion(A->getValue(Args), Res[0], Res[1], Res[2],
+ HadExtra) ||
+ HadExtra) {
+ const Driver &D = getHost().getDriver();
+ D.Diag(clang::diag::err_drv_invalid_version_number)
+ << A->getAsString(Args);
+ }
+ } else
+ return getMacosxVersion(Res);
+}
+
+DerivedArgList *Darwin::TranslateArgs(InputArgList &Args,
+ const char *BoundArch) const {
DerivedArgList *DAL = new DerivedArgList(Args, false);
const OptTable &Opts = getHost().getDriver().getOpts();
@@ -138,30 +280,36 @@ DerivedArgList *Darwin_X86::TranslateArgs(InputArgList &Args) const {
// 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.
+ // and try to push it down into tool specific logic.
- Arg *OSXVersion =
+ Arg *OSXVersion =
Args.getLastArg(options::OPT_mmacosx_version_min_EQ, false);
Arg *iPhoneVersion =
- Args.getLastArg(options::OPT_miphoneos_version_min_EQ, false);
+ 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);
+ << 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));
+ // FIXME: Are there iPhone overrides for this?
+
+ if (!isIPhoneOS()) {
+ // 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));
+ } else {
+ const char *Version = IPhoneOSVersionMin.c_str();
+ const Option *O = Opts.getOption(options::OPT_miphoneos_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;
@@ -174,7 +322,7 @@ DerivedArgList *Darwin_X86::TranslateArgs(InputArgList &Args) const {
// 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.
@@ -183,7 +331,7 @@ DerivedArgList *Darwin_X86::TranslateArgs(InputArgList &Args) const {
// 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 ||
+ if (!XarchArg || Index > Prev + 1 ||
XarchArg->getOption().isDriverOption()) {
getHost().getDriver().Diag(clang::diag::err_drv_invalid_Xarch_argument)
<< A->getAsString(Args);
@@ -192,7 +340,7 @@ DerivedArgList *Darwin_X86::TranslateArgs(InputArgList &Args) const {
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
@@ -209,7 +357,7 @@ DerivedArgList *Darwin_X86::TranslateArgs(InputArgList &Args) const {
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)));
@@ -270,35 +418,98 @@ DerivedArgList *Darwin_X86::TranslateArgs(InputArgList &Args) const {
}
}
- // 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))
+ if (getTriple().getArch() == llvm::Triple::x86 ||
+ getTriple().getArch() == llvm::Triple::x86_64)
+ if (!Args.hasArg(options::OPT_mtune_EQ, false))
+ DAL->append(DAL->MakeJoinedArg(0, Opts.getOption(options::OPT_mtune_EQ),
+ "core2"));
+
+ // Add the arch options based on the particular spelling of -arch, to match
+ // how the driver driver works.
+ if (BoundArch) {
+ llvm::StringRef Name = BoundArch;
+ const Option *MCpu = Opts.getOption(options::OPT_mcpu_EQ);
+ const Option *MArch = Opts.getOption(options::OPT_march_EQ);
+
+ // This code must be kept in sync with LLVM's getArchTypeForDarwinArch,
+ // which defines the list of which architectures we accept.
+ if (Name == "ppc")
+ ;
+ else if (Name == "ppc601")
+ DAL->append(DAL->MakeJoinedArg(0, MCpu, "601"));
+ else if (Name == "ppc603")
+ DAL->append(DAL->MakeJoinedArg(0, MCpu, "603"));
+ else if (Name == "ppc604")
+ DAL->append(DAL->MakeJoinedArg(0, MCpu, "604"));
+ else if (Name == "ppc604e")
+ DAL->append(DAL->MakeJoinedArg(0, MCpu, "604e"));
+ else if (Name == "ppc750")
+ DAL->append(DAL->MakeJoinedArg(0, MCpu, "750"));
+ else if (Name == "ppc7400")
+ DAL->append(DAL->MakeJoinedArg(0, MCpu, "7400"));
+ else if (Name == "ppc7450")
+ DAL->append(DAL->MakeJoinedArg(0, MCpu, "7450"));
+ else if (Name == "ppc970")
+ DAL->append(DAL->MakeJoinedArg(0, MCpu, "970"));
+
+ else if (Name == "ppc64")
+ DAL->append(DAL->MakeFlagArg(0, Opts.getOption(options::OPT_m64)));
+
+ else if (Name == "i386")
+ ;
+ else if (Name == "i486")
+ DAL->append(DAL->MakeJoinedArg(0, MArch, "i486"));
+ else if (Name == "i586")
+ DAL->append(DAL->MakeJoinedArg(0, MArch, "i586"));
+ else if (Name == "i686")
+ DAL->append(DAL->MakeJoinedArg(0, MArch, "i686"));
+ else if (Name == "pentium")
+ DAL->append(DAL->MakeJoinedArg(0, MArch, "pentium"));
+ else if (Name == "pentium2")
+ DAL->append(DAL->MakeJoinedArg(0, MArch, "pentium2"));
+ else if (Name == "pentpro")
+ DAL->append(DAL->MakeJoinedArg(0, MArch, "pentiumpro"));
+ else if (Name == "pentIIm3")
+ DAL->append(DAL->MakeJoinedArg(0, MArch, "pentium2"));
+
+ else if (Name == "x86_64")
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"));
+ else if (Name == "arm")
+ DAL->append(DAL->MakeJoinedArg(0, MArch, "armv4t"));
+ else if (Name == "armv4t")
+ DAL->append(DAL->MakeJoinedArg(0, MArch, "armv4t"));
+ else if (Name == "armv5")
+ DAL->append(DAL->MakeJoinedArg(0, MArch, "armv5tej"));
+ else if (Name == "xscale")
+ DAL->append(DAL->MakeJoinedArg(0, MArch, "xscale"));
+ else if (Name == "armv6")
+ DAL->append(DAL->MakeJoinedArg(0, MArch, "armv6k"));
+ else if (Name == "armv7")
+ DAL->append(DAL->MakeJoinedArg(0, MArch, "armv7a"));
+
+ else
+ llvm::llvm_unreachable("invalid Darwin arch");
+ }
return DAL;
-}
+}
-bool Darwin_X86::IsMathErrnoDefault() const {
- return false;
+bool Darwin::IsMathErrnoDefault() const {
+ return false;
}
-bool Darwin_X86::IsUnwindTablesDefault() const {
+bool Darwin::IsUnwindTablesDefault() const {
// FIXME: Gross; we should probably have some separate target
// definition, possibly even reusing the one in clang.
return getArchName() == "x86_64";
}
-const char *Darwin_X86::GetDefaultRelocationModel() const {
+const char *Darwin::GetDefaultRelocationModel() const {
return "pic";
}
-const char *Darwin_X86::GetForcedPicModel() const {
+const char *Darwin::GetForcedPicModel() const {
if (getArchName() == "x86_64")
return "pic";
return 0;
@@ -309,13 +520,12 @@ const char *Darwin_X86::GetForcedPicModel() const {
/// command line options.
Generic_GCC::Generic_GCC(const HostInfo &Host, const llvm::Triple& Triple)
- : ToolChain(Host, Triple)
-{
+ : ToolChain(Host, Triple) {
std::string Path(getHost().getDriver().Dir);
Path += "/../libexec";
getProgramPaths().push_back(Path);
- getProgramPaths().push_back(getHost().getDriver().Dir);
+ getProgramPaths().push_back(getHost().getDriver().Dir);
}
Generic_GCC::~Generic_GCC() {
@@ -325,10 +535,10 @@ Generic_GCC::~Generic_GCC() {
delete it->second;
}
-Tool &Generic_GCC::SelectTool(const Compilation &C,
+Tool &Generic_GCC::SelectTool(const Compilation &C,
const JobAction &JA) const {
Action::ActionClass Key;
- if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getArchName()))
+ if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
Key = Action::AnalyzeJobClass;
else
Key = JA.getKind();
@@ -351,7 +561,7 @@ Tool &Generic_GCC::SelectTool(const Compilation &C,
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:
@@ -362,8 +572,8 @@ Tool &Generic_GCC::SelectTool(const Compilation &C,
return *T;
}
-bool Generic_GCC::IsMathErrnoDefault() const {
- return true;
+bool Generic_GCC::IsMathErrnoDefault() const {
+ return true;
}
bool Generic_GCC::IsUnwindTablesDefault() const {
@@ -380,7 +590,8 @@ const char *Generic_GCC::GetForcedPicModel() const {
return 0;
}
-DerivedArgList *Generic_GCC::TranslateArgs(InputArgList &Args) const {
+DerivedArgList *Generic_GCC::TranslateArgs(InputArgList &Args,
+ const char *BoundArch) const {
return new DerivedArgList(Args, true);
}
@@ -394,7 +605,7 @@ OpenBSD::OpenBSD(const HostInfo &Host, const llvm::Triple& Triple)
Tool &OpenBSD::SelectTool(const Compilation &C, const JobAction &JA) const {
Action::ActionClass Key;
- if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getArchName()))
+ if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
Key = Action::AnalyzeJobClass;
else
Key = JA.getKind();
@@ -429,7 +640,7 @@ FreeBSD::FreeBSD(const HostInfo &Host, const llvm::Triple& Triple, bool Lib32)
Tool &FreeBSD::SelectTool(const Compilation &C, const JobAction &JA) const {
Action::ActionClass Key;
- if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getArchName()))
+ if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
Key = Action::AnalyzeJobClass;
else
Key = JA.getKind();
@@ -449,6 +660,48 @@ Tool &FreeBSD::SelectTool(const Compilation &C, const JobAction &JA) const {
return *T;
}
+/// AuroraUX - AuroraUX tool chain which can call as(1) and ld(1) directly.
+
+AuroraUX::AuroraUX(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/sfw/lib");
+ getFilePaths().push_back("/opt/gcc4/lib");
+
+}
+
+Tool &AuroraUX::SelectTool(const Compilation &C, const JobAction &JA) const {
+ Action::ActionClass Key;
+ if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
+ Key = Action::AnalyzeJobClass;
+ else
+ Key = JA.getKind();
+
+ Tool *&T = Tools[Key];
+ if (!T) {
+ switch (Key) {
+ case Action::AssembleJobClass:
+ T = new tools::auroraux::Assemble(*this); break;
+ case Action::LinkJobClass:
+ T = new tools::auroraux::Link(*this); break;
+ default:
+ T = &Generic_GCC::SelectTool(C, JA);
+ }
+ }
+
+ return *T;
+}
+
+
/// Linux toolchain (very bare-bones at the moment).
Linux::Linux(const HostInfo &Host, const llvm::Triple& Triple)
@@ -456,6 +709,15 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple& Triple)
getFilePaths().push_back(getHost().getDriver().Dir + "/../lib/clang/1.0/");
getFilePaths().push_back("/lib/");
getFilePaths().push_back("/usr/lib/");
+
+ // Depending on the Linux distribution, any combination of lib{,32,64} is
+ // possible. E.g. Debian uses lib and lib32 for mixed i386/x86-64 systems,
+ // openSUSE uses lib and lib64 for the same purpose.
+ getFilePaths().push_back("/lib32/");
+ getFilePaths().push_back("/usr/lib32/");
+ getFilePaths().push_back("/lib64/");
+ getFilePaths().push_back("/usr/lib64/");
+
// 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
@@ -475,7 +737,7 @@ DragonFly::DragonFly(const HostInfo &Host, const llvm::Triple& Triple)
Path += "/../libexec";
getProgramPaths().push_back(Path);
- getProgramPaths().push_back(getHost().getDriver().Dir);
+ getProgramPaths().push_back(getHost().getDriver().Dir);
getFilePaths().push_back(getHost().getDriver().Dir + "/../lib");
getFilePaths().push_back("/usr/lib");
@@ -484,7 +746,7 @@ DragonFly::DragonFly(const HostInfo &Host, const llvm::Triple& Triple)
Tool &DragonFly::SelectTool(const Compilation &C, const JobAction &JA) const {
Action::ActionClass Key;
- if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getArchName()))
+ if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
Key = Action::AnalyzeJobClass;
else
Key = JA.getKind();
diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
index c921d52..6088d96 100644
--- a/lib/Driver/ToolChains.h
+++ b/lib/Driver/ToolChains.h
@@ -22,9 +22,9 @@ 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.
+/// 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;
@@ -33,7 +33,8 @@ public:
Generic_GCC(const HostInfo &Host, const llvm::Triple& Triple);
~Generic_GCC();
- virtual DerivedArgList *TranslateArgs(InputArgList &Args) const;
+ virtual DerivedArgList *TranslateArgs(InputArgList &Args,
+ const char *BoundArch) const;
virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const;
@@ -43,30 +44,35 @@ public:
virtual const char *GetForcedPicModel() const;
};
- /// Darwin_X86 - Darwin tool chain for i386 an x86_64.
-class VISIBILITY_HIDDEN Darwin_X86 : public ToolChain {
+/// Darwin - The base Darwin tool chain.
+class VISIBILITY_HIDDEN Darwin : 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;
+ /// Whether this is this an iPhoneOS toolchain.
+ //
+ // FIXME: This should go away, such differences should be completely
+ // determined by the target triple.
+ bool IsIPhoneOS;
/// The default macosx-version-min of this tool chain; empty until
/// initialized.
mutable std::string MacosxVersionMin;
+ /// The default iphoneos-version-min of this tool chain.
+ std::string IPhoneOSVersionMin;
+
const char *getMacosxVersionMin() const;
public:
- Darwin_X86(const HostInfo &Host, const llvm::Triple& Triple,
- const unsigned (&DarwinVersion)[3],
- const unsigned (&GCCVersion)[3]);
- ~Darwin_X86();
+ Darwin(const HostInfo &Host, const llvm::Triple& Triple,
+ const unsigned (&DarwinVersion)[3], bool IsIPhoneOS);
+ ~Darwin();
+
+ /// @name Darwin Specific Toolchain API
+ /// {
void getDarwinVersion(unsigned (&Res)[3]) const {
Res[0] = DarwinVersion[0];
@@ -80,15 +86,53 @@ public:
Res[2] = DarwinVersion[1];
}
+ /// getMacosxVersionMin - Get the effective -mmacosx-version-min, which is
+ /// either the -mmacosx-version-min, or the current version if unspecified.
+ void getMacosxVersionMin(const ArgList &Args, unsigned (&Res)[3]) const;
+
+ 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 char *getMacosxVersionStr() const {
return MacosxVersionMin.c_str();
}
- const std::string &getToolChainDir() const {
- return ToolChainDir;
+ const char *getIPhoneOSVersionStr() const {
+ return IPhoneOSVersionMin.c_str();
}
- virtual DerivedArgList *TranslateArgs(InputArgList &Args) const;
+ /// AddLinkSearchPathArgs - Add the linker search paths to \arg CmdArgs.
+ ///
+ /// \param Args - The input argument list.
+ /// \param CmdArgs [out] - The command argument list to append the paths
+ /// (prefixed by -L) to.
+ virtual void AddLinkSearchPathArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const = 0;
+
+ /// AddLinkRuntimeLibArgs - Add the linker arguments to link the compiler
+ /// runtime library.
+ virtual void AddLinkRuntimeLibArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const = 0;
+
+ bool isIPhoneOS() const { return IsIPhoneOS; }
+
+ /// }
+ /// @name ToolChain Implementation
+ /// {
+
+ virtual DerivedArgList *TranslateArgs(InputArgList &Args,
+ const char *BoundArch) const;
virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const;
@@ -96,17 +140,69 @@ public:
virtual bool IsUnwindTablesDefault() const;
virtual const char *GetDefaultRelocationModel() const;
virtual const char *GetForcedPicModel() const;
+
+ /// }
+};
+
+/// DarwinClang - The Darwin toolchain used by Clang.
+class VISIBILITY_HIDDEN DarwinClang : public Darwin {
+public:
+ DarwinClang(const HostInfo &Host, const llvm::Triple& Triple,
+ const unsigned (&DarwinVersion)[3], bool IsIPhoneOS);
+
+ /// @name Darwin ToolChain Implementation
+ /// {
+
+ virtual void AddLinkSearchPathArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const;
+
+ virtual void AddLinkRuntimeLibArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const;
+
+ /// }
};
- /// Darwin_GCC - Generic Darwin tool chain using gcc.
-class VISIBILITY_HIDDEN Darwin_GCC : public Generic_GCC {
+/// DarwinGCC - The Darwin toolchain used by GCC.
+class VISIBILITY_HIDDEN DarwinGCC : public Darwin {
+ /// GCC version to use.
+ unsigned GCCVersion[3];
+
+ /// The directory suffix for this tool chain.
+ std::string ToolChainDir;
+
public:
- Darwin_GCC(const HostInfo &Host, const llvm::Triple& Triple)
+ DarwinGCC(const HostInfo &Host, const llvm::Triple& Triple,
+ const unsigned (&DarwinVersion)[3], const unsigned (&GCCVersion)[3],
+ bool IsIPhoneOS);
+
+ /// @name Darwin ToolChain Implementation
+ /// {
+
+ virtual void AddLinkSearchPathArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const;
+
+ virtual void AddLinkRuntimeLibArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const;
+
+ /// }
+};
+
+/// Darwin_Generic_GCC - Generic Darwin tool chain using gcc.
+class VISIBILITY_HIDDEN Darwin_Generic_GCC : public Generic_GCC {
+public:
+ Darwin_Generic_GCC(const HostInfo &Host, const llvm::Triple& Triple)
: Generic_GCC(Host, Triple) {}
virtual const char *GetDefaultRelocationModel() const { return "pic"; }
};
+class VISIBILITY_HIDDEN AuroraUX : public Generic_GCC {
+public:
+ AuroraUX(const HostInfo &Host, const llvm::Triple& Triple);
+
+ virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const;
+};
+
class VISIBILITY_HIDDEN OpenBSD : public Generic_GCC {
public:
OpenBSD(const HostInfo &Host, const llvm::Triple& Triple);
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index d198a54..fc91e4c 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -21,7 +21,8 @@
#include "clang/Driver/ToolChain.h"
#include "clang/Driver/Util.h"
-#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/Twine.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
@@ -33,25 +34,42 @@ 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());
+ llvm::SmallString<256> Str;
+ llvm::raw_svector_ostream(Str) << Fmt;
+ return Args.MakeArgString(Str.str());
}
-void Clang::AddPreprocessingOptions(const Driver &D,
+/// CheckPreprocessingOptions - Perform some validation of preprocessing
+/// arguments that is shared with gcc.
+static void CheckPreprocessingOptions(const Driver &D, const ArgList &Args) {
+ if (Arg *A = Args.getLastArg(options::OPT_C, options::OPT_CC))
+ if (!Args.hasArg(options::OPT_E))
+ D.Diag(clang::diag::err_drv_argument_only_allowed_with)
+ << A->getAsString(Args) << "-E";
+}
+
+/// CheckCodeGenerationOptions - Perform some validation of code generation
+/// arguments that is shared with gcc.
+static void CheckCodeGenerationOptions(const Driver &D, const ArgList &Args) {
+ // In gcc, only ARM checks this, but it seems reasonable to check universally.
+ if (Args.hasArg(options::OPT_static))
+ if (const Arg *A = Args.getLastArg(options::OPT_dynamic,
+ options::OPT_mdynamic_no_pic))
+ D.Diag(clang::diag::err_drv_argument_not_allowed_with)
+ << A->getAsString(Args) << "-static";
+}
+
+void Clang::AddPreprocessingOptions(const Driver &D,
const ArgList &Args,
ArgStringList &CmdArgs,
const InputInfo &Output,
const InputInfoList &Inputs) const {
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";
- A->render(Args, CmdArgs);
- }
+ CheckPreprocessingOptions(D, Args);
+
+ Args.AddLastArg(CmdArgs, options::OPT_C);
+ Args.AddLastArg(CmdArgs, options::OPT_CC);
// Handle dependency file generation.
if ((A = Args.getLastArg(options::OPT_M)) ||
@@ -77,6 +95,7 @@ void Clang::AddPreprocessingOptions(const Driver &D,
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;
@@ -94,7 +113,7 @@ void Clang::AddPreprocessingOptions(const Driver &D,
P.eraseSuffix();
P.appendSuffix("o");
- DepTarget = Args.MakeArgString(P.getLast().c_str());
+ DepTarget = Args.MakeArgString(P.getLast());
}
CmdArgs.push_back("-MT");
@@ -109,13 +128,13 @@ void Clang::AddPreprocessingOptions(const Driver &D,
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.
+ //
+ // FIXME: Use iterator.
for (ArgList::const_iterator
it = Args.begin(), ie = Args.end(); it != ie; ++it) {
const Arg *A = *it;
@@ -130,25 +149,25 @@ void Clang::AddPreprocessingOptions(const Driver &D,
P.appendSuffix("pch");
if (P.exists())
FoundPCH = true;
- else
+ else
P.eraseSuffix();
}
if (!FoundPCH) {
P.appendSuffix("pth");
- if (P.exists())
+ if (P.exists())
FoundPTH = true;
else
P.eraseSuffix();
- }
-
+ }
+
if (!FoundPCH && !FoundPTH) {
P.appendSuffix("gch");
if (P.exists()) {
FoundPCH = D.CCCUsePCH;
FoundPTH = !D.CCCUsePCH;
}
- else
+ else
P.eraseSuffix();
}
@@ -158,7 +177,7 @@ void Clang::AddPreprocessingOptions(const Driver &D,
CmdArgs.push_back("-include-pch");
else
CmdArgs.push_back("-include-pth");
- CmdArgs.push_back(Args.MakeArgString(P.c_str()));
+ CmdArgs.push_back(Args.MakeArgString(P.str()));
continue;
}
}
@@ -181,6 +200,308 @@ void Clang::AddPreprocessingOptions(const Driver &D,
options::OPT_Xpreprocessor);
}
+/// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targetting.
+//
+// FIXME: tblgen this.
+static llvm::StringRef getARMTargetCPU(const ArgList &Args) {
+ // FIXME: Warn on inconsistent use of -mcpu and -march.
+
+ // If we have -mcpu=, use that.
+ if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
+ return A->getValue(Args);
+
+ // Otherwise, if we have -march= choose the base CPU for that arch.
+ if (Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
+ llvm::StringRef MArch = A->getValue(Args);
+
+ if (MArch == "armv2" || MArch == "armv2a")
+ return "arm2";
+ if (MArch == "armv3")
+ return "arm6";
+ if (MArch == "armv3m")
+ return "arm7m";
+ if (MArch == "armv4" || MArch == "armv4t")
+ return "arm7tdmi";
+ if (MArch == "armv5" || MArch == "armv5t")
+ return "arm10tdmi";
+ if (MArch == "armv5e" || MArch == "armv5te")
+ return "arm1026ejs";
+ if (MArch == "armv5tej")
+ return "arm926ejs";
+ if (MArch == "armv6" || MArch == "armv6k")
+ return "arm1136jf-s";
+ if (MArch == "armv6j")
+ return "arm1136j-s";
+ if (MArch == "armv6z" || MArch == "armv6zk")
+ return "arm1176jzf-s";
+ if (MArch == "armv6t2")
+ return "arm1156t2-s";
+ if (MArch == "armv7" || MArch == "armv7a" || MArch == "armv7-a")
+ return "cortex-a8";
+ if (MArch == "armv7r" || MArch == "armv7-r")
+ return "cortex-r4";
+ if (MArch == "armv7m" || MArch == "armv7-m")
+ return "cortex-m3";
+ if (MArch == "ep9312")
+ return "ep9312";
+ if (MArch == "iwmmxt")
+ return "iwmmxt";
+ if (MArch == "xscale")
+ return "xscale";
+ }
+
+ // Otherwise return the most base CPU LLVM supports.
+ return "arm7tdmi";
+}
+
+/// getLLVMArchSuffixForARM - Get the LLVM arch name to use for a particular
+/// CPU.
+//
+// FIXME: This is redundant with -mcpu, why does LLVM use this.
+// FIXME: tblgen this, or kill it!
+static const char *getLLVMArchSuffixForARM(llvm::StringRef CPU) {
+ if (CPU == "arm7tdmi" || CPU == "arm7tdmi-s" || CPU == "arm710t" ||
+ CPU == "arm720t" || CPU == "arm9" || CPU == "arm9tdmi" ||
+ CPU == "arm920" || CPU == "arm920t" || CPU == "arm922t" ||
+ CPU == "arm940t" || CPU == "ep9312")
+ return "v4t";
+
+ if (CPU == "arm10tdmi" || CPU == "arm1020t")
+ return "v5";
+
+ if (CPU == "arm9e" || CPU == "arm926ej-s" || CPU == "arm946e-s" ||
+ CPU == "arm966e-s" || CPU == "arm968e-s" || CPU == "arm10e" ||
+ CPU == "arm1020e" || CPU == "arm1022e" || CPU == "xscale" ||
+ CPU == "iwmmxt")
+ return "v5e";
+
+ if (CPU == "arm1136j-s" || CPU == "arm1136jf-s" || CPU == "arm1176jz-s" ||
+ CPU == "arm1176jzf-s" || CPU == "mpcorenovfp" || CPU == "mpcore")
+ return "v6";
+
+ if (CPU == "arm1156t2-s" || CPU == "arm1156t2f-s")
+ return "v6t2";
+
+ if (CPU == "cortex-a8" || CPU == "cortex-a9")
+ return "v7";
+
+ return "";
+}
+
+/// getLLVMTriple - Get the LLVM triple to use for a particular toolchain, which
+/// may depend on command line arguments.
+static std::string getLLVMTriple(const ToolChain &TC, const ArgList &Args) {
+ switch (TC.getTriple().getArch()) {
+ default:
+ return TC.getTripleString();
+
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb: {
+ // FIXME: Factor into subclasses.
+ llvm::Triple Triple = TC.getTriple();
+
+ // Thumb2 is the default for V7 on Darwin.
+ //
+ // FIXME: Thumb should just be another -target-feaure, not in the triple.
+ llvm::StringRef Suffix = getLLVMArchSuffixForARM(getARMTargetCPU(Args));
+ bool ThumbDefault =
+ (Suffix == "v7" && TC.getTriple().getOS() == llvm::Triple::Darwin);
+ std::string ArchName = "arm";
+ if (Args.hasFlag(options::OPT_mthumb, options::OPT_mno_thumb, ThumbDefault))
+ ArchName = "thumb";
+ Triple.setArchName(ArchName + Suffix.str());
+
+ return Triple.getTriple();
+ }
+ }
+}
+
+void Clang::AddARMTargetArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ const Driver &D = getToolChain().getHost().getDriver();
+
+ // Select the ABI to use.
+ //
+ // FIXME: Support -meabi.
+ const char *ABIName = 0;
+ if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
+ ABIName = A->getValue(Args);
+ } else {
+ // Select the default based on the platform.
+ switch (getToolChain().getTriple().getOS()) {
+ // FIXME: Is this right for non-Darwin and non-Linux?
+ default:
+ ABIName = "aapcs";
+ break;
+
+ case llvm::Triple::Darwin:
+ ABIName = "apcs-gnu";
+ break;
+
+ case llvm::Triple::Linux:
+ ABIName = "aapcs-linux";
+ break;
+ }
+ }
+ CmdArgs.push_back("-target-abi");
+ CmdArgs.push_back(ABIName);
+
+ // Set the CPU based on -march= and -mcpu=.
+ CmdArgs.push_back(Args.MakeArgString("-mcpu=" + getARMTargetCPU(Args)));
+
+ // Select the float ABI as determined by -msoft-float, -mhard-float, and
+ // -mfloat-abi=.
+ llvm::StringRef FloatABI;
+ if (Arg *A = Args.getLastArg(options::OPT_msoft_float,
+ options::OPT_mhard_float,
+ options::OPT_mfloat_abi_EQ)) {
+ if (A->getOption().matches(options::OPT_msoft_float))
+ FloatABI = "soft";
+ else if (A->getOption().matches(options::OPT_mhard_float))
+ FloatABI = "hard";
+ else {
+ FloatABI = A->getValue(Args);
+ if (FloatABI != "soft" && FloatABI != "softfp" && FloatABI != "hard") {
+ D.Diag(clang::diag::err_drv_invalid_mfloat_abi)
+ << A->getAsString(Args);
+ FloatABI = "soft";
+ }
+ }
+ }
+
+ // If unspecified, choose the default based on the platform.
+ if (FloatABI.empty()) {
+ // FIXME: This is wrong for non-Darwin, we don't have a mechanism yet for
+ // distinguishing things like linux-eabi vs linux-elf.
+ switch (getToolChain().getTriple().getOS()) {
+ case llvm::Triple::Darwin: {
+ // Darwin defaults to "softfp" for v6 and v7.
+ //
+ // FIXME: Factor out an ARM class so we can cache the arch somewhere.
+ llvm::StringRef ArchName = getLLVMArchSuffixForARM(getARMTargetCPU(Args));
+ if (ArchName.startswith("v6") || ArchName.startswith("v7"))
+ FloatABI = "softfp";
+ else
+ FloatABI = "soft";
+ break;
+ }
+
+ default:
+ // Assume "soft", but warn the user we are guessing.
+ FloatABI = "soft";
+ D.Diag(clang::diag::warn_drv_assuming_mfloat_abi_is) << "soft";
+ break;
+ }
+ }
+
+ if (FloatABI == "soft") {
+ // Floating point operations and argument passing are soft.
+ //
+ // FIXME: This changes CPP defines, we need -target-soft-float.
+ CmdArgs.push_back("-soft-float");
+ CmdArgs.push_back("-float-abi=soft");
+ } else if (FloatABI == "softfp") {
+ // Floating point operations are hard, but argument passing is soft.
+ CmdArgs.push_back("-float-abi=soft");
+ } else {
+ // Floating point operations and argument passing are hard.
+ assert(FloatABI == "hard" && "Invalid float abi!");
+ CmdArgs.push_back("-float-abi=hard");
+ }
+}
+
+void Clang::AddX86TargetArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ // FIXME: This needs to change to use a clang-cc option, and set the attribute
+ // on functions.
+ 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");
+
+ // FIXME: This needs to change to use a clang-cc option, and set the attribute
+ // on functions.
+ if (Args.hasFlag(options::OPT_msoft_float,
+ options::OPT_mno_soft_float,
+ false))
+ CmdArgs.push_back("--no-implicit-float");
+
+ 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)) {
+ llvm::StringRef Name = A->getOption().getName();
+
+ // Skip over "-m".
+ assert(Name.startswith("-m") && "Invalid feature name.");
+ Name = Name.substr(2);
+
+ bool IsNegative = Name.startswith("no-");
+ if (IsNegative)
+ Name = Name.substr(3);
+
+ A->claim();
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name));
+ }
+ }
+}
+
+static bool needsExceptions(const ArgList &Args, types::ID InputType,
+ const llvm::Triple &Triple) {
+ if (Arg *A = Args.getLastArg(options::OPT_fexceptions,
+ options::OPT_fno_exceptions)) {
+ if (A->getOption().matches(options::OPT_fexceptions))
+ return true;
+ else
+ return false;
+ }
+ switch (InputType) {
+ case types::TY_CXX: case types::TY_CXXHeader:
+ case types::TY_PP_CXX: case types::TY_PP_CXXHeader:
+ case types::TY_ObjCXX: case types::TY_ObjCXXHeader:
+ case types::TY_PP_ObjCXX: case types::TY_PP_ObjCXXHeader:
+ return true;
+
+ case types::TY_ObjC: case types::TY_ObjCHeader:
+ case types::TY_PP_ObjC: case types::TY_PP_ObjCHeader:
+ if (Args.hasArg(options::OPT_fobjc_nonfragile_abi))
+ return true;
+ if (Triple.getOS() != llvm::Triple::Darwin)
+ return false;
+ return (Triple.getDarwinMajorNumber() >= 9 &&
+ Triple.getArch() == llvm::Triple::x86_64);
+
+ default:
+ return false;
+ }
+}
+
void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Job &Dest,
const InputInfo &Output,
@@ -193,8 +514,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
assert(Inputs.size() == 1 && "Unable to handle multiple inputs.");
CmdArgs.push_back("-triple");
+
const char *TripleStr =
- Args.MakeArgString(getToolChain().getTripleString().c_str());
+ Args.MakeArgString(getLLVMTriple(getToolChain(), Args));
CmdArgs.push_back(TripleStr);
if (isa<AnalyzeJobAction>(JA)) {
@@ -221,6 +543,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-emit-llvm-bc");
} else if (JA.getType() == types::TY_PP_Asm) {
CmdArgs.push_back("-S");
+ } else if (JA.getType() == types::TY_AST) {
+ CmdArgs.push_back("-emit-pch");
}
}
@@ -238,9 +562,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-static-define");
if (isa<AnalyzeJobAction>(JA)) {
+ // Enable region store model by default.
+ CmdArgs.push_back("-analyzer-store=region");
+
// Add default argument set.
if (!Args.hasArg(options::OPT__analyzer_no_default_checks)) {
CmdArgs.push_back("-warn-dead-stores");
+ CmdArgs.push_back("-warn-security-syntactic");
CmdArgs.push_back("-checker-cfref");
CmdArgs.push_back("-analyzer-eagerly-assume");
CmdArgs.push_back("-warn-objc-methodsigs");
@@ -259,8 +587,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Add -Xanalyzer arguments when running as analyzer.
Args.AddAllArgValues(CmdArgs, options::OPT_Xanalyzer);
- }
-
+ }
+
+ CheckCodeGenerationOptions(D, Args);
+
// Perform argument translation for LLVM backend. This
// takes some care in reconciling with llvm-gcc. The
// issue is that llvm-gcc translates these options based on
@@ -308,7 +638,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
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))
+ if (Args.hasFlag(options::OPT_fno_omit_frame_pointer,
+ 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,
@@ -322,71 +653,43 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
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))))
+
+ // This is a coarse approximation of what llvm-gcc actually does, both
+ // -fasynchronous-unwind-tables and -fnon-call-exceptions interact in more
+ // complicated ways.
+ bool AsynchronousUnwindTables =
+ Args.hasFlag(options::OPT_fasynchronous_unwind_tables,
+ options::OPT_fno_asynchronous_unwind_tables,
+ getToolChain().IsUnwindTablesDefault() &&
+ !Args.hasArg(options::OPT_mkernel));
+ if (Args.hasFlag(options::OPT_funwind_tables, options::OPT_fno_unwind_tables,
+ AsynchronousUnwindTables))
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("--no-implicit-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");
+ if (Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ)) {
+ CmdArgs.push_back("-code-model");
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();
+ // Add target specific cpu and features flags.
+ switch(getToolChain().getTriple().getArch()) {
+ default:
+ break;
- // 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;
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ AddARMTargetArgs(Args, CmdArgs);
+ break;
- A->claim();
- CmdArgs.push_back("-target-feature");
- CmdArgs.push_back(MakeFormattedString(Args,
- llvm::format("%c%s",
- IsNegative ? '-' : '+',
- Name)));
- }
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ AddX86TargetArgs(Args, CmdArgs);
+ break;
}
if (Args.hasFlag(options::OPT_fmath_errno,
@@ -415,7 +718,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
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);
+ Args.AddLastArg(CmdArgs, options::OPT_print_ivar_layout);
// Special case debug options to only pass -g to clang. This is
// wrong.
@@ -423,6 +726,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-g");
Args.AddLastArg(CmdArgs, options::OPT_nostdinc);
+ Args.AddLastArg(CmdArgs, options::OPT_nostdclanginc);
Args.AddLastArg(CmdArgs, options::OPT_isysroot);
@@ -434,13 +738,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
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
+ // Manually translate -O to -O2 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");
+ CmdArgs.push_back("-O2");
else
A->render(Args, CmdArgs);
}
@@ -474,9 +778,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(A->getValue(Args));
}
+ if (Args.hasArg(options::OPT__relocatable_pch, true))
+ CmdArgs.push_back("--relocatable-pch");
+
+ if (Arg *A = Args.getLastArg(options::OPT_fconstant_string_class_EQ)) {
+ CmdArgs.push_back("-fconstant-string-class");
+ CmdArgs.push_back(A->getValue(Args));
+ }
+
// 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);
@@ -498,6 +809,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_fvisibility_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fwritable_strings);
+ Args.AddLastArg(CmdArgs, options::OPT_pthread);
+
// Forward stack protector flags.
if (Arg *A = Args.getLastArg(options::OPT_fno_stack_protector,
options::OPT_fstack_protector_all,
@@ -526,6 +839,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fblocks=0");
}
+ if (needsExceptions(Args, InputType, getToolChain().getTriple()))
+ CmdArgs.push_back("-fexceptions");
+ else
+ CmdArgs.push_back("-fexceptions=0");
+
+ // -frtti is default, only pass non-default.
+ if (!Args.hasFlag(options::OPT_frtti, options::OPT_fno_rtti))
+ CmdArgs.push_back("-frtti=0");
+
// -fsigned-char/-funsigned-char default varies depending on platform; only
// pass if specified.
if (Arg *A = Args.getLastArg(options::OPT_fsigned_char,
@@ -556,18 +878,18 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// -fsigned-bitfields is default, and clang doesn't yet support
// --funsigned-bitfields.
- if (!Args.hasFlag(options::OPT_fsigned_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,
+ 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,
+ if (Args.hasFlag(options::OPT_fdiagnostics_show_option,
options::OPT_fno_diagnostics_show_option))
CmdArgs.push_back("-fdiagnostics-show-option");
if (!Args.hasFlag(options::OPT_fcolor_diagnostics,
@@ -579,7 +901,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// -fdollars-in-identifiers default varies depending on platform and
// language; only pass if specified.
- if (Arg *A = Args.getLastArg(options::OPT_fdollars_in_identifiers,
+ 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");
@@ -589,12 +911,30 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// -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,
+ 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);
+ D.Diag(clang::diag::warn_drv_clang_unsupported) << A->getAsString(Args);
}
-
+
+ // Default to -fno-builtin-str{cat,cpy} on Darwin for ARM.
+ //
+ // FIXME: This is disabled until clang-cc supports -fno-builtin-foo. PR4941.
+#if 0
+ if (getToolChain().getTriple().getOS() == llvm::Triple::Darwin &&
+ (getToolChain().getTriple().getArch() == llvm::Triple::arm ||
+ getToolChain().getTriple().getArch() == llvm::Triple::thumb)) {
+ if (!Args.hasArg(options::OPT_fbuiltin_strcat))
+ CmdArgs.push_back("-fno-builtin-strcat");
+ if (!Args.hasArg(options::OPT_fbuiltin_strcpy))
+ CmdArgs.push_back("-fno-builtin-strcpy");
+ }
+#endif
+
+ if (Arg *A = Args.getLastArg(options::OPT_traditional,
+ options::OPT_traditional_cpp))
+ D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
+
Args.AddLastArg(CmdArgs, options::OPT_dM);
Args.AddLastArg(CmdArgs, options::OPT_dD);
@@ -627,7 +967,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath(C, "clang-cc").c_str());
+ Args.MakeArgString(getToolChain().GetProgramPath(C, "clang-cc"));
Dest.addCommand(new Command(JA, Exec, CmdArgs));
// Explicitly warn that these options are unsupported, even though
@@ -699,7 +1039,7 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
else if (Arch == "powerpc64")
CmdArgs.push_back("ppc64");
else
- CmdArgs.push_back(Args.MakeArgString(Arch.c_str()));
+ CmdArgs.push_back(Args.MakeArgString(Arch));
}
// Try to force gcc to match the tool chain we want, if we recognize
@@ -736,10 +1076,13 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
const InputInfo &II = *it;
- // Don't try to pass LLVM inputs to a generic gcc.
+ // Don't try to pass LLVM or AST 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();
+ << getToolChain().getTripleString();
+ else if (II.getType() == types::TY_AST)
+ D.Diag(clang::diag::err_drv_no_ast_support)
+ << getToolChain().getTripleString();
if (types::canTypeBeUserSpecified(II.getType())) {
CmdArgs.push_back("-x");
@@ -758,7 +1101,7 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
const char *GCCName =
getToolChain().getHost().getDriver().CCCGenericGCCName.c_str();
const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath(C, GCCName).c_str());
+ Args.MakeArgString(getToolChain().GetProgramPath(C, GCCName));
Dest.addCommand(new Command(JA, Exec, CmdArgs));
}
@@ -805,7 +1148,7 @@ const char *darwin::CC1::getCC1Name(types::ID Type) const {
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());
+ return Args.MakeArgString(P.getLast());
}
const char *darwin::CC1::getBaseInputStem(const ArgList &Args,
@@ -813,7 +1156,7 @@ const char *darwin::CC1::getBaseInputStem(const ArgList &Args,
const char *Str = getBaseInputName(Args, Inputs);
if (const char *End = strchr(Str, '.'))
- return Args.MakeArgString(std::string(Str, End).c_str());
+ return Args.MakeArgString(std::string(Str, End));
return Str;
}
@@ -831,31 +1174,32 @@ darwin::CC1::getDependencyFileName(const ArgList &Args,
} else
Res = darwin::CC1::getBaseInputStem(Args, Inputs);
- return Args.MakeArgString((Res + ".d").c_str());
+ return Args.MakeArgString(Res + ".d");
}
void darwin::CC1::AddCC1Args(const ArgList &Args,
ArgStringList &CmdArgs) const {
- // Derived from cc1 spec.
+ const Driver &D = getToolChain().getHost().getDriver();
+
+ CheckCodeGenerationOptions(D, Args);
- // FIXME: -fapple-kext seems to disable this too. Investigate.
+ // Derived from cc1 spec.
if (!Args.hasArg(options::OPT_mkernel) && !Args.hasArg(options::OPT_static) &&
!Args.hasArg(options::OPT_mdynamic_no_pic))
CmdArgs.push_back("-fPIC");
+ if (getToolChain().getTriple().getArch() == llvm::Triple::arm ||
+ getToolChain().getTriple().getArch() == llvm::Triple::thumb) {
+ if (!Args.hasArg(options::OPT_fbuiltin_strcat))
+ CmdArgs.push_back("-fno-builtin-strcat");
+ if (!Args.hasArg(options::OPT_fbuiltin_strcpy))
+ CmdArgs.push_back("-fno-builtin-strcpy");
+ }
+
// 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");
@@ -924,7 +1268,28 @@ void darwin::CC1::AddCC1OptionsArgs(const ArgList &Args, ArgStringList &CmdArgs,
Args.AddLastArg(CmdArgs, options::OPT_p);
// The driver treats -fsyntax-only specially.
- Args.AddAllArgs(CmdArgs, options::OPT_f_Group, options::OPT_fsyntax_only);
+ if (getToolChain().getTriple().getArch() == llvm::Triple::arm ||
+ getToolChain().getTriple().getArch() == llvm::Triple::thumb) {
+ // Removes -fbuiltin-str{cat,cpy}; these aren't recognized by cc1 but are
+ // used to inhibit the default -fno-builtin-str{cat,cpy}.
+ //
+ // FIXME: Should we grow a better way to deal with "removing" args?
+ //
+ // 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_f_Group) ||
+ A->getOption().matches(options::OPT_fsyntax_only)) {
+ if (!A->getOption().matches(options::OPT_fbuiltin_strcat) &&
+ !A->getOption().matches(options::OPT_fbuiltin_strcpy)) {
+ A->claim();
+ A->render(Args, CmdArgs);
+ }
+ }
+ }
+ } else
+ Args.AddAllArgs(CmdArgs, options::OPT_f_Group, options::OPT_fsyntax_only);
Args.AddAllArgs(CmdArgs, options::OPT_undef);
if (Args.hasArg(options::OPT_Qn))
@@ -995,18 +1360,15 @@ void darwin::CC1::AddCPPOptionsArgs(const ArgList &Args, ArgStringList &CmdArgs,
void darwin::CC1::AddCPPUniqueOptionsArgs(const ArgList &Args,
ArgStringList &CmdArgs,
- const InputInfoList &Inputs) const
-{
+ const InputInfoList &Inputs) const {
const Driver &D = getToolChain().getHost().getDriver();
+ CheckPreprocessingOptions(D, Args);
+
// 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";
- }
+ // -{C,CC} only with -E is checked in CheckPreprocessingOptions().
+ Args.AddLastArg(CmdArgs, options::OPT_C);
+ Args.AddLastArg(CmdArgs, options::OPT_CC);
if (!Args.hasArg(options::OPT_Q))
CmdArgs.push_back("-quiet");
Args.AddAllArgs(CmdArgs, options::OPT_nostdinc);
@@ -1111,7 +1473,6 @@ void darwin::Preprocess::ConstructJob(Compilation &C, const JobAction &JA,
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");
@@ -1134,7 +1495,7 @@ void darwin::Preprocess::ConstructJob(Compilation &C, const JobAction &JA,
const char *CC1Name = getCC1Name(Inputs[0].getType());
const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath(C, CC1Name).c_str());
+ Args.MakeArgString(getToolChain().GetProgramPath(C, CC1Name));
Dest.addCommand(new Command(JA, Exec, CmdArgs));
}
@@ -1150,8 +1511,7 @@ void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA,
types::ID InputType = Inputs[0].getType();
const Arg *A;
- if ((A = Args.getLastArg(options::OPT_traditional)) ||
- (A = Args.getLastArg(options::OPT_ftraditional)))
+ if ((A = Args.getLastArg(options::OPT_traditional)))
D.Diag(clang::diag::err_drv_argument_only_allowed_with)
<< A->getAsString(Args) << "-E";
@@ -1159,6 +1519,9 @@ void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-emit-llvm");
else if (Output.getType() == types::TY_LLVMBC)
CmdArgs.push_back("-emit-llvm-bc");
+ else if (Output.getType() == types::TY_AST)
+ D.Diag(clang::diag::err_drv_no_ast_support)
+ << getToolChain().getTripleString();
ArgStringList OutputArgs;
if (Output.getType() != types::TY_PCH) {
@@ -1187,13 +1550,17 @@ void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA,
} 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;
+ // Reject AST inputs.
+ if (II.getType() == types::TY_AST) {
+ D.Diag(clang::diag::err_drv_no_ast_support)
+ << getToolChain().getTripleString();
+ return;
+ }
+
if (II.isPipe())
CmdArgs.push_back("-");
else
@@ -1222,7 +1589,7 @@ void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA,
const char *CC1Name = getCC1Name(Inputs[0].getType());
const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath(C, CC1Name).c_str());
+ Args.MakeArgString(getToolChain().GetProgramPath(C, CC1Name));
Dest.addCommand(new Command(JA, Exec, CmdArgs));
}
@@ -1248,14 +1615,16 @@ void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
}
// Derived from asm spec.
- CmdArgs.push_back("-arch");
- CmdArgs.push_back(Args.MakeArgString(getToolChain().getArchName().c_str()));
+ AddDarwinArch(Args, CmdArgs);
+
+ if (!getDarwinToolChain().isIPhoneOS() ||
+ Args.hasArg(options::OPT_force__cpusubtype__ALL))
+ CmdArgs.push_back("-force_cpusubtype_ALL");
- CmdArgs.push_back("-force_cpusubtype_ALL");
- if ((Args.hasArg(options::OPT_mkernel) ||
+ if (getToolChain().getTriple().getArch() != llvm::Triple::x86_64 &&
+ (Args.hasArg(options::OPT_mkernel) ||
Args.hasArg(options::OPT_static) ||
- Args.hasArg(options::OPT_fapple_kext)) &&
- !Args.hasArg(options::OPT_dynamic))
+ Args.hasArg(options::OPT_fapple_kext)))
CmdArgs.push_back("-static");
Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
@@ -1275,7 +1644,7 @@ void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
// asm_final spec is empty.
const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath(C, "as").c_str());
+ Args.MakeArgString(getToolChain().GetProgramPath(C, "as"));
Dest.addCommand(new Command(JA, Exec, CmdArgs));
}
@@ -1304,33 +1673,84 @@ static bool isSourceSuffix(const char *Str) {
}
}
-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;
-}
+// FIXME: Can we tablegen this?
+static const char *GetArmArchForMArch(llvm::StringRef Value) {
+ if (Value == "armv6k")
+ return "armv6";
+
+ if (Value == "armv5tej")
+ return "armv5";
+
+ if (Value == "xscale")
+ return "xscale";
-static bool isMacosxVersionLT(unsigned (&A)[3],
- unsigned V0, unsigned V1=0, unsigned V2=0) {
- unsigned B[3] = { V0, V1, V2 };
- return isMacosxVersionLT(A, B);
+ if (Value == "armv4t")
+ return "armv4t";
+
+ if (Value == "armv7" || Value == "armv7-a" || Value == "armv7-r" ||
+ Value == "armv7-m" || Value == "armv7a" || Value == "armv7r" ||
+ Value == "armv7m")
+ return "armv7";
+
+ return 0;
}
-const toolchains::Darwin_X86 &darwin::Link::getDarwinToolChain() const {
- return reinterpret_cast<const toolchains::Darwin_X86&>(getToolChain());
+// FIXME: Can we tablegen this?
+static const char *GetArmArchForMCpu(llvm::StringRef Value) {
+ if (Value == "arm10tdmi" || Value == "arm1020t" || Value == "arm9e" ||
+ Value == "arm946e-s" || Value == "arm966e-s" ||
+ Value == "arm968e-s" || Value == "arm10e" ||
+ Value == "arm1020e" || Value == "arm1022e" || Value == "arm926ej-s" ||
+ Value == "arm1026ej-s")
+ return "armv5";
+
+ if (Value == "xscale")
+ return "xscale";
+
+ if (Value == "arm1136j-s" || Value == "arm1136jf-s" ||
+ Value == "arm1176jz-s" || Value == "arm1176jzf-s")
+ return "armv6";
+
+ if (Value == "cortex-a8" || Value == "cortex-r4" || Value == "cortex-m3")
+ return "armv7";
+
+ return 0;
}
-void darwin::Link::AddDarwinArch(const ArgList &Args,
- ArgStringList &CmdArgs) const {
+void darwin::DarwinTool::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()));
+
+ switch (getToolChain().getTriple().getArch()) {
+ default:
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().getArchName()));
+ break;
+
+ case llvm::Triple::arm: {
+ if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
+ if (const char *Arch = GetArmArchForMArch(A->getValue(Args))) {
+ CmdArgs.push_back(Arch);
+ return;
+ }
+ }
+
+ if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
+ if (const char *Arch = GetArmArchForMCpu(A->getValue(Args))) {
+ CmdArgs.push_back(Arch);
+ return;
+ }
+ }
+
+ CmdArgs.push_back("arm");
+ CmdArgs.push_back("-force_cpusubtype_ALL");
+ return;
+ }
+ }
}
-void darwin::Link::AddDarwinSubArch(const ArgList &Args,
- ArgStringList &CmdArgs) const {
+void darwin::DarwinTool::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);
@@ -1401,6 +1821,8 @@ void darwin::Link::AddLinkArgs(const ArgList &Args,
Args.AddLastArg(CmdArgs, options::OPT_all__load);
Args.AddAllArgs(CmdArgs, options::OPT_allowable__client);
Args.AddLastArg(CmdArgs, options::OPT_bind__at__load);
+ if (getDarwinToolChain().isIPhoneOS())
+ Args.AddLastArg(CmdArgs, options::OPT_arch__errors__fatal);
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);
@@ -1411,22 +1833,22 @@ void darwin::Link::AddLinkArgs(const ArgList &Args,
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.
+ if (!Args.hasArg(options::OPT_mmacosx_version_min_EQ) &&
+ !Args.hasArg(options::OPT_miphoneos_version_min_EQ)) {
+ // Add default version min.
+ if (!getDarwinToolChain().isIPhoneOS()) {
CmdArgs.push_back("-macosx_version_min");
CmdArgs.push_back(getDarwinToolChain().getMacosxVersionStr());
+ } else {
+ CmdArgs.push_back("-iphoneos_version_min");
+ CmdArgs.push_back(getDarwinToolChain().getIPhoneOSVersionStr());
}
- } 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");
}
+ // 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);
@@ -1454,14 +1876,22 @@ void darwin::Link::AddLinkArgs(const ArgList &Args,
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");
+ if (getDarwinToolChain().isIPhoneOS()) {
+ if (!Args.hasArg(options::OPT_isysroot)) {
+ CmdArgs.push_back("-syslibroot");
+ CmdArgs.push_back("/Developer/SDKs/Extra");
+ }
+ }
+
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);
+ 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");
@@ -1490,20 +1920,16 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
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);
@@ -1514,28 +1940,12 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
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);
- }
+
+ unsigned MacosxVersionMin[3];
+ getDarwinToolChain().getMacosxVersionMin(Args, MacosxVersionMin);
if (!Args.hasArg(options::OPT_A) &&
!Args.hasArg(options::OPT_nostdlib) &&
@@ -1543,15 +1953,15 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
// Derived from startfile spec.
if (Args.hasArg(options::OPT_dynamiclib)) {
// Derived from darwin_dylib1 spec.
- if (isMacosxVersionLT(MacosxVersion, 10, 5))
+ if (getDarwinToolChain().isMacosxVersionLT(MacosxVersionMin, 10, 5))
CmdArgs.push_back("-ldylib1.o");
- else if (isMacosxVersionLT(MacosxVersion, 10, 6))
+ else if (getDarwinToolChain().isMacosxVersionLT(MacosxVersionMin, 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))
+ if (getDarwinToolChain().isMacosxVersionLT(MacosxVersionMin, 10, 6))
CmdArgs.push_back("-lbundle1.o");
}
} else {
@@ -1572,9 +1982,13 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-lcrt0.o");
} else {
// Derived from darwin_crt1 spec.
- if (isMacosxVersionLT(MacosxVersion, 10, 5))
+ if (getDarwinToolChain().isIPhoneOS()) {
+ CmdArgs.push_back("-lcrt1.o");
+ } else if (getDarwinToolChain().isMacosxVersionLT(MacosxVersionMin,
+ 10, 5))
CmdArgs.push_back("-lcrt1.o");
- else if (isMacosxVersionLT(MacosxVersion, 10, 6))
+ else if (getDarwinToolChain().isMacosxVersionLT(MacosxVersionMin,
+ 10, 6))
CmdArgs.push_back("-lcrt1.10.5.o");
else
CmdArgs.push_back("-lcrt1.10.6.o");
@@ -1587,9 +2001,10 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
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));
+ getDarwinToolChain().isMacosxVersionLT(MacosxVersionMin, 10, 5)) {
+ const char *Str =
+ Args.MakeArgString(getToolChain().GetFilePath(C, "crt3.o"));
+ CmdArgs.push_back(Str);
}
}
@@ -1599,26 +2014,7 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
// 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)));
+ getDarwinToolChain().AddLinkSearchPathArgs(Args, CmdArgs);
for (InputInfoList::const_iterator
it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
@@ -1653,40 +2049,8 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
// 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");
- }
- }
+ // Let the tool chain choose which runtime library to link.
+ getDarwinToolChain().AddLinkRuntimeLibArgs(Args, CmdArgs);
}
if (!Args.hasArg(options::OPT_A) &&
@@ -1699,7 +2063,7 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddAllArgs(CmdArgs, options::OPT_F);
const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath(C, "ld").c_str());
+ Args.MakeArgString(getToolChain().GetProgramPath(C, "ld"));
Dest.addCommand(new Command(JA, Exec, CmdArgs));
// Find the first non-empty base input (we want to ignore linker
@@ -1727,7 +2091,7 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
const char *Suffix = strrchr(BaseInput, '.');
if (Suffix && isSourceSuffix(Suffix + 1)) {
const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath(C, "dsymutil").c_str());
+ Args.MakeArgString(getToolChain().GetProgramPath(C, "dsymutil"));
ArgStringList CmdArgs;
CmdArgs.push_back(Output.getFilename());
C.getJobs().addCommand(new Command(JA, Exec, CmdArgs));
@@ -1755,7 +2119,135 @@ void darwin::Lipo::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(II.getFilename());
}
const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath(C, "lipo").c_str());
+ Args.MakeArgString(getToolChain().GetProgramPath(C, "lipo"));
+ Dest.addCommand(new Command(JA, Exec, CmdArgs));
+}
+
+void auroraux::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
+ Job &Dest, const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ ArgStringList CmdArgs;
+
+ 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"));
+ Dest.addCommand(new Command(JA, Exec, CmdArgs));
+}
+
+void auroraux::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_nostdlib)) &&
+ (!Args.hasArg(options::OPT_shared))) {
+ CmdArgs.push_back("-e");
+ CmdArgs.push_back("__start");
+ }
+
+ if (Args.hasArg(options::OPT_static)) {
+ CmdArgs.push_back("-Bstatic");
+ } else {
+ CmdArgs.push_back("--eh-frame-hdr");
+ CmdArgs.push_back("-Bdynamic");
+ if (Args.hasArg(options::OPT_shared)) {
+ CmdArgs.push_back("-shared");
+ } else {
+ CmdArgs.push_back("-dynamic-linker");
+ CmdArgs.push_back("/lib/ld.so.1"); // 64Bit Path /lib/amd64/ld.so.1
+ }
+ }
+
+ 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, "crt0.o")));
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtbegin.o")));
+ } else {
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtbeginS.o")));
+ }
+ }
+
+ CmdArgs.push_back(MakeFormattedString(Args,
+ llvm::format("-L/opt/gcc4/lib/gcc/%s/4.2.4",
+ getToolChain().getTripleString().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();
+
+ 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 before adding
+ // the default system libraries. Just mimic this for now.
+ CmdArgs.push_back("-lgcc");
+
+ if (Args.hasArg(options::OPT_pthread))
+ CmdArgs.push_back("-pthread");
+ if (!Args.hasArg(options::OPT_shared))
+ CmdArgs.push_back("-lc");
+ 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")));
+ else
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtendS.o")));
+ }
+
+ const char *Exec =
+ Args.MakeArgString(getToolChain().GetProgramPath(C, "ld"));
Dest.addCommand(new Command(JA, Exec, CmdArgs));
}
@@ -1763,8 +2255,7 @@ void openbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
Job &Dest, const InputInfo &Output,
const InputInfoList &Inputs,
const ArgList &Args,
- const char *LinkingOutput) const
-{
+ const char *LinkingOutput) const {
ArgStringList CmdArgs;
Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
@@ -1786,7 +2277,7 @@ void openbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
}
const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath(C, "as").c_str());
+ Args.MakeArgString(getToolChain().GetProgramPath(C, "as"));
Dest.addCommand(new Command(JA, Exec, CmdArgs));
}
@@ -1798,12 +2289,19 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
const Driver &D = getToolChain().getHost().getDriver();
ArgStringList CmdArgs;
+ if ((!Args.hasArg(options::OPT_nostdlib)) &&
+ (!Args.hasArg(options::OPT_shared))) {
+ CmdArgs.push_back("-e");
+ CmdArgs.push_back("__start");
+ }
+
if (Args.hasArg(options::OPT_static)) {
CmdArgs.push_back("-Bstatic");
} else {
CmdArgs.push_back("--eh-frame-hdr");
+ CmdArgs.push_back("-Bdynamic");
if (Args.hasArg(options::OPT_shared)) {
- CmdArgs.push_back("-Bshareable");
+ CmdArgs.push_back("-shared");
} else {
CmdArgs.push_back("-dynamic-linker");
CmdArgs.push_back("/usr/libexec/ld.so");
@@ -1823,13 +2321,17 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nostartfiles)) {
if (!Args.hasArg(options::OPT_shared)) {
- CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crt0.o").c_str()));
- CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtbegin.o").c_str()));
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crt0.o")));
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtbegin.o")));
} else {
- CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtbeginS.o").c_str()));
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtbeginS.o")));
}
}
+ CmdArgs.push_back(MakeFormattedString(Args,
+ llvm::format("-L/usr/lib/gcc-lib/%s/3.3.5",
+ getToolChain().getTripleString().c_str())));
+
Args.AddAllArgs(CmdArgs, options::OPT_L);
Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
Args.AddAllArgs(CmdArgs, options::OPT_e);
@@ -1841,7 +2343,7 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
// 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();
+ << getToolChain().getTripleString();
if (II.isPipe())
CmdArgs.push_back("-");
@@ -1853,22 +2355,27 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nodefaultlibs)) {
+ // FIXME: For some reason GCC passes -lgcc before adding
+ // the default system libraries. Just mimic this for now.
+ CmdArgs.push_back("-lgcc");
if (Args.hasArg(options::OPT_pthread))
CmdArgs.push_back("-pthread");
- CmdArgs.push_back("-lc");
+ if (!Args.hasArg(options::OPT_shared))
+ CmdArgs.push_back("-lc");
+ 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()));
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtend.o")));
else
- CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtendS.o").c_str()));
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtendS.o")));
}
const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath(C, "ld").c_str());
+ Args.MakeArgString(getToolChain().GetProgramPath(C, "ld"));
Dest.addCommand(new Command(JA, Exec, CmdArgs));
}
@@ -1876,8 +2383,7 @@ void freebsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
Job &Dest, const InputInfo &Output,
const InputInfoList &Inputs,
const ArgList &Args,
- const char *LinkingOutput) const
-{
+ const char *LinkingOutput) const {
ArgStringList CmdArgs;
// When building 32-bit code on FreeBSD/amd64, we have to explicitly
@@ -1904,7 +2410,7 @@ void freebsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
}
const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath(C, "as").c_str());
+ Args.MakeArgString(getToolChain().GetProgramPath(C, "as"));
Dest.addCommand(new Command(JA, Exec, CmdArgs));
}
@@ -1948,12 +2454,12 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nostartfiles)) {
if (!Args.hasArg(options::OPT_shared)) {
- CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(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()));
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crt1.o")));
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crti.o")));
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtbegin.o")));
} 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()));
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crti.o")));
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtbeginS.o")));
}
}
@@ -1968,7 +2474,7 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
// 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();
+ << getToolChain().getTripleString();
if (II.isPipe())
CmdArgs.push_back("-");
@@ -2008,14 +2514,14 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nostartfiles)) {
if (!Args.hasArg(options::OPT_shared))
- CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtend.o").c_str()));
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtend.o")));
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()));
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtendS.o")));
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtn.o")));
}
const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath(C, "ld").c_str());
+ Args.MakeArgString(getToolChain().GetProgramPath(C, "ld"));
Dest.addCommand(new Command(JA, Exec, CmdArgs));
}
@@ -2054,7 +2560,7 @@ void dragonfly::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
}
const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath(C, "as").c_str());
+ Args.MakeArgString(getToolChain().GetProgramPath(C, "as"));
Dest.addCommand(new Command(JA, Exec, CmdArgs));
}
@@ -2097,12 +2603,12 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nostartfiles)) {
if (!Args.hasArg(options::OPT_shared)) {
- CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(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()));
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crt1.o")));
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crti.o")));
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtbegin.o")));
} 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()));
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crti.o")));
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtbeginS.o")));
}
}
@@ -2117,7 +2623,7 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA,
// 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();
+ << getToolChain().getTripleString();
if (II.isPipe())
CmdArgs.push_back("-");
@@ -2171,13 +2677,13 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nostartfiles)) {
if (!Args.hasArg(options::OPT_shared))
- CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtend.o").c_str()));
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtend.o")));
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()));
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtendS.o")));
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtn.o")));
}
const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath(C, "ld").c_str());
+ Args.MakeArgString(getToolChain().GetProgramPath(C, "ld"));
Dest.addCommand(new Command(JA, Exec, CmdArgs));
}
diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h
index ab73496..6729da8 100644
--- a/lib/Driver/Tools.h
+++ b/lib/Driver/Tools.h
@@ -21,7 +21,7 @@ namespace driver {
class Driver;
namespace toolchains {
- class Darwin_X86;
+ class Darwin;
}
namespace tools {
@@ -33,6 +33,9 @@ namespace tools {
const InputInfo &Output,
const InputInfoList &Inputs) const;
+ void AddARMTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const;
+ void AddX86TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const;
+
public:
Clang(const ToolChain &TC) : Tool("clang", TC) {}
@@ -42,9 +45,9 @@ namespace tools {
virtual void ConstructJob(Compilation &C, const JobAction &JA,
Job &Dest,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &TCArgs,
const char *LinkingOutput) const;
};
@@ -56,9 +59,9 @@ namespace gcc {
virtual void ConstructJob(Compilation &C, const JobAction &JA,
Job &Dest,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &TCArgs,
const char *LinkingOutput) const;
/// RenderExtraToolArgs - Render any arguments necessary to force
@@ -66,7 +69,7 @@ namespace gcc {
virtual void RenderExtraToolArgs(ArgStringList &CmdArgs) const = 0;
};
-
+
class VISIBILITY_HIDDEN Preprocess : public Common {
public:
Preprocess(const ToolChain &TC) : Common("gcc::Preprocess", TC) {}
@@ -124,13 +127,26 @@ namespace gcc {
} // end namespace gcc
namespace darwin {
- class VISIBILITY_HIDDEN CC1 : public Tool {
+ class VISIBILITY_HIDDEN DarwinTool : public Tool {
+ protected:
+ void AddDarwinArch(const ArgList &Args, ArgStringList &CmdArgs) const;
+ void AddDarwinSubArch(const ArgList &Args, ArgStringList &CmdArgs) const;
+
+ const toolchains::Darwin &getDarwinToolChain() const {
+ return reinterpret_cast<const toolchains::Darwin&>(getToolChain());
+ }
+
+ public:
+ DarwinTool(const char *Name, const ToolChain &TC) : Tool(Name, TC) {};
+ };
+
+ class VISIBILITY_HIDDEN CC1 : public DarwinTool {
public:
- static const char *getBaseInputName(const ArgList &Args,
+ static const char *getBaseInputName(const ArgList &Args,
const InputInfoList &Input);
- static const char *getBaseInputStem(const ArgList &Args,
+ static const char *getBaseInputStem(const ArgList &Args,
const InputInfoList &Input);
- static const char *getDependencyFileName(const ArgList &Args,
+ static const char *getDependencyFileName(const ArgList &Args,
const InputInfoList &Inputs);
protected:
@@ -143,13 +159,13 @@ namespace darwin {
void AddCPPOptionsArgs(const ArgList &Args, ArgStringList &CmdArgs,
const InputInfoList &Inputs,
const ArgStringList &OutputArgs) const;
- void AddCPPUniqueOptionsArgs(const ArgList &Args,
+ 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) {}
+ CC1(const char *Name, const ToolChain &TC) : DarwinTool(Name, TC) {}
virtual bool acceptsPipedInput() const { return true; }
virtual bool canPipeOutput() const { return true; }
@@ -162,9 +178,9 @@ namespace darwin {
virtual void ConstructJob(Compilation &C, const JobAction &JA,
Job &Dest,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &TCArgs,
const char *LinkingOutput) const;
};
@@ -174,15 +190,15 @@ namespace darwin {
virtual void ConstructJob(Compilation &C, const JobAction &JA,
Job &Dest,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &TCArgs,
const char *LinkingOutput) const;
};
- class VISIBILITY_HIDDEN Assemble : public Tool {
+ class VISIBILITY_HIDDEN Assemble : public DarwinTool {
public:
- Assemble(const ToolChain &TC) : Tool("darwin::Assemble", TC) {}
+ Assemble(const ToolChain &TC) : DarwinTool("darwin::Assemble", TC) {}
virtual bool acceptsPipedInput() const { return true; }
virtual bool canPipeOutput() const { return false; }
@@ -190,27 +206,17 @@ namespace darwin {
virtual void ConstructJob(Compilation &C, const JobAction &JA,
Job &Dest,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ 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;
+ class VISIBILITY_HIDDEN Link : public DarwinTool {
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) {
- }
+ Link(const ToolChain &TC) : DarwinTool("darwin::Link", TC) {}
virtual bool acceptsPipedInput() const { return false; }
virtual bool canPipeOutput() const { return false; }
@@ -218,15 +224,15 @@ namespace darwin {
virtual void ConstructJob(Compilation &C, const JobAction &JA,
Job &Dest,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &TCArgs,
const char *LinkingOutput) const;
};
- class VISIBILITY_HIDDEN Lipo : public Tool {
+ class VISIBILITY_HIDDEN Lipo : public DarwinTool {
public:
- Lipo(const ToolChain &TC) : Tool("darwin::Lipo", TC) {}
+ Lipo(const ToolChain &TC) : DarwinTool("darwin::Lipo", TC) {}
virtual bool acceptsPipedInput() const { return false; }
virtual bool canPipeOutput() const { return false; }
@@ -234,9 +240,9 @@ namespace darwin {
virtual void ConstructJob(Compilation &C, const JobAction &JA,
Job &Dest,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &TCArgs,
const char *LinkingOutput) const;
};
}
@@ -253,9 +259,9 @@ namespace openbsd {
virtual void ConstructJob(Compilation &C, const JobAction &JA,
Job &Dest,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &TCArgs,
const char *LinkingOutput) const;
};
class VISIBILITY_HIDDEN Link : public Tool {
@@ -268,12 +274,12 @@ namespace openbsd {
virtual void ConstructJob(Compilation &C, const JobAction &JA,
Job &Dest,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &TCArgs,
const char *LinkingOutput) const;
};
-}
+} // end namespace openbsd
/// freebsd -- Directly call GNU Binutils assembler and linker
namespace freebsd {
@@ -287,9 +293,9 @@ namespace freebsd {
virtual void ConstructJob(Compilation &C, const JobAction &JA,
Job &Dest,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &TCArgs,
const char *LinkingOutput) const;
};
class VISIBILITY_HIDDEN Link : public Tool {
@@ -302,12 +308,46 @@ namespace freebsd {
virtual void ConstructJob(Compilation &C, const JobAction &JA,
Job &Dest,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &TCArgs,
const char *LinkingOutput) const;
};
-}
+} // end namespace freebsd
+
+ /// auroraux -- Directly call GNU Binutils assembler and linker
+namespace auroraux {
+ class VISIBILITY_HIDDEN Assemble : public Tool {
+ public:
+ Assemble(const ToolChain &TC) : Tool("auroraux::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("auroraux::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 auroraux
/// dragonfly -- Directly call GNU Binutils assembler and linker
namespace dragonfly {
@@ -321,9 +361,9 @@ namespace dragonfly {
virtual void ConstructJob(Compilation &C, const JobAction &JA,
Job &Dest,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &TCArgs,
const char *LinkingOutput) const;
};
class VISIBILITY_HIDDEN Link : public Tool {
@@ -336,15 +376,15 @@ namespace dragonfly {
virtual void ConstructJob(Compilation &C, const JobAction &JA,
Job &Dest,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &TCArgs,
const char *LinkingOutput) const;
};
-}
+} // end namespace dragonfly
} // end namespace toolchains
} // end namespace driver
} // end namespace clang
-#endif
+#endif // CLANG_LIB_DRIVER_TOOLS_H_
diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp
index e89e973..eee8c19 100644
--- a/lib/Driver/Types.cpp
+++ b/lib/Driver/Types.cpp
@@ -35,38 +35,38 @@ static Info &getInfo(unsigned id) {
return TypeInfos[id - 1];
}
-const char *types::getTypeName(ID Id) {
- return getInfo(Id).Name;
+const char *types::getTypeName(ID Id) {
+ return getInfo(Id).Name;
}
-types::ID types::getPreprocessedType(ID Id) {
- return getInfo(Id).PreprocessedType;
+types::ID types::getPreprocessedType(ID Id) {
+ return getInfo(Id).PreprocessedType;
}
-const char *types::getTypeTempSuffix(ID Id) {
- return getInfo(Id).TempSuffix;
+const char *types::getTypeTempSuffix(ID Id) {
+ return getInfo(Id).TempSuffix;
}
-bool types::onlyAssembleType(ID Id) {
- return strchr(getInfo(Id).Flags, 'a');
+bool types::onlyAssembleType(ID Id) {
+ return strchr(getInfo(Id).Flags, 'a');
}
-bool types::onlyPrecompileType(ID Id) {
- return strchr(getInfo(Id).Flags, 'p');
+bool types::onlyPrecompileType(ID Id) {
+ return strchr(getInfo(Id).Flags, 'p');
}
-bool types::canTypeBeUserSpecified(ID Id) {
- return strchr(getInfo(Id).Flags, 'u');
+bool types::canTypeBeUserSpecified(ID Id) {
+ return strchr(getInfo(Id).Flags, 'u');
}
-bool types::appendSuffixForType(ID Id) {
- return strchr(getInfo(Id).Flags, 'A');
+bool types::appendSuffixForType(ID Id) {
+ return strchr(getInfo(Id).Flags, 'A');
}
-bool types::canLipoType(ID Id) {
+bool types::canLipoType(ID Id) {
return (Id == TY_Nothing ||
Id == TY_Image ||
- Id == TY_Object);
+ Id == TY_Object);
}
bool types::isAcceptedByClang(ID Id) {
@@ -83,6 +83,7 @@ bool types::isAcceptedByClang(ID Id) {
case TY_ObjCHeader: case TY_PP_ObjCHeader:
case TY_CXXHeader: case TY_PP_CXXHeader:
case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader:
+ case TY_AST:
return true;
}
}
@@ -128,6 +129,7 @@ types::ID types::lookupTypeForExtension(const char *Ext) {
case 3:
if (memcmp(Ext, "ads", 3) == 0) return TY_Ada;
if (memcmp(Ext, "adb", 3) == 0) return TY_Ada;
+ if (memcmp(Ext, "ast", 3) == 0) return TY_AST;
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;
@@ -152,7 +154,7 @@ types::ID types::lookupTypeForTypeSpecifier(const char *Name) {
for (unsigned i=0; i<numTypes; ++i) {
types::ID Id = (types::ID) (i + 1);
- if (canTypeBeUserSpecified(Id) &&
+ if (canTypeBeUserSpecified(Id) &&
memcmp(Name, getInfo(Id).Name, N + 1) == 0)
return Id;
}
@@ -162,25 +164,25 @@ types::ID types::lookupTypeForTypeSpecifier(const char *Name) {
// FIXME: Why don't we just put this list in the defs file, eh.
-unsigned types::getNumCompilationPhases(ID Id) {
+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;
@@ -200,6 +202,6 @@ phases::ID types::getCompilationPhase(ID Id, unsigned N) {
return phases::Compile;
if (N == 1)
return phases::Assemble;
-
+
return phases::Link;
}
diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp
index 8f0ad13..8d76680 100644
--- a/lib/Frontend/ASTConsumers.cpp
+++ b/lib/Frontend/ASTConsumers.cpp
@@ -12,7 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/ASTConsumers.h"
-#include "clang/Frontend/DocumentXML.h"
+#include "clang/Frontend/DocumentXML.h"
#include "clang/Frontend/PathDiagnosticClients.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceManager.h"
@@ -20,13 +20,16 @@
#include "clang/AST/AST.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecordLayout.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/CodeGen/ModuleBuilder.h"
#include "llvm/Module.h"
-#include "llvm/Support/Streams.h"
+#include "llvm/Support/Format.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/System/Path.h"
+#include <cstdio>
+
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -36,11 +39,11 @@ namespace {
class ASTPrinter : public ASTConsumer {
llvm::raw_ostream &Out;
bool Dump;
-
+
public:
- ASTPrinter(llvm::raw_ostream* o = NULL, bool Dump = false)
+ 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;
@@ -62,21 +65,19 @@ namespace {
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
+ for (DeclContext::decl_iterator
D = Ctx.getTranslationUnitDecl()->decls_begin(),
DEnd = Ctx.getTranslationUnitDecl()->decls_end();
- D != DEnd;
+ D != DEnd;
++D)
- {
Doc.PrintDecl(*D);
- }
Doc.toParent();
Doc.finalize();
}
@@ -87,9 +88,9 @@ namespace {
ASTConsumer *clang::CreateASTPrinterXML(llvm::raw_ostream* out) {
return new ASTPrinterXML(out ? *out : llvm::outs());
}
-
-ASTConsumer *clang::CreateASTDumper() {
- return new ASTPrinter(0, true);
+
+ASTConsumer *clang::CreateASTDumper() {
+ return new ASTPrinter(0, true);
}
//===----------------------------------------------------------------------===//
@@ -107,7 +108,7 @@ namespace {
for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I)
HandleTopLevelSingleDecl(*I);
}
-
+
void HandleTopLevelSingleDecl(Decl *D);
};
}
@@ -115,22 +116,22 @@ namespace {
void ASTViewer::HandleTopLevelSingleDecl(Decl *D) {
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
FD->print(llvm::errs());
-
- if (FD->getBodyIfAvailable()) {
- llvm::cerr << '\n';
- FD->getBodyIfAvailable()->viewAST();
- llvm::cerr << '\n';
+
+ if (Stmt *Body = FD->getBody()) {
+ llvm::errs() << '\n';
+ Body->viewAST();
+ llvm::errs() << '\n';
}
return;
}
-
+
if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
MD->print(llvm::errs());
-
+
if (MD->getBody()) {
- llvm::cerr << '\n';
+ llvm::errs() << '\n';
MD->getBody()->viewAST();
- llvm::cerr << '\n';
+ llvm::errs() << '\n';
}
}
}
@@ -156,7 +157,7 @@ public:
};
} // end anonymous namespace
-void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
+void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
unsigned Indentation) {
// Print DeclContext name.
switch (DC->getDeclKind()) {
@@ -230,7 +231,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
// Print the parameters.
Out << "(";
bool PrintComma = false;
- for (FunctionDecl::param_const_iterator I = FD->param_begin(),
+ for (FunctionDecl::param_const_iterator I = FD->param_begin(),
E = FD->param_end(); I != E; ++I) {
if (PrintComma)
Out << ", ";
@@ -253,7 +254,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
// Print the parameters.
Out << "(";
bool PrintComma = false;
- for (FunctionDecl::param_const_iterator I = D->param_begin(),
+ for (FunctionDecl::param_const_iterator I = D->param_begin(),
E = D->param_end(); I != E; ++I) {
if (PrintComma)
Out << ", ";
@@ -283,7 +284,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
// Print the parameters.
Out << "(";
bool PrintComma = false;
- for (FunctionDecl::param_const_iterator I = D->param_begin(),
+ for (FunctionDecl::param_const_iterator I = D->param_begin(),
E = D->param_end(); I != E; ++I) {
if (PrintComma)
Out << ", ";
@@ -353,7 +354,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
case Decl::CXXRecord:
case Decl::ObjCMethod:
case Decl::ObjCInterface:
- case Decl::ObjCCategory:
+ case Decl::ObjCCategory:
case Decl::ObjCProtocol:
case Decl::ObjCImplementation:
case Decl::ObjCCategoryImpl:
@@ -415,8 +416,150 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
}
}
}
-ASTConsumer *clang::CreateDeclContextPrinter() {
- return new DeclContextPrinter();
+ASTConsumer *clang::CreateDeclContextPrinter() {
+ return new DeclContextPrinter();
+}
+
+//===----------------------------------------------------------------------===//
+/// RecordLayoutDumper - C++ Record Layout Dumping.
+namespace {
+class RecordLayoutDumper : public ASTConsumer {
+ llvm::raw_ostream& Out;
+
+ void PrintOffset(uint64_t Offset, unsigned IndentLevel) {
+ Out << llvm::format("%4d | ", Offset);
+ for (unsigned I = 0; I < IndentLevel * 2; ++I) Out << ' ';
+ }
+
+ void DumpRecordLayoutOffsets(const CXXRecordDecl *RD, ASTContext &C,
+ uint64_t Offset,
+ unsigned IndentLevel, const char* Description,
+ bool IncludeVirtualBases) {
+ const ASTRecordLayout &Info = C.getASTRecordLayout(RD);
+
+ PrintOffset(Offset, IndentLevel);
+ Out << C.getTypeDeclType((CXXRecordDecl *)RD).getAsString();
+ if (Description)
+ Out << ' ' << Description;
+ if (RD->isEmpty())
+ Out << " (empty)";
+ Out << '\n';
+
+ IndentLevel++;
+
+ const CXXRecordDecl *PrimaryBase = Info.getPrimaryBase();
+
+ // Vtable pointer.
+ if (RD->isDynamicClass() && !PrimaryBase) {
+ PrintOffset(Offset, IndentLevel);
+ Out << '(' << RD->getNameAsString() << " vtable pointer)\n";
+ }
+ // Dump (non-virtual) bases
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ if (I->isVirtual())
+ continue;
+
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ uint64_t BaseOffset = Offset + Info.getBaseClassOffset(Base) / 8;
+
+ DumpRecordLayoutOffsets(Base, C, BaseOffset, IndentLevel,
+ Base == PrimaryBase ? "(primary base)" : "(base)",
+ /*IncludeVirtualBases=*/false);
+ }
+
+ // Dump fields.
+ uint64_t FieldNo = 0;
+ for (CXXRecordDecl::field_iterator I = RD->field_begin(),
+ E = RD->field_end(); I != E; ++I, ++FieldNo) {
+ const FieldDecl *Field = *I;
+ uint64_t FieldOffset = Offset + Info.getFieldOffset(FieldNo) / 8;
+
+ if (const RecordType *RT = Field->getType()->getAs<RecordType>()) {
+ if (const CXXRecordDecl *D = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
+ DumpRecordLayoutOffsets(D, C, FieldOffset, IndentLevel,
+ Field->getNameAsCString(),
+ /*IncludeVirtualBases=*/true);
+ continue;
+ }
+ }
+
+ PrintOffset(FieldOffset, IndentLevel);
+ Out << Field->getType().getAsString() << ' ';
+ Out << Field->getNameAsString() << '\n';
+ }
+
+ if (!IncludeVirtualBases)
+ return;
+
+ // Dump virtual bases.
+ for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
+ E = RD->vbases_end(); I != E; ++I) {
+ assert(I->isVirtual() && "Found non-virtual class!");
+ const CXXRecordDecl *VBase =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ uint64_t VBaseOffset = Offset + Info.getVBaseClassOffset(VBase) / 8;
+ DumpRecordLayoutOffsets(VBase, C, VBaseOffset, IndentLevel,
+ VBase == PrimaryBase ?
+ "(primary virtual base)" : "(virtual base)",
+ /*IncludeVirtualBases=*/false);
+ }
+ }
+
+ // FIXME: Maybe this could be useful in ASTContext.cpp.
+ void DumpRecordLayout(const CXXRecordDecl *RD, ASTContext &C) {
+ const ASTRecordLayout &Info = C.getASTRecordLayout(RD);
+
+ DumpRecordLayoutOffsets(RD, C, 0, 0, 0,
+ /*IncludeVirtualBases=*/true);
+ Out << " sizeof=" << Info.getSize() / 8;
+ Out << ", dsize=" << Info.getDataSize() / 8;
+ Out << ", align=" << Info.getAlignment() / 8 << '\n';
+ Out << " nvsize=" << Info.getNonVirtualSize() / 8;
+ Out << ", nvalign=" << Info.getNonVirtualAlign() / 8 << '\n';
+ Out << '\n';
+ }
+
+public:
+ RecordLayoutDumper() : Out(llvm::errs()) {}
+
+ void HandleTranslationUnit(ASTContext &C) {
+ for (ASTContext::type_iterator I = C.types_begin(), E = C.types_end();
+ I != E; ++I) {
+ const RecordType *RT = dyn_cast<RecordType>(*I);
+ if (!RT)
+ continue;
+
+ const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
+ if (!RD)
+ continue;
+
+ if (RD->isImplicit())
+ continue;
+
+ if (RD->isDependentType())
+ continue;
+
+ if (RD->isInvalidDecl())
+ continue;
+
+ if (!RD->getDefinition(C))
+ continue;
+
+ // FIXME: Do we really need to hard code this?
+ if (RD->getQualifiedNameAsString() == "__va_list_tag")
+ continue;
+
+ DumpRecordLayout(RD, C);
+ }
+ }
+};
+} // end anonymous namespace
+ASTConsumer *clang::CreateRecordLayoutDumper() {
+ return new RecordLayoutDumper();
}
//===----------------------------------------------------------------------===//
@@ -427,7 +570,7 @@ 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)) {
@@ -435,12 +578,12 @@ public:
// FIXME: This lookup needs to be generalized to handle namespaces and
// (when we support them) templates.
if (D->getNameAsString() == clsname) {
- D->viewInheritance(C);
+ D->viewInheritance(C);
}
}
}
}
-};
+};
}
ASTConsumer *clang::CreateInheritanceViewer(const std::string& clsname) {
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 8143263..d3475b5 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -13,7 +13,6 @@
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/PCHReader.h"
-#include "clang/Frontend/TextDiagnosticBuffer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/StmtVisitor.h"
@@ -25,7 +24,7 @@
using namespace clang;
-ASTUnit::ASTUnit() { }
+ASTUnit::ASTUnit(Diagnostic &_Diags) : Diags(_Diags) { }
ASTUnit::~ASTUnit() { }
namespace {
@@ -38,38 +37,38 @@ class VISIBILITY_HIDDEN PCHInfoCollector : public PCHReaderListener {
std::string &TargetTriple;
std::string &Predefines;
unsigned &Counter;
-
+
unsigned NumHeaderInfos;
-
+
public:
PCHInfoCollector(LangOptions &LangOpt, HeaderSearch &HSI,
std::string &TargetTriple, std::string &Predefines,
unsigned &Counter)
: LangOpt(LangOpt), HSI(HSI), TargetTriple(TargetTriple),
Predefines(Predefines), Counter(Counter), NumHeaderInfos(0) {}
-
+
virtual bool ReadLanguageOptions(const LangOptions &LangOpts) {
LangOpt = LangOpts;
return false;
}
-
+
virtual bool ReadTargetTriple(const std::string &Triple) {
TargetTriple = Triple;
return false;
}
-
- virtual bool ReadPredefinesBuffer(const char *PCHPredef,
+
+ virtual bool ReadPredefinesBuffer(const char *PCHPredef,
unsigned PCHPredefLen,
FileID PCHBufferID,
std::string &SuggestedPredefines) {
Predefines = PCHPredef;
return false;
}
-
+
virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI) {
HSI.setHeaderFileInfoForUID(HFI, NumHeaderInfos++);
}
-
+
virtual void ReadCounter(unsigned Value) {
Counter = Value;
}
@@ -77,24 +76,24 @@ public:
} // anonymous namespace
+const std::string &ASTUnit::getOriginalSourceFileName() {
+ return dyn_cast<PCHReader>(Ctx->getExternalSource())->getOriginalSourceFile();
+}
+
+FileManager &ASTUnit::getFileManager() {
+ return HeaderInfo->getFileMgr();
+}
ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
+ Diagnostic &Diags,
FileManager &FileMgr,
std::string *ErrMsg) {
-
- llvm::OwningPtr<ASTUnit> AST(new ASTUnit());
-
- AST->DiagClient.reset(new TextDiagnosticBuffer());
- AST->Diags.reset(new Diagnostic(AST->DiagClient.get()));
+ llvm::OwningPtr<ASTUnit> AST(new ASTUnit(Diags));
AST->HeaderInfo.reset(new HeaderSearch(FileMgr));
- AST->SourceMgr.reset(new SourceManager());
-
- Diagnostic &Diags = *AST->Diags.get();
- SourceManager &SourceMgr = *AST->SourceMgr.get();
// Gather Info for preprocessor construction later on.
-
+
LangOptions LangInfo;
HeaderSearch &HeaderInfo = *AST->HeaderInfo.get();
std::string TargetTriple;
@@ -104,37 +103,37 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
llvm::OwningPtr<PCHReader> Reader;
llvm::OwningPtr<ExternalASTSource> Source;
- Reader.reset(new PCHReader(SourceMgr, FileMgr, Diags));
+ Reader.reset(new PCHReader(AST->getSourceManager(), FileMgr, AST->Diags));
Reader->setListener(new PCHInfoCollector(LangInfo, HeaderInfo, TargetTriple,
Predefines, Counter));
switch (Reader->ReadPCH(Filename)) {
case PCHReader::Success:
break;
-
+
case PCHReader::Failure:
case PCHReader::IgnorePCH:
if (ErrMsg)
*ErrMsg = "Could not load PCH file";
return NULL;
}
-
+
// PCH loaded successfully. Now create the preprocessor.
-
+
// Get information about the target being compiled for.
AST->Target.reset(TargetInfo::CreateTargetInfo(TargetTriple));
- AST->PP.reset(new Preprocessor(Diags, LangInfo, *AST->Target.get(),
- SourceMgr, HeaderInfo));
+ AST->PP.reset(new Preprocessor(AST->Diags, LangInfo, *AST->Target.get(),
+ AST->getSourceManager(), HeaderInfo));
Preprocessor &PP = *AST->PP.get();
- PP.setPredefines(Predefines);
+ PP.setPredefines(Reader->getSuggestedPredefines());
PP.setCounterValue(Counter);
Reader->setPreprocessor(PP);
-
+
// Create and initialize the ASTContext.
AST->Ctx.reset(new ASTContext(LangInfo,
- SourceMgr,
+ AST->getSourceManager(),
*AST->Target.get(),
PP.getIdentifierTable(),
PP.getSelectorTable(),
@@ -142,14 +141,14 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
/* FreeMemory = */ true,
/* size_reserve = */0));
ASTContext &Context = *AST->Ctx.get();
-
+
Reader->InitializeContext(Context);
-
+
// 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.
Source.reset(Reader.take());
Context.setExternalSource(Source);
- return AST.take();
+ return AST.take();
}
diff --git a/lib/Frontend/AnalysisConsumer.cpp b/lib/Frontend/AnalysisConsumer.cpp
index 06af2d9..2765994 100644
--- a/lib/Frontend/AnalysisConsumer.cpp
+++ b/lib/Frontend/AnalysisConsumer.cpp
@@ -17,39 +17,51 @@
#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/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/AnalysisManager.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/Compiler.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/System/Path.h"
#include "llvm/System/Program.h"
+#include "llvm/ADT/OwningPtr.h"
using namespace clang;
-static ExplodedNodeImpl::Auditor* CreateUbiViz();
+static ExplodedNode::Auditor* CreateUbiViz();
//===----------------------------------------------------------------------===//
// Basic type definitions.
//===----------------------------------------------------------------------===//
-namespace {
- class AnalysisManager;
- typedef void (*CodeAction)(AnalysisManager& Mgr);
+namespace {
+ typedef void (*CodeAction)(AnalysisManager& Mgr, Decl *D);
} // end anonymous namespace
//===----------------------------------------------------------------------===//
+// Special PathDiagnosticClients.
+//===----------------------------------------------------------------------===//
+
+static PathDiagnosticClient*
+CreatePlistHTMLDiagnosticClient(const std::string& prefix, Preprocessor* PP,
+ PreprocessorFactory* PPF) {
+ llvm::sys::Path F(prefix);
+ PathDiagnosticClientFactory *PF =
+ CreateHTMLDiagnosticClientFactory(F.getDirname(), PP, PPF);
+ return CreatePlistDiagnosticClient(prefix, PP, PPF, PF);
+}
+
+//===----------------------------------------------------------------------===//
// AnalysisConsumer declaration.
//===----------------------------------------------------------------------===//
@@ -61,16 +73,24 @@ namespace {
Actions ObjCMethodActions;
Actions ObjCImplementationActions;
Actions TranslationUnitActions;
-
+
public:
- const LangOptions& LOpts;
+ const LangOptions& LOpts;
Diagnostic &Diags;
ASTContext* Ctx;
Preprocessor* PP;
PreprocessorFactory* PPF;
const std::string OutDir;
AnalyzerOptions Opts;
- llvm::OwningPtr<PathDiagnosticClient> PD;
+
+
+ // PD is owned by AnalysisManager.
+ PathDiagnosticClient *PD;
+
+ StoreManagerCreator CreateStoreMgr;
+ ConstraintManagerCreator CreateConstraintMgr;
+
+ llvm::OwningPtr<AnalysisManager> Mgr;
AnalysisConsumer(Diagnostic &diags, Preprocessor* pp,
PreprocessorFactory* ppf,
@@ -79,181 +99,30 @@ namespace {
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;
+ OutDir(outdir), Opts(opts), PD(0) {
+ DigestAnalyzerOptions();
}
-
- 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;
+ void DigestAnalyzerOptions() {
+ // Create the PathDiagnosticClient.
+ if (!OutDir.empty()) {
+ switch (Opts.AnalysisDiagOpt) {
+ default:
+#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE) \
+ case PD_##NAME: PD = CREATEFN(OutDir, PP, 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() {
+ // Create the analyzer component creators.
if (ManagerRegistry::StoreMgrCreator != 0) {
CreateStoreMgr = ManagerRegistry::StoreMgrCreator;
}
else {
- switch (C.Opts.AnalysisStoreOpt) {
+ switch (Opts.AnalysisStoreOpt) {
default:
assert(0 && "Unknown store manager.");
-#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATEFN) \
+#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATEFN) \
case NAME##Model: CreateStoreMgr = CREATEFN; break;
#include "clang/Frontend/Analyses.def"
}
@@ -262,7 +131,7 @@ case PD_##NAME: C.PD.reset(CREATEFN(C.OutDir, C.PP, C.PPF)); break;
if (ManagerRegistry::ConstraintMgrCreator != 0)
CreateConstraintMgr = ManagerRegistry::ConstraintMgrCreator;
else {
- switch (C.Opts.AnalysisConstraintsOpt) {
+ switch (Opts.AnalysisConstraintsOpt) {
default:
assert(0 && "Unknown store manager.");
#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN) \
@@ -270,20 +139,44 @@ case PD_##NAME: C.PD.reset(CREATEFN(C.OutDir, C.PP, C.PPF)); 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"
- }
+ 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;
+ Mgr.reset(new AnalysisManager(*Ctx, Diags, LOpts, PD,
+ CreateStoreMgr, CreateConstraintMgr,
+ Opts.AnalyzerDisplayProgress,
+ Opts.VisualizeEGDot, Opts.VisualizeEGUbi,
+ Opts.PurgeDead, Opts.EagerlyAssume,
+ Opts.TrimGraph));
+ }
+
+ 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);
};
+
+
} // end anonymous namespace
namespace llvm {
@@ -291,71 +184,85 @@ namespace llvm {
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) {
+void AnalysisConsumer::HandleTopLevelSingleDecl(Decl *D) {
switch (D->getKind()) {
case Decl::Function: {
FunctionDecl* FD = cast<FunctionDecl>(D);
- if (Opts.AnalyzeSpecificFunction.size() > 0 &&
+ if (Opts.AnalyzeSpecificFunction.size() > 0 &&
Opts.AnalyzeSpecificFunction != FD->getIdentifier()->getName())
break;
-
+
Stmt* Body = FD->getBody();
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) {
+
+ TranslationUnitDecl *TU = C.getTranslationUnitDecl();
+
+ if (!TranslationUnitActions.empty()) {
+ // Find the entry function definition (if any).
+ FunctionDecl *FD = 0;
+
+ if (!Opts.AnalyzeSpecificFunction.empty()) {
+ for (DeclContext::decl_iterator I=TU->decls_begin(), E=TU->decls_end();
+ I != E; ++I) {
+ if (FunctionDecl *fd = dyn_cast<FunctionDecl>(*I))
+ if (fd->isThisDeclarationADefinition() &&
+ fd->getNameAsString() == Opts.AnalyzeSpecificFunction) {
+ FD = fd;
+ break;
+ }
+ }
+ }
- if(!TranslationUnitActions.empty()) {
- AnalysisManager mgr(*this, Opts.AnalyzerDisplayProgress);
for (Actions::iterator I = TranslationUnitActions.begin(),
E = TranslationUnitActions.end(); I != E; ++I)
- (*I)(mgr);
+ (*I)(*Mgr, FD);
}
if (!ObjCImplementationActions.empty()) {
- TranslationUnitDecl *TUD = C.getTranslationUnitDecl();
-
- for (DeclContext::decl_iterator I = TUD->decls_begin(),
- E = TUD->decls_end();
+ for (DeclContext::decl_iterator I = TU->decls_begin(),
+ E = TU->decls_end();
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();
+
+ // Explicitly destroy the PathDiagnosticClient. This will flush its output.
+ // FIXME: This should be replaced with something that doesn't rely on
+ // side-effects in PathDiagnosticClient's destructor.
+ Mgr.reset(NULL);
}
-void AnalysisConsumer::HandleCode(Decl* D, Stmt* Body, Actions& actions) {
-
+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;
@@ -364,154 +271,170 @@ void AnalysisConsumer::HandleCode(Decl* D, Stmt* Body, Actions& actions) {
// otherwise specified.
if (!Opts.AnalyzeAll &&
!Ctx->getSourceManager().isFromMainFile(D->getLocation()))
- return;
+ 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.
+ // Dispatch on the actions.
for (Actions::iterator I = actions.begin(), E = actions.end(); I != E; ++I)
- (*I)(mgr);
+ (*I)(*Mgr, D);
}
//===----------------------------------------------------------------------===//
// Analyses
//===----------------------------------------------------------------------===//
-static void ActionWarnDeadStores(AnalysisManager& mgr) {
- if (LiveVariables* L = mgr.getLiveVariables()) {
+static void ActionWarnDeadStores(AnalysisManager& mgr, Decl *D) {
+ if (LiveVariables *L = mgr.getLiveVariables(D)) {
BugReporter BR(mgr);
- CheckDeadStores(*L, BR);
+ CheckDeadStores(*mgr.getCFG(D), *L, mgr.getParentMap(D), BR);
}
}
-static void ActionWarnUninitVals(AnalysisManager& mgr) {
- if (CFG* c = mgr.getCFG())
- CheckUninitializedValues(*c, mgr.getContext(), mgr.getDiagnostic());
+static void ActionWarnUninitVals(AnalysisManager& mgr, Decl *D) {
+ if (CFG* c = mgr.getCFG(D))
+ CheckUninitializedValues(*c, mgr.getASTContext(), mgr.getDiagnostic());
}
-static void ActionGRExprEngine(AnalysisManager& mgr, GRTransferFuncs* tf,
- bool StandardWarnings = true) {
-
-
+static void ActionGRExprEngine(AnalysisManager& mgr, Decl *D,
+ GRTransferFuncs* tf) {
+
+
llvm::OwningPtr<GRTransferFuncs> TF(tf);
// Display progress.
- mgr.DisplayFunction();
-
- // Construct the analysis engine.
- LiveVariables* L = mgr.getLiveVariables();
- if (!L) return;
+ mgr.DisplayFunction(D);
- GRExprEngine Eng(*mgr.getCFG(), *mgr.getCodeDecl(), mgr.getContext(), *L, mgr,
- mgr.shouldPurgeDead(), mgr.shouldEagerlyAssume(),
- mgr.getStoreManagerCreator(),
- mgr.getConstraintManagerCreator());
+ // Construct the analysis engine. We first query for the LiveVariables
+ // information to see if the CFG is valid.
+ // FIXME: Inter-procedural analysis will need to handle invalid CFGs.
+ if (!mgr.getLiveVariables(D))
+ return;
+
+ GRExprEngine Eng(mgr);
Eng.setTransferFunctions(tf);
-
- if (StandardWarnings) {
- Eng.RegisterInternalChecks();
- RegisterAppleChecks(Eng);
- }
+ Eng.RegisterInternalChecks(); // FIXME: Internal checks should just
+ // automatically register.
+ RegisterAppleChecks(Eng, *D);
+
// Set the graph auditor.
- llvm::OwningPtr<ExplodedNodeImpl::Auditor> Auditor;
+ llvm::OwningPtr<ExplodedNode::Auditor> Auditor;
if (mgr.shouldVisualizeUbigraph()) {
Auditor.reset(CreateUbiViz());
- ExplodedNodeImpl::SetAuditor(Auditor.get());
+ ExplodedNode::SetAuditor(Auditor.get());
}
-
+
// Execute the worklist algorithm.
- Eng.ExecuteWorkList();
-
+ Eng.ExecuteWorkList(mgr.getStackFrame(D));
+
// Release the auditor (if any) so that it doesn't monitor the graph
// created BugReporter.
- ExplodedNodeImpl::SetAuditor(0);
+ ExplodedNode::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(),
+static void ActionCheckerCFRefAux(AnalysisManager& mgr, Decl *D,
+ bool GCEnabled) {
+
+ GRTransferFuncs* TF = MakeCFRefCountTF(mgr.getASTContext(),
GCEnabled,
mgr.getLangOptions());
-
- ActionGRExprEngine(mgr, TF, StandardWarnings);
+
+ ActionGRExprEngine(mgr, D, TF);
}
-static void ActionCheckerCFRef(AnalysisManager& mgr) {
-
+static void ActionCheckerCFRef(AnalysisManager& mgr, Decl *D) {
+
switch (mgr.getLangOptions().getGCMode()) {
default:
assert (false && "Invalid GC mode.");
case LangOptions::NonGC:
- ActionCheckerCFRefAux(mgr, false, true);
+ ActionCheckerCFRefAux(mgr, D, false);
break;
-
+
case LangOptions::GCOnly:
- ActionCheckerCFRefAux(mgr, true, true);
+ ActionCheckerCFRefAux(mgr, D, true);
break;
-
+
case LangOptions::HybridGC:
- ActionCheckerCFRefAux(mgr, false, true);
- ActionCheckerCFRefAux(mgr, true, false);
+ ActionCheckerCFRefAux(mgr, D, false);
+ ActionCheckerCFRefAux(mgr, D, true);
break;
}
}
-static void ActionDisplayLiveVariables(AnalysisManager& mgr) {
- if (LiveVariables* L = mgr.getLiveVariables()) {
- mgr.DisplayFunction();
+static void ActionDisplayLiveVariables(AnalysisManager& mgr, Decl *D) {
+ if (LiveVariables* L = mgr.getLiveVariables(D)) {
+ mgr.DisplayFunction(D);
L->dumpBlockLiveness(mgr.getSourceManager());
}
}
-static void ActionCFGDump(AnalysisManager& mgr) {
- if (CFG* c = mgr.getCFG()) {
- mgr.DisplayFunction();
- LangOptions LO; // FIXME!
- c->dump(LO);
+static void ActionCFGDump(AnalysisManager& mgr, Decl *D) {
+ if (CFG* c = mgr.getCFG(D)) {
+ mgr.DisplayFunction(D);
+ c->dump(mgr.getLangOptions());
}
}
-static void ActionCFGView(AnalysisManager& mgr) {
- if (CFG* c = mgr.getCFG()) {
- mgr.DisplayFunction();
- LangOptions LO; // FIXME!
- c->viewCFG(LO);
+static void ActionCFGView(AnalysisManager& mgr, Decl *D) {
+ if (CFG* c = mgr.getCFG(D)) {
+ mgr.DisplayFunction(D);
+ c->viewCFG(mgr.getLangOptions());
}
}
-static void ActionWarnObjCDealloc(AnalysisManager& mgr) {
+static void ActionSecuritySyntacticChecks(AnalysisManager &mgr, Decl *D) {
+ BugReporter BR(mgr);
+ CheckSecuritySyntaxOnly(D, BR);
+}
+
+static void ActionWarnObjCDealloc(AnalysisManager& mgr, Decl *D) {
if (mgr.getLangOptions().getGCMode() == LangOptions::GCOnly)
return;
-
+
BugReporter BR(mgr);
-
- CheckObjCDealloc(cast<ObjCImplementationDecl>(mgr.getCodeDecl()),
- mgr.getLangOptions(), BR);
+ CheckObjCDealloc(cast<ObjCImplementationDecl>(D), mgr.getLangOptions(), BR);
}
-static void ActionWarnObjCUnusedIvars(AnalysisManager& mgr) {
+static void ActionWarnObjCUnusedIvars(AnalysisManager& mgr, Decl *D) {
BugReporter BR(mgr);
- CheckObjCUnusedIvar(cast<ObjCImplementationDecl>(mgr.getCodeDecl()), BR);
+ CheckObjCUnusedIvar(cast<ObjCImplementationDecl>(D), BR);
}
-static void ActionWarnObjCMethSigs(AnalysisManager& mgr) {
+static void ActionWarnObjCMethSigs(AnalysisManager& mgr, Decl *D) {
BugReporter BR(mgr);
+
+ CheckObjCInstMethSignature(cast<ObjCImplementationDecl>(D), BR);
+}
+
+static void ActionInlineCall(AnalysisManager &mgr, Decl *D) {
+ if (!D)
+ return;
+
+ llvm::OwningPtr<GRTransferFuncs> TF(CreateCallInliner(mgr.getASTContext()));
+
+ // Construct the analysis engine.
+ GRExprEngine Eng(mgr);
+
+ Eng.setTransferFunctions(TF.get());
- CheckObjCInstMethSignature(cast<ObjCImplementationDecl>(mgr.getCodeDecl()),
- BR);
+ Eng.RegisterInternalChecks();
+ RegisterAppleChecks(Eng, *D);
+
+ // Execute the worklist algorithm.
+ Eng.ExecuteWorkList(mgr.getStackFrame(D));
+
+ // Visualize the exploded graph.
+ if (mgr.shouldVisualizeGraphviz())
+ Eng.ViewGraph(mgr.shouldTrimGraph());
}
//===----------------------------------------------------------------------===//
@@ -537,7 +460,7 @@ ASTConsumer* clang::CreateAnalysisConsumer(Diagnostic &diags, Preprocessor* pp,
#include "clang/Frontend/Analyses.def"
default: break;
}
-
+
// Last, disable the effects of '-Werror' when using the AnalysisConsumer.
diags.setWarningsAsErrors(false);
@@ -549,29 +472,29 @@ ASTConsumer* clang::CreateAnalysisConsumer(Diagnostic &diags, Preprocessor* pp,
//===----------------------------------------------------------------------===//
namespace {
-
-class UbigraphViz : public ExplodedNodeImpl::Auditor {
+
+class UbigraphViz : public ExplodedNode::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);
+
+ virtual void AddEdge(ExplodedNode* Src, ExplodedNode* Dst);
};
-
+
} // end anonymous namespace
-static ExplodedNodeImpl::Auditor* CreateUbiViz() {
+static ExplodedNode::Auditor* CreateUbiViz() {
std::string ErrMsg;
-
+
llvm::sys::Path Dir = llvm::sys::Path::GetTemporaryDirectory(&ErrMsg);
if (!ErrMsg.empty())
return 0;
@@ -583,33 +506,32 @@ static ExplodedNodeImpl::Auditor* CreateUbiViz() {
if (!ErrMsg.empty())
return 0;
- llvm::cerr << "Writing '" << Filename << "'.\n";
-
+ llvm::errs() << "Writing '" << Filename.str() << "'.\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));
+ Stream.reset(new llvm::raw_fd_ostream(Filename.c_str(), ErrMsg));
if (!ErrMsg.empty())
return 0;
-
+
return new UbigraphViz(Stream.take(), Dir, Filename);
}
-void UbigraphViz::AddEdge(ExplodedNodeImpl* Src, ExplodedNodeImpl* Dst) {
-
+void UbigraphViz::AddEdge(ExplodedNode* Src, ExplodedNode* 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;
@@ -625,7 +547,7 @@ void UbigraphViz::AddEdge(ExplodedNodeImpl* Src, ExplodedNodeImpl* Dst) {
}
// Add the edge.
- *Out << "('edge', " << SrcID << ", " << DstID
+ *Out << "('edge', " << SrcID << ", " << DstID
<< ", ('arrow','true'), ('oriented', 'true'))\n";
}
@@ -640,18 +562,18 @@ UbigraphViz::UbigraphViz(llvm::raw_ostream* out, llvm::sys::Path& dir,
UbigraphViz::~UbigraphViz() {
Out.reset(0);
- llvm::cerr << "Running 'ubiviz' program... ";
+ llvm::errs() << "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";
+ llvm::errs() << "Error viewing graph: " << ErrMsg << "\n";
}
-
+
// Delete the directory.
- Dir.eraseFromDisk(true);
+ Dir.eraseFromDisk(true);
}
diff --git a/lib/Frontend/Backend.cpp b/lib/Frontend/Backend.cpp
index 1c536b0..13aecf1 100644
--- a/lib/Frontend/Backend.cpp
+++ b/lib/Frontend/Backend.cpp
@@ -24,8 +24,8 @@
#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/FormattedStream.h"
#include "llvm/Support/StandardPasses.h"
#include "llvm/Support/Timer.h"
#include "llvm/System/Path.h"
@@ -33,7 +33,7 @@
#include "llvm/Target/SubtargetFeature.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetMachine.h"
-#include "llvm/Target/TargetMachineRegistry.h"
+#include "llvm/Target/TargetRegistry.h"
using namespace clang;
using namespace llvm;
@@ -42,13 +42,14 @@ namespace {
BackendAction Action;
CompileOptions CompileOpts;
llvm::raw_ostream *AsmOutStream;
+ llvm::formatted_raw_ostream FormattedOutStream;
ASTContext *Context;
Timer LLVMIRGeneration;
Timer CodeGenerationTime;
-
+
llvm::OwningPtr<CodeGenerator> Gen;
-
+
llvm::Module *TheModule;
llvm::TargetData *TheTargetData;
@@ -71,21 +72,25 @@ namespace {
bool AddEmitPasses(std::string &Error);
void EmitAssembly();
-
- public:
- BackendConsumer(BackendAction action, Diagnostic &Diags,
+
+ public:
+ BackendConsumer(BackendAction action, Diagnostic &Diags,
const LangOptions &langopts, const CompileOptions &compopts,
const std::string &infile, llvm::raw_ostream* OS,
LLVMContext& C) :
- Action(action),
+ Action(action),
CompileOpts(compopts),
- AsmOutStream(OS),
+ AsmOutStream(OS),
LLVMIRGeneration("LLVM IR Generation Time"),
CodeGenerationTime("Code Generation Time"),
Gen(CreateLLVMCodeGen(Diags, infile, compopts, C)),
TheModule(0), TheTargetData(0), ModuleProvider(0),
CodeGenPasses(0), PerModulePasses(0), PerFunctionPasses(0) {
-
+
+ if (AsmOutStream)
+ FormattedOutStream.setStream(*AsmOutStream,
+ formatted_raw_ostream::PRESERVE_STREAM);
+
// Enable -time-passes if -ftime-report is enabled.
llvm::TimePassesIsEnabled = CompileOpts.TimePasses;
}
@@ -100,25 +105,25 @@ namespace {
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();
@@ -127,7 +132,7 @@ namespace {
if (CompileOpts.TimePasses)
LLVMIRGeneration.stopTimer();
}
-
+
virtual void HandleTranslationUnit(ASTContext &C) {
{
PrettyStackTraceString CrashInfo("Per-file LLVM IR generation");
@@ -142,12 +147,12 @@ namespace {
// EmitAssembly times and registers crash info itself.
EmitAssembly();
-
+
// Force a flush here in case we never get released.
if (AsmOutStream)
- AsmOutStream->flush();
+ FormattedOutStream.flush();
}
-
+
virtual void HandleTagDeclDefinition(TagDecl *D) {
PrettyStackTraceDecl CrashInfo(D, SourceLocation(),
Context->getSourceManager(),
@@ -158,7 +163,7 @@ namespace {
virtual void CompleteTentativeDefinition(VarDecl *D) {
Gen->CompleteTentativeDefinition(D);
}
- };
+ };
}
FunctionPassManager *BackendConsumer::getCodeGenPasses() const {
@@ -193,16 +198,16 @@ bool BackendConsumer::AddEmitPasses(std::string &Error) {
return true;
if (Action == Backend_EmitBC) {
- getPerModulePasses()->add(createBitcodeWriterPass(*AsmOutStream));
+ getPerModulePasses()->add(createBitcodeWriterPass(FormattedOutStream));
} else if (Action == Backend_EmitLL) {
- getPerModulePasses()->add(createPrintModulePass(AsmOutStream));
+ getPerModulePasses()->add(createPrintModulePass(&FormattedOutStream));
} else {
bool Fast = CompileOpts.OptimizationLevel == 0;
// Create the TargetMachine for generating code.
- const TargetMachineRegistry::entry *TME =
- TargetMachineRegistry::getClosestStaticTargetForModule(*TheModule, Error);
- if (!TME) {
+ std::string Triple = TheModule->getTargetTriple();
+ const llvm::Target *TheTarget = TargetRegistry::lookupTarget(Triple, Error);
+ if (!TheTarget) {
Error = std::string("Unable to get target machine: ") + Error;
return false;
}
@@ -211,18 +216,18 @@ bool BackendConsumer::AddEmitPasses(std::string &Error) {
if (CompileOpts.CPU.size() || CompileOpts.Features.size()) {
SubtargetFeatures Features;
Features.setCPU(CompileOpts.CPU);
- for (std::vector<std::string>::iterator
+ 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);
-
+ TargetMachine *TM = TheTarget->createTargetMachine(Triple, FeaturesStr);
+
// Set register scheduler & allocation policy.
RegisterScheduler::setDefault(createDefaultScheduler);
- RegisterRegAlloc::setDefault(Fast ? createLocalRegisterAllocator :
- createLinearScanRegisterAllocator);
+ RegisterRegAlloc::setDefault(Fast ? createLocalRegisterAllocator :
+ createLinearScanRegisterAllocator);
// From llvm-gcc:
// If there are passes we have to run on the entire module, we do codegen
@@ -240,7 +245,7 @@ bool BackendConsumer::AddEmitPasses(std::string &Error) {
// Normal mode, emit a .s file by running the code generator.
// Note, this also adds codegenerator level optimization passes.
- switch (TM->addPassesToEmitFile(*PM, *AsmOutStream,
+ switch (TM->addPassesToEmitFile(*PM, FormattedOutStream,
TargetMachine::AssemblyFile, OptLevel)) {
default:
case FileModel::Error:
@@ -249,7 +254,7 @@ bool BackendConsumer::AddEmitPasses(std::string &Error) {
case FileModel::AsmFile:
break;
}
-
+
if (TM->addPassesToEmitFileFinish(*CodeGenPasses, (MachineCodeEmitter *)0,
OptLevel)) {
Error = "Unable to interface with target machine!\n";
@@ -287,8 +292,8 @@ void BackendConsumer::CreatePasses() {
// For now we always create per module passes.
PassManager *PM = getPerModulePasses();
- llvm::createStandardModulePasses(PM, CompileOpts.OptimizationLevel,
- CompileOpts.OptimizeSize,
+ llvm::createStandardModulePasses(PM, CompileOpts.OptimizationLevel,
+ CompileOpts.OptimizeSize,
CompileOpts.UnitAtATime,
CompileOpts.UnrollLoops,
CompileOpts.SimplifyLibCalls,
@@ -297,12 +302,12 @@ void BackendConsumer::CreatePasses() {
}
/// EmitAssembly - Handle interaction with LLVM backend to generate
-/// actual machine code.
+/// 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
@@ -323,7 +328,7 @@ void BackendConsumer::EmitAssembly() {
std::string Error;
if (!AddEmitPasses(Error)) {
// FIXME: Don't fail this way.
- llvm::cerr << "ERROR: " << Error << "\n";
+ llvm::errs() << "ERROR: " << Error << "\n";
::exit(1);
}
@@ -332,19 +337,19 @@ void BackendConsumer::EmitAssembly() {
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();
diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt
index f8d09db..e3ec786 100644
--- a/lib/Frontend/CMakeLists.txt
+++ b/lib/Frontend/CMakeLists.txt
@@ -1,9 +1,9 @@
set(LLVM_NO_RTTI 1)
add_clang_library(clangFrontend
- AnalysisConsumer.cpp
ASTConsumers.cpp
ASTUnit.cpp
+ AnalysisConsumer.cpp
Backend.cpp
CacheTokens.cpp
DeclXML.cpp
@@ -26,7 +26,6 @@ add_clang_library(clangFrontend
PlistDiagnostics.cpp
PrintParserCallbacks.cpp
PrintPreprocessedOutput.cpp
- ResolveLocation.cpp
RewriteBlocks.cpp
RewriteMacros.cpp
RewriteObjC.cpp
@@ -38,6 +37,14 @@ add_clang_library(clangFrontend
Warnings.cpp
)
+IF(MSVC)
+ get_target_property(NON_ANSI_COMPILE_FLAGS clangFrontend COMPILE_FLAGS)
+ string(REPLACE /Za
+ "" NON_ANSI_COMPILE_FLAGS
+ ${NON_ANSI_COMPILE_FLAGS})
+ set_target_properties(clangFrontend PROPERTIES COMPILE_FLAGS ${NON_ANSI_COMPILE_FLAGS})
+ENDIF(MSVC)
+
add_dependencies(clangFrontend
ClangDiagnosticFrontend
ClangDiagnosticLex
diff --git a/lib/Frontend/CacheTokens.cpp b/lib/Frontend/CacheTokens.cpp
index 0065828..e7fc566 100644
--- a/lib/Frontend/CacheTokens.cpp
+++ b/lib/Frontend/CacheTokens.cpp
@@ -20,12 +20,11 @@
#include "clang/Basic/OnDiskHashTable.h"
#include "clang/Lex/Lexer.h"
#include "clang/Lex/Preprocessor.h"
-#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/Compiler.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"
+#include "llvm/ADT/StringMap.h"
// FIXME: put this somewhere else?
#ifndef S_ISDIR
@@ -41,19 +40,19 @@ using namespace clang::io;
namespace {
class VISIBILITY_HIDDEN PTHEntry {
- Offset TokenData, PPCondData;
+ Offset TokenData, PPCondData;
-public:
+public:
PTHEntry() {}
PTHEntry(Offset td, Offset ppcd)
: TokenData(td), PPCondData(ppcd) {}
-
- Offset getTokenOffset() const { return TokenData; }
+
+ 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;
@@ -67,15 +66,15 @@ public:
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:
@@ -99,45 +98,45 @@ public:
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>
+
+ 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,
+
+ static void EmitData(llvm::raw_ostream& Out, PTHEntryKeyVariant V,
const PTHEntry& E, unsigned) {
@@ -147,12 +146,12 @@ public:
::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;
@@ -181,16 +180,16 @@ class VISIBILITY_HIDDEN PTHWriter {
//// 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);
@@ -203,13 +202,13 @@ class VISIBILITY_HIDDEN PTHWriter {
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); }
@@ -218,23 +217,23 @@ class VISIBILITY_HIDDEN PTHWriter {
Offset EmitCachedSpellings();
public:
- PTHWriter(llvm::raw_fd_ostream& out, Preprocessor& pp)
+ 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) {
+
+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;
}
@@ -243,7 +242,7 @@ 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 {
@@ -254,18 +253,18 @@ void PTHWriter::EmitToken(const Token& T) {
// 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()));
@@ -276,14 +275,14 @@ PTHEntry PTHWriter::LexTokens(Lexer& L) {
// 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:
@@ -301,7 +300,7 @@ PTHEntry PTHWriter::LexTokens(Lexer& L) {
EmitToken(Tmp);
ParsingPreprocessorDirective = false;
}
-
+
if (Tok.is(tok::identifier)) {
Tok.setIdentifierInfo(PP.LookUpIdentifierInfo(Tok));
EmitToken(Tok);
@@ -321,39 +320,39 @@ PTHEntry PTHWriter::LexTokens(Lexer& L) {
// 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: {
+ 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.LexIncludeFilename(Tok);
L.setParsingPreprocessorDirective(false);
assert(!Tok.isAtStartOfLine());
if (Tok.is(tok::identifier))
Tok.setIdentifierInfo(PP.LookUpIdentifierInfo(Tok));
-
+
break;
}
case tok::pp_if:
@@ -375,11 +374,11 @@ PTHEntry PTHWriter::LexTokens(Lexer& L) {
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.
+ 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
@@ -387,7 +386,7 @@ PTHEntry PTHWriter::LexTokens(Lexer& L) {
while (Tok.isNot(tok::eof) && !Tok.isAtStartOfLine());
// We have the next token in hand.
// Don't immediately lex the next one.
- goto NextToken;
+ goto NextToken;
}
case tok::pp_elif:
case tok::pp_else: {
@@ -408,7 +407,7 @@ PTHEntry PTHWriter::LexTokens(Lexer& L) {
}
}
}
-
+
EmitToken(Tok);
}
while (Tok.isNot(tok::eof));
@@ -436,11 +435,11 @@ PTHEntry PTHWriter::LexTokens(Lexer& L) {
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;
}
@@ -448,12 +447,12 @@ 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());
@@ -463,17 +462,17 @@ void PTHWriter::GeneratePTH(const std::string *MainFile) {
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())
@@ -489,13 +488,13 @@ void PTHWriter::GeneratePTH(const std::string *MainFile) {
// 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();
-
+ Offset FileTableOff = EmitFileTable();
+
// Finally, write the prologue.
Out.seek(PrologueOffset);
Emit32(IdTableOff.first);
@@ -515,20 +514,20 @@ class StatListener : public StatSysCallCache {
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;
}
};
@@ -541,27 +540,27 @@ void clang::CacheTokens(Preprocessor &PP, llvm::raw_fd_ostream* OS) {
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();
+ P.appendComponent(MainFilePath.str());
+ MainFileName = P.str();
} else {
- MainFileName = MainFilePath.toString();
+ MainFileName = MainFilePath.str();
}
// 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);
@@ -580,32 +579,32 @@ 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) {
+
+ 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
@@ -624,7 +623,7 @@ std::pair<Offset,Offset> PTHWriter::EmitIdentifierTable() {
// 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
@@ -632,27 +631,27 @@ std::pair<Offset,Offset> PTHWriter::EmitIdentifierTable() {
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.
+
+ // 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/DeclXML.cpp b/lib/Frontend/DeclXML.cpp
index 68f931f..b981fc4 100644
--- a/lib/Frontend/DeclXML.cpp
+++ b/lib/Frontend/DeclXML.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This file implements the XML document class, which provides the means to
+// 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.
//
//===----------------------------------------------------------------------===//
@@ -18,22 +18,18 @@
namespace clang {
-//---------------------------------------------------------
-class DocumentXML::DeclPrinter : public DeclVisitor<DocumentXML::DeclPrinter>
-{
+//---------------------------------------------------------
+class DocumentXML::DeclPrinter : public DeclVisitor<DocumentXML::DeclPrinter> {
DocumentXML& Doc;
- void addSubNodes(FunctionDecl* FD)
- {
- for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i)
- {
+ void addSubNodes(FunctionDecl* FD) {
+ for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i) {
Visit(FD->getParamDecl(i));
Doc.toParent();
}
}
- void addSubNodes(RecordDecl* RD)
- {
+ void addSubNodes(RecordDecl* RD) {
for (RecordDecl::field_iterator i = RD->field_begin(),
e = RD->field_end(); i != e; ++i) {
Visit(*i);
@@ -41,8 +37,7 @@ class DocumentXML::DeclPrinter : public DeclVisitor<DocumentXML::DeclPrinter>
}
}
- void addSubNodes(EnumDecl* ED)
- {
+ void addSubNodes(EnumDecl* ED) {
for (EnumDecl::enumerator_iterator i = ED->enumerator_begin(),
e = ED->enumerator_end(); i != e; ++i) {
Visit(*i);
@@ -50,54 +45,37 @@ class DocumentXML::DeclPrinter : public DeclVisitor<DocumentXML::DeclPrinter>
}
}
- void addSubNodes(EnumConstantDecl* ECD)
- {
- if (ECD->getInitExpr())
- {
+ void addSubNodes(EnumConstantDecl* ECD) {
+ if (ECD->getInitExpr())
Doc.PrintStmt(ECD->getInitExpr());
- }
}
- void addSubNodes(FieldDecl* FdD)
- {
+ void addSubNodes(FieldDecl* FdD) {
if (FdD->isBitField())
- {
Doc.PrintStmt(FdD->getBitWidth());
- }
}
- void addSubNodes(VarDecl* V)
- {
- if (V->getInit())
- {
+ void addSubNodes(VarDecl* V) {
+ if (V->getInit())
Doc.PrintStmt(V->getInit());
- }
}
- void addSubNodes(ParmVarDecl* argDecl)
- {
+ void addSubNodes(ParmVarDecl* argDecl) {
if (argDecl->getDefaultArg())
- {
Doc.PrintStmt(argDecl->getDefaultArg());
- }
}
- void addSpecialAttribute(const char* pName, EnumDecl* ED)
- {
+ void addSpecialAttribute(const char* pName, EnumDecl* ED) {
const QualType& enumType = ED->getIntegerType();
if (!enumType.isNull())
- {
Doc.addAttribute(pName, enumType);
- }
}
- void addIdAttribute(LinkageSpecDecl* ED)
- {
+ void addIdAttribute(LinkageSpecDecl* ED) {
Doc.addAttribute("id", ED);
}
- void addIdAttribute(NamedDecl* ND)
- {
+ void addIdAttribute(NamedDecl* ND) {
Doc.addAttribute("id", ND);
}
@@ -107,11 +85,11 @@ public:
#define NODE_XML( CLASS, NAME ) \
void Visit##CLASS(CLASS* T) \
{ \
- Doc.addSubNode(NAME);
+ Doc.addSubNode(NAME);
#define ID_ATTRIBUTE_XML addIdAttribute(T);
-#define ATTRIBUTE_XML( FN, NAME ) Doc.addAttribute(NAME, T->FN);
-#define ATTRIBUTE_OPT_XML( FN, NAME ) Doc.addAttributeOptional(NAME, T->FN);
+#define ATTRIBUTE_XML( FN, NAME ) Doc.addAttribute(NAME, T->FN);
+#define ATTRIBUTE_OPT_XML( FN, NAME ) Doc.addAttributeOptional(NAME, T->FN);
#define ATTRIBUTE_FILE_LOCATION_XML Doc.addLocation(T->getLocation());
#define ATTRIBUTE_SPECIAL_XML( FN, NAME ) addSpecialAttribute(NAME, T);
@@ -120,14 +98,14 @@ public:
const char* pAttributeName = NAME; \
const bool optional = false; \
switch (T->FN) { \
- default: assert(0 && "unknown enum value");
+ default: assert(0 && "unknown enum value");
#define ATTRIBUTE_ENUM_OPT_XML( FN, NAME ) \
{ \
const char* pAttributeName = NAME; \
const bool optional = true; \
switch (T->FN) { \
- default: assert(0 && "unknown enum value");
+ default: assert(0 && "unknown enum value");
#define ENUM_XML( VALUE, NAME ) case VALUE: if ((!optional) || NAME[0]) Doc.addAttribute(pAttributeName, NAME); break;
#define END_ENUM_XML } }
@@ -141,12 +119,10 @@ public:
};
-//---------------------------------------------------------
-void DocumentXML::writeDeclToXML(Decl *D)
-{
+//---------------------------------------------------------
+void DocumentXML::writeDeclToXML(Decl *D) {
DeclPrinter(*this).Visit(D);
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
- {
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
if (Stmt *Body = FD->getBody()) {
addSubNode("Body");
PrintStmt(Body);
@@ -156,6 +132,6 @@ void DocumentXML::writeDeclToXML(Decl *D)
toParent();
}
-//---------------------------------------------------------
+//---------------------------------------------------------
} // NS clang
diff --git a/lib/Frontend/DependencyFile.cpp b/lib/Frontend/DependencyFile.cpp
index c8a654c..81d1179 100644
--- a/lib/Frontend/DependencyFile.cpp
+++ b/lib/Frontend/DependencyFile.cpp
@@ -40,8 +40,8 @@ private:
void OutputDependencyFile();
public:
- DependencyFileCallback(const Preprocessor *_PP,
- llvm::raw_ostream *_OS,
+ DependencyFileCallback(const Preprocessor *_PP,
+ llvm::raw_ostream *_OS,
const std::vector<std::string> &_Targets,
bool _IncludeSystemHeaders,
bool _PhonyTarget)
@@ -67,8 +67,8 @@ void clang::AttachDependencyFileGen(Preprocessor *PP, llvm::raw_ostream *OS,
bool PhonyTarget) {
assert(!Targets.empty() && "Target required for dependency generation");
- DependencyFileCallback *PPDep =
- new DependencyFileCallback(PP, OS, Targets, IncludeSystemHeaders,
+ DependencyFileCallback *PPDep =
+ new DependencyFileCallback(PP, OS, Targets, IncludeSystemHeaders,
PhonyTarget);
PP->setPPCallbacks(PPDep);
}
@@ -91,16 +91,16 @@ void DependencyFileCallback::FileChanged(SourceLocation Loc,
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;
@@ -138,7 +138,7 @@ void DependencyFileCallback::OutputDependencyFile() {
*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(),
diff --git a/lib/Frontend/DiagChecker.cpp b/lib/Frontend/DiagChecker.cpp
index c0f5d14..26bb6cc 100644
--- a/lib/Frontend/DiagChecker.cpp
+++ b/lib/Frontend/DiagChecker.cpp
@@ -55,33 +55,33 @@ static void EmitError(Preprocessor &PP, SourceLocation Pos, const char *String){
/// 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;
@@ -94,12 +94,12 @@ static void FindDiagnostics(const char *CommentStart, unsigned CommentLen,
}
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] != '{') {
@@ -119,7 +119,7 @@ static void FindDiagnostics(const char *CommentStart, unsigned CommentLen,
EmitError(PP, Pos, "cannot find end ('}}') of expected string");
return;
}
-
+
if (ExpectedEnd[1] == '}')
break;
@@ -147,10 +147,10 @@ static void FindExpectedDiags(Preprocessor &PP,
// 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);
@@ -159,11 +159,11 @@ static void FindExpectedDiags(Preprocessor &PP,
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");
@@ -182,7 +182,7 @@ static void FindExpectedDiags(Preprocessor &PP,
/// 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,
@@ -201,7 +201,7 @@ static bool PrintProblem(SourceManager &SourceMgr,
/// 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,
@@ -245,7 +245,7 @@ static bool CompareDiagLists(SourceManager &SourceMgr,
/// 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,
diff --git a/lib/Frontend/DocumentXML.cpp b/lib/Frontend/DocumentXML.cpp
index 19a7573..d92d4cb 100644
--- a/lib/Frontend/DocumentXML.cpp
+++ b/lib/Frontend/DocumentXML.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This file implements the XML document class, which provides the means to
+// 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.
//
//===----------------------------------------------------------------------===//
@@ -20,23 +20,19 @@
namespace clang {
-//---------------------------------------------------------
+//---------------------------------------------------------
DocumentXML::DocumentXML(const std::string& rootName, llvm::raw_ostream& out) :
Out(out),
Ctx(0),
- HasCurrentNodeSubNodes(false)
-{
+ HasCurrentNodeSubNodes(false) {
NodeStack.push(rootName);
Out << "<?xml version=\"1.0\"?>\n<" << rootName;
}
-//---------------------------------------------------------
-DocumentXML& DocumentXML::addSubNode(const std::string& name)
-{
+//---------------------------------------------------------
+DocumentXML& DocumentXML::addSubNode(const std::string& name) {
if (!HasCurrentNodeSubNodes)
- {
Out << ">\n";
- }
NodeStack.push(name);
HasCurrentNodeSubNodes = false;
Indent();
@@ -44,46 +40,38 @@ DocumentXML& DocumentXML::addSubNode(const std::string& name)
return *this;
}
-//---------------------------------------------------------
-void DocumentXML::Indent()
-{
+//---------------------------------------------------------
+void DocumentXML::Indent() {
for (size_t i = 0, e = (NodeStack.size() - 1) * 2; i < e; ++i)
Out << ' ';
}
-//---------------------------------------------------------
-DocumentXML& DocumentXML::toParent()
-{
- assert(NodeStack.size() > 1 && "to much backtracking");
+//---------------------------------------------------------
+DocumentXML& DocumentXML::toParent() {
+ assert(NodeStack.size() > 1 && "too much backtracking");
- if (HasCurrentNodeSubNodes)
- {
+ if (HasCurrentNodeSubNodes) {
Indent();
Out << "</" << NodeStack.top() << ">\n";
- }
- else
- {
+ } else
Out << "/>\n";
- }
NodeStack.pop();
HasCurrentNodeSubNodes = true;
- return *this;
+ return *this;
}
-//---------------------------------------------------------
+//---------------------------------------------------------
namespace {
enum tIdType { ID_NORMAL, ID_FILE, ID_LABEL, ID_LAST };
-unsigned getNewId(tIdType idType)
-{
+unsigned getNewId(tIdType idType) {
static unsigned int idCounts[ID_LAST] = { 0 };
return ++idCounts[idType];
}
-//---------------------------------------------------------
-inline std::string getPrefixedId(unsigned uId, tIdType idType)
-{
+//---------------------------------------------------------
+inline std::string getPrefixedId(unsigned uId, tIdType idType) {
static const char idPrefix[ID_LAST] = { '_', 'f', 'l' };
char buffer[20];
char* BufPtr = llvm::utohex_buffer(uId, buffer + 20);
@@ -91,25 +79,22 @@ inline std::string getPrefixedId(unsigned uId, tIdType idType)
return BufPtr;
}
-//---------------------------------------------------------
+//---------------------------------------------------------
template<class T, class V>
-bool addToMap(T& idMap, const V& value, tIdType idType = ID_NORMAL)
-{
+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)
- {
+ 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 DocumentXML::escapeString(const char* pStr,
+ std::string::size_type len) {
std::string value;
value.reserve(len + 1);
char buffer[16];
@@ -118,8 +103,7 @@ std::string DocumentXML::escapeString(const char* pStr, std::string::size_type l
default:
if (isprint(C))
value += C;
- else
- {
+ else {
sprintf(buffer, "\\%03o", C);
value += buffer;
}
@@ -142,26 +126,24 @@ std::string DocumentXML::escapeString(const char* pStr, std::string::size_type l
return value;
}
-//---------------------------------------------------------
-void DocumentXML::finalize()
-{
+//---------------------------------------------------------
+void DocumentXML::finalize() {
assert(NodeStack.size() == 1 && "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)
- {
+ for (XML::IdMap<QualType>::iterator i = Types.begin(), e = Types.end();
+ i != e; ++i) {
+ if (i->first.hasQualifiers()) {
writeTypeToXML(i->first);
addAttribute("id", getPrefixedId(i->second, ID_NORMAL));
toParent();
}
}
- for (XML::IdMap<const Type*>::iterator i = BasicTypes.begin(), e = BasicTypes.end(); i != e; ++i)
- {
+ for (XML::IdMap<const Type*>::iterator i = BasicTypes.begin(),
+ e = BasicTypes.end(); i != e; ++i) {
writeTypeToXML(i->first);
addAttribute("id", getPrefixedId(i->second, ID_NORMAL));
toParent();
@@ -170,31 +152,26 @@ void DocumentXML::finalize()
toParent().addSubNode("Contexts");
- for (XML::IdMap<const DeclContext*>::iterator i = Contexts.begin(), e = Contexts.end(); i != e; ++i)
- {
+ 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)) {
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(i->first))
addAttribute("name", ND->getNameAsString());
- }
- if (const TagDecl *TD = dyn_cast<TagDecl>(i->first)) {
+ 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));
- }
+ else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(i->first))
+ addAttribute("type", getPrefixedId(BasicTypes[FD->getType()->getAs<FunctionType>()], ID_NORMAL));
if (const DeclContext* parent = i->first->getParent())
- {
addAttribute("context", parent);
- }
toParent();
}
toParent().addSubNode("Files");
- for (XML::IdMap<std::string>::iterator i = SourceFiles.begin(), e = SourceFiles.end(); i != e; ++i)
- {
+ 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()));
@@ -202,40 +179,40 @@ void DocumentXML::finalize()
}
toParent().toParent();
-
+
// write the root closing node (which has always subnodes)
Out << "</" << NodeStack.top() << ">\n";
}
-//---------------------------------------------------------
-void DocumentXML::addAttribute(const char* pAttributeName, const QualType& pType)
-{
+//---------------------------------------------------------
+void DocumentXML::addAttribute(const char* pAttributeName,
+ const QualType& pType) {
addTypeRecursively(pType);
addAttribute(pAttributeName, getPrefixedId(Types[pType], ID_NORMAL));
}
-//---------------------------------------------------------
-void DocumentXML::addPtrAttribute(const char* pAttributeName, const Type* pType)
-{
+//---------------------------------------------------------
+void DocumentXML::addPtrAttribute(const char* pAttributeName,
+ const Type* pType) {
addTypeRecursively(pType);
addAttribute(pAttributeName, getPrefixedId(BasicTypes[pType], ID_NORMAL));
}
-//---------------------------------------------------------
+//---------------------------------------------------------
void DocumentXML::addTypeRecursively(const QualType& pType)
{
if (addToMap(Types, pType))
{
addTypeRecursively(pType.getTypePtr());
// beautifier: a non-qualified type shall be transparent
- if (pType.getCVRQualifiers() == 0)
+ if (!pType.hasQualifiers())
{
- Types[pType] = BasicTypes[pType.getTypePtr()];
+ Types[pType] = BasicTypes[pType.getTypePtr()];
}
}
}
-//---------------------------------------------------------
+//---------------------------------------------------------
void DocumentXML::addTypeRecursively(const Type* pType)
{
if (addToMap(BasicTypes, pType))
@@ -243,7 +220,7 @@ void DocumentXML::addTypeRecursively(const Type* pType)
addParentTypes(pType);
/*
// FIXME: doesn't work in the immediate streaming approach
- if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(pType))
+ if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(pType))
{
addSubNode("VariableArraySizeExpression");
PrintStmt(VAT->getSizeExpr());
@@ -253,14 +230,14 @@ void DocumentXML::addTypeRecursively(const Type* pType)
}
}
-//---------------------------------------------------------
+//---------------------------------------------------------
void DocumentXML::addPtrAttribute(const char* pName, const DeclContext* DC)
{
addContextsRecursively(DC);
addAttribute(pName, getPrefixedId(Contexts[DC], ID_NORMAL));
}
-//---------------------------------------------------------
+//---------------------------------------------------------
void DocumentXML::addPtrAttribute(const char* pAttributeName, const NamedDecl* D)
{
if (const DeclContext* DC = dyn_cast<DeclContext>(D))
@@ -275,22 +252,22 @@ void DocumentXML::addPtrAttribute(const char* pAttributeName, const NamedDecl* D
}
}
-//---------------------------------------------------------
+//---------------------------------------------------------
void DocumentXML::addPtrAttribute(const char* pName, const NamespaceDecl* D)
{
addPtrAttribute(pName, static_cast<const DeclContext*>(D));
}
-//---------------------------------------------------------
+//---------------------------------------------------------
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);
@@ -298,7 +275,7 @@ void DocumentXML::addSourceFileAttribute(const std::string& fileName)
}
-//---------------------------------------------------------
+//---------------------------------------------------------
void DocumentXML::addPtrAttribute(const char* pName, const LabelStmt* L)
{
addToMap(Labels, L, ID_LABEL);
@@ -306,13 +283,13 @@ void DocumentXML::addPtrAttribute(const char* pName, const LabelStmt* L)
}
-//---------------------------------------------------------
+//---------------------------------------------------------
PresumedLoc DocumentXML::addLocation(const SourceLocation& Loc)
{
SourceManager& SM = Ctx->getSourceManager();
SourceLocation SpellingLoc = SM.getSpellingLoc(Loc);
PresumedLoc PLoc;
- if (!SpellingLoc.isInvalid())
+ if (!SpellingLoc.isInvalid())
{
PLoc = SM.getPresumedLoc(SpellingLoc);
addSourceFileAttribute(PLoc.getFilename());
@@ -323,18 +300,18 @@ PresumedLoc DocumentXML::addLocation(const SourceLocation& Loc)
return PLoc;
}
-//---------------------------------------------------------
+//---------------------------------------------------------
void DocumentXML::addLocationRange(const SourceRange& R)
{
PresumedLoc PStartLoc = addLocation(R.getBegin());
- if (R.getBegin() != R.getEnd())
+ if (R.getBegin() != R.getEnd())
{
SourceManager& SM = Ctx->getSourceManager();
SourceLocation SpellingLoc = SM.getSpellingLoc(R.getEnd());
- if (!SpellingLoc.isInvalid())
+ if (!SpellingLoc.isInvalid())
{
PresumedLoc PLoc = SM.getPresumedLoc(SpellingLoc);
- if (PStartLoc.isInvalid() ||
+ if (PStartLoc.isInvalid() ||
strcmp(PLoc.getFilename(), PStartLoc.getFilename()) != 0) {
addToMap(SourceFiles, PLoc.getFilename(), ID_FILE);
addAttribute("endfile", PLoc.getFilename());
@@ -345,17 +322,17 @@ void DocumentXML::addLocationRange(const SourceRange& R)
addAttribute("endcol", PLoc.getColumn());
} else {
addAttribute("endcol", PLoc.getColumn());
- }
+ }
}
}
}
-//---------------------------------------------------------
+//---------------------------------------------------------
void DocumentXML::PrintDecl(Decl *D)
{
writeDeclToXML(D);
}
-//---------------------------------------------------------
+//---------------------------------------------------------
} // NS clang
diff --git a/lib/Frontend/FixItRewriter.cpp b/lib/Frontend/FixItRewriter.cpp
index 1ed89d7..dddcaa9 100644
--- a/lib/Frontend/FixItRewriter.cpp
+++ b/lib/Frontend/FixItRewriter.cpp
@@ -16,10 +16,11 @@
#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"
+#include "llvm/ADT/OwningPtr.h"
+#include <cstdio>
+
using namespace clang;
FixItRewriter::FixItRewriter(Diagnostic &Diags, SourceManager &SourceMgr,
@@ -33,7 +34,7 @@ FixItRewriter::~FixItRewriter() {
Diags.setClient(Client);
}
-bool FixItRewriter::WriteFixedFile(const std::string &InFileName,
+bool FixItRewriter::WriteFixedFile(const std::string &InFileName,
const std::string &OutFileName) {
if (NumFailures > 0) {
Diag(FullSourceLoc(), diag::warn_fixit_no_changes);
@@ -44,10 +45,8 @@ bool FixItRewriter::WriteFixedFile(const std::string &InFileName,
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);
+ OutFile = new llvm::raw_fd_ostream(OutFileName.c_str(), Err,
+ llvm::raw_fd_ostream::F_Binary);
OwnedStream.reset(OutFile);
} else if (InFileName == "-") {
OutFile = &llvm::outs();
@@ -57,15 +56,13 @@ bool FixItRewriter::WriteFixedFile(const std::string &InFileName,
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);
+ OutFile = new llvm::raw_fd_ostream(Path.c_str(), Err,
+ llvm::raw_fd_ostream::F_Binary);
OwnedStream.reset(OutFile);
- }
+ }
FileID MainFileID = Rewrite.getSourceMgr().getMainFileID();
- if (const RewriteBuffer *RewriteBuf =
+ if (const RewriteBuffer *RewriteBuf =
Rewrite.getRewriteBufferFor(MainFileID)) {
*OutFile << std::string(RewriteBuf->begin(), RewriteBuf->end());
} else {
@@ -102,7 +99,7 @@ void FixItRewriter::HandleDiagnostic(Diagnostic::Level DiagLevel,
// See if the location of the error is one that matches what the
// user requested.
bool AcceptableLocation = false;
- const FileEntry *File
+ const FileEntry *File
= Rewrite.getSourceMgr().getFileEntryForID(
Info.getLocation().getFileID());
unsigned Line = Info.getLocation().getSpellingLineNumber();
@@ -132,14 +129,14 @@ void FixItRewriter::HandleDiagnostic(Diagnostic::Level DiagLevel,
break;
}
- if (Hint.InsertionLoc.isValid() &&
+ if (Hint.InsertionLoc.isValid() &&
!Rewrite.isRewritable(Hint.InsertionLoc)) {
CanRewrite = false;
break;
}
}
- if (!CanRewrite) {
+ if (!CanRewrite) {
if (Info.getNumCodeModificationHints() > 0)
Diag(Info.getLocation(), diag::note_fixit_in_macro);
@@ -152,29 +149,28 @@ void FixItRewriter::HandleDiagnostic(Diagnostic::Level DiagLevel,
}
bool Failed = false;
- for (unsigned Idx = 0, Last = Info.getNumCodeModificationHints();
+ 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))
+ if (Rewrite.InsertTextBefore(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()))
+ Hint.CodeToInsert))
Failed = true;
}
@@ -195,5 +191,5 @@ void FixItRewriter::Diag(FullSourceLoc Loc, unsigned DiagID) {
Diags.setClient(Client);
Diags.Clear();
Diags.Report(Loc, DiagID);
- Diags.setClient(this);
+ Diags.setClient(this);
}
diff --git a/lib/Frontend/GeneratePCH.cpp b/lib/Frontend/GeneratePCH.cpp
index 8be88ce..bc45cc4 100644
--- a/lib/Frontend/GeneratePCH.cpp
+++ b/lib/Frontend/GeneratePCH.cpp
@@ -23,7 +23,6 @@
#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;
@@ -32,19 +31,24 @@ using namespace llvm;
namespace {
class VISIBILITY_HIDDEN PCHGenerator : public SemaConsumer {
const Preprocessor &PP;
+ const char *isysroot;
llvm::raw_ostream *Out;
Sema *SemaPtr;
MemorizeStatCalls *StatCalls; // owned by the FileManager
public:
- explicit PCHGenerator(const Preprocessor &PP, llvm::raw_ostream *Out);
+ explicit PCHGenerator(const Preprocessor &PP,
+ const char *isysroot,
+ 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) {
+PCHGenerator::PCHGenerator(const Preprocessor &PP,
+ const char *isysroot,
+ llvm::raw_ostream *OS)
+ : PP(PP), isysroot(isysroot), Out(OS), SemaPtr(0), StatCalls(0) {
// Install a stat() listener to keep track of all of the stat()
// calls.
@@ -56,14 +60,14 @@ void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) {
if (PP.getDiagnostics().hasErrorOccurred())
return;
- // Write the PCH contents into a buffer
+ // 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);
+ Writer.WritePCH(*SemaPtr, StatCalls, isysroot);
// Write the generated bitstream to "Out".
Out->write((char *)&Buffer.front(), Buffer.size());
@@ -73,6 +77,7 @@ void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) {
}
ASTConsumer *clang::CreatePCHGenerator(const Preprocessor &PP,
- llvm::raw_ostream *OS) {
- return new PCHGenerator(PP, OS);
+ llvm::raw_ostream *OS,
+ const char *isysroot) {
+ return new PCHGenerator(PP, isysroot, OS);
}
diff --git a/lib/Frontend/HTMLDiagnostics.cpp b/lib/Frontend/HTMLDiagnostics.cpp
index 9cfe0b2..9d6f96c 100644
--- a/lib/Frontend/HTMLDiagnostics.cpp
+++ b/lib/Frontend/HTMLDiagnostics.cpp
@@ -23,10 +23,9 @@
#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;
//===----------------------------------------------------------------------===//
@@ -39,44 +38,82 @@ class VISIBILITY_HIDDEN HTMLDiagnostics : public PathDiagnosticClient {
llvm::sys::Path Directory, FilePrefix;
bool createdDir, noDir;
Preprocessor* PP;
- std::vector<const PathDiagnostic*> BatchedDiags;
+ std::vector<const PathDiagnostic*> BatchedDiags;
+ llvm::SmallVectorImpl<std::string> *FilesMade;
public:
- HTMLDiagnostics(const std::string& prefix, Preprocessor* pp);
+ HTMLDiagnostics(const std::string& prefix, Preprocessor* pp,
+ llvm::SmallVectorImpl<std::string> *filesMade = 0);
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)
+HTMLDiagnostics::HTMLDiagnostics(const std::string& prefix, Preprocessor* pp,
+ llvm::SmallVectorImpl<std::string>* filesMade)
: Directory(prefix), FilePrefix(prefix), createdDir(false), noDir(false),
- PP(pp) {
-
- // All html files begin with "report"
+ PP(pp), FilesMade(filesMade) {
+
+ // All html files begin with "report"
FilePrefix.appendComponent("report");
}
PathDiagnosticClient*
clang::CreateHTMLDiagnosticClient(const std::string& prefix, Preprocessor* PP,
- PreprocessorFactory*) {
- return new HTMLDiagnostics(prefix, PP);
+ PreprocessorFactory*,
+ llvm::SmallVectorImpl<std::string>* FilesMade)
+{
+ return new HTMLDiagnostics(prefix, PP, FilesMade);
+}
+
+//===----------------------------------------------------------------------===//
+// Factory for HTMLDiagnosticClients
+//===----------------------------------------------------------------------===//
+
+namespace {
+class VISIBILITY_HIDDEN HTMLDiagnosticsFactory
+ : public PathDiagnosticClientFactory {
+
+ std::string Prefix;
+ Preprocessor *PP;
+public:
+ HTMLDiagnosticsFactory(const std::string& prefix, Preprocessor* pp)
+ : Prefix(prefix), PP(pp) {}
+
+ virtual ~HTMLDiagnosticsFactory() {}
+
+ const char *getName() const { return "HTMLDiagnostics"; }
+
+ PathDiagnosticClient*
+ createPathDiagnosticClient(llvm::SmallVectorImpl<std::string> *FilesMade) {
+
+ return new HTMLDiagnostics(Prefix, PP, FilesMade);
+ }
+};
+} // end anonymous namespace
+
+PathDiagnosticClientFactory*
+clang::CreateHTMLDiagnosticClientFactory(const std::string& prefix,
+ Preprocessor* PP,
+ PreprocessorFactory*) {
+ return new HTMLDiagnosticsFactory(prefix, PP);
}
//===----------------------------------------------------------------------===//
@@ -86,12 +123,12 @@ clang::CreateHTMLDiagnosticClient(const std::string& prefix, Preprocessor* PP,
void HTMLDiagnostics::HandlePathDiagnostic(const PathDiagnostic* D) {
if (!D)
return;
-
+
if (D->empty()) {
delete D;
return;
}
-
+
const_cast<PathDiagnostic*>(D)->flattenLocations();
BatchedDiags.push_back(D);
}
@@ -102,7 +139,7 @@ HTMLDiagnostics::~HTMLDiagnostics() {
BatchedDiags.pop_back();
ReportDiag(*D);
delete D;
- }
+ }
}
void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D) {
@@ -111,73 +148,73 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D) {
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';
-
+ llvm::errs() << "warning: could not create directory '"
+ << Directory.str() << "'\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?
+ 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.
+
+ // 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,
@@ -186,141 +223,121 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D) {
// 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() + "/";
+ DirName = P.str() + "/";
}
-
- // Add the name of the file as an <h1> tag.
-
+
+ // 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 "
+ "<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());
+ "<h3>Annotated Source Code</h3>\n";
+
+ R.InsertTextBefore(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);
+
+ const std::string& BugDesc = D.getDescription();
+ if (!BugDesc.empty())
+ os << "\n<!-- BUGDESC " << BugDesc << " -->\n";
+
+ const std::string& BugType = D.getBugType();
+ if (!BugType.empty())
+ os << "\n<!-- BUGTYPE " << BugType << " -->\n";
+
+ const std::string& BugCategory = D.getCategory();
+ if (!BugCategory.empty())
+ os << "\n<!-- BUGCATEGORY " << BugCategory << " -->\n";
+
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());
+
+ // Mark the end of the tags.
+ os << "\n<!-- BUGMETAEND -->\n";
+
+ // Insert the text.
+ R.InsertTextBefore(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";
+ llvm::errs() << "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;
- }
+ // 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);
+
+ std::string ErrorMsg;
+ llvm::raw_fd_ostream os(H.c_str(), ErrorMsg);
+
+ if (!ErrorMsg.empty()) {
+ (llvm::errs() << "warning: could not create file '" << F.str()
+ << "'\n").flush();
+ return;
}
-
- // Emit the HTML to disk.
+ if (FilesMade)
+ FilesMade->push_back(H.getLast());
+
+ // Emit the HTML to disk.
for (RewriteBuffer::iterator I = Buf->begin(), E = Buf->end(); I!=E; ++I)
os << *I;
}
@@ -328,24 +345,24 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D) {
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;
-
+ 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();
-
+ 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);
@@ -357,12 +374,12 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID,
const char* FileEnd = Buf->getBufferEnd();
while (*LineEnd != '\n' && LineEnd != FileEnd)
++LineEnd;
-
+
// Compute the margin offset by counting tabs and non-tabs.
- unsigned PosNo = 0;
+ 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;
@@ -372,22 +389,22 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID,
// 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 << " msg" << Kind;
os << "\" style=\"margin-left:" << PosNo << "ex";
-
+
// Output a maximum size.
if (!isa<PathDiagnosticMacroPiece>(P)) {
// Get the string and determining its maximum substring.
@@ -395,32 +412,32 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID,
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;
+ 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) {
@@ -428,18 +445,18 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID,
break;
}
}
-
+
em = characters / 2;
}
-
+
if (em < max_line/2)
- os << "; max-width:" << em << "em";
+ 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";
@@ -449,10 +466,10 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID,
}
if (const PathDiagnosticMacroPiece *MP =
- dyn_cast<PathDiagnosticMacroPiece>(&P)) {
+ 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();
@@ -461,15 +478,15 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID,
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>";
@@ -478,21 +495,21 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID,
}
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 =
+ unsigned DisplayPos = LineEnd - FileStart;
+ SourceLocation Loc =
SM.getLocForStartOfFile(LPosInfo.first).getFileLocWithOffset(DisplayPos);
- R.InsertStrBefore(Loc, os.str());
+ R.InsertTextBefore(Loc, os.str());
- // Now highlight the ranges.
+ // Now highlight the ranges.
for (const SourceRange *I = P.ranges_begin(), *E = P.ranges_end();
I != E; ++I)
HighlightRange(R, LPosInfo.first, *I);
@@ -513,7 +530,7 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID,
std::string EscapedCode = html::EscapeText(Hint->CodeToInsert, true);
EscapedCode = "<span class=\"CodeInsertionHint\">" + EscapedCode
+ "</span>";
- R.InsertStrBefore(Hint->InsertionLoc, EscapedCode);
+ R.InsertTextBefore(Hint->InsertionLoc, EscapedCode);
}
}
#endif
@@ -527,9 +544,9 @@ static void EmitAlphaCounter(llvm::raw_ostream& os, unsigned n) {
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;
@@ -538,10 +555,10 @@ static void EmitAlphaCounter(llvm::raw_ostream& os, unsigned n) {
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);
@@ -559,7 +576,7 @@ unsigned HTMLDiagnostics::ProcessMacroPiece(llvm::raw_ostream& os,
<< "</td></tr></table></div>\n";
}
}
-
+
return num;
}
@@ -569,20 +586,20 @@ void HTMLDiagnostics::HighlightRange(Rewriter& R, FileID BugFileID,
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;
@@ -591,12 +608,12 @@ void HTMLDiagnostics::HighlightRange(Rewriter& R, FileID BugFileID,
// 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
index d5eb9fb..8d93d70 100644
--- a/lib/Frontend/HTMLPrint.cpp
+++ b/lib/Frontend/HTMLPrint.cpp
@@ -21,12 +21,12 @@
#include "clang/Basic/FileManager.h"
#include "clang/AST/ASTContext.h"
#include "llvm/Support/MemoryBuffer.h"
-
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
//===----------------------------------------------------------------------===//
// Functional HTML pretty-printing.
-//===----------------------------------------------------------------------===//
+//===----------------------------------------------------------------------===//
namespace {
class HTMLPrinter : public ASTConsumer {
@@ -40,7 +40,7 @@ namespace {
PreprocessorFactory* ppf)
: Out(OS), Diags(D), PP(pp), PPF(ppf) {}
virtual ~HTMLPrinter();
-
+
void Initialize(ASTContext &context);
};
}
@@ -48,7 +48,7 @@ namespace {
ASTConsumer* clang::CreateHTMLPrinter(llvm::raw_ostream *OS,
Diagnostic &D, Preprocessor *PP,
PreprocessorFactory* PPF) {
-
+
return new HTMLPrinter(OS, D, PP, PPF);
}
@@ -78,7 +78,7 @@ HTMLPrinter::~HTMLPrinter() {
// 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);
diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp
index 8c80786..822a5ba 100644
--- a/lib/Frontend/InitHeaderSearch.cpp
+++ b/lib/Frontend/InitHeaderSearch.cpp
@@ -17,21 +17,26 @@
#include "clang/Basic/LangOptions.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/System/Path.h"
#include "llvm/Config/config.h"
#include <cstdio>
-#include <vector>
+#ifdef _MSC_VER
+ #define WIN32_LEAN_AND_MEAN 1
+ #include <windows.h>
+#endif
using namespace clang;
-void InitHeaderSearch::AddPath(const std::string &Path, IncludeDirGroup Group,
- bool isCXXAware, bool isUserSupplied,
- bool isFramework, bool IgnoreSysRoot) {
+void InitHeaderSearch::AddPath(const llvm::StringRef &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
@@ -39,7 +44,7 @@ void InitHeaderSearch::AddPath(const std::string &Path, IncludeDirGroup Group,
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.
@@ -50,22 +55,19 @@ void InitHeaderSearch::AddPath(const std::string &Path, IncludeDirGroup Group,
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())) {
+ if (const DirectoryEntry *DE = FM.getDirectory(MappedPath.str())) {
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 FileEntry *FE = FM.getFile(MappedPath.str())) {
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));
@@ -73,10 +75,10 @@ void InitHeaderSearch::AddPath(const std::string &Path, IncludeDirGroup Group,
}
}
}
-
+
if (Verbose)
- fprintf(stderr, "ignoring nonexistent directory \"%s\"\n",
- MappedPath.c_str());
+ llvm::errs() << "ignoring nonexistent directory \""
+ << MappedPath.str() << "\"\n";
}
@@ -90,8 +92,7 @@ void InitHeaderSearch::AddEnvVarPaths(const char *Name) {
if (delim-at == 0)
AddPath(".", Angled, false, true, false);
else
- AddPath(std::string(at, std::string::size_type(delim-at)), Angled, false,
- true, false);
+ AddPath(llvm::StringRef(at, delim-at), Angled, false, true, false);
at = delim + 1;
delim = strchr(at, llvm::sys::PathSeparator);
}
@@ -101,104 +102,321 @@ void InitHeaderSearch::AddEnvVarPaths(const char *Name) {
AddPath(at, Angled, false, true, false);
}
+void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(const std::string &Base,
+ const char *Dir32,
+ const char *Dir64,
+ const llvm::Triple &triple) {
+ llvm::Triple::ArchType arch = triple.getArch();
+ bool is64bit = arch == llvm::Triple::ppc64 || arch == llvm::Triple::x86_64;
-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);
+ AddPath(Base, System, true, false, false);
+ if (is64bit)
+ AddPath(Base + "/" + Dir64, System, true, false, false);
+ else
+ AddPath(Base + "/" + Dir32, System, true, false, false);
+ AddPath(Base + "/backward", System, true, false, false);
+}
+
+void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(const std::string &Base,
+ const char *Arch,
+ const char *Version) {
+ std::string localBase = Base + "/" + Arch + "/" + Version + "/include";
+ AddPath(localBase, System, true, false, false);
+ AddPath(localBase + "/c++", System, true, false, false);
+ AddPath(localBase + "/c++/backward", System, true, false, false);
+}
+
+ // FIXME: This probably should goto to some platform utils place.
+#ifdef _MSC_VER
+ // Read registry string.
+bool getSystemRegistryString(const char *keyPath, const char *valueName,
+ char *value, size_t maxLength) {
+ HKEY hRootKey = NULL;
+ HKEY hKey = NULL;
+ const char* subKey = NULL;
+ DWORD valueType;
+ DWORD valueSize = maxLength - 1;
+ bool returnValue = false;
+ if (strncmp(keyPath, "HKEY_CLASSES_ROOT\\", 18) == 0) {
+ hRootKey = HKEY_CLASSES_ROOT;
+ subKey = keyPath + 18;
}
+ else if (strncmp(keyPath, "HKEY_USERS\\", 11) == 0) {
+ hRootKey = HKEY_USERS;
+ subKey = keyPath + 11;
+ }
+ else if (strncmp(keyPath, "HKEY_LOCAL_MACHINE\\", 19) == 0) {
+ hRootKey = HKEY_LOCAL_MACHINE;
+ subKey = keyPath + 19;
+ }
+ else if (strncmp(keyPath, "HKEY_CURRENT_USER\\", 18) == 0) {
+ hRootKey = HKEY_CURRENT_USER;
+ subKey = keyPath + 18;
+ }
+ else
+ return(false);
+ long lResult = RegOpenKeyEx(hRootKey, subKey, 0, KEY_READ, &hKey);
+ if (lResult == ERROR_SUCCESS) {
+ lResult = RegQueryValueEx(hKey, valueName, NULL, &valueType,
+ (LPBYTE)value, &valueSize);
+ if (lResult == ERROR_SUCCESS)
+ returnValue = true;
+ RegCloseKey(hKey);
+ }
+ return(returnValue);
+}
+#else // _MSC_VER
+ // Read registry string.
+bool getSystemRegistryString(const char *, const char *, char *, size_t) {
+ return(false);
+}
+#endif // _MSC_VER
+
+ // Get Visual Studio installation directory.
+bool getVisualStudioDir(std::string &path) {
+ // Try the Windows registry first.
+ char vs80IDEInstallDir[256];
+ char vs90IDEInstallDir[256];
+ const char* vsIDEInstallDir = NULL;
+ bool has80 = getSystemRegistryString(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0",
+ "InstallDir", vs80IDEInstallDir, sizeof(vs80IDEInstallDir) - 1);
+ bool has90 = getSystemRegistryString(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\9.0",
+ "InstallDir", vs90IDEInstallDir, sizeof(vs90IDEInstallDir) - 1);
+ // If we have both vc80 and vc90, pick version we were compiled with.
+ if (has80 && has90) {
+ #ifdef _MSC_VER
+ #if (_MSC_VER >= 1500) // VC90
+ vsIDEInstallDir = vs90IDEInstallDir;
+ #elif (_MSC_VER == 1400) // VC80
+ vsIDEInstallDir = vs80IDEInstallDir;
+ #else
+ vsIDEInstallDir = vs90IDEInstallDir;
+ #endif
+ #else
+ vsIDEInstallDir = vs90IDEInstallDir;
+ #endif
+ }
+ else if (has90)
+ vsIDEInstallDir = vs90IDEInstallDir;
+ else if (has80)
+ vsIDEInstallDir = vs80IDEInstallDir;
+ if (vsIDEInstallDir && *vsIDEInstallDir) {
+ char *p = (char*)strstr(vsIDEInstallDir, "\\Common7\\IDE");
+ if (p)
+ *p = '\0';
+ path = vsIDEInstallDir;
+ return(true);
+ }
+ else {
+ // Try the environment.
+ const char* vs90comntools = getenv("VS90COMNTOOLS");
+ const char* vs80comntools = getenv("VS80COMNTOOLS");
+ const char* vscomntools = NULL;
+ // If we have both vc80 and vc90, pick version we were compiled with.
+ if (vs90comntools && vs80comntools) {
+ #if (_MSC_VER >= 1500) // VC90
+ vscomntools = vs90comntools;
+ #elif (_MSC_VER == 1400) // VC80
+ vscomntools = vs80comntools;
+ #else
+ vscomntools = vs90comntools;
+ #endif
+ }
+ else if (vs90comntools)
+ vscomntools = vs90comntools;
+ else if (vs80comntools)
+ vscomntools = vs80comntools;
+ if (vscomntools && *vscomntools) {
+ char *p = (char*)strstr(vscomntools, "\\Common7\\Tools");
+ if (p)
+ *p = '\0';
+ path = vscomntools;
+ return(true);
+ }
+ else
+ return(false);
+ }
+ return(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);
-
- // Ubuntu 9.04
- AddPath("/usr/include/c++/4.3.3", System, true, false, false);
- AddPath("/usr/include/c++/4.3.3/x86_64-linux-gnu/", System, true, false,
- false);
- AddPath("/usr/include/c++/4.3.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);
-
- // Gentoo amd64 stable
- AddPath("/usr/lib/gcc/x86_64-pc-linux-gnu/4.1.2/include/g++-v4", System,
- true, false, false);
- AddPath("/usr/lib/gcc/x86_64-pc-linux-gnu/4.1.2/include/g++-v4/"
- "i686-pc-linux-gnu", System, true, false, false);
- AddPath("/usr/lib/gcc/x86_64-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);
+void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang,
+ const llvm::Triple &triple) {
+ // FIXME: temporary hack: hard-coded paths.
+ llvm::Triple::OSType os = triple.getOS();
+
+ switch (os) {
+ case llvm::Triple::Win32:
+ {
+ std::string VSDir;
+ if (getVisualStudioDir(VSDir)) {
+ AddPath(VSDir + "\\VC\\include", System, false, false, false);
+ AddPath(VSDir + "\\VC\\PlatformSDK\\Include",
+ System, false, false, false);
+ }
+ else {
+ // Default install paths.
+ AddPath("C:/Program Files/Microsoft Visual Studio 9.0/VC/include",
+ System, false, false, false);
+ AddPath(
+ "C:/Program Files/Microsoft Visual Studio 9.0/VC/PlatformSDK/Include",
+ System, false, false, false);
+ AddPath("C:/Program Files/Microsoft Visual Studio 8/VC/include",
+ System, false, false, false);
+ AddPath(
+ "C:/Program Files/Microsoft Visual Studio 8/VC/PlatformSDK/Include",
+ System, false, false, false);
+ // For some clang developers.
+ AddPath("G:/Program Files/Microsoft Visual Studio 9.0/VC/include",
+ System, false, false, false);
+ AddPath(
+ "G:/Program Files/Microsoft Visual Studio 9.0/VC/PlatformSDK/Include",
+ System, false, false, false);
+ }
+ }
+ break;
+ case llvm::Triple::Cygwin:
+ if (Lang.CPlusPlus) {
+ AddPath("/lib/gcc/i686-pc-cygwin/3.4.4/include",
+ System, false, false, false);
+ AddPath("/lib/gcc/i686-pc-cygwin/3.4.4/include/c++",
+ System, false, false, false);
+ }
+ AddPath("/usr/include", System, false, false, false);
+ break;
+ case llvm::Triple::MinGW64:
+ if (Lang.CPlusPlus) { // I'm guessing here.
+ // Try gcc 4.4.0
+ AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw64", "4.4.0");
+ // Try gcc 4.3.0
+ AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw64", "4.3.0");
+ }
+ // Fall through.
+ case llvm::Triple::MinGW32:
+ if (Lang.CPlusPlus) {
+ // Try gcc 4.4.0
+ AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.4.0");
+ // Try gcc 4.3.0
+ AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.3.0");
+ }
+ AddPath("c:/mingw/include", System, true, false, false);
+ break;
+ default:
+ if (Lang.CPlusPlus) {
+ switch (os) {
+ case llvm::Triple::Darwin:
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2.1",
+ "i686-apple-darwin10",
+ "i686-apple-darwin10/x86_64",
+ triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.0.0",
+ "i686-apple-darwin8",
+ "i686-apple-darwin8",
+ triple);
+ break;
+ case llvm::Triple::Linux:
+ // Ubuntu 7.10 - Gutsy Gibbon
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.3",
+ "i486-linux-gnu",
+ "i486-linux-gnu",
+ triple);
+ // Ubuntu 9.04
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.3",
+ "x86_64-linux-gnu/32",
+ "x86_64-linux-gnu",
+ triple);
+ // Fedora 8
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.2",
+ "i386-redhat-linux",
+ "i386-redhat-linux",
+ triple);
+ // Fedora 9
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.0",
+ "i386-redhat-linux",
+ "i386-redhat-linux",
+ triple);
+ // Fedora 10
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.2",
+ "i386-redhat-linux",
+ "i386-redhat-linux",
+ triple);
+ // openSUSE 11.1 32 bit
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3",
+ "i586-suse-linux",
+ "i586-suse-linux",
+ triple);
+ // openSUSE 11.1 64 bit
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3",
+ "x86_64-suse-linux/32",
+ "x86_64-suse-linux",
+ triple);
+ // openSUSE 11.2
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4",
+ "i586-suse-linux",
+ "i586-suse-linux",
+ triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4",
+ "x86_64-suse-linux",
+ "x86_64-suse-linux",
+ triple);
+ // Arch Linux 2008-06-24
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.1",
+ "i686-pc-linux-gnu",
+ "i686-pc-linux-gnu",
+ triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.1",
+ "x86_64-unknown-linux-gnu",
+ "x86_64-unknown-linux-gnu",
+ triple);
+ // Gentoo x86 2009.0 stable
+ AddGnuCPlusPlusIncludePaths(
+ "/usr/lib/gcc/i686-pc-linux-gnu/4.3.2/include/g++-v4",
+ "i686-pc-linux-gnu",
+ "i686-pc-linux-gnu",
+ triple);
+ // Gentoo x86 2008.0 stable
+ AddGnuCPlusPlusIncludePaths(
+ "/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/include/g++-v4",
+ "i686-pc-linux-gnu",
+ "i686-pc-linux-gnu",
+ triple);
+ // Ubuntu 8.10
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3",
+ "i486-pc-linux-gnu",
+ "i486-pc-linux-gnu",
+ triple);
+ // Gentoo amd64 stable
+ AddGnuCPlusPlusIncludePaths(
+ "/usr/lib/gcc/x86_64-pc-linux-gnu/4.1.2/include/g++-v4",
+ "i686-pc-linux-gnu",
+ "i686-pc-linux-gnu",
+ triple);
+ break;
+ case llvm::Triple::FreeBSD:
+ // DragonFly
+ AddPath("/usr/include/c++/4.1", System, true, false, false);
+ // FreeBSD
+ AddPath("/usr/include/c++/4.2", System, true, false, false);
+ break;
+ case llvm::Triple::Solaris:
+ // AuroraUX
+ AddGnuCPlusPlusIncludePaths("/opt/gcc4/include/c++/4.2.4",
+ "i386-pc-solaris2.11",
+ "i386-pc-solaris2.11",
+ triple);
+ break;
+ default:
+ break;
+ }
+ }
+ break;
}
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) {
@@ -223,9 +441,9 @@ static void RemoveDuplicates(std::vector<DirectoryLookup> &SearchList,
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()))
@@ -240,7 +458,7 @@ static void RemoveDuplicates(std::vector<DirectoryLookup> &SearchList,
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
@@ -253,13 +471,13 @@ static void RemoveDuplicates(std::vector<DirectoryLookup> &SearchList,
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();
@@ -269,11 +487,11 @@ static void RemoveDuplicates(std::vector<DirectoryLookup> &SearchList,
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)
@@ -287,7 +505,7 @@ static void RemoveDuplicates(std::vector<DirectoryLookup> &SearchList,
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);
@@ -306,11 +524,11 @@ void InitHeaderSearch::Realize() {
IncludeGroup[After].end());
RemoveDuplicates(SearchList, Verbose);
RemoveDuplicates(IncludeGroup[Quoted], Verbose);
-
+
// Prepend QUOTED list on the search list.
- SearchList.insert(SearchList.begin(), IncludeGroup[Quoted].begin(),
+ 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(),
@@ -338,4 +556,3 @@ void InitHeaderSearch::Realize() {
fprintf(stderr, "End of search list.\n");
}
}
-
diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp
index e41dfdd..0f3b4b8 100644
--- a/lib/Frontend/InitPreprocessor.cpp
+++ b/lib/Frontend/InitPreprocessor.cpp
@@ -30,7 +30,7 @@ static void DefineBuiltinMacro(std::vector<char> &Buf, const char *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) {
@@ -40,7 +40,7 @@ static void DefineBuiltinMacro(std::vector<char> &Buf, const char *Macro) {
} else {
End = Equal+strlen(Equal);
}
-
+
Buf.insert(Buf.end(), Equal+1, End);
} else {
// Push "macroname 1".
@@ -62,7 +62,7 @@ static void UndefineBuiltinMacro(std::vector<char> &Buf, const char *Macro) {
}
/// Add the quoted name of an implicit include file.
-static void AddQuotedIncludePath(std::vector<char> &Buf,
+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
@@ -75,17 +75,17 @@ static void AddQuotedIncludePath(std::vector<char> &Buf,
Path.makeAbsolute();
if (!Path.exists())
Path = File;
-
+
// Escape double quotes etc.
Buf.push_back('"');
- std::string EscapedFile = Lexer::Stringify(Path.toString());
+ std::string EscapedFile = Lexer::Stringify(Path.str());
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,
+static void AddImplicitInclude(std::vector<char> &Buf,
const std::string &File) {
const char *Inc = "#include ";
Buf.insert(Buf.end(), Inc, Inc+strlen(Inc));
@@ -106,12 +106,12 @@ static void AddImplicitIncludeMacros(std::vector<char> &Buf,
/// AddImplicitIncludePTH - Add an implicit #include using the original file
/// used to generate a PTH cache.
-static void AddImplicitIncludePTH(std::vector<char> &Buf, Preprocessor &PP,
+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 "
@@ -119,7 +119,7 @@ static void AddImplicitIncludePTH(std::vector<char> &Buf, Preprocessor &PP,
ImplicitIncludePTH.c_str());
exit (1);
}
-
+
AddImplicitInclude(Buf, OriginalFile);
}
@@ -144,7 +144,7 @@ static T PickFP(const llvm::fltSemantics *Sem, T IEEESingleVal,
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",
+ DenormMin = PickFP(Sem, "1.40129846e-45F", "4.9406564584124654e-324",
"3.64519953188247460253e-4951L",
"4.94065645841246544176568792868221e-324L",
"6.47517511943802511092443895822764655e-4966L");
@@ -167,7 +167,7 @@ static void DefineFloatMacros(std::vector<char> &Buf, const char *Prefix,
"1.18973149535723176502e+4932L",
"1.79769313486231580793728971405301e+308L",
"1.18973149535723176508575932662800702e+4932L");
-
+
char MacroBuf[100];
sprintf(MacroBuf, "__%s_DENORM_MIN__=%s", Prefix, DenormMin);
DefineBuiltinMacro(Buf, MacroBuf);
@@ -210,8 +210,10 @@ static void DefineTypeSize(const char *MacroName, unsigned TypeWidth,
MaxVal = (1LL << (TypeWidth - 1)) - 1;
else
MaxVal = ~0LL >> (64-TypeWidth);
-
- sprintf(MacroBuf, "%s=%llu%s", MacroName, MaxVal, ValSuffix);
+
+ // FIXME: Switch to using raw_ostream and avoid utostr().
+ sprintf(MacroBuf, "%s=%s%s", MacroName, llvm::utostr(MaxVal).c_str(),
+ ValSuffix);
DefineBuiltinMacro(Buf, MacroBuf);
}
@@ -230,32 +232,35 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
// 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, "__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");
+
+ if (!LangOpts.CPlusPlus) {
+ if (LangOpts.C99)
+ DefineBuiltinMacro(Buf, "__STDC_VERSION__=199901L");
+ else if (!LangOpts.GNUMode && LangOpts.Digraphs)
+ DefineBuiltinMacro(Buf, "__STDC_VERSION__=199409L");
+ }
// Standard conforming mode?
if (!LangOpts.GNUMode)
DefineBuiltinMacro(Buf, "__STRICT_ANSI__=1");
-
+
if (LangOpts.CPlusPlus0x)
DefineBuiltinMacro(Buf, "__GXX_EXPERIMENTAL_CXX0X__");
@@ -263,32 +268,28 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
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__");
@@ -296,32 +297,42 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
DefineBuiltinMacro(Buf, "__block=__attribute__((__blocks__(byref)))");
DefineBuiltinMacro(Buf, "__BLOCKS__=1");
}
-
+
+ if (LangOpts.Exceptions)
+ DefineBuiltinMacro(Buf, "__EXCEPTIONS=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");
+ if (LangOpts.GNUMode)
+ DefineBuiltinMacro(Buf, "__cplusplus=1");
+ else
+ // C++ [cpp.predefined]p1:
+ // The name_ _cplusplusis defined to the value199711Lwhen compiling a
+ // C++ translation unit.
+ DefineBuiltinMacro(Buf, "__cplusplus=199711L");
DefineBuiltinMacro(Buf, "__private_extern__=extern");
+ // Ugly hack to work with GNU libstdc++.
+ DefineBuiltinMacro(Buf, "_GNU_SOURCE=1");
}
-
+
// Filter out some microsoft extensions when trying to parse in ms-compat
- // mode.
+ // mode.
if (LangOpts.Microsoft) {
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");
@@ -339,7 +350,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
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);
@@ -356,7 +367,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
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());
@@ -364,39 +375,39 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
// Define a __POINTER_WIDTH__ macro for stdint.h.
sprintf(MacroBuf, "__POINTER_WIDTH__=%d", (int)TI.getPointerWidth(0));
DefineBuiltinMacro(Buf, MacroBuf);
-
+
if (!LangOpts.CharIsSigned)
- DefineBuiltinMacro(Buf, "__CHAR_UNSIGNED__");
+ 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)
DefineType("__INT64_TYPE__", TI.getInt64Type(), Buf);
-
+
// 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");
@@ -439,15 +450,15 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
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";
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp
index 95b1661..e61668d 100644
--- a/lib/Frontend/PCHReader.cpp
+++ b/lib/Frontend/PCHReader.cpp
@@ -26,6 +26,7 @@
#include "clang/Basic/SourceManagerInternals.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/Version.h"
#include "llvm/Bitcode/BitstreamReader.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -69,20 +70,21 @@ PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) {
PARSE_LANGOPT_IMPORTANT(ObjCNonFragileABI, diag::warn_pch_nonfragile_abi);
PARSE_LANGOPT_BENIGN(PascalStrings);
PARSE_LANGOPT_BENIGN(WritableStrings);
- PARSE_LANGOPT_IMPORTANT(LaxVectorConversions,
+ PARSE_LANGOPT_IMPORTANT(LaxVectorConversions,
diag::warn_pch_lax_vector_conversions);
PARSE_LANGOPT_IMPORTANT(AltiVec, diag::warn_pch_altivec);
PARSE_LANGOPT_IMPORTANT(Exceptions, diag::warn_pch_exceptions);
PARSE_LANGOPT_IMPORTANT(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,
+ PARSE_LANGOPT_IMPORTANT(ThreadsafeStatics,
diag::warn_pch_thread_safe_statics);
+ PARSE_LANGOPT_IMPORTANT(POSIXThreads, diag::warn_pch_posix_threads);
PARSE_LANGOPT_IMPORTANT(Blocks, diag::warn_pch_blocks);
PARSE_LANGOPT_BENIGN(EmitAllDecls);
PARSE_LANGOPT_IMPORTANT(MathErrno, diag::warn_pch_math_errno);
PARSE_LANGOPT_IMPORTANT(OverflowChecking, diag::warn_pch_overflow_checking);
- PARSE_LANGOPT_IMPORTANT(HeinousExtensions,
+ 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
@@ -100,13 +102,16 @@ PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) {
PARSE_LANGOPT_IMPORTANT(AccessControl, diag::warn_pch_access_control);
PARSE_LANGOPT_IMPORTANT(CharIsSigned, diag::warn_pch_char_signed);
if ((PPLangOpts.getGCMode() != 0) != (LangOpts.getGCMode() != 0)) {
- Reader.Diag(diag::warn_pch_gc_mode)
+ Reader.Diag(diag::warn_pch_gc_mode)
<< LangOpts.getGCMode() << PPLangOpts.getGCMode();
return true;
}
PARSE_LANGOPT_BENIGN(getVisibilityMode());
+ PARSE_LANGOPT_IMPORTANT(getStackProtectorMode(),
+ diag::warn_pch_stack_protector);
PARSE_LANGOPT_BENIGN(InstantiationDepth);
PARSE_LANGOPT_IMPORTANT(OpenCL, diag::warn_pch_opencl);
+ PARSE_LANGOPT_IMPORTANT(ElideConstructors, diag::warn_pch_elide_constructors);
#undef PARSE_LANGOPT_IRRELEVANT
#undef PARSE_LANGOPT_BENIGN
@@ -114,9 +119,9 @@ PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) {
}
bool PCHValidator::ReadTargetTriple(const std::string &Triple) {
- if (Triple != PP.getTargetInfo().getTargetTriple()) {
+ if (Triple != PP.getTargetInfo().getTriple().getTriple()) {
Reader.Diag(diag::warn_pch_target_triple)
- << Triple << PP.getTargetInfo().getTargetTriple();
+ << Triple << PP.getTargetInfo().getTriple().getTriple();
return true;
}
return false;
@@ -163,7 +168,7 @@ static inline bool startsWith(const std::string &Haystack,
return startsWith(Haystack, Needle.c_str());
}
-bool PCHValidator::ReadPredefinesBuffer(const char *PCHPredef,
+bool PCHValidator::ReadPredefinesBuffer(const char *PCHPredef,
unsigned PCHPredefLen,
FileID PCHBufferID,
std::string &SuggestedPredefines) {
@@ -171,19 +176,19 @@ bool PCHValidator::ReadPredefinesBuffer(const char *PCHPredef,
unsigned PredefLen = PP.getPredefines().size();
// If the two predefines buffers compare equal, we're done!
- if (PredefLen == PCHPredefLen &&
+ 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
+ // Sort both sets of predefined buffer lines, since
std::sort(CmdLineLines.begin(), CmdLineLines.end());
std::sort(PCHLines.begin(), PCHLines.end());
@@ -202,11 +207,11 @@ bool PCHValidator::ReadPredefinesBuffer(const char *PCHPredef,
Reader.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
+ 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");
@@ -224,19 +229,19 @@ bool PCHValidator::ReadPredefinesBuffer(const char *PCHPredef,
if (!startsWith(*ConflictPos, MacroDefStart)) {
// Different macro; we're done.
ConflictPos = CmdLineLines.end();
- break;
+ break;
}
-
- assert(ConflictPos->size() > MacroDefLen &&
+
+ assert(ConflictPos->size() > MacroDefLen &&
"Invalid #define in predefines buffer?");
- if ((*ConflictPos)[MacroDefLen] != ' ' &&
+ if ((*ConflictPos)[MacroDefLen] != ' ' &&
(*ConflictPos)[MacroDefLen] != '(')
continue; // Longer macro name; keep trying.
-
+
// We found a conflicting macro definition.
break;
}
-
+
if (ConflictPos != CmdLineLines.end()) {
Reader.Diag(diag::warn_cmdline_conflicting_macro_def)
<< MacroName;
@@ -253,13 +258,13 @@ bool PCHValidator::ReadPredefinesBuffer(const char *PCHPredef,
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) {
Reader.Diag(diag::warn_cmdline_missing_macro_defs);
MissingDefines = true;
@@ -273,10 +278,10 @@ bool PCHValidator::ReadPredefinesBuffer(const char *PCHPredef,
.getFileLocWithOffset(Offset);
Reader.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
@@ -284,7 +289,7 @@ bool PCHValidator::ReadPredefinesBuffer(const char *PCHPredef,
std::vector<std::string> ExtraPredefines;
std::set_difference(CmdLineLines.begin(), CmdLineLines.end(),
PCHLines.begin(), PCHLines.end(),
- std::back_inserter(ExtraPredefines));
+ 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) {
@@ -295,7 +300,7 @@ bool PCHValidator::ReadPredefinesBuffer(const char *PCHPredef,
// 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
+ 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");
@@ -336,7 +341,8 @@ void PCHValidator::ReadCounter(unsigned Value) {
// PCH reader implementation
//===----------------------------------------------------------------------===//
-PCHReader::PCHReader(Preprocessor &PP, ASTContext *Context)
+PCHReader::PCHReader(Preprocessor &PP, ASTContext *Context,
+ const char *isysroot)
: Listener(new PCHValidator(PP, *this)), SourceMgr(PP.getSourceManager()),
FileMgr(PP.getFileManager()), Diags(PP.getDiagnostics()),
SemaObj(0), PP(&PP), Context(Context), Consumer(0),
@@ -344,24 +350,31 @@ PCHReader::PCHReader(Preprocessor &PP, ASTContext *Context)
IdentifierOffsets(0),
MethodPoolLookupTable(0), MethodPoolLookupTableData(0),
TotalSelectorsInMethodPool(0), SelectorOffsets(0),
- TotalNumSelectors(0), Comments(0), NumComments(0),
- NumStatHits(0), NumStatMisses(0),
- NumSLocEntriesRead(0), NumStatementsRead(0),
+ TotalNumSelectors(0), Comments(0), NumComments(0), isysroot(isysroot),
+ NumStatHits(0), NumStatMisses(0),
+ NumSLocEntriesRead(0), NumStatementsRead(0),
NumMacrosRead(0), NumMethodPoolSelectorsRead(0), NumMethodPoolMisses(0),
- NumLexicalDeclContextsRead(0), NumVisibleDeclContextsRead(0) { }
+ NumLexicalDeclContextsRead(0), NumVisibleDeclContextsRead(0),
+ CurrentlyLoadingTypeOrDecl(0) {
+ RelocatablePCH = false;
+}
PCHReader::PCHReader(SourceManager &SourceMgr, FileManager &FileMgr,
- Diagnostic &Diags)
+ Diagnostic &Diags, const char *isysroot)
: SourceMgr(SourceMgr), FileMgr(FileMgr), Diags(Diags),
SemaObj(0), PP(0), Context(0), 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),
+ TotalNumSelectors(0), Comments(0), NumComments(0), isysroot(isysroot),
+ NumStatHits(0), NumStatMisses(0),
+ NumSLocEntriesRead(0), NumStatementsRead(0),
NumMacrosRead(0), NumMethodPoolSelectorsRead(0), NumMethodPoolMisses(0),
- NumLexicalDeclContextsRead(0), NumVisibleDeclContextsRead(0) { }
+ NumLexicalDeclContextsRead(0), NumVisibleDeclContextsRead(0),
+ CurrentlyLoadingTypeOrDecl(0) {
+ RelocatablePCH = false;
+}
PCHReader::~PCHReader() {}
@@ -385,12 +398,12 @@ public:
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)
@@ -401,11 +414,11 @@ public:
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;
@@ -413,12 +426,12 @@ public:
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
+ IdentifierInfo *FirstII
= Reader.DecodeIdentifierInfo(ReadUnalignedLE32(d));
if (N == 0)
return SelTable.getNullarySelector(FirstII);
@@ -432,7 +445,7 @@ public:
return SelTable.getSelector(N, Args.data());
}
-
+
data_type ReadData(Selector, const unsigned char* d, unsigned DataLen) {
using namespace clang::io;
unsigned NumInstanceMethods = ReadUnalignedLE16(d);
@@ -443,7 +456,7 @@ public:
// Load instance methods
ObjCMethodList *Prev = 0;
for (unsigned I = 0; I != NumInstanceMethods; ++I) {
- ObjCMethodDecl *Method
+ ObjCMethodDecl *Method
= cast<ObjCMethodDecl>(Reader.GetDecl(ReadUnalignedLE32(d)));
if (!Result.first.Method) {
// This is the first method, which is the easy case.
@@ -459,7 +472,7 @@ public:
// Load factory methods
Prev = 0;
for (unsigned I = 0; I != NumFactoryMethods; ++I) {
- ObjCMethodDecl *Method
+ ObjCMethodDecl *Method
= cast<ObjCMethodDecl>(Reader.GetDecl(ReadUnalignedLE32(d)));
if (!Result.second.Method) {
// This is the first method, which is the easy case.
@@ -475,11 +488,11 @@ public:
return Result;
}
};
-
-} // end anonymous namespace
+
+} // end anonymous namespace
/// \brief The on-disk hash table used for the global method pool.
-typedef OnDiskChainedHashTable<PCHMethodPoolLookupTrait>
+typedef OnDiskChainedHashTable<PCHMethodPoolLookupTrait>
PCHMethodPoolLookupTable;
namespace {
@@ -498,23 +511,23 @@ public:
typedef external_key_type internal_key_type;
- explicit PCHIdentifierLookupTrait(PCHReader &Reader, IdentifierInfo *II = 0)
+ 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;
@@ -522,14 +535,14 @@ public:
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,
+
+ IdentifierInfo *ReadData(const internal_key_type& k,
const unsigned char* d,
unsigned DataLen) {
using namespace clang::io;
@@ -561,7 +574,7 @@ public:
Bits >>= 1;
unsigned ObjCOrBuiltinID = Bits & 0x3FF;
Bits >>= 10;
-
+
assert(Bits == 0 && "Extra bits in the identifier?");
DataLen -= 6;
@@ -576,7 +589,7 @@ public:
// Set or check the various bits in the IdentifierInfo structure.
// FIXME: Load token IDs lazily, too?
II->setObjCOrBuiltinID(ObjCOrBuiltinID);
- assert(II->isExtensionToken() == ExtensionToken &&
+ assert(II->isExtensionToken() == ExtensionToken &&
"Incorrect extension token flag");
(void)ExtensionToken;
II->setIsPoisoned(Poisoned);
@@ -594,38 +607,25 @@ public:
// 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;
+ if (DataLen > 0) {
+ llvm::SmallVector<uint32_t, 4> DeclIDs;
+ for (; DataLen > 0; DataLen -= 4)
+ DeclIDs.push_back(ReadUnalignedLE32(d));
+ Reader.SetGloballyVisibleDecls(II, DeclIDs);
}
+
return II;
}
};
-
-} // end anonymous namespace
+
+} // end anonymous namespace
/// \brief The on-disk hash table used to contain information about
/// all of the identifiers in the program.
-typedef OnDiskChainedHashTable<PCHIdentifierLookupTrait>
+typedef OnDiskChainedHashTable<PCHIdentifierLookupTrait>
PCHIdentifierLookupTable;
-// FIXME: use the diagnostics machinery
bool PCHReader::Error(const char *Msg) {
unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Fatal, Msg);
Diag(DiagID);
@@ -649,7 +649,7 @@ bool PCHReader::Error(const char *Msg) {
///
/// \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,
+bool PCHReader::CheckPredefinesBuffer(const char *PCHPredef,
unsigned PCHPredefLen,
FileID PCHBufferID) {
if (Listener)
@@ -664,8 +664,7 @@ bool PCHReader::CheckPredefinesBuffer(const char *PCHPredef,
/// \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) {
+bool PCHReader::ParseLineTable(llvm::SmallVectorImpl<uint64_t> &Record) {
unsigned Idx = 0;
LineTableInfo &LineTable = SourceMgr.getLineTable();
@@ -676,7 +675,8 @@ static bool ParseLineTable(SourceManager &SourceMgr,
unsigned FilenameLen = Record[Idx++];
std::string Filename(&Record[Idx], &Record[Idx] + FilenameLen);
Idx += FilenameLen;
- FileIDs[I] = LineTable.getLineTableFilenameID(Filename.c_str(),
+ MaybeAddSystemRootToFilename(Filename);
+ FileIDs[I] = LineTable.getLineTableFilenameID(Filename.c_str(),
Filename.size());
}
@@ -693,7 +693,7 @@ static bool ParseLineTable(SourceManager &SourceMgr,
unsigned FileOffset = Record[Idx++];
unsigned LineNo = Record[Idx++];
int FilenameID = Record[Idx++];
- SrcMgr::CharacteristicKind FileKind
+ SrcMgr::CharacteristicKind FileKind
= (SrcMgr::CharacteristicKind)Record[Idx++];
unsigned IncludeOffset = Record[Idx++];
Entries.push_back(LineEntry::get(FileOffset, LineNo, FilenameID,
@@ -715,10 +715,10 @@ public:
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) {}
-
+ : 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) {}
};
@@ -761,7 +761,7 @@ class VISIBILITY_HIDDEN PCHStatLookupTrait {
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);
+ time_t mtime = (time_t) ReadUnalignedLE64(d);
off_t size = (off_t) ReadUnalignedLE64(d);
return data_type(ino, dev, mode, mtime, size);
}
@@ -776,17 +776,17 @@ class VISIBILITY_HIDDEN PCHStatCache : public StatSysCallCache {
CacheTy *Cache;
unsigned &NumStatHits, &NumStatMisses;
-public:
+public:
PCHStatCache(const unsigned char *Buckets,
const unsigned char *Base,
unsigned &NumStatHits,
- unsigned &NumStatMisses)
+ 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);
@@ -796,10 +796,10 @@ public:
++NumStatMisses;
return ::stat(path, buf);
}
-
+
++NumStatHits;
PCHStatData Data = *I;
-
+
if (!Data.hasStat)
return 1;
@@ -846,7 +846,7 @@ PCHReader::PCHReadResult PCHReader::ReadSourceManagerBlock() {
}
return Success;
}
-
+
if (Code == llvm::bitc::ENTER_SUBBLOCK) {
// No known subblocks, always skip them.
SLocEntryCursor.ReadSubBlockID();
@@ -856,12 +856,12 @@ PCHReader::PCHReadResult PCHReader::ReadSourceManagerBlock() {
}
continue;
}
-
+
if (Code == llvm::bitc::DEFINE_ABBREV) {
SLocEntryCursor.ReadAbbrevRecord();
continue;
}
-
+
// Read a record.
const char *BlobStart;
unsigned BlobLen;
@@ -871,7 +871,7 @@ PCHReader::PCHReadResult PCHReader::ReadSourceManagerBlock() {
break;
case pch::SM_LINE_TABLE:
- if (ParseLineTable(SourceMgr, Record))
+ if (ParseLineTable(Record))
return Failure;
break;
@@ -924,15 +924,17 @@ PCHReader::PCHReadResult PCHReader::ReadSLocEntryRecord(unsigned ID) {
return Failure;
case pch::SM_SLOC_FILE_ENTRY: {
- const FileEntry *File = FileMgr.getFile(BlobStart, BlobStart + BlobLen);
+ std::string Filename(BlobStart, BlobStart + BlobLen);
+ MaybeAddSystemRootToFilename(Filename);
+ const FileEntry *File = FileMgr.getFile(Filename);
if (File == 0) {
std::string ErrorStr = "could not find file '";
- ErrorStr.append(BlobStart, BlobLen);
+ ErrorStr += Filename;
ErrorStr += "' referenced by PCH file";
Error(ErrorStr.c_str());
return Failure;
}
-
+
FileID FID = SourceMgr.createFileID(File,
SourceLocation::getFromRawEncoding(Record[1]),
(SrcMgr::CharacteristicKind)Record[2],
@@ -949,16 +951,16 @@ PCHReader::PCHReadResult PCHReader::ReadSLocEntryRecord(unsigned ID) {
unsigned Offset = Record[0];
unsigned Code = SLocEntryCursor.ReadCode();
Record.clear();
- unsigned RecCode
+ 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,
+ = 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;
@@ -969,7 +971,7 @@ PCHReader::PCHReadResult PCHReader::ReadSLocEntryRecord(unsigned ID) {
}
case pch::SM_SLOC_INSTANTIATION_ENTRY: {
- SourceLocation SpellingLoc
+ SourceLocation SpellingLoc
= SourceLocation::getFromRawEncoding(Record[1]);
SourceMgr.createInstantiationLoc(SpellingLoc,
SourceLocation::getFromRawEncoding(Record[2]),
@@ -978,7 +980,7 @@ PCHReader::PCHReadResult PCHReader::ReadSLocEntryRecord(unsigned ID) {
ID,
Record[0]);
break;
- }
+ }
}
return Success;
@@ -993,10 +995,10 @@ bool PCHReader::ReadBlockAbbrevs(llvm::BitstreamCursor &Cursor,
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;
@@ -1006,7 +1008,7 @@ bool PCHReader::ReadBlockAbbrevs(llvm::BitstreamCursor &Cursor,
void PCHReader::ReadMacroRecord(uint64_t Offset) {
assert(PP && "Forgot to set Preprocessor ?");
-
+
// Keep track of where we are in the stream, then jump back there
// after reading this macro.
SavedStreamPosition SavedPosition(Stream);
@@ -1015,7 +1017,7 @@ void PCHReader::ReadMacroRecord(uint64_t Offset) {
RecordData Record;
llvm::SmallVector<IdentifierInfo*, 16> MacroArgs;
MacroInfo *Macro = 0;
-
+
while (true) {
unsigned Code = Stream.ReadCode();
switch (Code) {
@@ -1030,7 +1032,7 @@ void PCHReader::ReadMacroRecord(uint64_t Offset) {
return;
}
continue;
-
+
case llvm::bitc::DEFINE_ABBREV:
Stream.ReadAbbrevRecord();
continue;
@@ -1057,10 +1059,10 @@ void PCHReader::ReadMacroRecord(uint64_t Offset) {
}
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];
@@ -1087,12 +1089,12 @@ void PCHReader::ReadMacroRecord(uint64_t Offset) {
++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]));
@@ -1108,7 +1110,33 @@ void PCHReader::ReadMacroRecord(uint64_t Offset) {
}
}
-PCHReader::PCHReadResult
+/// \brief If we are loading a relocatable PCH file, and the filename is
+/// not an absolute path, add the system root to the beginning of the file
+/// name.
+void PCHReader::MaybeAddSystemRootToFilename(std::string &Filename) {
+ // If this is not a relocatable PCH file, there's nothing to do.
+ if (!RelocatablePCH)
+ return;
+
+ if (Filename.empty() || Filename[0] == '/' || Filename[0] == '<')
+ return;
+
+ std::string FIXME = Filename;
+
+ if (isysroot == 0) {
+ // If no system root was given, default to '/'
+ Filename.insert(Filename.begin(), '/');
+ return;
+ }
+
+ unsigned Length = strlen(isysroot);
+ if (isysroot[Length - 1] != '/')
+ Filename.insert(Filename.begin(), '/');
+
+ Filename.insert(Filename.begin(), isysroot, isysroot + Length);
+}
+
+PCHReader::PCHReadResult
PCHReader::ReadPCHBlock() {
if (Stream.EnterSubBlock(pch::PCH_BLOCK_ID)) {
Error("malformed block record in PCH file");
@@ -1151,7 +1179,7 @@ PCHReader::ReadPCHBlock() {
return Failure;
}
break;
-
+
case pch::PREPROCESSOR_BLOCK_ID:
if (Stream.SkipBlock()) {
Error("malformed block record in PCH file");
@@ -1185,7 +1213,7 @@ PCHReader::ReadPCHBlock() {
Record.clear();
const char *BlobStart = 0;
unsigned BlobLen = 0;
- switch ((pch::PCHRecordTypes)Stream.ReadRecord(Code, Record,
+ switch ((pch::PCHRecordTypes)Stream.ReadRecord(Code, Record,
&BlobStart, &BlobLen)) {
default: // Default behavior: ignore.
break;
@@ -1220,6 +1248,7 @@ PCHReader::ReadPCHBlock() {
return IgnorePCH;
}
+ RelocatablePCH = Record[4];
if (Listener) {
std::string TargetTriple(BlobStart, BlobLen);
if (Listener->ReadTargetTriple(TargetTriple))
@@ -1231,10 +1260,10 @@ PCHReader::ReadPCHBlock() {
case pch::IDENTIFIER_TABLE:
IdentifierTableData = BlobStart;
if (Record[0]) {
- IdentifierLookupTable
+ IdentifierLookupTable
= PCHIdentifierLookupTable::Create(
(const unsigned char *)IdentifierTableData + Record[0],
- (const unsigned char *)IdentifierTableData,
+ (const unsigned char *)IdentifierTableData,
PCHIdentifierLookupTrait(*this));
if (PP)
PP->getIdentifierTable().setExternalIdentifierLookup(this);
@@ -1296,10 +1325,10 @@ PCHReader::ReadPCHBlock() {
case pch::METHOD_POOL:
MethodPoolLookupTableData = (const unsigned char *)BlobStart;
if (Record[0])
- MethodPoolLookupTable
+ MethodPoolLookupTable
= PCHMethodPoolLookupTable::Create(
MethodPoolLookupTableData + Record[0],
- MethodPoolLookupTableData,
+ MethodPoolLookupTableData,
PCHMethodPoolLookupTrait(*this));
TotalSelectorsInMethodPool = Record[1];
break;
@@ -1312,9 +1341,7 @@ PCHReader::ReadPCHBlock() {
case pch::SOURCE_LOCATION_OFFSETS:
SLocOffsets = (const uint32_t *)BlobStart;
TotalNumSLocEntries = Record[0];
- SourceMgr.PreallocateSLocEntries(this,
- TotalNumSLocEntries,
- Record[1]);
+ SourceMgr.PreallocateSLocEntries(this, TotalNumSLocEntries, Record[1]);
break;
case pch::SOURCE_LOCATION_PRELOADS:
@@ -1340,22 +1367,32 @@ PCHReader::ReadPCHBlock() {
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);
+ MaybeAddSystemRootToFilename(OriginalFileName);
break;
-
+
case pch::COMMENT_RANGES:
Comments = (SourceRange *)BlobStart;
NumComments = BlobLen / sizeof(SourceRange);
break;
+
+ case pch::SVN_BRANCH_REVISION: {
+ unsigned CurRevision = getClangSubversionRevision();
+ if (Record[0] && CurRevision && Record[0] != CurRevision) {
+ Diag(Record[0] < CurRevision? diag::warn_pch_version_too_old
+ : diag::warn_pch_version_too_new);
+ return IgnorePCH;
+ }
+
+ const char *CurBranch = getClangSubversionPath();
+ if (strncmp(CurBranch, BlobStart, BlobLen)) {
+ std::string PCHBranch(BlobStart, BlobLen);
+ Diag(diag::warn_pch_different_branch) << PCHBranch << CurBranch;
+ return IgnorePCH;
+ }
+ break;
+ }
}
}
Error("premature end of bitstream in PCH file");
@@ -1367,15 +1404,20 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) {
this->FileName = FileName;
// Open the PCH file.
+ //
+ // FIXME: This shouldn't be here, we should just take a raw_ostream.
std::string ErrStr;
- Buffer.reset(llvm::MemoryBuffer::getFile(FileName.c_str(), &ErrStr));
+ if (FileName == "-")
+ Buffer.reset(llvm::MemoryBuffer::getSTDIN());
+ else
+ 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(),
+ StreamFile.init((const unsigned char *)Buffer->getBufferStart(),
(const unsigned char *)Buffer->getBufferEnd());
Stream.init(StreamFile);
@@ -1390,7 +1432,7 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) {
while (!Stream.AtEndOfStream()) {
unsigned Code = Stream.ReadCode();
-
+
if (Code != llvm::bitc::ENTER_SUBBLOCK) {
Error("invalid record at top-level of PCH file");
return Failure;
@@ -1436,15 +1478,15 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) {
}
break;
}
- }
-
+ }
+
// Check the predefines buffer.
- if (CheckPredefinesBuffer(PCHPredefines, PCHPredefinesLen,
+ if (CheckPredefinesBuffer(PCHPredefines, PCHPredefinesLen,
PCHPredefinesBufferID))
return IgnorePCH;
-
+
if (PP) {
- // Initialization of builtins and library builtins occurs before the
+ // Initialization of keywords and pragmas 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
@@ -1461,7 +1503,7 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) {
IdEnd = PP->getIdentifierTable().end();
Id != IdEnd; ++Id)
Identifiers.push_back(Id->second);
- PCHIdentifierLookupTable *IdTable
+ PCHIdentifierLookupTable *IdTable
= (PCHIdentifierLookupTable *)IdentifierLookupTable;
for (unsigned I = 0, N = Identifiers.size(); I != N; ++I) {
IdentifierInfo *II = Identifiers[I];
@@ -1471,7 +1513,7 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) {
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;
@@ -1491,7 +1533,7 @@ void PCHReader::InitializeContext(ASTContext &Ctx) {
assert(PP && "Forgot to set Preprocessor ?");
PP->getIdentifierTable().setExternalIdentifierLookup(this);
PP->getHeaderSearchInfo().SetExternalLookup(this);
-
+
// Load the translation unit declaration
ReadDeclRecord(DeclOffsets[0], 0);
@@ -1506,11 +1548,51 @@ void PCHReader::InitializeContext(ASTContext &Ctx) {
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
+ if (unsigned FastEnum
= SpecialTypes[pch::SPECIAL_TYPE_OBJC_FAST_ENUMERATION_STATE])
Context->setObjCFastEnumerationStateType(GetType(FastEnum));
+ if (unsigned File = SpecialTypes[pch::SPECIAL_TYPE_FILE]) {
+ QualType FileType = GetType(File);
+ assert(!FileType.isNull() && "FILE type is NULL");
+ if (const TypedefType *Typedef = FileType->getAs<TypedefType>())
+ Context->setFILEDecl(Typedef->getDecl());
+ else {
+ const TagType *Tag = FileType->getAs<TagType>();
+ assert(Tag && "Invalid FILE type in PCH file");
+ Context->setFILEDecl(Tag->getDecl());
+ }
+ }
+ if (unsigned Jmp_buf = SpecialTypes[pch::SPECIAL_TYPE_jmp_buf]) {
+ QualType Jmp_bufType = GetType(Jmp_buf);
+ assert(!Jmp_bufType.isNull() && "jmp_bug type is NULL");
+ if (const TypedefType *Typedef = Jmp_bufType->getAs<TypedefType>())
+ Context->setjmp_bufDecl(Typedef->getDecl());
+ else {
+ const TagType *Tag = Jmp_bufType->getAs<TagType>();
+ assert(Tag && "Invalid jmp_bug type in PCH file");
+ Context->setjmp_bufDecl(Tag->getDecl());
+ }
+ }
+ if (unsigned Sigjmp_buf = SpecialTypes[pch::SPECIAL_TYPE_sigjmp_buf]) {
+ QualType Sigjmp_bufType = GetType(Sigjmp_buf);
+ assert(!Sigjmp_bufType.isNull() && "sigjmp_buf type is NULL");
+ if (const TypedefType *Typedef = Sigjmp_bufType->getAs<TypedefType>())
+ Context->setsigjmp_bufDecl(Typedef->getDecl());
+ else {
+ const TagType *Tag = Sigjmp_bufType->getAs<TagType>();
+ assert(Tag && "Invalid sigjmp_buf type in PCH file");
+ Context->setsigjmp_bufDecl(Tag->getDecl());
+ }
+ }
+ if (unsigned ObjCIdRedef
+ = SpecialTypes[pch::SPECIAL_TYPE_OBJC_ID_REDEFINITION])
+ Context->ObjCIdRedefinitionType = GetType(ObjCIdRedef);
+ if (unsigned ObjCClassRedef
+ = SpecialTypes[pch::SPECIAL_TYPE_OBJC_CLASS_REDEFINITION])
+ Context->ObjCClassRedefinitionType = GetType(ObjCClassRedef);
}
/// \brief Retrieve the name of the original source file name
@@ -1529,7 +1611,7 @@ std::string PCHReader::getOriginalSourceFile(const std::string &PCHFileName) {
// Initialize the stream
llvm::BitstreamReader StreamFile;
llvm::BitstreamCursor Stream;
- StreamFile.init((const unsigned char *)Buffer->getBufferStart(),
+ StreamFile.init((const unsigned char *)Buffer->getBufferStart(),
(const unsigned char *)Buffer->getBufferEnd());
Stream.init(StreamFile);
@@ -1538,7 +1620,7 @@ std::string PCHReader::getOriginalSourceFile(const std::string &PCHFileName) {
Stream.Read(8) != 'P' ||
Stream.Read(8) != 'C' ||
Stream.Read(8) != 'H') {
- fprintf(stderr,
+ fprintf(stderr,
"error: '%s' does not appear to be a precompiled header file\n",
PCHFileName.c_str());
return std::string();
@@ -1547,10 +1629,10 @@ std::string PCHReader::getOriginalSourceFile(const std::string &PCHFileName) {
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:
@@ -1559,7 +1641,7 @@ std::string PCHReader::getOriginalSourceFile(const std::string &PCHFileName) {
return std::string();
}
break;
-
+
default:
if (Stream.SkipBlock()) {
fprintf(stderr, "error: malformed block record in PCH file\n");
@@ -1586,10 +1668,10 @@ std::string PCHReader::getOriginalSourceFile(const std::string &PCHFileName) {
Record.clear();
const char *BlobStart = 0;
unsigned BlobLen = 0;
- if (Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen)
+ if (Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen)
== pch::ORIGINAL_FILE_NAME)
return std::string(BlobStart, BlobLen);
- }
+ }
return std::string();
}
@@ -1612,11 +1694,11 @@ bool PCHReader::ParseLanguageOptions(
const llvm::SmallVectorImpl<uint64_t> &Record) {
if (Listener) {
LangOptions LangOpts;
-
+
#define PARSE_LANGOPT(Option) \
LangOpts.Option = Record[Idx]; \
++Idx
-
+
unsigned Idx = 0;
PARSE_LANGOPT(Trigraphs);
PARSE_LANGOPT(BCPLComment);
@@ -1643,6 +1725,7 @@ bool PCHReader::ParseLanguageOptions(
PARSE_LANGOPT(Freestanding);
PARSE_LANGOPT(NoBuiltin);
PARSE_LANGOPT(ThreadsafeStatics);
+ PARSE_LANGOPT(POSIXThreads);
PARSE_LANGOPT(Blocks);
PARSE_LANGOPT(EmitAllDecls);
PARSE_LANGOPT(MathErrno);
@@ -1660,6 +1743,9 @@ bool PCHReader::ParseLanguageOptions(
++Idx;
LangOpts.setVisibilityMode((LangOptions::VisibilityMode)Record[Idx]);
++Idx;
+ LangOpts.setStackProtectorMode((LangOptions::StackProtectorMode)
+ Record[Idx]);
+ ++Idx;
PARSE_LANGOPT(InstantiationDepth);
PARSE_LANGOPT(OpenCL);
#undef PARSE_LANGOPT
@@ -1686,23 +1772,19 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
// after reading this type.
SavedStreamPosition SavedPosition(Stream);
+ // Note that we are loading a type record.
+ LoadingTypeOrDecl Loading(*this);
+
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 &&
+ assert(Record.size() == 2 &&
"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;
+ Qualifiers Quals = Qualifiers::fromOpaqueValue(Record[1]);
+ return Context->getQualifiedType(Base, Quals);
}
case pch::TYPE_FIXED_WIDTH_INT: {
@@ -1753,7 +1835,32 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
unsigned IndexTypeQuals = Record[2];
unsigned Idx = 3;
llvm::APInt Size = ReadAPInt(Record, Idx);
- return Context->getConstantArrayType(ElementType, Size, ASM,IndexTypeQuals);
+ return Context->getConstantArrayType(ElementType, Size,
+ ASM, IndexTypeQuals);
+ }
+
+ case pch::TYPE_CONSTANT_ARRAY_WITH_EXPR: {
+ QualType ElementType = GetType(Record[0]);
+ ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1];
+ unsigned IndexTypeQuals = Record[2];
+ SourceLocation LBLoc = SourceLocation::getFromRawEncoding(Record[3]);
+ SourceLocation RBLoc = SourceLocation::getFromRawEncoding(Record[4]);
+ unsigned Idx = 5;
+ llvm::APInt Size = ReadAPInt(Record, Idx);
+ return Context->getConstantArrayWithExprType(ElementType,
+ Size, ReadTypeExpr(),
+ ASM, IndexTypeQuals,
+ SourceRange(LBLoc, RBLoc));
+ }
+
+ case pch::TYPE_CONSTANT_ARRAY_WITHOUT_EXPR: {
+ 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->getConstantArrayWithoutExprType(ElementType, Size,
+ ASM, IndexTypeQuals);
}
case pch::TYPE_INCOMPLETE_ARRAY: {
@@ -1767,8 +1874,11 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
QualType ElementType = GetType(Record[0]);
ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1];
unsigned IndexTypeQuals = Record[2];
+ SourceLocation LBLoc = SourceLocation::getFromRawEncoding(Record[3]);
+ SourceLocation RBLoc = SourceLocation::getFromRawEncoding(Record[4]);
return Context->getVariableArrayType(ElementType, ReadTypeExpr(),
- ASM, IndexTypeQuals);
+ ASM, IndexTypeQuals,
+ SourceRange(LBLoc, RBLoc));
}
case pch::TYPE_VECTOR: {
@@ -1838,7 +1948,7 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
QualType UnderlyingType = GetType(Record[0]);
return Context->getTypeOfType(UnderlyingType);
}
-
+
case pch::TYPE_DECLTYPE:
return Context->getDecltypeType(ReadTypeExpr());
@@ -1850,30 +1960,41 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
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_ELABORATED: {
+ assert(Record.size() == 2 && "incorrect encoding of elaborated type");
+ unsigned Tag = Record[1];
+ return Context->getElaboratedType(GetType(Record[0]),
+ (ElaboratedType::TagKind) Tag);
+ }
- case pch::TYPE_OBJC_QUALIFIED_INTERFACE: {
+ case pch::TYPE_OBJC_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);
+ return Context->getObjCInterfaceType(ItfD, Protos.data(), NumProtos);
}
case pch::TYPE_OBJC_OBJECT_POINTER: {
unsigned Idx = 0;
- ObjCInterfaceDecl *ItfD =
- cast_or_null<ObjCInterfaceDecl>(GetDecl(Record[Idx++]));
+ QualType OIT = GetType(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->getObjCObjectPointerType(OIT, Protos.data(), NumProtos);
+ }
+
+ case pch::TYPE_OBJC_PROTOCOL_LIST: {
+ unsigned Idx = 0;
+ QualType OIT = GetType(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->getObjCObjectPointerType(ItfD, Protos.data(), NumProtos);
+ return Context->getObjCProtocolListType(OIT, Protos.data(), NumProtos);
}
}
// Suppress a GCC warning
@@ -1882,8 +2003,8 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
QualType PCHReader::GetType(pch::TypeID ID) {
- unsigned Quals = ID & 0x07;
- unsigned Index = ID >> 3;
+ unsigned FastQuals = ID & Qualifiers::FastMask;
+ unsigned Index = ID >> Qualifiers::FastWidth;
if (Index < pch::NUM_PREDEF_TYPE_IDS) {
QualType T;
@@ -1917,18 +2038,22 @@ QualType PCHReader::GetType(pch::TypeID ID) {
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;
+ case pch::PREDEF_TYPE_CHAR16_ID: T = Context->Char16Ty; break;
+ case pch::PREDEF_TYPE_CHAR32_ID: T = Context->Char32Ty; break;
+ case pch::PREDEF_TYPE_OBJC_ID: T = Context->ObjCBuiltinIdTy; break;
+ case pch::PREDEF_TYPE_OBJC_CLASS: T = Context->ObjCBuiltinClassTy; break;
}
assert(!T.isNull() && "Unknown predefined type");
- return T.getQualifiedType(Quals);
+ return T.withFastQualifiers(FastQuals);
}
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);
+ //assert(Index < TypesLoaded.size() && "Type index out-of-range");
+ if (TypesLoaded[Index].isNull())
+ TypesLoaded[Index] = ReadTypeRecord(TypeOffsets[Index]);
+
+ return TypesLoaded[Index].withFastQualifiers(FastQuals);
}
Decl *PCHReader::GetDecl(pch::DeclID ID) {
@@ -1961,7 +2086,7 @@ Stmt *PCHReader::GetDeclStmt(uint64_t Offset) {
bool PCHReader::ReadDeclsLexicallyInContext(DeclContext *DC,
llvm::SmallVectorImpl<pch::DeclID> &Decls) {
- assert(DC->hasExternalLexicalStorage() &&
+ 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");
@@ -1988,7 +2113,7 @@ bool PCHReader::ReadDeclsLexicallyInContext(DeclContext *DC,
bool PCHReader::ReadDeclsVisibleInContext(DeclContext *DC,
llvm::SmallVectorImpl<VisibleDeclaration> &Decls) {
- assert(DC->hasExternalVisibleStorage() &&
+ 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");
@@ -2006,7 +2131,7 @@ bool PCHReader::ReadDeclsVisibleInContext(DeclContext *DC,
(void)RecCode;
assert(RecCode == pch::DECL_CONTEXT_VISIBLE && "Expected visible block");
if (Record.size() == 0)
- return false;
+ return false;
Decls.clear();
@@ -2033,9 +2158,9 @@ void PCHReader::StartTranslationUnit(ASTConsumer *Consumer) {
return;
for (unsigned I = 0, N = ExternalDefinitions.size(); I != N; ++I) {
- Decl *D = GetDecl(ExternalDefinitions[I]);
- DeclGroupRef DG(D);
- Consumer->HandleTopLevelDecl(DG);
+ // Force deserialization of this decl, which will cause it to be passed to
+ // the consumer (or queued).
+ GetDecl(ExternalDefinitions[I]);
}
for (unsigned I = 0, N = InterestingDecls.size(); I != N; ++I) {
@@ -2047,9 +2172,9 @@ void PCHReader::StartTranslationUnit(ASTConsumer *Consumer) {
void PCHReader::PrintStats() {
std::fprintf(stderr, "*** PCH Statistics:\n");
- unsigned NumTypesLoaded
+ unsigned NumTypesLoaded
= TypesLoaded.size() - std::count(TypesLoaded.begin(), TypesLoaded.end(),
- (Type *)0);
+ QualType());
unsigned NumDeclsLoaded
= DeclsLoaded.size() - std::count(DeclsLoaded.begin(), DeclsLoaded.end(),
(Decl *)0);
@@ -2057,7 +2182,7 @@ void PCHReader::PrintStats() {
= IdentifiersLoaded.size() - std::count(IdentifiersLoaded.begin(),
IdentifiersLoaded.end(),
(IdentifierInfo *)0);
- unsigned NumSelectorsLoaded
+ unsigned NumSelectorsLoaded
= SelectorsLoaded.size() - std::count(SelectorsLoaded.begin(),
SelectorsLoaded.end(),
Selector());
@@ -2129,6 +2254,7 @@ void PCHReader::InitializeSema(Sema &S) {
for (unsigned I = 0, N = TentativeDefinitions.size(); I != N; ++I) {
VarDecl *Var = cast<VarDecl>(GetDecl(TentativeDefinitions[I]));
SemaObj->TentativeDefinitions[Var->getDeclName()] = Var;
+ SemaObj->TentativeDefinitionList.push_back(Var->getDeclName());
}
// If there were any locally-scoped external declarations,
@@ -2144,18 +2270,11 @@ void PCHReader::InitializeSema(Sema &S) {
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 *IdTable
= (PCHIdentifierLookupTable *)IdentifierLookupTable;
std::pair<const char*, unsigned> Key(NameStart, NameEnd - NameStart);
PCHIdentifierLookupTable::iterator Pos = IdTable->find(Key);
@@ -2168,7 +2287,7 @@ IdentifierInfo* PCHReader::get(const char *NameStart, const char *NameEnd) {
return *Pos;
}
-std::pair<ObjCMethodList, ObjCMethodList>
+std::pair<ObjCMethodList, ObjCMethodList>
PCHReader::ReadMethodPool(Selector Sel) {
if (!MethodPoolLookupTable)
return std::pair<ObjCMethodList, ObjCMethodList>();
@@ -2192,15 +2311,61 @@ void PCHReader::SetIdentifierInfo(unsigned ID, IdentifierInfo *II) {
IdentifiersLoaded[ID - 1] = II;
}
+/// \brief Set the globally-visible declarations associated with the given
+/// identifier.
+///
+/// If the PCH reader is currently in a state where the given declaration IDs
+/// cannot safely be resolved, they are queued until it is safe to resolve
+/// them.
+///
+/// \param II an IdentifierInfo that refers to one or more globally-visible
+/// declarations.
+///
+/// \param DeclIDs the set of declaration IDs with the name @p II that are
+/// visible at global scope.
+///
+/// \param Nonrecursive should be true to indicate that the caller knows that
+/// this call is non-recursive, and therefore the globally-visible declarations
+/// will not be placed onto the pending queue.
+void
+PCHReader::SetGloballyVisibleDecls(IdentifierInfo *II,
+ const llvm::SmallVectorImpl<uint32_t> &DeclIDs,
+ bool Nonrecursive) {
+ if (CurrentlyLoadingTypeOrDecl && !Nonrecursive) {
+ PendingIdentifierInfos.push_back(PendingIdentifierInfo());
+ PendingIdentifierInfo &PII = PendingIdentifierInfos.back();
+ PII.II = II;
+ for (unsigned I = 0, N = DeclIDs.size(); I != N; ++I)
+ PII.DeclIDs.push_back(DeclIDs[I]);
+ return;
+ }
+
+ for (unsigned I = 0, N = DeclIDs.size(); I != N; ++I) {
+ NamedDecl *D = cast<NamedDecl>(GetDecl(DeclIDs[I]));
+ 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.
+ PreloadedDecls.push_back(D);
+ }
+ }
+}
+
IdentifierInfo *PCHReader::DecodeIdentifierInfo(unsigned ID) {
if (ID == 0)
return 0;
-
+
if (!IdentifierTableData || IdentifiersLoaded.empty()) {
Error("no identifier table in PCH file");
return 0;
}
-
+
assert(PP && "Forgot to set Preprocessor ?");
if (!IdentifiersLoaded[ID - 1]) {
uint32_t Offset = IdentifierOffsets[ID - 1];
@@ -2212,10 +2377,10 @@ IdentifierInfo *PCHReader::DecodeIdentifierInfo(unsigned ID) {
const char *StrLenPtr = Str - 2;
unsigned StrLen = (((unsigned) StrLenPtr[0])
| (((unsigned) StrLenPtr[1]) << 8)) - 1;
- IdentifiersLoaded[ID - 1]
+ IdentifiersLoaded[ID - 1]
= &PP->getIdentifierTable().get(Str, Str + StrLen);
}
-
+
return IdentifiersLoaded[ID - 1];
}
@@ -2226,7 +2391,7 @@ void PCHReader::ReadSLocEntry(unsigned ID) {
Selector PCHReader::DecodeSelector(unsigned ID) {
if (ID == 0)
return Selector();
-
+
if (!MethodPoolLookupTableData)
return Selector();
@@ -2240,14 +2405,14 @@ Selector PCHReader::DecodeSelector(unsigned ID) {
// Load this selector from the selector table.
// FIXME: endianness portability issues with SelectorOffsets table
PCHMethodPoolLookupTrait Trait(*this);
- SelectorsLoaded[Index]
+ SelectorsLoaded[Index]
= Trait.ReadKey(MethodPoolLookupTableData + SelectorOffsets[Index], 0);
}
return SelectorsLoaded[Index];
}
-DeclarationName
+DeclarationName
PCHReader::ReadDeclarationName(const RecordData &Record, unsigned &Idx) {
DeclarationName::NameKind Kind = (DeclarationName::NameKind)Record[Idx++];
switch (Kind) {
@@ -2261,15 +2426,15 @@ PCHReader::ReadDeclarationName(const RecordData &Record, unsigned &Idx) {
case DeclarationName::CXXConstructorName:
return Context->DeclarationNames.getCXXConstructorName(
- GetType(Record[Idx++]));
+ Context->getCanonicalType(GetType(Record[Idx++])));
case DeclarationName::CXXDestructorName:
return Context->DeclarationNames.getCXXDestructorName(
- GetType(Record[Idx++]));
+ Context->getCanonicalType(GetType(Record[Idx++])));
case DeclarationName::CXXConversionFunctionName:
return Context->DeclarationNames.getCXXConversionFunctionName(
- GetType(Record[Idx++]));
+ Context->getCanonicalType(GetType(Record[Idx++])));
case DeclarationName::CXXOperatorName:
return Context->DeclarationNames.getCXXOperatorName(
@@ -2342,7 +2507,7 @@ SwitchCase *PCHReader::getSwitchCaseWithID(unsigned 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() &&
+ assert(LabelStmts.find(ID) == LabelStmts.end() &&
"Deserialized label twice");
LabelStmts[ID] = S;
@@ -2357,9 +2522,9 @@ void PCHReader::RecordLabelStmt(LabelStmt *S, unsigned ID) {
// 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
+ std::pair<AddrLabelIter, AddrLabelIter> AddrLabels
= UnresolvedAddrLabelExprs.equal_range(ID);
- for (AddrLabelIter AddrLabel = AddrLabels.first;
+ for (AddrLabelIter AddrLabel = AddrLabels.first;
AddrLabel != AddrLabels.second; ++AddrLabel)
AddrLabel->second->setLabel(S);
UnresolvedAddrLabelExprs.erase(AddrLabels.first, AddrLabels.second);
@@ -2404,3 +2569,24 @@ void PCHReader::SetLabelOf(AddrLabelExpr *S, unsigned ID) {
UnresolvedAddrLabelExprs.insert(std::make_pair(ID, S));
}
}
+
+
+PCHReader::LoadingTypeOrDecl::LoadingTypeOrDecl(PCHReader &Reader)
+ : Reader(Reader), Parent(Reader.CurrentlyLoadingTypeOrDecl) {
+ Reader.CurrentlyLoadingTypeOrDecl = this;
+}
+
+PCHReader::LoadingTypeOrDecl::~LoadingTypeOrDecl() {
+ if (!Parent) {
+ // If any identifiers with corresponding top-level declarations have
+ // been loaded, load those declarations now.
+ while (!Reader.PendingIdentifierInfos.empty()) {
+ Reader.SetGloballyVisibleDecls(Reader.PendingIdentifierInfos.front().II,
+ Reader.PendingIdentifierInfos.front().DeclIDs,
+ true);
+ Reader.PendingIdentifierInfos.pop_front();
+ }
+ }
+
+ Reader.CurrentlyLoadingTypeOrDecl = Parent;
+}
diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp
index 15b54a2..353a646 100644
--- a/lib/Frontend/PCHReaderDecl.cpp
+++ b/lib/Frontend/PCHReaderDecl.cpp
@@ -18,6 +18,7 @@
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/DeclGroup.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/TypeLocVisitor.h"
using namespace clang;
@@ -46,6 +47,7 @@ namespace {
void VisitRecordDecl(RecordDecl *RD);
void VisitValueDecl(ValueDecl *VD);
void VisitEnumConstantDecl(EnumConstantDecl *ECD);
+ void VisitDeclaratorDecl(DeclaratorDecl *DD);
void VisitFunctionDecl(FunctionDecl *FD);
void VisitFieldDecl(FieldDecl *FD);
void VisitVarDecl(VarDecl *VD);
@@ -92,7 +94,7 @@ void PCHDeclReader::VisitTranslationUnitDecl(TranslationUnitDecl *TU) {
void PCHDeclReader::VisitNamedDecl(NamedDecl *ND) {
VisitDecl(ND);
- ND->setDeclName(Reader.ReadDeclarationName(Record, Idx));
+ ND->setDeclName(Reader.ReadDeclarationName(Record, Idx));
}
void PCHDeclReader::VisitTypeDecl(TypeDecl *TD) {
@@ -112,10 +114,14 @@ void PCHDeclReader::VisitTypedefDecl(TypedefDecl *TD) {
void PCHDeclReader::VisitTagDecl(TagDecl *TD) {
VisitTypeDecl(TD);
+ TD->setPreviousDeclaration(
+ cast_or_null<TagDecl>(Reader.GetDecl(Record[Idx++])));
TD->setTagKind((TagDecl::TagKind)Record[Idx++]);
TD->setDefinition(Record[Idx++]);
TD->setTypedefForAnonDecl(
cast_or_null<TypedefDecl>(Reader.GetDecl(Record[Idx++])));
+ TD->setRBraceLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ TD->setTagKeywordLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
}
void PCHDeclReader::VisitEnumDecl(EnumDecl *ED) {
@@ -128,6 +134,7 @@ void PCHDeclReader::VisitRecordDecl(RecordDecl *RD) {
VisitTagDecl(RD);
RD->setHasFlexibleArrayMember(Record[Idx++]);
RD->setAnonymousStructOrUnion(Record[Idx++]);
+ RD->setHasObjectMember(Record[Idx++]);
}
void PCHDeclReader::VisitValueDecl(ValueDecl *VD) {
@@ -142,21 +149,99 @@ void PCHDeclReader::VisitEnumConstantDecl(EnumConstantDecl *ECD) {
ECD->setInitVal(Reader.ReadAPSInt(Record, Idx));
}
+namespace {
+
+class TypeLocReader : public TypeLocVisitor<TypeLocReader> {
+ PCHReader &Reader;
+ const PCHReader::RecordData &Record;
+ unsigned &Idx;
+
+public:
+ TypeLocReader(PCHReader &Reader, const PCHReader::RecordData &Record,
+ unsigned &Idx)
+ : Reader(Reader), Record(Record), Idx(Idx) { }
+
+#define ABSTRACT_TYPELOC(CLASS)
+#define TYPELOC(CLASS, PARENT, TYPE) \
+ void Visit##CLASS(CLASS TyLoc);
+#include "clang/AST/TypeLocNodes.def"
+
+ void VisitTypeLoc(TypeLoc TyLoc) {
+ assert(0 && "A type loc wrapper was not handled!");
+ }
+};
+
+}
+
+void TypeLocReader::VisitDefaultTypeSpecLoc(DefaultTypeSpecLoc TyLoc) {
+ TyLoc.setStartLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+void TypeLocReader::VisitTypedefLoc(TypedefLoc TyLoc) {
+ TyLoc.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+void TypeLocReader::VisitObjCInterfaceLoc(ObjCInterfaceLoc TyLoc) {
+ TyLoc.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+void TypeLocReader::VisitObjCProtocolListLoc(ObjCProtocolListLoc TyLoc) {
+ TyLoc.setLAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ TyLoc.setRAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ for (unsigned i = 0, e = TyLoc.getNumProtocols(); i != e; ++i)
+ TyLoc.setProtocolLoc(i, SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+void TypeLocReader::VisitPointerLoc(PointerLoc TyLoc) {
+ TyLoc.setStarLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+void TypeLocReader::VisitBlockPointerLoc(BlockPointerLoc TyLoc) {
+ TyLoc.setCaretLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+void TypeLocReader::VisitMemberPointerLoc(MemberPointerLoc TyLoc) {
+ TyLoc.setStarLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+void TypeLocReader::VisitReferenceLoc(ReferenceLoc TyLoc) {
+ TyLoc.setAmpLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+void TypeLocReader::VisitFunctionLoc(FunctionLoc TyLoc) {
+ TyLoc.setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ TyLoc.setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ for (unsigned i = 0, e = TyLoc.getNumArgs(); i != e; ++i)
+ TyLoc.setArg(i, cast<ParmVarDecl>(Reader.GetDecl(Record[Idx++])));
+}
+void TypeLocReader::VisitArrayLoc(ArrayLoc TyLoc) {
+ TyLoc.setLBracketLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ TyLoc.setRBracketLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ if (Record[Idx++])
+ TyLoc.setSizeExpr(Reader.ReadDeclExpr());
+}
+
+void PCHDeclReader::VisitDeclaratorDecl(DeclaratorDecl *DD) {
+ VisitValueDecl(DD);
+ QualType InfoTy = Reader.GetType(Record[Idx++]);
+ if (InfoTy.isNull())
+ return;
+
+ DeclaratorInfo *DInfo = Reader.getContext()->CreateDeclaratorInfo(InfoTy);
+ TypeLocReader TLR(Reader, Record, Idx);
+ for (TypeLoc TL = DInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc())
+ TLR.Visit(TL);
+ DD->setDeclaratorInfo(DInfo);
+}
+
void PCHDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
- VisitValueDecl(FD);
+ VisitDeclaratorDecl(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++]));
+ FD->setTrivial(Record[Idx++]);
+ FD->setCopyAssignment(Record[Idx++]);
+ FD->setHasImplicitReturnZero(Record[Idx++]);
FD->setLocEnd(SourceLocation::getFromRawEncoding(Record[Idx++]));
// FIXME: C++ TemplateOrInstantiation
unsigned NumParams = Record[Idx++];
@@ -219,7 +304,7 @@ void PCHDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) {
ID->setImplicitInterfaceDecl(Record[Idx++]);
ID->setClassLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
ID->setSuperClassLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
- ID->setAtEndLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ ID->setLocEnd(SourceLocation::getFromRawEncoding(Record[Idx++]));
}
void PCHDeclReader::VisitObjCIvarDecl(ObjCIvarDecl *IVD) {
@@ -301,10 +386,9 @@ void PCHDeclReader::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
}
void PCHDeclReader::VisitObjCImplDecl(ObjCImplDecl *D) {
- VisitNamedDecl(D);
+ VisitObjCContainerDecl(D);
D->setClassInterface(
cast_or_null<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++])));
- D->setLocEnd(SourceLocation::getFromRawEncoding(Record[Idx++]));
}
void PCHDeclReader::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
@@ -329,21 +413,20 @@ void PCHDeclReader::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
}
void PCHDeclReader::VisitFieldDecl(FieldDecl *FD) {
- VisitValueDecl(FD);
+ VisitDeclaratorDecl(FD);
FD->setMutable(Record[Idx++]);
if (Record[Idx++])
FD->setBitWidth(Reader.ReadDeclExpr());
}
void PCHDeclReader::VisitVarDecl(VarDecl *VD) {
- VisitValueDecl(VD);
+ VisitDeclaratorDecl(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());
}
@@ -355,7 +438,6 @@ void PCHDeclReader::VisitImplicitParamDecl(ImplicitParamDecl *PD) {
void PCHDeclReader::VisitParmVarDecl(ParmVarDecl *PD) {
VisitVarDecl(PD);
PD->setObjCDeclQualifier((Decl::ObjCDeclQualifier)Record[Idx++]);
- // FIXME: default argument (C++ only)
}
void PCHDeclReader::VisitOriginalParmVarDecl(OriginalParmVarDecl *PD) {
@@ -376,10 +458,10 @@ void PCHDeclReader::VisitBlockDecl(BlockDecl *BD) {
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);
+ BD->setParams(*Reader.getContext(), Params.data(), NumParams);
}
-std::pair<uint64_t, uint64_t>
+std::pair<uint64_t, uint64_t>
PCHDeclReader::VisitDeclContext(DeclContext *DC) {
uint64_t LexicalOffset = Record[Idx++];
uint64_t VisibleOffset = Record[Idx++];
@@ -393,13 +475,13 @@ PCHDeclReader::VisitDeclContext(DeclContext *DC) {
/// \brief Reads attributes from the current stream position.
Attr *PCHReader::ReadAttributes() {
unsigned Code = DeclsCursor.ReadCode();
- assert(Code == llvm::bitc::UNABBREV_RECORD &&
+ 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");
+ assert(RecCode == pch::DECL_ATTR && "Expected attribute record");
(void)RecCode;
#define SIMPLE_ATTR(Name) \
@@ -430,12 +512,12 @@ Attr *PCHReader::ReadAttributes() {
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++])));
@@ -448,7 +530,7 @@ Attr *PCHReader::ReadAttributes() {
SIMPLE_ATTR(Deprecated);
UNSIGNED_ATTR(Destructor);
SIMPLE_ATTR(FastCall);
-
+
case Attr::Format: {
std::string Type = ReadString(Record, Idx);
unsigned FormatIdx = Record[Idx++];
@@ -456,13 +538,13 @@ Attr *PCHReader::ReadAttributes() {
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++];
@@ -471,16 +553,17 @@ Attr *PCHReader::ReadAttributes() {
}
SIMPLE_ATTR(GNUInline);
-
+
case Attr::IBOutletKind:
New = ::new (*Context) IBOutletAttr();
break;
+ SIMPLE_ATTR(Malloc);
+ SIMPLE_ATTR(NoDebug);
+ SIMPLE_ATTR(NoInline);
SIMPLE_ATTR(NoReturn);
SIMPLE_ATTR(NoThrow);
- SIMPLE_ATTR(Nodebug);
- SIMPLE_ATTR(Noinline);
-
+
case Attr::NonNull: {
unsigned Size = Record[Idx++];
llvm::SmallVector<unsigned, 16> ArgNums;
@@ -489,7 +572,7 @@ Attr *PCHReader::ReadAttributes() {
New = ::new (*Context) NonNullAttr(ArgNums.data(), Size);
break;
}
-
+
case Attr::ReqdWorkGroupSize: {
unsigned X = Record[Idx++];
unsigned Y = Record[Idx++];
@@ -503,7 +586,8 @@ Attr *PCHReader::ReadAttributes() {
SIMPLE_ATTR(CFReturnsRetained);
SIMPLE_ATTR(NSReturnsRetained);
SIMPLE_ATTR(Overloadable);
- UNSIGNED_ATTR(Packed);
+ SIMPLE_ATTR(Packed);
+ UNSIGNED_ATTR(PragmaPack);
SIMPLE_ATTR(Pure);
UNSIGNED_ATTR(Regparm);
STRING_ATTR(Section);
@@ -512,7 +596,7 @@ Attr *PCHReader::ReadAttributes() {
SIMPLE_ATTR(Unavailable);
SIMPLE_ATTR(Unused);
SIMPLE_ATTR(Used);
-
+
case Attr::Visibility:
New = ::new (*Context) VisibilityAttr(
(VisibilityAttr::VisibilityTypes)Record[Idx++]);
@@ -551,7 +635,7 @@ Attr *PCHReader::ReadAttributes() {
/// \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.
@@ -568,6 +652,8 @@ inline void PCHReader::LoadedDecl(unsigned Index, Decl *D) {
/// code generation, e.g., inline function definitions, Objective-C
/// declarations with metadata, etc.
static bool isConsumerInterestedIn(Decl *D) {
+ if (isa<FileScopeAsmDecl>(D))
+ return true;
if (VarDecl *Var = dyn_cast<VarDecl>(D))
return Var->isFileVarDecl() && Var->getInit();
if (FunctionDecl *Func = dyn_cast<FunctionDecl>(D))
@@ -581,6 +667,9 @@ Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) {
// after reading this declaration.
SavedStreamPosition SavedPosition(DeclsCursor);
+ // Note that we are loading a declaration record.
+ LoadingTypeOrDecl Loading(*this);
+
DeclsCursor.JumpToBit(Offset);
RecordData Record;
unsigned Code = DeclsCursor.ReadCode();
@@ -602,36 +691,36 @@ Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) {
D = TypedefDecl::Create(*Context, 0, SourceLocation(), 0, QualType());
break;
case pch::DECL_ENUM:
- D = EnumDecl::Create(*Context, 0, SourceLocation(), 0, 0);
+ D = EnumDecl::Create(*Context, 0, SourceLocation(), 0, SourceLocation(), 0);
break;
case pch::DECL_RECORD:
D = RecordDecl::Create(*Context, TagDecl::TK_struct, 0, SourceLocation(),
- 0, 0);
+ 0, SourceLocation(), 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());
+ D = FunctionDecl::Create(*Context, 0, SourceLocation(), DeclarationName(),
+ QualType(), 0);
break;
case pch::DECL_OBJC_METHOD:
- D = ObjCMethodDecl::Create(*Context, SourceLocation(), SourceLocation(),
+ 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(),
+ D = ObjCIvarDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), 0,
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,
+ D = ObjCAtDefsFieldDecl::Create(*Context, 0, SourceLocation(), 0,
QualType(), 0);
break;
case pch::DECL_OBJC_CLASS:
@@ -657,16 +746,16 @@ Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) {
break;
case pch::DECL_OBJC_PROPERTY_IMPL:
D = ObjCPropertyImplDecl::Create(*Context, 0, SourceLocation(),
- SourceLocation(), 0,
+ SourceLocation(), 0,
ObjCPropertyImplDecl::Dynamic, 0);
break;
case pch::DECL_FIELD:
- D = FieldDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), 0,
+ D = FieldDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), 0, 0,
false);
break;
case pch::DECL_VAR:
- D = VarDecl::Create(*Context, 0, SourceLocation(), 0, QualType(),
- VarDecl::None, SourceLocation());
+ D = VarDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), 0,
+ VarDecl::None);
break;
case pch::DECL_IMPLICIT_PARAM:
@@ -674,12 +763,12 @@ Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) {
break;
case pch::DECL_PARM_VAR:
- D = ParmVarDecl::Create(*Context, 0, SourceLocation(), 0, QualType(),
+ D = ParmVarDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), 0,
VarDecl::None, 0);
break;
case pch::DECL_ORIGINAL_PARM_VAR:
D = OriginalParmVarDecl::Create(*Context, 0, SourceLocation(), 0,
- QualType(), QualType(), VarDecl::None, 0);
+ QualType(),0, QualType(), VarDecl::None, 0);
break;
case pch::DECL_FILE_SCOPE_ASM:
D = FileScopeAsmDecl::Create(*Context, 0, SourceLocation(), 0);
@@ -719,4 +808,3 @@ Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) {
return D;
}
-
diff --git a/lib/Frontend/PCHReaderStmt.cpp b/lib/Frontend/PCHReaderStmt.cpp
index eccb53b..4b9496e 100644
--- a/lib/Frontend/PCHReaderStmt.cpp
+++ b/lib/Frontend/PCHReaderStmt.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/PCHReader.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/AST/StmtVisitor.h"
using namespace clang;
@@ -101,16 +102,21 @@ namespace {
unsigned VisitObjCProtocolExpr(ObjCProtocolExpr *E);
unsigned VisitObjCIvarRefExpr(ObjCIvarRefExpr *E);
unsigned VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E);
- unsigned VisitObjCKVCRefExpr(ObjCKVCRefExpr *E);
+ unsigned VisitObjCImplicitSetterGetterRefExpr(
+ ObjCImplicitSetterGetterRefExpr *E);
unsigned VisitObjCMessageExpr(ObjCMessageExpr *E);
unsigned VisitObjCSuperExpr(ObjCSuperExpr *E);
-
+ unsigned VisitObjCIsaExpr(ObjCIsaExpr *E);
+
unsigned VisitObjCForCollectionStmt(ObjCForCollectionStmt *);
unsigned VisitObjCAtCatchStmt(ObjCAtCatchStmt *);
unsigned VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *);
unsigned VisitObjCAtTryStmt(ObjCAtTryStmt *);
unsigned VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *);
unsigned VisitObjCAtThrowStmt(ObjCAtThrowStmt *);
+
+ unsigned VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E);
+ unsigned VisitCXXConstructExpr(CXXConstructExpr *E);
};
}
@@ -128,7 +134,7 @@ unsigned PCHStmtReader::VisitNullStmt(NullStmt *S) {
unsigned PCHStmtReader::VisitCompoundStmt(CompoundStmt *S) {
VisitStmt(S);
unsigned NumStmts = Record[Idx++];
- S->setStmts(*Reader.getContext(),
+ S->setStmts(*Reader.getContext(),
StmtStack.data() + StmtStack.size() - NumStmts, NumStmts);
S->setLBracLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
S->setRBracLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
@@ -191,6 +197,10 @@ unsigned PCHStmtReader::VisitSwitchStmt(SwitchStmt *S) {
PrevSC->setNextSwitchCase(SC);
else
S->setSwitchCaseList(SC);
+
+ // Retain this SwitchCase, since SwitchStmt::addSwitchCase() would
+ // normally retain it (but we aren't calling addSwitchCase).
+ SC->Retain();
PrevSC = SC;
}
return 2;
@@ -290,8 +300,8 @@ unsigned PCHStmtReader::VisitAsmStmt(AsmStmt *S) {
S->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
S->setVolatile(Record[Idx++]);
S->setSimple(Record[Idx++]);
-
- unsigned StackIdx
+
+ unsigned StackIdx
= StmtStack.size() - (NumOutputs*2 + NumInputs*2 + NumClobbers + 1);
S->setAsmString(cast_or_null<StringLiteral>(StmtStack[StackIdx++]));
@@ -364,14 +374,14 @@ unsigned PCHStmtReader::VisitImaginaryLiteral(ImaginaryLiteral *E) {
unsigned PCHStmtReader::VisitStringLiteral(StringLiteral *E) {
VisitExpr(E);
unsigned Len = Record[Idx++];
- assert(Record[Idx] == E->getNumConcatenated() &&
+ 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);
+ // Read string data
+ llvm::SmallString<16> Str(&Record[Idx], &Record[Idx] + Len);
+ E->setString(*Reader.getContext(), Str.str());
Idx += Len;
// Read source locations
@@ -446,9 +456,19 @@ unsigned PCHStmtReader::VisitMemberExpr(MemberExpr *E) {
return 1;
}
+unsigned PCHStmtReader::VisitObjCIsaExpr(ObjCIsaExpr *E) {
+ VisitExpr(E);
+ E->setBase(cast<Expr>(StmtStack.back()));
+ E->setIsaMemberLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setArrow(Record[Idx++]);
+ return 1;
+}
+
unsigned PCHStmtReader::VisitCastExpr(CastExpr *E) {
VisitExpr(E);
E->setSubExpr(cast<Expr>(StmtStack.back()));
+ E->setCastKind((CastExpr::CastKind)Record[Idx++]);
+
return 1;
}
@@ -473,6 +493,8 @@ unsigned PCHStmtReader::VisitConditionalOperator(ConditionalOperator *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->setQuestionLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setColonLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
return 3;
}
@@ -516,7 +538,7 @@ unsigned PCHStmtReader::VisitInitListExpr(InitListExpr *E) {
unsigned NumInits = Record[Idx++];
E->reserveInits(NumInits);
for (unsigned I = 0; I != NumInits; ++I)
- E->updateInit(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++]));
@@ -543,11 +565,11 @@ unsigned PCHStmtReader::VisitDesignatedInitExpr(DesignatedInitExpr *E) {
switch ((pch::DesignatorTypes)Record[Idx++]) {
case pch::DESIG_FIELD_DECL: {
FieldDecl *Field = cast<FieldDecl>(Reader.GetDecl(Record[Idx++]));
- SourceLocation DotLoc
+ SourceLocation DotLoc
= SourceLocation::getFromRawEncoding(Record[Idx++]);
- SourceLocation FieldLoc
+ SourceLocation FieldLoc
= SourceLocation::getFromRawEncoding(Record[Idx++]);
- Designators.push_back(Designator(Field->getIdentifier(), DotLoc,
+ Designators.push_back(Designator(Field->getIdentifier(), DotLoc,
FieldLoc));
Designators.back().setField(Field);
break;
@@ -555,14 +577,14 @@ unsigned PCHStmtReader::VisitDesignatedInitExpr(DesignatedInitExpr *E) {
case pch::DESIG_FIELD_NAME: {
const IdentifierInfo *Name = Reader.GetIdentifierInfo(Record, Idx);
- SourceLocation DotLoc
+ SourceLocation DotLoc
= SourceLocation::getFromRawEncoding(Record[Idx++]);
- SourceLocation FieldLoc
+ SourceLocation FieldLoc
= SourceLocation::getFromRawEncoding(Record[Idx++]);
Designators.push_back(Designator(Name, DotLoc, FieldLoc));
break;
}
-
+
case pch::DESIG_ARRAY: {
unsigned Index = Record[Idx++];
SourceLocation LBracketLoc
@@ -649,7 +671,8 @@ unsigned PCHStmtReader::VisitGNUNullExpr(GNUNullExpr *E) {
unsigned PCHStmtReader::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
VisitExpr(E);
unsigned NumExprs = Record[Idx++];
- E->setExprs((Expr **)&StmtStack[StmtStack.size() - NumExprs], NumExprs);
+ E->setExprs(*Reader.getContext(),
+ (Expr **)&StmtStack[StmtStack.size() - NumExprs], NumExprs);
E->setBuiltinLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
return NumExprs;
@@ -723,13 +746,14 @@ unsigned PCHStmtReader::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
return 1;
}
-unsigned PCHStmtReader::VisitObjCKVCRefExpr(ObjCKVCRefExpr *E) {
+unsigned PCHStmtReader::VisitObjCImplicitSetterGetterRefExpr(
+ ObjCImplicitSetterGetterRefExpr *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(
+ E->setInterfaceDecl(
cast_or_null<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++])));
E->setBase(cast_or_null<Expr>(StmtStack.back()));
E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
@@ -744,7 +768,7 @@ unsigned PCHStmtReader::VisitObjCMessageExpr(ObjCMessageExpr *E) {
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()) {
@@ -816,6 +840,23 @@ unsigned PCHStmtReader::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) {
return 1;
}
+//===----------------------------------------------------------------------===//
+// C++ Expressions and Statements
+
+unsigned PCHStmtReader::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
+ unsigned num = VisitCallExpr(E);
+ E->setOperator((OverloadedOperatorKind)Record[Idx++]);
+ return num;
+}
+
+unsigned PCHStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) {
+ VisitExpr(E);
+ E->setConstructor(cast<CXXConstructorDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setElidable(Record[Idx++]);
+ for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
+ E->setArg(I, cast<Expr>(StmtStack[StmtStack.size() - N + I]));
+ return E->getNumArgs();
+}
// Within the bitstream, expressions are stored in Reverse Polish
// Notation, with each of the subexpressions preceding the
@@ -865,8 +906,8 @@ Stmt *PCHReader::ReadStmt(llvm::BitstreamCursor &Cursor) {
Finished = true;
break;
- case pch::STMT_NULL_PTR:
- S = 0;
+ case pch::STMT_NULL_PTR:
+ S = 0;
break;
case pch::STMT_NULL:
@@ -904,7 +945,7 @@ Stmt *PCHReader::ReadStmt(llvm::BitstreamCursor &Cursor) {
case pch::STMT_DO:
S = new (Context) DoStmt(Empty);
break;
-
+
case pch::STMT_FOR:
S = new (Context) ForStmt(Empty);
break;
@@ -912,7 +953,7 @@ Stmt *PCHReader::ReadStmt(llvm::BitstreamCursor &Cursor) {
case pch::STMT_GOTO:
S = new (Context) GotoStmt(Empty);
break;
-
+
case pch::STMT_INDIRECT_GOTO:
S = new (Context) IndirectGotoStmt(Empty);
break;
@@ -940,25 +981,25 @@ Stmt *PCHReader::ReadStmt(llvm::BitstreamCursor &Cursor) {
case pch::EXPR_PREDEFINED:
S = new (Context) PredefinedExpr(Empty);
break;
-
- case pch::EXPR_DECL_REF:
- S = new (Context) DeclRefExpr(Empty);
+
+ case pch::EXPR_DECL_REF:
+ S = new (Context) DeclRefExpr(Empty);
break;
-
- case pch::EXPR_INTEGER_LITERAL:
+
+ 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,
+ S = StringLiteral::CreateEmpty(*Context,
Record[PCHStmtReader::NumExprFields + 1]);
break;
@@ -983,7 +1024,7 @@ Stmt *PCHReader::ReadStmt(llvm::BitstreamCursor &Cursor) {
break;
case pch::EXPR_CALL:
- S = new (Context) CallExpr(*Context, Empty);
+ S = new (Context) CallExpr(*Context, Stmt::CallExprClass, Empty);
break;
case pch::EXPR_MEMBER:
@@ -1025,7 +1066,7 @@ Stmt *PCHReader::ReadStmt(llvm::BitstreamCursor &Cursor) {
case pch::EXPR_DESIGNATED_INIT:
S = DesignatedInitExpr::CreateEmpty(*Context,
Record[PCHStmtReader::NumExprFields] - 1);
-
+
break;
case pch::EXPR_IMPLICIT_VALUE_INIT:
@@ -1059,7 +1100,7 @@ Stmt *PCHReader::ReadStmt(llvm::BitstreamCursor &Cursor) {
case pch::EXPR_SHUFFLE_VECTOR:
S = new (Context) ShuffleVectorExpr(Empty);
break;
-
+
case pch::EXPR_BLOCK:
S = new (Context) BlockExpr(Empty);
break;
@@ -1067,7 +1108,7 @@ Stmt *PCHReader::ReadStmt(llvm::BitstreamCursor &Cursor) {
case pch::EXPR_BLOCK_DECL_REF:
S = new (Context) BlockDeclRefExpr(Empty);
break;
-
+
case pch::EXPR_OBJC_STRING_LITERAL:
S = new (Context) ObjCStringLiteral(Empty);
break;
@@ -1087,7 +1128,7 @@ Stmt *PCHReader::ReadStmt(llvm::BitstreamCursor &Cursor) {
S = new (Context) ObjCPropertyRefExpr(Empty);
break;
case pch::EXPR_OBJC_KVC_REF_EXPR:
- S = new (Context) ObjCKVCRefExpr(Empty);
+ S = new (Context) ObjCImplicitSetterGetterRefExpr(Empty);
break;
case pch::EXPR_OBJC_MESSAGE_EXPR:
S = new (Context) ObjCMessageExpr(Empty);
@@ -1095,6 +1136,9 @@ Stmt *PCHReader::ReadStmt(llvm::BitstreamCursor &Cursor) {
case pch::EXPR_OBJC_SUPER_EXPR:
S = new (Context) ObjCSuperExpr(Empty);
break;
+ case pch::EXPR_OBJC_ISA:
+ S = new (Context) ObjCIsaExpr(Empty);
+ break;
case pch::STMT_OBJC_FOR_COLLECTION:
S = new (Context) ObjCForCollectionStmt(Empty);
break;
@@ -1113,6 +1157,15 @@ Stmt *PCHReader::ReadStmt(llvm::BitstreamCursor &Cursor) {
case pch::STMT_OBJC_AT_THROW:
S = new (Context) ObjCAtThrowStmt(Empty);
break;
+
+ case pch::EXPR_CXX_OPERATOR_CALL:
+ S = new (Context) CXXOperatorCallExpr(*Context, Empty);
+ break;
+
+ case pch::EXPR_CXX_CONSTRUCT:
+ S = new (Context) CXXConstructExpr(Empty, *Context,
+ Record[PCHStmtReader::NumExprFields + 2]);
+ break;
}
// We hit a STMT_STOP, so we're done with this expression.
diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp
index 3bfc9e8..64a678e 100644
--- a/lib/Frontend/PCHWriter.cpp
+++ b/lib/Frontend/PCHWriter.cpp
@@ -13,7 +13,7 @@
#include "clang/Frontend/PCHWriter.h"
#include "../Sema/Sema.h" // FIXME: move header into include/clang/Sema
-#include "../Sema/IdentifierResolver.h" // FIXME: move header
+#include "../Sema/IdentifierResolver.h" // FIXME: move header
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclContextInternals.h"
@@ -50,7 +50,7 @@ namespace {
/// \brief Type code that corresponds to the record generated.
pch::TypeCode Code;
- PCHTypeWriter(PCHWriter &Writer, PCHWriter::RecordData &Record)
+ PCHTypeWriter(PCHWriter &Writer, PCHWriter::RecordData &Record)
: Writer(Writer), Record(Record), Code(pch::TYPE_EXT_QUAL) { }
void VisitArrayType(const ArrayType *T);
@@ -64,13 +64,6 @@ namespace {
};
}
-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");
}
@@ -92,7 +85,7 @@ void PCHTypeWriter::VisitPointerType(const PointerType *T) {
}
void PCHTypeWriter::VisitBlockPointerType(const BlockPointerType *T) {
- Writer.AddTypeRef(T->getPointeeType(), Record);
+ Writer.AddTypeRef(T->getPointeeType(), Record);
Code = pch::TYPE_BLOCK_POINTER;
}
@@ -107,15 +100,15 @@ void PCHTypeWriter::VisitRValueReferenceType(const RValueReferenceType *T) {
}
void PCHTypeWriter::VisitMemberPointerType(const MemberPointerType *T) {
- Writer.AddTypeRef(T->getPointeeType(), Record);
- Writer.AddTypeRef(QualType(T->getClass(), 0), Record);
+ 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
+ Record.push_back(T->getIndexTypeCVRQualifiers()); // FIXME: stable values
}
void PCHTypeWriter::VisitConstantArrayType(const ConstantArrayType *T) {
@@ -124,6 +117,23 @@ void PCHTypeWriter::VisitConstantArrayType(const ConstantArrayType *T) {
Code = pch::TYPE_CONSTANT_ARRAY;
}
+void PCHTypeWriter
+::VisitConstantArrayWithExprType(const ConstantArrayWithExprType *T) {
+ VisitArrayType(T);
+ Writer.AddSourceLocation(T->getLBracketLoc(), Record);
+ Writer.AddSourceLocation(T->getRBracketLoc(), Record);
+ Writer.AddAPInt(T->getSize(), Record);
+ Writer.AddStmt(T->getSizeExpr());
+ Code = pch::TYPE_CONSTANT_ARRAY_WITH_EXPR;
+}
+
+void PCHTypeWriter
+::VisitConstantArrayWithoutExprType(const ConstantArrayWithoutExprType *T) {
+ VisitArrayType(T);
+ Writer.AddAPInt(T->getSize(), Record);
+ Code = pch::TYPE_CONSTANT_ARRAY_WITHOUT_EXPR;
+}
+
void PCHTypeWriter::VisitIncompleteArrayType(const IncompleteArrayType *T) {
VisitArrayType(T);
Code = pch::TYPE_INCOMPLETE_ARRAY;
@@ -131,6 +141,8 @@ void PCHTypeWriter::VisitIncompleteArrayType(const IncompleteArrayType *T) {
void PCHTypeWriter::VisitVariableArrayType(const VariableArrayType *T) {
VisitArrayType(T);
+ Writer.AddSourceLocation(T->getLBracketLoc(), Record);
+ Writer.AddSourceLocation(T->getRBracketLoc(), Record);
Writer.AddStmt(T->getSizeExpr());
Code = pch::TYPE_VARIABLE_ARRAY;
}
@@ -192,7 +204,7 @@ void PCHTypeWriter::VisitDecltypeType(const DecltypeType *T) {
void PCHTypeWriter::VisitTagType(const TagType *T) {
Writer.AddDeclRef(T->getDecl(), Record);
- assert(!T->isBeingDefined() &&
+ assert(!T->isBeingDefined() &&
"Cannot serialize in the middle of a type definition");
}
@@ -206,7 +218,13 @@ void PCHTypeWriter::VisitEnumType(const EnumType *T) {
Code = pch::TYPE_ENUM;
}
-void
+void PCHTypeWriter::VisitElaboratedType(const ElaboratedType *T) {
+ Writer.AddTypeRef(T->getUnderlyingType(), Record);
+ Record.push_back(T->getTagKind());
+ Code = pch::TYPE_ELABORATED;
+}
+
+void
PCHTypeWriter::VisitTemplateSpecializationType(
const TemplateSpecializationType *T) {
// FIXME: Serialize this type (C++ only)
@@ -220,23 +238,16 @@ void PCHTypeWriter::VisitQualifiedNameType(const QualifiedNameType *T) {
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;
+ Code = pch::TYPE_OBJC_INTERFACE;
}
void
PCHTypeWriter::VisitObjCObjectPointerType(const ObjCObjectPointerType *T) {
- Writer.AddDeclRef(T->getDecl(), Record);
+ Writer.AddTypeRef(T->getPointeeType(), Record);
Record.push_back(T->getNumProtocols());
for (ObjCInterfaceType::qual_iterator I = T->qual_begin(),
E = T->qual_end(); I != E; ++I)
@@ -244,6 +255,15 @@ PCHTypeWriter::VisitObjCObjectPointerType(const ObjCObjectPointerType *T) {
Code = pch::TYPE_OBJC_OBJECT_POINTER;
}
+void PCHTypeWriter::VisitObjCProtocolListType(const ObjCProtocolListType *T) {
+ Writer.AddTypeRef(T->getBaseType(), Record);
+ Record.push_back(T->getNumProtocols());
+ for (ObjCProtocolListType::qual_iterator I = T->qual_begin(),
+ E = T->qual_end(); I != E; ++I)
+ Writer.AddDeclRef(*I, Record);
+ Code = pch::TYPE_OBJC_PROTOCOL_LIST;
+}
+
//===----------------------------------------------------------------------===//
// PCHWriter Implementation
//===----------------------------------------------------------------------===//
@@ -344,14 +364,14 @@ static void AddStmtsExprs(llvm::BitstreamWriter &Stream,
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(ORIGINAL_FILE_NAME);
@@ -373,8 +393,8 @@ void PCHWriter::WriteBlockInfoBlock() {
RECORD(SOURCE_LOCATION_PRELOADS);
RECORD(STAT_CACHE);
RECORD(EXT_VECTOR_DECLS);
- RECORD(OBJC_CATEGORY_IMPLEMENTATIONS);
RECORD(COMMENT_RANGES);
+ RECORD(SVN_BRANCH_REVISION);
// SourceManager Block.
BLOCK(SOURCE_MANAGER_BLOCK);
@@ -384,7 +404,7 @@ void PCHWriter::WriteBlockInfoBlock() {
RECORD(SM_SLOC_INSTANTIATION_ENTRY);
RECORD(SM_LINE_TABLE);
RECORD(SM_HEADER_FILE_INFO);
-
+
// Preprocessor Block.
BLOCK(PREPROCESSOR_BLOCK);
RECORD(PP_MACRO_OBJECT_LIKE);
@@ -414,8 +434,8 @@ void PCHWriter::WriteBlockInfoBlock() {
RECORD(TYPE_RECORD);
RECORD(TYPE_ENUM);
RECORD(TYPE_OBJC_INTERFACE);
- RECORD(TYPE_OBJC_QUALIFIED_INTERFACE);
RECORD(TYPE_OBJC_OBJECT_POINTER);
+ RECORD(TYPE_OBJC_PROTOCOL_LIST);
// Statements and Exprs can occur in the Types block.
AddStmtsExprs(Stream, Record);
@@ -457,35 +477,45 @@ void PCHWriter::WriteBlockInfoBlock() {
Stream.ExitBlock();
}
+/// \brief Adjusts the given filename to only write out the portion of the
+/// filename that is not part of the system root directory.
+///
+/// \param Filename the file name to adjust.
+///
+/// \param isysroot When non-NULL, the PCH file is a relocatable PCH file and
+/// the returned filename will be adjusted by this system root.
+///
+/// \returns either the original filename (if it needs no adjustment) or the
+/// adjusted filename (which points into the @p Filename parameter).
+static const char *
+adjustFilenameForRelocatablePCH(const char *Filename, const char *isysroot) {
+ assert(Filename && "No file name to adjust?");
-/// \brief Write the PCH metadata (e.g., i686-apple-darwin9).
-void PCHWriter::WriteMetadata(ASTContext &Context) {
- using namespace llvm;
+ if (!isysroot)
+ return Filename;
- // 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);
+ // Verify that the filename and the system root have the same prefix.
+ unsigned Pos = 0;
+ for (; Filename[Pos] && isysroot[Pos]; ++Pos)
+ if (Filename[Pos] != isysroot[Pos])
+ return Filename; // Prefixes don't match.
- 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();
- }
+ // We hit the end of the filename before we hit the end of the system root.
+ if (!Filename[Pos])
+ return Filename;
- RecordData Record;
- Record.push_back(pch::ORIGINAL_FILE_NAME);
- Stream.EmitRecordWithBlob(FileAbbrevCode, Record, MainFileName.c_str(),
- MainFileName.size());
- }
+ // If the file name has a '/' at the current position, skip over the '/'.
+ // We distinguish sysroot-based includes from absolute includes by the
+ // absence of '/' at the beginning of sysroot-based includes.
+ if (Filename[Pos] == '/')
+ ++Pos;
+
+ return Filename + Pos;
+}
+
+/// \brief Write the PCH metadata (e.g., i686-apple-darwin9).
+void PCHWriter::WriteMetadata(ASTContext &Context, const char *isysroot) {
+ using namespace llvm;
// Metadata
const TargetInfo &Target = Context.Target;
@@ -495,6 +525,7 @@ void PCHWriter::WriteMetadata(ASTContext &Context) {
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::Fixed, 1)); // Relocatable
MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Target triple
unsigned MetaAbbrevCode = Stream.EmitAbbrev(MetaAbbrev);
@@ -504,8 +535,47 @@ void PCHWriter::WriteMetadata(ASTContext &Context) {
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));
+ Record.push_back(isysroot != 0);
+ const std::string &TripleStr = Target.getTriple().getTriple();
+ Stream.EmitRecordWithBlob(MetaAbbrevCode, Record, TripleStr);
+
+ // 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.str());
+ MainFileName = P.str();
+ } else {
+ MainFileName = MainFilePath.str();
+ }
+
+ const char *MainFileNameStr = MainFileName.c_str();
+ MainFileNameStr = adjustFilenameForRelocatablePCH(MainFileNameStr,
+ isysroot);
+ RecordData Record;
+ Record.push_back(pch::ORIGINAL_FILE_NAME);
+ Stream.EmitRecordWithBlob(FileAbbrevCode, Record, MainFileNameStr);
+ }
+
+ // Subversion branch/version information.
+ BitCodeAbbrev *SvnAbbrev = new BitCodeAbbrev();
+ SvnAbbrev->Add(BitCodeAbbrevOp(pch::SVN_BRANCH_REVISION));
+ SvnAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // SVN revision
+ SvnAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // SVN branch/tag
+ unsigned SvnAbbrevCode = Stream.EmitAbbrev(SvnAbbrev);
+ Record.clear();
+ Record.push_back(pch::SVN_BRANCH_REVISION);
+ Record.push_back(getClangSubversionRevision());
+ Stream.EmitRecordWithBlob(SvnAbbrevCode, Record, getClangSubversionPath());
}
/// \brief Write the LangOptions structure.
@@ -524,11 +594,11 @@ void PCHWriter::WriteLanguageOptions(const LangOptions &LangOpts) {
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);
@@ -541,6 +611,7 @@ void PCHWriter::WriteLanguageOptions(const LangOptions &LangOpts) {
// Whether static initializers are protected by locks.
Record.push_back(LangOpts.ThreadsafeStatics);
+ Record.push_back(LangOpts.POSIXThreads);
Record.push_back(LangOpts.Blocks); // block extension to C
Record.push_back(LangOpts.EmitAllDecls); // Emit all declarations, even if
// they are unused.
@@ -554,7 +625,7 @@ void PCHWriter::WriteLanguageOptions(const LangOptions &LangOpts) {
// 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
+ Record.push_back(LangOpts.OptimizeSize); // Whether __OPTIMIZE_SIZE__ should be
// defined.
Record.push_back(LangOpts.Static); // Should __STATIC__ be defined (as
// opposed to __DYNAMIC__).
@@ -569,8 +640,10 @@ void PCHWriter::WriteLanguageOptions(const LangOptions &LangOpts) {
// unsigned type
Record.push_back(LangOpts.getGCMode());
Record.push_back(LangOpts.getVisibilityMode());
+ Record.push_back(LangOpts.getStackProtectorMode());
Record.push_back(LangOpts.InstantiationDepth);
Record.push_back(LangOpts.OpenCL);
+ Record.push_back(LangOpts.ElideConstructors);
Stream.EmitRecord(pch::LANGUAGE_OPTIONS, Record);
}
@@ -584,15 +657,15 @@ 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>
+
+ std::pair<unsigned,unsigned>
EmitKeyDataLength(llvm::raw_ostream& Out, const char *path,
data_type_ref Data) {
unsigned StrLen = strlen(path);
@@ -603,19 +676,19 @@ public:
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);
@@ -630,18 +703,22 @@ public:
} // end anonymous namespace
/// \brief Write the stat() system call cache to the PCH file.
-void PCHWriter::WriteStatCache(MemorizeStatCalls &StatCalls) {
+void PCHWriter::WriteStatCache(MemorizeStatCalls &StatCalls,
+ const char *isysroot) {
// Build the on-disk hash table containing information about every
// stat() call.
OnDiskChainedHashTableGenerator<PCHStatCacheTrait> Generator;
unsigned NumStatEntries = 0;
- for (MemorizeStatCalls::iterator Stat = StatCalls.begin(),
+ for (MemorizeStatCalls::iterator Stat = StatCalls.begin(),
StatEnd = StatCalls.end();
- Stat != StatEnd; ++Stat, ++NumStatEntries)
- Generator.insert(Stat->first(), Stat->second);
-
+ Stat != StatEnd; ++Stat, ++NumStatEntries) {
+ const char *Filename = Stat->first();
+ Filename = adjustFilenameForRelocatablePCH(Filename, isysroot);
+ Generator.insert(Filename, Stat->second);
+ }
+
// Create the on-disk hash table in a buffer.
- llvm::SmallVector<char, 4096> StatCacheData;
+ llvm::SmallString<4096> StatCacheData;
uint32_t BucketOffset;
{
llvm::raw_svector_ostream Out(StatCacheData);
@@ -664,9 +741,7 @@ void PCHWriter::WriteStatCache(MemorizeStatCalls &StatCalls) {
Record.push_back(pch::STAT_CACHE);
Record.push_back(BucketOffset);
Record.push_back(NumStatEntries);
- Stream.EmitRecordWithBlob(StatCacheAbbrev, Record,
- &StatCacheData.front(),
- StatCacheData.size());
+ Stream.EmitRecordWithBlob(StatCacheAbbrev, Record, StatCacheData.str());
}
//===----------------------------------------------------------------------===//
@@ -734,7 +809,8 @@ static unsigned CreateSLocInstantiationAbbrev(llvm::BitstreamWriter &Stream) {
/// 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) {
+ const Preprocessor &PP,
+ const char *isysroot) {
RecordData Record;
// Enter the source manager block.
@@ -755,21 +831,22 @@ void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
for (unsigned I = 0, N = LineTable.getNumFilenames(); I != N; ++I) {
// Emit the file name
const char *Filename = LineTable.getFilename(I);
+ Filename = adjustFilenameForRelocatablePCH(Filename, isysroot);
unsigned FilenameLen = Filename? strlen(Filename) : 0;
Record.push_back(FilenameLen);
if (FilenameLen)
Record.insert(Record.end(), Filename, Filename + FilenameLen);
}
-
+
// Emit the line entries
for (LineTableInfo::iterator L = LineTable.begin(), LEnd = LineTable.end();
L != LEnd; ++L) {
// Emit the file ID
Record.push_back(L->first);
-
+
// Emit the line entries
Record.push_back(L->second.size());
- for (std::vector<LineEntry>::iterator LE = L->second.begin(),
+ for (std::vector<LineEntry>::iterator LE = L->second.begin(),
LEEnd = L->second.end();
LE != LEEnd; ++LE) {
Record.push_back(LE->FileOffset);
@@ -783,9 +860,9 @@ void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
}
// Write out entries for all of the header files we know about.
- HeaderSearch &HS = PP.getHeaderSearchInfo();
+ HeaderSearch &HS = PP.getHeaderSearchInfo();
Record.clear();
- for (HeaderSearch::header_file_iterator I = HS.header_file_begin(),
+ for (HeaderSearch::header_file_iterator I = HS.header_file_begin(),
E = HS.header_file_end();
I != E; ++I) {
Record.push_back(I->isImport);
@@ -801,7 +878,7 @@ void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
std::vector<uint32_t> SLocEntryOffsets;
RecordData PreloadSLocs;
SLocEntryOffsets.reserve(SourceMgr.sloc_entry_size() - 1);
- for (SourceManager::sloc_entry_iterator
+ for (SourceManager::sloc_entry_iterator
SLoc = SourceMgr.sloc_entry_begin() + 1,
SLocEnd = SourceMgr.sloc_entry_end();
SLoc != SLocEnd; ++SLoc) {
@@ -831,9 +908,20 @@ void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
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()));
+
+ // Turn the file name into an absolute path, if it isn't already.
+ const char *Filename = Content->Entry->getName();
+ llvm::sys::Path FilePath(Filename, strlen(Filename));
+ std::string FilenameStr;
+ if (!FilePath.isAbsolute()) {
+ llvm::sys::Path P = llvm::sys::Path::GetCurrentDirectory();
+ P.appendComponent(FilePath.str());
+ FilenameStr = P.str();
+ Filename = FilenameStr.c_str();
+ }
+
+ Filename = adjustFilenameForRelocatablePCH(Filename, isysroot);
+ Stream.EmitRecordWithBlob(SLocFileAbbrv, Record, Filename);
// FIXME: For now, preload all file source locations, so that
// we get the appropriate File entries in the reader. This is
@@ -848,12 +936,13 @@ void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
// the reader side).
const llvm::MemoryBuffer *Buffer = Content->getBuffer();
const char *Name = Buffer->getBufferIdentifier();
- Stream.EmitRecordWithBlob(SLocBufferAbbrv, Record, Name, strlen(Name) + 1);
+ Stream.EmitRecordWithBlob(SLocBufferAbbrv, Record,
+ llvm::StringRef(Name, strlen(Name) + 1));
Record.clear();
Record.push_back(pch::SM_SLOC_BUFFER_BLOB);
Stream.EmitRecordWithBlob(SLocBufferBlobAbbrv, Record,
- Buffer->getBufferStart(),
- Buffer->getBufferSize() + 1);
+ llvm::StringRef(Buffer->getBufferStart(),
+ Buffer->getBufferSize() + 1));
if (strcmp(Name, "<built-in>") == 0)
PreloadSLocs.push_back(SLocEntryOffsets.size());
@@ -889,13 +978,13 @@ void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
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(),
+ (const char *)&SLocEntryOffsets.front(),
SLocEntryOffsets.size()*sizeof(SLocEntryOffsets[0]));
// Write the source location entry preloads array, telling the PCH
@@ -922,12 +1011,12 @@ void PCHWriter::WritePreprocessor(const Preprocessor &PP) {
// 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();
@@ -946,13 +1035,13 @@ void PCHWriter::WritePreprocessor(const Preprocessor &PP) {
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());
@@ -969,19 +1058,19 @@ void PCHWriter::WritePreprocessor(const Preprocessor &PP) {
// 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();
}
@@ -992,18 +1081,18 @@ void PCHWriter::WritePreprocessor(const Preprocessor &PP) {
void PCHWriter::WriteComments(ASTContext &Context) {
using namespace llvm;
-
+
if (Context.Comments.empty())
return;
-
+
BitCodeAbbrev *CommentAbbrev = new BitCodeAbbrev();
CommentAbbrev->Add(BitCodeAbbrevOp(pch::COMMENT_RANGES));
CommentAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
unsigned CommentCode = Stream.EmitAbbrev(CommentAbbrev);
-
+
RecordData Record;
Record.push_back(pch::COMMENT_RANGES);
- Stream.EmitRecordWithBlob(CommentCode, Record,
+ Stream.EmitRecordWithBlob(CommentCode, Record,
(const char*)&Context.Comments[0],
Context.Comments.size() * sizeof(SourceRange));
}
@@ -1013,11 +1102,11 @@ void PCHWriter::WriteComments(ASTContext &Context) {
//===----------------------------------------------------------------------===//
/// \brief Write the representation of a type to the PCH stream.
-void PCHWriter::WriteType(const Type *T) {
+void PCHWriter::WriteType(QualType 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());
@@ -1027,25 +1116,33 @@ void PCHWriter::WriteType(const Type *T) {
}
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.
+
+ if (T.hasNonFastQualifiers()) {
+ Qualifiers Qs = T.getQualifiers();
+ AddTypeRef(T.getUnqualifiedType(), Record);
+ Record.push_back(Qs.getAsOpaqueValue());
+ W.Code = pch::TYPE_EXT_QUAL;
+ } else {
+ 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;
+ 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.
+ // 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;
+ assert(false && "Cannot serialize dependent type nodes");
+ break;
+ }
}
// Emit the serialized record.
@@ -1062,9 +1159,8 @@ void PCHWriter::WriteTypesBlock(ASTContext &Context) {
// Emit all of the types that need to be emitted (so far).
while (!TypesToEmit.empty()) {
- const Type *T = TypesToEmit.front();
+ QualType T = TypesToEmit.front();
TypesToEmit.pop();
- assert(!isa<BuiltinType>(T) && "Built-in types are not serialized");
WriteType(T);
}
@@ -1081,7 +1177,7 @@ void PCHWriter::WriteTypesBlock(ASTContext &Context) {
///
/// \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,
+uint64_t PCHWriter::WriteDeclContextLexicalBlock(ASTContext &Context,
DeclContext *DC) {
if (DC->decls_empty())
return 0;
@@ -1133,7 +1229,7 @@ uint64_t PCHWriter::WriteDeclContextVisibleBlock(ASTContext &Context,
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)
+ for (; Result.first != Result.second; ++Result.first)
AddDeclRef(*Result.first, Record);
}
@@ -1157,12 +1253,12 @@ class VISIBILITY_HIDDEN PCHMethodPoolTrait {
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)
@@ -1173,27 +1269,27 @@ public:
R = clang::BernsteinHashPartial(II->getName(), II->getLength(), R);
return R;
}
-
- std::pair<unsigned,unsigned>
+
+ 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;
+ for (const ObjCMethodList *Method = &Methods.first; Method;
Method = Method->Next)
if (Method->Method)
DataLen += 4;
- for (const ObjCMethodList *Method = &Methods.second; Method;
+ 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();
+ uint64_t Start = Out.tell();
assert((Start >> 32) == 0 && "Selector key offset too large");
Writer.SetSelectorOffset(Sel, Start);
unsigned N = Sel.getNumArgs();
@@ -1201,32 +1297,32 @@ public:
if (N == 0)
N = 1;
for (unsigned I = 0; I != N; ++I)
- clang::io::Emit32(Out,
+ 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;
+ for (const ObjCMethodList *Method = &Methods.first; Method;
Method = Method->Next)
if (Method->Method)
++NumInstanceMethods;
unsigned NumFactoryMethods = 0;
- for (const ObjCMethodList *Method = &Methods.second; Method;
+ 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;
+ 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;
+ for (const ObjCMethodList *Method = &Methods.second; Method;
Method = Method->Next)
if (Method->Method)
clang::io::Emit32(Out, Writer.getDeclID(Method->Method));
@@ -1248,13 +1344,13 @@ void PCHWriter::WriteMethodPool(Sema &SemaRef) {
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(),
+ Instance = SemaRef.InstanceMethodPool.begin(),
InstanceEnd = SemaRef.InstanceMethodPool.end();
Instance != InstanceEnd; ++Instance) {
// Check whether there is a factory method with the same
@@ -1264,7 +1360,7 @@ void PCHWriter::WriteMethodPool(Sema &SemaRef) {
if (Factory == SemaRef.FactoryMethodPool.end())
Generator.insert(Instance->first,
- std::make_pair(Instance->second,
+ std::make_pair(Instance->second,
ObjCMethodList()));
else
Generator.insert(Instance->first,
@@ -1277,7 +1373,7 @@ void PCHWriter::WriteMethodPool(Sema &SemaRef) {
// 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(),
+ Factory = SemaRef.FactoryMethodPool.begin(),
FactoryEnd = SemaRef.FactoryMethodPool.end();
Factory != FactoryEnd; ++Factory) {
// Check whether there is an instance method with the same
@@ -1298,7 +1394,7 @@ void PCHWriter::WriteMethodPool(Sema &SemaRef) {
return;
// Create the on-disk hash table in a buffer.
- llvm::SmallVector<char, 4096> MethodPool;
+ llvm::SmallString<4096> MethodPool;
uint32_t BucketOffset;
SelectorOffsets.resize(SelVector.size());
{
@@ -1329,9 +1425,7 @@ void PCHWriter::WriteMethodPool(Sema &SemaRef) {
Record.push_back(pch::METHOD_POOL);
Record.push_back(BucketOffset);
Record.push_back(NumSelectorsInMethodPool);
- Stream.EmitRecordWithBlob(MethodPoolAbbrev, Record,
- &MethodPool.front(),
- MethodPool.size());
+ Stream.EmitRecordWithBlob(MethodPoolAbbrev, Record, MethodPool.str());
// Create a blob abbreviation for the selector table offsets.
Abbrev = new BitCodeAbbrev();
@@ -1373,25 +1467,25 @@ class VISIBILITY_HIDDEN PCHIdentifierTableTrait {
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)
+
+ 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,
+
+ 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() &&
+ if (II->hasMacroDefinition() &&
!PP.getMacroInfo(const_cast<IdentifierInfo *>(II))->isBuiltinMacro())
DataLen += 4;
for (IdentifierResolver::iterator D = IdentifierResolver::begin(II),
@@ -1406,16 +1500,16 @@ public:
clang::io::Emit16(Out, KeyLen);
return std::make_pair(KeyLen, DataLen);
}
-
- void EmitKey(llvm::raw_ostream& Out, const IdentifierInfo* II,
+
+ 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,
+
+ void EmitData(llvm::raw_ostream& Out, const IdentifierInfo* II,
pch::IdentID ID, unsigned) {
if (!isInterestingIdentifier(II)) {
clang::io::Emit32(Out, ID << 1);
@@ -1424,8 +1518,8 @@ public:
clang::io::Emit32(Out, (ID << 1) | 0x01);
uint32_t Bits = 0;
- bool hasMacroDefinition =
- II->hasMacroDefinition() &&
+ bool hasMacroDefinition =
+ II->hasMacroDefinition() &&
!PP.getMacroInfo(const_cast<IdentifierInfo *>(II))->isBuiltinMacro();
Bits = (uint32_t)II->getObjCOrBuiltinID();
Bits = (Bits << 1) | hasMacroDefinition;
@@ -1443,7 +1537,7 @@ public:
// "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),
+ llvm::SmallVector<Decl *, 16> Decls(IdentifierResolver::begin(II),
IdentifierResolver::end());
for (llvm::SmallVector<Decl *, 16>::reverse_iterator D = Decls.rbegin(),
DEnd = Decls.rend();
@@ -1465,7 +1559,7 @@ void PCHWriter::WriteIdentifierTable(Preprocessor &PP) {
// 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
@@ -1486,7 +1580,7 @@ void PCHWriter::WriteIdentifierTable(Preprocessor &PP) {
}
// Create the on-disk hash table in a buffer.
- llvm::SmallVector<char, 4096> IdentifierTable;
+ llvm::SmallString<4096> IdentifierTable;
uint32_t BucketOffset;
{
PCHIdentifierTableTrait Trait(*this, PP);
@@ -1507,9 +1601,7 @@ void PCHWriter::WriteIdentifierTable(Preprocessor &PP) {
RecordData Record;
Record.push_back(pch::IDENTIFIER_TABLE);
Record.push_back(BucketOffset);
- Stream.EmitRecordWithBlob(IDTableAbbrev, Record,
- &IdentifierTable.front(),
- IdentifierTable.size());
+ Stream.EmitRecordWithBlob(IDTableAbbrev, Record, IdentifierTable.str());
}
// Write the offsets table for identifier IDs.
@@ -1548,7 +1640,7 @@ void PCHWriter::WriteAttributeRecord(const Attr *Attr) {
case Attr::AlwaysInline:
break;
-
+
case Attr::AnalyzerNoReturn:
break;
@@ -1607,13 +1699,14 @@ void PCHWriter::WriteAttributeRecord(const Attr *Attr) {
Record.push_back(Sentinel->getNullPos());
break;
}
-
+
case Attr::GNUInline:
case Attr::IBOutletKind:
+ case Attr::Malloc:
+ case Attr::NoDebug:
case Attr::NoReturn:
case Attr::NoThrow:
- case Attr::Nodebug:
- case Attr::Noinline:
+ case Attr::NoInline:
break;
case Attr::NonNull: {
@@ -1630,8 +1723,11 @@ void PCHWriter::WriteAttributeRecord(const Attr *Attr) {
case Attr::Overloadable:
break;
+ case Attr::PragmaPack:
+ Record.push_back(cast<PragmaPackAttr>(Attr)->getAlignment());
+ break;
+
case Attr::Packed:
- Record.push_back(cast<PackedAttr>(Attr)->getAlignment());
break;
case Attr::Pure:
@@ -1640,7 +1736,7 @@ void PCHWriter::WriteAttributeRecord(const Attr *Attr) {
case Attr::Regparm:
Record.push_back(cast<RegparmAttr>(Attr)->getNumParams());
break;
-
+
case Attr::ReqdWorkGroupSize:
Record.push_back(cast<ReqdWorkGroupSizeAttr>(Attr)->getXDim());
Record.push_back(cast<ReqdWorkGroupSizeAttr>(Attr)->getYDim());
@@ -1660,7 +1756,7 @@ void PCHWriter::WriteAttributeRecord(const Attr *Attr) {
case Attr::Visibility:
// FIXME: stable encoding
- Record.push_back(cast<VisibilityAttr>(Attr)->getVisibility());
+ Record.push_back(cast<VisibilityAttr>(Attr)->getVisibility());
break;
case Attr::WarnUnusedResult:
@@ -1692,12 +1788,13 @@ void PCHWriter::SetSelectorOffset(Selector Sel, uint32_t Offset) {
SelectorOffsets[ID - 1] = Offset;
}
-PCHWriter::PCHWriter(llvm::BitstreamWriter &Stream)
- : Stream(Stream), NextTypeID(pch::NUM_PREDEF_TYPE_IDS),
+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) {
+void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls,
+ const char *isysroot) {
using namespace llvm;
ASTContext &Context = SemaRef.Context;
@@ -1708,7 +1805,7 @@ void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls) {
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.
@@ -1726,20 +1823,23 @@ void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls) {
getIdentifierRef(&Table.get(BuiltinNames[I]));
}
- // Build a record containing all of the tentative definitions in
- // this header file. Generally, this record will be empty.
+ // Build a record containing all of the tentative definitions in this file, in
+ // TentativeDefinitionList order. Generally, this record will be empty for
+ // headers.
RecordData TentativeDefinitions;
- for (llvm::DenseMap<DeclarationName, VarDecl *>::iterator
- TD = SemaRef.TentativeDefinitions.begin(),
- TDEnd = SemaRef.TentativeDefinitions.end();
- TD != TDEnd; ++TD)
- AddDeclRef(TD->second, TentativeDefinitions);
+ for (unsigned i = 0, e = SemaRef.TentativeDefinitionList.size(); i != e; ++i){
+ VarDecl *VD =
+ SemaRef.TentativeDefinitions.lookup(SemaRef.TentativeDefinitionList[i]);
+ if (VD) AddDeclRef(VD, 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
+ // FIXME: This is filling in the PCH file in densemap order which is
+ // nondeterminstic!
+ for (llvm::DenseMap<DeclarationName, NamedDecl *>::iterator
TD = SemaRef.LocallyScopedExternalDecls.begin(),
TDEnd = SemaRef.LocallyScopedExternalDecls.end();
TD != TDEnd; ++TD)
@@ -1750,23 +1850,33 @@ void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls) {
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);
+ WriteMetadata(Context, isysroot);
WriteLanguageOptions(Context.getLangOptions());
- if (StatCalls)
- WriteStatCache(*StatCalls);
- WriteSourceManagerBlock(Context.getSourceManager(), PP);
+ if (StatCalls && !isysroot)
+ WriteStatCache(*StatCalls, isysroot);
+ WriteSourceManagerBlock(Context.getSourceManager(), PP, isysroot);
WritePreprocessor(PP);
- WriteComments(Context);
-
+ WriteComments(Context);
+ // Write the record of special types.
+ Record.clear();
+
+ AddTypeRef(Context.getBuiltinVaListType(), Record);
+ AddTypeRef(Context.getObjCIdType(), Record);
+ AddTypeRef(Context.getObjCSelType(), Record);
+ AddTypeRef(Context.getObjCProtoType(), Record);
+ AddTypeRef(Context.getObjCClassType(), Record);
+ AddTypeRef(Context.getRawCFConstantStringType(), Record);
+ AddTypeRef(Context.getRawObjCFastEnumerationStateType(), Record);
+ AddTypeRef(Context.getFILEType(), Record);
+ AddTypeRef(Context.getjmp_bufType(), Record);
+ AddTypeRef(Context.getsigjmp_bufType(), Record);
+ AddTypeRef(Context.ObjCIdRedefinitionType, Record);
+ AddTypeRef(Context.ObjCClassRedefinitionType, Record);
+ Stream.EmitRecord(pch::SPECIAL_TYPES, Record);
+
// Keep writing types and declarations until all types and
// declarations have been written.
do {
@@ -1789,9 +1899,9 @@ void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls) {
Record.push_back(pch::TYPE_OFFSET);
Record.push_back(TypeOffsets.size());
Stream.EmitRecordWithBlob(TypeOffsetAbbrev, Record,
- (const char *)&TypeOffsets.front(),
+ (const char *)&TypeOffsets.front(),
TypeOffsets.size() * sizeof(TypeOffsets[0]));
-
+
// Write the declaration offsets array
Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(pch::DECL_OFFSET));
@@ -1802,20 +1912,9 @@ void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls) {
Record.push_back(pch::DECL_OFFSET);
Record.push_back(DeclOffsets.size());
Stream.EmitRecordWithBlob(DeclOffsetAbbrev, Record,
- (const char *)&DeclOffsets.front(),
+ (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);
@@ -1826,17 +1925,13 @@ void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls) {
// Write the record containing locally-scoped external definitions.
if (!LocallyScopedExternalDecls.empty())
- Stream.EmitRecord(pch::LOCALLY_SCOPED_EXTERNAL_DECLS,
+ 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);
@@ -1902,6 +1997,26 @@ void PCHWriter::AddTypeRef(QualType T, RecordData &Record) {
return;
}
+ unsigned FastQuals = T.getFastQualifiers();
+ T.removeFastQualifiers();
+
+ if (T.hasNonFastQualifiers()) {
+ pch::TypeID &ID = TypeIDs[T];
+ if (ID == 0) {
+ // We haven't seen these qualifiers applied to this type before.
+ // Assign it a new ID. This is the only time we enqueue a
+ // qualified type, and it has no CV qualifiers.
+ ID = NextTypeID++;
+ TypesToEmit.push(T);
+ }
+
+ // Encode the type qualifiers in the type reference.
+ Record.push_back((ID << Qualifiers::FastWidth) | FastQuals);
+ return;
+ }
+
+ assert(!T.hasQualifiers());
+
if (const BuiltinType *BT = dyn_cast<BuiltinType>(T.getTypePtr())) {
pch::TypeID ID = 0;
switch (BT->getKind()) {
@@ -1926,27 +2041,31 @@ void PCHWriter::AddTypeRef(QualType T, RecordData &Record) {
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::Char16: ID = pch::PREDEF_TYPE_CHAR16_ID; break;
+ case BuiltinType::Char32: ID = pch::PREDEF_TYPE_CHAR32_ID; break;
case BuiltinType::Overload: ID = pch::PREDEF_TYPE_OVERLOAD_ID; break;
case BuiltinType::Dependent: ID = pch::PREDEF_TYPE_DEPENDENT_ID; break;
+ case BuiltinType::ObjCId: ID = pch::PREDEF_TYPE_OBJC_ID; break;
+ case BuiltinType::ObjCClass: ID = pch::PREDEF_TYPE_OBJC_CLASS; break;
case BuiltinType::UndeducedAuto:
assert(0 && "Should not see undeduced auto here");
break;
}
- Record.push_back((ID << 3) | T.getCVRQualifiers());
+ Record.push_back((ID << Qualifiers::FastWidth) | FastQuals);
return;
}
- pch::TypeID &ID = TypeIDs[T.getTypePtr()];
+ pch::TypeID &ID = TypeIDs[T];
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.
+ // into the queue of types to emit.
ID = NextTypeID++;
- TypesToEmit.push(T.getTypePtr());
+ TypesToEmit.push(T);
}
// Encode the type qualifiers in the type reference.
- Record.push_back((ID << 3) | T.getCVRQualifiers());
+ Record.push_back((ID << Qualifiers::FastWidth) | FastQuals);
}
void PCHWriter::AddDeclRef(const Decl *D, RecordData &Record) {
@@ -1956,7 +2075,7 @@ void PCHWriter::AddDeclRef(const Decl *D, RecordData &Record) {
}
pch::DeclID &ID = DeclIDs[D];
- if (ID == 0) {
+ 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();
diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp
index a6843e1..4527bb1 100644
--- a/lib/Frontend/PCHWriterDecl.cpp
+++ b/lib/Frontend/PCHWriterDecl.cpp
@@ -14,7 +14,10 @@
#include "clang/Frontend/PCHWriter.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/TypeLocVisitor.h"
#include "llvm/Bitcode/BitstreamWriter.h"
+#include <cstdio>
+
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -32,8 +35,8 @@ namespace {
pch::DeclCode Code;
unsigned AbbrevToUse;
- PCHDeclWriter(PCHWriter &Writer, ASTContext &Context,
- PCHWriter::RecordData &Record)
+ PCHDeclWriter(PCHWriter &Writer, ASTContext &Context,
+ PCHWriter::RecordData &Record)
: Writer(Writer), Context(Context), Record(Record) {
}
@@ -47,6 +50,7 @@ namespace {
void VisitRecordDecl(RecordDecl *D);
void VisitValueDecl(ValueDecl *D);
void VisitEnumConstantDecl(EnumConstantDecl *D);
+ void VisitDeclaratorDecl(DeclaratorDecl *D);
void VisitFunctionDecl(FunctionDecl *D);
void VisitFieldDecl(FieldDecl *D);
void VisitVarDecl(VarDecl *D);
@@ -55,7 +59,7 @@ namespace {
void VisitOriginalParmVarDecl(OriginalParmVarDecl *D);
void VisitFileScopeAsmDecl(FileScopeAsmDecl *D);
void VisitBlockDecl(BlockDecl *D);
- void VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset,
+ void VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset,
uint64_t VisibleOffset);
void VisitObjCMethodDecl(ObjCMethodDecl *D);
void VisitObjCContainerDecl(ObjCContainerDecl *D);
@@ -109,9 +113,12 @@ void PCHDeclWriter::VisitTypedefDecl(TypedefDecl *D) {
void PCHDeclWriter::VisitTagDecl(TagDecl *D) {
VisitTypeDecl(D);
+ Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
Record.push_back((unsigned)D->getTagKind()); // FIXME: stable encoding
Record.push_back(D->isDefinition());
Writer.AddDeclRef(D->getTypedefForAnonDecl(), Record);
+ Writer.AddSourceLocation(D->getRBraceLoc(), Record);
+ Writer.AddSourceLocation(D->getTagKeywordLoc(), Record);
}
void PCHDeclWriter::VisitEnumDecl(EnumDecl *D) {
@@ -125,6 +132,7 @@ void PCHDeclWriter::VisitRecordDecl(RecordDecl *D) {
VisitTagDecl(D);
Record.push_back(D->hasFlexibleArrayMember());
Record.push_back(D->isAnonymousStructOrUnion());
+ Record.push_back(D->hasObjectMember());
Code = pch::DECL_RECORD;
}
@@ -141,22 +149,99 @@ void PCHDeclWriter::VisitEnumConstantDecl(EnumConstantDecl *D) {
Writer.AddAPSInt(D->getInitVal(), Record);
Code = pch::DECL_ENUM_CONSTANT;
}
+namespace {
-void PCHDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
+class TypeLocWriter : public TypeLocVisitor<TypeLocWriter> {
+ PCHWriter &Writer;
+ PCHWriter::RecordData &Record;
+
+public:
+ TypeLocWriter(PCHWriter &Writer, PCHWriter::RecordData &Record)
+ : Writer(Writer), Record(Record) { }
+
+#define ABSTRACT_TYPELOC(CLASS)
+#define TYPELOC(CLASS, PARENT, TYPE) \
+ void Visit##CLASS(CLASS TyLoc);
+#include "clang/AST/TypeLocNodes.def"
+
+ void VisitTypeLoc(TypeLoc TyLoc) {
+ assert(0 && "A type loc wrapper was not handled!");
+ }
+};
+
+}
+
+void TypeLocWriter::VisitDefaultTypeSpecLoc(DefaultTypeSpecLoc TyLoc) {
+ Writer.AddSourceLocation(TyLoc.getStartLoc(), Record);
+}
+void TypeLocWriter::VisitTypedefLoc(TypedefLoc TyLoc) {
+ Writer.AddSourceLocation(TyLoc.getNameLoc(), Record);
+}
+void TypeLocWriter::VisitObjCInterfaceLoc(ObjCInterfaceLoc TyLoc) {
+ Writer.AddSourceLocation(TyLoc.getNameLoc(), Record);
+}
+void TypeLocWriter::VisitObjCProtocolListLoc(ObjCProtocolListLoc TyLoc) {
+ Writer.AddSourceLocation(TyLoc.getLAngleLoc(), Record);
+ Writer.AddSourceLocation(TyLoc.getRAngleLoc(), Record);
+ for (unsigned i = 0, e = TyLoc.getNumProtocols(); i != e; ++i)
+ Writer.AddSourceLocation(TyLoc.getProtocolLoc(i), Record);
+}
+void TypeLocWriter::VisitPointerLoc(PointerLoc TyLoc) {
+ Writer.AddSourceLocation(TyLoc.getStarLoc(), Record);
+}
+void TypeLocWriter::VisitBlockPointerLoc(BlockPointerLoc TyLoc) {
+ Writer.AddSourceLocation(TyLoc.getCaretLoc(), Record);
+}
+void TypeLocWriter::VisitMemberPointerLoc(MemberPointerLoc TyLoc) {
+ Writer.AddSourceLocation(TyLoc.getStarLoc(), Record);
+}
+void TypeLocWriter::VisitReferenceLoc(ReferenceLoc TyLoc) {
+ Writer.AddSourceLocation(TyLoc.getAmpLoc(), Record);
+}
+void TypeLocWriter::VisitFunctionLoc(FunctionLoc TyLoc) {
+ Writer.AddSourceLocation(TyLoc.getLParenLoc(), Record);
+ Writer.AddSourceLocation(TyLoc.getRParenLoc(), Record);
+ for (unsigned i = 0, e = TyLoc.getNumArgs(); i != e; ++i)
+ Writer.AddDeclRef(TyLoc.getArg(i), Record);
+}
+void TypeLocWriter::VisitArrayLoc(ArrayLoc TyLoc) {
+ Writer.AddSourceLocation(TyLoc.getLBracketLoc(), Record);
+ Writer.AddSourceLocation(TyLoc.getRBracketLoc(), Record);
+ Record.push_back(TyLoc.getSizeExpr() ? 1 : 0);
+ if (TyLoc.getSizeExpr())
+ Writer.AddStmt(TyLoc.getSizeExpr());
+}
+
+void PCHDeclWriter::VisitDeclaratorDecl(DeclaratorDecl *D) {
VisitValueDecl(D);
+ DeclaratorInfo *DInfo = D->getDeclaratorInfo();
+ if (DInfo == 0) {
+ Writer.AddTypeRef(QualType(), Record);
+ return;
+ }
+
+ Writer.AddTypeRef(DInfo->getTypeLoc().getSourceType(), Record);
+ TypeLocWriter TLW(Writer, Record);
+ for (TypeLoc TL = DInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc())
+ TLW.Visit(TL);
+}
+
+void PCHDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
+ VisitDeclaratorDecl(D);
Record.push_back(D->isThisDeclarationADefinition());
if (D->isThisDeclarationADefinition())
Writer.AddStmt(D->getBody());
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);
+ Record.push_back(D->isTrivial());
+ Record.push_back(D->isCopyAssignment());
+ Record.push_back(D->hasImplicitReturnZero());
Writer.AddSourceLocation(D->getLocEnd(), Record);
// FIXME: C++ TemplateOrInstantiation
Record.push_back(D->param_size());
@@ -169,7 +254,7 @@ void PCHDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
void PCHDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
VisitNamedDecl(D);
// FIXME: convert to LazyStmtPtr?
- // Unlike C/C++, method bodies will never be in header files.
+ // 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());
@@ -180,13 +265,13 @@ void PCHDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
Record.push_back(D->isVariadic());
Record.push_back(D->isSynthesized());
// FIXME: stable encoding for @required/@optional
- Record.push_back(D->getImplementationControl());
+ Record.push_back(D->getImplementationControl());
// FIXME: stable encoding for in/out/inout/bycopy/byref/oneway
- Record.push_back(D->getObjCDeclQualifier());
+ 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(),
+ for (ObjCMethodDecl::param_iterator P = D->param_begin(),
PEnd = D->param_end(); P != PEnd; ++P)
Writer.AddDeclRef(*P, Record);
Code = pch::DECL_OBJC_METHOD;
@@ -203,12 +288,12 @@ void PCHDeclWriter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *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(),
+ 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(),
+ for (ObjCInterfaceDecl::ivar_iterator I = D->ivar_begin(),
IEnd = D->ivar_end(); I != IEnd; ++I)
Writer.AddDeclRef(*I, Record);
Writer.AddDeclRef(D->getCategoryList(), Record);
@@ -223,7 +308,7 @@ void PCHDeclWriter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
void PCHDeclWriter::VisitObjCIvarDecl(ObjCIvarDecl *D) {
VisitFieldDecl(D);
// FIXME: stable encoding for @public/@private/@protected/@package
- Record.push_back(D->getAccessControl());
+ Record.push_back(D->getAccessControl());
Code = pch::DECL_OBJC_IVAR;
}
@@ -232,7 +317,7 @@ void PCHDeclWriter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) {
Record.push_back(D->isForwardDecl());
Writer.AddSourceLocation(D->getLocEnd(), Record);
Record.push_back(D->protocol_size());
- for (ObjCProtocolDecl::protocol_iterator
+ for (ObjCProtocolDecl::protocol_iterator
I = D->protocol_begin(), IEnd = D->protocol_end(); I != IEnd; ++I)
Writer.AddDeclRef(*I, Record);
Code = pch::DECL_OBJC_PROTOCOL;
@@ -254,7 +339,7 @@ void PCHDeclWriter::VisitObjCClassDecl(ObjCClassDecl *D) {
void PCHDeclWriter::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) {
VisitDecl(D);
Record.push_back(D->protocol_size());
- for (ObjCProtocolDecl::protocol_iterator
+ 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;
@@ -264,7 +349,7 @@ void PCHDeclWriter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) {
VisitObjCContainerDecl(D);
Writer.AddDeclRef(D->getClassInterface(), Record);
Record.push_back(D->protocol_size());
- for (ObjCProtocolDecl::protocol_iterator
+ for (ObjCProtocolDecl::protocol_iterator
I = D->protocol_begin(), IEnd = D->protocol_end(); I != IEnd; ++I)
Writer.AddDeclRef(*I, Record);
Writer.AddDeclRef(D->getNextClassCategory(), Record);
@@ -294,9 +379,8 @@ void PCHDeclWriter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
}
void PCHDeclWriter::VisitObjCImplDecl(ObjCImplDecl *D) {
- VisitNamedDecl(D);
+ VisitObjCContainerDecl(D);
Writer.AddDeclRef(D->getClassInterface(), Record);
- Writer.AddSourceLocation(D->getLocEnd(), Record);
// Abstract class (no need to define a stable pch::DECL code).
}
@@ -321,7 +405,7 @@ void PCHDeclWriter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
}
void PCHDeclWriter::VisitFieldDecl(FieldDecl *D) {
- VisitValueDecl(D);
+ VisitDeclaratorDecl(D);
Record.push_back(D->isMutable());
Record.push_back(D->getBitWidth()? 1 : 0);
if (D->getBitWidth())
@@ -330,13 +414,12 @@ void PCHDeclWriter::VisitFieldDecl(FieldDecl *D) {
}
void PCHDeclWriter::VisitVarDecl(VarDecl *D) {
- VisitValueDecl(D);
+ VisitDeclaratorDecl(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());
@@ -351,16 +434,14 @@ void PCHDeclWriter::VisitImplicitParamDecl(ImplicitParamDecl *D) {
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() &&
+ if (!D->getDeclaratorInfo() &&
+ !D->hasAttrs() &&
!D->isImplicit() &&
!D->isUsed() &&
D->getAccess() == AS_none &&
@@ -413,7 +494,7 @@ void PCHDeclWriter::VisitBlockDecl(BlockDecl *D) {
/// 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,
+void PCHDeclWriter::VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset,
uint64_t VisibleOffset) {
Record.push_back(LexicalOffset);
Record.push_back(VisibleOffset);
@@ -439,26 +520,90 @@ void PCHWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
Abv->Add(BitCodeAbbrevOp(0)); // isUsed
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
+ // DeclaratorDecl
+ Abv->Add(BitCodeAbbrevOp(pch::PREDEF_TYPE_NULL_ID)); // InfoType
// 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);
}
+/// isRequiredDecl - Check if this is a "required" Decl, which must be seen by
+/// consumers of the AST.
+///
+/// Such decls will always be deserialized from the PCH file, so we would like
+/// this to be as restrictive as possible. Currently the predicate is driven by
+/// code generation requirements, if other clients have a different notion of
+/// what is "required" then we may have to consider an alternate scheme where
+/// clients can iterate over the top-level decls and get information on them,
+/// without necessary deserializing them. We could explicitly require such
+/// clients to use a separate API call to "realize" the decl. This should be
+/// relatively painless since they would presumably only do it for top-level
+/// decls.
+//
+// FIXME: This predicate is essentially IRgen's predicate to determine whether a
+// declaration can be deferred. Merge them somehow.
+static bool isRequiredDecl(const Decl *D, ASTContext &Context) {
+ // File scoped assembly must be seen.
+ if (isa<FileScopeAsmDecl>(D))
+ return true;
+
+ // Otherwise if this isn't a function or a file scoped variable it doesn't
+ // need to be seen.
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ if (!VD->isFileVarDecl())
+ return false;
+ } else if (!isa<FunctionDecl>(D))
+ return false;
+
+ // Aliases and used decls must be seen.
+ if (D->hasAttr<AliasAttr>() || D->hasAttr<UsedAttr>())
+ return true;
+
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ // Forward declarations don't need to be seen.
+ if (!FD->isThisDeclarationADefinition())
+ return false;
+
+ // Constructors and destructors must be seen.
+ if (FD->hasAttr<ConstructorAttr>() || FD->hasAttr<DestructorAttr>())
+ return true;
+
+ // Otherwise, this is required unless it is static.
+ //
+ // FIXME: Inlines.
+ return FD->getStorageClass() != FunctionDecl::Static;
+ } else {
+ const VarDecl *VD = cast<VarDecl>(D);
+
+ // In C++, this doesn't need to be seen if it is marked "extern".
+ if (Context.getLangOptions().CPlusPlus && !VD->getInit() &&
+ (VD->getStorageClass() == VarDecl::Extern ||
+ VD->isExternC()))
+ return false;
+
+ // In C, this doesn't need to be seen unless it is a definition.
+ if (!Context.getLangOptions().CPlusPlus && !VD->getInit())
+ return false;
+
+ // Otherwise, this is required unless it is static.
+ return VD->getStorageClass() != VarDecl::Static;
+ }
+}
+
/// \brief Write a block containing all of the declarations.
void PCHWriter::WriteDeclsBlock(ASTContext &Context) {
// Enter the declarations block.
@@ -466,7 +611,7 @@ void PCHWriter::WriteDeclsBlock(ASTContext &Context) {
// Output the abbreviations that we will use in this block.
WriteDeclsBlockAbbrevs();
-
+
// Emit all of the declarations.
RecordData Record;
PCHDeclWriter W(*this, Context, Record);
@@ -517,17 +662,19 @@ void PCHWriter::WriteDeclsBlock(ASTContext &Context) {
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))
+
+ // Note "external" declarations so that we can add them to a record in the
+ // PCH file later.
+ //
+ // FIXME: This should be renamed, the predicate is much more complicated.
+ if (isRequiredDecl(D, Context))
ExternalDefinitions.push_back(ID);
}
diff --git a/lib/Frontend/PCHWriterStmt.cpp b/lib/Frontend/PCHWriterStmt.cpp
index 5235326..9497f97 100644
--- a/lib/Frontend/PCHWriterStmt.cpp
+++ b/lib/Frontend/PCHWriterStmt.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/PCHWriter.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/StmtVisitor.h"
#include "llvm/Bitcode/BitstreamWriter.h"
@@ -86,7 +87,7 @@ namespace {
void VisitShuffleVectorExpr(ShuffleVectorExpr *E);
void VisitBlockExpr(BlockExpr *E);
void VisitBlockDeclRefExpr(BlockDeclRefExpr *E);
-
+
// Objective-C Expressions
void VisitObjCStringLiteral(ObjCStringLiteral *E);
void VisitObjCEncodeExpr(ObjCEncodeExpr *E);
@@ -94,21 +95,27 @@ namespace {
void VisitObjCProtocolExpr(ObjCProtocolExpr *E);
void VisitObjCIvarRefExpr(ObjCIvarRefExpr *E);
void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E);
- void VisitObjCKVCRefExpr(ObjCKVCRefExpr *E);
+ void VisitObjCImplicitSetterGetterRefExpr(
+ ObjCImplicitSetterGetterRefExpr *E);
void VisitObjCMessageExpr(ObjCMessageExpr *E);
void VisitObjCSuperExpr(ObjCSuperExpr *E);
-
- // Objective-C Statements
+ void VisitObjCIsaExpr(ObjCIsaExpr *E);
+
+ // Objective-C Statements
void VisitObjCForCollectionStmt(ObjCForCollectionStmt *);
void VisitObjCAtCatchStmt(ObjCAtCatchStmt *);
void VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *);
void VisitObjCAtTryStmt(ObjCAtTryStmt *);
void VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *);
void VisitObjCAtThrowStmt(ObjCAtThrowStmt *);
+
+ // C++ Statements
+ void VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E);
+ void VisitCXXConstructExpr(CXXConstructExpr *E);
};
}
-void PCHStmtWriter::VisitStmt(Stmt *S) {
+void PCHStmtWriter::VisitStmt(Stmt *S) {
}
void PCHStmtWriter::VisitNullStmt(NullStmt *S) {
@@ -176,7 +183,7 @@ void PCHStmtWriter::VisitSwitchStmt(SwitchStmt *S) {
Writer.WriteSubStmt(S->getCond());
Writer.WriteSubStmt(S->getBody());
Writer.AddSourceLocation(S->getSwitchLoc(), Record);
- for (SwitchCase *SC = S->getSwitchCaseList(); SC;
+ for (SwitchCase *SC = S->getSwitchCaseList(); SC;
SC = SC->getNextSwitchCase())
Record.push_back(Writer.getSwitchCaseID(SC));
Code = pch::STMT_SWITCH;
@@ -340,7 +347,7 @@ void PCHStmtWriter::VisitStringLiteral(StringLiteral *E) {
// 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(),
+ 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);
@@ -350,7 +357,7 @@ void PCHStmtWriter::VisitStringLiteral(StringLiteral *E) {
void PCHStmtWriter::VisitCharacterLiteral(CharacterLiteral *E) {
VisitExpr(E);
Record.push_back(E->getValue());
- Writer.AddSourceLocation(E->getLoc(), Record);
+ Writer.AddSourceLocation(E->getLocation(), Record);
Record.push_back(E->isWide());
Code = pch::EXPR_CHARACTER_LITERAL;
}
@@ -371,7 +378,7 @@ void PCHStmtWriter::VisitUnaryOperator(UnaryOperator *E) {
Code = pch::EXPR_UNARY_OPERATOR;
}
-void PCHStmtWriter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
+void PCHStmtWriter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
VisitExpr(E);
Record.push_back(E->isSizeOf());
if (E->isArgumentType())
@@ -410,12 +417,23 @@ void PCHStmtWriter::VisitMemberExpr(MemberExpr *E) {
Writer.AddDeclRef(E->getMemberDecl(), Record);
Writer.AddSourceLocation(E->getMemberLoc(), Record);
Record.push_back(E->isArrow());
+ // FIXME: C++ nested-name-specifier
+ // FIXME: C++ template argument list
Code = pch::EXPR_MEMBER;
}
+void PCHStmtWriter::VisitObjCIsaExpr(ObjCIsaExpr *E) {
+ VisitExpr(E);
+ Writer.WriteSubStmt(E->getBase());
+ Writer.AddSourceLocation(E->getIsaMemberLoc(), Record);
+ Record.push_back(E->isArrow());
+ Code = pch::EXPR_OBJC_ISA;
+}
+
void PCHStmtWriter::VisitCastExpr(CastExpr *E) {
VisitExpr(E);
Writer.WriteSubStmt(E->getSubExpr());
+ Record.push_back(E->getCastKind()); // FIXME: stable encoding
}
void PCHStmtWriter::VisitBinaryOperator(BinaryOperator *E) {
@@ -439,6 +457,8 @@ void PCHStmtWriter::VisitConditionalOperator(ConditionalOperator *E) {
Writer.WriteSubStmt(E->getCond());
Writer.WriteSubStmt(E->getLHS());
Writer.WriteSubStmt(E->getRHS());
+ Writer.AddSourceLocation(E->getQuestionLoc(), Record);
+ Writer.AddSourceLocation(E->getColonLoc(), Record);
Code = pch::EXPR_CONDITIONAL_OPERATOR;
}
@@ -617,7 +637,7 @@ void PCHStmtWriter::VisitObjCStringLiteral(ObjCStringLiteral *E) {
Code = pch::EXPR_OBJC_STRING_LITERAL;
}
-void PCHStmtWriter::VisitObjCEncodeExpr(ObjCEncodeExpr *E) {
+void PCHStmtWriter::VisitObjCEncodeExpr(ObjCEncodeExpr *E) {
VisitExpr(E);
Writer.AddTypeRef(E->getEncodedType(), Record);
Writer.AddSourceLocation(E->getAtLoc(), Record);
@@ -659,13 +679,14 @@ void PCHStmtWriter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
Code = pch::EXPR_OBJC_PROPERTY_REF_EXPR;
}
-void PCHStmtWriter::VisitObjCKVCRefExpr(ObjCKVCRefExpr *E) {
+void PCHStmtWriter::VisitObjCImplicitSetterGetterRefExpr(
+ ObjCImplicitSetterGetterRefExpr *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);
+
+ // NOTE: InterfaceDecl and Base are mutually exclusive.
+ Writer.AddDeclRef(E->getInterfaceDecl(), Record);
Writer.WriteSubStmt(E->getBase());
Writer.AddSourceLocation(E->getLocation(), Record);
Writer.AddSourceLocation(E->getClassLoc(), Record);
@@ -746,11 +767,31 @@ void PCHStmtWriter::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) {
}
//===----------------------------------------------------------------------===//
+// C++ Expressions and Statements.
+//===----------------------------------------------------------------------===//
+
+void PCHStmtWriter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
+ VisitCallExpr(E);
+ Record.push_back(E->getOperator());
+ Code = pch::EXPR_CXX_OPERATOR_CALL;
+}
+
+void PCHStmtWriter::VisitCXXConstructExpr(CXXConstructExpr *E) {
+ VisitExpr(E);
+ Writer.AddDeclRef(E->getConstructor(), Record);
+ Record.push_back(E->isElidable());
+ Record.push_back(E->getNumArgs());
+ for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
+ Writer.WriteSubStmt(E->getArg(I));
+ Code = pch::EXPR_CXX_CONSTRUCT;
+}
+
+//===----------------------------------------------------------------------===//
// PCHWriter Implementation
//===----------------------------------------------------------------------===//
unsigned PCHWriter::RecordSwitchCaseID(SwitchCase *S) {
- assert(SwitchCaseIDs.find(S) == SwitchCaseIDs.end() &&
+ assert(SwitchCaseIDs.find(S) == SwitchCaseIDs.end() &&
"SwitchCase recorded twice");
unsigned NextID = SwitchCaseIDs.size();
SwitchCaseIDs[S] = NextID;
@@ -758,7 +799,7 @@ unsigned PCHWriter::RecordSwitchCaseID(SwitchCase *S) {
}
unsigned PCHWriter::getSwitchCaseID(SwitchCase *S) {
- assert(SwitchCaseIDs.find(S) != SwitchCaseIDs.end() &&
+ assert(SwitchCaseIDs.find(S) != SwitchCaseIDs.end() &&
"SwitchCase hasn't been seen yet");
return SwitchCaseIDs[S];
}
@@ -769,7 +810,7 @@ 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;
@@ -781,17 +822,17 @@ 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 &&
+ assert(Writer.Code != pch::STMT_NULL_PTR &&
"Unhandled expression writing PCH file");
- Stream.EmitRecord(Writer.Code, Record);
+ Stream.EmitRecord(Writer.Code, Record);
}
/// \brief Flush all of the statements that have been added to the
@@ -799,31 +840,31 @@ void PCHWriter::WriteSubStmt(Stmt *S) {
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 &&
+ assert(Writer.Code != pch::STMT_NULL_PTR &&
"Unhandled expression writing PCH file");
- Stream.EmitRecord(Writer.Code, Record);
-
- assert(N == StmtsToEmit.size() &&
+ 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();
}
diff --git a/lib/Frontend/PlistDiagnostics.cpp b/lib/Frontend/PlistDiagnostics.cpp
index 387ed45..a83dca0 100644
--- a/lib/Frontend/PlistDiagnostics.cpp
+++ b/lib/Frontend/PlistDiagnostics.cpp
@@ -37,26 +37,44 @@ namespace {
std::vector<const PathDiagnostic*> BatchedDiags;
const std::string OutputFile;
const LangOptions &LangOpts;
+ llvm::OwningPtr<PathDiagnosticClientFactory> PF;
+ llvm::OwningPtr<PathDiagnosticClient> SubPDC;
+ llvm::SmallVector<std::string, 1> FilesMade;
public:
- PlistDiagnostics(const std::string& prefix, const LangOptions &LangOpts);
+ PlistDiagnostics(const std::string& prefix, const LangOptions &LangOpts,
+ PathDiagnosticClientFactory *pf);
~PlistDiagnostics();
void HandlePathDiagnostic(const PathDiagnostic* D);
-
- PathGenerationScheme getGenerationScheme() const { return Extensive; }
+
+ PathGenerationScheme getGenerationScheme() const;
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) {}
+ const LangOptions &LO,
+ PathDiagnosticClientFactory *pf)
+ : OutputFile(output), LangOpts(LO), PF(pf) {
+
+ if (PF)
+ SubPDC.reset(PF->createPathDiagnosticClient(&FilesMade));
+}
PathDiagnosticClient*
clang::CreatePlistDiagnosticClient(const std::string& s,
- Preprocessor *PP, PreprocessorFactory*) {
- return new PlistDiagnostics(s, PP->getLangOptions());
+ Preprocessor *PP, PreprocessorFactory*,
+ PathDiagnosticClientFactory *PF) {
+ return new PlistDiagnostics(s, PP->getLangOptions(), PF);
+}
+
+PathDiagnosticClient::PathGenerationScheme
+PlistDiagnostics::getGenerationScheme() const {
+ if (const PathDiagnosticClient *PD = SubPDC.get())
+ return PD->getGenerationScheme();
+
+ return Extensive;
}
static void AddFID(FIDMap &FIDs, llvm::SmallVectorImpl<FileID> &V,
@@ -92,7 +110,7 @@ static void EmitLocation(llvm::raw_ostream& o, const 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";
@@ -115,7 +133,7 @@ static void EmitRange(llvm::raw_ostream& o, const SourceManager &SM,
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.getBegin(), FM, indent+1);
EmitLocation(o, SM, LangOpts, R.getEnd(), FM, indent+1, !R.isPoint);
Indent(o, indent) << "</array>\n";
}
@@ -144,12 +162,12 @@ static void ReportControlFlow(llvm::raw_ostream& o,
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;
@@ -169,39 +187,39 @@ static void ReportControlFlow(llvm::raw_ostream& o,
--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";
+ Indent(o, indent) << "</dict>\n";
}
-static void ReportEvent(llvm::raw_ostream& o, const PathDiagnosticPiece& P,
+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";
@@ -211,13 +229,13 @@ static void ReportEvent(llvm::raw_ostream& o, const PathDiagnosticPiece& P,
--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";
@@ -233,10 +251,10 @@ static void ReportMacro(llvm::raw_ostream& o,
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;
@@ -248,16 +266,16 @@ static void ReportMacro(llvm::raw_ostream& o,
ReportMacro(o, cast<PathDiagnosticMacroPiece>(**I), FM, SM, LangOpts,
indent);
break;
- }
- }
+ }
+ }
}
-static void ReportDiag(llvm::raw_ostream& o, const PathDiagnosticPiece& P,
+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,
@@ -277,38 +295,38 @@ static void ReportDiag(llvm::raw_ostream& o, const PathDiagnosticPiece& P,
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();
+ const_cast<PathDiagnostic*>(D)->flattenLocations();
BatchedDiags.push_back(D);
}
-PlistDiagnostics::~PlistDiagnostics() {
+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())
+
+ 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());
@@ -319,71 +337,89 @@ PlistDiagnostics::~PlistDiagnostics() {
// Open the file.
std::string ErrMsg;
- llvm::raw_fd_ostream o(OutputFile.c_str(), false, ErrMsg);
+ llvm::raw_fd_ostream o(OutputFile.c_str(), 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"
+ "\"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
+ // - "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.
+
+ // 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);
-
+
+ // Output the diagnostic to the sub-diagnostic client, if any.
+ if (PF) {
+ if (!SubPDC.get())
+ SubPDC.reset(PF->createPathDiagnosticClient(&FilesMade));
+
+ FilesMade.clear();
+ SubPDC->HandlePathDiagnostic(OwnedD.take());
+ SubPDC.reset(0);
+
+ if (!FilesMade.empty()) {
+ o << " <key>" << PF->getName() << "_files</key>\n";
+ o << " <array>\n";
+ for (size_t i = 0, n = FilesMade.size(); i < n ; ++i)
+ o << " <string>" << FilesMade[i] << "</string>\n";
+ o << " </array>\n";
+ }
+ }
+
// 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
index 170ab5e..25b40c7 100644
--- a/lib/Frontend/PrintParserCallbacks.cpp
+++ b/lib/Frontend/PrintParserCallbacks.cpp
@@ -39,7 +39,7 @@ namespace {
Out << "<anon>";
}
Out << "\n";
-
+
// Pass up to EmptyActions so that the symbol table is maintained right.
return MinimalAction::ActOnDeclarator(S, D);
}
@@ -69,16 +69,16 @@ namespace {
AttributeList *AttrList) {
Out << __FUNCTION__ << "\n";
return MinimalAction::ActOnStartClassInterface(AtInterfaceLoc,
- ClassName, ClassLoc,
+ ClassName, ClassLoc,
SuperName, SuperLoc,
ProtoRefs, NumProtocols,
EndProtoLoc, AttrList);
}
- /// ActOnForwardClassDeclaration -
- /// Scope will always be top level file scope.
+ /// ActOnForwardClassDeclaration -
+ /// Scope will always be top level file scope.
Action::DeclPtrTy ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
- IdentifierInfo **IdentList,
+ IdentifierInfo **IdentList,
unsigned NumElts) {
Out << __FUNCTION__ << "\n";
return MinimalAction::ActOnForwardClassDeclaration(AtClassLoc, IdentList,
@@ -101,15 +101,15 @@ namespace {
Out << "\n";
return DeclPtrTy();
}
-
- /// AddInitializerToDecl - This action is called immediately after
- /// ParseDeclarator (when an initializer is present). The code is factored
+
+ /// 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,
+ /// initializer. The declaration above should still result in a warning,
/// since the reference to "xx" is uninitialized.
- virtual void AddInitializerToDecl(DeclPtrTy Dcl, FullExprArg Init) {
+ virtual void AddInitializerToDecl(DeclPtrTy Dcl, ExprArg Init) {
Out << __FUNCTION__ << "\n";
}
@@ -142,7 +142,7 @@ namespace {
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) {
@@ -155,14 +155,14 @@ namespace {
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
@@ -170,12 +170,12 @@ namespace {
virtual DeclPtrTy ActOnLinkageSpec(SourceLocation Loc,
SourceLocation LBrace,
SourceLocation RBrace, const char *Lang,
- unsigned StrSize,
+ 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.
@@ -183,42 +183,43 @@ namespace {
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,
+
+ virtual DeclPtrTy ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
SourceLocation KWLoc, const CXXScopeSpec &SS,
IdentifierInfo *Name, SourceLocation NameLoc,
AttributeList *Attr, AccessSpecifier AS,
- bool &Owned) {
+ MultiTemplateParamsArg TemplateParameterLists,
+ bool &OwnedDecl, bool &IsDependent) {
// 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.
+ /// 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,
+ 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,
DeclPtrTy IntfDecl,
Declarator &D, ExprTy *BitfieldWidth,
@@ -226,14 +227,14 @@ namespace {
Out << __FUNCTION__ << "\n";
return DeclPtrTy();
}
-
+
virtual void ActOnFields(Scope* S, SourceLocation RecLoc, DeclPtrTy TagDecl,
- DeclPtrTy *Fields, unsigned NumFields,
+ 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,
@@ -244,7 +245,8 @@ namespace {
virtual void ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
SourceLocation RBraceLoc, DeclPtrTy EnumDecl,
- DeclPtrTy *Elements, unsigned NumElements) {
+ DeclPtrTy *Elements, unsigned NumElements,
+ Scope *S, AttributeList *AttrList) {
Out << __FUNCTION__ << "\n";
}
@@ -270,12 +272,12 @@ namespace {
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,
@@ -301,7 +303,7 @@ namespace {
return StmtEmpty();
}
- virtual OwningStmtResult ActOnIfStmt(SourceLocation IfLoc,
+ virtual OwningStmtResult ActOnIfStmt(SourceLocation IfLoc,
FullExprArg CondVal, StmtArg ThenVal,
SourceLocation ElseLoc,
StmtArg ElseVal) {
@@ -327,7 +329,7 @@ namespace {
return StmtEmpty();
}
virtual OwningStmtResult ActOnDoStmt(SourceLocation DoLoc, StmtArg Body,
- SourceLocation WhileLoc,
+ SourceLocation WhileLoc,
SourceLocation LPLoc, ExprArg Cond,
SourceLocation RPLoc){
Out << __FUNCTION__ << "\n";
@@ -372,7 +374,7 @@ namespace {
return StmtEmpty();
}
virtual OwningStmtResult ActOnReturnStmt(SourceLocation ReturnLoc,
- FullExprArg RetValExp) {
+ ExprArg RetValExp) {
Out << __FUNCTION__ << "\n";
return StmtEmpty();
}
@@ -488,12 +490,12 @@ namespace {
return ExprEmpty();
}
- virtual OwningExprResult ActOnCharacterConstant(const Token &) {
+ virtual OwningExprResult ActOnCharacterConstant(const Token &) {
Out << __FUNCTION__ << "\n";
return ExprEmpty();
}
- virtual OwningExprResult ActOnNumericConstant(const Token &) {
+ virtual OwningExprResult ActOnNumericConstant(const Token &) {
Out << __FUNCTION__ << "\n";
return ExprEmpty();
}
@@ -513,7 +515,7 @@ namespace {
}
// Postfix Expressions.
- virtual OwningExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
+ virtual OwningExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
tok::TokenKind Kind,
ExprArg Input) {
Out << __FUNCTION__ << "\n";
@@ -531,7 +533,8 @@ namespace {
tok::TokenKind OpKind,
SourceLocation MemberLoc,
IdentifierInfo &Member,
- DeclPtrTy ImplDecl) {
+ DeclPtrTy ImplDecl,
+ const CXXScopeSpec *SS=0) {
Out << __FUNCTION__ << "\n";
return ExprEmpty();
}
@@ -571,8 +574,9 @@ namespace {
Out << __FUNCTION__ << "\n";
return ExprEmpty();
}
- virtual OwningExprResult ActOnCastExpr(SourceLocation LParenLoc, TypeTy *Ty,
- SourceLocation RParenLoc,ExprArg Op){
+ virtual OwningExprResult ActOnCastExpr(Scope *S, SourceLocation LParenLoc,
+ TypeTy *Ty, SourceLocation RParenLoc,
+ ExprArg Op) {
Out << __FUNCTION__ << "\n";
return ExprEmpty();
}
@@ -722,8 +726,7 @@ namespace {
}
virtual void ActOnStartDelayedCXXMethodDeclaration(Scope *S,
- DeclPtrTy Method)
- {
+ DeclPtrTy Method) {
Out << __FUNCTION__ << "\n";
}
diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp
index d63d9cb..492b31a 100644
--- a/lib/Frontend/PrintPreprocessedOutput.cpp
+++ b/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -32,12 +32,12 @@ using namespace clang;
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)
+ else if (MI.getNumArgs() == 1)
OS << (*MI.arg_begin())->getName();
else {
MacroInfo::arg_iterator AI = MI.arg_begin(), E = MI.arg_end();
@@ -45,7 +45,7 @@ static void PrintMacroDefinition(const IdentifierInfo &II, const MacroInfo &MI,
while (AI != E)
OS << ',' << (*AI++)->getName();
}
-
+
if (MI.isVariadic()) {
if (!MI.arg_empty())
OS << ',';
@@ -53,18 +53,18 @@ static void PrintMacroDefinition(const IdentifierInfo &II, const MacroInfo &MI,
}
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());
@@ -105,14 +105,14 @@ public:
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,
+ virtual void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind,
const std::string &Str);
@@ -122,12 +122,12 @@ public:
return ConcatInfo.AvoidConcat(PrevTok, Tok);
}
void WriteLineInfo(unsigned LineNo, const char *Extra=0, unsigned ExtraLen=0);
-
+
void HandleNewlinesInToken(const char *TokStr, unsigned Len);
-
+
/// MacroDefined - This hook is called whenever a macro definition is seen.
void MacroDefined(const IdentifierInfo *II, const MacroInfo *MI);
-
+
};
} // end anonymous namespace
@@ -143,7 +143,7 @@ void PrintPPOutputPPCallbacks::WriteLineInfo(unsigned LineNo,
OS << '#' << ' ' << LineNo << ' ' << '"';
OS.write(&CurFilename[0], CurFilename.size());
OS << '"';
-
+
if (ExtraLen)
OS.write(Extra, ExtraLen);
@@ -163,12 +163,12 @@ bool PrintPPOutputPPCallbacks::MoveToLine(SourceLocation Loc) {
if (DisableLineMarkers) {
if (LineNo == CurLine) return false;
-
+
CurLine = LineNo;
-
+
if (!EmittedTokensOnThisLine && !EmittedMacroOnThisLine)
return true;
-
+
OS << '\n';
EmittedTokensOnThisLine = false;
EmittedMacroOnThisLine = false;
@@ -188,9 +188,9 @@ bool PrintPPOutputPPCallbacks::MoveToLine(SourceLocation Loc) {
}
} else {
WriteLineInfo(LineNo, 0, 0);
- }
+ }
- CurLine = LineNo;
+ CurLine = LineNo;
return true;
}
@@ -210,12 +210,12 @@ void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc,
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);
@@ -239,8 +239,8 @@ void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc,
case PPCallbacks::ExitFile:
WriteLineInfo(CurLine, " 2", 2);
break;
- case PPCallbacks::SystemHeaderPragma:
- case PPCallbacks::RenameFile:
+ case PPCallbacks::SystemHeaderPragma:
+ case PPCallbacks::RenameFile:
WriteLineInfo(CurLine);
break;
}
@@ -250,7 +250,7 @@ void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc,
///
void PrintPPOutputPPCallbacks::Ident(SourceLocation Loc, const std::string &S) {
MoveToLine(Loc);
-
+
OS.write("#ident ", strlen("#ident "));
OS.write(&S[0], S.size());
EmittedTokensOnThisLine = true;
@@ -263,7 +263,7 @@ void PrintPPOutputPPCallbacks::MacroDefined(const IdentifierInfo *II,
if (!DumpDefines ||
// Ignore __FILE__ etc.
MI->isBuiltinMacro()) return;
-
+
MoveToLine(MI->getDefinitionLoc());
PrintMacroDefinition(*II, *MI, PP, OS);
EmittedMacroOnThisLine = true;
@@ -271,14 +271,14 @@ void PrintPPOutputPPCallbacks::MacroDefined(const IdentifierInfo *II,
void PrintPPOutputPPCallbacks::PragmaComment(SourceLocation Loc,
- const IdentifierInfo *Kind,
+ 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 != '"')
@@ -291,7 +291,7 @@ void PrintPPOutputPPCallbacks::PragmaComment(SourceLocation Loc,
}
OS << '"';
}
-
+
OS << ')';
EmittedTokensOnThisLine = true;
}
@@ -307,12 +307,12 @@ bool PrintPPOutputPPCallbacks::HandleFirstTokOnLine(Token &Tok) {
// 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
@@ -321,11 +321,11 @@ bool PrintPPOutputPPCallbacks::HandleFirstTokOnLine(Token &Tok) {
// -fpreprocessed mode.
if (ColNo <= 1 && Tok.is(tok::hash))
OS << ' ';
-
+
// Otherwise, indent the appropriate number of spaces.
for (; ColNo > 1; --ColNo)
OS << ' ';
-
+
return true;
}
@@ -336,18 +336,18 @@ void PrintPPOutputPPCallbacks::HandleNewlinesInToken(const char *TokStr,
if (*TokStr != '\n' &&
*TokStr != '\r')
continue;
-
+
++NumNewlines;
-
+
// If we have \n\r or \r\n, skip both and count as one line.
if (Len != 1 &&
(TokStr[1] == '\n' || TokStr[1] == '\r') &&
TokStr[0] != TokStr[1])
++TokStr, --Len;
}
-
+
if (NumNewlines == 0) return;
-
+
CurLine += NumNewlines;
}
@@ -356,7 +356,7 @@ 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) {
@@ -364,7 +364,7 @@ struct UnknownPragmaHandler : public PragmaHandler {
// 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())
@@ -385,11 +385,11 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
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() ||
+ } 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() &&
@@ -397,7 +397,7 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
Callbacks->AvoidConcat(PrevTok, Tok))) {
OS << ' ';
}
-
+
if (IdentifierInfo *II = Tok.getIdentifierInfo()) {
OS.write(II->getName(), II->getLength());
} else if (Tok.isLiteral() && !Tok.needsCleaning() &&
@@ -407,24 +407,24 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
const char *TokPtr = Buffer;
unsigned Len = PP.getSpelling(Tok, TokPtr);
OS.write(TokPtr, Len);
-
+
// Tokens that can contain embedded newlines need to adjust our current
- // line number.
+ // line number.
if (Tok.getKind() == tok::comment)
Callbacks->HandleNewlinesInToken(TokPtr, Len);
} else {
std::string S = PP.getSpelling(Tok);
OS.write(&S[0], S.size());
-
+
// Tokens that can contain embedded newlines need to adjust our current
- // line number.
+ // line number.
if (Tok.getKind() == tok::comment)
Callbacks->HandleNewlinesInToken(&S[0], S.size());
}
Callbacks->SetEmittedTokensOnThisLine();
-
+
if (Tok.is(tok::eof)) break;
-
+
PrevTok = Tok;
PP.Lex(Tok);
}
@@ -456,7 +456,7 @@ void clang::DoPrintMacros(Preprocessor &PP, llvm::raw_ostream *OS) {
for (unsigned i = 0, e = MacrosByID.size(); i != e; ++i) {
MacroInfo &MI = *MacrosByID[i].second;
- // Ignore computed macros like __LINE__ and friends.
+ // Ignore computed macros like __LINE__ and friends.
if (MI.isBuiltinMacro()) continue;
PrintMacroDefinition(*MacrosByID[i].first, MI, PP, *OS);
diff --git a/lib/Frontend/RewriteBlocks.cpp b/lib/Frontend/RewriteBlocks.cpp
index bc855fa..25e7fc4 100644
--- a/lib/Frontend/RewriteBlocks.cpp
+++ b/lib/Frontend/RewriteBlocks.cpp
@@ -22,7 +22,6 @@
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
-#include <sstream>
using namespace clang;
using llvm::utostr;
@@ -44,28 +43,28 @@ class RewriteBlocks : public ASTConsumer {
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,
+ RewriteBlocks(std::string inFile, Diagnostic &D,
const LangOptions &LOpts);
~RewriteBlocks() {
- // Get the buffer corresponding to MainFileID.
+ // Get the buffer corresponding to MainFileID.
// If we haven't changed it, then we are done.
- if (const RewriteBuffer *RewriteBuf =
+ if (const RewriteBuffer *RewriteBuf =
Rewrite.getRewriteBufferFor(MainFileID)) {
std::string S(RewriteBuf->begin(), RewriteBuf->end());
printf("%s\n", S.c_str());
@@ -73,7 +72,7 @@ public:
printf("No changes\n");
}
}
-
+
void Initialize(ASTContext &context);
void InsertText(SourceLocation Loc, const char *StrData, unsigned StrLen);
@@ -87,51 +86,51 @@ public:
}
void HandleTopLevelSingleDecl(Decl *D);
void HandleDeclInMainFile(Decl *D);
-
- // Top level
+
+ // 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,
+
+ std::string SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
const char *funcName, std::string Tag);
- std::string SynthesizeBlockFunc(BlockExpr *CE, int i,
+ std::string SynthesizeBlockFunc(BlockExpr *CE, int i,
const char *funcName, std::string Tag);
- std::string SynthesizeBlockImpl(BlockExpr *CE, 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()) ||
+
+ if (const PointerType *PT = OCT->getAs<PointerType>()) {
+ if (isa<ObjCInterfaceType>(PT->getPointeeType()) ||
PT->getPointeeType()->isObjCQualifiedIdType())
return true;
}
@@ -146,34 +145,34 @@ public:
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;
+ 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) :
+ Diagnostic &D, const LangOptions &LOpts) :
Diags(D), LangOpts(LOpts) {
IsHeader = IsHeaderFile(inFile);
CurFunctionDef = 0;
CurMethodDef = 0;
- RewriteFailedDiag = Diags.getCustomDiagID(Diagnostic::Warning,
+ RewriteFailedDiag = Diags.getCustomDiagID(Diagnostic::Warning,
"rewriting failed");
}
@@ -186,15 +185,15 @@ ASTConsumer *clang::CreateBlockRewriter(const std::string& InFile,
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";
@@ -209,7 +208,7 @@ void RewriteBlocks::Initialize(ASTContext &context) {
Preamble += " BLOCK_HAS_COPY_DISPOSE = (1<<25),\n";
Preamble += " BLOCK_IS_GLOBAL = (1<<28)\n";
Preamble += "};\n";
- if (LangOpts.Microsoft)
+ if (LangOpts.Microsoft)
Preamble += "#define __OBJC_RW_EXTERN extern \"C\" __declspec(dllimport)\n";
else
Preamble += "#define __OBJC_RW_EXTERN extern\n";
@@ -221,14 +220,13 @@ void RewriteBlocks::Initialize(ASTContext &context) {
Preamble += "__OBJC_RW_EXTERN void *_NSConcreteGlobalBlock;\n";
Preamble += "__OBJC_RW_EXTERN void *_NSConcreteStackBlock;\n";
Preamble += "#endif\n";
-
- InsertText(SM->getLocForStartOfFile(MainFileID),
+
+ InsertText(SM->getLocForStartOfFile(MainFileID),
Preamble.c_str(), Preamble.size());
}
-void RewriteBlocks::InsertText(SourceLocation Loc, const char *StrData,
- unsigned StrLen)
-{
+void RewriteBlocks::InsertText(SourceLocation Loc, const char *StrData,
+ unsigned StrLen) {
if (!Rewrite.InsertText(Loc, StrData, StrLen))
return;
Diags.Report(Context->getFullLoc(Loc), RewriteFailedDiag);
@@ -236,21 +234,22 @@ void RewriteBlocks::InsertText(SourceLocation Loc, const char *StrData,
void RewriteBlocks::ReplaceText(SourceLocation Start, unsigned OrigLength,
const char *NewStr, unsigned NewLength) {
- if (!Rewrite.ReplaceText(Start, OrigLength, NewStr, NewLength))
+ if (!Rewrite.ReplaceText(Start, OrigLength,
+ llvm::StringRef(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(),
+ 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();
@@ -260,7 +259,7 @@ void RewriteBlocks::RewriteMethodDecl(ObjCMethodDecl *Method) {
const char *methodPtr = startBuf;
std::string Tag = "struct __block_impl *";
-
+
while (*methodPtr++ && (methodPtr != endBuf)) {
switch (*methodPtr) {
case ':':
@@ -269,13 +268,13 @@ void RewriteBlocks::RewriteMethodDecl(ObjCMethodDecl *Method) {
const char *scanType = ++methodPtr;
bool foundBlockPointer = false;
unsigned parenCount = 1;
-
+
while (parenCount) {
switch (*scanType) {
- case '(':
- parenCount++;
+ case '(':
+ parenCount++;
break;
- case ')':
+ case ')':
parenCount--;
break;
case '^':
@@ -289,7 +288,7 @@ void RewriteBlocks::RewriteMethodDecl(ObjCMethodDecl *Method) {
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).
@@ -305,34 +304,34 @@ void RewriteBlocks::RewriteMethodDecl(ObjCMethodDecl *Method) {
}
void RewriteBlocks::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) {
- for (ObjCInterfaceDecl::instmeth_iterator
- I = ClassDecl->instmeth_begin(), E = ClassDecl->instmeth_end();
+ for (ObjCInterfaceDecl::instmeth_iterator
+ I = ClassDecl->instmeth_begin(), E = ClassDecl->instmeth_end();
I != E; ++I)
RewriteMethodDecl(*I);
- for (ObjCInterfaceDecl::classmeth_iterator
+ for (ObjCInterfaceDecl::classmeth_iterator
I = ClassDecl->classmeth_begin(), E = ClassDecl->classmeth_end();
I != E; ++I)
RewriteMethodDecl(*I);
}
void RewriteBlocks::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) {
- for (ObjCCategoryDecl::instmeth_iterator
- I = CatDecl->instmeth_begin(), E = CatDecl->instmeth_end();
+ for (ObjCCategoryDecl::instmeth_iterator
+ I = CatDecl->instmeth_begin(), E = CatDecl->instmeth_end();
I != E; ++I)
RewriteMethodDecl(*I);
- for (ObjCCategoryDecl::classmeth_iterator
+ for (ObjCCategoryDecl::classmeth_iterator
I = CatDecl->classmeth_begin(), E = CatDecl->classmeth_end();
I != E; ++I)
RewriteMethodDecl(*I);
}
void RewriteBlocks::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
- for (ObjCProtocolDecl::instmeth_iterator
- I = PDecl->instmeth_begin(), E = PDecl->instmeth_end();
+ for (ObjCProtocolDecl::instmeth_iterator
+ I = PDecl->instmeth_begin(), E = PDecl->instmeth_end();
I != E; ++I)
RewriteMethodDecl(*I);
- for (ObjCProtocolDecl::classmeth_iterator
- I = PDecl->classmeth_begin(), E = PDecl->classmeth_end();
+ for (ObjCProtocolDecl::classmeth_iterator
+ I = PDecl->classmeth_begin(), E = PDecl->classmeth_end();
I != E; ++I)
RewriteMethodDecl(*I);
}
@@ -347,10 +346,10 @@ void RewriteBlocks::HandleTopLevelSingleDecl(Decl *D) {
// 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))
@@ -374,7 +373,7 @@ std::string RewriteBlocks::SynthesizeBlockFunc(BlockExpr *CE, int i,
funcName + "_" + "block_func_" + utostr(i);
BlockDecl *BD = CE->getBlockDecl();
-
+
if (isa<FunctionNoProtoType>(AFT)) {
S += "()";
} else if (BD->param_empty()) {
@@ -400,19 +399,19 @@ std::string RewriteBlocks::SynthesizeBlockFunc(BlockExpr *CE, int i,
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(),
+ 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(),
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
E = BlockByCopyDecls.end(); I != E; ++I) {
S += " ";
std::string Name = (*I)->getNameAsString();
@@ -420,7 +419,7 @@ std::string RewriteBlocks::SynthesizeBlockFunc(BlockExpr *CE, int i,
//
// void (^myImportedClosure)(void);
// myImportedClosure = ^(void) { setGlobalInt(x + y); };
- //
+ //
// void (^anotherClosure)(void);
// anotherClosure = ^(void) {
// myImportedClosure(); // import and invoke the closure
@@ -445,13 +444,13 @@ std::string RewriteBlocks::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
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(),
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = ImportedBlockDecls.begin(),
E = ImportedBlockDecls.end(); I != E; ++I) {
S += "_Block_copy_assign(&dst->";
S += (*I)->getNameAsString();
@@ -464,13 +463,13 @@ std::string RewriteBlocks::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
S += "_block_dispose_" + utostr(i);
S += "(" + StructRef;
S += "*src) {";
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = ImportedBlockDecls.begin(),
+ 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";
+ S += "}\n";
return S;
}
@@ -478,20 +477,20 @@ 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(),
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
E = BlockByCopyDecls.end(); I != E; ++I) {
S += " ";
std::string FieldName = (*I)->getNameAsString();
@@ -500,7 +499,7 @@ std::string RewriteBlocks::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
//
// void (^myImportedBlock)(void);
// myImportedBlock = ^(void) { setGlobalInt(x + y); };
- //
+ //
// void (^anotherBlock)(void);
// anotherBlock = ^(void) {
// myImportedBlock(); // import and invoke the closure
@@ -517,7 +516,7 @@ std::string RewriteBlocks::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
S += FieldName + ";\n";
}
// Output all "by ref" declarations.
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
E = BlockByRefDecls.end(); I != E; ++I) {
S += " ";
std::string FieldName = (*I)->getNameAsString();
@@ -526,7 +525,7 @@ std::string RewriteBlocks::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
//
// void (^myImportedBlock)(void);
// myImportedBlock = ^(void) { setGlobalInt(x + y); };
- //
+ //
// void (^anotherBlock)(void);
// anotherBlock = ^(void) {
// myImportedBlock(); // import and invoke the closure
@@ -549,12 +548,12 @@ std::string RewriteBlocks::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
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(),
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
E = BlockByCopyDecls.end(); I != E; ++I) {
std::string Name = (*I)->getNameAsString();
Constructor += " ";
@@ -565,7 +564,7 @@ std::string RewriteBlocks::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
Constructor += Name + ";\n";
}
// Initialize all "by ref" arguments.
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
E = BlockByRefDecls.end(); I != E; ++I) {
std::string Name = (*I)->getNameAsString();
Constructor += " ";
@@ -599,21 +598,21 @@ void RewriteBlocks::SynthesizeBlockLiterals(SourceLocation FunLocStart,
CollectBlockDeclRefInfo(Blocks[i]);
std::string Tag = "__" + std::string(FunName) + "_block_impl_" + utostr(i);
-
- std::string CI = SynthesizeBlockImpl(Blocks[i], Tag,
+
+ 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();
@@ -627,7 +626,7 @@ void RewriteBlocks::SynthesizeBlockLiterals(SourceLocation FunLocStart,
void RewriteBlocks::InsertBlockLiteralsWithinFunction(FunctionDecl *FD) {
SourceLocation FunLocStart = FD->getTypeSpecStartLoc();
const char *FuncName = FD->getNameAsCString();
-
+
SynthesizeBlockLiterals(FunLocStart, FuncName);
}
@@ -638,7 +637,7 @@ void RewriteBlocks::InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD) {
std::string::size_type loc = 0;
while ((loc = FuncName.find(":", loc)) != std::string::npos)
FuncName.replace(loc, 1, "_");
-
+
SynthesizeBlockLiterals(FunLocStart, FuncName.c_str());
}
@@ -668,7 +667,7 @@ void RewriteBlocks::GetBlockCallExprs(Stmt *S) {
else
GetBlockCallExprs(*CI);
}
-
+
if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
if (CE->getCallee()->getType()->isBlockPointerType()) {
BlockCallExprs[dyn_cast<BlockDeclRefExpr>(CE->getCallee())] = CE;
@@ -681,38 +680,38 @@ 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();
+ CPT = DRE->getType()->getAs<BlockPointerType>();
} else if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(Exp->getCallee())) {
closureName = CDRE->getDecl()->getNameAsCString();
- CPT = CDRE->getType()->getAsBlockPointerType();
+ CPT = CDRE->getType()->getAs<BlockPointerType>();
} else if (MemberExpr *MExpr = dyn_cast<MemberExpr>(Exp->getCallee())) {
closureName = MExpr->getMemberDecl()->getNameAsCString();
- CPT = MExpr->getType()->getAsBlockPointerType();
+ CPT = MExpr->getType()->getAs<BlockPointerType>();
} else {
assert(1 && "RewriteBlockClass: Bad type");
}
assert(CPT && "RewriteBlockClass: Bad type");
- const FunctionType *FT = CPT->getPointeeType()->getAsFunctionType();
+ const FunctionType *FT = CPT->getPointeeType()->getAs<FunctionType>();
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.
+ // Synthesize the cast.
BlockCall += "(" + Exp->getType().getAsString() + "(*)";
BlockCall += "(struct __block_impl *";
if (FTP) {
- for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(),
+ 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 *)";
@@ -722,11 +721,11 @@ std::string RewriteBlocks::SynthesizeBlockCall(CallExpr *Exp) {
PrintingPolicy(LangOpts));
BlockCall += closureExprBuf.str();
BlockCall += ")->FuncPtr)";
-
+
// Add the arguments.
BlockCall += "((struct __block_impl *)";
BlockCall += closureExprBuf.str();
- for (CallExpr::arg_iterator I = Exp->arg_begin(),
+ for (CallExpr::arg_iterator I = Exp->arg_begin(),
E = Exp->arg_end(); I != E; ++I) {
std::string syncExprBufS;
llvm::raw_string_ostream Buf(syncExprBufS);
@@ -738,11 +737,11 @@ std::string RewriteBlocks::SynthesizeBlockCall(CallExpr *Exp) {
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,
+ ReplaceText(Exp->getLocStart(), endBuf-startBuf,
BlockCall.c_str(), BlockCall.size());
}
@@ -754,19 +753,19 @@ void RewriteBlocks::RewriteBlockDeclRefExpr(BlockDeclRefExpr *BDRE) {
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 '^':
+ case '^':
// Replace the '^' with '*'.
LocStart = LocStart.getFileLocWithOffset(argPtr-startBuf);
ReplaceText(LocStart, 1, "*", 1);
@@ -779,31 +778,31 @@ void RewriteBlocks::RewriteCastExpr(CastExpr *CE) {
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 '^':
+ case '^':
// Replace the '^' with '*'.
DeclLoc = DeclLoc.getFileLocWithOffset(argPtr-startArgList);
ReplaceText(DeclLoc, 1, "*", 1);
break;
- case '(':
- parenCount++;
+ case '(':
+ parenCount++;
break;
- case ')':
+ case ')':
parenCount--;
break;
}
@@ -813,16 +812,16 @@ void RewriteBlocks::RewriteBlockPointerFunctionArgs(FunctionDecl *FD) {
bool RewriteBlocks::PointerTypeTakesAnyBlockArguments(QualType QT) {
const FunctionProtoType *FTP;
- const PointerType *PT = QT->getAsPointerType();
+ const PointerType *PT = QT->getAs<PointerType>();
if (PT) {
- FTP = PT->getPointeeType()->getAsFunctionProtoType();
+ FTP = PT->getPointeeType()->getAs<FunctionProtoType>();
} else {
- const BlockPointerType *BPT = QT->getAsBlockPointerType();
+ const BlockPointerType *BPT = QT->getAs<BlockPointerType>();
assert(BPT && "BlockPointerTypeTakeAnyBlockArguments(): not a block pointer type");
- FTP = BPT->getPointeeType()->getAsFunctionProtoType();
+ FTP = BPT->getPointeeType()->getAs<FunctionProtoType>();
}
if (FTP) {
- for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(),
+ for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(),
E = FTP->arg_type_end(); I != E; ++I)
if (isBlockPointerType(*I))
return true;
@@ -830,15 +829,15 @@ bool RewriteBlocks::PointerTypeTakesAnyBlockArguments(QualType QT) {
return false;
}
-void RewriteBlocks::GetExtentOfArgList(const char *Name,
+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;
@@ -855,7 +854,7 @@ 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;
@@ -865,15 +864,15 @@ void RewriteBlocks::RewriteBlockPointerDecl(NamedDecl *ND) {
DeclT = TDD->getUnderlyingType();
else if (FieldDecl *FD = dyn_cast<FieldDecl>(ND))
DeclT = FD->getType();
- else
+ 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 == '^') {
@@ -898,7 +897,7 @@ void RewriteBlocks::RewriteBlockPointerDecl(NamedDecl *ND) {
return;
}
-void RewriteBlocks::CollectBlockDeclRefInfo(BlockExpr *Exp) {
+void RewriteBlocks::CollectBlockDeclRefInfo(BlockExpr *Exp) {
// Add initializers for any closure decl refs.
GetBlockDeclRefExprs(Exp->getBody());
if (BlockDeclRefs.size()) {
@@ -925,7 +924,7 @@ std::string RewriteBlocks::SynthesizeBlockInitExpr(BlockExpr *Exp, VarDecl *VD)
CollectBlockDeclRefInfo(Exp);
std::string FuncName;
-
+
if (CurFunctionDef)
FuncName = std::string(CurFunctionDef->getNameAsString());
else if (CurMethodDef) {
@@ -936,27 +935,27 @@ std::string RewriteBlocks::SynthesizeBlockInitExpr(BlockExpr *Exp, VarDecl *VD)
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;
@@ -966,7 +965,7 @@ std::string RewriteBlocks::SynthesizeBlockInitExpr(BlockExpr *Exp, VarDecl *VD)
// Add initializers for any closure decl refs.
if (BlockDeclRefs.size()) {
// Output all "by copy" declarations.
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
E = BlockByCopyDecls.end(); I != E; ++I) {
Init += ",";
if (isObjCType((*I)->getType())) {
@@ -981,7 +980,7 @@ std::string RewriteBlocks::SynthesizeBlockInitExpr(BlockExpr *Exp, VarDecl *VD)
}
}
// Output all "by ref" declarations.
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
E = BlockByRefDecls.end(); I != E; ++I) {
Init += ",&";
Init += (*I)->getNameAsString();
@@ -1007,7 +1006,7 @@ Stmt *RewriteBlocks::RewriteFunctionBody(Stmt *S) {
if (*CI) {
if (BlockExpr *CBE = dyn_cast<BlockExpr>(*CI)) {
RewriteFunctionBody(CBE->getBody());
-
+
// 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());
@@ -1030,18 +1029,18 @@ Stmt *RewriteBlocks::RewriteFunctionBody(Stmt *S) {
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())
+ 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())
+ else if (TD->getUnderlyingType()->isFunctionPointerType())
CheckFunctionPointerDecl(TD->getUnderlyingType(), TD);
}
}
@@ -1055,9 +1054,9 @@ Stmt *RewriteBlocks::RewriteFunctionBody(Stmt *S) {
return S;
}
-void RewriteBlocks::RewriteFunctionProtoType(QualType funcType, NamedDecl *D) {
+void RewriteBlocks::RewriteFunctionProtoType(QualType funcType, NamedDecl *D) {
if (FunctionProtoType *fproto = dyn_cast<FunctionProtoType>(funcType)) {
- for (FunctionProtoType::arg_type_iterator I = fproto->arg_type_begin(),
+ 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!
@@ -1068,7 +1067,7 @@ void RewriteBlocks::RewriteFunctionProtoType(QualType funcType, NamedDecl *D) {
}
void RewriteBlocks::CheckFunctionPointerDecl(QualType funcType, NamedDecl *ND) {
- const PointerType *PT = funcType->getAsPointerType();
+ const PointerType *PT = funcType->getAs<PointerType>();
if (PT && PointerTypeTakesAnyBlockArguments(funcType))
RewriteFunctionProtoType(PT->getPointeeType(), ND);
}
@@ -1090,7 +1089,7 @@ void RewriteBlocks::HandleDeclInMainFile(Decl *D) {
// and any copy/dispose helper functions.
InsertBlockLiteralsWithinFunction(FD);
CurFunctionDef = 0;
- }
+ }
return;
}
if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
@@ -1116,7 +1115,7 @@ void RewriteBlocks::HandleDeclInMainFile(Decl *D) {
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(),
+ SynthesizeBlockLiterals(VD->getTypeSpecStartLoc(),
VD->getNameAsCString());
} else if (CastExpr *CE = dyn_cast<CastExpr>(VD->getInit())) {
RewriteCastExpr(CE);
@@ -1135,13 +1134,13 @@ void RewriteBlocks::HandleDeclInMainFile(Decl *D) {
if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
if (isBlockPointerType(TD->getUnderlyingType()))
RewriteBlockPointerDecl(TD);
- else if (TD->getUnderlyingType()->isFunctionPointerType())
+ 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(),
+ for (RecordDecl::field_iterator i = RD->field_begin(),
e = RD->field_end(); i != e; ++i) {
FieldDecl *FD = *i;
if (isBlockPointerType(FD->getType()))
diff --git a/lib/Frontend/RewriteMacros.cpp b/lib/Frontend/RewriteMacros.cpp
index 5ef4892..d92f5c7 100644
--- a/lib/Frontend/RewriteMacros.cpp
+++ b/lib/Frontend/RewriteMacros.cpp
@@ -16,10 +16,11 @@
#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"
+#include <cstdio>
+
using namespace clang;
/// isSameToken - Return true if the two specified tokens start have the same
@@ -30,14 +31,14 @@ static bool isSameToken(Token &RawTok, Token &PPTok) {
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;
}
@@ -47,11 +48,11 @@ static bool isSameToken(Token &RawTok, Token &PPTok) {
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++];
}
@@ -61,24 +62,24 @@ static const Token &GetNextRawTok(const std::vector<Token> &RawTokens,
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));
}
@@ -87,7 +88,7 @@ static void LexRawTokensFromMainFile(Preprocessor &PP,
/// 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());
@@ -97,12 +98,12 @@ void clang::RewriteMacrosInInput(Preprocessor &PP, llvm::raw_ostream *OS) {
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
@@ -117,7 +118,7 @@ void clang::RewriteMacrosInInput(Preprocessor &PP, llvm::raw_ostream *OS) {
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
@@ -129,16 +130,16 @@ void clang::RewriteMacrosInInput(Preprocessor &PP, llvm::raw_ostream *OS) {
const IdentifierInfo *II = RawTokens[CurRawTok].getIdentifierInfo();
if (!strcmp(II->getName(), "warning")) {
// Comment out #warning.
- RB.InsertTextAfter(SM.getFileOffset(RawTok.getLocation()), "//", 2);
+ RB.InsertTextAfter(SM.getFileOffset(RawTok.getLocation()), "//");
} 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);
+ RB.InsertTextAfter(SM.getFileOffset(RawTok.getLocation()), "//");
}
}
-
+
// Otherwise, if this is a #include or some other directive, just leave it
// in the file by skipping over the line.
RawTok = GetNextRawTok(RawTokens, CurRawTok, false);
@@ -146,7 +147,7 @@ void clang::RewriteMacrosInInput(Preprocessor &PP, llvm::raw_ostream *OS) {
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);
@@ -165,7 +166,7 @@ void clang::RewriteMacrosInInput(Preprocessor &PP, llvm::raw_ostream *OS) {
// 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);
+ RB.InsertTextAfter(RawOffs, " /*"+HasSpace);
unsigned EndPos;
do {
@@ -173,20 +174,20 @@ void clang::RewriteMacrosInInput(Preprocessor &PP, llvm::raw_ostream *OS) {
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);
+ RB.InsertTextBefore(EndPos, "*/");
continue;
}
-
+
// Otherwise, there was a replacement an expansion. Insert the new token
// in the output buffer. Insert the whole run of new tokens at once to get
// them in the right order.
@@ -199,12 +200,12 @@ void clang::RewriteMacrosInInput(Preprocessor &PP, llvm::raw_ostream *OS) {
PPOffs = SM.getFileOffset(PPLoc);
}
Expansion += ' ';
- RB.InsertTextBefore(InsertPos, &Expansion[0], Expansion.size());
+ RB.InsertTextBefore(InsertPos, Expansion);
}
// Get the buffer corresponding to MainFileID. If we haven't changed it, then
// we are done.
- if (const RewriteBuffer *RewriteBuf =
+ if (const RewriteBuffer *RewriteBuf =
Rewrite.getRewriteBufferFor(SM.getMainFileID())) {
//printf("Changed:\n");
*OS << std::string(RewriteBuf->begin(), RewriteBuf->end());
diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp
index cf31f2b..55ab78e 100644
--- a/lib/Frontend/RewriteObjC.cpp
+++ b/lib/Frontend/RewriteObjC.cpp
@@ -20,12 +20,11 @@
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Lex/Lexer.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/OwningPtr.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/Streams.h"
-#include "llvm/Support/raw_ostream.h"
using namespace clang;
using llvm::utostr;
@@ -36,14 +35,14 @@ namespace {
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;
@@ -54,9 +53,9 @@ namespace {
llvm::SmallVector<int, 8> ObjCBcLabelNo;
// Remember all the @protocol(<expr>) expressions.
llvm::SmallPtrSet<ObjCProtocolDecl *, 32> ProtocolExprDecls;
-
+
unsigned NumObjCStringLiterals;
-
+
FunctionDecl *MsgSendFunctionDecl;
FunctionDecl *MsgSendSuperFunctionDecl;
FunctionDecl *MsgSendStretFunctionDecl;
@@ -67,25 +66,25 @@ namespace {
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;
@@ -97,7 +96,7 @@ namespace {
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;
@@ -110,7 +109,7 @@ namespace {
// 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.
@@ -118,9 +117,9 @@ namespace {
FunctionDecl *CurFunctionDef;
VarDecl *GlobalVarDecl;
-
+
bool DisableReplaceStmt;
-
+
static const int OBJC_ABI_VERSION =7 ;
public:
virtual void Initialize(ASTContext &context);
@@ -137,12 +136,12 @@ namespace {
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.
@@ -175,7 +174,7 @@ namespace {
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())) {
+ if (!Rewrite.ReplaceText(SrcRange.getBegin(), Size, Str)) {
ReplacedNodes[Old] = New;
return;
}
@@ -188,31 +187,33 @@ namespace {
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) ||
+ if (!Rewrite.InsertText(Loc, llvm::StringRef(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) ||
+ if (!Rewrite.ReplaceText(Start, OrigLength,
+ llvm::StringRef(NewStr, NewLength)) ||
SilenceRewriteMacroWarning)
return;
-
+
Diags.Report(Context->getFullLoc(Start), RewriteFailedDiag);
}
-
+
// Syntactic Rewriting.
void RewritePrologue(SourceLocation Loc);
void RewriteInclude();
@@ -237,18 +238,18 @@ namespace {
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,
+ Stmt *RewritePropertySetter(BinaryOperator *BinOp, Expr *newStmt,
SourceRange SrcRange);
Stmt *RewriteAtSelector(ObjCSelectorExpr *Exp);
Stmt *RewriteMessageExpr(ObjCMessageExpr *Exp);
@@ -262,13 +263,13 @@ namespace {
Stmt *RewriteObjCThrowStmt(ObjCAtThrowStmt *S);
Stmt *RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
SourceLocation OrigEnd);
- CallExpr *SynthesizeCallToFunctionDecl(FunctionDecl *FD,
+ 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();
@@ -278,14 +279,14 @@ namespace {
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,
@@ -293,69 +294,69 @@ namespace {
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 *prefix,
const char *ClassName,
std::string &Result);
void SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl,
std::string &Result);
- void SynthesizeIvarOffsetComputation(ObjCImplementationDecl *IDecl,
- ObjCIvarDecl *ivar,
+ 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 RewriteBlocksInFunctionProtoType(QualType funcType, NamedDecl *D);
void CheckFunctionPointerDecl(QualType dType, NamedDecl *ND);
-
+
void InsertBlockLiteralsWithinFunction(FunctionDecl *FD);
void InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD);
-
- // Block specific rewrite rules.
+
+ // 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,
+
+ std::string SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
const char *funcName, std::string Tag);
- std::string SynthesizeBlockFunc(BlockExpr *CE, int i,
+ std::string SynthesizeBlockFunc(BlockExpr *CE, int i,
const char *funcName, std::string Tag);
- std::string SynthesizeBlockImpl(BlockExpr *CE, 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()) ||
+
+ if (const PointerType *PT = OCT->getAs<PointerType>()) {
+ if (isa<ObjCInterfaceType>(PT->getPointeeType()) ||
PT->getPointeeType()->isObjCQualifiedIdType())
return true;
}
@@ -365,12 +366,12 @@ namespace {
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++) {
+ for (unsigned i = 0; i < From.length(); i++) {
if (From[i] == '"')
To += "\\\"";
else
@@ -380,10 +381,10 @@ namespace {
};
}
-void RewriteObjC::RewriteBlocksInFunctionProtoType(QualType funcType,
- NamedDecl *D) {
+void RewriteObjC::RewriteBlocksInFunctionProtoType(QualType funcType,
+ NamedDecl *D) {
if (FunctionProtoType *fproto = dyn_cast<FunctionProtoType>(funcType)) {
- for (FunctionProtoType::arg_type_iterator I = fproto->arg_type_begin(),
+ 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!
@@ -394,24 +395,24 @@ void RewriteObjC::RewriteBlocksInFunctionProtoType(QualType funcType,
}
void RewriteObjC::CheckFunctionPointerDecl(QualType funcType, NamedDecl *ND) {
- const PointerType *PT = funcType->getAsPointerType();
+ const PointerType *PT = funcType->getAs<PointerType>();
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;
+ 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,
@@ -419,16 +420,16 @@ RewriteObjC::RewriteObjC(std::string inFile, llvm::raw_ostream* OS,
: Diags(D), LangOpts(LOpts), InFileName(inFile), OutFile(OS),
SilenceRewriteMacroWarning(silenceMacroWarn) {
IsHeader = IsHeaderFile(inFile);
- RewriteFailedDiag = Diags.getCustomDiagID(Diagnostic::Warning,
+ RewriteFailedDiag = Diags.getCustomDiagID(Diagnostic::Warning,
"rewriting sub-expression within a macro (may not be correct)");
- TryFinallyContainsReturnDiag = Diags.getCustomDiagID(Diagnostic::Warning,
+ 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,
+ Diagnostic &Diags,
const LangOptions &LOpts,
bool SilenceRewriteMacroWarning) {
return new RewriteObjC(InFile, OS, Diags, LOpts, SilenceRewriteMacroWarning);
@@ -461,15 +462,15 @@ void RewriteObjC::Initialize(ASTContext &context) {
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)
@@ -573,7 +574,7 @@ void RewriteObjC::HandleTopLevelSingleDecl(Decl *D) {
// 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;
@@ -592,7 +593,7 @@ void RewriteObjC::HandleTopLevelSingleDecl(Decl *D) {
RewriteCategoryDecl(CD);
} else if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D)) {
RewriteProtocolDecl(PD);
- } else if (ObjCForwardProtocolDecl *FP =
+ } else if (ObjCForwardProtocolDecl *FP =
dyn_cast<ObjCForwardProtocolDecl>(D)){
RewriteForwardProtocolDecl(FP);
} else if (LinkageSpecDecl *LSD = dyn_cast<LinkageSpecDecl>(D)) {
@@ -618,7 +619,7 @@ void RewriteObjC::RewriteInclude() {
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 == '#') {
@@ -629,7 +630,7 @@ void RewriteObjC::RewriteInclude() {
return;
if (!strncmp(BufPtr, "import", ImportLen)) {
// replace import with include
- SourceLocation ImportLoc =
+ SourceLocation ImportLoc =
LocStart.getFileLocWithOffset(BufPtr-MainBufStart);
ReplaceText(ImportLoc, ImportLen, "include", IncludeLen);
BufPtr += ImportLen;
@@ -642,27 +643,27 @@ 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);
}
@@ -692,35 +693,35 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
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).
+ // 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).
+ // 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();
@@ -733,7 +734,7 @@ void RewriteObjC::RewriteForwardClassDecl(ObjCClassDecl *ClassDecl) {
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.
@@ -754,16 +755,16 @@ void RewriteObjC::RewriteForwardClassDecl(ObjCClassDecl *ClassDecl) {
typedefString += ForwardDecl->getNameAsString();
typedefString += ";\n#endif\n";
}
-
+
// Replace the @class with typedefs corresponding to the classes.
- ReplaceText(startLoc, semiPtr-startBuf+1,
+ 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);
@@ -773,26 +774,25 @@ void RewriteObjC::RewriteMethodDeclaration(ObjCMethodDecl *Method) {
}
}
-void RewriteObjC::RewriteProperty(ObjCPropertyDecl *prop)
-{
+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(), E = CatDecl->instmeth_end();
+
+ for (ObjCCategoryDecl::instmeth_iterator
+ I = CatDecl->instmeth_begin(), E = CatDecl->instmeth_end();
I != E; ++I)
RewriteMethodDeclaration(*I);
- for (ObjCCategoryDecl::classmeth_iterator
+ for (ObjCCategoryDecl::classmeth_iterator
I = CatDecl->classmeth_begin(), E = CatDecl->classmeth_end();
I != E; ++I)
RewriteMethodDeclaration(*I);
@@ -803,14 +803,14 @@ void RewriteObjC::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) {
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(), E = PDecl->instmeth_end();
+
+ for (ObjCProtocolDecl::instmeth_iterator
+ I = PDecl->instmeth_begin(), E = PDecl->instmeth_end();
I != E; ++I)
RewriteMethodDeclaration(*I);
for (ObjCProtocolDecl::classmeth_iterator
@@ -831,14 +831,14 @@ void RewriteObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
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());
-
+
}
}
}
@@ -851,7 +851,7 @@ void RewriteObjC::RewriteForwardProtocolDecl(ObjCForwardProtocolDecl *PDecl) {
ReplaceText(LocStart, 0, "// ", 3);
}
-void RewriteObjC::RewriteObjCMethodDecl(ObjCMethodDecl *OMD,
+void RewriteObjC::RewriteObjCMethodDecl(ObjCMethodDecl *OMD,
std::string &ResultStr) {
//fprintf(stderr,"In RewriteObjCMethodDecl\n");
const FunctionType *FPRetType = 0;
@@ -864,35 +864,35 @@ void RewriteObjC::RewriteObjCMethodDecl(ObjCMethodDecl *OMD,
// syntax (where a decaration models use).
QualType retType = OMD->getResultType();
QualType PointeeTy;
- if (const PointerType* PT = retType->getAsPointerType())
+ if (const PointerType* PT = retType->getAs<PointerType>())
PointeeTy = PT->getPointeeType();
- else if (const BlockPointerType *BPT = retType->getAsBlockPointerType())
+ else if (const BlockPointerType *BPT = retType->getAs<BlockPointerType>())
PointeeTy = BPT->getPointeeType();
- if ((FPRetType = PointeeTy->getAsFunctionType())) {
+ if ((FPRetType = PointeeTy->getAs<FunctionType>())) {
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 =
+
+ if (ObjCCategoryImplDecl *CID =
dyn_cast<ObjCCategoryImplDecl>(OMD->getDeclContext())) {
NameStr += CID->getNameAsString();
NameStr += "_";
}
- // Append selector names, replacing ':' with '_'
+ // Append selector names, replacing ':' with '_'
{
std::string selString = OMD->getSelector().getAsString();
int len = selString.size();
@@ -904,10 +904,10 @@ void RewriteObjC::RewriteObjCMethodDecl(ObjCMethodDecl *OMD,
// 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());
@@ -922,11 +922,11 @@ void RewriteObjC::RewriteObjCMethodDecl(ObjCMethodDecl *OMD,
}
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) {
@@ -939,7 +939,7 @@ void RewriteObjC::RewriteObjCMethodDecl(ObjCMethodDecl *OMD,
std::string Name = PDecl->getNameAsString();
if (isTopLevelBlockPointerType(PDecl->getType())) {
// Make sure we convert "t (^)(...)" to "t (*)(...)".
- const BlockPointerType *BPT = PDecl->getType()->getAsBlockPointerType();
+ const BlockPointerType *BPT = PDecl->getType()->getAs<BlockPointerType>();
Context->getPointerType(BPT->getPointeeType()).getAsStringInternal(Name,
Context->PrintingPolicy);
} else
@@ -950,10 +950,10 @@ void RewriteObjC::RewriteObjCMethodDecl(ObjCMethodDecl *OMD,
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 += "(";
@@ -975,12 +975,12 @@ void RewriteObjC::RewriteObjCMethodDecl(ObjCMethodDecl *OMD,
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() : CID->instmeth_begin(),
E = IMD ? IMD->instmeth_end() : CID->instmeth_end();
@@ -996,7 +996,7 @@ void RewriteObjC::RewriteImplementationDecl(Decl *OID) {
ReplaceText(LocStart, endBuf-startBuf,
ResultStr.c_str(), ResultStr.size());
}
-
+
for (ObjCCategoryImplDecl::classmeth_iterator
I = IMD ? IMD->classmeth_begin() : CID->classmeth_begin(),
E = IMD ? IMD->classmeth_end() : CID->classmeth_end();
@@ -1006,15 +1006,15 @@ void RewriteObjC::RewriteImplementationDecl(Decl *OID) {
RewriteObjCMethodDecl(OMD, ResultStr);
SourceLocation LocStart = OMD->getLocStart();
SourceLocation LocEnd = OMD->getCompoundBody()->getLocStart();
-
+
const char *startBuf = SM->getCharacterData(LocStart);
const char *endBuf = SM->getCharacterData(LocEnd);
ReplaceText(LocStart, endBuf-startBuf,
- ResultStr.c_str(), ResultStr.size());
+ ResultStr.c_str(), ResultStr.size());
}
for (ObjCCategoryImplDecl::propimpl_iterator
I = IMD ? IMD->propimpl_begin() : CID->propimpl_begin(),
- E = IMD ? IMD->propimpl_end() : CID->propimpl_end();
+ E = IMD ? IMD->propimpl_end() : CID->propimpl_end();
I != E; ++I) {
RewritePropertyImplDecl(*I, IMD, CID);
}
@@ -1022,7 +1022,7 @@ void RewriteObjC::RewriteImplementationDecl(Decl *OID) {
if (IMD)
InsertText(IMD->getLocEnd(), "// ", 3);
else
- InsertText(CID->getLocEnd(), "// ", 3);
+ InsertText(CID->getLocEnd(), "// ", 3);
}
void RewriteObjC::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) {
@@ -1042,16 +1042,16 @@ void RewriteObjC::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) {
ObjCForwardDecls.insert(ClassDecl);
}
SynthesizeObjCInternalStruct(ClassDecl, ResultStr);
-
- for (ObjCInterfaceDecl::prop_iterator I = ClassDecl->prop_begin(),
+
+ for (ObjCInterfaceDecl::prop_iterator I = ClassDecl->prop_begin(),
E = ClassDecl->prop_end(); I != E; ++I)
RewriteProperty(*I);
- for (ObjCInterfaceDecl::instmeth_iterator
+ for (ObjCInterfaceDecl::instmeth_iterator
I = ClassDecl->instmeth_begin(), E = ClassDecl->instmeth_end();
I != E; ++I)
RewriteMethodDeclaration(*I);
- for (ObjCInterfaceDecl::classmeth_iterator
- I = ClassDecl->classmeth_begin(), E = ClassDecl->classmeth_end();
+ for (ObjCInterfaceDecl::classmeth_iterator
+ I = ClassDecl->classmeth_begin(), E = ClassDecl->classmeth_end();
I != E; ++I)
RewriteMethodDeclaration(*I);
@@ -1068,20 +1068,20 @@ Stmt *RewriteObjC::RewritePropertySetter(BinaryOperator *BinOp, Expr *newStmt,
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(),
+ 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;
@@ -1096,18 +1096,18 @@ Stmt *RewriteObjC::RewritePropertyGetter(ObjCPropertyRefExpr *PropRefExpr) {
// 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(),
+ MsgExpr = new (Context) ObjCMessageExpr(dyn_cast<Expr>(Receiver),
+ PDecl->getGetterName(), PDecl->getType(),
+ PDecl->getGetterMethodDecl(),
+ SourceLocation(), SourceLocation(),
0, 0);
Stmt *ReplacingStmt = SynthMessageExpr(MsgExpr);
@@ -1126,7 +1126,7 @@ Stmt *RewriteObjC::RewritePropertyGetter(ObjCPropertyRefExpr *PropRefExpr) {
return PropRefExpr; // return the original...
} else {
ReplaceStmt(PropRefExpr, ReplacingStmt);
- // delete PropRefExpr; elsewhere...
+ // delete PropRefExpr; elsewhere...
// NOTE: We don't want to call MsgExpr->Destroy(), as it holds references
// to things that stay around.
Context->Deallocate(MsgExpr);
@@ -1134,19 +1134,19 @@ Stmt *RewriteObjC::RewritePropertyGetter(ObjCPropertyRefExpr *PropRefExpr) {
}
}
-Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV,
+Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV,
SourceLocation OrigStart) {
ObjCIvarDecl *D = IV->getDecl();
if (CurMethodDef) {
- if (const PointerType *pType = IV->getBase()->getType()->getAsPointerType()) {
+ if (const PointerType *pType = IV->getBase()->getType()->getAs<PointerType>()) {
ObjCInterfaceType *iFaceDecl =
dyn_cast<ObjCInterfaceType>(pType->getPointeeType());
// lookup which class implements the instance variable.
ObjCInterfaceDecl *clsDeclared = 0;
- iFaceDecl->getDecl()->lookupInstanceVariable(D->getIdentifier(),
+ iFaceDecl->getDecl()->lookupInstanceVariable(D->getIdentifier(),
clsDeclared);
assert(clsDeclared && "RewriteObjCIvarRefExpr(): Can't find class");
-
+
// Synthesize an explicit cast to gain access to the ivar.
std::string RecName = clsDeclared->getIdentifier()->getName();
RecName += "_IMPL";
@@ -1155,14 +1155,16 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV,
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());
+ CastExpr *castExpr = new (Context) CStyleCastExpr(castT,
+ CastExpr::CK_Unknown,
+ 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() &&
+ if (IV->isFreeIvar() &&
CurMethodDef->getClassInterface() == iFaceDecl->getDecl()) {
MemberExpr *ME = new (Context) MemberExpr(PE, true, D,
IV->getLocation(),
@@ -1171,27 +1173,27 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV,
// 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);
+ 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()) {
+ if (const PointerType *pType = IV->getBase()->getType()->getAs<PointerType>()) {
ObjCInterfaceType *iFaceDecl = dyn_cast<ObjCInterfaceType>(pType->getPointeeType());
// lookup which class implements the instance variable.
ObjCInterfaceDecl *clsDeclared = 0;
- iFaceDecl->getDecl()->lookupInstanceVariable(D->getIdentifier(),
+ iFaceDecl->getDecl()->lookupInstanceVariable(D->getIdentifier(),
clsDeclared);
assert(clsDeclared && "RewriteObjCIvarRefExpr(): Can't find class");
-
+
// Synthesize an explicit cast to gain access to the ivar.
std::string RecName = clsDeclared->getIdentifier()->getName();
RecName += "_IMPL";
@@ -1200,7 +1202,9 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV,
SourceLocation(), II);
assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl");
QualType castT = Context->getPointerType(Context->getTagDeclType(RD));
- CastExpr *castExpr = new (Context) CStyleCastExpr(castT, IV->getBase(),
+ CastExpr *castExpr = new (Context) CStyleCastExpr(castT,
+ CastExpr::CK_Unknown,
+ IV->getBase(),
castT, SourceLocation(),
SourceLocation());
// Don't forget the parens to enforce the proper binding.
@@ -1210,7 +1214,7 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV,
// 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);
+ IV->setBase(PE);
return IV;
}
}
@@ -1220,10 +1224,10 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV,
/// SynthCountByEnumWithState - To print:
/// ((unsigned int (*)
/// (id, SEL, struct __objcFastEnumerationState *, id *, unsigned int))
-/// (void *)objc_msgSend)((id)l_collection,
+/// (void *)objc_msgSend)((id)l_collection,
/// sel_registerName(
-/// "countByEnumeratingWithState:objects:count:"),
-/// &enumState,
+/// "countByEnumeratingWithState:objects:count:"),
+/// &enumState,
/// (id *)items, (unsigned int)16)
///
void RewriteObjC::SynthCountByEnumWithState(std::string &buf) {
@@ -1245,7 +1249,7 @@ Stmt *RewriteObjC::RewriteBreakStmt(BreakStmt *S) {
return S;
// replace break with goto __break_label
std::string buf;
-
+
SourceLocation startLoc = S->getLocStart();
buf = "goto __break_label_";
buf += utostr(ObjCBcLabelNo.back());
@@ -1262,39 +1266,39 @@ Stmt *RewriteObjC::RewriteContinueStmt(ContinueStmt *S) {
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;
+/// type elem;
/// struct __objcFastEnumerationState enumState = { 0 };
/// id items[16];
/// id l_collection = (id)collection;
-/// unsigned long limit = [l_collection countByEnumeratingWithState:&enumState
+/// 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)
+/// 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
+/// } while (limit = [l_collection countByEnumeratingWithState:&enumState
/// objects:items count:16]);
/// elem = nil;
/// __break_label: ;
@@ -1306,11 +1310,11 @@ Stmt *RewriteObjC::RewriteContinueStmt(ContinueStmt *S) {
Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
SourceLocation OrigEnd) {
assert(!Stmts.empty() && "ObjCForCollectionStmt - Statement stack empty");
- assert(isa<ObjCForCollectionStmt>(Stmts.back()) &&
+ assert(isa<ObjCForCollectionStmt>(Stmts.back()) &&
"ObjCForCollectionStmt Statement stack mismatch");
- assert(!ObjCBcLabelNo.empty() &&
+ assert(!ObjCBcLabelNo.empty() &&
"ObjCForCollectionStmt - Label No stack empty");
-
+
SourceLocation startLoc = S->getLocStart();
const char *startBuf = SM->getCharacterData(startLoc);
const char *elementName;
@@ -1331,10 +1335,10 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
else {
DeclRefExpr *DR = cast<DeclRefExpr>(S->getElement());
elementName = DR->getDecl()->getNameAsCString();
- elementTypeAsString
+ elementTypeAsString
= cast<ValueDecl>(DR->getDecl())->getType().getAsString();
}
-
+
// struct __objcFastEnumerationState enumState = { 0 };
buf += "struct __objcFastEnumerationState enumState = { 0 };\n\t";
// id items[16];
@@ -1353,8 +1357,8 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
*(startCollectionBuf+3) != '[' && *(startCollectionBuf+3) != '('))
startCollectionBuf++;
startCollectionBuf += 3;
-
- // Replace: "for (type element in" with string constructed thus far.
+
+ // 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 ';'
@@ -1362,17 +1366,17 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
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 limit =
// ((unsigned int (*)
// (id, SEL, struct __objcFastEnumerationState *, id *, unsigned int))
- // (void *)objc_msgSend)((id)l_collection,
+ // (void *)objc_msgSend)((id)l_collection,
// sel_registerName(
- // "countByEnumeratingWithState:objects:count:"),
- // (struct __objcFastEnumerationState *)&state,
+ // "countByEnumeratingWithState:objects:count:"),
+ // (struct __objcFastEnumerationState *)&state,
// (id *)items, (unsigned int)16);
buf += "unsigned long limit =\n\t\t";
SynthCountByEnumWithState(buf);
@@ -1382,7 +1386,7 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
/// do {
/// unsigned long counter = 0;
/// do {
- /// if (startMutations != *enumState.mutationsPtr)
+ /// if (startMutations != *enumState.mutationsPtr)
/// objc_enumerationMutation(l_collection);
/// elem = (type)enumState.itemsPtr[counter++];
buf += "if (limit) {\n\t";
@@ -1398,10 +1402,10 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
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
+ /// } while (limit = [l_collection countByEnumeratingWithState:&enumState
/// objects:items count:16]);
/// elem = nil;
/// __break_label: ;
@@ -1409,7 +1413,7 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
/// else
/// elem = nil;
/// }
- ///
+ ///
buf = ";\n\t";
buf += "__continue_label_";
buf += utostr(ObjCBcLabelNo.back());
@@ -1429,7 +1433,7 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
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())) {
@@ -1454,7 +1458,7 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
return 0;
}
-/// RewriteObjCSynchronizedStmt -
+/// RewriteObjCSynchronizedStmt -
/// This routine rewrites @synchronized(expr) stmt;
/// into:
/// objc_sync_enter(expr);
@@ -1464,16 +1468,16 @@ 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;
+
+ 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
+ // 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);
@@ -1490,7 +1494,7 @@ Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
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";
@@ -1499,8 +1503,9 @@ Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
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(),
+ Expr *syncExpr = new (Context) CStyleCastExpr(Context->getObjCIdType(),
+ CastExpr::CK_Unknown,
+ S->getSynchExpr(),
Context->getObjCIdType(),
SourceLocation(),
SourceLocation());
@@ -1513,21 +1518,21 @@ Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
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) {
+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) ||
+ if (isa<ReturnStmt>(S) || isa<ContinueStmt>(S) ||
isa<BreakStmt>(S) || isa<GotoStmt>(S)) {
- Diags.Report(Context->getFullLoc(S->getLocStart()),
+ Diags.Report(Context->getFullLoc(S->getLocStart()),
TryFinallyContainsReturnDiag);
}
return;
@@ -1537,7 +1542,7 @@ 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;
@@ -1550,12 +1555,12 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
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) {
@@ -1566,7 +1571,7 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
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";
@@ -1579,15 +1584,15 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
while (catchList) {
ParmVarDecl *catchDecl = catchList->getCatchParamDecl();
- if (catchList == S->getCatchStmts())
+ 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()) {
@@ -1598,19 +1603,18 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
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());
+ Rewrite.ReplaceText(startLoc, bodyBuf-startBuf+1, buf);
} else if (catchDecl) {
QualType t = catchDecl->getType();
if (t == Context->getObjCIdType()) {
buf += "1) { ";
ReplaceText(startLoc, lParenLoc-startBuf+1, buf.c_str(), buf.size());
sawIdTypedCatch = true;
- } else if (const PointerType *pType = t->getAsPointerType()) {
+ } else if (const PointerType *pType = t->getAs<PointerType>()) {
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(\"";
@@ -1627,9 +1631,9 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
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
+ // Here we replace ") {" with "= _caught;" (which initializes and
// declares the @catch parameter).
ReplaceText(rParenLoc, bodyBuf-rParenBuf+1, buf.c_str(), buf.size());
} else {
@@ -1643,7 +1647,7 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
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";
@@ -1654,7 +1658,7 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
if (!S->getFinallyStmt())
buf += "}\n";
InsertText(bodyLoc, buf.c_str(), buf.size());
-
+
// Set lastCurlyLoc
lastCurlyLoc = lastCatchBody->getLocEnd();
}
@@ -1662,28 +1666,28 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
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) == '}' &&
+ 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 */
@@ -1708,14 +1712,14 @@ 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
+// 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;
@@ -1724,12 +1728,12 @@ Stmt *RewriteObjC::RewriteObjCThrowStmt(ObjCAtThrowStmt *S) {
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);
@@ -1747,7 +1751,7 @@ Stmt *RewriteObjC::RewriteAtEncode(ObjCEncodeExpr *Exp) {
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;
@@ -1760,7 +1764,7 @@ Stmt *RewriteObjC::RewriteAtSelector(ObjCSelectorExpr *Exp) {
// Create a call to sel_registerName("selName").
llvm::SmallVector<Expr*, 8> SelExprs;
QualType argType = Context->getPointerType(Context->CharTy);
- SelExprs.push_back(StringLiteral::Create(*Context,
+ SelExprs.push_back(StringLiteral::Create(*Context,
Exp->getSelector().getAsString().c_str(),
Exp->getSelector().getAsString().size(),
false, argType, SourceLocation()));
@@ -1775,17 +1779,19 @@ 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,
+ ImplicitCastExpr *ICE = new (Context) ImplicitCastExpr(pToFunc,
+ CastExpr::CK_Unknown,
+ DRE,
/*isLvalue=*/false);
-
- const FunctionType *FT = msgSendType->getAsFunctionType();
-
+
+ const FunctionType *FT = msgSendType->getAs<FunctionType>();
+
return new (Context) CallExpr(*Context, ICE, args, nargs, FT->getResultType(),
SourceLocation());
}
@@ -1820,23 +1826,14 @@ static void scanToNextArgument(const char *&argRef) {
}
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;
+ return T->isObjCQualifiedIdType() || T->isObjCQualifiedInterfaceType();
}
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();
@@ -1874,7 +1871,7 @@ void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Decl *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();
+ const FunctionType *funcType = FD->getType()->getAs<FunctionType>();
assert(funcType && "missing function type");
proto = dyn_cast<FunctionProtoType>(funcType);
if (!proto)
@@ -1883,10 +1880,10 @@ void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) {
}
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)
@@ -1909,16 +1906,16 @@ void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) {
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 =
+ SourceLocation LessLoc =
Loc.getFileLocWithOffset(startRef-startFuncBuf);
- SourceLocation GreaterLoc =
+ SourceLocation GreaterLoc =
Loc.getFileLocWithOffset(endRef-startFuncBuf+1);
// Comment out the protocol references.
InsertText(LessLoc, "/*", 2);
@@ -1940,14 +1937,13 @@ void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) {
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)));
+ ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst()));
QualType getFuncType = Context->getFunctionType(Context->getObjCSelType(),
&ArgTys[0], ArgTys.size(),
false /*isVariadic*/, 0);
SelGetUidFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- SelGetUidIdent, getFuncType,
+ SourceLocation(),
+ SelGetUidIdent, getFuncType, 0,
FunctionDecl::Extern, false);
}
@@ -1975,8 +1971,8 @@ void RewriteObjC::SynthSuperContructorFunctionDecl() {
&ArgTys[0], ArgTys.size(),
false, 0);
SuperContructorFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- msgSendIdent, msgSendType,
+ SourceLocation(),
+ msgSendIdent, msgSendType, 0,
FunctionDecl::Extern, false);
}
@@ -1995,7 +1991,7 @@ void RewriteObjC::SynthMsgSendFunctionDecl() {
true /*isVariadic*/, 0);
MsgSendFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
- msgSendIdent, msgSendType,
+ msgSendIdent, msgSendType, 0,
FunctionDecl::Extern, false);
}
@@ -2016,8 +2012,8 @@ void RewriteObjC::SynthMsgSendSuperFunctionDecl() {
&ArgTys[0], ArgTys.size(),
true /*isVariadic*/, 0);
MsgSendSuperFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- msgSendIdent, msgSendType,
+ SourceLocation(),
+ msgSendIdent, msgSendType, 0,
FunctionDecl::Extern, false);
}
@@ -2035,15 +2031,15 @@ void RewriteObjC::SynthMsgSendStretFunctionDecl() {
&ArgTys[0], ArgTys.size(),
true /*isVariadic*/, 0);
MsgSendStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- msgSendIdent, msgSendType,
+ SourceLocation(),
+ msgSendIdent, msgSendType, 0,
FunctionDecl::Extern, false);
}
-// SynthMsgSendSuperStretFunctionDecl -
+// SynthMsgSendSuperStretFunctionDecl -
// id objc_msgSendSuper_stret(struct objc_super *, SEL op, ...);
void RewriteObjC::SynthMsgSendSuperStretFunctionDecl() {
- IdentifierInfo *msgSendIdent =
+ IdentifierInfo *msgSendIdent =
&Context->Idents.get("objc_msgSendSuper_stret");
llvm::SmallVector<QualType, 16> ArgTys;
RecordDecl *RD = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl,
@@ -2059,8 +2055,8 @@ void RewriteObjC::SynthMsgSendSuperStretFunctionDecl() {
&ArgTys[0], ArgTys.size(),
true /*isVariadic*/, 0);
MsgSendSuperStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- msgSendIdent, msgSendType,
+ SourceLocation(),
+ msgSendIdent, msgSendType, 0,
FunctionDecl::Extern, false);
}
@@ -2078,8 +2074,8 @@ void RewriteObjC::SynthMsgSendFpretFunctionDecl() {
&ArgTys[0], ArgTys.size(),
true /*isVariadic*/, 0);
MsgSendFpretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- msgSendIdent, msgSendType,
+ SourceLocation(),
+ msgSendIdent, msgSendType, 0,
FunctionDecl::Extern, false);
}
@@ -2087,14 +2083,13 @@ void RewriteObjC::SynthMsgSendFpretFunctionDecl() {
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)));
+ ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst()));
QualType getClassType = Context->getFunctionType(Context->getObjCIdType(),
&ArgTys[0], ArgTys.size(),
false /*isVariadic*/, 0);
GetClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- getClassIdent, getClassType,
+ SourceLocation(),
+ getClassIdent, getClassType, 0,
FunctionDecl::Extern, false);
}
@@ -2102,14 +2097,13 @@ void RewriteObjC::SynthGetClassFunctionDecl() {
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)));
+ ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst()));
QualType getClassType = Context->getFunctionType(Context->getObjCIdType(),
&ArgTys[0], ArgTys.size(),
false /*isVariadic*/, 0);
GetMetaClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- getClassIdent, getClassType,
+ SourceLocation(),
+ getClassIdent, getClassType, 0,
FunctionDecl::Extern, false);
}
@@ -2142,17 +2136,20 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
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 *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(),
+ &Context->Idents.get(S.c_str()), strType, 0,
VarDecl::Static);
DeclRefExpr *DRE = new (Context) DeclRefExpr(NewVD, strType, SourceLocation());
Expr *Unop = new (Context) UnaryOperator(DRE, UnaryOperator::AddrOf,
- Context->getPointerType(DRE->getType()),
+ Context->getPointerType(DRE->getType()),
SourceLocation());
// cast to NSConstantString *
- CastExpr *cast = new (Context) CStyleCastExpr(Exp->getType(), Unop,
- Exp->getType(), SourceLocation(), SourceLocation());
+ CastExpr *cast = new (Context) CStyleCastExpr(Exp->getType(),
+ CastExpr::CK_Unknown,
+ Unop, Exp->getType(),
+ SourceLocation(),
+ SourceLocation());
ReplaceStmt(Exp, cast);
// delete Exp; leak for now, see RewritePropertySetter() usage for more info.
return cast;
@@ -2161,11 +2158,12 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
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());
+ const ObjCObjectPointerType *OPT =
+ Super->getType()->getAs<ObjCObjectPointerType>();
+ assert(OPT);
+ const ObjCInterfaceType *IT = OPT->getInterfaceType();
return IT->getDecl();
}
return 0;
@@ -2175,23 +2173,24 @@ ObjCInterfaceDecl *RewriteObjC::isSuperReceiver(Expr *recExpr) {
QualType RewriteObjC::getSuperStructType() {
if (!SuperStructDecl) {
SuperStructDecl = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl,
- SourceLocation(),
+ SourceLocation(),
&Context->Idents.get("objc_super"));
QualType FieldTypes[2];
-
+
// struct objc_object *receiver;
- FieldTypes[0] = Context->getObjCIdType();
+ FieldTypes[0] = Context->getObjCIdType();
// struct objc_class *super;
- FieldTypes[1] = Context->getObjCClassType();
+ FieldTypes[1] = Context->getObjCClassType();
// Create fields
for (unsigned i = 0; i < 2; ++i) {
- SuperStructDecl->addDecl(FieldDecl::Create(*Context, SuperStructDecl,
- SourceLocation(), 0,
- FieldTypes[i], /*BitWidth=*/0,
+ SuperStructDecl->addDecl(FieldDecl::Create(*Context, SuperStructDecl,
+ SourceLocation(), 0,
+ FieldTypes[i], 0,
+ /*BitWidth=*/0,
/*Mutable=*/false));
}
-
+
SuperStructDecl->completeDefinition(*Context);
}
return Context->getTagDeclType(SuperStructDecl);
@@ -2200,25 +2199,25 @@ QualType RewriteObjC::getSuperStructType() {
QualType RewriteObjC::getConstantStringStructType() {
if (!ConstantStringDecl) {
ConstantStringDecl = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl,
- SourceLocation(),
+ SourceLocation(),
&Context->Idents.get("__NSConstantStringImpl"));
QualType FieldTypes[4];
-
+
// struct objc_object *receiver;
- FieldTypes[0] = Context->getObjCIdType();
+ FieldTypes[0] = Context->getObjCIdType();
// int flags;
- FieldTypes[1] = Context->IntTy;
+ FieldTypes[1] = Context->IntTy;
// char *str;
- FieldTypes[2] = Context->getPointerType(Context->CharTy);
+ FieldTypes[2] = Context->getPointerType(Context->CharTy);
// long length;
- FieldTypes[3] = Context->LongTy;
+ FieldTypes[3] = Context->LongTy;
// Create fields
for (unsigned i = 0; i < 4; ++i) {
- ConstantStringDecl->addDecl(FieldDecl::Create(*Context,
- ConstantStringDecl,
+ ConstantStringDecl->addDecl(FieldDecl::Create(*Context,
+ ConstantStringDecl,
SourceLocation(), 0,
- FieldTypes[i],
+ FieldTypes[i], 0,
/*BitWidth=*/0,
/*Mutable=*/true));
}
@@ -2245,7 +2244,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
SynthGetClassFunctionDecl();
if (!GetMetaClassFunctionDecl)
SynthGetMetaClassFunctionDecl();
-
+
// default to objc_msgSend().
FunctionDecl *MsgSendFlavor = MsgSendFunctionDecl;
// May need to use objc_msgSend_stret() as well.
@@ -2257,11 +2256,11 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
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
@@ -2271,16 +2270,17 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
if (MsgSendStretFlavor)
MsgSendStretFlavor = MsgSendSuperStretFunctionDecl;
assert(MsgSendFlavor && "MsgSendFlavor is NULL!");
-
- ObjCInterfaceDecl *SuperDecl =
+
+ 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(),
+ new (Context) CStyleCastExpr(Context->getObjCIdType(),
+ CastExpr::CK_Unknown,
+ new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(),
Context->getObjCIdType(),
SourceLocation()),
Context->getObjCIdType(),
@@ -2289,28 +2289,29 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
llvm::SmallVector<Expr*, 8> ClsExprs;
QualType argType = Context->getPointerType(Context->CharTy);
ClsExprs.push_back(StringLiteral::Create(*Context,
- SuperDecl->getIdentifier()->getName(),
+ SuperDecl->getIdentifier()->getName(),
SuperDecl->getIdentifier()->getLength(),
false, argType, SourceLocation()));
CallExpr *Cls = SynthesizeCallToFunctionDecl(GetMetaClassFunctionDecl,
- &ClsExprs[0],
+ &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(),
+ new (Context) CStyleCastExpr(Context->getObjCIdType(),
+ CastExpr::CK_Unknown,
Cls, Context->getObjCIdType(),
- SourceLocation(), SourceLocation()));
+ SourceLocation(), SourceLocation()));
// struct objc_super
QualType superType = getSuperStructType();
Expr *SuperRep;
-
+
if (LangOpts.Microsoft) {
SynthSuperContructorFunctionDecl();
// Simulate a contructor call...
- DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl,
+ DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl,
superType, SourceLocation());
SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0],
- InitExprs.size(),
+ 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
@@ -2319,21 +2320,22 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
// (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER"))
//
SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf,
- Context->getPointerType(SuperRep->getType()),
+ Context->getPointerType(SuperRep->getType()),
SourceLocation());
- SuperRep = new (Context) CStyleCastExpr(Context->getPointerType(superType),
- SuperRep, Context->getPointerType(superType),
- SourceLocation(), SourceLocation());
- } else {
+ SuperRep = new (Context) CStyleCastExpr(Context->getPointerType(superType),
+ CastExpr::CK_Unknown, SuperRep,
+ Context->getPointerType(superType),
+ SourceLocation(), SourceLocation());
+ } else {
// (struct objc_super) { <exprs from above> }
- InitListExpr *ILE = new (Context) InitListExpr(SourceLocation(),
- &InitExprs[0], InitExprs.size(),
+ 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()),
+ Context->getPointerType(SuperRep->getType()),
SourceLocation());
}
MsgExprs.push_back(SuperRep);
@@ -2341,12 +2343,12 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
llvm::SmallVector<Expr*, 8> ClsExprs;
QualType argType = Context->getPointerType(Context->CharTy);
ClsExprs.push_back(StringLiteral::Create(*Context,
- clsName->getName(),
+ clsName->getName(),
clsName->getLength(),
false, argType,
SourceLocation()));
CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
- &ClsExprs[0],
+ &ClsExprs[0],
ClsExprs.size());
MsgExprs.push_back(Cls);
}
@@ -2358,42 +2360,44 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
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(),
+ new (Context) CStyleCastExpr(Context->getObjCIdType(),
+ CastExpr::CK_Unknown,
+ 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(),
+ ClsExprs.push_back(StringLiteral::Create(*Context,
+ SuperDecl->getIdentifier()->getName(),
SuperDecl->getIdentifier()->getLength(),
false, argType, SourceLocation()));
CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
- &ClsExprs[0],
+ &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()));
+ new (Context) CStyleCastExpr(Context->getObjCIdType(),
+ CastExpr::CK_Unknown,
+ 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,
+ DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl,
superType, SourceLocation());
SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0],
- InitExprs.size(),
+ 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
@@ -2402,15 +2406,16 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
// (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER"))
//
SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf,
- Context->getPointerType(SuperRep->getType()),
+ Context->getPointerType(SuperRep->getType()),
SourceLocation());
- SuperRep = new (Context) CStyleCastExpr(Context->getPointerType(superType),
+ SuperRep = new (Context) CStyleCastExpr(Context->getPointerType(superType),
+ CastExpr::CK_Unknown,
SuperRep, Context->getPointerType(superType),
- SourceLocation(), SourceLocation());
+ SourceLocation(), SourceLocation());
} else {
// (struct objc_super) { <exprs from above> }
- InitListExpr *ILE = new (Context) InitListExpr(SourceLocation(),
- &InitExprs[0], InitExprs.size(),
+ InitListExpr *ILE = new (Context) InitListExpr(SourceLocation(),
+ &InitExprs[0], InitExprs.size(),
SourceLocation());
SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superType, ILE, false);
}
@@ -2420,8 +2425,9 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
// Foo<Proto> *.
while (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(recExpr))
recExpr = CE->getSubExpr();
- recExpr = new (Context) CStyleCastExpr(Context->getObjCIdType(), recExpr,
- Context->getObjCIdType(),
+ recExpr = new (Context) CStyleCastExpr(Context->getObjCIdType(),
+ CastExpr::CK_Unknown, recExpr,
+ Context->getObjCIdType(),
SourceLocation(), SourceLocation());
MsgExprs.push_back(recExpr);
}
@@ -2429,14 +2435,14 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
// 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,
+ 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);
@@ -2446,18 +2452,21 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
QualType type = ICE->getType()->isObjCQualifiedIdType()
? Context->getObjCIdType()
: ICE->getType();
- userExpr = new (Context) CStyleCastExpr(type, userExpr, type, SourceLocation(), SourceLocation());
+ userExpr = new (Context) CStyleCastExpr(type, CastExpr::CK_Unknown,
+ 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(),
+ userExpr = new (Context) CStyleCastExpr(Context->getObjCIdType(),
+ CastExpr::CK_Unknown,
+ 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
@@ -2468,7 +2477,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
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()));
@@ -2480,11 +2489,11 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
for (ObjCMethodDecl::param_iterator PI = OMD->param_begin(),
E = OMD->param_end(); PI != E; ++PI) {
QualType t = (*PI)->getType()->isObjCQualifiedIdType()
- ? Context->getObjCIdType()
+ ? Context->getObjCIdType()
: (*PI)->getType();
// Make sure we convert "t (^)(...)" to "t (*)(...)".
if (isTopLevelBlockPointerType(t)) {
- const BlockPointerType *BPT = t->getAsBlockPointerType();
+ const BlockPointerType *BPT = t->getAs<BlockPointerType>();
t = Context->getPointerType(BPT->getPointeeType());
}
ArgTypes.push_back(t);
@@ -2496,33 +2505,36 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
}
// 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,
+ DeclRefExpr *DRE = new (Context) DeclRefExpr(MsgSendFlavor, msgSendType,
SourceLocation());
- // Need to cast objc_msgSend to "void *" (to workaround a GCC bandaid).
+ // 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,
+ cast = new (Context) CStyleCastExpr(Context->getPointerType(Context->VoidTy),
+ CastExpr::CK_Unknown, DRE,
Context->getPointerType(Context->VoidTy),
SourceLocation(), SourceLocation());
-
+
// Now do the "normal" pointer to function cast.
- QualType castType = Context->getFunctionType(returnType,
+ 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());
+ cast = new (Context) CStyleCastExpr(castType, CastExpr::CK_Unknown, 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();
+
+ const FunctionType *FT = msgSendType->getAs<FunctionType>();
CallExpr *CE = new (Context) CallExpr(*Context, PE, &MsgExprs[0],
- MsgExprs.size(),
+ MsgExprs.size(),
FT->getResultType(), SourceLocation());
Stmt *ReplacingStmt = CE;
if (MsgSendStretFlavor) {
@@ -2530,31 +2542,33 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
// 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,
+ 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,
+ cast = new (Context) CStyleCastExpr(Context->getPointerType(Context->VoidTy),
+ CastExpr::CK_Unknown, STDRE,
Context->getPointerType(Context->VoidTy),
SourceLocation(), SourceLocation());
// Now do the "normal" pointer to function cast.
- castType = Context->getFunctionType(returnType,
+ 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());
-
+ cast = new (Context) CStyleCastExpr(castType, CastExpr::CK_Unknown,
+ cast, castType, SourceLocation(), SourceLocation());
+
// Don't forget the parens to enforce the proper binding.
PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), cast);
-
- FT = msgSendType->getAsFunctionType();
+
+ FT = msgSendType->getAs<FunctionType>();
CallExpr *STCE = new (Context) CallExpr(*Context, PE, &MsgExprs[0],
- MsgExprs.size(),
+ MsgExprs.size(),
FT->getResultType(), SourceLocation());
-
+
// Build sizeof(returnType)
- SizeOfAlignOfExpr *sizeofExpr = new (Context) SizeOfAlignOfExpr(true,
+ SizeOfAlignOfExpr *sizeofExpr = new (Context) SizeOfAlignOfExpr(true,
returnType,
Context->getSizeType(),
SourceLocation(), SourceLocation());
@@ -2562,31 +2576,33 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
// 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 =
+ unsigned IntSize =
static_cast<unsigned>(Context->getTypeSize(Context->IntTy));
- IntegerLiteral *limit = new (Context) IntegerLiteral(llvm::APInt(IntSize, 8),
+ IntegerLiteral *limit = new (Context) IntegerLiteral(llvm::APInt(IntSize, 8),
Context->IntTy,
SourceLocation());
- BinaryOperator *lessThanExpr = new (Context) BinaryOperator(sizeofExpr, limit,
- BinaryOperator::LE,
- Context->IntTy,
+ 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);
+ ConditionalOperator *CondExpr =
+ new (Context) ConditionalOperator(lessThanExpr,
+ SourceLocation(), CE,
+ SourceLocation(), STCE, returnType);
ReplacingStmt = new (Context) ParenExpr(SourceLocation(), SourceLocation(), CondExpr);
}
- // delete Exp; leak for now, see RewritePropertySetter() usage for more info.
+ // 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.
+
+ // delete Exp; leak for now, see RewritePropertySetter() usage for more info.
return ReplacingStmt;
}
@@ -2594,7 +2610,7 @@ Stmt *RewriteObjC::RewriteMessageExpr(ObjCMessageExpr *Exp) {
QualType RewriteObjC::getProtocolType() {
if (!ProtocolTypeDecl) {
ProtocolTypeDecl = TypedefDecl::Create(*Context, TUDecl,
- SourceLocation(),
+ SourceLocation(),
&Context->Idents.get("Protocol"),
Context->getObjCIdType());
}
@@ -2608,23 +2624,24 @@ QualType RewriteObjC::getProtocolType() {
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);
+ VarDecl *VD = VarDecl::Create(*Context, TUDecl, SourceLocation(),
+ ID, QualType()/*UNUSED*/, 0, 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(),
+ CastExpr *castExpr = new (Context) CStyleCastExpr(DerefExpr->getType(),
+ CastExpr::CK_Unknown,
+ DerefExpr, DerefExpr->getType(),
SourceLocation(), SourceLocation());
ReplaceStmt(Exp, castExpr);
ProtocolExprDecls.insert(Exp->getProtocol());
- // delete Exp; leak for now, see RewritePropertySetter() usage for more info.
+ // delete Exp; leak for now, see RewritePropertySetter() usage for more info.
return castExpr;
-
+
}
-bool RewriteObjC::BufferContainsPPDirectives(const char *startBuf,
+bool RewriteObjC::BufferContainsPPDirectives(const char *startBuf,
const char *endBuf) {
while (startBuf < endBuf) {
if (*startBuf == '#') {
@@ -2655,7 +2672,7 @@ bool RewriteObjC::BufferContainsPPDirectives(const char *startBuf,
void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl,
std::string &Result) {
assert(CDecl && "Class missing in SynthesizeObjCInternalStruct");
- assert(CDecl->getNameAsCString() &&
+ assert(CDecl->getNameAsCString() &&
"Name missing in SynthesizeObjCInternalStruct");
// Do not synthesize more than once.
if (ObjCSynthesizedStructs.count(CDecl))
@@ -2664,10 +2681,10 @@ void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl,
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) &&
@@ -2676,8 +2693,8 @@ void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl,
ReplaceText(LocStart, endBuf-startBuf, Result.c_str(), Result.size());
return;
}
-
- // FIXME: This has potential of causing problem. If
+
+ // FIXME: This has potential of causing problem. If
// SynthesizeObjCInternalStruct is ever called recursively.
Result += "\nstruct ";
Result += CDecl->getNameAsString();
@@ -2686,7 +2703,7 @@ void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl,
if (NumIvars > 0) {
const char *cursor = strchr(startBuf, '{');
- assert((cursor && endBuf)
+ 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
@@ -2704,7 +2721,7 @@ void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl,
//
// This clause is segregated to avoid breaking the common case.
if (BufferContainsPPDirectives(startBuf, cursor)) {
- SourceLocation L = RCDecl ? CDecl->getSuperClassLoc() :
+ SourceLocation L = RCDecl ? CDecl->getSuperClassLoc() :
CDecl->getClassLoc();
const char *endHeader = SM->getCharacterData(L);
endHeader += Lexer::MeasureTokenLength(L, *SM, LangOpts);
@@ -2726,14 +2743,14 @@ void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl,
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 == '@') {
@@ -2792,7 +2809,7 @@ void RewriteObjC::RewriteObjCMethodsMetaData(MethodIterator MethodBegin,
const char *ClassName,
std::string &Result) {
if (MethodBegin == MethodEnd) return;
-
+
static bool objc_impl_method = false;
if (!objc_impl_method) {
/* struct _objc_method {
@@ -2806,12 +2823,12 @@ void RewriteObjC::RewriteObjCMethodsMetaData(MethodIterator MethodBegin,
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;
@@ -2874,13 +2891,13 @@ RewriteObjCProtocolMetaData(ObjCProtocolDecl *PDecl, const char *prefix,
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() != PDecl->instmeth_end()) {
unsigned NumMethods = std::distance(PDecl->instmeth_begin(),
PDecl->instmeth_end());
@@ -2897,10 +2914,10 @@ RewriteObjCProtocolMetaData(ObjCProtocolDecl *PDecl, const char *prefix,
Result += PDecl->getNameAsString();
Result += " __attribute__ ((used, section (\"__OBJC, __cat_inst_meth\")))= "
"{\n\t" + utostr(NumMethods) + "\n";
-
+
// Output instance methods declared in this protocol.
- for (ObjCProtocolDecl::instmeth_iterator
- I = PDecl->instmeth_begin(), E = PDecl->instmeth_end();
+ for (ObjCProtocolDecl::instmeth_iterator
+ I = PDecl->instmeth_begin(), E = PDecl->instmeth_end();
I != E; ++I) {
if (I == PDecl->instmeth_begin())
Result += "\t ,{{(struct objc_selector *)\"";
@@ -2915,7 +2932,7 @@ RewriteObjCProtocolMetaData(ObjCProtocolDecl *PDecl, const char *prefix,
}
Result += "\t }\n};\n";
}
-
+
// Output class methods declared in this protocol.
unsigned NumMethods = std::distance(PDecl->classmeth_begin(),
PDecl->classmeth_end());
@@ -2935,9 +2952,9 @@ RewriteObjCProtocolMetaData(ObjCProtocolDecl *PDecl, const char *prefix,
"{\n\t";
Result += utostr(NumMethods);
Result += "\n";
-
+
// Output instance methods declared in this protocol.
- for (ObjCProtocolDecl::classmeth_iterator
+ for (ObjCProtocolDecl::classmeth_iterator
I = PDecl->classmeth_begin(), E = PDecl->classmeth_end();
I != E; ++I) {
if (I == PDecl->classmeth_begin())
@@ -2962,7 +2979,7 @@ RewriteObjCProtocolMetaData(ObjCProtocolDecl *PDecl, const char *prefix,
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) {
@@ -2973,10 +2990,10 @@ RewriteObjCProtocolMetaData(ObjCProtocolDecl *PDecl, const char *prefix,
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\")))= "
@@ -2998,7 +3015,7 @@ RewriteObjCProtocolMetaData(ObjCProtocolDecl *PDecl, const char *prefix,
else
Result += "0\n";
Result += "};\n";
-
+
// Mark this protocol as having been generated.
if (!ObjCSynthesizedProtocols.insert(PDecl))
assert(false && "protocol already synthesized");
@@ -3010,7 +3027,7 @@ 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);
@@ -3034,11 +3051,11 @@ RewriteObjCProtocolListMetaData(const ObjCList<ObjCProtocolDecl> &Protocols,
"{\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();
@@ -3048,24 +3065,24 @@ RewriteObjCProtocolListMetaData(const ObjCList<ObjCProtocolDecl> &Protocols,
}
-/// RewriteObjCCategoryImplDecl - Rewrite metadata for each category
+/// 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;
+ 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>
+ llvm::SmallVector<ObjCMethodDecl *, 32>
InstanceMethods(IDecl->instmeth_begin(), IDecl->instmeth_end());
// If any of our property implementations have associated getters or
@@ -3090,12 +3107,12 @@ void RewriteObjC::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *IDecl,
RewriteObjCMethodsMetaData(InstanceMethods.begin(), InstanceMethods.end(),
true, "CATEGORY_", FullCategoryName.c_str(),
Result);
-
+
// Build _objc_method_list for class's class methods if needed
RewriteObjCMethodsMetaData(IDecl->classmeth_begin(), IDecl->classmeth_end(),
false, "CATEGORY_", FullCategoryName.c_str(),
Result);
-
+
// Protocols referenced in class declaration?
// Null CDecl is case of a category implementation with no category interface
if (CDecl)
@@ -3109,11 +3126,11 @@ void RewriteObjC::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *IDecl,
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
+ struct _objc_property_list *instance_properties; // category's own
// @property decl.
- };
+ };
*/
-
+
static bool objc_category = false;
if (!objc_category) {
Result += "\nstruct _objc_category {\n";
@@ -3122,7 +3139,7 @@ void RewriteObjC::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *IDecl,
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 += "\tunsigned int size;\n";
Result += "\tstruct _objc_property_list *instance_properties;\n";
Result += "};\n";
objc_category = true;
@@ -3134,7 +3151,7 @@ void RewriteObjC::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *IDecl,
Result += "\"\n\t, \"";
Result += ClassDecl->getNameAsString();
Result += "\"\n";
-
+
if (IDecl->instmeth_begin() != IDecl->instmeth_end()) {
Result += "\t, (struct _objc_method_list *)"
"&_OBJC_CATEGORY_INSTANCE_METHODS_";
@@ -3151,9 +3168,9 @@ void RewriteObjC::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *IDecl,
}
else
Result += "\t, 0\n";
-
+
if (CDecl && CDecl->protocol_begin() != CDecl->protocol_end()) {
- Result += "\t, (struct _objc_protocol_list *)&_OBJC_CATEGORY_PROTOCOLS_";
+ Result += "\t, (struct _objc_protocol_list *)&_OBJC_CATEGORY_PROTOCOLS_";
Result += FullCategoryName;
Result += "\n";
}
@@ -3164,8 +3181,8 @@ void RewriteObjC::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *IDecl,
/// SynthesizeIvarOffsetComputation - This rutine synthesizes computation of
/// ivar offset.
-void RewriteObjC::SynthesizeIvarOffsetComputation(ObjCImplementationDecl *IDecl,
- ObjCIvarDecl *ivar,
+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
@@ -3189,17 +3206,17 @@ void RewriteObjC::SynthesizeIvarOffsetComputation(ObjCImplementationDecl *IDecl,
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
+ // 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()
- ? IDecl->ivar_size()
+ ? IDecl->ivar_size()
: (CDecl ? CDecl->ivar_size() : 0);
if (NumIvars > 0) {
static bool objc_ivar = false;
@@ -3208,23 +3225,23 @@ void RewriteObjC::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
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 += "\nstatic struct {\n";
Result += "\tint ivar_count;\n";
Result += "\tstruct _objc_ivar ivar_list[";
Result += utostr(NumIvars);
@@ -3234,11 +3251,11 @@ void RewriteObjC::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
"{\n\t";
Result += utostr(NumIvars);
Result += "\n";
-
+
ObjCInterfaceDecl::ivar_iterator IVI, IVE;
llvm::SmallVector<ObjCIvarDecl *, 8> IVars;
if (!IDecl->ivar_empty()) {
- for (ObjCImplementationDecl::ivar_iterator
+ for (ObjCImplementationDecl::ivar_iterator
IV = IDecl->ivar_begin(), IVEnd = IDecl->ivar_end();
IV != IVEnd; ++IV)
IVars.push_back(*IV);
@@ -3270,12 +3287,12 @@ void RewriteObjC::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
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>
+ llvm::SmallVector<ObjCMethodDecl *, 32>
InstanceMethods(IDecl->instmeth_begin(), IDecl->instmeth_end());
// If any of our property implementations have associated getters or
@@ -3299,15 +3316,15 @@ void RewriteObjC::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
}
RewriteObjCMethodsMetaData(InstanceMethods.begin(), InstanceMethods.end(),
true, "", IDecl->getNameAsCString(), Result);
-
+
// Build _objc_method_list for class's class methods if needed
RewriteObjCMethodsMetaData(IDecl->classmeth_begin(), IDecl->classmeth_end(),
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
@@ -3322,7 +3339,7 @@ void RewriteObjC::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
struct objc_protocol_list *protocols;
const char *ivar_layout;
struct _objc_class_ext *ext;
- };
+ };
*/
static bool objc_class = false;
if (!objc_class) {
@@ -3342,7 +3359,7 @@ void RewriteObjC::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
Result += "};\n";
objc_class = true;
}
-
+
// Meta-class metadata generation.
ObjCInterfaceDecl *RootClass = 0;
ObjCInterfaceDecl *SuperClass = CDecl->getSuperClass();
@@ -3351,7 +3368,7 @@ void RewriteObjC::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
SuperClass = SuperClass->getSuperClass();
}
SuperClass = CDecl->getSuperClass();
-
+
Result += "\nstatic struct _objc_class _OBJC_METACLASS_";
Result += CDecl->getNameAsString();
Result += " __attribute__ ((used, section (\"__OBJC, __meta_class\")))= "
@@ -3377,7 +3394,7 @@ void RewriteObjC::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
if (IDecl->classmeth_begin() != IDecl->classmeth_end()) {
Result += "\n\t, (struct _objc_method_list *)&_OBJC_CLASS_METHODS_";
Result += IDecl->getNameAsString();
- Result += "\n";
+ Result += "\n";
}
else
Result += ", 0\n";
@@ -3389,7 +3406,7 @@ void RewriteObjC::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
else
Result += "\t,0,0,0,0\n";
Result += "};\n";
-
+
// class metadata generation.
Result += "\nstatic struct _objc_class _OBJC_CLASS_";
Result += CDecl->getNameAsString();
@@ -3430,7 +3447,7 @@ void RewriteObjC::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
if (IDecl->instmeth_begin() != IDecl->instmeth_end()) {
Result += ", (struct _objc_method_list *)&_OBJC_INSTANCE_METHODS_";
Result += CDecl->getNameAsString();
- Result += ", 0\n\t";
+ Result += ", 0\n\t";
}
else
Result += ",0,0";
@@ -3450,25 +3467,25 @@ void RewriteObjC::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
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";
+ 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);
@@ -3482,9 +3499,9 @@ void RewriteObjC::SynthesizeMetaDataIntoBuffer(std::string &Result) {
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";
@@ -3492,17 +3509,17 @@ void RewriteObjC::SynthesizeMetaDataIntoBuffer(std::string &Result) {
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)
+ 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();
@@ -3510,11 +3527,11 @@ void RewriteObjC::SynthesizeMetaDataIntoBuffer(std::string &Result) {
Result += CategoryImplementation[i]->getNameAsString();
Result += "\n";
}
-
+
Result += "};\n\n";
-
+
// Write objc_module metadata
-
+
/*
struct _objc_module {
long version;
@@ -3523,7 +3540,7 @@ void RewriteObjC::SynthesizeMetaDataIntoBuffer(std::string &Result) {
struct _objc_symtab *symtab;
}
*/
-
+
Result += "\nstruct _objc_module {\n";
Result += "\tlong version;\n";
Result += "\tlong size;\n";
@@ -3532,7 +3549,7 @@ void RewriteObjC::SynthesizeMetaDataIntoBuffer(std::string &Result) {
Result += "};\n\n";
Result += "static struct _objc_module "
"_OBJC_MODULES __attribute__ ((used, section (\"__OBJC, __module_info\")))= {\n";
- Result += "\t" + utostr(OBJC_ABI_VERSION) +
+ Result += "\t" + utostr(OBJC_ABI_VERSION) +
", sizeof(struct _objc_module), \"\", &_OBJC_SYMBOLS\n";
Result += "};\n\n";
@@ -3540,7 +3557,7 @@ void RewriteObjC::SynthesizeMetaDataIntoBuffer(std::string &Result) {
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(),
+ 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();
@@ -3568,9 +3585,9 @@ std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i,
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
+ // 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()) {
@@ -3596,19 +3613,19 @@ std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i,
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(),
+ 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->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(),
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
E = BlockByCopyDecls.end(); I != E; ++I) {
S += " ";
std::string Name = (*I)->getNameAsString();
@@ -3616,7 +3633,7 @@ std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i,
//
// void (^myImportedClosure)(void);
// myImportedClosure = ^(void) { setGlobalInt(x + y); };
- //
+ //
// void (^anotherClosure)(void);
// anotherClosure = ^(void) {
// myImportedClosure(); // import and invoke the closure
@@ -3641,13 +3658,13 @@ std::string RewriteObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
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(),
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = ImportedBlockDecls.begin(),
E = ImportedBlockDecls.end(); I != E; ++I) {
S += "_Block_object_assign((void*)&dst->";
S += (*I)->getNameAsString();
@@ -3660,13 +3677,13 @@ std::string RewriteObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
S += "_block_dispose_" + utostr(i);
S += "(" + StructRef;
S += "*src) {";
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = ImportedBlockDecls.begin(),
+ 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";
+ S += "}\n";
return S;
}
@@ -3674,20 +3691,20 @@ 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(),
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
E = BlockByCopyDecls.end(); I != E; ++I) {
S += " ";
std::string FieldName = (*I)->getNameAsString();
@@ -3696,7 +3713,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
//
// void (^myImportedBlock)(void);
// myImportedBlock = ^(void) { setGlobalInt(x + y); };
- //
+ //
// void (^anotherBlock)(void);
// anotherBlock = ^(void) {
// myImportedBlock(); // import and invoke the closure
@@ -3713,7 +3730,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
S += FieldName + ";\n";
}
// Output all "by ref" declarations.
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
E = BlockByRefDecls.end(); I != E; ++I) {
S += " ";
std::string FieldName = (*I)->getNameAsString();
@@ -3722,7 +3739,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
//
// void (^myImportedBlock)(void);
// myImportedBlock = ^(void) { setGlobalInt(x + y); };
- //
+ //
// void (^anotherBlock)(void);
// anotherBlock = ^(void) {
// myImportedBlock(); // import and invoke the closure
@@ -3732,9 +3749,9 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
S += "struct __block_impl *";
Constructor += ", void *" + ArgName;
} else {
- Context->getPointerType((*I)->getType()).getAsStringInternal(FieldName,
+ Context->getPointerType((*I)->getType()).getAsStringInternal(FieldName,
Context->PrintingPolicy);
- Context->getPointerType((*I)->getType()).getAsStringInternal(ArgName,
+ Context->getPointerType((*I)->getType()).getAsStringInternal(ArgName,
Context->PrintingPolicy);
Constructor += ", " + ArgName;
}
@@ -3748,12 +3765,12 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
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(),
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
E = BlockByCopyDecls.end(); I != E; ++I) {
std::string Name = (*I)->getNameAsString();
Constructor += " ";
@@ -3764,7 +3781,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
Constructor += Name + ";\n";
}
// Initialize all "by ref" arguments.
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
E = BlockByRefDecls.end(); I != E; ++I) {
std::string Name = (*I)->getNameAsString();
Constructor += " ";
@@ -3801,21 +3818,21 @@ void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart,
CollectBlockDeclRefInfo(Blocks[i]);
std::string Tag = "__" + std::string(FunName) + "_block_impl_" + utostr(i);
-
- std::string CI = SynthesizeBlockImpl(Blocks[i], Tag,
+
+ 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();
@@ -3829,7 +3846,7 @@ void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart,
void RewriteObjC::InsertBlockLiteralsWithinFunction(FunctionDecl *FD) {
SourceLocation FunLocStart = FD->getTypeSpecStartLoc();
const char *FuncName = FD->getNameAsCString();
-
+
SynthesizeBlockLiterals(FunLocStart, FuncName);
}
@@ -3843,7 +3860,7 @@ void RewriteObjC::InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD) {
std::string::size_type loc = 0;
while ((loc = FuncName.find(":", loc)) != std::string::npos)
FuncName.replace(loc, 1, "_");
-
+
SynthesizeBlockLiterals(FunLocStart, FuncName.c_str());
}
@@ -3873,7 +3890,7 @@ void RewriteObjC::GetBlockCallExprs(Stmt *S) {
else
GetBlockCallExprs(*CI);
}
-
+
if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
if (CE->getCallee()->getType()->isBlockPointerType()) {
BlockCallExprs[dyn_cast<BlockDeclRefExpr>(CE->getCallee())] = CE;
@@ -3886,25 +3903,25 @@ 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();
+ CPT = DRE->getType()->getAs<BlockPointerType>();
} else if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(Exp->getCallee())) {
closureName = CDRE->getDecl()->getNameAsCString();
- CPT = CDRE->getType()->getAsBlockPointerType();
+ CPT = CDRE->getType()->getAs<BlockPointerType>();
} else if (MemberExpr *MExpr = dyn_cast<MemberExpr>(Exp->getCallee())) {
closureName = MExpr->getMemberDecl()->getNameAsCString();
- CPT = MExpr->getType()->getAsBlockPointerType();
+ CPT = MExpr->getType()->getAs<BlockPointerType>();
} else {
assert(1 && "RewriteBlockClass: Bad type");
}
assert(CPT && "RewriteBlockClass: Bad type");
- const FunctionType *FT = CPT->getPointeeType()->getAsFunctionType();
+ const FunctionType *FT = CPT->getPointeeType()->getAs<FunctionType>();
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"));
@@ -3912,52 +3929,55 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp) {
// 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(),
+ 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();
+ const BlockPointerType *BPT = t->getAs<BlockPointerType>();
t = Context->getPointerType(BPT->getPointeeType());
}
ArgTypes.push_back(t);
}
}
// Now do the pointer to function cast.
- QualType PtrToFuncCastType = Context->getFunctionType(Exp->getType(),
+ 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(),
+
+ CastExpr *BlkCast = new (Context) CStyleCastExpr(PtrBlock,
+ CastExpr::CK_Unknown,
+ 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,
+ &Context->Idents.get("FuncPtr"), Context->VoidPtrTy, 0,
/*BitWidth=*/0, /*Mutable=*/true);
MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(),
FD->getType());
-
- CastExpr *FunkCast = new (Context) CStyleCastExpr(PtrToFuncCastType, ME,
+
+ CastExpr *FunkCast = new (Context) CStyleCastExpr(PtrToFuncCastType,
+ CastExpr::CK_Unknown, 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(),
+ for (CallExpr::arg_iterator I = Exp->arg_begin(),
E = Exp->arg_end(); I != E; ++I) {
BlkExprs.push_back(*I);
}
@@ -3979,7 +3999,7 @@ void RewriteObjC::RewriteBlockCall(CallExpr *Exp) {
// 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;
@@ -4006,16 +4026,16 @@ void RewriteObjC::RewriteCastExpr(CStyleCastExpr *CE) {
// 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 '^':
+ case '^':
// Replace the '^' with '*'.
LocStart = LocStart.getFileLocWithOffset(argPtr-startBuf);
ReplaceText(LocStart, 1, "*", 1);
@@ -4028,31 +4048,31 @@ void RewriteObjC::RewriteCastExpr(CStyleCastExpr *CE) {
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 '^':
+ case '^':
// Replace the '^' with '*'.
DeclLoc = DeclLoc.getFileLocWithOffset(argPtr-startArgList);
ReplaceText(DeclLoc, 1, "*", 1);
break;
- case '(':
- parenCount++;
+ case '(':
+ parenCount++;
break;
- case ')':
+ case ')':
parenCount--;
break;
}
@@ -4062,16 +4082,16 @@ void RewriteObjC::RewriteBlockPointerFunctionArgs(FunctionDecl *FD) {
bool RewriteObjC::PointerTypeTakesAnyBlockArguments(QualType QT) {
const FunctionProtoType *FTP;
- const PointerType *PT = QT->getAsPointerType();
+ const PointerType *PT = QT->getAs<PointerType>();
if (PT) {
- FTP = PT->getPointeeType()->getAsFunctionProtoType();
+ FTP = PT->getPointeeType()->getAs<FunctionProtoType>();
} else {
- const BlockPointerType *BPT = QT->getAsBlockPointerType();
+ const BlockPointerType *BPT = QT->getAs<BlockPointerType>();
assert(BPT && "BlockPointerTypeTakeAnyBlockArguments(): not a block pointer type");
- FTP = BPT->getPointeeType()->getAsFunctionProtoType();
+ FTP = BPT->getPointeeType()->getAs<FunctionProtoType>();
}
if (FTP) {
- for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(),
+ for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(),
E = FTP->arg_type_end(); I != E; ++I)
if (isTopLevelBlockPointerType(*I))
return true;
@@ -4083,11 +4103,11 @@ 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;
@@ -4104,7 +4124,7 @@ 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;
@@ -4114,15 +4134,15 @@ void RewriteObjC::RewriteBlockPointerDecl(NamedDecl *ND) {
DeclT = TDD->getUnderlyingType();
else if (FieldDecl *FD = dyn_cast<FieldDecl>(ND))
DeclT = FD->getType();
- else
+ 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 == '^') {
@@ -4147,7 +4167,7 @@ void RewriteObjC::RewriteBlockPointerDecl(NamedDecl *ND) {
return;
}
-void RewriteObjC::CollectBlockDeclRefInfo(BlockExpr *Exp) {
+void RewriteObjC::CollectBlockDeclRefInfo(BlockExpr *Exp) {
// Add initializers for any closure decl refs.
GetBlockDeclRefExprs(Exp->getBody());
if (BlockDeclRefs.size()) {
@@ -4172,8 +4192,8 @@ void RewriteObjC::CollectBlockDeclRefInfo(BlockExpr *Exp) {
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,
+ return FunctionDecl::Create(*Context, TUDecl,SourceLocation(),
+ ID, FType, 0, FunctionDecl::Extern, false,
false);
}
@@ -4182,7 +4202,7 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) {
CollectBlockDeclRefInfo(Exp);
std::string FuncName;
-
+
if (CurFunctionDef)
FuncName = CurFunctionDef->getNameAsString();
else if (CurMethodDef) {
@@ -4193,55 +4213,58 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) {
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,
+ CastExpr *castExpr = new (Context) CStyleCastExpr(Context->VoidPtrTy,
+ CastExpr::CK_Unknown, Arg,
Context->VoidPtrTy, SourceLocation(),
SourceLocation());
- InitExprs.push_back(castExpr);
-
+ 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,
+ castExpr = new (Context) CStyleCastExpr(Context->VoidPtrTy,
+ CastExpr::CK_Unknown, Arg,
Context->VoidPtrTy, SourceLocation(),
SourceLocation());
- InitExprs.push_back(castExpr);
-
+ 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,
+ castExpr = new (Context) CStyleCastExpr(Context->VoidPtrTy,
+ CastExpr::CK_Unknown, Arg,
Context->VoidPtrTy, SourceLocation(),
SourceLocation());
- InitExprs.push_back(castExpr);
+ 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(),
+ 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]).
@@ -4250,32 +4273,35 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) {
} 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(),
+ Exp = new (Context) CStyleCastExpr(Context->VoidPtrTy,
+ CastExpr::CK_Unknown, Arg,
+ Context->VoidPtrTy,
+ SourceLocation(),
SourceLocation());
} else {
FD = SynthBlockInitFunctionDecl((*I)->getNameAsCString());
Exp = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation());
}
- InitExprs.push_back(Exp);
+ InitExprs.push_back(Exp);
}
// Output all "by ref" declarations.
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ 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()),
+ Context->getPointerType(Exp->getType()),
SourceLocation());
- InitExprs.push_back(Exp);
+ 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()),
+ Context->getPointerType(NewRep->getType()),
SourceLocation());
- NewRep = new (Context) CStyleCastExpr(FType, NewRep, FType, SourceLocation(),
+ NewRep = new (Context) CStyleCastExpr(FType, CastExpr::CK_Unknown, NewRep,
+ FType, SourceLocation(),
SourceLocation());
BlockDeclRefs.clear();
BlockByRefDecls.clear();
@@ -4310,33 +4336,33 @@ void RewriteObjC::CollectPropertySetters(Stmt *S) {
}
Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
- if (isa<SwitchStmt>(S) || isa<WhileStmt>(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)
+ 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);
@@ -4345,7 +4371,7 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
// 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());
@@ -4358,7 +4384,7 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
// 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 :
+ // self.errorHandler = handler ? handler :
// ^(NSURL *errorURL, NSError *error) { return (BOOL)1; };
SourceRange SrcRange = BinOp->getSourceRange();
Stmt *newStmt = RewriteFunctionBodyOrGlobalInitializer(BinOp->getRHS());
@@ -4392,7 +4418,7 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
// 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
+ // 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);
@@ -4402,25 +4428,25 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
}
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
+
+ // 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...
@@ -4428,7 +4454,7 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
#endif
return RewriteMessageExpr(MessExpr);
}
-
+
if (ObjCAtTryStmt *StmtTry = dyn_cast<ObjCAtTryStmt>(S))
return RewriteObjCTryStmt(StmtTry);
@@ -4437,13 +4463,13 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
if (ObjCAtThrowStmt *StmtThrow = dyn_cast<ObjCAtThrowStmt>(S))
return RewriteObjCThrowStmt(StmtThrow);
-
+
if (ObjCProtocolExpr *ProtocolExp = dyn_cast<ObjCProtocolExpr>(S))
return RewriteObjCProtocolExpr(ProtocolExp);
-
- if (ObjCForCollectionStmt *StmtForCollection =
+
+ if (ObjCForCollectionStmt *StmtForCollection =
dyn_cast<ObjCForCollectionStmt>(S))
- return RewriteObjCForCollectionStmt(StmtForCollection,
+ return RewriteObjCForCollectionStmt(StmtForCollection,
OrigStmtRange.getEnd());
if (BreakStmt *StmtBreakStmt =
dyn_cast<BreakStmt>(S))
@@ -4451,15 +4477,15 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
if (ContinueStmt *StmtContinueStmt =
dyn_cast<ContinueStmt>(S))
return RewriteContinueStmt(StmtContinueStmt);
-
- // Need to check for protocol refs (id <P>, Foo <P> *) in variable decls
+
+ // 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.
+ // 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) {
@@ -4467,26 +4493,26 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
if (ValueDecl *ND = dyn_cast<ValueDecl>(SD)) {
if (isTopLevelBlockPointerType(ND->getType()))
RewriteBlockPointerDecl(ND);
- else if (ND->getType()->isFunctionPointerType())
+ 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())
+ 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) ||
+
+ 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()))
+ assert ((isa<SwitchStmt>(Stmts.back()) || isa<WhileStmt>(Stmts.back()) ||
+ isa<DoStmt>(Stmts.back()) || isa<ForStmt>(Stmts.back()))
&& "Statement stack mismatch");
Stmts.pop_back();
}
@@ -4530,7 +4556,7 @@ 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.
@@ -4553,7 +4579,7 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) {
// and any copy/dispose helper functions.
InsertBlockLiteralsWithinFunction(FD);
CurFunctionDef = 0;
- }
+ }
return;
}
if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
@@ -4601,7 +4627,7 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) {
delete PropParentMap;
PropParentMap = 0;
}
- SynthesizeBlockLiterals(VD->getTypeSpecStartLoc(),
+ SynthesizeBlockLiterals(VD->getTypeSpecStartLoc(),
VD->getNameAsCString());
GlobalVarDecl = 0;
@@ -4615,13 +4641,13 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) {
if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
if (isTopLevelBlockPointerType(TD->getUnderlyingType()))
RewriteBlockPointerDecl(TD);
- else if (TD->getUnderlyingType()->isFunctionPointerType())
+ 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(),
+ for (RecordDecl::field_iterator i = RD->field_begin(),
e = RD->field_end(); i != e; ++i) {
FieldDecl *FD = *i;
if (isTopLevelBlockPointerType(FD->getType()))
@@ -4635,29 +4661,29 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) {
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(),
+ for (llvm::SmallPtrSet<ObjCProtocolDecl *,8>::iterator I = ProtocolExprDecls.begin(),
E = ProtocolExprDecls.end(); I != E; ++I)
RewriteObjCProtocolMetaData(*I, "", "", Preamble);
- InsertText(SM->getLocForStartOfFile(MainFileID),
+ 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 =
+ if (const RewriteBuffer *RewriteBuf =
Rewrite.getRewriteBufferFor(MainFileID)) {
//printf("Changed:\n");
*OutFile << std::string(RewriteBuf->begin(), RewriteBuf->end());
diff --git a/lib/Frontend/RewriteTest.cpp b/lib/Frontend/RewriteTest.cpp
index f9eb58f..0414678 100644
--- a/lib/Frontend/RewriteTest.cpp
+++ b/lib/Frontend/RewriteTest.cpp
@@ -30,8 +30,8 @@ void clang::DoRewriteTest(Preprocessor &PP, llvm::raw_ostream* OS) {
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)
diff --git a/lib/Frontend/StmtXML.cpp b/lib/Frontend/StmtXML.cpp
index 6ba0a28..4a3c0bf 100644
--- a/lib/Frontend/StmtXML.cpp
+++ b/lib/Frontend/StmtXML.cpp
@@ -32,25 +32,18 @@ namespace {
//static const char *getOpcodeStr(BinaryOperator::Opcode Op);
- void addSpecialAttribute(const char* pName, StringLiteral* Str)
- {
+ void addSpecialAttribute(const char* pName, StringLiteral* Str) {
Doc.addAttribute(pName, Doc.escapeString(Str->getStrData(), Str->getByteLength()));
}
- void addSpecialAttribute(const char* pName, SizeOfAlignOfExpr* S)
- {
+ void addSpecialAttribute(const char* pName, SizeOfAlignOfExpr* S) {
if (S->isArgumentType())
- {
Doc.addAttribute(pName, S->getArgumentType());
- }
}
- void addSpecialAttribute(const char* pName, CXXTypeidExpr* S)
- {
+ void addSpecialAttribute(const char* pName, CXXTypeidExpr* S) {
if (S->isTypeOperand())
- {
Doc.addAttribute(pName, S->getTypeOperand());
- }
}
@@ -58,29 +51,21 @@ namespace {
StmtXML(DocumentXML& doc)
: Doc(doc) {
}
-
+
void DumpSubTree(Stmt *S) {
- if (S)
- {
+ if (S) {
Visit(S);
- if (DeclStmt* DS = dyn_cast<DeclStmt>(S))
- {
- for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end();
- DI != DE; ++DI)
- {
+ if (DeclStmt* DS = dyn_cast<DeclStmt>(S)) {
+ for (DeclStmt::decl_iterator DI = DS->decl_begin(),
+ DE = DS->decl_end(); DI != DE; ++DI) {
Doc.PrintDecl(*DI);
}
- }
- else
- {
+ } else {
if (CXXConditionDeclExpr* CCDE = dyn_cast<CXXConditionDeclExpr>(S))
- {
Doc.PrintDecl(CCDE->getVarDecl());
- }
- for (Stmt::child_iterator i = S->child_begin(), e = S->child_end(); i != e; ++i)
- {
+ for (Stmt::child_iterator i = S->child_begin(), e = S->child_end();
+ i != e; ++i)
DumpSubTree(*i);
- }
}
Doc.toParent();
} else {
@@ -93,12 +78,12 @@ namespace {
void Visit##CLASS(CLASS* S) \
{ \
typedef CLASS tStmtType; \
- Doc.addSubNode(NAME);
+ Doc.addSubNode(NAME);
-#define ATTRIBUTE_XML( FN, NAME ) Doc.addAttribute(NAME, S->FN);
+#define ATTRIBUTE_XML( FN, NAME ) Doc.addAttribute(NAME, S->FN);
#define TYPE_ATTRIBUTE_XML( FN ) ATTRIBUTE_XML(FN, "type")
-#define ATTRIBUTE_OPT_XML( FN, NAME ) Doc.addAttributeOptional(NAME, S->FN);
-#define ATTRIBUTE_SPECIAL_XML( FN, NAME ) addSpecialAttribute(NAME, S);
+#define ATTRIBUTE_OPT_XML( FN, NAME ) Doc.addAttributeOptional(NAME, S->FN);
+#define ATTRIBUTE_SPECIAL_XML( FN, NAME ) addSpecialAttribute(NAME, S);
#define ATTRIBUTE_FILE_LOCATION_XML Doc.addLocationRange(S->getSourceRange());
@@ -107,14 +92,14 @@ namespace {
const char* pAttributeName = NAME; \
const bool optional = false; \
switch (S->FN) { \
- default: assert(0 && "unknown enum value");
+ default: assert(0 && "unknown enum value");
#define ATTRIBUTE_ENUM_OPT_XML( FN, NAME ) \
{ \
const char* pAttributeName = NAME; \
const bool optional = true; \
switch (S->FN) { \
- default: assert(0 && "unknown enum value");
+ default: assert(0 && "unknown enum value");
#define ENUM_XML( VALUE, NAME ) case VALUE: if ((!optional) || NAME[0]) Doc.addAttribute(pAttributeName, NAME); break;
#define END_ENUM_XML } }
@@ -133,7 +118,7 @@ namespace {
void VisitDeclStmt(DeclStmt *Node);
void VisitLabelStmt(LabelStmt *Node);
void VisitGotoStmt(GotoStmt *Node);
-
+
// Exprs
void VisitExpr(Expr *Node);
void VisitDeclRefExpr(DeclRefExpr *Node);
@@ -156,14 +141,15 @@ namespace {
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 VisitObjCImplicitSetterGetterRefExpr(
+ ObjCImplicitSetterGetterRefExpr *Node);
void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node);
void VisitObjCSuperExpr(ObjCSuperExpr *Node);
#endif
@@ -174,27 +160,22 @@ namespace {
// Stmt printing methods.
//===----------------------------------------------------------------------===//
#if (0)
-void StmtXML::VisitStmt(Stmt *Node)
-{
+void StmtXML::VisitStmt(Stmt *Node) {
// nothing special to do
}
-void StmtXML::VisitDeclStmt(DeclStmt *Node)
-{
+void StmtXML::VisitDeclStmt(DeclStmt *Node) {
for (DeclStmt::decl_iterator DI = Node->decl_begin(), DE = Node->decl_end();
- DI != DE; ++DI)
- {
+ DI != DE; ++DI) {
Doc.PrintDecl(*DI);
}
}
-void StmtXML::VisitLabelStmt(LabelStmt *Node)
-{
+void StmtXML::VisitLabelStmt(LabelStmt *Node) {
Doc.addAttribute("name", Node->getName());
}
-void StmtXML::VisitGotoStmt(GotoStmt *Node)
-{
+void StmtXML::VisitGotoStmt(GotoStmt *Node) {
Doc.addAttribute("name", Node->getLabel()->getName());
}
@@ -335,9 +316,7 @@ void StmtXML::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *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) {
@@ -414,7 +393,7 @@ void StmtXML::VisitObjCMessageExpr(ObjCMessageExpr* Node) {
DumpExpr(Node);
Doc.addAttribute("selector", Node->getSelector().getAsString());
IdentifierInfo* clsName = Node->getClassName();
- if (clsName)
+ if (clsName)
Doc.addAttribute("class", clsName->getName());
}
@@ -438,7 +417,8 @@ void StmtXML::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) {
Doc.addAttribute("property", Node->getProperty()->getNameAsString());
}
-void StmtXML::VisitObjCKVCRefExpr(ObjCKVCRefExpr *Node) {
+void StmtXML::VisitObjCImplicitSetterGetterRefExpr(
+ ObjCImplicitSetterGetterRefExpr *Node) {
DumpExpr(Node);
ObjCMethodDecl *Getter = Node->getGetterMethod();
ObjCMethodDecl *Setter = Node->getSetterMethod();
diff --git a/lib/Frontend/TextDiagnosticBuffer.cpp b/lib/Frontend/TextDiagnosticBuffer.cpp
index a4518ee..34bc3c7 100644
--- a/lib/Frontend/TextDiagnosticBuffer.cpp
+++ b/lib/Frontend/TextDiagnosticBuffer.cpp
@@ -17,7 +17,7 @@ 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;
diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp
index d4c7e0f..63d9a50 100644
--- a/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -66,7 +66,7 @@ void TextDiagnosticPrinter::HighlightRange(const SourceRange &R,
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
@@ -74,15 +74,15 @@ void TextDiagnosticPrinter::HighlightRange(const SourceRange &R,
// 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) {
@@ -94,21 +94,21 @@ void TextDiagnosticPrinter::HighlightRange(const SourceRange &R,
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 &&
@@ -116,7 +116,7 @@ void TextDiagnosticPrinter::HighlightRange(const SourceRange &R,
--EndColNo;
else
EndColNo = SourceLine.size();
-
+
// Fill the range with ~'s.
assert(StartColNo <= EndColNo && "Invalid range!");
for (unsigned i = StartColNo; i < EndColNo; ++i)
@@ -156,7 +156,7 @@ static void SelectInterestingSourceRegion(std::string &SourceLine,
for (; FixItStart != FixItEnd; ++FixItStart)
if (!isspace(FixItInsertionLine[FixItStart]))
break;
-
+
for (; FixItEnd != FixItStart; --FixItEnd)
if (!isspace(FixItInsertionLine[FixItEnd - 1]))
break;
@@ -189,16 +189,16 @@ static void SelectInterestingSourceRegion(std::string &SourceLine,
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;
@@ -220,7 +220,7 @@ static void SelectInterestingSourceRegion(std::string &SourceLine,
// 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;
@@ -244,7 +244,7 @@ static void SelectInterestingSourceRegion(std::string &SourceLine,
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, " ");
@@ -271,7 +271,7 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
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();
@@ -279,10 +279,10 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
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) << ':';
@@ -291,75 +291,75 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
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
+ 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
@@ -368,7 +368,7 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
SourceLine = ' ' + SourceLine;
CaretLine = ' ' + CaretLine;
}
-
+
std::string FixItInsertionLine;
if (NumHints && PrintFixItInfo) {
for (const CodeModificationHint *Hint = Hints, *LastHint = Hints + NumHints;
@@ -376,15 +376,15 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
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
+ 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
+ unsigned HintColNo
= SM.getColumnNumber(HintLocInfo.first, HintLocInfo.second);
- unsigned LastColumnModified
+ unsigned LastColumnModified
= HintColNo - 1 + Hint->CodeToInsert.size();
if (LastColumnModified > FixItInsertionLine.size())
FixItInsertionLine.resize(LastColumnModified, ' ');
@@ -407,7 +407,7 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
// 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';
@@ -421,7 +421,7 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
if (UseColors)
// Print fixit line in color
OS.changeColor(fixitColor, false);
- if (PrintRangeInfo)
+ if (PrintRangeInfo)
OS << ' ';
OS << FixItInsertionLine << '\n';
if (UseColors)
@@ -435,8 +435,8 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
/// \returns The index of the first non-whitespace character that is
/// greater than or equal to Idx or, if no such character exists,
/// returns the end of the string.
-static unsigned skipWhitespace(unsigned Idx,
- const llvm::SmallVectorImpl<char> &Str,
+static unsigned skipWhitespace(unsigned Idx,
+ const llvm::SmallVectorImpl<char> &Str,
unsigned Length) {
while (Idx < Length && isspace(Str[Idx]))
++Idx;
@@ -455,7 +455,7 @@ static inline char findMatchingPunctuation(char c) {
case '`': return '\'';
case '"': return '"';
case '(': return ')';
- case '[': return ']';
+ case '[': return ']';
case '{': return '}';
default: break;
}
@@ -468,9 +468,9 @@ static inline char findMatchingPunctuation(char c) {
///
/// \returns the index pointing one character past the end of the
/// word.
-unsigned findEndOfWord(unsigned Start,
+unsigned findEndOfWord(unsigned Start,
const llvm::SmallVectorImpl<char> &Str,
- unsigned Length, unsigned Column,
+ unsigned Length, unsigned Column,
unsigned Columns) {
unsigned End = Start + 1;
@@ -535,13 +535,13 @@ unsigned findEndOfWord(unsigned Start,
///
/// \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,
+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
@@ -556,7 +556,7 @@ static bool PrintWordWrapped(llvm::raw_ostream &OS,
llvm::SmallString<16> IndentStr;
IndentStr.assign(Indentation, ' ');
bool Wrapped = false;
- for (unsigned WordStart = 0, WordEnd; WordStart < Length;
+ for (unsigned WordStart = 0, WordEnd; WordStart < Length;
WordStart = WordEnd) {
// Find the beginning of the next word.
WordStart = skipWhitespace(WordStart, Str, Length);
@@ -565,7 +565,7 @@ static bool PrintWordWrapped(llvm::raw_ostream &OS,
// 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) {
@@ -587,7 +587,7 @@ static bool PrintWordWrapped(llvm::raw_ostream &OS,
Column = Indentation + WordLength;
Wrapped = true;
}
-
+
if (Length == Str.size())
return Wrapped; // We're done.
@@ -597,7 +597,7 @@ static bool PrintWordWrapped(llvm::raw_ostream &OS,
return true;
}
-void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
+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
@@ -611,7 +611,7 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
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()) {
@@ -619,7 +619,7 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
PrintIncludeStack(LastWarningLoc, SM);
StartOfLocationInfo = OS.tell();
}
-
+
// Compute the column number.
if (ShowLocation) {
if (UseColors)
@@ -628,12 +628,12 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
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;
@@ -642,7 +642,7 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
SourceLocation E = Info.getRange(i).getEnd();
B = SM.getInstantiationLoc(B);
E = SM.getInstantiationLoc(E);
-
+
// If the End location and the start location are the same and are a
// macro location, then the range was something that came from a macro
// expansion or _Pragma. If this is an object-like macro, the best we
@@ -653,22 +653,22 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B);
std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E);
-
+
// If the start or end of the range is in another file, just discard
// it.
if (BInfo.first != CaretFileID || EInfo.first != CaretFileID)
continue;
-
+
// Add in the length of the token, so that we cover multi-char tokens.
unsigned TokSize = 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 << ':';
}
@@ -688,7 +688,7 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
case Diagnostic::Fatal: OS.changeColor(fatalColor, true); break;
}
}
-
+
switch (Level) {
case Diagnostic::Ignored: assert(0 && "Invalid diagnostic type");
case Diagnostic::Note: OS << "note: "; break;
@@ -702,14 +702,14 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
llvm::SmallString<100> OutStr;
Info.FormatDiagnostic(OutStr);
-
+
if (PrintDiagnosticOption)
if (const char *Opt = Diagnostic::getWarningOptionForDiag(Info.getID())) {
OutStr += " [-W";
OutStr += Opt;
OutStr += ']';
}
-
+
if (UseColors) {
// Print warnings, errors and fatal errors in bold, no color
switch (Level) {
@@ -732,7 +732,7 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
OS << '\n';
if (UseColors)
OS.resetColor();
-
+
// 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
@@ -740,7 +740,7 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
// 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() ||
+ ((LastLoc != Info.getLocation()) || Info.getNumRanges() ||
(LastCaretDiagnosticWasNote && Level != Diagnostic::Note) ||
Info.getNumCodeModificationHints())) {
// Cache the LastLoc, it allows us to omit duplicate source/caret spewage.
@@ -753,7 +753,7 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
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);
@@ -768,6 +768,6 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
Info.getNumCodeModificationHints(),
MessageLength);
}
-
+
OS.flush();
}
diff --git a/lib/Frontend/TypeXML.cpp b/lib/Frontend/TypeXML.cpp
index f32fbbd..8bd0544 100644
--- a/lib/Frontend/TypeXML.cpp
+++ b/lib/Frontend/TypeXML.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This file implements the XML document class, which provides the means to
+// 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.
//
//===----------------------------------------------------------------------===//
@@ -21,38 +21,36 @@ namespace clang {
namespace XML {
namespace {
-//---------------------------------------------------------
-class TypeWriter : public TypeVisitor<TypeWriter>
-{
+//---------------------------------------------------------
+class TypeWriter : public TypeVisitor<TypeWriter> {
DocumentXML& Doc;
public:
TypeWriter(DocumentXML& doc) : Doc(doc) {}
#define NODE_XML( CLASS, NAME ) \
- void Visit##CLASS(CLASS* T) \
- { \
- Doc.addSubNode(NAME);
+ void Visit##CLASS(CLASS* T) { \
+ Doc.addSubNode(NAME);
#define ID_ATTRIBUTE_XML // done by the Document class itself
-#define ATTRIBUTE_XML( FN, NAME ) Doc.addAttribute(NAME, T->FN);
+#define ATTRIBUTE_XML( FN, NAME ) Doc.addAttribute(NAME, T->FN);
#define TYPE_ATTRIBUTE_XML( FN ) ATTRIBUTE_XML(FN, "type")
#define CONTEXT_ATTRIBUTE_XML( FN ) ATTRIBUTE_XML(FN, "context")
-#define ATTRIBUTE_OPT_XML( FN, NAME ) Doc.addAttributeOptional(NAME, T->FN);
+#define ATTRIBUTE_OPT_XML( FN, NAME ) Doc.addAttributeOptional(NAME, T->FN);
#define ATTRIBUTE_ENUM_XML( FN, NAME ) \
{ \
const char* pAttributeName = NAME; \
const bool optional = false; \
switch (T->FN) { \
- default: assert(0 && "unknown enum value");
+ default: assert(0 && "unknown enum value");
#define ATTRIBUTE_ENUM_OPT_XML( FN, NAME ) \
{ \
const char* pAttributeName = NAME; \
const bool optional = true; \
switch (T->FN) { \
- default: assert(0 && "unknown enum value");
+ default: assert(0 && "unknown enum value");
#define ENUM_XML( VALUE, NAME ) case VALUE: if ((!optional) || NAME[0]) Doc.addAttribute(pAttributeName, NAME); break;
#define END_ENUM_XML } }
@@ -62,22 +60,19 @@ public:
};
-//---------------------------------------------------------
+//---------------------------------------------------------
} // anon clang
} // NS XML
-//---------------------------------------------------------
-class DocumentXML::TypeAdder : public TypeVisitor<DocumentXML::TypeAdder>
-{
+//---------------------------------------------------------
+class DocumentXML::TypeAdder : public TypeVisitor<DocumentXML::TypeAdder> {
DocumentXML& Doc;
- void addIfType(const Type* pType)
- {
+ void addIfType(const Type* pType) {
Doc.addTypeRecursively(pType);
}
- void addIfType(const QualType& pType)
- {
+ void addIfType(const QualType& pType) {
Doc.addTypeRecursively(pType);
}
@@ -88,40 +83,37 @@ public:
#define NODE_XML( CLASS, NAME ) \
void Visit##CLASS(CLASS* T) \
- {
-
-#define ID_ATTRIBUTE_XML
-#define TYPE_ATTRIBUTE_XML( FN ) Doc.addTypeRecursively(T->FN);
-#define CONTEXT_ATTRIBUTE_XML( FN )
-#define ATTRIBUTE_XML( FN, NAME ) addIfType(T->FN);
-#define ATTRIBUTE_OPT_XML( FN, NAME )
-#define ATTRIBUTE_ENUM_XML( FN, NAME )
-#define ATTRIBUTE_ENUM_OPT_XML( FN, NAME )
-#define ENUM_XML( VALUE, NAME )
-#define END_ENUM_XML
+ {
+
+#define ID_ATTRIBUTE_XML
+#define TYPE_ATTRIBUTE_XML( FN ) Doc.addTypeRecursively(T->FN);
+#define CONTEXT_ATTRIBUTE_XML( FN )
+#define ATTRIBUTE_XML( FN, NAME ) addIfType(T->FN);
+#define ATTRIBUTE_OPT_XML( FN, NAME )
+#define ATTRIBUTE_ENUM_XML( FN, NAME )
+#define ATTRIBUTE_ENUM_OPT_XML( FN, NAME )
+#define ENUM_XML( VALUE, NAME )
+#define END_ENUM_XML
#define END_NODE_XML }
#include "clang/Frontend/TypeXML.def"
};
-//---------------------------------------------------------
-void DocumentXML::addParentTypes(const Type* pType)
-{
+//---------------------------------------------------------
+void DocumentXML::addParentTypes(const Type* pType) {
TypeAdder(*this).Visit(const_cast<Type*>(pType));
}
-//---------------------------------------------------------
-void DocumentXML::writeTypeToXML(const Type* pType)
-{
+//---------------------------------------------------------
+void DocumentXML::writeTypeToXML(const Type* pType) {
XML::TypeWriter(*this).Visit(const_cast<Type*>(pType));
}
-//---------------------------------------------------------
-void DocumentXML::writeTypeToXML(const QualType& pType)
-{
+//---------------------------------------------------------
+void DocumentXML::writeTypeToXML(const QualType& pType) {
XML::TypeWriter(*this).VisitQualType(const_cast<QualType*>(&pType));
}
-//---------------------------------------------------------
+//---------------------------------------------------------
} // NS clang
diff --git a/lib/Frontend/Warnings.cpp b/lib/Frontend/Warnings.cpp
index c8fd5f6..7b01b0f 100644
--- a/lib/Frontend/Warnings.cpp
+++ b/lib/Frontend/Warnings.cpp
@@ -47,7 +47,7 @@ bool clang::ProcessWarningOptions(Diagnostic &Diags,
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) {
@@ -55,7 +55,7 @@ bool clang::ProcessWarningOptions(Diagnostic &Diags,
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;
@@ -74,7 +74,7 @@ bool clang::ProcessWarningOptions(Diagnostic &Diags,
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) {
@@ -88,21 +88,21 @@ bool clang::ProcessWarningOptions(Diagnostic &Diags,
}
Specifier = OptStart+6;
}
-
+
if (Specifier == 0) {
- Diags.setWarningsAsErrors(true);
+ Diags.setWarningsAsErrors(isPositive);
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))
Diags.Report(FullSourceLoc(), diag::warn_unknown_warning_option)
<< ("-W" + Opt);
}
-
+
return false;
}
diff --git a/lib/Headers/CMakeLists.txt b/lib/Headers/CMakeLists.txt
index 57d7ee5..6c874f4 100644
--- a/lib/Headers/CMakeLists.txt
+++ b/lib/Headers/CMakeLists.txt
@@ -14,11 +14,10 @@ set(files
tmmintrin.h
xmmintrin.h)
-#FIXME: Centralize Clang version info
if (MSVC_IDE OR XCODE)
- set(output_dir ${LLVM_BINARY_DIR}/bin/lib/clang/1.0/include)
+ set(output_dir ${LLVM_BINARY_DIR}/bin/lib/clang/${CLANG_VERSION}/include)
else ()
- set(output_dir ${LLVM_BINARY_DIR}/lib/clang/1.0/include)
+ set(output_dir ${LLVM_BINARY_DIR}/lib/clang/${CLANG_VERSION}/include)
endif ()
@@ -36,4 +35,4 @@ add_custom_target(clang-headers ALL
install(FILES ${files}
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
- DESTINATION Headers)
+ DESTINATION lib/clang/${CLANG_VERSION}/include)
diff --git a/lib/Headers/Makefile b/lib/Headers/Makefile
index 77eb96d..cb36e84 100644
--- a/lib/Headers/Makefile
+++ b/lib/Headers/Makefile
@@ -10,8 +10,9 @@
LEVEL = ../../../..
include $(LEVEL)/Makefile.common
-# FIXME: Get version from a common place.
-HeaderDir := $(PROJ_OBJ_ROOT)/$(BuildMode)/lib/clang/1.0/include
+CLANG_VERSION := $(shell cat $(PROJ_SRC_DIR)/../../VER)
+
+HeaderDir := $(PROJ_OBJ_ROOT)/$(BuildMode)/lib/clang/$(CLANG_VERSION)/include
HEADERS := $(notdir $(wildcard $(PROJ_SRC_DIR)/*.h))
@@ -25,7 +26,7 @@ $(OBJHEADERS): $(HeaderDir)/%.h: $(PROJ_SRC_DIR)/%.h $(HeaderDir)/.dir
# Hook into the standard Makefile rules.
all-local:: $(OBJHEADERS)
-PROJ_headers := $(DESTDIR)$(PROJ_prefix)/lib/clang/1.0/include
+PROJ_headers := $(DESTDIR)$(PROJ_prefix)/lib/clang/$(CLANG_VERSION)/include
INSTHEADERS := $(addprefix $(PROJ_headers)/, $(HEADERS))
@@ -37,4 +38,3 @@ $(INSTHEADERS): $(PROJ_headers)/%.h: $(HeaderDir)/%.h | $(PROJ_headers)
$(Echo) Installing compiler include file: $(notdir $<)
install-local:: $(INSTHEADERS)
-
diff --git a/lib/Headers/emmintrin.h b/lib/Headers/emmintrin.h
index 72710be..fec0154 100644
--- a/lib/Headers/emmintrin.h
+++ b/lib/Headers/emmintrin.h
@@ -500,13 +500,13 @@ _mm_set1_pd(double w)
static inline __m128d __attribute__((__always_inline__, __nodebug__))
_mm_set_pd(double w, double x)
{
- return (__m128d){ w, x };
+ return (__m128d){ x, w };
}
static inline __m128d __attribute__((__always_inline__, __nodebug__))
_mm_setr_pd(double w, double x)
{
- return (__m128d){ x, w };
+ return (__m128d){ w, x };
}
static inline __m128d __attribute__((__always_inline__, __nodebug__))
@@ -886,55 +886,55 @@ _mm_srl_epi64(__m128i a, __m128i count)
static inline __m128i __attribute__((__always_inline__, __nodebug__))
_mm_cmpeq_epi8(__m128i a, __m128i b)
{
- return (__m128i)__builtin_ia32_pcmpeqb128((__v16qi)a, (__v16qi)b);
+ return (__m128i)((__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);
+ return (__m128i)((__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);
+ return (__m128i)((__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);
+ return (__m128i)((__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);
+ return (__m128i)((__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);
+ return (__m128i)((__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);
+ return _mm_cmpgt_epi8(b,a);
}
static inline __m128i __attribute__((__always_inline__, __nodebug__))
_mm_cmplt_epi16(__m128i a, __m128i b)
{
- return (__m128i)__builtin_ia32_pcmpgtw128((__v8hi)b, (__v8hi)a);
+ return _mm_cmpgt_epi16(b,a);
}
static inline __m128i __attribute__((__always_inline__, __nodebug__))
_mm_cmplt_epi32(__m128i a, __m128i b)
{
- return (__m128i)__builtin_ia32_pcmpgtd128((__v4si)b, (__v4si)a);
+ return _mm_cmpgt_epi32(b,a);
}
#ifdef __x86_64__
@@ -1024,6 +1024,12 @@ _mm_loadl_epi64(__m128i const *p)
}
static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_set_epi64x(long long q1, long long q0)
+{
+ return (__m128i){ q0, q1 };
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
_mm_set_epi64(__m64 q1, __m64 q0)
{
return (__m128i){ (long long)q0, (long long)q1 };
@@ -1048,6 +1054,12 @@ _mm_set_epi8(char b15, char b14, char b13, char b12, char b11, char b10, char b9
}
static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_set1_epi64x(long long q)
+{
+ return (__m128i){ q, q };
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
_mm_set1_epi64(__m64 q)
{
return (__m128i){ (long long)q, (long long)q };
diff --git a/lib/Headers/mmintrin.h b/lib/Headers/mmintrin.h
index 8ea3c47..0f06f78 100644
--- a/lib/Headers/mmintrin.h
+++ b/lib/Headers/mmintrin.h
@@ -348,37 +348,37 @@ _mm_xor_si64(__m64 __m1, __m64 __m2)
static inline __m64 __attribute__((__always_inline__, __nodebug__))
_mm_cmpeq_pi8(__m64 __m1, __m64 __m2)
{
- return (__m64)__builtin_ia32_pcmpeqb((__v8qi)__m1, (__v8qi)__m2);
+ return (__m64)((__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);
+ return (__m64)((__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);
+ return (__m64)((__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);
+ return (__m64)((__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);
+ return (__m64)((__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);
+ return (__m64)((__v2si)__m1 > (__v2si)__m2);
}
static inline __m64 __attribute__((__always_inline__, __nodebug__))
diff --git a/lib/Headers/stdarg.h b/lib/Headers/stdarg.h
index c436ced..bbbaff9 100644
--- a/lib/Headers/stdarg.h
+++ b/lib/Headers/stdarg.h
@@ -34,7 +34,7 @@ typedef __builtin_va_list va_list;
/* 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)
+#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)
diff --git a/lib/Index/ASTLocation.cpp b/lib/Index/ASTLocation.cpp
new file mode 100644
index 0000000..6294d69
--- /dev/null
+++ b/lib/Index/ASTLocation.cpp
@@ -0,0 +1,117 @@
+//===--- ASTLocation.cpp - A <Decl, Stmt> pair ------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// ASTLocation is Decl or a Stmt and its immediate Decl parent.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Index/ASTLocation.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Stmt.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprObjC.h"
+using namespace clang;
+using namespace idx;
+
+static Decl *getDeclFromExpr(Stmt *E) {
+ if (DeclRefExpr *RefExpr = dyn_cast<DeclRefExpr>(E))
+ return RefExpr->getDecl();
+ if (MemberExpr *ME = dyn_cast<MemberExpr>(E))
+ return ME->getMemberDecl();
+ if (ObjCIvarRefExpr *RE = dyn_cast<ObjCIvarRefExpr>(E))
+ return RE->getDecl();
+
+ if (CallExpr *CE = dyn_cast<CallExpr>(E))
+ return getDeclFromExpr(CE->getCallee());
+ if (CastExpr *CE = dyn_cast<CastExpr>(E))
+ return getDeclFromExpr(CE->getSubExpr());
+
+ return 0;
+}
+
+Decl *ASTLocation::getReferencedDecl() {
+ if (isInvalid())
+ return 0;
+
+ switch (getKind()) {
+ default: assert(0 && "Invalid Kind");
+ case N_Type:
+ return 0;
+ case N_Decl:
+ return D;
+ case N_NamedRef:
+ return NDRef.ND;
+ case N_Stmt:
+ return getDeclFromExpr(Stm);
+ }
+
+ return 0;
+}
+
+SourceRange ASTLocation::getSourceRange() const {
+ if (isInvalid())
+ return SourceRange();
+
+ switch (getKind()) {
+ default: assert(0 && "Invalid Kind");
+ return SourceRange();
+ case N_Decl:
+ return D->getSourceRange();
+ case N_Stmt:
+ return Stm->getSourceRange();
+ case N_NamedRef:
+ return SourceRange(AsNamedRef().Loc, AsNamedRef().Loc);
+ case N_Type:
+ return AsTypeLoc().getSourceRange();
+ }
+
+ return SourceRange();
+}
+
+void ASTLocation::print(llvm::raw_ostream &OS) const {
+ if (isInvalid()) {
+ OS << "<< Invalid ASTLocation >>\n";
+ return;
+ }
+
+ ASTContext &Ctx = getParentDecl()->getASTContext();
+
+ switch (getKind()) {
+ case N_Decl:
+ OS << "[Decl: " << AsDecl()->getDeclKindName() << " ";
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(AsDecl()))
+ OS << ND->getNameAsString();
+ break;
+
+ case N_Stmt:
+ OS << "[Stmt: " << AsStmt()->getStmtClassName() << " ";
+ AsStmt()->printPretty(OS, Ctx, 0, PrintingPolicy(Ctx.getLangOptions()));
+ break;
+
+ case N_NamedRef:
+ OS << "[NamedRef: " << AsNamedRef().ND->getDeclKindName() << " ";
+ OS << AsNamedRef().ND->getNameAsString();
+ break;
+
+ case N_Type: {
+ QualType T = AsTypeLoc().getSourceType();
+ OS << "[Type: " << T->getTypeClassName() << " " << T.getAsString();
+ }
+ }
+
+ OS << "] <";
+
+ SourceRange Range = getSourceRange();
+ SourceManager &SourceMgr = Ctx.getSourceManager();
+ Range.getBegin().print(OS, SourceMgr);
+ OS << ", ";
+ Range.getEnd().print(OS, SourceMgr);
+ OS << ">\n";
+}
diff --git a/lib/Index/ASTVisitor.h b/lib/Index/ASTVisitor.h
new file mode 100644
index 0000000..e18aa57
--- /dev/null
+++ b/lib/Index/ASTVisitor.h
@@ -0,0 +1,144 @@
+//===--- ASTVisitor.h - Visitor for an ASTContext ---------------*- 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 ASTVisitor interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_INDEX_ASTVISITOR_H
+#define LLVM_CLANG_INDEX_ASTVISITOR_H
+
+#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/TypeLocVisitor.h"
+
+namespace clang {
+
+namespace idx {
+
+/// \brief Traverses the full AST, both Decls and Stmts.
+template<typename ImplClass>
+class ASTVisitor : public DeclVisitor<ImplClass>,
+ public StmtVisitor<ImplClass>,
+ public TypeLocVisitor<ImplClass> {
+public:
+ ASTVisitor() : CurrentDecl(0) { }
+
+ Decl *CurrentDecl;
+
+ typedef ASTVisitor<ImplClass> Base;
+ typedef DeclVisitor<ImplClass> BaseDeclVisitor;
+ typedef StmtVisitor<ImplClass> BaseStmtVisitor;
+ typedef TypeLocVisitor<ImplClass> BaseTypeLocVisitor;
+
+ using BaseStmtVisitor::Visit;
+
+ //===--------------------------------------------------------------------===//
+ // DeclVisitor
+ //===--------------------------------------------------------------------===//
+
+ void Visit(Decl *D) {
+ Decl *PrevDecl = CurrentDecl;
+ CurrentDecl = D;
+ BaseDeclVisitor::Visit(D);
+ CurrentDecl = PrevDecl;
+ }
+
+ void VisitDeclaratorDecl(DeclaratorDecl *D) {
+ BaseDeclVisitor::VisitDeclaratorDecl(D);
+ if (DeclaratorInfo *DInfo = D->getDeclaratorInfo())
+ Visit(DInfo->getTypeLoc());
+ }
+
+ void VisitFunctionDecl(FunctionDecl *D) {
+ BaseDeclVisitor::VisitFunctionDecl(D);
+ if (D->isThisDeclarationADefinition())
+ Visit(D->getBody());
+ }
+
+ void VisitObjCMethodDecl(ObjCMethodDecl *D) {
+ BaseDeclVisitor::VisitObjCMethodDecl(D);
+ if (D->getBody())
+ Visit(D->getBody());
+ }
+
+ void VisitBlockDecl(BlockDecl *D) {
+ BaseDeclVisitor::VisitBlockDecl(D);
+ Visit(D->getBody());
+ }
+
+ void VisitVarDecl(VarDecl *D) {
+ BaseDeclVisitor::VisitVarDecl(D);
+ if (Expr *Init = D->getInit())
+ Visit(Init);
+ }
+
+ void VisitDecl(Decl *D) {
+ if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D) || isa<BlockDecl>(D))
+ return;
+
+ if (DeclContext *DC = dyn_cast<DeclContext>(D))
+ static_cast<ImplClass*>(this)->VisitDeclContext(DC);
+ }
+
+ void VisitDeclContext(DeclContext *DC) {
+ for (DeclContext::decl_iterator
+ I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I)
+ Visit(*I);
+ }
+
+ //===--------------------------------------------------------------------===//
+ // StmtVisitor
+ //===--------------------------------------------------------------------===//
+
+ void VisitDeclStmt(DeclStmt *Node) {
+ for (DeclStmt::decl_iterator
+ I = Node->decl_begin(), E = Node->decl_end(); I != E; ++I)
+ Visit(*I);
+ }
+
+ void VisitBlockExpr(BlockExpr *Node) {
+ Visit(Node->getBlockDecl());
+ }
+
+ void VisitStmt(Stmt *Node) {
+ for (Stmt::child_iterator
+ I = Node->child_begin(), E = Node->child_end(); I != E; ++I)
+ if (*I)
+ Visit(*I);
+ }
+
+ //===--------------------------------------------------------------------===//
+ // TypeLocVisitor
+ //===--------------------------------------------------------------------===//
+
+ void Visit(TypeLoc TL) {
+ for (; TL; TL = TL.getNextTypeLoc())
+ BaseTypeLocVisitor::Visit(TL);
+ }
+
+ void VisitArrayLoc(ArrayLoc TL) {
+ BaseTypeLocVisitor::VisitArrayLoc(TL);
+ if (TL.getSizeExpr())
+ Visit(TL.getSizeExpr());
+ }
+
+ void VisitFunctionLoc(FunctionLoc TL) {
+ BaseTypeLocVisitor::VisitFunctionLoc(TL);
+ for (unsigned i = 0; i != TL.getNumArgs(); ++i)
+ Visit(TL.getArg(i));
+ }
+
+};
+
+} // namespace idx
+
+} // namespace clang
+
+#endif
diff --git a/lib/Index/Analyzer.cpp b/lib/Index/Analyzer.cpp
new file mode 100644
index 0000000..300a469
--- /dev/null
+++ b/lib/Index/Analyzer.cpp
@@ -0,0 +1,438 @@
+//===--- Analyzer.cpp - Analysis for indexing information -------*- 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 Analyzer interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Index/Analyzer.h"
+#include "clang/Index/Entity.h"
+#include "clang/Index/TranslationUnit.h"
+#include "clang/Index/Handlers.h"
+#include "clang/Index/ASTLocation.h"
+#include "clang/Index/GlobalSelector.h"
+#include "clang/Index/DeclReferenceMap.h"
+#include "clang/Index/SelectorMap.h"
+#include "clang/Index/IndexProvider.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/ExprObjC.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/Support/Compiler.h"
+using namespace clang;
+using namespace idx;
+
+namespace {
+
+//===----------------------------------------------------------------------===//
+// DeclEntityAnalyzer Implementation
+//===----------------------------------------------------------------------===//
+
+class VISIBILITY_HIDDEN DeclEntityAnalyzer : public TranslationUnitHandler {
+ Entity Ent;
+ TULocationHandler &TULocHandler;
+
+public:
+ DeclEntityAnalyzer(Entity ent, TULocationHandler &handler)
+ : Ent(ent), TULocHandler(handler) { }
+
+ virtual void Handle(TranslationUnit *TU) {
+ assert(TU && "Passed null translation unit");
+
+ Decl *D = Ent.getDecl(TU->getASTContext());
+ assert(D && "Couldn't resolve Entity");
+
+ for (Decl::redecl_iterator I = D->redecls_begin(),
+ E = D->redecls_end(); I != E; ++I)
+ TULocHandler.Handle(TULocation(TU, ASTLocation(*I)));
+ }
+};
+
+//===----------------------------------------------------------------------===//
+// RefEntityAnalyzer Implementation
+//===----------------------------------------------------------------------===//
+
+class VISIBILITY_HIDDEN RefEntityAnalyzer : public TranslationUnitHandler {
+ Entity Ent;
+ TULocationHandler &TULocHandler;
+
+public:
+ RefEntityAnalyzer(Entity ent, TULocationHandler &handler)
+ : Ent(ent), TULocHandler(handler) { }
+
+ virtual void Handle(TranslationUnit *TU) {
+ assert(TU && "Passed null translation unit");
+
+ Decl *D = Ent.getDecl(TU->getASTContext());
+ assert(D && "Couldn't resolve Entity");
+ NamedDecl *ND = dyn_cast<NamedDecl>(D);
+ if (!ND)
+ return;
+
+ DeclReferenceMap &RefMap = TU->getDeclReferenceMap();
+ for (DeclReferenceMap::astlocation_iterator
+ I = RefMap.refs_begin(ND), E = RefMap.refs_end(ND); I != E; ++I)
+ TULocHandler.Handle(TULocation(TU, *I));
+ }
+};
+
+//===----------------------------------------------------------------------===//
+// RefSelectorAnalyzer Implementation
+//===----------------------------------------------------------------------===//
+
+/// \brief Accepts an ObjC method and finds all message expressions that this
+/// method may respond to.
+class VISIBILITY_HIDDEN RefSelectorAnalyzer : public TranslationUnitHandler {
+ Program &Prog;
+ TULocationHandler &TULocHandler;
+
+ // The original ObjCInterface associated with the method.
+ Entity IFaceEnt;
+ GlobalSelector GlobSel;
+ bool IsInstanceMethod;
+
+ /// \brief Super classes of the ObjCInterface.
+ typedef llvm::SmallSet<Entity, 16> EntitiesSetTy;
+ EntitiesSetTy HierarchyEntities;
+
+public:
+ RefSelectorAnalyzer(ObjCMethodDecl *MD,
+ Program &prog, TULocationHandler &handler)
+ : Prog(prog), TULocHandler(handler) {
+ assert(MD);
+
+ // FIXME: Protocol methods.
+ assert(!isa<ObjCProtocolDecl>(MD->getDeclContext()) &&
+ "Protocol methods not supported yet");
+
+ ObjCInterfaceDecl *IFD = MD->getClassInterface();
+ assert(IFD);
+ IFaceEnt = Entity::get(IFD, Prog);
+ GlobSel = GlobalSelector::get(MD->getSelector(), Prog);
+ IsInstanceMethod = MD->isInstanceMethod();
+
+ for (ObjCInterfaceDecl *Cls = IFD->getSuperClass();
+ Cls; Cls = Cls->getSuperClass())
+ HierarchyEntities.insert(Entity::get(Cls, Prog));
+ }
+
+ virtual void Handle(TranslationUnit *TU) {
+ assert(TU && "Passed null translation unit");
+
+ ASTContext &Ctx = TU->getASTContext();
+ // Null means it doesn't exist in this translation unit.
+ ObjCInterfaceDecl *IFace =
+ cast_or_null<ObjCInterfaceDecl>(IFaceEnt.getDecl(Ctx));
+ Selector Sel = GlobSel.getSelector(Ctx);
+
+ SelectorMap &SelMap = TU->getSelectorMap();
+ for (SelectorMap::astlocation_iterator
+ I = SelMap.refs_begin(Sel), E = SelMap.refs_end(Sel); I != E; ++I) {
+ if (ValidReference(*I, IFace))
+ TULocHandler.Handle(TULocation(TU, *I));
+ }
+ }
+
+ /// \brief Determines whether the given message expression is likely to end
+ /// up at the given interface decl.
+ ///
+ /// It returns true "eagerly", meaning it will return false only if it can
+ /// "prove" statically that the interface cannot accept this message.
+ bool ValidReference(ASTLocation ASTLoc, ObjCInterfaceDecl *IFace) {
+ assert(ASTLoc.isStmt());
+
+ // FIXME: Finding @selector references should be through another Analyzer
+ // method, like FindSelectors.
+ if (isa<ObjCSelectorExpr>(ASTLoc.AsStmt()))
+ return false;
+
+ ObjCInterfaceDecl *MsgD = 0;
+ ObjCMessageExpr *Msg = cast<ObjCMessageExpr>(ASTLoc.AsStmt());
+
+ if (Msg->getReceiver()) {
+ const ObjCObjectPointerType *OPT =
+ Msg->getReceiver()->getType()->getAsObjCInterfacePointerType();
+
+ // Can be anything! Accept it as a possibility..
+ if (!OPT || OPT->isObjCIdType() || OPT->isObjCQualifiedIdType())
+ return true;
+
+ // Expecting class method.
+ if (OPT->isObjCClassType() || OPT->isObjCQualifiedClassType())
+ return !IsInstanceMethod;
+
+ MsgD = OPT->getInterfaceDecl();
+ assert(MsgD);
+
+ // Should be an instance method.
+ if (!IsInstanceMethod)
+ return false;
+
+ } else {
+ // Expecting class method.
+ if (IsInstanceMethod)
+ return false;
+
+ MsgD = Msg->getClassInfo().first;
+ // FIXME: Case when we only have an identifier.
+ assert(MsgD && "Identifier only");
+ }
+
+ assert(MsgD);
+
+ // Same interface ? We have a winner!
+ if (MsgD == IFace)
+ return true;
+
+ // If the message interface is a superclass of the original interface,
+ // accept this message as a possibility.
+ if (HierarchyEntities.count(Entity::get(MsgD, Prog)))
+ return true;
+
+ // If the message interface is a subclass of the original interface, accept
+ // the message unless there is a subclass in the hierarchy that will
+ // "steal" the message (thus the message "will go" to the subclass and not
+ /// the original interface).
+ if (IFace) {
+ Selector Sel = Msg->getSelector();
+ for (ObjCInterfaceDecl *Cls = MsgD; Cls; Cls = Cls->getSuperClass()) {
+ if (Cls == IFace)
+ return true;
+ if (Cls->getMethod(Sel, IsInstanceMethod))
+ return false;
+ }
+ }
+
+ // The interfaces are unrelated, don't accept the message.
+ return false;
+ }
+};
+
+//===----------------------------------------------------------------------===//
+// MessageAnalyzer Implementation
+//===----------------------------------------------------------------------===//
+
+/// \brief Accepts an ObjC message expression and finds all methods that may
+/// respond to it.
+class VISIBILITY_HIDDEN MessageAnalyzer : public TranslationUnitHandler {
+ Program &Prog;
+ TULocationHandler &TULocHandler;
+
+ // The ObjCInterface associated with the message. Can be null/invalid.
+ Entity MsgIFaceEnt;
+ GlobalSelector GlobSel;
+ bool CanBeInstanceMethod;
+ bool CanBeClassMethod;
+
+ /// \brief Super classes of the ObjCInterface.
+ typedef llvm::SmallSet<Entity, 16> EntitiesSetTy;
+ EntitiesSetTy HierarchyEntities;
+
+ /// \brief The interface in the message interface hierarchy that "intercepts"
+ /// the selector.
+ Entity ReceiverIFaceEnt;
+
+public:
+ MessageAnalyzer(ObjCMessageExpr *Msg,
+ Program &prog, TULocationHandler &handler)
+ : Prog(prog), TULocHandler(handler),
+ CanBeInstanceMethod(false),
+ CanBeClassMethod(false) {
+
+ assert(Msg);
+
+ ObjCInterfaceDecl *MsgD = 0;
+
+ while (true) {
+ if (Msg->getReceiver() == 0) {
+ CanBeClassMethod = true;
+ MsgD = Msg->getClassInfo().first;
+ // FIXME: Case when we only have an identifier.
+ assert(MsgD && "Identifier only");
+ break;
+ }
+
+ const ObjCObjectPointerType *OPT =
+ Msg->getReceiver()->getType()->getAsObjCInterfacePointerType();
+
+ if (!OPT || OPT->isObjCIdType() || OPT->isObjCQualifiedIdType()) {
+ CanBeInstanceMethod = CanBeClassMethod = true;
+ break;
+ }
+
+ if (OPT->isObjCClassType() || OPT->isObjCQualifiedClassType()) {
+ CanBeClassMethod = true;
+ break;
+ }
+
+ MsgD = OPT->getInterfaceDecl();
+ assert(MsgD);
+ CanBeInstanceMethod = true;
+ break;
+ }
+
+ assert(CanBeInstanceMethod || CanBeClassMethod);
+
+ Selector sel = Msg->getSelector();
+ assert(!sel.isNull());
+
+ MsgIFaceEnt = Entity::get(MsgD, Prog);
+ GlobSel = GlobalSelector::get(sel, Prog);
+
+ if (MsgD) {
+ for (ObjCInterfaceDecl *Cls = MsgD->getSuperClass();
+ Cls; Cls = Cls->getSuperClass())
+ HierarchyEntities.insert(Entity::get(Cls, Prog));
+
+ // Find the interface in the hierarchy that "receives" the message.
+ for (ObjCInterfaceDecl *Cls = MsgD; Cls; Cls = Cls->getSuperClass()) {
+ bool isReceiver = false;
+
+ ObjCInterfaceDecl::lookup_const_iterator Meth, MethEnd;
+ for (llvm::tie(Meth, MethEnd) = Cls->lookup(sel);
+ Meth != MethEnd; ++Meth) {
+ if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth))
+ if ((MD->isInstanceMethod() && CanBeInstanceMethod) ||
+ (MD->isClassMethod() && CanBeClassMethod)) {
+ isReceiver = true;
+ break;
+ }
+ }
+
+ if (isReceiver) {
+ ReceiverIFaceEnt = Entity::get(Cls, Prog);
+ break;
+ }
+ }
+ }
+ }
+
+ virtual void Handle(TranslationUnit *TU) {
+ assert(TU && "Passed null translation unit");
+ ASTContext &Ctx = TU->getASTContext();
+
+ // Null means it doesn't exist in this translation unit or there was no
+ // interface that was determined to receive the original message.
+ ObjCInterfaceDecl *ReceiverIFace =
+ cast_or_null<ObjCInterfaceDecl>(ReceiverIFaceEnt.getDecl(Ctx));
+
+ // No subclass for the original receiver interface, so it remains the
+ // receiver.
+ if (ReceiverIFaceEnt.isValid() && ReceiverIFace == 0)
+ return;
+
+ // Null means it doesn't exist in this translation unit or there was no
+ // interface associated with the message in the first place.
+ ObjCInterfaceDecl *MsgIFace =
+ cast_or_null<ObjCInterfaceDecl>(MsgIFaceEnt.getDecl(Ctx));
+
+ Selector Sel = GlobSel.getSelector(Ctx);
+ SelectorMap &SelMap = TU->getSelectorMap();
+ for (SelectorMap::method_iterator
+ I = SelMap.methods_begin(Sel), E = SelMap.methods_end(Sel);
+ I != E; ++I) {
+ ObjCMethodDecl *D = *I;
+ if (ValidMethod(D, MsgIFace, ReceiverIFace)) {
+ for (ObjCMethodDecl::redecl_iterator
+ RI = D->redecls_begin(), RE = D->redecls_end(); RI != RE; ++RI)
+ TULocHandler.Handle(TULocation(TU, ASTLocation(*RI)));
+ }
+ }
+ }
+
+ /// \brief Determines whether the given method is likely to accept the
+ /// original message.
+ ///
+ /// It returns true "eagerly", meaning it will return false only if it can
+ /// "prove" statically that the method cannot accept the original message.
+ bool ValidMethod(ObjCMethodDecl *D, ObjCInterfaceDecl *MsgIFace,
+ ObjCInterfaceDecl *ReceiverIFace) {
+ assert(D);
+
+ // FIXME: Protocol methods ?
+ if (isa<ObjCProtocolDecl>(D->getDeclContext()))
+ return false;
+
+ // No specific interface associated with the message. Can be anything.
+ if (MsgIFaceEnt.isInvalid())
+ return true;
+
+ if ((!CanBeInstanceMethod && D->isInstanceMethod()) ||
+ (!CanBeClassMethod && D->isClassMethod()))
+ return false;
+
+ ObjCInterfaceDecl *IFace = D->getClassInterface();
+ assert(IFace);
+
+ // If the original message interface is the same or a superclass of the
+ // given interface, accept the method as a possibility.
+ if (MsgIFace && MsgIFace->isSuperClassOf(IFace))
+ return true;
+
+ if (ReceiverIFace) {
+ // The given interface, "overrides" the receiver.
+ if (ReceiverIFace->isSuperClassOf(IFace))
+ return true;
+ } else {
+ // No receiver was found for the original message.
+ assert(ReceiverIFaceEnt.isInvalid());
+
+ // If the original message interface is a subclass of the given interface,
+ // accept the message.
+ if (HierarchyEntities.count(Entity::get(IFace, Prog)))
+ return true;
+ }
+
+ // The interfaces are unrelated, or the receiver interface wasn't
+ // "overriden".
+ return false;
+ }
+};
+
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// Analyzer Implementation
+//===----------------------------------------------------------------------===//
+
+void Analyzer::FindDeclarations(Decl *D, TULocationHandler &Handler) {
+ assert(D && "Passed null declaration");
+ Entity Ent = Entity::get(D, Prog);
+ if (Ent.isInvalid())
+ return;
+
+ DeclEntityAnalyzer DEA(Ent, Handler);
+ Idxer.GetTranslationUnitsFor(Ent, DEA);
+}
+
+void Analyzer::FindReferences(Decl *D, TULocationHandler &Handler) {
+ assert(D && "Passed null declaration");
+ if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ RefSelectorAnalyzer RSA(MD, Prog, Handler);
+ GlobalSelector Sel = GlobalSelector::get(MD->getSelector(), Prog);
+ Idxer.GetTranslationUnitsFor(Sel, RSA);
+ return;
+ }
+
+ Entity Ent = Entity::get(D, Prog);
+ if (Ent.isInvalid())
+ return;
+
+ RefEntityAnalyzer REA(Ent, Handler);
+ Idxer.GetTranslationUnitsFor(Ent, REA);
+}
+
+/// \brief Find methods that may respond to the given message and pass them
+/// to Handler.
+void Analyzer::FindObjCMethods(ObjCMessageExpr *Msg,
+ TULocationHandler &Handler) {
+ assert(Msg);
+ MessageAnalyzer MsgAnalyz(Msg, Prog, Handler);
+ GlobalSelector GlobSel = GlobalSelector::get(Msg->getSelector(), Prog);
+ Idxer.GetTranslationUnitsFor(GlobSel, MsgAnalyz);
+}
diff --git a/lib/Index/CMakeLists.txt b/lib/Index/CMakeLists.txt
new file mode 100644
index 0000000..5f81817
--- /dev/null
+++ b/lib/Index/CMakeLists.txt
@@ -0,0 +1,15 @@
+set(LLVM_NO_RTTI 1)
+
+add_clang_library(clangIndex
+ ASTLocation.cpp
+ Analyzer.cpp
+ DeclReferenceMap.cpp
+ Entity.cpp
+ GlobalSelector.cpp
+ Handlers.cpp
+ IndexProvider.cpp
+ Indexer.cpp
+ Program.cpp
+ ResolveLocation.cpp
+ SelectorMap.cpp
+ )
diff --git a/lib/Index/DeclReferenceMap.cpp b/lib/Index/DeclReferenceMap.cpp
new file mode 100644
index 0000000..0e48a36
--- /dev/null
+++ b/lib/Index/DeclReferenceMap.cpp
@@ -0,0 +1,91 @@
+//===--- DeclReferenceMap.cpp - Map Decls to their references -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// DeclReferenceMap creates a mapping from Decls to the ASTLocations that
+// reference them.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Index/DeclReferenceMap.h"
+#include "clang/Index/ASTLocation.h"
+#include "ASTVisitor.h"
+#include "llvm/Support/Compiler.h"
+using namespace clang;
+using namespace idx;
+
+namespace {
+
+class VISIBILITY_HIDDEN RefMapper : public ASTVisitor<RefMapper> {
+ DeclReferenceMap::MapTy &Map;
+
+public:
+ RefMapper(DeclReferenceMap::MapTy &map) : Map(map) { }
+
+ void VisitDeclRefExpr(DeclRefExpr *Node);
+ void VisitMemberExpr(MemberExpr *Node);
+ void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node);
+
+ void VisitTypedefLoc(TypedefLoc TL);
+ void VisitObjCInterfaceLoc(ObjCInterfaceLoc TL);
+};
+
+} // anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// RefMapper Implementation
+//===----------------------------------------------------------------------===//
+
+void RefMapper::VisitDeclRefExpr(DeclRefExpr *Node) {
+ NamedDecl *PrimD = cast<NamedDecl>(Node->getDecl()->getCanonicalDecl());
+ Map.insert(std::make_pair(PrimD, ASTLocation(CurrentDecl, Node)));
+}
+
+void RefMapper::VisitMemberExpr(MemberExpr *Node) {
+ NamedDecl *PrimD = cast<NamedDecl>(Node->getMemberDecl()->getCanonicalDecl());
+ Map.insert(std::make_pair(PrimD, ASTLocation(CurrentDecl, Node)));
+}
+
+void RefMapper::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) {
+ Map.insert(std::make_pair(Node->getDecl(), ASTLocation(CurrentDecl, Node)));
+}
+
+void RefMapper::VisitTypedefLoc(TypedefLoc TL) {
+ NamedDecl *ND = TL.getTypedefDecl();
+ Map.insert(std::make_pair(ND, ASTLocation(CurrentDecl, ND, TL.getNameLoc())));
+}
+
+void RefMapper::VisitObjCInterfaceLoc(ObjCInterfaceLoc TL) {
+ NamedDecl *ND = TL.getIFaceDecl();
+ Map.insert(std::make_pair(ND, ASTLocation(CurrentDecl, ND, TL.getNameLoc())));
+}
+
+//===----------------------------------------------------------------------===//
+// DeclReferenceMap Implementation
+//===----------------------------------------------------------------------===//
+
+DeclReferenceMap::DeclReferenceMap(ASTContext &Ctx) {
+ RefMapper(Map).Visit(Ctx.getTranslationUnitDecl());
+}
+
+DeclReferenceMap::astlocation_iterator
+DeclReferenceMap::refs_begin(NamedDecl *D) const {
+ NamedDecl *Prim = cast<NamedDecl>(D->getCanonicalDecl());
+ return astlocation_iterator(Map.lower_bound(Prim));
+}
+
+DeclReferenceMap::astlocation_iterator
+DeclReferenceMap::refs_end(NamedDecl *D) const {
+ NamedDecl *Prim = cast<NamedDecl>(D->getCanonicalDecl());
+ return astlocation_iterator(Map.upper_bound(Prim));
+}
+
+bool DeclReferenceMap::refs_empty(NamedDecl *D) const {
+ NamedDecl *Prim = cast<NamedDecl>(D->getCanonicalDecl());
+ return refs_begin(Prim) == refs_end(Prim);
+}
diff --git a/lib/Index/Entity.cpp b/lib/Index/Entity.cpp
new file mode 100644
index 0000000..77d7a84
--- /dev/null
+++ b/lib/Index/Entity.cpp
@@ -0,0 +1,225 @@
+//===--- Entity.cpp - Cross-translation-unit "token" for decls ------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Entity is a ASTContext-independent way to refer to declarations that are
+// visible across translation units.
+//
+//===----------------------------------------------------------------------===//
+
+#include "EntityImpl.h"
+#include "ProgramImpl.h"
+#include "clang/Index/Program.h"
+#include "clang/Index/GlobalSelector.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclVisitor.h"
+using namespace clang;
+using namespace idx;
+
+// FIXME: Entity is really really basic currently, mostly written to work
+// on variables and functions. Should support types and other decls eventually..
+
+
+//===----------------------------------------------------------------------===//
+// EntityGetter
+//===----------------------------------------------------------------------===//
+
+namespace clang {
+namespace idx {
+
+/// \brief Gets the Entity associated with a Decl.
+class EntityGetter : public DeclVisitor<EntityGetter, Entity> {
+ Program &Prog;
+ ProgramImpl &ProgImpl;
+
+public:
+ EntityGetter(Program &prog, ProgramImpl &progImpl)
+ : Prog(prog), ProgImpl(progImpl) { }
+
+ Entity VisitNamedDecl(NamedDecl *D);
+ Entity VisitVarDecl(VarDecl *D);
+ Entity VisitFunctionDecl(FunctionDecl *D);
+};
+
+}
+}
+
+Entity EntityGetter::VisitNamedDecl(NamedDecl *D) {
+ Entity Parent;
+ if (!D->getDeclContext()->isTranslationUnit()) {
+ Parent = Visit(cast<Decl>(D->getDeclContext()));
+ // FIXME: Anonymous structs ?
+ if (Parent.isInvalid())
+ return Entity();
+ }
+ if (Parent.isValid() && Parent.isInternalToTU())
+ return Entity(D);
+
+ // FIXME: Only works for DeclarationNames that are identifiers and selectors.
+ // Treats other DeclarationNames as internal Decls for now..
+
+ DeclarationName LocalName = D->getDeclName();
+ if (!LocalName)
+ return Entity(D);
+
+ DeclarationName GlobName;
+
+ if (IdentifierInfo *II = LocalName.getAsIdentifierInfo()) {
+ IdentifierInfo *GlobII =
+ &ProgImpl.getIdents().get(II->getName(), II->getName() + II->getLength());
+ GlobName = DeclarationName(GlobII);
+ } else {
+ Selector LocalSel = LocalName.getObjCSelector();
+
+ // Treats other DeclarationNames as internal Decls for now..
+ if (LocalSel.isNull())
+ return Entity(D);
+
+ Selector GlobSel =
+ (uintptr_t)GlobalSelector::get(LocalSel, Prog).getAsOpaquePtr();
+ GlobName = DeclarationName(GlobSel);
+ }
+
+ assert(GlobName);
+
+ unsigned IdNS = D->getIdentifierNamespace();
+
+ ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D);
+ bool isObjCInstanceMethod = MD && MD->isInstanceMethod();
+
+ llvm::FoldingSetNodeID ID;
+ EntityImpl::Profile(ID, Parent, GlobName, IdNS, isObjCInstanceMethod);
+
+ ProgramImpl::EntitySetTy &Entities = ProgImpl.getEntities();
+ void *InsertPos = 0;
+ if (EntityImpl *Ent = Entities.FindNodeOrInsertPos(ID, InsertPos))
+ return Entity(Ent);
+
+ void *Buf = ProgImpl.Allocate(sizeof(EntityImpl));
+ EntityImpl *New =
+ new (Buf) EntityImpl(Parent, GlobName, IdNS, isObjCInstanceMethod);
+ Entities.InsertNode(New, InsertPos);
+
+ return Entity(New);
+}
+
+Entity EntityGetter::VisitVarDecl(VarDecl *D) {
+ // If it's static it cannot be referred to by another translation unit.
+ if (D->getStorageClass() == VarDecl::Static)
+ return Entity(D);
+
+ return VisitNamedDecl(D);
+}
+
+Entity EntityGetter::VisitFunctionDecl(FunctionDecl *D) {
+ // If it's static it cannot be refered to by another translation unit.
+ if (D->getStorageClass() == FunctionDecl::Static)
+ return Entity(D);
+
+ return VisitNamedDecl(D);
+}
+
+//===----------------------------------------------------------------------===//
+// EntityImpl Implementation
+//===----------------------------------------------------------------------===//
+
+Decl *EntityImpl::getDecl(ASTContext &AST) {
+ DeclContext *DC =
+ Parent.isInvalid() ? AST.getTranslationUnitDecl()
+ : cast<DeclContext>(Parent.getDecl(AST));
+ if (!DC)
+ return 0; // Couldn't get the parent context.
+
+ DeclarationName LocalName;
+
+ if (IdentifierInfo *GlobII = Name.getAsIdentifierInfo()) {
+ IdentifierInfo &II = AST.Idents.get(GlobII->getName(),
+ GlobII->getName() + GlobII->getLength());
+ LocalName = DeclarationName(&II);
+ } else {
+ Selector GlobSel = Name.getObjCSelector();
+ assert(!GlobSel.isNull() && "A not handled yet declaration name");
+ GlobalSelector GSel =
+ GlobalSelector::getFromOpaquePtr(GlobSel.getAsOpaquePtr());
+ LocalName = GSel.getSelector(AST);
+ }
+
+ assert(LocalName);
+
+ DeclContext::lookup_result Res = DC->lookup(LocalName);
+ for (DeclContext::lookup_iterator I = Res.first, E = Res.second; I!=E; ++I) {
+ Decl *D = *I;
+ if (D->getIdentifierNamespace() == IdNS) {
+ if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ if (MD->isInstanceMethod() == IsObjCInstanceMethod)
+ return MD;
+ } else
+ return D;
+ }
+ }
+
+ return 0; // Failed to find a decl using this Entity.
+}
+
+/// \brief Get an Entity associated with the given Decl.
+/// \returns Null if an Entity cannot refer to this Decl.
+Entity EntityImpl::get(Decl *D, Program &Prog, ProgramImpl &ProgImpl) {
+ assert(D && "Passed null Decl");
+ return EntityGetter(Prog, ProgImpl).Visit(D);
+}
+
+std::string EntityImpl::getPrintableName() {
+ return Name.getAsString();
+}
+
+//===----------------------------------------------------------------------===//
+// Entity Implementation
+//===----------------------------------------------------------------------===//
+
+Entity::Entity(Decl *D) : Val(D->getCanonicalDecl()) { }
+
+/// \brief Find the Decl that can be referred to by this entity.
+Decl *Entity::getDecl(ASTContext &AST) const {
+ if (isInvalid())
+ return 0;
+
+ if (Decl *D = Val.dyn_cast<Decl *>())
+ // Check that the passed AST is actually the one that this Decl belongs to.
+ return (&D->getASTContext() == &AST) ? D : 0;
+
+ return Val.get<EntityImpl *>()->getDecl(AST);
+}
+
+std::string Entity::getPrintableName() const {
+ if (isInvalid())
+ return "<< Invalid >>";
+
+ if (Decl *D = Val.dyn_cast<Decl *>()) {
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(D))
+ return ND->getNameAsString();
+ else
+ return std::string();
+ }
+
+ return Val.get<EntityImpl *>()->getPrintableName();
+}
+
+/// \brief Get an Entity associated with the given Decl.
+/// \returns Null if an Entity cannot refer to this Decl.
+Entity Entity::get(Decl *D, Program &Prog) {
+ if (D == 0)
+ return Entity();
+ ProgramImpl &ProgImpl = *static_cast<ProgramImpl*>(Prog.Impl);
+ return EntityImpl::get(D, Prog, ProgImpl);
+}
+
+unsigned
+llvm::DenseMapInfo<Entity>::getHashValue(Entity E) {
+ return DenseMapInfo<void*>::getHashValue(E.getAsOpaquePtr());
+}
diff --git a/lib/Index/EntityImpl.h b/lib/Index/EntityImpl.h
new file mode 100644
index 0000000..cbce934
--- /dev/null
+++ b/lib/Index/EntityImpl.h
@@ -0,0 +1,70 @@
+//===--- EntityImpl.h - Internal Entity implementation---------*- C++ -*-=====//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Internal implementation for the Entity class
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_INDEX_ENTITYIMPL_H
+#define LLVM_CLANG_INDEX_ENTITYIMPL_H
+
+#include "clang/Index/Entity.h"
+#include "clang/AST/DeclarationName.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/StringSet.h"
+
+namespace clang {
+
+namespace idx {
+ class ProgramImpl;
+
+class EntityImpl : public llvm::FoldingSetNode {
+ Entity Parent;
+ DeclarationName Name;
+
+ /// \brief Identifier namespace.
+ unsigned IdNS;
+
+ /// \brief If Name is a selector, this keeps track whether it's for an
+ /// instance method.
+ bool IsObjCInstanceMethod;
+
+public:
+ EntityImpl(Entity parent, DeclarationName name, unsigned idNS,
+ bool isObjCInstanceMethod)
+ : Parent(parent), Name(name), IdNS(idNS),
+ IsObjCInstanceMethod(isObjCInstanceMethod) { }
+
+ /// \brief Find the Decl that can be referred to by this entity.
+ Decl *getDecl(ASTContext &AST);
+
+ /// \brief Get an Entity associated with the given Decl.
+ /// \returns Null if an Entity cannot refer to this Decl.
+ static Entity get(Decl *D, Program &Prog, ProgramImpl &ProgImpl);
+
+ std::string getPrintableName();
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ Profile(ID, Parent, Name, IdNS, IsObjCInstanceMethod);
+ }
+ static void Profile(llvm::FoldingSetNodeID &ID, Entity Parent,
+ DeclarationName Name, unsigned IdNS,
+ bool isObjCInstanceMethod) {
+ ID.AddPointer(Parent.getAsOpaquePtr());
+ ID.AddPointer(Name.getAsOpaquePtr());
+ ID.AddInteger(IdNS);
+ ID.AddBoolean(isObjCInstanceMethod);
+ }
+};
+
+} // namespace idx
+
+} // namespace clang
+
+#endif
diff --git a/lib/Index/GlobalSelector.cpp b/lib/Index/GlobalSelector.cpp
new file mode 100644
index 0000000..f3ec41d
--- /dev/null
+++ b/lib/Index/GlobalSelector.cpp
@@ -0,0 +1,73 @@
+//===-- GlobalSelector.cpp - Cross-translation-unit "token" for selectors -===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// GlobalSelector is a ASTContext-independent way to refer to selectors.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Index/GlobalSelector.h"
+#include "ProgramImpl.h"
+#include "clang/Index/Program.h"
+#include "clang/AST/ASTContext.h"
+using namespace clang;
+using namespace idx;
+
+/// \brief Get the ASTContext-specific selector.
+Selector GlobalSelector::getSelector(ASTContext &AST) const {
+ if (isInvalid())
+ return Selector();
+
+ Selector GlobSel = Selector(reinterpret_cast<uintptr_t>(Val));
+
+ llvm::SmallVector<IdentifierInfo *, 8> Ids;
+ for (unsigned i = 0, e = GlobSel.isUnarySelector() ? 1 : GlobSel.getNumArgs();
+ i != e; ++i) {
+ IdentifierInfo *GlobII = GlobSel.getIdentifierInfoForSlot(i);
+ IdentifierInfo *II = &AST.Idents.get(GlobII->getName(),
+ GlobII->getName() + GlobII->getLength());
+ Ids.push_back(II);
+ }
+
+ return AST.Selectors.getSelector(GlobSel.getNumArgs(), Ids.data());
+}
+
+/// \brief Get a printable name for debugging purpose.
+std::string GlobalSelector::getPrintableName() const {
+ if (isInvalid())
+ return "<< Invalid >>";
+
+ Selector GlobSel = Selector(reinterpret_cast<uintptr_t>(Val));
+ return GlobSel.getAsString();
+}
+
+/// \brief Get a GlobalSelector for the ASTContext-specific selector.
+GlobalSelector GlobalSelector::get(Selector Sel, Program &Prog) {
+ if (Sel.isNull())
+ return GlobalSelector();
+
+ ProgramImpl &ProgImpl = *static_cast<ProgramImpl*>(Prog.Impl);
+
+ llvm::SmallVector<IdentifierInfo *, 8> Ids;
+ for (unsigned i = 0, e = Sel.isUnarySelector() ? 1 : Sel.getNumArgs();
+ i != e; ++i) {
+ IdentifierInfo *II = Sel.getIdentifierInfoForSlot(i);
+ IdentifierInfo *GlobII = &ProgImpl.getIdents().get(II->getName(),
+ II->getName() + II->getLength());
+ Ids.push_back(GlobII);
+ }
+
+ Selector GlobSel = ProgImpl.getSelectors().getSelector(Sel.getNumArgs(),
+ Ids.data());
+ return GlobalSelector(GlobSel.getAsOpaquePtr());
+}
+
+unsigned
+llvm::DenseMapInfo<GlobalSelector>::getHashValue(GlobalSelector Sel) {
+ return DenseMapInfo<void*>::getHashValue(Sel.getAsOpaquePtr());
+}
diff --git a/lib/Index/Handlers.cpp b/lib/Index/Handlers.cpp
new file mode 100644
index 0000000..1e9a27d
--- /dev/null
+++ b/lib/Index/Handlers.cpp
@@ -0,0 +1,22 @@
+//===--- Handlers.cpp - Interfaces for receiving information ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Abstract interfaces for receiving information.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Index/Handlers.h"
+#include "clang/Index/Entity.h"
+using namespace clang;
+using namespace idx;
+
+// Out-of-line to give the virtual tables a home.
+EntityHandler::~EntityHandler() { }
+TranslationUnitHandler::~TranslationUnitHandler() { }
+TULocationHandler::~TULocationHandler() { }
diff --git a/lib/Index/IndexProvider.cpp b/lib/Index/IndexProvider.cpp
new file mode 100644
index 0000000..eea0988
--- /dev/null
+++ b/lib/Index/IndexProvider.cpp
@@ -0,0 +1,20 @@
+//===- IndexProvider.cpp - Maps information to translation units -*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Maps information to TranslationUnits.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Index/IndexProvider.h"
+#include "clang/Index/Entity.h"
+using namespace clang;
+using namespace idx;
+
+// Out-of-line to give the virtual table a home.
+IndexProvider::~IndexProvider() { }
diff --git a/lib/Index/Indexer.cpp b/lib/Index/Indexer.cpp
new file mode 100644
index 0000000..57bfc5b
--- /dev/null
+++ b/lib/Index/Indexer.cpp
@@ -0,0 +1,104 @@
+//===--- Indexer.cpp - IndexProvider implementation -------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// IndexProvider implementation.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Index/Indexer.h"
+#include "clang/Index/Program.h"
+#include "clang/Index/Handlers.h"
+#include "clang/Index/TranslationUnit.h"
+#include "ASTVisitor.h"
+#include "clang/AST/DeclBase.h"
+using namespace clang;
+using namespace idx;
+
+namespace {
+
+class EntityIndexer : public EntityHandler {
+ TranslationUnit *TU;
+ Indexer::MapTy &Map;
+
+public:
+ EntityIndexer(TranslationUnit *tu, Indexer::MapTy &map) : TU(tu), Map(map) { }
+
+ virtual void Handle(Entity Ent) {
+ if (Ent.isInternalToTU())
+ return;
+ Map[Ent].insert(TU);
+ }
+};
+
+class SelectorIndexer : public ASTVisitor<SelectorIndexer> {
+ Program &Prog;
+ TranslationUnit *TU;
+ Indexer::SelMapTy &Map;
+
+public:
+ SelectorIndexer(Program &prog, TranslationUnit *tu, Indexer::SelMapTy &map)
+ : Prog(prog), TU(tu), Map(map) { }
+
+ void VisitObjCMethodDecl(ObjCMethodDecl *D) {
+ Map[GlobalSelector::get(D->getSelector(), Prog)].insert(TU);
+ Base::VisitObjCMethodDecl(D);
+ }
+
+ void VisitObjCMessageExpr(ObjCMessageExpr *Node) {
+ Map[GlobalSelector::get(Node->getSelector(), Prog)].insert(TU);
+ Base::VisitObjCMessageExpr(Node);
+ }
+};
+
+} // anonymous namespace
+
+void Indexer::IndexAST(TranslationUnit *TU) {
+ assert(TU && "Passed null TranslationUnit");
+ ASTContext &Ctx = TU->getASTContext();
+ CtxTUMap[&Ctx] = TU;
+ EntityIndexer Idx(TU, Map);
+ Prog.FindEntities(Ctx, Idx);
+
+ SelectorIndexer SelIdx(Prog, TU, SelMap);
+ SelIdx.Visit(Ctx.getTranslationUnitDecl());
+}
+
+void Indexer::GetTranslationUnitsFor(Entity Ent,
+ TranslationUnitHandler &Handler) {
+ assert(Ent.isValid() && "Expected valid Entity");
+
+ if (Ent.isInternalToTU()) {
+ Decl *D = Ent.getInternalDecl();
+ CtxTUMapTy::iterator I = CtxTUMap.find(&D->getASTContext());
+ if (I != CtxTUMap.end())
+ Handler.Handle(I->second);
+ return;
+ }
+
+ MapTy::iterator I = Map.find(Ent);
+ if (I == Map.end())
+ return;
+
+ TUSetTy &Set = I->second;
+ for (TUSetTy::iterator I = Set.begin(), E = Set.end(); I != E; ++I)
+ Handler.Handle(*I);
+}
+
+void Indexer::GetTranslationUnitsFor(GlobalSelector Sel,
+ TranslationUnitHandler &Handler) {
+ assert(Sel.isValid() && "Expected valid GlobalSelector");
+
+ SelMapTy::iterator I = SelMap.find(Sel);
+ if (I == SelMap.end())
+ return;
+
+ TUSetTy &Set = I->second;
+ for (TUSetTy::iterator I = Set.begin(), E = Set.end(); I != E; ++I)
+ Handler.Handle(*I);
+}
diff --git a/lib/Index/Makefile b/lib/Index/Makefile
new file mode 100644
index 0000000..7dee87f
--- /dev/null
+++ b/lib/Index/Makefile
@@ -0,0 +1,28 @@
+##===- clang/lib/Index/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 Indexer library for the C-Language front-end.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../../../..
+include $(LEVEL)/Makefile.config
+
+LIBRARYNAME := clangIndex
+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/Index/Program.cpp b/lib/Index/Program.cpp
new file mode 100644
index 0000000..4efad2c
--- /dev/null
+++ b/lib/Index/Program.cpp
@@ -0,0 +1,50 @@
+//===--- Program.cpp - Entity originator and misc -------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Storage for Entities and utility functions
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Index/Program.h"
+#include "ProgramImpl.h"
+#include "clang/Index/Handlers.h"
+#include "clang/Index/TranslationUnit.h"
+#include "clang/AST/DeclBase.h"
+#include "clang/AST/ASTContext.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+using namespace idx;
+
+// Out-of-line to give the virtual tables a home.
+TranslationUnit::~TranslationUnit() { }
+
+Program::Program() : Impl(new ProgramImpl()) { }
+
+Program::~Program() {
+ delete static_cast<ProgramImpl *>(Impl);
+}
+
+static void FindEntitiesInDC(DeclContext *DC, Program &Prog,
+ EntityHandler &Handler) {
+ for (DeclContext::decl_iterator
+ I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) {
+ if (I->getLocation().isInvalid())
+ continue;
+ Entity Ent = Entity::get(*I, Prog);
+ if (Ent.isValid())
+ Handler.Handle(Ent);
+ if (DeclContext *SubDC = dyn_cast<DeclContext>(*I))
+ FindEntitiesInDC(SubDC, Prog, Handler);
+ }
+}
+
+/// \brief Traverses the AST and passes all the entities to the Handler.
+void Program::FindEntities(ASTContext &Ctx, EntityHandler &Handler) {
+ FindEntitiesInDC(Ctx.getTranslationUnitDecl(), *this, Handler);
+}
diff --git a/lib/Index/ProgramImpl.h b/lib/Index/ProgramImpl.h
new file mode 100644
index 0000000..57b9ce3
--- /dev/null
+++ b/lib/Index/ProgramImpl.h
@@ -0,0 +1,56 @@
+//===--- ProgramImpl.h - Internal Program implementation---------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Internal implementation for the Program class
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_INDEX_PROGRAMIMPL_H
+#define LLVM_CLANG_INDEX_PROGRAMIMPL_H
+
+#include "EntityImpl.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/LangOptions.h"
+
+namespace clang {
+
+namespace idx {
+ class EntityListener;
+
+class ProgramImpl {
+public:
+ typedef llvm::FoldingSet<EntityImpl> EntitySetTy;
+
+private:
+ EntitySetTy Entities;
+ llvm::BumpPtrAllocator BumpAlloc;
+
+ IdentifierTable Identifiers;
+ SelectorTable Selectors;
+
+ ProgramImpl(const ProgramImpl&); // do not implement
+ ProgramImpl &operator=(const ProgramImpl &); // do not implement
+
+public:
+ ProgramImpl() : Identifiers(LangOptions()) { }
+
+ EntitySetTy &getEntities() { return Entities; }
+ IdentifierTable &getIdents() { return Identifiers; }
+ SelectorTable &getSelectors() { return Selectors; }
+
+ void *Allocate(unsigned Size, unsigned Align = 8) {
+ return BumpAlloc.Allocate(Size, Align);
+ }
+};
+
+} // namespace idx
+
+} // namespace clang
+
+#endif
diff --git a/lib/Index/ResolveLocation.cpp b/lib/Index/ResolveLocation.cpp
new file mode 100644
index 0000000..229669d
--- /dev/null
+++ b/lib/Index/ResolveLocation.cpp
@@ -0,0 +1,505 @@
+//===--- ResolveLocation.cpp - Source location resolver ---------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines the ResolveLocationInAST function, which resolves a
+// source location into a ASTLocation.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Index/Utils.h"
+#include "clang/Index/ASTLocation.h"
+#include "clang/AST/TypeLocVisitor.h"
+#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/Support/Compiler.h"
+using namespace clang;
+using namespace idx;
+
+namespace {
+
+/// \brief Base for the LocResolver classes. Mostly does source range checking.
+class VISIBILITY_HIDDEN LocResolverBase {
+protected:
+ ASTContext &Ctx;
+ SourceLocation Loc;
+
+ ASTLocation ResolveInDeclarator(Decl *D, Stmt *Stm, DeclaratorInfo *DInfo);
+
+ enum RangePos {
+ BeforeLoc,
+ ContainsLoc,
+ AfterLoc
+ };
+
+ RangePos CheckRange(SourceRange Range);
+ RangePos CheckRange(DeclaratorInfo *DInfo);
+ RangePos CheckRange(Decl *D) {
+ if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D))
+ if (ContainsLocation(DD->getDeclaratorInfo()))
+ return ContainsLoc;
+
+ return CheckRange(D->getSourceRange());
+ }
+ RangePos CheckRange(Stmt *Node) { return CheckRange(Node->getSourceRange()); }
+ RangePos CheckRange(TypeLoc TL) { return CheckRange(TL.getSourceRange()); }
+
+ template <typename T>
+ bool isBeforeLocation(T Node) {
+ return CheckRange(Node) == BeforeLoc;
+ }
+
+ template <typename T>
+ bool ContainsLocation(T Node) {
+ return CheckRange(Node) == ContainsLoc;
+ }
+
+ template <typename T>
+ bool isAfterLocation(T Node) {
+ return CheckRange(Node) == AfterLoc;
+ }
+
+public:
+ LocResolverBase(ASTContext &ctx, SourceLocation loc)
+ : Ctx(ctx), Loc(loc) {}
+
+#ifndef NDEBUG
+ /// \brief Debugging output.
+ void print(Decl *D);
+ /// \brief Debugging output.
+ void print(Stmt *Node);
+#endif
+};
+
+/// \brief Searches a statement for the ASTLocation that corresponds to a source
+/// location.
+class VISIBILITY_HIDDEN StmtLocResolver : public LocResolverBase,
+ public StmtVisitor<StmtLocResolver,
+ ASTLocation > {
+ Decl * const Parent;
+
+public:
+ StmtLocResolver(ASTContext &ctx, SourceLocation loc, Decl *parent)
+ : LocResolverBase(ctx, loc), Parent(parent) {}
+
+ ASTLocation VisitCXXOperatorCallExpr(CXXOperatorCallExpr *Node);
+ ASTLocation VisitDeclStmt(DeclStmt *Node);
+ ASTLocation VisitStmt(Stmt *Node);
+};
+
+/// \brief Searches a declaration for the ASTLocation that corresponds to a
+/// source location.
+class VISIBILITY_HIDDEN DeclLocResolver : public LocResolverBase,
+ public DeclVisitor<DeclLocResolver,
+ ASTLocation > {
+public:
+ DeclLocResolver(ASTContext &ctx, SourceLocation loc)
+ : LocResolverBase(ctx, loc) {}
+
+ ASTLocation VisitDeclContext(DeclContext *DC);
+ ASTLocation VisitTranslationUnitDecl(TranslationUnitDecl *TU);
+ ASTLocation VisitDeclaratorDecl(DeclaratorDecl *D);
+ ASTLocation VisitVarDecl(VarDecl *D);
+ ASTLocation VisitFunctionDecl(FunctionDecl *D);
+ ASTLocation VisitObjCMethodDecl(ObjCMethodDecl *D);
+ ASTLocation VisitDecl(Decl *D);
+};
+
+class TypeLocResolver : public LocResolverBase,
+ public TypeLocVisitor<TypeLocResolver, ASTLocation> {
+ Decl * const ParentDecl;
+
+public:
+ TypeLocResolver(ASTContext &ctx, SourceLocation loc, Decl *pd)
+ : LocResolverBase(ctx, loc), ParentDecl(pd) { }
+
+ ASTLocation VisitTypedefLoc(TypedefLoc TL);
+ ASTLocation VisitFunctionLoc(FunctionLoc TL);
+ ASTLocation VisitArrayLoc(ArrayLoc TL);
+ ASTLocation VisitObjCInterfaceLoc(ObjCInterfaceLoc TL);
+ ASTLocation VisitObjCProtocolListLoc(ObjCProtocolListLoc TL);
+ ASTLocation VisitTypeLoc(TypeLoc TL);
+};
+
+} // anonymous namespace
+
+ASTLocation
+StmtLocResolver::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *Node) {
+ assert(ContainsLocation(Node) &&
+ "Should visit only after verifying that loc is in range");
+
+ if (Node->getNumArgs() == 1)
+ // Unary operator. Let normal child traversal handle it.
+ return VisitCallExpr(Node);
+
+ assert(Node->getNumArgs() == 2 &&
+ "Wrong args for the C++ operator call expr ?");
+
+ llvm::SmallVector<Expr *, 3> Nodes;
+ // Binary operator. Check in order of 1-left arg, 2-callee, 3-right arg.
+ Nodes.push_back(Node->getArg(0));
+ Nodes.push_back(Node->getCallee());
+ Nodes.push_back(Node->getArg(1));
+
+ for (unsigned i = 0, e = Nodes.size(); i != e; ++i) {
+ RangePos RP = CheckRange(Nodes[i]);
+ if (RP == AfterLoc)
+ break;
+ if (RP == ContainsLoc)
+ return Visit(Nodes[i]);
+ }
+
+ return ASTLocation(Parent, Node);
+}
+
+ASTLocation StmtLocResolver::VisitDeclStmt(DeclStmt *Node) {
+ assert(ContainsLocation(Node) &&
+ "Should visit only after verifying that loc is in range");
+
+ // Search all declarations of this DeclStmt.
+ for (DeclStmt::decl_iterator
+ I = Node->decl_begin(), E = Node->decl_end(); I != E; ++I) {
+ RangePos RP = CheckRange(*I);
+ if (RP == AfterLoc)
+ break;
+ if (RP == ContainsLoc)
+ return DeclLocResolver(Ctx, Loc).Visit(*I);
+ }
+
+ return ASTLocation(Parent, Node);
+}
+
+ASTLocation StmtLocResolver::VisitStmt(Stmt *Node) {
+ assert(ContainsLocation(Node) &&
+ "Should visit only after verifying that loc is in range");
+
+ // Search the child statements.
+ for (Stmt::child_iterator
+ I = Node->child_begin(), E = Node->child_end(); I != E; ++I) {
+ if (*I == NULL)
+ continue;
+
+ RangePos RP = CheckRange(*I);
+ if (RP == AfterLoc)
+ break;
+ if (RP == ContainsLoc)
+ return Visit(*I);
+ }
+
+ return ASTLocation(Parent, Node);
+}
+
+ASTLocation DeclLocResolver::VisitDeclContext(DeclContext *DC) {
+ for (DeclContext::decl_iterator
+ I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) {
+ RangePos RP = CheckRange(*I);
+ if (RP == AfterLoc)
+ break;
+ if (RP == ContainsLoc)
+ return Visit(*I);
+ }
+
+ return ASTLocation(cast<Decl>(DC));
+}
+
+ASTLocation DeclLocResolver::VisitTranslationUnitDecl(TranslationUnitDecl *TU) {
+ ASTLocation ASTLoc = VisitDeclContext(TU);
+ if (ASTLoc.getParentDecl() == TU)
+ return ASTLocation();
+ return ASTLoc;
+}
+
+ASTLocation DeclLocResolver::VisitFunctionDecl(FunctionDecl *D) {
+ assert(ContainsLocation(D) &&
+ "Should visit only after verifying that loc is in range");
+
+ if (ContainsLocation(D->getDeclaratorInfo()))
+ return ResolveInDeclarator(D, 0, D->getDeclaratorInfo());
+
+ // First, search through the parameters of the function.
+ for (FunctionDecl::param_iterator
+ I = D->param_begin(), E = D->param_end(); I != E; ++I) {
+ RangePos RP = CheckRange(*I);
+ if (RP == AfterLoc)
+ return ASTLocation(D);
+ if (RP == ContainsLoc)
+ return Visit(*I);
+ }
+
+ // We didn't find the location in the parameters and we didn't get passed it.
+
+ if (!D->isThisDeclarationADefinition())
+ return ASTLocation(D);
+
+ // Second, search through the declarations that are part of the function.
+ // If we find he location there, we won't have to search through its body.
+
+ for (DeclContext::decl_iterator
+ I = D->decls_begin(), E = D->decls_end(); I != E; ++I) {
+ if (isa<ParmVarDecl>(*I))
+ continue; // We already searched through the parameters.
+
+ RangePos RP = CheckRange(*I);
+ if (RP == AfterLoc)
+ break;
+ if (RP == ContainsLoc)
+ return Visit(*I);
+ }
+
+ // We didn't find a declaration that corresponds to the source location.
+
+ // Finally, search through the body of the function.
+ Stmt *Body = D->getBody();
+ assert(Body && "Expected definition");
+ assert(!isBeforeLocation(Body) &&
+ "This function is supposed to contain the loc");
+ if (isAfterLocation(Body))
+ return ASTLocation(D);
+
+ // The body contains the location.
+ assert(ContainsLocation(Body));
+ return StmtLocResolver(Ctx, Loc, D).Visit(Body);
+}
+
+ASTLocation DeclLocResolver::VisitDeclaratorDecl(DeclaratorDecl *D) {
+ assert(ContainsLocation(D) &&
+ "Should visit only after verifying that loc is in range");
+ if (ContainsLocation(D->getDeclaratorInfo()))
+ return ResolveInDeclarator(D, /*Stmt=*/0, D->getDeclaratorInfo());
+
+ return ASTLocation(D);
+}
+
+ASTLocation DeclLocResolver::VisitVarDecl(VarDecl *D) {
+ assert(ContainsLocation(D) &&
+ "Should visit only after verifying that loc is in range");
+
+ // Check whether the location points to the init expression.
+ Expr *Init = D->getInit();
+ if (Init && ContainsLocation(Init))
+ return StmtLocResolver(Ctx, Loc, D).Visit(Init);
+
+ if (ContainsLocation(D->getDeclaratorInfo()))
+ return ResolveInDeclarator(D, 0, D->getDeclaratorInfo());
+
+ return ASTLocation(D);
+}
+
+ASTLocation DeclLocResolver::VisitObjCMethodDecl(ObjCMethodDecl *D) {
+ assert(ContainsLocation(D) &&
+ "Should visit only after verifying that loc is in range");
+
+ // First, search through the parameters of the method.
+ for (ObjCMethodDecl::param_iterator
+ I = D->param_begin(), E = D->param_end(); I != E; ++I) {
+ RangePos RP = CheckRange(*I);
+ if (RP == AfterLoc)
+ return ASTLocation(D);
+ if (RP == ContainsLoc)
+ return Visit(*I);
+ }
+
+ // We didn't find the location in the parameters and we didn't get passed it.
+
+ if (!D->getBody())
+ return ASTLocation(D);
+
+ // Second, search through the declarations that are part of the method.
+ // If we find he location there, we won't have to search through its body.
+
+ for (DeclContext::decl_iterator
+ I = D->decls_begin(), E = D->decls_end(); I != E; ++I) {
+ if (isa<ParmVarDecl>(*I))
+ continue; // We already searched through the parameters.
+
+ RangePos RP = CheckRange(*I);
+ if (RP == AfterLoc)
+ break;
+ if (RP == ContainsLoc)
+ return Visit(*I);
+ }
+
+ // We didn't find a declaration that corresponds to the source location.
+
+ // Finally, search through the body of the method.
+ Stmt *Body = D->getBody();
+ assert(Body && "Expected definition");
+ assert(!isBeforeLocation(Body) &&
+ "This method is supposed to contain the loc");
+ if (isAfterLocation(Body))
+ return ASTLocation(D);
+
+ // The body contains the location.
+ assert(ContainsLocation(Body));
+ return StmtLocResolver(Ctx, Loc, D).Visit(Body);
+}
+
+ASTLocation DeclLocResolver::VisitDecl(Decl *D) {
+ assert(ContainsLocation(D) &&
+ "Should visit only after verifying that loc is in range");
+ if (DeclContext *DC = dyn_cast<DeclContext>(D))
+ return VisitDeclContext(DC);
+ return ASTLocation(D);
+}
+
+ASTLocation TypeLocResolver::VisitTypedefLoc(TypedefLoc TL) {
+ assert(ContainsLocation(TL) &&
+ "Should visit only after verifying that loc is in range");
+ if (ContainsLocation(TL.getNameLoc()))
+ return ASTLocation(ParentDecl, TL.getTypedefDecl(), TL.getNameLoc());
+ return ASTLocation(ParentDecl, TL);
+}
+
+ASTLocation TypeLocResolver::VisitFunctionLoc(FunctionLoc TL) {
+ assert(ContainsLocation(TL) &&
+ "Should visit only after verifying that loc is in range");
+
+ for (unsigned i = 0; i != TL.getNumArgs(); ++i) {
+ ParmVarDecl *Parm = TL.getArg(i);
+ RangePos RP = CheckRange(Parm);
+ if (RP == AfterLoc)
+ break;
+ if (RP == ContainsLoc)
+ return DeclLocResolver(Ctx, Loc).Visit(Parm);
+ }
+
+ return ASTLocation(ParentDecl, TL);
+}
+
+ASTLocation TypeLocResolver::VisitArrayLoc(ArrayLoc TL) {
+ assert(ContainsLocation(TL) &&
+ "Should visit only after verifying that loc is in range");
+
+ Expr *E = TL.getSizeExpr();
+ if (E && ContainsLocation(E))
+ return StmtLocResolver(Ctx, Loc, ParentDecl).Visit(E);
+
+ return ASTLocation(ParentDecl, TL);
+}
+
+ASTLocation TypeLocResolver::VisitObjCInterfaceLoc(ObjCInterfaceLoc TL) {
+ assert(ContainsLocation(TL) &&
+ "Should visit only after verifying that loc is in range");
+ if (ContainsLocation(TL.getNameLoc()))
+ return ASTLocation(ParentDecl, TL.getIFaceDecl(), TL.getNameLoc());
+ return ASTLocation(ParentDecl, TL);
+}
+
+ASTLocation TypeLocResolver::VisitObjCProtocolListLoc(ObjCProtocolListLoc TL) {
+ assert(ContainsLocation(TL) &&
+ "Should visit only after verifying that loc is in range");
+
+ for (unsigned i = 0; i != TL.getNumProtocols(); ++i) {
+ SourceLocation L = TL.getProtocolLoc(i);
+ RangePos RP = CheckRange(L);
+ if (RP == AfterLoc)
+ break;
+ if (RP == ContainsLoc)
+ return ASTLocation(ParentDecl, TL.getProtocol(i), L);
+ }
+
+ return ASTLocation(ParentDecl, TL);
+}
+
+ASTLocation TypeLocResolver::VisitTypeLoc(TypeLoc TL) {
+ assert(ContainsLocation(TL) &&
+ "Should visit only after verifying that loc is in range");
+ return ASTLocation(ParentDecl, TL);
+}
+
+ASTLocation LocResolverBase::ResolveInDeclarator(Decl *D, Stmt *Stm,
+ DeclaratorInfo *DInfo) {
+ assert(ContainsLocation(DInfo) &&
+ "Should visit only after verifying that loc is in range");
+
+ TypeLocResolver(Ctx, Loc, D);
+ for (TypeLoc TL = DInfo->getTypeLoc(); TL; TL = TL.getNextTypeLoc())
+ if (ContainsLocation(TL))
+ return TypeLocResolver(Ctx, Loc, D).Visit(TL);
+
+ assert(0 && "Should have found the loc in a typeloc");
+ return ASTLocation(D, Stm);
+}
+
+LocResolverBase::RangePos LocResolverBase::CheckRange(DeclaratorInfo *DInfo) {
+ if (!DInfo)
+ return BeforeLoc; // Keep looking.
+
+ for (TypeLoc TL = DInfo->getTypeLoc(); TL; TL = TL.getNextTypeLoc())
+ if (ContainsLocation(TL))
+ return ContainsLoc;
+
+ return BeforeLoc; // Keep looking.
+}
+
+LocResolverBase::RangePos LocResolverBase::CheckRange(SourceRange Range) {
+ if (!Range.isValid())
+ return BeforeLoc; // Keep looking.
+
+ // Update the end source range to cover the full length of the token
+ // positioned at the end of the source range.
+ //
+ // e.g.,
+ // int foo
+ // ^ ^
+ //
+ // will be updated to
+ // int foo
+ // ^ ^
+ unsigned TokSize = Lexer::MeasureTokenLength(Range.getEnd(),
+ Ctx.getSourceManager(),
+ Ctx.getLangOptions());
+ Range.setEnd(Range.getEnd().getFileLocWithOffset(TokSize-1));
+
+ SourceManager &SourceMgr = Ctx.getSourceManager();
+ if (SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), Loc))
+ return BeforeLoc;
+
+ if (SourceMgr.isBeforeInTranslationUnit(Loc, Range.getBegin()))
+ return AfterLoc;
+
+ return ContainsLoc;
+}
+
+#ifndef NDEBUG
+void LocResolverBase::print(Decl *D) {
+ llvm::raw_ostream &OS = llvm::outs();
+ OS << "#### DECL " << D->getDeclKindName() << " ####\n";
+ D->print(OS);
+ OS << " <";
+ D->getLocStart().print(OS, Ctx.getSourceManager());
+ OS << " > - <";
+ D->getLocEnd().print(OS, Ctx.getSourceManager());
+ OS << ">\n\n";
+ OS.flush();
+}
+
+void LocResolverBase::print(Stmt *Node) {
+ llvm::raw_ostream &OS = llvm::outs();
+ OS << "#### STMT " << Node->getStmtClassName() << " ####\n";
+ Node->printPretty(OS, Ctx, 0, PrintingPolicy(Ctx.getLangOptions()));
+ OS << " <";
+ Node->getLocStart().print(OS, Ctx.getSourceManager());
+ OS << " > - <";
+ Node->getLocEnd().print(OS, Ctx.getSourceManager());
+ OS << ">\n\n";
+ OS.flush();
+}
+#endif
+
+
+/// \brief Returns the AST node that a source location points to.
+///
+ASTLocation idx::ResolveLocationInAST(ASTContext &Ctx, SourceLocation Loc) {
+ if (Loc.isInvalid())
+ return ASTLocation();
+
+ return DeclLocResolver(Ctx, Loc).Visit(Ctx.getTranslationUnitDecl());
+}
diff --git a/lib/Index/SelectorMap.cpp b/lib/Index/SelectorMap.cpp
new file mode 100644
index 0000000..325b371
--- /dev/null
+++ b/lib/Index/SelectorMap.cpp
@@ -0,0 +1,85 @@
+//===- SelectorMap.cpp - Maps selectors to methods and messages -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// SelectorMap creates a mapping from selectors to ObjC method declarations
+// and ObjC message expressions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Index/SelectorMap.h"
+#include "ASTVisitor.h"
+#include "llvm/Support/Compiler.h"
+using namespace clang;
+using namespace idx;
+
+namespace {
+
+class VISIBILITY_HIDDEN SelMapper : public ASTVisitor<SelMapper> {
+ SelectorMap::SelMethMapTy &SelMethMap;
+ SelectorMap::SelRefMapTy &SelRefMap;
+
+public:
+ SelMapper(SelectorMap::SelMethMapTy &MethMap,
+ SelectorMap::SelRefMapTy &RefMap)
+ : SelMethMap(MethMap), SelRefMap(RefMap) { }
+
+ void VisitObjCMethodDecl(ObjCMethodDecl *D);
+ void VisitObjCMessageExpr(ObjCMessageExpr *Node);
+ void VisitObjCSelectorExpr(ObjCSelectorExpr *Node);
+};
+
+} // anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// SelMapper Implementation
+//===----------------------------------------------------------------------===//
+
+void SelMapper::VisitObjCMethodDecl(ObjCMethodDecl *D) {
+ if (D->getCanonicalDecl() == D)
+ SelMethMap.insert(std::make_pair(D->getSelector(), D));
+ Base::VisitObjCMethodDecl(D);
+}
+
+void SelMapper::VisitObjCMessageExpr(ObjCMessageExpr *Node) {
+ ASTLocation ASTLoc(CurrentDecl, Node);
+ SelRefMap.insert(std::make_pair(Node->getSelector(), ASTLoc));
+}
+
+void SelMapper::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) {
+ ASTLocation ASTLoc(CurrentDecl, Node);
+ SelRefMap.insert(std::make_pair(Node->getSelector(), ASTLoc));
+}
+
+//===----------------------------------------------------------------------===//
+// SelectorMap Implementation
+//===----------------------------------------------------------------------===//
+
+SelectorMap::SelectorMap(ASTContext &Ctx) {
+ SelMapper(SelMethMap, SelRefMap).Visit(Ctx.getTranslationUnitDecl());
+}
+
+SelectorMap::method_iterator
+SelectorMap::methods_begin(Selector Sel) const {
+ return method_iterator(SelMethMap.lower_bound(Sel));
+}
+
+SelectorMap::method_iterator
+SelectorMap::methods_end(Selector Sel) const {
+ return method_iterator(SelMethMap.upper_bound(Sel));
+}
+
+SelectorMap::astlocation_iterator
+SelectorMap::refs_begin(Selector Sel) const {
+ return astlocation_iterator(SelRefMap.lower_bound(Sel));
+}
+
+SelectorMap::astlocation_iterator
+SelectorMap::refs_end(Selector Sel) const {
+ return astlocation_iterator(SelRefMap.upper_bound(Sel));
+}
diff --git a/lib/Lex/CMakeLists.txt b/lib/Lex/CMakeLists.txt
index a7237a7..81a1e01 100644
--- a/lib/Lex/CMakeLists.txt
+++ b/lib/Lex/CMakeLists.txt
@@ -14,13 +14,13 @@ add_clang_library(clangLex
PPExpressions.cpp
PPLexerChange.cpp
PPMacroExpansion.cpp
+ PTHLexer.cpp
Pragma.cpp
Preprocessor.cpp
PreprocessorLexer.cpp
- PTHLexer.cpp
ScratchBuffer.cpp
- TokenLexer.cpp
TokenConcatenation.cpp
+ TokenLexer.cpp
)
add_dependencies(clangLex ClangDiagnosticLex)
diff --git a/lib/Lex/HeaderMap.cpp b/lib/Lex/HeaderMap.cpp
index 4c8b70e..c9a10dc 100644
--- a/lib/Lex/HeaderMap.cpp
+++ b/lib/Lex/HeaderMap.cpp
@@ -28,8 +28,8 @@ using namespace clang;
enum {
HMAP_HeaderMagicNumber = ('h' << 24) | ('m' << 16) | ('a' << 8) | 'p',
HMAP_HeaderVersion = 1,
-
- HMAP_EmptyBucketKey = 0
+
+ HMAP_EmptyBucketKey = 0
};
namespace clang {
@@ -58,7 +58,7 @@ struct HMapHeader {
/// 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;
@@ -78,27 +78,27 @@ 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::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 &&
+ 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
+ else
return 0; // Not a header map.
-
+
if (Header->Reserved != 0) return 0;
// Okay, everything looks good, create the header map.
@@ -137,11 +137,11 @@ const HMapHeader &HeaderMap::getHeader() const {
HMapBucket HeaderMap::getBucket(unsigned BucketNo) const {
HMapBucket Result;
Result.Key = HMAP_EmptyBucketKey;
-
- const HMapBucket *BucketArray =
+
+ 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;
@@ -161,11 +161,11 @@ HMapBucket HeaderMap::getBucket(unsigned BucketNo) const {
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.
@@ -191,15 +191,15 @@ static bool StringsEqualWithoutCase(const char *S1, const char *S2,
void HeaderMap::dump() const {
const HMapHeader &Hdr = getHeader();
unsigned NumBuckets = getEndianAdjustedWord(Hdr.NumBuckets);
-
- fprintf(stderr, "Header Map %s:\n %d buckets, %d entries\n",
+
+ 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);
@@ -219,22 +219,22 @@ const FileEntry *HeaderMap::LookupFile(const char *FilenameStart,
// 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;
diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp
index 9023b11..2b9b7c9 100644
--- a/lib/Lex/HeaderSearch.cpp
+++ b/lib/Lex/HeaderSearch.cpp
@@ -35,7 +35,7 @@ HeaderFileInfo::getControllingMacro(ExternalIdentifierLookup *External) {
HeaderSearch::HeaderSearch(FileManager &FM) : FileMgr(FM), FrameworkMap(64) {
SystemDirIdx = 0;
NoCurDirSearch = false;
-
+
ExternalLookup = 0;
NumIncluded = 0;
NumMultiIncludeFileOptzn = 0;
@@ -47,7 +47,7 @@ HeaderSearch::~HeaderSearch() {
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());
@@ -61,11 +61,11 @@ void HeaderSearch::PrintStats() {
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);
}
@@ -79,15 +79,15 @@ const HeaderMap *HeaderSearch::CreateHeaderMap(const FileEntry *FE) {
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)
+ 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;
}
@@ -121,10 +121,10 @@ const FileEntry *DirectoryLookup::LookupFile(const char *FilenameStart,
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());
}
@@ -136,63 +136,63 @@ 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 =
+ 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(),
+ 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,
+ FrameworkName.insert(FrameworkName.begin()+OrigSize, Private,
Private+strlen(Private));
return FileMgr.getFile(FrameworkName.begin(), FrameworkName.end());
}
@@ -209,7 +209,7 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(const char *FilenameStart,
/// 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,
+ const char *FilenameEnd,
bool isAngled,
const DirectoryLookup *FromDir,
const DirectoryLookup *&CurDir,
@@ -220,11 +220,11 @@ const FileEntry *HeaderSearch::LookupFile(const char *FilenameStart,
// 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
@@ -249,17 +249,17 @@ const FileEntry *HeaderSearch::LookupFile(const char *FilenameStart,
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
@@ -279,23 +279,23 @@ const FileEntry *HeaderSearch::LookupFile(const char *FilenameStart,
// 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 =
+ 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;
@@ -311,20 +311,20 @@ 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,
+
+ llvm::SmallString<1024> FrameworkName(ContextName,
FrameworkPos+strlen(".framework/"));
// Append Frameworks/HIToolbox.framework/
@@ -334,28 +334,28 @@ LookupSubframeworkHeader(const char *FilenameStart,
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"
@@ -364,7 +364,7 @@ LookupSubframeworkHeader(const char *FilenameStart,
HeadersFilename.append(SlashPos+1, FilenameEnd);
if (!(FE = FileMgr.getFile(HeadersFilename.begin(),
HeadersFilename.end()))) {
-
+
// Check ".../Frameworks/HIToolbox.framework/PrivateHeaders/HIToolbox.h"
HeadersFilename = FrameworkName;
HeadersFilename += "PrivateHeaders/";
@@ -372,7 +372,7 @@ LookupSubframeworkHeader(const char *FilenameStart,
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
@@ -394,7 +394,7 @@ 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())
@@ -410,13 +410,13 @@ bool HeaderSearch::ShouldEnterIncludeFile(const FileEntry *File, bool isImport){
// 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 {
@@ -425,19 +425,19 @@ bool HeaderSearch::ShouldEnterIncludeFile(const FileEntry *File, bool isImport){
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
+ 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
index 6f1043a..c8b9a5d 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -39,7 +39,7 @@ static void InitCharacterInfo();
// Token Class Implementation
//===----------------------------------------------------------------------===//
-/// isObjCAtKeyword - Return true if we have an ObjC keyword identifier.
+/// 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;
@@ -57,35 +57,36 @@ tok::ObjCKeywordKind Token::getObjCKeywordID() const {
// Lexer Class Implementation
//===----------------------------------------------------------------------===//
-void Lexer::InitLexer(const char *BufStart, const char *BufPtr,
+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;
+ Is_PragmaLexer = false;
+ IsEofCodeCompletion = 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;
}
@@ -98,14 +99,18 @@ 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());
+
+ // If the input file is truncated, the EOF is a code-completion token.
+ if (PP.getSourceManager().isTruncatedFile(FID))
+ IsEofCodeCompletion = true;
}
/// Lexer constructor - Create a new raw lexer object. This object is only
@@ -116,7 +121,7 @@ Lexer::Lexer(SourceLocation fileloc, const LangOptions &features,
: FileLoc(fileloc), Features(features) {
InitLexer(BufStart, BufPtr, BufEnd);
-
+
// We *are* in raw mode.
LexingRawMode = true;
}
@@ -128,9 +133,9 @@ 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(),
+ InitLexer(FromFile->getBufferStart(), FromFile->getBufferStart(),
FromFile->getBufferEnd());
-
+
// We *are* in raw mode.
LexingRawMode = true;
}
@@ -150,7 +155,7 @@ Lexer::Lexer(FileID FID, const SourceManager &SM, const LangOptions &features)
/// interface that could handle this stuff. This would pull GetMappedTokenLoc
/// out of the critical path of the lexer!
///
-Lexer *Lexer::Create_PragmaLexer(SourceLocation SpellingLoc,
+Lexer *Lexer::Create_PragmaLexer(SourceLocation SpellingLoc,
SourceLocation InstantiationLocStart,
SourceLocation InstantiationLocEnd,
unsigned TokLen, Preprocessor &PP) {
@@ -159,12 +164,12 @@ Lexer *Lexer::Create_PragmaLexer(SourceLocation SpellingLoc,
// 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!");
@@ -174,11 +179,11 @@ Lexer *Lexer::Create_PragmaLexer(SourceLocation SpellingLoc,
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;
@@ -220,7 +225,7 @@ unsigned Lexer::MeasureTokenLength(SourceLocation Loc,
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
+ // all obviously single-char tokens. This could use
// Lexer::isObviouslySimpleCharacter for example to handle identifiers or
// something.
@@ -233,6 +238,7 @@ unsigned Lexer::MeasureTokenLength(SourceLocation Loc,
// Create a lexer starting at the beginning of this token.
Lexer TheLexer(Loc, LangOpts, Buffer.first, StrData, Buffer.second);
+ TheLexer.SetCommentRetentionState(true);
Token TheTok;
TheLexer.LexFromRawLexer(TheTok);
return TheTok.getLength();
@@ -242,8 +248,6 @@ unsigned Lexer::MeasureTokenLength(SourceLocation Loc,
// Character information.
//===----------------------------------------------------------------------===//
-static unsigned char CharInfo[256];
-
enum {
CHAR_HORZ_WS = 0x01, // ' ', '\t', '\f', '\v'. Note, no '\0'
CHAR_VERT_WS = 0x02, // '\r', '\n'
@@ -253,25 +257,98 @@ enum {
CHAR_PERIOD = 0x20 // .
};
+// Statically initialize CharInfo table based on ASCII character set
+// Reference: FreeBSD 7.2 /usr/share/misc/ascii
+static const unsigned char CharInfo[256] =
+{
+// 0 NUL 1 SOH 2 STX 3 ETX
+// 4 EOT 5 ENQ 6 ACK 7 BEL
+ 0 , 0 , 0 , 0 ,
+ 0 , 0 , 0 , 0 ,
+// 8 BS 9 HT 10 NL 11 VT
+//12 NP 13 CR 14 SO 15 SI
+ 0 , CHAR_HORZ_WS, CHAR_VERT_WS, CHAR_HORZ_WS,
+ CHAR_HORZ_WS, CHAR_VERT_WS, 0 , 0 ,
+//16 DLE 17 DC1 18 DC2 19 DC3
+//20 DC4 21 NAK 22 SYN 23 ETB
+ 0 , 0 , 0 , 0 ,
+ 0 , 0 , 0 , 0 ,
+//24 CAN 25 EM 26 SUB 27 ESC
+//28 FS 29 GS 30 RS 31 US
+ 0 , 0 , 0 , 0 ,
+ 0 , 0 , 0 , 0 ,
+//32 SP 33 ! 34 " 35 #
+//36 $ 37 % 38 & 39 '
+ CHAR_HORZ_WS, 0 , 0 , 0 ,
+ 0 , 0 , 0 , 0 ,
+//40 ( 41 ) 42 * 43 +
+//44 , 45 - 46 . 47 /
+ 0 , 0 , 0 , 0 ,
+ 0 , 0 , CHAR_PERIOD , 0 ,
+//48 0 49 1 50 2 51 3
+//52 4 53 5 54 6 55 7
+ CHAR_NUMBER , CHAR_NUMBER , CHAR_NUMBER , CHAR_NUMBER ,
+ CHAR_NUMBER , CHAR_NUMBER , CHAR_NUMBER , CHAR_NUMBER ,
+//56 8 57 9 58 : 59 ;
+//60 < 61 = 62 > 63 ?
+ CHAR_NUMBER , CHAR_NUMBER , 0 , 0 ,
+ 0 , 0 , 0 , 0 ,
+//64 @ 65 A 66 B 67 C
+//68 D 69 E 70 F 71 G
+ 0 , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
+ CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
+//72 H 73 I 74 J 75 K
+//76 L 77 M 78 N 79 O
+ CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
+ CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
+//80 P 81 Q 82 R 83 S
+//84 T 85 U 86 V 87 W
+ CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
+ CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
+//88 X 89 Y 90 Z 91 [
+//92 \ 93 ] 94 ^ 95 _
+ CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , 0 ,
+ 0 , 0 , 0 , CHAR_UNDER ,
+//96 ` 97 a 98 b 99 c
+//100 d 101 e 102 f 103 g
+ 0 , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
+ CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
+//104 h 105 i 106 j 107 k
+//108 l 109 m 110 n 111 o
+ CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
+ CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
+//112 p 113 q 114 r 115 s
+//116 t 117 u 118 v 119 w
+ CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
+ CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
+//120 x 121 y 122 z 123 {
+//124 | 125 } 126 ~ 127 DEL
+ CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , 0 ,
+ 0 , 0 , 0 , 0
+};
+
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;
+ // check the statically-initialized CharInfo table
+ assert(CHAR_HORZ_WS == CharInfo[(int)' ']);
+ assert(CHAR_HORZ_WS == CharInfo[(int)'\t']);
+ assert(CHAR_HORZ_WS == CharInfo[(int)'\f']);
+ assert(CHAR_HORZ_WS == CharInfo[(int)'\v']);
+ assert(CHAR_VERT_WS == CharInfo[(int)'\n']);
+ assert(CHAR_VERT_WS == CharInfo[(int)'\r']);
+ assert(CHAR_UNDER == CharInfo[(int)'_']);
+ assert(CHAR_PERIOD == CharInfo[(int)'.']);
+ for (unsigned i = 'a'; i <= 'z'; ++i) {
+ assert(CHAR_LETTER == CharInfo[i]);
+ assert(CHAR_LETTER == CharInfo[i+'A'-'a']);
+ }
for (unsigned i = '0'; i <= '9'; ++i)
- CharInfo[i] = CHAR_NUMBER;
+ assert(CHAR_NUMBER == CharInfo[i]);
+ isInited = true;
}
+
/// 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) {
@@ -294,7 +371,7 @@ static inline bool isWhitespace(unsigned char c) {
/// 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)) ?
+ return (CharInfo[c] & (CHAR_LETTER|CHAR_NUMBER|CHAR_UNDER|CHAR_PERIOD)) ?
true : false;
}
@@ -315,22 +392,22 @@ 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);
}
@@ -346,7 +423,7 @@ SourceLocation Lexer::getSourceLocation(const char *Loc,
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");
@@ -387,13 +464,13 @@ static char GetTrigraphCharForLetter(char Letter) {
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;
@@ -401,12 +478,12 @@ static char DecodeTrigraphChar(const char *CP, Lexer *L) {
/// 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.
+/// 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;
@@ -414,10 +491,10 @@ unsigned Lexer::getEscapedNewLineSize(const char *Ptr) {
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;
}
@@ -438,7 +515,7 @@ const char *Lexer::SkipEscapedNewLines(const char *P) {
} else {
return P;
}
-
+
unsigned NewLineSize = Lexer::getEscapedNewLineSize(AfterEscape);
if (NewLineSize == 0) return P;
P = AfterEscape+NewLineSize;
@@ -472,7 +549,7 @@ char Lexer::getCharAndSizeSlow(const char *Ptr, unsigned &Size,
Slash:
// Common case, backslash-char where the char is not whitespace.
if (!isWhitespace(Ptr[0])) return '\\';
-
+
// See if we have optional whitespace characters between the slash and
// newline.
if (unsigned EscapedNewLineSize = getEscapedNewLineSize(Ptr)) {
@@ -482,18 +559,18 @@ Slash:
// Warn if there was whitespace between the backslash and newline.
if (Ptr[0] != '\n' && Ptr[0] != '\r' && 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
@@ -508,7 +585,7 @@ Slash:
return C;
}
}
-
+
// If this is neither, return a single character.
++Size;
return *Ptr;
@@ -530,21 +607,21 @@ char Lexer::getCharAndSizeSlowNoWarn(const char *Ptr, unsigned &Size,
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
@@ -556,7 +633,7 @@ Slash:
return C;
}
}
-
+
// If this is neither, return a single character.
++Size;
return *Ptr;
@@ -582,34 +659,34 @@ void Lexer::LexIdentifier(Token &Result, const char *CurPtr) {
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);
@@ -645,7 +722,7 @@ void Lexer::LexNumericConstant(Token &Result, const char *CurPtr) {
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));
@@ -653,7 +730,7 @@ void Lexer::LexNumericConstant(Token &Result, const char *CurPtr) {
// 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);
@@ -664,7 +741,7 @@ void Lexer::LexNumericConstant(Token &Result, const char *CurPtr) {
/// 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.
@@ -682,7 +759,7 @@ void Lexer::LexStringLiteral(Token &Result, const char *CurPtr, bool Wide) {
}
C = getAndAdvanceChar(CurPtr, Result);
}
-
+
// If a nul character existed in the string, warn about it.
if (NulCharacter && !isLexingRawMode())
Diag(NulCharacter, diag::null_in_string);
@@ -716,11 +793,11 @@ void Lexer::LexAngledStringLiteral(Token &Result, const char *CurPtr) {
}
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);
@@ -745,7 +822,7 @@ void Lexer::LexCharConstant(Token &Result, const char *CurPtr) {
// FIXME: UCN's.
C = getAndAdvanceChar(CurPtr, Result);
}
-
+
if (C && C != '\n' && C != '\r' && CurPtr[0] == '\'') {
++CurPtr;
} else {
@@ -767,7 +844,7 @@ void Lexer::LexCharConstant(Token &Result, const char *CurPtr) {
C = getAndAdvanceChar(CurPtr, Result);
} while (C != '\'');
}
-
+
if (NulCharacter && !isLexingRawMode())
Diag(NulCharacter, diag::null_in_char);
@@ -789,17 +866,17 @@ bool Lexer::SkipWhitespace(Token &Result, const char *CurPtr) {
// 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);
@@ -818,7 +895,7 @@ bool Lexer::SkipWhitespace(Token &Result, const char *CurPtr) {
FormTokenWithChars(Result, CurPtr, tok::unknown);
return true;
}
-
+
BufferPtr = CurPtr;
return false;
}
@@ -832,12 +909,12 @@ bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) {
// 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.
@@ -847,7 +924,7 @@ bool Lexer::SkipBCPLComment(Token &Result, const char *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.
@@ -858,7 +935,7 @@ bool Lexer::SkipBCPLComment(Token &Result, const char *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,
@@ -876,7 +953,7 @@ bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) {
--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.
@@ -892,21 +969,21 @@ bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) {
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 (PP)
- PP->HandleComment(SourceRange(getSourceLocation(BufferPtr),
+ PP->HandleComment(SourceRange(getSourceLocation(BufferPtr),
getSourceLocation(CurPtr)));
-
+
// If we are returning comments as tokens, return this comment as a token.
if (inKeepCommentMode())
return SaveBCPLComment(Result, CurPtr);
@@ -917,14 +994,14 @@ bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) {
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.
@@ -939,17 +1016,17 @@ 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());
@@ -959,13 +1036,13 @@ bool Lexer::SaveBCPLComment(Token &Result, const char *CurPtr) {
/// 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,
+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.
@@ -974,7 +1051,7 @@ static bool isEndOfBlockCommentWithEscapedNewLine(const char *CurPtr,
// \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;
@@ -982,7 +1059,7 @@ static bool isEndOfBlockCommentWithEscapedNewLine(const char *CurPtr,
--CurPtr;
HasSpace = true;
}
-
+
// If we have a slash, we know this is an escaped newline.
if (*CurPtr == '\\') {
if (CurPtr[-1] != '*') return false;
@@ -991,7 +1068,7 @@ static bool isEndOfBlockCommentWithEscapedNewLine(const char *CurPtr,
if (CurPtr[0] != '/' || CurPtr[-1] != '?' || CurPtr[-2] != '?' ||
CurPtr[-3] != '*')
return false;
-
+
// This is the trigraph ending the comment. Emit a stern warning!
CurPtr -= 2;
@@ -1005,15 +1082,15 @@ static bool isEndOfBlockCommentWithEscapedNewLine(const char *CurPtr,
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;
}
@@ -1049,23 +1126,23 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) {
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.
@@ -1073,7 +1150,7 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) {
// While not aligned to a 16-byte boundary.
while (C != '/' && ((intptr_t)CurPtr & 0x0F) != 0)
C = *CurPtr++;
-
+
if (C == '/') goto FoundSlash;
#ifdef __SSE2__
@@ -1084,13 +1161,13 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) {
CurPtr += 16;
#elif __ALTIVEC__
__vector unsigned char Slashes = {
- '/', '/', '/', '/', '/', '/', '/', '/',
+ '/', '/', '/', '/', '/', '/', '/', '/',
'/', '/', '/', '/', '/', '/', '/', '/'
};
while (CurPtr+16 <= BufferEnd &&
!vec_any_eq(*(vector unsigned char*)CurPtr, Slashes))
CurPtr += 16;
-#else
+#else
// Scan for '/' quickly. Many block comments are very large.
while (CurPtr[0] != '/' &&
CurPtr[1] != '/' &&
@@ -1100,20 +1177,20 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) {
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
@@ -1135,22 +1212,22 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) {
// 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 (PP)
- PP->HandleComment(SourceRange(getSourceLocation(BufferPtr),
+
+ if (PP)
+ PP->HandleComment(SourceRange(getSourceLocation(BufferPtr),
getSourceLocation(CurPtr)));
// If we are returning comments as tokens, return this comment as a token.
@@ -1208,11 +1285,11 @@ std::string Lexer::ReadToEndOfLine() {
// 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;
}
@@ -1232,12 +1309,12 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) {
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()) {
@@ -1246,23 +1323,44 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) {
FormTokenWithChars(Result, BufferEnd, tok::eof);
return true;
}
-
- // Otherwise, issue diagnostics for unterminated #if and missing newline.
+ // Otherwise, check if we are code-completing, then issue diagnostics for
+ // unterminated #if and missing newline.
+
+ if (IsEofCodeCompletion) {
+ bool isIntendedFile = true;
+ if (PP && FileLoc.isFileID()) {
+ SourceManager &SM = PP->getSourceManager();
+ isIntendedFile = SM.isTruncatedFile(SM.getFileID(FileLoc));
+ }
+
+ if (isIntendedFile) {
+ // We're at the end of the file, but we've been asked to consider the
+ // end of the file to be a code-completion token. Return the
+ // code-completion token.
+ Result.startToken();
+ FormTokenWithChars(Result, CurPtr, tok::code_completion);
+
+ // Only do the eof -> code_completion translation once.
+ IsEofCodeCompletion = false;
+ return true;
+ }
+ }
+
// 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.
@@ -1275,27 +1373,27 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) {
/// 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);
@@ -1304,17 +1402,15 @@ unsigned Lexer::isNextPPTokenLParen() {
/// 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.
+/// has a null character at the end of the file. 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;
@@ -1323,7 +1419,7 @@ LexNextToken:
++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.
@@ -1331,17 +1427,17 @@ LexNextToken:
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?
@@ -1354,13 +1450,13 @@ LexNextToken:
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':
@@ -1369,13 +1465,13 @@ LexNextToken:
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;
}
@@ -1383,7 +1479,7 @@ LexNextToken:
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.
@@ -1398,7 +1494,7 @@ LexNextToken:
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() &&
@@ -1420,7 +1516,7 @@ LexNextToken:
// 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();
@@ -1435,7 +1531,7 @@ LexNextToken:
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':
@@ -1458,10 +1554,10 @@ LexNextToken:
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.
@@ -1527,7 +1623,7 @@ LexNextToken:
Kind = tok::amp;
}
break;
- case '*':
+ case '*':
if (getCharAndSize(CurPtr, SizeTmp) == '=') {
Kind = tok::starequal;
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
@@ -1552,7 +1648,7 @@ LexNextToken:
if (Char == '-') { // --
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::minusminus;
- } else if (Char == '>' && Features.CPlusPlus &&
+ } else if (Char == '>' && Features.CPlusPlus &&
getCharAndSize(CurPtr+SizeTmp, SizeTmp2) == '*') { // C++ ->*
CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
SizeTmp2, Result);
@@ -1593,20 +1689,20 @@ LexNextToken:
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;
@@ -1642,7 +1738,7 @@ LexNextToken:
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)) {
@@ -1655,10 +1751,10 @@ LexNextToken:
}
goto LexNextToken; // GCC isn't tail call eliminating.
}
-
+
return PP->Lex(Result);
}
-
+
Kind = tok::hash;
}
} else {
@@ -1695,7 +1791,7 @@ LexNextToken:
if (Char == '=') {
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::greaterequal;
- } else if (Char == '>' &&
+ } else if (Char == '>' &&
getCharAndSize(CurPtr+SizeTmp, SizeTmp2) == '=') {
CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
SizeTmp2, Result);
@@ -1736,7 +1832,7 @@ LexNextToken:
} else if (Features.CPlusPlus && Char == ':') {
Kind = tok::coloncolon;
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
- } else {
+ } else {
Kind = tok::colon;
}
break;
@@ -1748,7 +1844,7 @@ LexNextToken:
if (Char == '=') {
Kind = tok::equalequal;
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
- } else {
+ } else {
Kind = tok::equal;
}
break;
@@ -1773,7 +1869,7 @@ LexNextToken:
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)) {
@@ -1788,7 +1884,7 @@ LexNextToken:
}
return PP->Lex(Result);
}
-
+
Kind = tok::hash;
}
break;
@@ -1800,7 +1896,7 @@ LexNextToken:
else
Kind = tok::unknown;
break;
-
+
case '\\':
// FIXME: UCN's.
// FALL THROUGH.
@@ -1808,7 +1904,7 @@ LexNextToken:
Kind = tok::unknown;
break;
}
-
+
// Notify MIOpt that we read a non-whitespace/non-comment token.
MIOpt.ReadToken();
diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp
index 37ea52b..42dd75e 100644
--- a/lib/Lex/LiteralSupport.cpp
+++ b/lib/Lex/LiteralSupport.cpp
@@ -16,6 +16,7 @@
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/LexDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringExtras.h"
using namespace clang;
@@ -43,7 +44,7 @@ static unsigned ProcessCharEscape(const char *&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
@@ -82,7 +83,7 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf,
HadError = 1;
break;
}
-
+
// Hex escapes are a maximal series of hex digits.
bool Overflow = false;
for (; ThisTokBuf != ThisTokEnd; ++ThisTokBuf) {
@@ -95,13 +96,15 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf,
}
// See if any bits will be truncated when evaluated as a character.
- unsigned CharWidth = PP.getTargetInfo().getCharWidth(IsWide);
-
+ unsigned CharWidth = IsWide
+ ? PP.getTargetInfo().getWCharWidth()
+ : PP.getTargetInfo().getCharWidth();
+
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);
@@ -122,17 +125,19 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf,
++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);
-
+ unsigned CharWidth = IsWide
+ ? PP.getTargetInfo().getWCharWidth()
+ : PP.getTargetInfo().getCharWidth();
+
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.
@@ -146,7 +151,7 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf,
PP.Diag(Loc, diag::ext_unknown_escape) << "x"+llvm::utohexstr(ResultChar);
break;
}
-
+
return ResultChar;
}
@@ -154,16 +159,16 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf,
/// 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)
+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;
@@ -173,7 +178,7 @@ static void ProcessUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd,
return;
}
typedef uint32_t UTF32;
-
+
UTF32 UcnVal = 0;
unsigned short UcnLen = (ThisTokBuf[-1] == 'u' ? 4 : 8);
for (; ThisTokBuf != ThisTokEnd && UcnLen; ++ThisTokBuf, UcnLen--) {
@@ -189,10 +194,10 @@ static void ProcessUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd,
HadError = 1;
return;
}
- // Check UCN constraints (C99 6.4.3p2).
+ // Check UCN constraints (C99 6.4.3p2).
if ((UcnVal < 0xa0 &&
(UcnVal != 0x24 && UcnVal != 0x40 && UcnVal != 0x60 )) // $, @, `
- || (UcnVal >= 0xD800 && UcnVal <= 0xDFFF)
+ || (UcnVal >= 0xD800 && UcnVal <= 0xDFFF)
|| (UcnVal > 0x10FFFF)) /* the maximum legal UTF32 value */ {
PP.Diag(Loc, diag::err_ucn_escape_invalid);
HadError = 1;
@@ -201,7 +206,7 @@ static void ProcessUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd,
// 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.
+ // First, we determine how many bytes the result will require.
typedef uint8_t UTF8;
unsigned short bytesToWrite = 0;
@@ -213,13 +218,13 @@ static void ProcessUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd,
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] = {
+ static const UTF8 firstByteMark[5] = {
0x00, 0x00, 0xC0, 0xE0, 0xF0
};
// Finally, we write the bytes into ResultBuf.
@@ -239,13 +244,13 @@ static void ProcessUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd,
/// decimal-constant integer-suffix
/// octal-constant integer-suffix
/// hexadecimal-constant integer-suffix
-/// decimal-constant:
+/// decimal-constant:
/// nonzero-digit
/// decimal-constant digit
-/// octal-constant:
+/// octal-constant:
/// 0
/// octal-constant octal-digit
-/// hexadecimal-constant:
+/// hexadecimal-constant:
/// hexadecimal-prefix hexadecimal-digit
/// hexadecimal-constant hexadecimal-digit
/// hexadecimal-prefix: one of
@@ -267,7 +272,7 @@ static void ProcessUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd,
/// u U
/// long-suffix: one of
/// l L
-/// long-long-suffix: one of
+/// long-long-suffix: one of
/// ll LL
///
/// floating-constant: [C99 6.4.4.2]
@@ -277,14 +282,14 @@ 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;
@@ -293,8 +298,9 @@ NumericLiteralParser(const char *begin, const char *end,
isLongLong = false;
isFloat = false;
isImaginary = false;
+ isMicrosoftInteger = false;
hadError = false;
-
+
if (*s == '0') { // parse radix
ParseNumberStartingWithZero(TokLoc);
if (hadError)
@@ -313,7 +319,7 @@ NumericLiteralParser(const char *begin, const char *end,
s++;
saw_period = true;
s = SkipDigits(s);
- }
+ }
if ((*s == 'e' || *s == 'E')) { // exponent
const char *Exponent = s;
s++;
@@ -332,11 +338,11 @@ NumericLiteralParser(const char *begin, const char *end,
}
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) {
@@ -357,7 +363,7 @@ NumericLiteralParser(const char *begin, const char *end,
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.
@@ -370,31 +376,50 @@ NumericLiteralParser(const char *begin, const char *end,
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;
+ if (s + 1 != ThisTokEnd) {
+ switch (s[1]) {
+ case '8':
+ s += 2; // i8 suffix
+ isMicrosoftInteger = true;
+ continue;
+ case '1':
+ s += 2;
+ if (s == ThisTokEnd) break;
+ if (*s == '6') s++; // i16 suffix
+ else if (*s == '2') {
+ if (++s == ThisTokEnd) break;
+ if (*s == '8') s++; // i128 suffix
+ }
+ isMicrosoftInteger = true;
+ continue;
+ case '3':
+ s += 2;
+ if (s == ThisTokEnd) break;
+ if (*s == '2') s++; // i32 suffix
+ isMicrosoftInteger = true;
+ continue;
+ case '6':
+ s += 2;
+ if (s == ThisTokEnd) break;
+ if (*s == '4') s++; // i64 suffix
+ isMicrosoftInteger = true;
+ continue;
+ case 'f': // FP Suffix for "float"
+ case 'F':
+ if (!isFPConstant) break; // Error for integer constant.
+ if (isFloat || isLong) break; // FF, LF invalid.
+ isFloat = true;
+ if (isImaginary) break; // Cannot be repeated.
+ PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-begin),
+ diag::ext_imaginary_constant);
+ isImaginary = true;
+ s++;
+ continue; // Success.
+ default:
+ break;
+ }
+ break;
}
- break;
}
// fall through.
case 'I':
@@ -409,7 +434,7 @@ NumericLiteralParser(const char *begin, const char *end,
// 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),
@@ -424,12 +449,12 @@ NumericLiteralParser(const char *begin, const char *end,
/// 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
+/// 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++;
@@ -444,7 +469,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
s = SkipHexDigits(s);
}
// A binary exponent can appear with or with a '.'. If dotted, the
- // binary exponent is required.
+ // binary exponent is required.
if (*s == 'p' || *s == 'P') {
const char *Exponent = s;
s++;
@@ -458,7 +483,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
return;
}
s = first_non_digit;
-
+
if (!PP.getLangOptions().HexFloats)
PP.Diag(TokLoc, diag::ext_hexconstant_invalid);
} else if (saw_period) {
@@ -468,7 +493,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
}
return;
}
-
+
// Handle simple binary numbers 0b01010
if (*s == 'b' || *s == 'B') {
// 0b101010 is a GCC extension.
@@ -487,16 +512,16 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
// 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).
+ // 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)) {
@@ -506,7 +531,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
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') {
@@ -515,7 +540,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
hadError = true;
return;
}
-
+
if (*s == '.') {
s++;
radix = 10;
@@ -532,7 +557,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
if (first_non_digit != s) {
s = first_non_digit;
} else {
- PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, Exponent-ThisTokBegin),
+ PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, Exponent-ThisTokBegin),
diag::err_exponent_has_no_digits);
hadError = true;
return;
@@ -552,7 +577,7 @@ bool NumericLiteralParser::GetIntegerValue(llvm::APInt &Val) {
// handles the common cases that matter (small decimal integers and
// hex/octal values which don't overflow).
unsigned MaxBitsPerDigit = 1;
- while ((1U << MaxBitsPerDigit) < radix)
+ while ((1U << MaxBitsPerDigit) < radix)
MaxBitsPerDigit += 1;
if ((SuffixBegin - DigitsBegin) * MaxBitsPerDigit <= 64) {
uint64_t N = 0;
@@ -571,16 +596,16 @@ bool NumericLiteralParser::GetIntegerValue(llvm::APInt &Val) {
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;
@@ -600,21 +625,24 @@ bool NumericLiteralParser::GetIntegerValue(llvm::APInt &Val) {
llvm::APFloat NumericLiteralParser::
GetFloatValue(const llvm::fltSemantics &Format, bool* isExact) {
using llvm::APFloat;
-
+ using llvm::StringRef;
+
llvm::SmallVector<char,256> floatChars;
- for (unsigned i = 0, n = ThisTokEnd-ThisTokBegin; i != n; ++i)
+ unsigned n = std::min(SuffixBegin - ThisTokBegin, ThisTokEnd - ThisTokBegin);
+ for (unsigned i = 0; 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);
-
+
+ status = V.convertFromString(StringRef(&floatChars[0], n),
+ APFloat::rmNearestTiesToEven);
+
if (isExact)
*isExact = status == APFloat::opOK;
-
+
return V;
}
@@ -623,16 +651,16 @@ 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
+ // 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 &&
@@ -643,9 +671,9 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
assert(PP.getTargetInfo().getWCharWidth() <= 64 &&
"Assumes sizeof(wchar) on target is <= 64");
- // This is what we will use for overflow detection
+ // 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;
@@ -668,7 +696,7 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
LitVal <<= 8;
}
}
-
+
LitVal = LitVal + ResultChar;
++NumCharsSoFar;
}
@@ -684,11 +712,12 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
else
PP.Diag(Loc, diag::ext_four_char_character_literal);
IsMultiChar = true;
- }
+ } else
+ IsMultiChar = false;
// 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:
@@ -743,7 +772,7 @@ StringLiteralParser(const Token *StringToks, unsigned NumStringToks,
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
@@ -752,20 +781,20 @@ StringLiteralParser(const Token *StringToks, unsigned NumStringToks,
// 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)
+ 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;
@@ -774,25 +803,25 @@ StringLiteralParser(const Token *StringToks, unsigned NumStringToks,
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
@@ -800,23 +829,23 @@ StringLiteralParser(const Token *StringToks, unsigned NumStringToks,
// 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) {
@@ -825,7 +854,7 @@ StringLiteralParser(const Token *StringToks, unsigned NumStringToks,
} else if (Pascal)
ThisTokBuf += 2;
}
-
+
while (ThisTokBuf != ThisTokEnd) {
// Is this a span of non-escape characters?
if (ThisTokBuf[0] != '\\') {
@@ -833,7 +862,7 @@ StringLiteralParser(const Token *StringToks, unsigned NumStringToks,
do {
++ThisTokBuf;
} while (ThisTokBuf != ThisTokEnd && ThisTokBuf[0] != '\\');
-
+
// Copy the character span over.
unsigned Len = ThisTokBuf-InStart;
if (!AnyWide) {
@@ -852,7 +881,7 @@ StringLiteralParser(const Token *StringToks, unsigned NumStringToks,
}
// Is this a Universal Character Name escape?
if (ThisTokBuf[1] == 'u' || ThisTokBuf[1] == 'U') {
- ProcessUCNEscape(ThisTokBuf, ThisTokEnd, ResultPtr,
+ ProcessUCNEscape(ThisTokBuf, ThisTokEnd, ResultPtr,
hadError, StringToks[i].getLocation(), ThisIsWide, PP);
continue;
}
@@ -860,17 +889,17 @@ StringLiteralParser(const Token *StringToks, unsigned NumStringToks,
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;
@@ -895,31 +924,31 @@ unsigned StringLiteralParser::getOffsetOfStringByte(const Token &Tok,
// 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,
@@ -927,6 +956,6 @@ unsigned StringLiteralParser::getOffsetOfStringByte(const Token &Tok,
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
index cba69b7..c14d7c4 100644
--- a/lib/Lex/MacroArgs.cpp
+++ b/lib/Lex/MacroArgs.cpp
@@ -23,18 +23,18 @@ MacroArgs *MacroArgs::create(const MacroInfo *MI,
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;
}
@@ -98,7 +98,7 @@ bool MacroArgs::ArgNeedsPreexpansion(const Token *ArgTok,
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);
@@ -108,12 +108,12 @@ MacroArgs::getPreExpArgument(unsigned Arg, Preprocessor &PP) {
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*/,
+ PP.EnterTokenStream(AT, NumToks, false /*disable expand*/,
false /*owns tokens*/);
// Lex all of the macro-expanded tokens into Result.
@@ -122,7 +122,7 @@ MacroArgs::getPreExpArgument(unsigned Arg, Preprocessor &PP) {
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
@@ -145,18 +145,18 @@ Token MacroArgs::StringifyArgument(const Token *ArgToks,
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"
@@ -171,18 +171,18 @@ Token MacroArgs::StringifyArgument(const Token *ArgToks,
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() == '\\') {
@@ -199,27 +199,27 @@ Token MacroArgs::StringifyArgument(const Token *ArgToks,
}
}
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;
}
diff --git a/lib/Lex/MacroArgs.h b/lib/Lex/MacroArgs.h
index 4b22fa1..8dee5b3 100644
--- a/lib/Lex/MacroArgs.h
+++ b/lib/Lex/MacroArgs.h
@@ -20,7 +20,7 @@ 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 {
@@ -45,7 +45,7 @@ class MacroArgs {
/// 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() {}
@@ -55,46 +55,46 @@ public:
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);
-
+ 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
diff --git a/lib/Lex/MacroInfo.cpp b/lib/Lex/MacroInfo.cpp
index df89450..fda884c 100644
--- a/lib/Lex/MacroInfo.cpp
+++ b/lib/Lex/MacroInfo.cpp
@@ -22,7 +22,7 @@ MacroInfo::MacroInfo(SourceLocation DefLoc) : Location(DefLoc) {
IsBuiltinMacro = false;
IsDisabled = false;
IsUsed = true;
-
+
ArgumentList = 0;
NumArguments = 0;
}
@@ -44,32 +44,32 @@ bool MacroInfo::isIdenticalTo(const MacroInfo &Other, Preprocessor &PP) const {
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/PPCaching.cpp b/lib/Lex/PPCaching.cpp
index 53aa09c..c3f0eea 100644
--- a/lib/Lex/PPCaching.cpp
+++ b/lib/Lex/PPCaching.cpp
@@ -36,7 +36,7 @@ void Preprocessor::CommitBacktrackedTokens() {
}
/// Backtrack - Make Preprocessor re-lex the tokens that were lexed since
-/// EnableBacktrackAtThisPos() was previously called.
+/// EnableBacktrackAtThisPos() was previously called.
void Preprocessor::Backtrack() {
assert(!BacktrackPositions.empty()
&& "EnableBacktrackAtThisPos was not called!");
@@ -102,7 +102,8 @@ void Preprocessor::AnnotatePreviousCachedTokens(const Token &Tok) {
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);
+ if (i < CachedLexPos)
+ CachedTokens.erase(AnnotBegin + 1, CachedTokens.begin() + CachedLexPos);
*AnnotBegin = Tok;
CachedLexPos = i;
return;
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index af59ded..196a77f 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -26,7 +26,7 @@ using namespace clang;
MacroInfo *Preprocessor::AllocateMacroInfo(SourceLocation L) {
MacroInfo *MI;
-
+
if (!MICache.empty()) {
MI = MICache.back();
MICache.pop_back();
@@ -61,13 +61,13 @@ void Preprocessor::DiscardUntilEndOfDirective() {
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);
@@ -93,7 +93,7 @@ void Preprocessor::ReadMacroName(Token &MacroNameTok, char isDefineUndef) {
// 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);
@@ -112,12 +112,12 @@ void Preprocessor::CheckEndOfDirective(const char *DirType, bool 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
@@ -148,12 +148,12 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
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;
@@ -163,7 +163,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
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
@@ -172,26 +172,26 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
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)) {
@@ -208,14 +208,14 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
// other common directives.
const char *RawCharData = SourceMgr.getCharacterData(Tok.getLocation());
char FirstChar = RawCharData[0];
- if (FirstChar >= 'a' && FirstChar <= 'z' &&
+ 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.
@@ -240,7 +240,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
Directive[IdLen] = 0;
FirstChar = Directive[0];
}
-
+
if (FirstChar == 'i' && Directive[1] == 'f') {
if ((IdLen == 2) || // "if"
(IdLen == 5 && !strcmp(Directive+2, "def")) || // "ifdef"
@@ -260,7 +260,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
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;
@@ -270,13 +270,13 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
// 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) {
@@ -301,10 +301,10 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
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;
@@ -312,7 +312,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
}
}
}
-
+
CurPPLexer->ParsingPreprocessorDirective = false;
// Restore comment saving mode.
if (CurLexer) CurLexer->SetCommentRetentionState(KeepComments);
@@ -325,11 +325,11 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
}
void Preprocessor::PTHSkipExcludedConditionalBlock() {
-
- while(1) {
+
+ 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
@@ -340,12 +340,12 @@ void Preprocessor::PTHSkipExcludedConditionalBlock() {
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();
@@ -357,32 +357,32 @@ void Preprocessor::PTHSkipExcludedConditionalBlock() {
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.
+ // block, don't bother parsing the condition. We just skip this block.
if (CondInfo.FoundNonSkip)
continue;
@@ -417,7 +417,7 @@ const FileEntry *Preprocessor::LookupFile(const char *FilenameStart,
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
@@ -429,14 +429,14 @@ const FileEntry *Preprocessor::LookupFile(const char *FilenameStart,
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.
@@ -446,18 +446,18 @@ const FileEntry *Preprocessor::LookupFile(const char *FilenameStart,
CurFileEnt)))
return FE;
}
-
+
for (unsigned i = 0, e = IncludeMacroStack.size(); i != e; ++i) {
IncludeStackInfo &ISEntry = IncludeMacroStack[e-i-1];
if (IsFileLexer(ISEntry)) {
- if ((CurFileEnt =
+ 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;
}
@@ -468,31 +468,31 @@ const FileEntry *Preprocessor::LookupFile(const char *FilenameStart,
//===----------------------------------------------------------------------===//
/// HandleDirective - This callback is invoked when the lexer sees a # token
-/// at the start of a line. This consumes the directive, modifies the
+/// 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
+ // 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
@@ -501,7 +501,7 @@ void Preprocessor::HandleDirective(Token &Result) {
// 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:
@@ -518,7 +518,7 @@ TryAgain:
default:
IdentifierInfo *II = Result.getIdentifierInfo();
if (II == 0) break; // Not an identifier.
-
+
// Ask what the preprocessor keyword ID is.
switch (II->getPPKeywordID()) {
default: break;
@@ -535,13 +535,13 @@ TryAgain:
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);
@@ -551,21 +551,21 @@ TryAgain:
// 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);
@@ -582,15 +582,15 @@ TryAgain:
}
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]();
+ Token *Toks = new Token[2];
// Return the # and the token after it.
- Toks[0] = SavedHash;
+ 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
@@ -598,13 +598,13 @@ TryAgain:
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.
}
@@ -614,17 +614,17 @@ 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.
@@ -636,7 +636,7 @@ static bool GetLineValue(Token &DigitTok, unsigned &Val,
PP.DiscardUntilEndOfDirective();
return true;
}
-
+
unsigned NextVal = Val*10+(DigitTokBegin[i]-'0');
if (NextVal < Val) { // overflow.
PP.Diag(DigitTok, DiagID);
@@ -645,21 +645,21 @@ static bool GetLineValue(Token &DigitTok, unsigned &Val,
}
Val = NextVal;
}
-
- // Reject 0, this is needed both by #line numbers and flags.
+
+ // 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
+/// HandleLineDirective - Handle #line directive: C99 6.10.4. The two
/// acceptable forms are:
/// # line digit-sequence
/// # line digit-sequence "s-char-sequence"
@@ -679,14 +679,14 @@ void Preprocessor::HandleLineDirective(Token &Tok) {
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))
+ if (StrTok.is(tok::eom))
; // ok
else if (StrTok.isNot(tok::string_literal)) {
Diag(StrTok, diag::err_pp_line_invalid_filename);
@@ -704,14 +704,14 @@ void Preprocessor::HandleLineDirective(Token &Tok) {
}
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);
@@ -731,21 +731,21 @@ static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit,
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();
@@ -755,7 +755,7 @@ static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit,
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))
@@ -768,9 +768,9 @@ static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit,
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))
@@ -782,9 +782,9 @@ static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit,
PP.DiscardUntilEndOfDirective();
return true;
}
-
+
IsExternCHeader = true;
-
+
PP.Lex(FlagTok);
if (FlagTok.is(tok::eom)) return false;
@@ -798,7 +798,7 @@ static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit,
/// one of the following forms:
///
/// # 42
-/// # 42 "file" ('1' | '2')?
+/// # 42 "file" ('1' | '2')?
/// # 42 "file" ('1' | '2')? '3' '4'?
///
void Preprocessor::HandleDigitDirective(Token &DigitTok) {
@@ -808,17 +808,17 @@ void Preprocessor::HandleDigitDirective(Token &DigitTok) {
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))
+ if (StrTok.is(tok::eom))
; // ok
else if (StrTok.isNot(tok::string_literal)) {
Diag(StrTok, diag::err_pp_linemarker_invalid_filename);
@@ -835,18 +835,18 @@ void Preprocessor::HandleDigitDirective(Token &DigitTok) {
}
FilenameID = SourceMgr.getLineTableFilenameID(Literal.GetString(),
Literal.GetStringLength());
-
+
// If a filename was present, read any flags that are present.
- if (ReadLineMarkerFlags(IsFileEntry, IsFileExit,
+ if (ReadLineMarkerFlags(IsFileEntry, IsFileExit,
IsSystemHeader, IsExternCHeader, *this))
return;
}
-
+
// Create a line note with this information.
SourceMgr.AddLineNote(DigitTok.getLocation(), LineNo, FilenameID,
- IsFileEntry, IsFileExit,
+ 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.
@@ -861,7 +861,7 @@ void Preprocessor::HandleDigitDirective(Token &DigitTok) {
FileKind = SrcMgr::C_ExternCSystem;
else if (IsSystemHeader)
FileKind = SrcMgr::C_System;
-
+
Callbacks->FileChanged(DigitTok.getLocation(), Reason, FileKind);
}
}
@@ -869,7 +869,7 @@ void Preprocessor::HandleDigitDirective(Token &DigitTok) {
/// HandleUserDiagnosticDirective - Handle a #warning or #error directive.
///
-void Preprocessor::HandleUserDiagnosticDirective(Token &Tok,
+void Preprocessor::HandleUserDiagnosticDirective(Token &Tok,
bool isWarning) {
// PTH doesn't emit #warning or #error directives.
if (CurPTHLexer)
@@ -892,11 +892,11 @@ void Preprocessor::HandleUserDiagnosticDirective(Token &Tok,
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)) {
@@ -905,7 +905,7 @@ void Preprocessor::HandleIdentSCCSDirective(Token &Tok) {
DiscardUntilEndOfDirective();
return;
}
-
+
// Verify that there is nothing after the string, other than EOM.
CheckEndOfDirective("ident");
@@ -928,7 +928,7 @@ bool Preprocessor::GetIncludeFilenameSpelling(SourceLocation Loc,
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] == '<') {
@@ -950,14 +950,14 @@ bool Preprocessor::GetIncludeFilenameSpelling(SourceLocation Loc,
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;
@@ -977,33 +977,33 @@ bool Preprocessor::GetIncludeFilenameSpelling(SourceLocation Loc,
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);
}
@@ -1017,14 +1017,14 @@ static bool ConcatenateIncludeName(llvm::SmallVector<char, 128> &FilenameBuffer,
/// 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.
+/// 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;
@@ -1033,7 +1033,7 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok,
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());
@@ -1042,7 +1042,7 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok,
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.
@@ -1057,7 +1057,7 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok,
DiscardUntilEndOfDirective();
return;
}
-
+
bool isAngled = GetIncludeFilenameSpelling(FilenameTok.getLocation(),
FilenameStart, FilenameEnd);
// If GetIncludeFilenameSpelling set the start ptr to null, there was an
@@ -1066,7 +1066,7 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok,
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
@@ -1078,7 +1078,7 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok,
Diag(FilenameTok, diag::err_pp_include_too_deep);
return;
}
-
+
// Search include directories.
const DirectoryLookup *CurDir;
const FileEntry *File = LookupFile(FilenameStart, FilenameEnd,
@@ -1088,19 +1088,19 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok,
<< 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 =
+ 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);
@@ -1118,7 +1118,7 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok,
///
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.
@@ -1132,7 +1132,7 @@ void Preprocessor::HandleIncludeNextDirective(Token &IncludeNextTok) {
// Start looking up in the next directory.
++Lookup;
}
-
+
return HandleIncludeDirective(IncludeNextTok, Lookup);
}
@@ -1141,7 +1141,7 @@ void Preprocessor::HandleIncludeNextDirective(Token &IncludeNextTok) {
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);
}
@@ -1159,11 +1159,11 @@ void Preprocessor::HandleIncludeMacrosDirective(Token &IncludeMacrosTok) {
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);
@@ -1181,7 +1181,7 @@ void Preprocessor::HandleIncludeMacrosDirective(Token &IncludeMacrosTok) {
/// parsing the arg list.
bool Preprocessor::ReadMacroDefinitionArgList(MacroInfo *MI) {
llvm::SmallVector<IdentifierInfo*, 32> Arguments;
-
+
Token Tok;
while (1) {
LexUnexpandedToken(Tok);
@@ -1223,18 +1223,18 @@ bool Preprocessor::ReadMacroDefinitionArgList(MacroInfo *MI) {
// 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) !=
+ 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);
@@ -1247,14 +1247,14 @@ bool Preprocessor::ReadMacroDefinitionArgList(MacroInfo *MI) {
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;
@@ -1270,7 +1270,7 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
Token MacroNameTok;
ReadMacroName(MacroNameTok, 1);
-
+
// Error reading macro name? If so, diagnostic already issued.
if (MacroNameTok.is(tok::eom))
return;
@@ -1280,13 +1280,13 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
// 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.
@@ -1310,13 +1310,13 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
// 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) {
@@ -1357,7 +1357,7 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
// 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
@@ -1367,15 +1367,15 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
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) {
@@ -1389,24 +1389,24 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
} 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);
@@ -1425,14 +1425,14 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
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())) {
@@ -1452,12 +1452,12 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
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);
@@ -1470,17 +1470,17 @@ void Preprocessor::HandleUndefDirective(Token &UndefTok) {
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;
@@ -1513,7 +1513,7 @@ void Preprocessor::HandleIfdefDirective(Token &Result, bool isIfndef,
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
@@ -1522,7 +1522,7 @@ void Preprocessor::HandleIfdefDirective(Token &Result, bool isIfndef,
/*Foundnonskip*/false, /*FoundElse*/false);
return;
}
-
+
// Check to see if this is the last token on the #if[n]def line.
CheckEndOfDirective(isIfndef ? "ifndef" : "ifdef");
@@ -1541,7 +1541,7 @@ void Preprocessor::HandleIfdefDirective(Token &Result, bool isIfndef,
// 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.
@@ -1550,7 +1550,7 @@ void Preprocessor::HandleIfdefDirective(Token &Result, bool isIfndef,
} else {
// No, skip the contents of this block and return the first token after it.
SkipExcludedConditionalBlock(DirectiveTok.getLocation(),
- /*Foundnonskip*/false,
+ /*Foundnonskip*/false,
/*FoundElse*/false);
}
}
@@ -1560,11 +1560,11 @@ void Preprocessor::HandleIfdefDirective(Token &Result, bool isIfndef,
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.
@@ -1582,7 +1582,7 @@ void Preprocessor::HandleIfDirective(Token &IfToken,
/*foundnonskip*/true, /*foundelse*/false);
} else {
// No, skip the contents of this block and return the first token after it.
- SkipExcludedConditionalBlock(IfToken.getLocation(), /*Foundnonskip*/false,
+ SkipExcludedConditionalBlock(IfToken.getLocation(), /*Foundnonskip*/false,
/*FoundElse*/false);
}
}
@@ -1591,21 +1591,21 @@ void Preprocessor::HandleIfDirective(Token &IfToken,
///
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!");
}
@@ -1613,23 +1613,23 @@ void Preprocessor::HandleEndifDirective(Token &EndifToken) {
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,
@@ -1638,7 +1638,7 @@ void Preprocessor::HandleElseDirective(Token &Result) {
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).
@@ -1649,11 +1649,11 @@ void Preprocessor::HandleElifDirective(Token &ElifToken) {
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);
diff --git a/lib/Lex/PPExpressions.cpp b/lib/Lex/PPExpressions.cpp
index c98acc4..908385c 100644
--- a/lib/Lex/PPExpressions.cpp
+++ b/lib/Lex/PPExpressions.cpp
@@ -30,18 +30,18 @@ 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);
+ Range.setBegin(B); Range.setEnd(E);
}
void setBegin(SourceLocation L) { Range.setBegin(L); }
void setEnd(SourceLocation L) { Range.setEnd(L); }
@@ -82,7 +82,7 @@ struct DefinedTracker {
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.
@@ -113,13 +113,13 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
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.
@@ -145,13 +145,13 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
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);
@@ -166,11 +166,11 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
IntegerBuffer.resize(PeekTok.getLength());
const char *ThisTokBegin = &IntegerBuffer[0];
unsigned ActualLength = PP.getSpelling(PeekTok, ThisTokBegin);
- NumericLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength,
+ 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;
@@ -191,7 +191,7 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
// 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
@@ -203,7 +203,7 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
Result.Val.setIsUnsigned(true);
}
}
-
+
// Consume the token.
Result.setRange(PeekTok.getLocation());
PP.LexNonComment(PeekTok);
@@ -214,7 +214,7 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
CharBuffer.resize(PeekTok.getLength());
const char *ThisTokBegin = &CharBuffer[0];
unsigned ActualLength = PP.getSpelling(PeekTok, ThisTokBegin);
- CharLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength,
+ CharLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength,
PeekTok.getLocation(), PP);
if (Literal.hadError())
return true; // A diagnostic was already emitted.
@@ -224,8 +224,10 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
unsigned NumBits;
if (Literal.isMultiChar())
NumBits = TI.getIntWidth();
+ else if (Literal.isWide())
+ NumBits = TI.getWCharWidth();
else
- NumBits = TI.getCharWidth(Literal.isWide());
+ NumBits = TI.getCharWidth();
// Set the width.
llvm::APSInt Val(NumBits);
@@ -233,7 +235,7 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
Val = Literal.getValue();
// Set the signedness.
Val.setIsUnsigned(!PP.getLangOptions().CharIsSigned);
-
+
if (Result.Val.getBitWidth() > Val.getBitWidth()) {
Result.Val = Val.extend(Result.Val.getBitWidth());
} else {
@@ -262,7 +264,7 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
// 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();
@@ -288,21 +290,21 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
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);
@@ -314,7 +316,7 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
DT.State = DefinedTracker::Unknown;
return false;
}
-
+
case tok::exclaim: {
SourceLocation Start = PeekTok.getLocation();
PP.LexNonComment(PeekTok);
@@ -323,14 +325,14 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
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
}
}
@@ -388,17 +390,17 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
<< 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
+ // 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.
@@ -432,7 +434,7 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
<< 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
@@ -449,16 +451,16 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
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.
+ // either operand is unsigned.
llvm::APSInt Res(LHS.getBitWidth());
switch (Operator) {
case tok::question: // No UAC for x and y in "x ? y : z".
@@ -487,7 +489,7 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
LHS.Val.setIsUnsigned(Res.isUnsigned());
RHS.Val.setIsUnsigned(Res.isUnsigned());
}
-
+
// FIXME: All of these should detect and report overflow??
bool Overflow = false;
switch (Operator) {
@@ -512,7 +514,7 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
return true;
}
break;
-
+
case tok::star:
Res = LHS.Val * RHS.Val;
if (Res.isSigned() && LHS.Val != 0 && RHS.Val != 0)
@@ -529,7 +531,7 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
Overflow = ShAmt >= LHS.Val.countLeadingZeros();
else
Overflow = ShAmt >= LHS.Val.countLeadingOnes();
-
+
Res = LHS.Val << ShAmt;
break;
}
@@ -605,7 +607,7 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
PP.Diag(OpLoc, diag::ext_pp_comma_expr)
<< LHS.getRange() << RHS.getRange();
Res = RHS.Val; // LHS = LHS,RHS -> RHS.
- break;
+ break;
case tok::question: {
// Parse the : part of the expression.
if (PeekTok.isNot(tok::colon)) {
@@ -629,7 +631,7 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
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());
@@ -637,7 +639,7 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
// 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;
@@ -653,12 +655,12 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
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;
}
@@ -670,10 +672,10 @@ 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)) {
@@ -682,7 +684,7 @@ EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) {
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.
@@ -691,10 +693,10 @@ EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) {
// 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),
@@ -704,14 +706,14 @@ EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) {
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
index 2a05ba3..41ed991 100644
--- a/lib/Lex/PPLexerChange.cpp
+++ b/lib/Lex/PPLexerChange.cpp
@@ -31,7 +31,7 @@ PPCallbacks::~PPCallbacks() {}
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?");
@@ -47,7 +47,7 @@ bool Preprocessor::isInPrimaryFile() const {
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];
@@ -68,7 +68,7 @@ PreprocessorLexer *Preprocessor::getCurrentFileLexer() const {
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();
@@ -77,13 +77,13 @@ void Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir) {
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,
+void Preprocessor::EnterSourceFileWithLexer(Lexer *TheLexer,
const DirectoryLookup *CurDir) {
-
+
// Add the current lexer to the include stack.
if (CurPPLexer || CurTokenLexer)
PushIncludeMacroStack();
@@ -91,12 +91,12 @@ void Preprocessor::EnterSourceFileWithLexer(Lexer *TheLexer,
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);
}
@@ -104,9 +104,9 @@ void Preprocessor::EnterSourceFileWithLexer(Lexer *TheLexer,
/// 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,
+void Preprocessor::EnterSourceFileWithPTH(PTHLexer *PL,
const DirectoryLookup *CurDir) {
-
+
if (CurPPLexer || CurTokenLexer)
PushIncludeMacroStack();
@@ -130,7 +130,7 @@ void Preprocessor::EnterMacro(Token &Tok, SourceLocation ILEnd,
MacroArgs *Args) {
PushIncludeMacroStack();
CurDirLookup = 0;
-
+
if (NumCachedTokenLexers == 0) {
CurTokenLexer.reset(new TokenLexer(Tok, ILEnd, Args, *this));
} else {
@@ -174,18 +174,18 @@ void Preprocessor::EnterTokenStream(const Token *Toks, unsigned NumToks,
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 =
+ if (const IdentifierInfo *ControllingMacro =
CurPPLexer->MIOpt.GetControllingMacroAtEndOfFile()) {
// Okay, this has a controlling macro, remember in HeaderFileInfo.
- if (const FileEntry *FE =
+ 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()) {
@@ -197,7 +197,7 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
SrcMgr::CharacteristicKind FileType =
SourceMgr.getFileCharacteristic(CurPPLexer->getSourceLocation());
Callbacks->FileChanged(CurPPLexer->getSourceLocation(),
- PPCallbacks::ExitFile, FileType);
+ PPCallbacks::ExitFile, FileType);
}
// Client should lex another token.
@@ -210,21 +210,21 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
// actually typed, which is goodness.
if (CurLexer) {
const char *EndPos = CurLexer->BufferEnd;
- if (EndPos != CurLexer->BufferStart &&
+ if (EndPos != CurLexer->BufferStart &&
(EndPos[-1] == '\n' || EndPos[-1] == '\r')) {
--EndPos;
-
+
// Handle \n\r and \r\n:
- if (EndPos != CurLexer->BufferStart &&
+ 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 {
@@ -232,12 +232,12 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
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) !=
+ 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())
@@ -267,15 +267,15 @@ bool Preprocessor::HandleEndOfTokenLexer(Token &Result) {
/// 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();
}
@@ -285,7 +285,7 @@ void Preprocessor::RemoveTopOfLexerStack() {
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.
@@ -294,7 +294,7 @@ void Preprocessor::HandleMicrosoftCommentPaste(Token &Tok) {
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
@@ -307,12 +307,12 @@ void Preprocessor::HandleMicrosoftCommentPaste(Token &Tok) {
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:
@@ -321,22 +321,22 @@ void Preprocessor::HandleMicrosoftCommentPaste(Token &Tok) {
// 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
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index 2867051..7ddf215 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -39,7 +39,7 @@ void Preprocessor::setMacroInfo(IdentifierInfo *II, MacroInfo *MI) {
static IdentifierInfo *RegisterBuiltinMacro(Preprocessor &PP, const char *Name){
// Get the identifier.
IdentifierInfo *Id = PP.getIdentifierInfo(Name);
-
+
// Mark it as being a macro that is builtin.
MacroInfo *MI = PP.AllocateMacroInfo(SourceLocation());
MI->setIsBuiltinMacro();
@@ -57,12 +57,12 @@ void Preprocessor::RegisterBuiltinMacros() {
Ident__TIME__ = RegisterBuiltinMacro(*this, "__TIME__");
Ident__COUNTER__ = RegisterBuiltinMacro(*this, "__COUNTER__");
Ident_Pragma = RegisterBuiltinMacro(*this, "_Pragma");
-
+
// GCC Extensions.
Ident__BASE_FILE__ = RegisterBuiltinMacro(*this, "__BASE_FILE__");
Ident__INCLUDE_LEVEL__ = RegisterBuiltinMacro(*this, "__INCLUDE_LEVEL__");
Ident__TIMESTAMP__ = RegisterBuiltinMacro(*this, "__TIMESTAMP__");
-
+
// Clang Extensions.
Ident__has_feature = RegisterBuiltinMacro(*this, "__has_feature");
Ident__has_builtin = RegisterBuiltinMacro(*this, "__has_builtin");
@@ -77,14 +77,14 @@ static bool isTrivialSingleTokenExpansion(const MacroInfo *MI,
// 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;
@@ -95,7 +95,7 @@ static bool isTrivialSingleTokenExpansion(const MacroInfo *MI,
I != E; ++I)
if (*I == II)
return false; // Identifier is a macro argument.
-
+
return true;
}
@@ -112,7 +112,7 @@ bool Preprocessor::isNextPPTokenLParen() {
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
@@ -127,10 +127,10 @@ bool Preprocessor::isNextPPTokenLParen() {
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;
@@ -145,72 +145,72 @@ bool Preprocessor::isNextPPTokenLParen() {
/// HandleMacroExpandedIdentifier - If an identifier token is read that is to be
/// expanded as a macro, handle it and return the next token as 'Identifier'.
-bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
+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
@@ -221,12 +221,12 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
}
++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
+ // token: expand it now. This handles common cases like
// "#define VAL 42".
// No need for arg info.
@@ -236,38 +236,38 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
// 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);
@@ -284,7 +284,7 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
// 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;
@@ -292,7 +292,7 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
// 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.
@@ -302,19 +302,19 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
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.
@@ -331,7 +331,7 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
} 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.
+ // variadic part, then the comma is just an argument token.
if (!isVariadic) break;
if (NumFixedArgsLeft > 1)
break;
@@ -344,7 +344,7 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
// 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
+ // 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())
@@ -352,7 +352,7 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
}
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)
@@ -363,18 +363,18 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
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();
@@ -386,19 +386,19 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
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).
@@ -413,9 +413,9 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
// 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__)
+ // #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 {
@@ -423,7 +423,7 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
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();
@@ -435,14 +435,14 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
// 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);
}
@@ -454,15 +454,15 @@ 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,
+ 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);
@@ -478,12 +478,15 @@ static void ComputeDATE_TIME(SourceLocation &DATELoc, SourceLocation &TIMELoc,
/// specified by the identifier.
static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
const LangOptions &LangOpts = PP.getLangOptions();
-
+
switch (II->getLength()) {
default: return false;
case 6:
if (II->isStr("blocks")) return LangOpts.Blocks;
return false;
+ case 19:
+ if (II->isStr("objc_nonfragile_abi")) return LangOpts.ObjCNonFragileABI;
+ return false;
case 22:
if (II->isStr("attribute_overloadable")) return true;
return false;
@@ -507,12 +510,12 @@ 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];
@@ -520,17 +523,17 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
// 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__.
@@ -538,7 +541,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
// 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);
@@ -558,7 +561,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
NextLoc = PLoc.getIncludeLoc();
}
}
-
+
// Escape this filename. Turn '\' -> '\\' '"' -> '\"'
std::string FN = PLoc.getFilename();
FN = '"' + Lexer::Stringify(FN) + '"';
@@ -586,12 +589,12 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
// 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);
@@ -605,10 +608,10 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
// 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) {
@@ -619,14 +622,14 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
Result = "??? ??? ?? ??:??:?? ????\n";
}
TmpBuffer[0] = '"';
- strcpy(TmpBuffer+1, Result);
- unsigned Len = strlen(TmpBuffer);
- TmpBuffer[Len] = '"'; // Replace the newline with a quote.
+ unsigned Len = strlen(Result);
+ memcpy(TmpBuffer+1, Result, Len-1); // Copy string without the newline.
+ TmpBuffer[Len] = '"';
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);
@@ -635,10 +638,10 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
II == Ident__has_builtin) {
// The argument to these two builtins should be a parenthesized identifier.
SourceLocation StartLoc = Tok.getLocation();
-
+
bool IsValid = false;
IdentifierInfo *FeatureII = 0;
-
+
// Read the '('.
Lex(Tok);
if (Tok.is(tok::l_paren)) {
@@ -646,25 +649,25 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
Lex(Tok);
if (Tok.is(tok::identifier)) {
FeatureII = Tok.getIdentifierInfo();
-
+
// Read the ')'.
Lex(Tok);
if (Tok.is(tok::r_paren))
IsValid = true;
}
}
-
+
bool Value = false;
if (!IsValid)
Diag(StartLoc, diag::err_feature_check_malformed);
else if (II == Ident__has_builtin) {
- // Check for a builtin is trivial.
+ // Check for a builtin is trivial.
Value = FeatureII->getBuiltinID() != 0;
} else {
assert(II == Ident__has_feature && "Must be feature check");
Value = HasFeature(*this, FeatureII);
}
-
+
sprintf(TmpBuffer, "%d", (int)Value);
Tok.setKind(tok::numeric_constant);
CreateString(TmpBuffer, strlen(TmpBuffer), Tok, Tok.getLocation());
diff --git a/lib/Lex/PTHLexer.cpp b/lib/Lex/PTHLexer.cpp
index 916bdef..36ace8b 100644
--- a/lib/Lex/PTHLexer.cpp
+++ b/lib/Lex/PTHLexer.cpp
@@ -37,7 +37,7 @@ 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);
}
@@ -47,25 +47,25 @@ LexNextToken:
//===--------------------------------------==//
// Read the raw token data.
//===--------------------------------------==//
-
+
// Shadow CurPtr into an automatic variable.
- const unsigned char *CurPtrShadow = CurPtr;
+ 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);
@@ -80,57 +80,57 @@ LexNextToken:
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
+#if 0
SourceManager& SM = PP->getSourceManager();
- llvm::cerr << SM.getFileEntryForID(FileID)->getName()
+ llvm::errs() << SM.getFileEntryForID(FileID)->getName()
<< ':' << SM.getLogicalLineNumber(Tok.getLocation())
<< ':' << SM.getLogicalColumnNumber(Tok.getLocation())
<< '\n';
-#endif
+#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;
@@ -154,7 +154,7 @@ void PTHLexer::DiscardToEndOfLine() {
// 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.
@@ -163,7 +163,7 @@ void PTHLexer::DiscardToEndOfLine() {
// 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;
@@ -171,7 +171,7 @@ void PTHLexer::DiscardToEndOfLine() {
// Skip to the next token.
p += DISK_TOKEN_SIZE;
}
-
+
CurPtr = p;
}
@@ -179,18 +179,18 @@ void PTHLexer::DiscardToEndOfLine() {
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 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.
+
+ // 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;
@@ -208,7 +208,7 @@ bool PTHLexer::SkipBlock() {
// 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;
@@ -218,23 +218,23 @@ bool PTHLexer::SkipBlock() {
}
}
}
- while (HashEntryI < LastHashTokPtr);
+ 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 ...
@@ -243,7 +243,7 @@ bool PTHLexer::SkipBlock() {
//
// 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.
@@ -251,13 +251,13 @@ bool PTHLexer::SkipBlock() {
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;
@@ -265,7 +265,7 @@ bool PTHLexer::SkipBlock() {
// 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; }
@@ -297,12 +297,12 @@ class VISIBILITY_HIDDEN PTHFileData {
public:
PTHFileData(uint32_t tokenOff, uint32_t ppCondOff)
: TokenOff(tokenOff), PPCondOff(ppCondOff) {}
-
- uint32_t getTokenOffset() const { return TokenOff; }
- uint32_t getPPCondOffset() const { return 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;
@@ -310,84 +310,84 @@ public:
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) {
+ }
+
+ 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);
+ return PTHFileData(x, y);
}
};
class VISIBILITY_HIDDEN PTHStringLookupTrait {
public:
- typedef uint32_t
+ 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
+
+} // end anonymous namespace
typedef OnDiskChainedHashTable<PTHFileLookupTrait> PTHFileLookup;
typedef OnDiskChainedHashTable<PTHStringLookupTrait> PTHStringIdLookup;
@@ -398,7 +398,7 @@ typedef OnDiskChainedHashTable<PTHStringLookupTrait> PTHStringIdLookup;
PTHManager::PTHManager(const llvm::MemoryBuffer* buf, void* fileLookup,
const unsigned char* idDataTable,
- IdentifierInfo** perIDCache,
+ IdentifierInfo** perIDCache,
void* stringIdLookup, unsigned numIds,
const unsigned char* spellingBase,
const char* originalSourceFile)
@@ -416,7 +416,7 @@ PTHManager::~PTHManager() {
static void InvalidPTH(Diagnostic *Diags, Diagnostic::Level level,
const char* Msg = 0) {
- if (!Diags) return;
+ if (!Diags) return;
if (!Msg) Msg = "Invalid or corrupted PTH file";
unsigned DiagID = Diags->getCustomDiagID(level, Msg);
Diags->Report(FullSourceLoc(), DiagID);
@@ -427,7 +427,7 @@ PTHManager* PTHManager::Create(const std::string& file, Diagnostic* Diags,
// 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,
@@ -437,7 +437,7 @@ PTHManager* PTHManager::Create(const std::string& file, Diagnostic* Diags,
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();
@@ -449,54 +449,54 @@ PTHManager* PTHManager::Create(const std::string& file, Diagnostic* Diags,
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
+ 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.
+ // 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;
@@ -508,7 +508,7 @@ PTHManager* PTHManager::Create(const std::string& file, Diagnostic* Diags,
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);
@@ -516,19 +516,19 @@ PTHManager* PTHManager::Create(const std::string& file, Diagnostic* Diags,
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));
+ PerIDCache = (IdentifierInfo**)calloc(NumIds, sizeof(*PerIDCache));
if (!PerIDCache) {
- InvalidPTH(Diags, level,
+ InvalidPTH(Diags, level,
"Could not allocate memory for processing PTH file");
return 0;
}
@@ -537,8 +537,8 @@ PTHManager* PTHManager::Create(const std::string& file, Diagnostic* Diags,
// 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;
-
+ if (!len) originalSourceBase = 0;
+
// Create the new PTHManager.
return new PTHManager(File.take(), FL.take(), IData, PerIDCache,
SL.take(), NumIds, spellingBase,
@@ -551,7 +551,7 @@ IdentifierInfo* PTHManager::LazilyCreateIdentifierInfo(unsigned 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*> >();
@@ -559,7 +559,7 @@ IdentifierInfo* PTHManager::LazilyCreateIdentifierInfo(unsigned PersistentID) {
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');
@@ -584,18 +584,18 @@ 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 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();
@@ -604,9 +604,9 @@ PTHLexer *PTHManager::CreateLexer(FileID FID) {
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);
+ return new PTHLexer(*PP, FID, data, ppcond, *this);
}
//===----------------------------------------------------------------------===//
@@ -622,19 +622,19 @@ public:
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) {}
-
+ : 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);
@@ -644,17 +644,17 @@ public:
// 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) {
-
+ 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);
+ time_t mtime = (time_t) ReadUnalignedLE64(d);
return data_type(ino, dev, mode, mtime, (off_t) ReadUnalignedLE64(d));
}
@@ -667,22 +667,22 @@ class VISIBILITY_HIDDEN PTHStatCache : public StatSysCallCache {
typedef OnDiskChainedHashTable<PTHStatLookupTrait> CacheTy;
CacheTy Cache;
-public:
+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;
diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp
index bb0b71e..8b46f71 100644
--- a/lib/Lex/Pragma.cpp
+++ b/lib/Lex/Pragma.cpp
@@ -44,9 +44,9 @@ 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)
+ if (Handlers[i]->getName() == Name)
return Handlers[i];
-
+
if (Handlers[i]->getName() == 0)
NullHandler = Handlers[i];
}
@@ -68,14 +68,14 @@ 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);
}
@@ -88,11 +88,11 @@ void PragmaNamespace::HandlePragma(Preprocessor &PP, Token &Tok) {
/// 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 && CurPPLexer->ParsingPreprocessorDirective)
DiscardUntilEndOfDirective();
@@ -104,7 +104,7 @@ void Preprocessor::HandlePragmaDirective() {
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)) {
@@ -118,7 +118,7 @@ void Preprocessor::Handle_Pragma(Token &Tok) {
Diag(PragmaLoc, diag::err__Pragma_malformed);
return;
}
-
+
// Remember the string.
std::string StrVal = getSpelling(Tok);
@@ -128,9 +128,9 @@ void Preprocessor::Handle_Pragma(Token &Tok) {
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
@@ -140,14 +140,14 @@ void Preprocessor::Handle_Pragma(Token &Tok) {
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] == '\\' &&
@@ -157,7 +157,7 @@ void Preprocessor::Handle_Pragma(Token &Tok) {
--e;
}
}
-
+
// Plop the string (including the newline and trailing null) into a buffer
// where we can lex it.
Token TmpTok;
@@ -174,7 +174,7 @@ void Preprocessor::Handle_Pragma(Token &Tok) {
// With everything set up, lex this as a #pragma directive.
HandlePragmaDirective();
-
+
// Finally, return whatever came after the pragma directive.
return Lex(Tok);
}
@@ -188,7 +188,7 @@ void Preprocessor::HandlePragmaOnce(Token &OnceTok) {
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());
@@ -217,27 +217,27 @@ void Preprocessor::HandlePragmaPoison(Token &PoisonTok) {
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();
}
@@ -250,25 +250,25 @@ void Preprocessor::HandlePragmaSystemHeader(Token &SysHeaderTok) {
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());
-
-
+
+
PresumedLoc PLoc = SourceMgr.getPresumedLoc(SysHeaderTok.getLocation());
unsigned FilenameLen = strlen(PLoc.getFilename());
unsigned FilenameID = SourceMgr.getLineTableFilenameID(PLoc.getFilename(),
FilenameLen);
-
+
// Emit a line marker. This will change any source locations from this point
// forward to realize they are in a system header.
// Create a line note with this information.
SourceMgr.AddLineNote(SysHeaderTok.getLocation(), PLoc.getLine(), FilenameID,
false, false, true, false);
-
+
// Notify the client, if desired, that we are in a new source file.
if (Callbacks)
Callbacks->FileChanged(SysHeaderTok.getLocation(),
@@ -284,11 +284,11 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) {
// 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;
@@ -298,7 +298,7 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) {
// error.
if (FilenameStart == 0)
return;
-
+
// Search include directories for this file.
const DirectoryLookup *CurDir;
const FileEntry *File = LookupFile(FilenameStart, FilenameEnd,
@@ -308,7 +308,7 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) {
<< std::string(FilenameStart, FilenameEnd);
return;
}
-
+
const FileEntry *CurFile = getCurrentFileLexer()->getFileEntry();
// If this file is older than the file it depends on, emit a diagnostic.
@@ -320,7 +320,7 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) {
Message += getSpelling(DependencyTok) + " ";
Lex(DependencyTok);
}
-
+
Message.erase(Message.end()-1);
Diag(FilenameTok, diag::pp_out_of_date_dependency) << Message;
}
@@ -339,23 +339,23 @@ void Preprocessor::HandlePragmaComment(Token &Tok) {
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") &&
+ 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;
@@ -390,13 +390,13 @@ void Preprocessor::HandlePragmaComment(Token &Tok) {
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;
@@ -407,7 +407,7 @@ void Preprocessor::HandlePragmaComment(Token &Tok) {
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);
@@ -419,14 +419,14 @@ void Preprocessor::HandlePragmaComment(Token &Tok) {
/// 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,
+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.
@@ -441,7 +441,7 @@ void Preprocessor::AddPragmaHandler(const char *Namespace,
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!");
@@ -455,7 +455,7 @@ void Preprocessor::AddPragmaHandler(const char *Namespace,
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);
@@ -467,7 +467,7 @@ void Preprocessor::RemovePragmaHandler(const char *Namespace,
}
NS->RemovePragmaHandler(Handler);
-
+
// If this is a non-default namespace and it is now empty, remove
// it.
if (NS != PragmaHandlers && NS->IsEmpty())
@@ -516,19 +516,29 @@ struct PragmaDependencyHandler : public PragmaHandler {
PP.HandlePragmaDependency(DepToken);
}
};
-
+
/// PragmaDiagnosticHandler - e.g. '#pragma GCC diagnostic ignored "-Wformat"'
+/// Since clang's diagnostic supports extended functionality beyond GCC's
+/// the constructor takes a clangMode flag to tell it whether or not to allow
+/// clang's extended functionality, or whether to reject it.
struct PragmaDiagnosticHandler : public PragmaHandler {
- PragmaDiagnosticHandler(const IdentifierInfo *ID) : PragmaHandler(ID) {}
+private:
+ const bool ClangMode;
+public:
+ PragmaDiagnosticHandler(const IdentifierInfo *ID,
+ const bool clangMode) : PragmaHandler(ID),
+ ClangMode(clangMode) {}
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);
+ unsigned Diag = ClangMode ? diag::warn_pragma_diagnostic_clang_invalid
+ : diag::warn_pragma_diagnostic_gcc_invalid;
+ PP.Diag(Tok, Diag);
return;
}
IdentifierInfo *II = Tok.getIdentifierInfo();
-
+
diag::Mapping Map;
if (II->isStr("warning"))
Map = diag::MAP_WARNING;
@@ -538,11 +548,25 @@ struct PragmaDiagnosticHandler : public PragmaHandler {
Map = diag::MAP_IGNORE;
else if (II->isStr("fatal"))
Map = diag::MAP_FATAL;
- else {
- PP.Diag(Tok, diag::warn_pragma_diagnostic_invalid);
+ else if (ClangMode) {
+ if (II->isStr("pop")) {
+ if (!PP.getDiagnostics().popMappings())
+ PP.Diag(Tok, diag::warn_pragma_diagnostic_clang_cannot_ppp);
+ return;
+ }
+
+ if (II->isStr("push")) {
+ PP.getDiagnostics().pushMappings();
+ return;
+ }
+
+ PP.Diag(Tok, diag::warn_pragma_diagnostic_clang_invalid);
+ return;
+ } else {
+ PP.Diag(Tok, diag::warn_pragma_diagnostic_gcc_invalid);
return;
}
-
+
PP.LexUnexpandedToken(Tok);
// We need at least one string.
@@ -550,7 +574,7 @@ struct PragmaDiagnosticHandler : public PragmaHandler {
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"
@@ -559,22 +583,24 @@ struct PragmaDiagnosticHandler : public PragmaHandler {
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);
+ unsigned Diag = ClangMode ? diag::warn_pragma_diagnostic_clang_invalid
+ : diag::warn_pragma_diagnostic_gcc_invalid;
+ PP.Diag(Tok, Diag);
return;
}
-
+
std::string WarningName(Literal.GetString(),
Literal.GetString()+Literal.GetStringLength());
@@ -584,14 +610,14 @@ struct PragmaDiagnosticHandler : public PragmaHandler {
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) {}
@@ -599,13 +625,13 @@ struct PragmaCommentHandler : public PragmaHandler {
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);
@@ -633,7 +659,7 @@ static STDCSetting LexOnOffSwitch(Preprocessor &PP) {
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) {}
@@ -645,7 +671,7 @@ struct PragmaSTDC_FP_CONTRACTHandler : public PragmaHandler {
LexOnOffSwitch(PP);
}
};
-
+
/// PragmaSTDC_FENV_ACCESSHandler - "#pragma STDC FENV_ACCESS ...".
struct PragmaSTDC_FENV_ACCESSHandler : public PragmaHandler {
PragmaSTDC_FENV_ACCESSHandler(const IdentifierInfo *ID) : PragmaHandler(ID) {}
@@ -654,7 +680,7 @@ struct PragmaSTDC_FENV_ACCESSHandler : public PragmaHandler {
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)
@@ -663,7 +689,7 @@ struct PragmaSTDC_CX_LIMITED_RANGEHandler : public PragmaHandler {
LexOnOffSwitch(PP);
}
};
-
+
/// PragmaSTDC_UnknownHandler - "#pragma STDC ...".
struct PragmaSTDC_UnknownHandler : public PragmaHandler {
PragmaSTDC_UnknownHandler() : PragmaHandler(0) {}
@@ -672,7 +698,7 @@ struct PragmaSTDC_UnknownHandler : public PragmaHandler {
PP.Diag(UnknownTok, diag::ext_stdc_pragma_ignored);
}
};
-
+
} // end anonymous namespace
@@ -681,7 +707,7 @@ struct PragmaSTDC_UnknownHandler : public PragmaHandler {
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(
@@ -689,7 +715,8 @@ void Preprocessor::RegisterBuiltinPragmas() {
AddPragmaHandler("GCC", new PragmaDependencyHandler(
getIdentifierInfo("dependency")));
AddPragmaHandler("GCC", new PragmaDiagnosticHandler(
- getIdentifierInfo("diagnostic")));
+ getIdentifierInfo("diagnostic"),
+ false));
// #pragma clang ...
AddPragmaHandler("clang", new PragmaPoisonHandler(
getIdentifierInfo("poison")));
@@ -698,7 +725,8 @@ void Preprocessor::RegisterBuiltinPragmas() {
AddPragmaHandler("clang", new PragmaDependencyHandler(
getIdentifierInfo("dependency")));
AddPragmaHandler("clang", new PragmaDiagnosticHandler(
- getIdentifierInfo("diagnostic")));
+ getIdentifierInfo("diagnostic"),
+ true));
AddPragmaHandler("STDC", new PragmaSTDC_FP_CONTRACTHandler(
getIdentifierInfo("FP_CONTRACT")));
@@ -707,7 +735,7 @@ void Preprocessor::RegisterBuiltinPragmas() {
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
index 9f0c15f..bfa090a 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -37,7 +37,7 @@
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/Streams.h"
+#include "llvm/Support/raw_ostream.h"
#include <cstdio>
using namespace clang;
@@ -46,7 +46,7 @@ using namespace clang;
PreprocessorFactory::~PreprocessorFactory() {}
Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts,
- TargetInfo &target, SourceManager &SM,
+ TargetInfo &target, SourceManager &SM,
HeaderSearch &Headers,
IdentifierInfoLookup* IILookup)
: Diags(&diags), Features(opts), Target(target),FileMgr(Headers.getFileMgr()),
@@ -54,20 +54,20 @@ Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts,
BuiltinInfo(Target), 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;
+ MaxIncludeStackDepth = 0;
NumSkipped = 0;
// Default to discarding comments.
KeepComments = false;
KeepMacroComments = false;
-
+
// Macro expansion is enabled.
DisableMacroExpansion = false;
InMacroArgs = false;
@@ -78,11 +78,11 @@ Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts,
// "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();
}
@@ -106,11 +106,11 @@ Preprocessor::~Preprocessor() {
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;
@@ -126,27 +126,27 @@ void Preprocessor::setPTHManager(PTHManager* pm) {
}
void Preprocessor::DumpToken(const Token &Tok, bool DumpFlags) const {
- llvm::cerr << tok::getTokenName(Tok.getKind()) << " '"
- << getSpelling(Tok) << "'";
-
+ llvm::errs() << tok::getTokenName(Tok.getKind()) << " '"
+ << getSpelling(Tok) << "'";
+
if (!DumpFlags) return;
-
- llvm::cerr << "\t";
+
+ llvm::errs() << "\t";
if (Tok.isAtStartOfLine())
- llvm::cerr << " [StartOfLine]";
+ llvm::errs() << " [StartOfLine]";
if (Tok.hasLeadingSpace())
- llvm::cerr << " [LeadingSpace]";
+ llvm::errs() << " [LeadingSpace]";
if (Tok.isExpandDisabled())
- llvm::cerr << " [ExpandDisabled]";
+ llvm::errs() << " [ExpandDisabled]";
if (Tok.needsCleaning()) {
const char *Start = SourceMgr.getCharacterData(Tok.getLocation());
- llvm::cerr << " [UnClean='" << std::string(Start, Start+Tok.getLength())
- << "']";
+ llvm::errs() << " [UnClean='" << std::string(Start, Start+Tok.getLength())
+ << "']";
}
-
- llvm::cerr << "\tLoc=<";
+
+ llvm::errs() << "\tLoc=<";
DumpLocation(Tok.getLocation());
- llvm::cerr << ">";
+ llvm::errs() << ">";
}
void Preprocessor::DumpLocation(SourceLocation Loc) const {
@@ -154,32 +154,32 @@ void Preprocessor::DumpLocation(SourceLocation Loc) const {
}
void Preprocessor::DumpMacro(const MacroInfo &MI) const {
- llvm::cerr << "MACRO: ";
+ llvm::errs() << "MACRO: ";
for (unsigned i = 0, e = MI.getNumTokens(); i != e; ++i) {
DumpToken(MI.getReplacementToken(i));
- llvm::cerr << " ";
+ llvm::errs() << " ";
}
- llvm::cerr << "\n";
+ llvm::errs() << "\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 << "/"
+ llvm::errs() << "\n*** Preprocessor Stats:\n";
+ llvm::errs() << NumDirectives << " directives found:\n";
+ llvm::errs() << " " << NumDefined << " #define.\n";
+ llvm::errs() << " " << NumUndefined << " #undef.\n";
+ llvm::errs() << " #include/#include_next/#import:\n";
+ llvm::errs() << " " << NumEnteredSourceFiles << " source files entered.\n";
+ llvm::errs() << " " << MaxIncludeStackDepth << " max include stack depth\n";
+ llvm::errs() << " " << NumIf << " #if/#ifndef/#ifdef.\n";
+ llvm::errs() << " " << NumElse << " #else/#elif.\n";
+ llvm::errs() << " " << NumEndif << " #endif.\n";
+ llvm::errs() << " " << NumPragma << " #pragma.\n";
+ llvm::errs() << NumSkipped << " #if/#ifndef#ifdef regions skipped\n";
+
+ llvm::errs() << NumMacroExpanded << "/" << NumFnMacroExpanded << "/"
<< NumBuiltinMacroExpanded << " obj/fn/builtin macros expanded, "
<< NumFastMacroExpanded << " on the fast path.\n";
- llvm::cerr << (NumFastTokenPaste+NumTokenPaste)
+ llvm::errs() << (NumFastTokenPaste+NumTokenPaste)
<< " token paste (##) operations performed, "
<< NumFastTokenPaste << " on the fast path.\n";
}
@@ -201,10 +201,10 @@ std::string Preprocessor::getSpelling(const Token &Tok) const {
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; ) {
@@ -230,7 +230,7 @@ std::string Preprocessor::getSpelling(const Token &Tok) const {
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()) {
@@ -240,10 +240,10 @@ unsigned Preprocessor::getSpelling(const Token &Tok,
// 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());
@@ -252,7 +252,7 @@ unsigned Preprocessor::getSpelling(const Token &Tok,
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();
@@ -263,7 +263,7 @@ unsigned Preprocessor::getSpelling(const Token &Tok,
}
assert(unsigned(OutBuf-Buffer) != Tok.getLength() &&
"NeedsCleaning flag set on something that didn't need cleaning!");
-
+
return OutBuf-Buffer;
}
@@ -273,15 +273,15 @@ unsigned Preprocessor::getSpelling(const Token &Tok,
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);
@@ -290,19 +290,19 @@ void Preprocessor::CreateString(const char *Buf, unsigned Len, Token &Tok,
/// 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,
+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.
@@ -311,7 +311,7 @@ SourceLocation Preprocessor::AdvanceToTokenCharacter(SourceLocation TokStart,
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) {
@@ -320,14 +320,14 @@ SourceLocation Preprocessor::AdvanceToTokenCharacter(SourceLocation TokStart,
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);
}
@@ -364,33 +364,33 @@ void Preprocessor::EnterMainSourceFile() {
// 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 *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);
}
@@ -406,7 +406,7 @@ 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()) {
@@ -436,7 +436,7 @@ IdentifierInfo *Preprocessor::LookUpIdentifierInfo(Token &Identifier,
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
@@ -447,7 +447,7 @@ void Preprocessor::HandleIdentifier(Token &Identifier) {
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()) {
diff --git a/lib/Lex/PreprocessorLexer.cpp b/lib/Lex/PreprocessorLexer.cpp
index f9dfad9..e005c49 100644
--- a/lib/Lex/PreprocessorLexer.cpp
+++ b/lib/Lex/PreprocessorLexer.cpp
@@ -26,13 +26,13 @@ void PreprocessorLexer::LexIncludeFilename(Token &FilenameTok) {
// 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);
diff --git a/lib/Lex/ScratchBuffer.cpp b/lib/Lex/ScratchBuffer.cpp
index 28f3d7f..0e98c17 100644
--- a/lib/Lex/ScratchBuffer.cpp
+++ b/lib/Lex/ScratchBuffer.cpp
@@ -38,16 +38,16 @@ SourceLocation ScratchBuffer::getToken(const char *Buf, unsigned Len,
// 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.
@@ -62,8 +62,8 @@ void ScratchBuffer::AllocScratchBuffer(unsigned RequestLen) {
// support gigantic tokens, which almost certainly won't happen. :)
if (RequestLen < ScratchBufSize)
RequestLen = ScratchBufSize;
-
- llvm::MemoryBuffer *Buf =
+
+ llvm::MemoryBuffer *Buf =
llvm::MemoryBuffer::getNewMemBuffer(RequestLen, "<scratch space>");
FileID FID = SourceMgr.createFileIDForMemBuffer(Buf);
BufferStartLoc = SourceMgr.getLocForStartOfFile(FID);
diff --git a/lib/Lex/TokenConcatenation.cpp b/lib/Lex/TokenConcatenation.cpp
index be13b27..ade7f85 100644
--- a/lib/Lex/TokenConcatenation.cpp
+++ b/lib/Lex/TokenConcatenation.cpp
@@ -13,7 +13,7 @@
#include "clang/Lex/TokenConcatenation.h"
#include "clang/Lex/Preprocessor.h"
-using namespace clang;
+using namespace clang;
/// StartsWithL - Return true if the spelling of this token starts with 'L'.
@@ -22,14 +22,14 @@ bool TokenConcatenation::StartsWithL(const Token &Tok) const {
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';
}
@@ -42,21 +42,21 @@ bool TokenConcatenation::IsIdentifierL(const Token &Tok) const {
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)
+ 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;
@@ -72,7 +72,7 @@ TokenConcatenation::TokenConcatenation(Preprocessor &pp) : PP(pp) {
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; // +=
@@ -130,29 +130,29 @@ bool TokenConcatenation::AvoidConcat(const Token &PrevTok,
// source. If they were, it must be okay to stick them together: if there
// were an issue, the tokens would have been lexed differently.
if (PrevTok.getLocation().isFileID() && Tok.getLocation().isFileID() &&
- PrevTok.getLocation().getFileLocWithOffset(PrevTok.getLength()) ==
+ PrevTok.getLocation().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.
@@ -162,10 +162,10 @@ bool TokenConcatenation::AvoidConcat(const Token &PrevTok,
} 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".
+ 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) != '.';
@@ -173,18 +173,18 @@ bool TokenConcatenation::AvoidConcat(const Token &PrevTok,
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);
diff --git a/lib/Lex/TokenLexer.cpp b/lib/Lex/TokenLexer.cpp
index f9f9386..f006f5a 100644
--- a/lib/Lex/TokenLexer.cpp
+++ b/lib/Lex/TokenLexer.cpp
@@ -27,11 +27,11 @@ 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();
@@ -45,7 +45,7 @@ void TokenLexer::Init(Token &Tok, SourceLocation ILEnd, MacroArgs *Actuals) {
// 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.
@@ -61,7 +61,7 @@ void TokenLexer::Init(const Token *TokArray, unsigned NumToks,
// If the client is reusing a TokenLexer, make sure to free any memory
// associated with it.
destroy();
-
+
Macro = 0;
ActualArgs = 0;
Tokens = TokArray;
@@ -72,7 +72,7 @@ void TokenLexer::Init(const Token *TokArray, unsigned NumToks,
InstantiateLocStart = InstantiateLocEnd = SourceLocation();
AtStartOfLine = false;
HasLeadingSpace = false;
-
+
// Set HasLeadingSpace/AtStartOfLine so that the first token will be
// returned unmodified.
if (NumToks != 0) {
@@ -90,7 +90,7 @@ void TokenLexer::destroy() {
Tokens = 0;
OwnsTokens = false;
}
-
+
// TokenLexer owns its formal arguments.
if (ActualArgs) ActualArgs->destroy();
}
@@ -99,17 +99,17 @@ void TokenLexer::destroy() {
/// 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
@@ -118,7 +118,7 @@ void TokenLexer::ExpandFunctionArguments() {
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);
@@ -127,19 +127,19 @@ void TokenLexer::ExpandFunctionArguments() {
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();
@@ -154,17 +154,17 @@ void TokenLexer::ExpandFunctionArguments() {
}
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 =
+ 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.
@@ -178,13 +178,13 @@ void TokenLexer::ExpandFunctionArguments() {
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.
@@ -199,7 +199,7 @@ void TokenLexer::ExpandFunctionArguments() {
}
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);
@@ -217,9 +217,9 @@ void TokenLexer::ExpandFunctionArguments() {
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.
@@ -233,11 +233,11 @@ void TokenLexer::ExpandFunctionArguments() {
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
@@ -250,13 +250,13 @@ void TokenLexer::ExpandFunctionArguments() {
++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.
@@ -271,7 +271,7 @@ void TokenLexer::ExpandFunctionArguments() {
}
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");
@@ -284,7 +284,7 @@ void TokenLexer::ExpandFunctionArguments() {
if (NumTokens)
memcpy(Res, &ResultToks[0], NumTokens*sizeof(Token));
Tokens = Res;
-
+
// The preprocessor bump pointer owns these tokens, not us.
OwnsTokens = false;
}
@@ -309,16 +309,16 @@ void TokenLexer::Lex(Token &Tok) {
// 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)) {
@@ -328,7 +328,7 @@ void TokenLexer::Lex(Token &Tok) {
} 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
@@ -337,26 +337,26 @@ void TokenLexer::Lex(Token &Tok) {
// 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(),
+ 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.
@@ -367,7 +367,7 @@ void TokenLexer::Lex(Token &Tok) {
else
PP.Diag(Tok, diag::err_pp_used_poisoned_id);
}
-
+
if (!DisableMacroExpansion && II->isHandleIdentifierCase())
PP.HandleIdentifier(Tok);
}
@@ -387,33 +387,33 @@ bool TokenLexer::PasteTokens(Token &Tok) {
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);
@@ -423,7 +423,7 @@ bool TokenLexer::PasteTokens(Token &Tok) {
// 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.
@@ -434,42 +434,42 @@ bool TokenLexer::PasteTokens(Token &Tok) {
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) &&
+ 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
@@ -481,26 +481,26 @@ bool TokenLexer::PasteTokens(Token &Tok) {
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.
@@ -532,11 +532,11 @@ unsigned TokenLexer::isNextTokenLParen() const {
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
index 50ed94a..adf9474 100755
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -9,7 +9,7 @@
LEVEL = ../../..
PARALLEL_DIRS = Headers Basic Lex Parse AST Sema CodeGen Analysis Rewrite \
- Frontend Driver
+ Frontend Index Driver
include $(LEVEL)/Makefile.common
diff --git a/lib/Parse/AttributeList.cpp b/lib/Parse/AttributeList.cpp
index 5ee668a..2ee41bc 100644
--- a/lib/Parse/AttributeList.cpp
+++ b/lib/Parse/AttributeList.cpp
@@ -21,7 +21,7 @@ AttributeList::AttributeList(IdentifierInfo *aName, SourceLocation aLoc,
AttributeList *n, bool declspec)
: AttrName(aName), AttrLoc(aLoc), ParmName(pName), ParmLoc(pLoc),
NumArgs(numArgs), Next(n), DeclspecAttribute(declspec) {
-
+
if (numArgs == 0)
Args = 0;
else {
@@ -32,12 +32,12 @@ AttributeList::AttributeList(IdentifierInfo *aName, SourceLocation aLoc,
AttributeList::~AttributeList() {
if (Args) {
- // FIXME: before we delete the vector, we need to make sure the Expr's
+ // 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
+ // 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;
}
@@ -54,7 +54,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
Str += 2;
Len -= 4;
}
-
+
// FIXME: Hand generating this is neither smart nor efficient.
switch (Len) {
case 4:
@@ -69,7 +69,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
break;
case 6:
if (!memcmp(Str, "packed", 6)) return AT_packed;
- if (!memcmp(Str, "malloc", 6)) return IgnoredAttribute; // FIXME: noalias.
+ if (!memcmp(Str, "malloc", 6)) return AT_malloc;
if (!memcmp(Str, "format", 6)) return AT_format;
if (!memcmp(Str, "unused", 6)) return AT_unused;
if (!memcmp(Str, "blocks", 6)) return AT_blocks;
@@ -103,7 +103,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
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, "format_arg", 10)) return AT_format_arg;
if (!memcmp(Str, "gnu_inline", 10)) return AT_gnu_inline;
break;
case 11:
@@ -136,13 +136,13 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
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;
+ break;
case 20:
if (!memcmp(Str, "reqd_work_group_size", 20)) return AT_reqd_wg_size;
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
index 8fb7cd2..bec1c6e 100644
--- a/lib/Parse/CMakeLists.txt
+++ b/lib/Parse/CMakeLists.txt
@@ -12,10 +12,10 @@ add_clang_library(clangParse
ParseInit.cpp
ParseObjc.cpp
ParsePragma.cpp
- Parser.cpp
ParseStmt.cpp
- ParseTentative.cpp
ParseTemplate.cpp
+ ParseTentative.cpp
+ Parser.cpp
)
add_dependencies(clangParse ClangDiagnosticParse)
diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp
index 8b3b285..b8422aa 100644
--- a/lib/Parse/DeclSpec.cpp
+++ b/lib/Parse/DeclSpec.cpp
@@ -16,6 +16,7 @@
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/LangOptions.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/ErrorHandling.h"
#include <cstring>
using namespace clang;
@@ -38,11 +39,13 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic,
ActionBase::TypeTy **Exceptions,
SourceRange *ExceptionRanges,
unsigned NumExceptions,
- SourceLocation Loc,
+ SourceLocation LPLoc,
+ SourceLocation RPLoc,
Declarator &TheDeclarator) {
DeclaratorChunk I;
I.Kind = Function;
- I.Loc = Loc;
+ I.Loc = LPLoc;
+ I.EndLoc = RPLoc;
I.Fun.hasPrototype = hasProto;
I.Fun.isVariadic = isVariadic;
I.Fun.EllipsisLoc = EllipsisLoc.getRawEncoding();
@@ -62,7 +65,7 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic,
// 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 &&
+ if (!TheDeclarator.InlineParamsUsed &&
NumArgs <= llvm::array_lengthof(TheDeclarator.InlineParams)) {
I.Fun.ArgInfo = TheDeclarator.InlineParams;
I.Fun.DeleteArgInfo = false;
@@ -95,18 +98,26 @@ unsigned DeclSpec::getParsedSpecifiers() const {
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;
}
+template <class T> static bool BadSpecifier(T TNew, T TPrev,
+ const char *&PrevSpec,
+ unsigned &DiagID) {
+ PrevSpec = DeclSpec::getSpecifierName(TPrev);
+ DiagID = (TNew == TPrev ? diag::ext_duplicate_declspec
+ : diag::err_invalid_decl_spec_combination);
+ return true;
+}
+
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";
@@ -116,49 +127,46 @@ const char *DeclSpec::getSpecifierName(DeclSpec::SCS S) {
case DeclSpec::SCS_private_extern: return "__private_extern__";
case DeclSpec::SCS_mutable: return "mutable";
}
+ llvm::llvm_unreachable("Unknown typespec!");
}
-bool DeclSpec::BadSpecifier(SCS S, const char *&PrevSpec) {
- PrevSpec = getSpecifierName(S);
- return true;
-}
-
-bool DeclSpec::BadSpecifier(TSW W, const char *&PrevSpec) {
+const char *DeclSpec::getSpecifierName(TSW W) {
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;
+ case TSW_unspecified: return "unspecified";
+ case TSW_short: return "short";
+ case TSW_long: return "long";
+ case TSW_longlong: return "long long";
}
- return true;
+ llvm::llvm_unreachable("Unknown typespec!");
}
-bool DeclSpec::BadSpecifier(TSC C, const char *&PrevSpec) {
+const char *DeclSpec::getSpecifierName(TSC C) {
switch (C) {
- case TSC_unspecified: PrevSpec = "unspecified"; break;
- case TSC_imaginary: PrevSpec = "imaginary"; break;
- case TSC_complex: PrevSpec = "complex"; break;
+ case TSC_unspecified: return "unspecified";
+ case TSC_imaginary: return "imaginary";
+ case TSC_complex: return "complex";
}
- return true;
+ llvm::llvm_unreachable("Unknown typespec!");
}
-bool DeclSpec::BadSpecifier(TSS S, const char *&PrevSpec) {
+const char *DeclSpec::getSpecifierName(TSS S) {
switch (S) {
- case TSS_unspecified: PrevSpec = "unspecified"; break;
- case TSS_signed: PrevSpec = "signed"; break;
- case TSS_unsigned: PrevSpec = "unsigned"; break;
+ case TSS_unspecified: return "unspecified";
+ case TSS_signed: return "signed";
+ case TSS_unsigned: return "unsigned";
}
- return true;
+ llvm::llvm_unreachable("Unknown typespec!");
}
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_char16: return "char16_t";
+ case DeclSpec::TST_char32: return "char32_t";
case DeclSpec::TST_int: return "int";
case DeclSpec::TST_float: return "float";
case DeclSpec::TST_double: return "double";
@@ -173,39 +181,40 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T) {
case DeclSpec::TST_typename: return "type-name";
case DeclSpec::TST_typeofType:
case DeclSpec::TST_typeofExpr: return "typeof";
- case DeclSpec::TST_auto: return "auto";
+ case DeclSpec::TST_auto: return "auto";
+ case DeclSpec::TST_decltype: return "(decltype)";
+ case DeclSpec::TST_error: return "(error)";
}
+ llvm::llvm_unreachable("Unknown typespec!");
}
-bool DeclSpec::BadSpecifier(TST T, const char *&PrevSpec) {
- PrevSpec = getSpecifierName(T);
- return true;
-}
-
-bool DeclSpec::BadSpecifier(TQ T, const char *&PrevSpec) {
+const char *DeclSpec::getSpecifierName(TQ T) {
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;
+ case DeclSpec::TQ_unspecified: return "unspecified";
+ case DeclSpec::TQ_const: return "const";
+ case DeclSpec::TQ_restrict: return "restrict";
+ case DeclSpec::TQ_volatile: return "volatile";
}
- return true;
+ llvm::llvm_unreachable("Unknown typespec!");
}
bool DeclSpec::SetStorageClassSpec(SCS S, SourceLocation Loc,
- const char *&PrevSpec) {
+ const char *&PrevSpec,
+ unsigned &DiagID) {
if (StorageClassSpec != SCS_unspecified)
- return BadSpecifier((SCS)StorageClassSpec, PrevSpec);
+ return BadSpecifier(S, (SCS)StorageClassSpec, PrevSpec, DiagID);
StorageClassSpec = S;
StorageClassSpecLoc = Loc;
assert((unsigned)S == StorageClassSpec && "SCS constants overflow bitfield");
return false;
}
-bool DeclSpec::SetStorageClassSpecThread(SourceLocation Loc,
- const char *&PrevSpec) {
+bool DeclSpec::SetStorageClassSpecThread(SourceLocation Loc,
+ const char *&PrevSpec,
+ unsigned &DiagID) {
if (SCS_thread_specified) {
PrevSpec = "__thread";
+ DiagID = diag::ext_duplicate_declspec;
return true;
}
SCS_thread_specified = true;
@@ -218,39 +227,46 @@ bool DeclSpec::SetStorageClassSpecThread(SourceLocation Loc,
/// and ignore the request if invalid (e.g. "extern" then "auto" is
/// specified).
bool DeclSpec::SetTypeSpecWidth(TSW W, SourceLocation Loc,
- const char *&PrevSpec) {
+ const char *&PrevSpec,
+ unsigned &DiagID) {
if (TypeSpecWidth != TSW_unspecified &&
// Allow turning long -> long long.
(W != TSW_longlong || TypeSpecWidth != TSW_long))
- return BadSpecifier((TSW)TypeSpecWidth, PrevSpec);
+ return BadSpecifier(W, (TSW)TypeSpecWidth, PrevSpec, DiagID);
TypeSpecWidth = W;
TSWLoc = Loc;
return false;
}
-bool DeclSpec::SetTypeSpecComplex(TSC C, SourceLocation Loc,
- const char *&PrevSpec) {
+bool DeclSpec::SetTypeSpecComplex(TSC C, SourceLocation Loc,
+ const char *&PrevSpec,
+ unsigned &DiagID) {
if (TypeSpecComplex != TSC_unspecified)
- return BadSpecifier((TSC)TypeSpecComplex, PrevSpec);
+ return BadSpecifier(C, (TSC)TypeSpecComplex, PrevSpec, DiagID);
TypeSpecComplex = C;
TSCLoc = Loc;
return false;
}
-bool DeclSpec::SetTypeSpecSign(TSS S, SourceLocation Loc,
- const char *&PrevSpec) {
+bool DeclSpec::SetTypeSpecSign(TSS S, SourceLocation Loc,
+ const char *&PrevSpec,
+ unsigned &DiagID) {
if (TypeSpecSign != TSS_unspecified)
- return BadSpecifier((TSS)TypeSpecSign, PrevSpec);
+ return BadSpecifier(S, (TSS)TypeSpecSign, PrevSpec, DiagID);
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);
+ const char *&PrevSpec,
+ unsigned &DiagID,
+ void *Rep, bool Owned) {
+ if (TypeSpecType != TST_unspecified) {
+ PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType);
+ DiagID = diag::err_invalid_decl_spec_combination;
+ return true;
+ }
TypeSpecType = T;
TypeRep = Rep;
TSTLoc = Loc;
@@ -266,12 +282,12 @@ bool DeclSpec::SetTypeSpecError() {
}
bool DeclSpec::SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec,
- const LangOptions &Lang) {
+ unsigned &DiagID, const LangOptions &Lang) {
// Duplicates turn into warnings pre-C99.
if ((TypeQualifiers & T) && !Lang.C99)
- return BadSpecifier(T, PrevSpec);
+ return BadSpecifier(T, T, PrevSpec, DiagID);
TypeQualifiers |= T;
-
+
switch (T) {
default: assert(0 && "Unknown type qualifier!");
case TQ_const: TQ_constLoc = Loc; break;
@@ -281,38 +297,56 @@ bool DeclSpec::SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec,
return false;
}
-bool DeclSpec::SetFunctionSpecInline(SourceLocation Loc, const char *&PrevSpec){
+bool DeclSpec::SetFunctionSpecInline(SourceLocation Loc, const char *&PrevSpec,
+ unsigned &DiagID) {
// 'inline inline' is ok.
FS_inline_specified = true;
FS_inlineLoc = Loc;
return false;
}
-bool DeclSpec::SetFunctionSpecVirtual(SourceLocation Loc, const char *&PrevSpec){
+bool DeclSpec::SetFunctionSpecVirtual(SourceLocation Loc, const char *&PrevSpec,
+ unsigned &DiagID) {
// 'virtual virtual' is ok.
FS_virtual_specified = true;
FS_virtualLoc = Loc;
return false;
}
-bool DeclSpec::SetFunctionSpecExplicit(SourceLocation Loc, const char *&PrevSpec){
+bool DeclSpec::SetFunctionSpecExplicit(SourceLocation Loc, const char *&PrevSpec,
+ unsigned &DiagID) {
// 'explicit explicit' is ok.
FS_explicit_specified = true;
FS_explicitLoc = Loc;
return false;
}
-bool DeclSpec::SetFriendSpec(SourceLocation Loc, const char *&PrevSpec) {
+bool DeclSpec::SetFriendSpec(SourceLocation Loc, const char *&PrevSpec,
+ unsigned &DiagID) {
if (Friend_specified) {
PrevSpec = "friend";
+ DiagID = diag::ext_duplicate_declspec;
return true;
}
-
+
Friend_specified = true;
FriendLoc = Loc;
return false;
}
+void DeclSpec::setProtocolQualifiers(const ActionBase::DeclPtrTy *Protos,
+ unsigned NP,
+ SourceLocation *ProtoLocs,
+ SourceLocation LAngleLoc) {
+ if (NP == 0) return;
+ ProtocolQualifiers = new ActionBase::DeclPtrTy[NP];
+ ProtocolLocs = new SourceLocation[NP];
+ memcpy((void*)ProtocolQualifiers, Protos, sizeof(ActionBase::DeclPtrTy)*NP);
+ memcpy(ProtocolLocs, ProtoLocs, sizeof(SourceLocation)*NP);
+ NumProtocolQualifiers = NP;
+ ProtocolLAngleLoc = LAngleLoc;
+}
+
/// 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,
@@ -359,7 +393,7 @@ void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) {
}
break;
}
-
+
// TODO: if the implementation does not implement _Complex or _Imaginary,
// disallow their use. Need information about the backend.
if (TypeSpecComplex != TSC_unspecified) {
@@ -379,10 +413,28 @@ void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) {
}
}
+ // C++ [class.friend]p6:
+ // No storage-class-specifier shall appear in the decl-specifier-seq
+ // of a friend declaration.
+ if (isFriendSpecified() && getStorageClassSpec()) {
+ DeclSpec::SCS SC = getStorageClassSpec();
+ const char *SpecName = getSpecifierName(SC);
+
+ SourceLocation SCLoc = getStorageClassSpecLoc();
+ SourceLocation SCEndLoc = SCLoc.getFileLocWithOffset(strlen(SpecName));
+
+ Diag(D, SCLoc, SrcMgr, diag::err_friend_storage_spec)
+ << SpecName
+ << CodeModificationHint::CreateRemoval(SourceRange(SCLoc, SCEndLoc));
+
+ ClearStorageClassSpecs();
+ }
+
+
// 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'?
}
diff --git a/lib/Parse/ExtensionRAIIObject.h b/lib/Parse/ExtensionRAIIObject.h
index 2b2bd3b..cc7c8e2 100644
--- a/lib/Parse/ExtensionRAIIObject.h
+++ b/lib/Parse/ExtensionRAIIObject.h
@@ -30,7 +30,7 @@ namespace clang {
ExtensionRAIIObject(Diagnostic &diags) : Diags(diags) {
Diags.IncrementAllExtensionsSilenced();
}
-
+
~ExtensionRAIIObject() {
Diags.DecrementAllExtensionsSilenced();
}
diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp
index 648e2da..71b22ca 100644
--- a/lib/Parse/MinimalAction.cpp
+++ b/lib/Parse/MinimalAction.cpp
@@ -34,7 +34,7 @@ Action::DeclPtrTy Action::ActOnUsingDirective(Scope *CurScope,
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?
@@ -44,14 +44,15 @@ Action::DeclPtrTy Action::ActOnUsingDirective(Scope *CurScope,
// Defined out-of-line here because of dependecy on AttributeList
Action::DeclPtrTy Action::ActOnUsingDeclaration(Scope *CurScope,
- SourceLocation UsingLoc,
- const CXXScopeSpec &SS,
- SourceLocation IdentLoc,
- IdentifierInfo *TargetName,
- OverloadedOperatorKind Op,
- AttributeList *AttrList,
- bool IsTypeName) {
-
+ AccessSpecifier AS,
+ SourceLocation UsingLoc,
+ const CXXScopeSpec &SS,
+ SourceLocation IdentLoc,
+ IdentifierInfo *TargetName,
+ OverloadedOperatorKind Op,
+ AttributeList *AttrList,
+ bool IsTypeName) {
+
// 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?
@@ -66,11 +67,11 @@ void PrettyStackTraceActionsDecl::print(llvm::raw_ostream &OS) const {
OS << ": ";
}
OS << Message;
-
+
std::string Name = Actions.getDeclName(TheDecl);
if (!Name.empty())
OS << " '" << Name << '\'';
-
+
OS << '\n';
}
@@ -80,7 +81,7 @@ namespace {
struct TypeNameInfo {
TypeNameInfo *Prev;
bool isTypeName;
-
+
TypeNameInfo(bool istypename, TypeNameInfo *prev) {
isTypeName = istypename;
Prev = prev;
@@ -89,13 +90,13 @@ namespace {
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);
@@ -107,7 +108,7 @@ static TypeNameInfoTable *getTable(void *TP) {
return static_cast<TypeNameInfoTable*>(TP);
}
-MinimalAction::MinimalAction(Preprocessor &pp)
+MinimalAction::MinimalAction(Preprocessor &pp)
: Idents(pp.getIdentifierTable()), PP(pp) {
TypeNameInfoTablePtr = new TypeNameInfoTable();
}
@@ -126,9 +127,9 @@ void MinimalAction::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
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.
+ // 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"));
@@ -143,7 +144,8 @@ void MinimalAction::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
/// FIXME: Use the passed CXXScopeSpec for accurate C++ type checking.
Action::TypeTy *
MinimalAction::getTypeName(IdentifierInfo &II, SourceLocation Loc,
- Scope *S, const CXXScopeSpec *SS) {
+ Scope *S, const CXXScopeSpec *SS,
+ bool isClassName) {
if (TypeNameInfo *TI = II.getFETokenInfo<TypeNameInfo>())
if (TI->isTypeName)
return TI;
@@ -157,10 +159,14 @@ bool MinimalAction::isCurrentClassName(const IdentifierInfo &, Scope *,
return false;
}
-TemplateNameKind
-MinimalAction::isTemplateName(const IdentifierInfo &II, Scope *S,
- TemplateTy &TemplateDecl,
- const CXXScopeSpec *SS) {
+TemplateNameKind
+MinimalAction::isTemplateName(Scope *S,
+ const IdentifierInfo &II,
+ SourceLocation IdLoc,
+ const CXXScopeSpec *SS,
+ TypeTy *ObjectType,
+ bool EnteringScope,
+ TemplateTy &TemplateDecl) {
return TNK_Non_template;
}
@@ -170,10 +176,10 @@ MinimalAction::isTemplateName(const IdentifierInfo &II, Scope *S,
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;
@@ -184,10 +190,10 @@ MinimalAction::ActOnDeclarator(Scope *S, Declarator &D) {
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();
}
@@ -206,15 +212,15 @@ MinimalAction::ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
return DeclPtrTy();
}
-/// ActOnForwardClassDeclaration -
-/// Scope will always be top level file scope.
+/// 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]));
}
@@ -225,17 +231,17 @@ MinimalAction::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
/// 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
index af6fab7..c34653e 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -21,17 +21,31 @@ using namespace clang;
/// 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) {
+Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D,
+ const ParsedTemplateInfo &TemplateInfo) {
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);
+ Action::MultiTemplateParamsArg TemplateParams(Actions,
+ TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->data() : 0,
+ TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->size() : 0);
+ DeclPtrTy FnD;
+ if (D.getDeclSpec().isFriendSpecified())
+ // FIXME: Friend templates
+ FnD = Actions.ActOnFriendFunctionDecl(CurScope, D, true, move(TemplateParams));
+ else // FIXME: pass template information through
+ FnD = Actions.ActOnCXXMemberDeclarator(CurScope, AS, D,
+ move(TemplateParams), 0, 0);
+
+ HandleMemberFunctionDefaultArgs(D, FnD);
// Consume the tokens and store them for later parsing.
getCurrentClass().MethodDefs.push_back(LexedMethod(FnD));
+ getCurrentClass().MethodDefs.back().TemplateScope
+ = CurScope->isTemplateParamScope();
CachedTokens &Toks = getCurrentClass().MethodDefs.back().Toks;
tok::TokenKind kind = Tok.getKind();
@@ -40,7 +54,7 @@ Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D) {
// 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.
+ // constructor initializer.
if (Tok.is(tok::semi)) {
// We found a semicolon; complain, consume the semicolon, and
// don't try to parse this method later.
@@ -52,7 +66,7 @@ Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D) {
}
} else {
- // Begin by storing the '{' token.
+ // Begin by storing the '{' token.
Toks.push_back(Tok);
ConsumeBrace();
}
@@ -86,16 +100,18 @@ void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) {
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.
+
+ // If this is a member template, introduce the template parameter scope.
+ ParseScope TemplateScope(this, Scope::TemplateParamScope, LM.TemplateScope);
+ if (LM.TemplateScope)
+ Actions.ActOnReenterTemplateScope(CurScope, LM.Method);
// Start the delayed C++ method declaration
Actions.ActOnStartDelayedCXXMethodDeclaration(CurScope, LM.Method);
// Introduce the parameters into scope and parse their default
// arguments.
- ParseScope PrototypeScope(this,
+ ParseScope PrototypeScope(this,
Scope::FunctionPrototypeScope|Scope::DeclScope);
for (unsigned I = 0, N = LM.DefaultArgs.size(); I != N; ++I) {
// Introduce the parameter into scope.
@@ -149,11 +165,16 @@ void Parser::ParseLexedMethodDefs(ParsingClass &Class) {
for (; !Class.MethodDefs.empty(); Class.MethodDefs.pop_front()) {
LexedMethod &LM = Class.MethodDefs.front();
+ // If this is a member template, introduce the template parameter scope.
+ ParseScope TemplateScope(this, Scope::TemplateParamScope, LM.TemplateScope);
+ if (LM.TemplateScope)
+ Actions.ActOnReenterTemplateScope(CurScope, LM.D);
+
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);
+ PP.EnterTokenStream(LM.Toks.data(), LM.Toks.size(), true, false);
// Consume the previously pushed token.
ConsumeAnyToken();
@@ -171,6 +192,9 @@ void Parser::ParseLexedMethodDefs(ParsingClass &Class) {
}
if (Tok.is(tok::colon))
ParseConstructorInitializer(LM.D);
+ else
+ Actions.ActOnDefaultCtorInitializers(LM.D);
+
// FIXME: What if ParseConstructorInitializer doesn't leave us with a '{'??
ParseFunctionStatementBody(LM.D);
}
@@ -181,7 +205,7 @@ void Parser::ParseLexedMethodDefs(ParsingClass &Class) {
/// ConsumeAndStoreUntil - Consume and store the token at the passed token
/// container until the token 'T' is reached (which gets
-/// consumed/stored too, if ConsumeFinalToken).
+/// 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.
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 4a3532c..b56c331 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -69,10 +69,10 @@ Action::TypeResult Parser::ParseTypeName(SourceRange *Range) {
/// 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
+/// 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
@@ -82,9 +82,9 @@ Action::TypeResult Parser::ParseTypeName(SourceRange *Range) {
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,
@@ -99,8 +99,8 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) {
// 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)) {
+
+ if (Tok.is(tok::comma)) {
// allows for empty/non-empty attributes. ((__vector_size__(16),,,,))
ConsumeToken();
continue;
@@ -108,26 +108,26 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) {
// 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)) {
+
+ if (Tok.is(tok::r_paren)) {
// __attribute__(( mode(byte) ))
ConsumeParen(); // ignore the right paren loc for now
- CurrAttr = new AttributeList(AttrName, AttrNameLoc,
+ 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());
@@ -144,7 +144,7 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) {
}
if (ArgExprsOk && Tok.is(tok::r_paren)) {
ConsumeParen(); // ignore the right paren loc for now
- CurrAttr = new AttributeList(AttrName, AttrNameLoc, ParmName,
+ CurrAttr = new AttributeList(AttrName, AttrNameLoc, ParmName,
ParmLoc, ArgExprs.take(), ArgExprs.size(), CurrAttr);
}
}
@@ -154,11 +154,13 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) {
// parse a possibly empty comma separated list of expressions
// __attribute__(( nonnull() ))
ConsumeParen(); // ignore the right paren loc for now
- CurrAttr = new AttributeList(AttrName, AttrNameLoc,
+ CurrAttr = new AttributeList(AttrName, AttrNameLoc,
0, SourceLocation(), 0, 0, CurrAttr);
break;
case tok::kw_char:
case tok::kw_wchar_t:
+ case tok::kw_char16_t:
+ case tok::kw_char32_t:
case tok::kw_bool:
case tok::kw_short:
case tok::kw_int:
@@ -172,7 +174,7 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) {
// If it's a builtin type name, eat it and expect a rparen
// __attribute__(( vec_type_hint(char) ))
ConsumeToken();
- CurrAttr = new AttributeList(AttrName, AttrNameLoc,
+ CurrAttr = new AttributeList(AttrName, AttrNameLoc,
0, SourceLocation(), 0, 0, CurrAttr);
if (Tok.is(tok::r_paren))
ConsumeParen();
@@ -181,7 +183,7 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) {
// __attribute__(( aligned(16) ))
ExprVector ArgExprs(Actions);
bool ArgExprsOk = true;
-
+
// now parse the list of expressions
while (1) {
OwningExprResult ArgExpr(ParseAssignmentExpression());
@@ -207,7 +209,7 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) {
}
}
} else {
- CurrAttr = new AttributeList(AttrName, AttrNameLoc,
+ CurrAttr = new AttributeList(AttrName, AttrNameLoc,
0, SourceLocation(), 0, 0, CurrAttr);
}
}
@@ -320,7 +322,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(unsigned Context,
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);
@@ -339,7 +341,7 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(unsigned Context,
// 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)) {
@@ -347,25 +349,25 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(unsigned Context,
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);
+
+ Diag(Tok, diag::err_expected_semi_declaration);
// Skip to end of block or statement
SkipUntil(tok::r_brace, true, true);
if (Tok.is(tok::semi))
@@ -404,27 +406,50 @@ Parser::DeclPtrTy Parser::ParseDeclarationAfterDeclarator(Declarator &D,
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 = TemplateInfo.TemplateParams?
- Actions.ActOnTemplateDeclarator(CurScope,
+ DeclPtrTy ThisDecl;
+ switch (TemplateInfo.Kind) {
+ case ParsedTemplateInfo::NonTemplate:
+ ThisDecl = Actions.ActOnDeclarator(CurScope, D);
+ break;
+
+ case ParsedTemplateInfo::Template:
+ case ParsedTemplateInfo::ExplicitSpecialization:
+ ThisDecl = Actions.ActOnTemplateDeclarator(CurScope,
Action::MultiTemplateParamsArg(Actions,
TemplateInfo.TemplateParams->data(),
TemplateInfo.TemplateParams->size()),
- D)
- : Actions.ActOnDeclarator(CurScope, D);
-
+ D);
+ break;
+
+ case ParsedTemplateInfo::ExplicitInstantiation: {
+ Action::DeclResult ThisRes
+ = Actions.ActOnExplicitInstantiation(CurScope,
+ TemplateInfo.ExternLoc,
+ TemplateInfo.TemplateLoc,
+ D);
+ if (ThisRes.isInvalid()) {
+ SkipUntil(tok::semi, true, true);
+ return DeclPtrTy();
+ }
+
+ ThisDecl = ThisRes.get();
+ break;
+ }
+ }
+
// Parse declarator '=' initializer.
if (Tok.is(tok::equal)) {
ConsumeToken();
@@ -444,7 +469,7 @@ Parser::DeclPtrTy Parser::ParseDeclarationAfterDeclarator(Declarator &D,
SkipUntil(tok::semi, true, true);
return DeclPtrTy();
}
- Actions.AddInitializerToDecl(ThisDecl, Actions.FullExpr(Init));
+ Actions.AddInitializerToDecl(ThisDecl, move(Init));
}
} else if (Tok.is(tok::l_paren)) {
// Parse C++ direct initializer: '(' expression-list ')'
@@ -465,7 +490,9 @@ Parser::DeclPtrTy Parser::ParseDeclarationAfterDeclarator(Declarator &D,
CommaLocs.data(), RParenLoc);
}
} else {
- Actions.ActOnUninitializedDecl(ThisDecl);
+ bool TypeContainsUndeducedAuto =
+ D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto;
+ Actions.ActOnUninitializedDecl(ThisDecl, TypeContainsUndeducedAuto);
}
return ThisDecl;
@@ -488,25 +515,25 @@ 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
@@ -519,10 +546,10 @@ ParseInitDeclaratorListAfterFirstDeclarator(Declarator &D) {
AttributeList *AttrList = ParseAttributes(&Loc);
D.AddAttributes(AttrList, Loc);
}
-
+
ParseDeclarator(D);
}
-
+
return Actions.FinalizeDeclaratorGroup(CurScope, D.getDeclSpec(),
DeclsInGroup.data(),
DeclsInGroup.size());
@@ -538,13 +565,13 @@ 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())
@@ -553,7 +580,7 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS) {
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())
@@ -604,7 +631,7 @@ 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
@@ -619,7 +646,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
// 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())) {
@@ -628,7 +655,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
// 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.
@@ -638,7 +665,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *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;
@@ -646,12 +673,12 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
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);
@@ -660,19 +687,43 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
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;
+
+ // This is almost certainly an invalid type name. Let the action emit a
+ // diagnostic and attempt to recover.
+ Action::TypeTy *T = 0;
+ if (Actions.DiagnoseUnknownTypeName(*Tok.getIdentifierInfo(), Loc,
+ CurScope, SS, T)) {
+ // The action emitted a diagnostic, so we don't have to.
+ if (T) {
+ // The action has suggested that the type T could be used. Set that as
+ // the type in the declaration specifiers, consume the would-be type
+ // name token, and we're done.
+ const char *PrevSpec;
+ unsigned DiagID;
+ DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID, T,
+ false);
+ DS.SetRangeEnd(Tok.getLocation());
+ ConsumeToken();
+
+ // There may be other declaration specifiers after this.
+ return true;
+ }
+
+ // Fall through; the action had no suggestion for us.
+ } else {
+ // The action did not emit a diagnostic, so emit one now.
+ SourceRange R;
+ if (SS) R = SS->getRange();
+ Diag(Loc, diag::err_unknown_typename) << Tok.getIdentifierInfo() << R;
+ }
+
+ // Mark this as an error.
const char *PrevSpec;
- DS.SetTypeSpecType(DeclSpec::TST_error, Loc, PrevSpec);
+ unsigned DiagID;
+ DS.SetTypeSpecType(DeclSpec::TST_error, Loc, PrevSpec, DiagID);
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.
@@ -703,24 +754,32 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
///
void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
const ParsedTemplateInfo &TemplateInfo,
- AccessSpecifier AS) {
+ AccessSpecifier AS,
+ DeclSpecContext DSContext) {
+ if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteOrdinaryName(CurScope);
+ ConsumeToken();
+ }
+
DS.SetRangeStart(Tok.getLocation());
while (1) {
- int isInvalid = false;
+ bool isInvalid = false;
const char *PrevSpec = 0;
+ unsigned DiagID = 0;
+
SourceLocation Loc = Tok.getLocation();
switch (Tok.getKind()) {
- default:
+ 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())
+ if (TryAnnotateCXXScopeToken(true))
continue;
goto DoneWithDeclSpec;
@@ -730,18 +789,31 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// We are looking for a qualified typename.
Token Next = NextToken();
- if (Next.is(tok::annot_template_id) &&
+ 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(SS, /*ObjectType=*/0, true);
+ assert(Tok.is(tok::annot_template_id) &&
"ParseOptionalCXXScopeSpecifier not working");
AnnotateTemplateIdTokenAsType(&SS);
continue;
}
+ if (Next.is(tok::annot_typename)) {
+ // FIXME: is this scope-specifier getting dropped?
+ ConsumeToken(); // the scope-specifier
+ if (Tok.getAnnotationValue())
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc,
+ PrevSpec, DiagID,
+ Tok.getAnnotationValue());
+ else
+ DS.SetTypeSpecError();
+ DS.SetRangeEnd(Tok.getAnnotationEndLoc());
+ ConsumeToken(); // The typename
+ }
+
if (Next.isNot(tok::identifier))
goto DoneWithDeclSpec;
@@ -763,66 +835,69 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// 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.
+ // 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);
+ DiagID, 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());
+ DiagID, 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;
+
+ SourceLocation LAngleLoc, EndProtoLoc;
llvm::SmallVector<DeclPtrTy, 8> ProtocolDecl;
- ParseObjCProtocolReferences(ProtocolDecl, false, EndProtoLoc);
- DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size());
-
+ llvm::SmallVector<SourceLocation, 8> ProtocolLocs;
+ ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, false,
+ LAngleLoc, EndProtoLoc);
+ DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size(),
+ ProtocolLocs.data(), LAngleLoc);
+
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())
+ if (getLang().CPlusPlus && TryAnnotateCXXScopeToken(true))
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(),
+ 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,
@@ -836,16 +911,19 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// 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) &&
+ if (getLang().CPlusPlus &&
+ (CurScope->isClassScope() ||
+ (CurScope->isTemplateParamScope() &&
+ CurScope->getParent()->isClassScope())) &&
+ Actions.isCurrentClassName(*Tok.getIdentifierInfo(), CurScope) &&
NextToken().getKind() == tok::l_paren)
goto DoneWithDeclSpec;
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
- TypeRep);
+ DiagID, TypeRep);
if (isInvalid)
break;
-
+
DS.SetRangeEnd(Tok.getLocation());
ConsumeToken(); // The identifier
@@ -855,12 +933,15 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// just a normal reference to a typedef name.
if (!Tok.is(tok::less) || !getLang().ObjC1)
continue;
-
- SourceLocation EndProtoLoc;
+
+ SourceLocation LAngleLoc, EndProtoLoc;
llvm::SmallVector<DeclPtrTy, 8> ProtocolDecl;
- ParseObjCProtocolReferences(ProtocolDecl, false, EndProtoLoc);
- DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size());
-
+ llvm::SmallVector<SourceLocation, 8> ProtocolLocs;
+ ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, false,
+ LAngleLoc, EndProtoLoc);
+ DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size(),
+ ProtocolLocs.data(), LAngleLoc);
+
DS.SetRangeEnd(EndProtoLoc);
// Need to support trailing type qualifiers (e.g. "id<p> const").
@@ -870,7 +951,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// type-name
case tok::annot_template_id: {
- TemplateIdAnnotation *TemplateId
+ 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
@@ -893,7 +974,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
case tok::kw___declspec:
DS.AddAttributes(ParseMicrosoftDeclSpec());
continue;
-
+
// Microsoft single token adornments.
case tok::kw___forceinline:
// FIXME: Add handling here!
@@ -909,106 +990,144 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// storage-class-specifier
case tok::kw_typedef:
- isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_typedef, Loc, PrevSpec);
+ isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_typedef, Loc, PrevSpec,
+ DiagID);
break;
case tok::kw_extern:
if (DS.isThreadSpecified())
Diag(Tok, diag::ext_thread_before) << "extern";
- isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_extern, Loc, PrevSpec);
+ isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_extern, Loc, PrevSpec,
+ DiagID);
break;
case tok::kw___private_extern__:
isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_private_extern, Loc,
- PrevSpec);
+ PrevSpec, DiagID);
break;
case tok::kw_static:
if (DS.isThreadSpecified())
Diag(Tok, diag::ext_thread_before) << "static";
- isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_static, Loc, PrevSpec);
+ isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_static, Loc, PrevSpec,
+ DiagID);
break;
case tok::kw_auto:
if (getLang().CPlusPlus0x)
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec);
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec,
+ DiagID);
else
- isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_auto, Loc, PrevSpec);
+ isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_auto, Loc, PrevSpec,
+ DiagID);
break;
case tok::kw_register:
- isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_register, Loc, PrevSpec);
+ isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_register, Loc, PrevSpec,
+ DiagID);
break;
case tok::kw_mutable:
- isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_mutable, Loc, PrevSpec);
+ isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_mutable, Loc, PrevSpec,
+ DiagID);
break;
case tok::kw___thread:
- isInvalid = DS.SetStorageClassSpecThread(Loc, PrevSpec)*2;
+ isInvalid = DS.SetStorageClassSpecThread(Loc, PrevSpec, DiagID);
break;
-
+
// function-specifier
case tok::kw_inline:
- isInvalid = DS.SetFunctionSpecInline(Loc, PrevSpec);
+ isInvalid = DS.SetFunctionSpecInline(Loc, PrevSpec, DiagID);
break;
case tok::kw_virtual:
- isInvalid = DS.SetFunctionSpecVirtual(Loc, PrevSpec);
+ isInvalid = DS.SetFunctionSpecVirtual(Loc, PrevSpec, DiagID);
break;
case tok::kw_explicit:
- isInvalid = DS.SetFunctionSpecExplicit(Loc, PrevSpec);
+ isInvalid = DS.SetFunctionSpecExplicit(Loc, PrevSpec, DiagID);
break;
// friend
case tok::kw_friend:
- isInvalid = DS.SetFriendSpec(Loc, PrevSpec);
+ if (DSContext == DSC_class)
+ isInvalid = DS.SetFriendSpec(Loc, PrevSpec, DiagID);
+ else {
+ PrevSpec = ""; // not actually used by the diagnostic
+ DiagID = diag::err_friend_invalid_in_context;
+ isInvalid = true;
+ }
break;
-
+
// type-specifier
case tok::kw_short:
- isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec);
+ isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec,
+ DiagID);
break;
case tok::kw_long:
if (DS.getTypeSpecWidth() != DeclSpec::TSW_long)
- isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec);
+ isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec,
+ DiagID);
else
- isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec);
+ isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec,
+ DiagID);
break;
case tok::kw_signed:
- isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec);
+ isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec,
+ DiagID);
break;
case tok::kw_unsigned:
- isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec);
+ isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec,
+ DiagID);
break;
case tok::kw__Complex:
- isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_complex, Loc, PrevSpec);
+ isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_complex, Loc, PrevSpec,
+ DiagID);
break;
case tok::kw__Imaginary:
- isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_imaginary, Loc, PrevSpec);
+ isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_imaginary, Loc, PrevSpec,
+ DiagID);
break;
case tok::kw_void:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec);
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec,
+ DiagID);
break;
case tok::kw_char:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec);
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec,
+ DiagID);
break;
case tok::kw_int:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec);
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec,
+ DiagID);
break;
case tok::kw_float:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec);
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec,
+ DiagID);
break;
case tok::kw_double:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec);
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec,
+ DiagID);
break;
case tok::kw_wchar_t:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec);
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec,
+ DiagID);
+ break;
+ case tok::kw_char16_t:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char16, Loc, PrevSpec,
+ DiagID);
+ break;
+ case tok::kw_char32_t:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char32, Loc, PrevSpec,
+ DiagID);
break;
case tok::kw_bool:
case tok::kw__Bool:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec);
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec,
+ DiagID);
break;
case tok::kw__Decimal32:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal32, Loc, PrevSpec);
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal32, Loc, PrevSpec,
+ DiagID);
break;
case tok::kw__Decimal64:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal64, Loc, PrevSpec);
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal64, Loc, PrevSpec,
+ DiagID);
break;
case tok::kw__Decimal128:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal128, Loc, PrevSpec);
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal128, Loc, PrevSpec,
+ DiagID);
break;
// class-specifier:
@@ -1029,15 +1148,16 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// cv-qualifier:
case tok::kw_const:
- isInvalid = DS.SetTypeQual(DeclSpec::TQ_const, Loc, PrevSpec,getLang())*2;
+ isInvalid = DS.SetTypeQual(DeclSpec::TQ_const, Loc, PrevSpec, DiagID,
+ getLang());
break;
case tok::kw_volatile:
- isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec,
- getLang())*2;
+ isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec, DiagID,
+ getLang());
break;
case tok::kw_restrict:
- isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec,
- getLang())*2;
+ isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, DiagID,
+ getLang());
break;
// C++ typename-specifier:
@@ -1061,12 +1181,15 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// but we support it.
if (DS.hasTypeSpecifier() || !getLang().ObjC1)
goto DoneWithDeclSpec;
-
+
{
- SourceLocation EndProtoLoc;
+ SourceLocation LAngleLoc, EndProtoLoc;
llvm::SmallVector<DeclPtrTy, 8> ProtocolDecl;
- ParseObjCProtocolReferences(ProtocolDecl, false, EndProtoLoc);
- DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size());
+ llvm::SmallVector<SourceLocation, 8> ProtocolLocs;
+ ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, false,
+ LAngleLoc, EndProtoLoc);
+ DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size(),
+ ProtocolLocs.data(), LAngleLoc);
DS.SetRangeEnd(EndProtoLoc);
Diag(Loc, diag::warn_objc_protocol_qualifier_missing_id)
@@ -1077,12 +1200,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
continue;
}
}
- // If the specifier combination wasn't legal, issue a diagnostic.
+ // If the specifier 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;
+ assert(DiagID);
Diag(Tok, DiagID) << PrevSpec;
}
DS.SetRangeEnd(Tok.getLocation());
@@ -1133,8 +1254,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
/// [OBJC] class-name objc-protocol-refs[opt] [TODO]
/// [OBJC] typedef-name objc-protocol-refs[opt] [TODO]
/// [C++0x] 'decltype' ( expression )
-bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, int& isInvalid,
+bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid,
const char *&PrevSpec,
+ unsigned &DiagID,
const ParsedTemplateInfo &TemplateInfo) {
SourceLocation Loc = Tok.getLocation();
@@ -1144,98 +1266,117 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, int& isInvalid,
// 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);
+ return ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID,
+ 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);
+ return ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID,
+ 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());
+ DiagID, 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;
+
+ SourceLocation LAngleLoc, EndProtoLoc;
llvm::SmallVector<DeclPtrTy, 8> ProtocolDecl;
- ParseObjCProtocolReferences(ProtocolDecl, false, EndProtoLoc);
- DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size());
-
+ llvm::SmallVector<SourceLocation, 8> ProtocolLocs;
+ ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, false,
+ LAngleLoc, EndProtoLoc);
+ DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size(),
+ ProtocolLocs.data(), LAngleLoc);
+
DS.SetRangeEnd(EndProtoLoc);
return true;
}
case tok::kw_short:
- isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec);
+ isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec, DiagID);
break;
case tok::kw_long:
if (DS.getTypeSpecWidth() != DeclSpec::TSW_long)
- isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec);
+ isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec,
+ DiagID);
else
- isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec);
+ isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec,
+ DiagID);
break;
case tok::kw_signed:
- isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec);
+ isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec, DiagID);
break;
case tok::kw_unsigned:
- isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec);
+ isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec,
+ DiagID);
break;
case tok::kw__Complex:
- isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_complex, Loc, PrevSpec);
+ isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_complex, Loc, PrevSpec,
+ DiagID);
break;
case tok::kw__Imaginary:
- isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_imaginary, Loc, PrevSpec);
+ isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_imaginary, Loc, PrevSpec,
+ DiagID);
break;
case tok::kw_void:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec);
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec, DiagID);
break;
case tok::kw_char:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec);
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec, DiagID);
break;
case tok::kw_int:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec);
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec, DiagID);
break;
case tok::kw_float:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec);
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec, DiagID);
break;
case tok::kw_double:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec);
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec, DiagID);
break;
case tok::kw_wchar_t:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec);
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec, DiagID);
+ break;
+ case tok::kw_char16_t:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char16, Loc, PrevSpec, DiagID);
+ break;
+ case tok::kw_char32_t:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char32, Loc, PrevSpec, DiagID);
break;
case tok::kw_bool:
case tok::kw__Bool:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec);
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec, DiagID);
break;
case tok::kw__Decimal32:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal32, Loc, PrevSpec);
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal32, Loc, PrevSpec,
+ DiagID);
break;
case tok::kw__Decimal64:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal64, Loc, PrevSpec);
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal64, Loc, PrevSpec,
+ DiagID);
break;
case tok::kw__Decimal128:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal128, Loc, PrevSpec);
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal128, Loc, PrevSpec,
+ DiagID);
break;
// class-specifier:
@@ -1257,15 +1398,15 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, int& isInvalid,
// cv-qualifier:
case tok::kw_const:
isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec,
- getLang())*2;
+ DiagID, getLang());
break;
case tok::kw_volatile:
isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec,
- getLang())*2;
+ DiagID, getLang());
break;
case tok::kw_restrict:
isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec,
- getLang())*2;
+ DiagID, getLang());
break;
// GNU typeof support.
@@ -1277,13 +1418,13 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, int& isInvalid,
case tok::kw_decltype:
ParseDecltypeSpecifier(DS);
return true;
-
+
// C++0x auto support.
case tok::kw_auto:
if (!getLang().CPlusPlus0x)
return false;
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec);
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec, DiagID);
break;
case tok::kw___ptr64:
case tok::kw___w64:
@@ -1302,8 +1443,6 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, int& isInvalid,
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());
@@ -1337,11 +1476,11 @@ ParseStructDeclaration(DeclSpec &DS,
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)) {
@@ -1353,12 +1492,12 @@ ParseStructDeclaration(DeclSpec &DS,
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());
@@ -1410,9 +1549,9 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
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);
@@ -1428,7 +1567,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
// 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)
@@ -1442,14 +1581,23 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
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];
+ DeclPtrTy Field;
// Install the declarator into the current TagDecl.
- DeclPtrTy Field = Actions.ActOnField(CurScope, TagDecl,
- DS.getSourceRange().getBegin(),
- FD.D, FD.BitfieldSize);
+ if (FD.D.getExtension()) {
+ // Silences extension warnings
+ ExtensionRAIIObject O(Diags);
+ Field = Actions.ActOnField(CurScope, TagDecl,
+ DS.getSourceRange().getBegin(),
+ FD.D, FD.BitfieldSize);
+ } else {
+ Field = Actions.ActOnField(CurScope, TagDecl,
+ DS.getSourceRange().getBegin(),
+ FD.D, FD.BitfieldSize);
+ }
FieldDecls.push_back(Field);
}
} else { // Handle @defs
@@ -1467,12 +1615,12 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
continue;
}
llvm::SmallVector<DeclPtrTy, 16> Fields;
- Actions.ActOnDefs(CurScope, TagDecl, Tok.getLocation(),
+ 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();
@@ -1485,9 +1633,9 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
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))
@@ -1498,7 +1646,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
LBraceLoc, RBraceLoc,
AttrList);
StructScope.Exit();
- Actions.ActOnTagFinishDefinition(CurScope, TagDecl);
+ Actions.ActOnTagFinishDefinition(CurScope, TagDecl, RBraceLoc);
}
@@ -1517,14 +1665,19 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
AccessSpecifier AS) {
// Parse the tag portion of this.
-
+ if (Tok.is(tok::code_completion)) {
+ // Code completion for an enum name.
+ Actions.CodeCompleteTag(CurScope, DeclSpec::TST_enum);
+ ConsumeToken();
+ }
+
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 (getLang().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS, 0, false)) {
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident);
if (Tok.isNot(tok::l_brace)) {
@@ -1535,16 +1688,16 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
}
}
}
-
+
// 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;
@@ -1552,7 +1705,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
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.
@@ -1561,26 +1714,30 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
// enum foo {..}; void bar() { enum foo; } <- new foo in bar.
// enum foo {..}; void bar() { enum foo x; } <- use of old foo.
//
- Action::TagKind TK;
+ Action::TagUseKind TUK;
if (Tok.is(tok::l_brace))
- TK = Action::TK_Definition;
+ TUK = Action::TUK_Definition;
else if (Tok.is(tok::semi))
- TK = Action::TK_Declaration;
+ TUK = Action::TUK_Declaration;
else
- TK = Action::TK_Reference;
+ TUK = Action::TUK_Reference;
bool Owned = false;
- DeclPtrTy TagDecl = Actions.ActOnTag(CurScope, DeclSpec::TST_enum, TK,
+ bool IsDependent = false;
+ DeclPtrTy TagDecl = Actions.ActOnTag(CurScope, DeclSpec::TST_enum, TUK,
StartLoc, SS, Name, NameLoc, Attr, AS,
- Owned);
-
+ Action::MultiTemplateParamsArg(Actions),
+ Owned, IsDependent);
+ assert(!IsDependent && "didn't expect dependent enum");
+
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,
+ unsigned DiagID;
+ if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc, PrevSpec, DiagID,
TagDecl.getAs<void>(), Owned))
- Diag(StartLoc, diag::err_invalid_decl_spec_combination) << PrevSpec;
+ Diag(StartLoc, DiagID) << PrevSpec;
}
/// ParseEnumBody - Parse a {} enclosed enumerator-list.
@@ -1599,20 +1756,20 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, DeclPtrTy EnumDecl) {
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)) {
@@ -1621,7 +1778,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, DeclPtrTy EnumDecl) {
if (AssignedVal.isInvalid())
SkipUntil(tok::comma, tok::r_brace, true, true);
}
-
+
// Install the enumerator constant into EnumDecl.
DeclPtrTy EnumConstDecl = Actions.ActOnEnumConstant(CurScope, EnumDecl,
LastEnumConstDecl,
@@ -1630,31 +1787,32 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, DeclPtrTy EnumDecl) {
AssignedVal.release());
EnumConstantDecls.push_back(EnumConstDecl);
LastEnumConstDecl = EnumConstDecl;
-
+
if (Tok.isNot(tok::comma))
break;
SourceLocation CommaLoc = ConsumeToken();
-
- if (Tok.isNot(tok::identifier) &&
+
+ 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;
+ AttributeList *Attr = 0;
// If attributes exist after the identifier list, parse them.
if (Tok.is(tok::kw___attribute))
- AttrList = ParseAttributes(); // FIXME: where do they do?
+ Attr = ParseAttributes();
+
+ Actions.ActOnEnumBody(StartLoc, LBraceLoc, RBraceLoc, EnumDecl,
+ EnumConstantDecls.data(), EnumConstantDecls.size(),
+ CurScope, Attr);
EnumScope.Exit();
- Actions.ActOnTagFinishDefinition(CurScope, EnumDecl);
+ Actions.ActOnTagFinishDefinition(CurScope, EnumDecl, RBraceLoc);
}
/// isTypeSpecifierQualifier - Return true if the current token could be the
@@ -1675,7 +1833,7 @@ bool Parser::isTypeQualifier() const {
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
@@ -1696,12 +1854,12 @@ bool Parser::isTypeSpecifierQualifier() {
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:
@@ -1712,6 +1870,8 @@ bool Parser::isTypeSpecifierQualifier() {
case tok::kw_void:
case tok::kw_char:
case tok::kw_wchar_t:
+ case tok::kw_char16_t:
+ case tok::kw_char32_t:
case tok::kw_int:
case tok::kw_float:
case tok::kw_double:
@@ -1720,14 +1880,14 @@ bool Parser::isTypeSpecifierQualifier() {
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:
@@ -1736,11 +1896,11 @@ bool Parser::isTypeSpecifierQualifier() {
// 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:
@@ -1755,7 +1915,7 @@ bool Parser::isTypeSpecifierQualifier() {
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))
@@ -1773,14 +1933,14 @@ bool Parser::isDeclarationSpecifier() {
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:
@@ -1789,7 +1949,7 @@ bool Parser::isDeclarationSpecifier() {
case tok::kw_auto:
case tok::kw_register:
case tok::kw___thread:
-
+
// type-specifiers
case tok::kw_short:
case tok::kw_long:
@@ -1800,6 +1960,9 @@ bool Parser::isDeclarationSpecifier() {
case tok::kw_void:
case tok::kw_char:
case tok::kw_wchar_t:
+ case tok::kw_char16_t:
+ case tok::kw_char32_t:
+
case tok::kw_int:
case tok::kw_float:
case tok::kw_double:
@@ -1808,14 +1971,14 @@ bool Parser::isDeclarationSpecifier() {
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:
@@ -1831,15 +1994,15 @@ bool Parser::isDeclarationSpecifier() {
// 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:
@@ -1861,22 +2024,23 @@ bool Parser::isDeclarationSpecifier() {
///
void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, bool AttributesAllowed) {
while (1) {
- int isInvalid = false;
+ bool isInvalid = false;
const char *PrevSpec = 0;
+ unsigned DiagID = 0;
SourceLocation Loc = Tok.getLocation();
switch (Tok.getKind()) {
case tok::kw_const:
- isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec,
- getLang())*2;
+ isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec, DiagID,
+ getLang());
break;
case tok::kw_volatile:
- isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec,
- getLang())*2;
+ isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec, DiagID,
+ getLang());
break;
case tok::kw_restrict:
- isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec,
- getLang())*2;
+ isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, DiagID,
+ getLang());
break;
case tok::kw___w64:
case tok::kw___ptr64:
@@ -1905,9 +2069,6 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, bool AttributesAllowed) {
// 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();
@@ -1947,6 +2108,8 @@ void Parser::ParseDeclarator(Declarator &D) {
void Parser::ParseDeclaratorInternal(Declarator &D,
DirectDeclParseFunction DirectDeclParser) {
+ if (Diags.hasAllExtensionsSilenced())
+ D.setExtension();
// 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.
@@ -1954,8 +2117,8 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
(Tok.is(tok::coloncolon) || Tok.is(tok::identifier) ||
Tok.is(tok::annot_cxxscope))) {
CXXScopeSpec SS;
- if (ParseOptionalCXXScopeSpecifier(SS)) {
- if(Tok.isNot(tok::star)) {
+ if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true)) {
+ if (Tok.isNot(tok::star)) {
// The scope spec really belongs to the direct-declarator.
D.getCXXScopeSpec() = SS;
if (DirectDeclParser)
@@ -2013,7 +2176,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
SourceLocation());
else
// Remember that we parsed a Block type, and remember the type-quals.
- D.AddTypeInfo(DeclaratorChunk::getBlockPointer(DS.getTypeQualifiers(),
+ D.AddTypeInfo(DeclaratorChunk::getBlockPointer(DS.getTypeQualifiers(),
Loc, DS.TakeAttributes()),
SourceLocation());
} else {
@@ -2095,13 +2258,13 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
///
/// id-expression: [C++ 5.1]
/// unqualified-id
-/// qualified-id [TODO]
+/// qualified-id
///
/// unqualified-id: [C++ 5.1]
-/// identifier
+/// identifier
/// operator-function-id
-/// conversion-function-id [TODO]
-/// '~' class-name
+/// conversion-function-id
+/// '~' class-name
/// template-id
///
void Parser::ParseDirectDeclarator(Declarator &D) {
@@ -2111,7 +2274,8 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
if (D.mayHaveIdentifier()) {
// ParseDeclaratorInternal might already have parsed the scope.
bool afterCXXScope = D.getCXXScopeSpec().isSet() ||
- ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec());
+ ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), /*ObjectType=*/0,
+ true);
if (afterCXXScope) {
// Change the declaration context for name lookup, until this function
// is exited (and the declarator has been parsed).
@@ -2122,11 +2286,12 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
assert(Tok.getIdentifierInfo() && "Not an identifier?");
// If this identifier is the name of the current class, it's a
- // constructor name.
+ // constructor name.
if (!D.getDeclSpec().hasTypeSpecifier() &&
Actions.isCurrentClassName(*Tok.getIdentifierInfo(),CurScope)) {
+ CXXScopeSpec *SS = afterCXXScope? &D.getCXXScopeSpec() : 0;
D.setConstructor(Actions.getTypeName(*Tok.getIdentifierInfo(),
- Tok.getLocation(), CurScope),
+ Tok.getLocation(), CurScope, SS),
Tok.getLocation());
// This is a normal identifier.
} else
@@ -2134,18 +2299,10 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
ConsumeToken();
goto PastIdentifier;
} else if (Tok.is(tok::annot_template_id)) {
- TemplateIdAnnotation *TemplateId
+ 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();
+ D.setTemplateId(TemplateId);
ConsumeToken();
goto PastIdentifier;
} else if (Tok.is(tok::kw_operator)) {
@@ -2167,17 +2324,18 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
} else if (Tok.is(tok::tilde)) {
// This should be a C++ destructor.
SourceLocation TildeLoc = ConsumeToken();
- if (Tok.is(tok::identifier)) {
+ if (Tok.is(tok::identifier) || Tok.is(tok::annot_template_id)) {
// FIXME: Inaccurate.
SourceLocation NameLoc = Tok.getLocation();
SourceLocation EndLoc;
- TypeResult Type = ParseClassName(EndLoc);
+ CXXScopeSpec *SS = afterCXXScope? &D.getCXXScopeSpec() : 0;
+ TypeResult Type = ParseClassName(EndLoc, SS, true);
if (Type.isInvalid())
D.SetIdentifier(0, TildeLoc);
else
D.setDestructor(Type.get(), TildeLoc, NameLoc);
} else {
- Diag(Tok, diag::err_expected_class_name);
+ Diag(Tok, diag::err_destructor_class_name);
D.SetIdentifier(0, TildeLoc);
}
goto PastIdentifier;
@@ -2222,11 +2380,11 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
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);".
@@ -2250,7 +2408,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
/// 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
+/// parens for precedence. If we find that these are actually function
/// parameter parens in an abstract-declarator, we call ParseFunctionDeclarator.
///
/// direct-declarator:
@@ -2264,7 +2422,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
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:
@@ -2279,7 +2437,7 @@ void Parser::ParseParenDeclarator(Declarator &D) {
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;
@@ -2290,13 +2448,13 @@ void Parser::ParseParenDeclarator(Declarator &D) {
Tok.is(tok::kw___ptr64)) {
AttrList = ParseMicrosoftTypeAttributes(AttrList);
}
-
+
// 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.
@@ -2311,7 +2469,7 @@ void Parser::ParseParenDeclarator(Declarator &D) {
// 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 ')'
@@ -2329,7 +2487,7 @@ void Parser::ParseParenDeclarator(Declarator &D) {
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
@@ -2353,6 +2511,7 @@ void Parser::ParseParenDeclarator(Declarator &D) {
/// parameter-type-list: [C99 6.7.5]
/// parameter-list
/// parameter-list ',' '...'
+/// [C++] parameter-list '...'
///
/// parameter-list: [C99 6.7.5]
/// parameter-declaration
@@ -2375,7 +2534,7 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
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) {
@@ -2383,7 +2542,8 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
delete AttrList;
}
- SourceLocation Loc = ConsumeParen(); // Eat the closing ')'.
+ SourceLocation RParenLoc = ConsumeParen(); // Eat the closing ')'.
+ SourceLocation EndLoc = RParenLoc;
// cv-qualifier-seq[opt].
DeclSpec DS;
@@ -2395,13 +2555,13 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
if (getLang().CPlusPlus) {
ParseTypeQualifierListOpt(DS, false /*no attributes*/);
if (!DS.getSourceRange().getEnd().isInvalid())
- Loc = DS.getSourceRange().getEnd();
+ EndLoc = DS.getSourceRange().getEnd();
// Parse exception-specification[opt].
if (Tok.is(tok::kw_throw)) {
hasExceptionSpec = true;
ThrowLoc = Tok.getLocation();
- ParseExceptionSpecification(Loc, Exceptions, ExceptionRanges,
+ ParseExceptionSpecification(EndLoc, Exceptions, ExceptionRanges,
hasAnyExceptionSpec);
assert(Exceptions.size() == ExceptionRanges.size() &&
"Produced different number of exception types and ranges.");
@@ -2420,8 +2580,8 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
Exceptions.data(),
ExceptionRanges.data(),
Exceptions.size(),
- LParenLoc, D),
- Loc);
+ LParenLoc, RParenLoc, D),
+ EndLoc);
return;
}
@@ -2440,9 +2600,9 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
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;
@@ -2450,7 +2610,7 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
// function prototype scope, including parameter declarators.
ParseScope PrototypeScope(this,
Scope::FunctionPrototypeScope|Scope::DeclScope);
-
+
bool IsVariadic = false;
SourceLocation EllipsisLoc;
while (1) {
@@ -2459,9 +2619,9 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
EllipsisLoc = ConsumeToken(); // Consume the ellipsis.
break;
}
-
+
SourceLocation DSStart = Tok.getLocation();
-
+
// Parse the declaration-specifiers.
DeclSpec DS;
@@ -2471,7 +2631,7 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
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);
@@ -2483,10 +2643,10 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
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;
@@ -2500,7 +2660,7 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
} 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);
@@ -2521,18 +2681,18 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
// FIXME: Can we use a smart pointer for Toks?
DefArgToks = new CachedTokens;
- if (!ConsumeAndStoreUntil(tok::comma, tok::r_paren, *DefArgToks,
+ if (!ConsumeAndStoreUntil(tok::comma, tok::r_paren, *DefArgToks,
tok::semi, false)) {
delete DefArgToks;
DefArgToks = 0;
Actions.ActOnParamDefaultArgumentError(Param);
} else
- Actions.ActOnParamUnparsedDefaultArgument(Param, EqualLoc,
+ Actions.ActOnParamUnparsedDefaultArgument(Param, EqualLoc,
(*DefArgToks)[1].getLocation());
} else {
// Consume the '='.
ConsumeToken();
-
+
OwningExprResult DefArgResult(ParseAssignmentExpression());
if (DefArgResult.isInvalid()) {
Actions.ActOnParamDefaultArgumentError(Param);
@@ -2544,24 +2704,39 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
}
}
}
-
- ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII,
- ParmDecl.getIdentifierLoc(), Param,
+
+ 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;
-
+ if (Tok.isNot(tok::comma)) {
+ if (Tok.is(tok::ellipsis)) {
+ IsVariadic = true;
+ EllipsisLoc = ConsumeToken(); // Consume the ellipsis.
+
+ if (!getLang().CPlusPlus) {
+ // We have ellipsis without a preceding ',', which is ill-formed
+ // in C. Complain and provide the fix.
+ Diag(EllipsisLoc, diag::err_missing_comma_before_ellipsis)
+ << CodeModificationHint::CreateInsertion(EllipsisLoc, ", ");
+ }
+ }
+
+ break;
+ }
+
// Consume the comma.
ConsumeToken();
}
-
+
// Leave prototype scope.
PrototypeScope.Exit();
-
+
// If we have the closing ')', eat it.
- SourceLocation Loc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ SourceLocation EndLoc = RParenLoc;
DeclSpec DS;
bool hasExceptionSpec = false;
@@ -2573,13 +2748,13 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
// Parse cv-qualifier-seq[opt].
ParseTypeQualifierListOpt(DS, false /*no attributes*/);
if (!DS.getSourceRange().getEnd().isInvalid())
- Loc = DS.getSourceRange().getEnd();
+ EndLoc = DS.getSourceRange().getEnd();
// Parse exception-specification[opt].
if (Tok.is(tok::kw_throw)) {
hasExceptionSpec = true;
ThrowLoc = Tok.getLocation();
- ParseExceptionSpecification(Loc, Exceptions, ExceptionRanges,
+ ParseExceptionSpecification(EndLoc, Exceptions, ExceptionRanges,
hasAnyExceptionSpec);
assert(Exceptions.size() == ExceptionRanges.size() &&
"Produced different number of exception types and ranges.");
@@ -2595,8 +2770,9 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
hasAnyExceptionSpec,
Exceptions.data(),
ExceptionRanges.data(),
- Exceptions.size(), LParenLoc, D),
- Loc);
+ Exceptions.size(),
+ LParenLoc, RParenLoc, D),
+ EndLoc);
}
/// ParseFunctionDeclaratorIdentifierList - While parsing a function declarator
@@ -2612,7 +2788,7 @@ void Parser::ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc,
// 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:
@@ -2626,13 +2802,13 @@ void Parser::ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc,
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);
@@ -2645,7 +2821,7 @@ void Parser::ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc,
// 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;
@@ -2655,7 +2831,7 @@ void Parser::ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc,
Tok.getLocation(),
DeclPtrTy()));
}
-
+
// Eat the identifier.
ConsumeToken();
}
@@ -2672,7 +2848,7 @@ void Parser::ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc,
/*TypeQuals*/0,
/*exception*/false,
SourceLocation(), false, 0, 0, 0,
- LParenLoc, D),
+ LParenLoc, RLoc, D),
RLoc);
}
@@ -2683,14 +2859,15 @@ void Parser::ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc,
/// [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),
+ D.AddTypeInfo(DeclaratorChunk::getArray(0, false, false, 0,
+ StartLoc, EndLoc),
EndLoc);
return;
} else if (Tok.getKind() == tok::numeric_constant &&
@@ -2704,33 +2881,33 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
// 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),
+ D.AddTypeInfo(DeclaratorChunk::getArray(0, false, 0, ExprRes.release(),
+ StartLoc, EndLoc),
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
@@ -2748,7 +2925,7 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
// 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 constant-expression or assignment-expression now (depending
// on dialect).
if (getLang().CPlusPlus)
@@ -2756,7 +2933,7 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
else
NumElements = ParseAssignmentExpression();
}
-
+
// If there was an error parsing the assignment-expression, recover.
if (NumElements.isInvalid()) {
D.setInvalidType(true);
@@ -2770,7 +2947,8 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
// Remember that we parsed a array type, and remember its features.
D.AddTypeInfo(DeclaratorChunk::getArray(DS.getTypeQualifiers(),
StaticLoc.isValid(), isStar,
- NumElements.release(), StartLoc),
+ NumElements.release(),
+ StartLoc, EndLoc),
EndLoc);
}
@@ -2797,7 +2975,7 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
DS.SetRangeEnd(Tok.getLocation());
else
DS.SetRangeEnd(CastRange.getEnd());
-
+
if (isCastExpr) {
if (!CastTy) {
DS.SetTypeSpecError();
@@ -2805,10 +2983,11 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
}
const char *PrevSpec = 0;
+ unsigned DiagID;
// 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;
+ DiagID, CastTy))
+ Diag(StartLoc, DiagID) << PrevSpec;
return;
}
@@ -2819,8 +2998,9 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
}
const char *PrevSpec = 0;
+ unsigned DiagID;
// 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;
+ DiagID, Operand.release()))
+ Diag(StartLoc, DiagID) << PrevSpec;
}
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 373d22f..d381e3e 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -38,7 +38,7 @@ using namespace clang;
///
/// extension-namespace-definition:
/// 'namespace' original-namespace-name '{' namespace-body '}'
-///
+///
/// namespace-alias-definition: [C++ 7.3.2: namespace.alias]
/// 'namespace' identifier '=' qualified-namespace-specifier ';'
///
@@ -46,17 +46,22 @@ Parser::DeclPtrTy Parser::ParseNamespace(unsigned Context,
SourceLocation &DeclEnd) {
assert(Tok.is(tok::kw_namespace) && "Not a namespace!");
SourceLocation NamespaceLoc = ConsumeToken(); // eat the 'namespace'.
+
+ if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteNamespaceDecl(CurScope);
+ ConsumeToken();
+ }
SourceLocation IdentLoc;
IdentifierInfo *Ident = 0;
Token attrTok;
-
+
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)) {
@@ -65,20 +70,20 @@ Parser::DeclPtrTy Parser::ParseNamespace(unsigned Context,
// FIXME: save these somewhere.
AttrList = ParseAttributes();
}
-
+
if (Tok.is(tok::equal)) {
if (AttrList)
Diag(attrTok, diag::err_unexpected_namespace_attributes_alias);
return ParseNamespaceAlias(NamespaceLoc, IdentLoc, Ident, DeclEnd);
}
-
+
if (Tok.isNot(tok::l_brace)) {
- Diag(Tok, Ident ? diag::err_expected_lbrace :
+ Diag(Tok, Ident ? diag::err_expected_lbrace :
diag::err_expected_ident_lbrace);
return DeclPtrTy();
}
-
+
SourceLocation LBrace = ConsumeBrace();
// Enter a scope for the namespace.
@@ -90,10 +95,10 @@ Parser::DeclPtrTy Parser::ParseNamespace(unsigned Context,
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();
@@ -108,16 +113,21 @@ Parser::DeclPtrTy Parser::ParseNamespace(unsigned Context,
/// alias definition.
///
Parser::DeclPtrTy Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc,
- SourceLocation AliasLoc,
+ SourceLocation AliasLoc,
IdentifierInfo *Alias,
SourceLocation &DeclEnd) {
assert(Tok.is(tok::equal) && "Not equal token");
-
+
ConsumeToken(); // eat the '='.
+
+ if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteNamespaceAliasDecl(CurScope);
+ ConsumeToken();
+ }
CXXScopeSpec SS;
// Parse (optional) nested-name-specifier.
- ParseOptionalCXXScopeSpecifier(SS);
+ ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
if (SS.isInvalid() || Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_namespace_name);
@@ -129,13 +139,13 @@ Parser::DeclPtrTy Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc,
// 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,
+
+ return Actions.ActOnNamespaceAliasDef(CurScope, NamespaceLoc, AliasLoc, Alias,
SS, IdentLoc, Ident);
}
@@ -157,18 +167,18 @@ Parser::DeclPtrTy Parser::ParseLinkage(unsigned Context) {
SourceLocation Loc = ConsumeStringToken();
ParseScope LinkageScope(this, Scope::DeclScope);
- DeclPtrTy LinkageSpec
- = Actions.ActOnStartLinkageSpecification(CurScope,
+ DeclPtrTy LinkageSpec
+ = Actions.ActOnStartLinkageSpecification(CurScope,
/*FIXME: */SourceLocation(),
Loc, LangBufPtr, StrSize,
- Tok.is(tok::l_brace)? Tok.getLocation()
+ Tok.is(tok::l_brace)? Tok.getLocation()
: SourceLocation());
if (Tok.isNot(tok::l_brace)) {
ParseDeclarationOrFunctionDefinition();
- return Actions.ActOnFinishLinkageSpecification(CurScope, LinkageSpec,
+ return Actions.ActOnFinishLinkageSpecification(CurScope, LinkageSpec,
SourceLocation());
- }
+ }
SourceLocation LBrace = ConsumeBrace();
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
@@ -188,6 +198,11 @@ Parser::DeclPtrTy Parser::ParseUsingDirectiveOrDeclaration(unsigned Context,
// Eat 'using'.
SourceLocation UsingLoc = ConsumeToken();
+ if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteUsing(CurScope);
+ ConsumeToken();
+ }
+
if (Tok.is(tok::kw_namespace))
// Next token after 'using' is 'namespace' so it must be using-directive
return ParseUsingDirective(Context, UsingLoc, DeclEnd);
@@ -214,9 +229,14 @@ Parser::DeclPtrTy Parser::ParseUsingDirective(unsigned Context,
// Eat 'namespace'.
SourceLocation NamespcLoc = ConsumeToken();
+ if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteUsingDirective(CurScope);
+ ConsumeToken();
+ }
+
CXXScopeSpec SS;
// Parse (optional) nested-name-specifier.
- ParseOptionalCXXScopeSpecifier(SS);
+ ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
AttributeList *AttrList = 0;
IdentifierInfo *NamespcName = 0;
@@ -230,15 +250,15 @@ Parser::DeclPtrTy Parser::ParseUsingDirective(unsigned Context,
// 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,
@@ -259,7 +279,8 @@ Parser::DeclPtrTy Parser::ParseUsingDirective(unsigned Context,
///
Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context,
SourceLocation UsingLoc,
- SourceLocation &DeclEnd) {
+ SourceLocation &DeclEnd,
+ AccessSpecifier AS) {
CXXScopeSpec SS;
bool IsTypeName;
@@ -272,7 +293,7 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context,
IsTypeName = false;
// Parse nested-name-specifier.
- ParseOptionalCXXScopeSpecifier(SS);
+ ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
AttributeList *AttrList = 0;
@@ -282,15 +303,17 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context,
return DeclPtrTy();
}
if (Tok.is(tok::annot_template_id)) {
- Diag(Tok, diag::err_unexpected_template_spec_in_using);
+ // C++0x N2914 [namespace.udecl]p5:
+ // A using-declaration shall not name a template-id.
+ Diag(Tok, diag::err_using_decl_can_not_refer_to_template_spec);
SkipUntil(tok::semi);
return DeclPtrTy();
}
-
+
IdentifierInfo *TargetName = 0;
OverloadedOperatorKind Op = OO_None;
SourceLocation IdentLoc;
-
+
if (Tok.is(tok::kw_operator)) {
IdentLoc = Tok.getLocation();
@@ -312,17 +335,17 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context,
SkipUntil(tok::semi);
return DeclPtrTy();
}
-
+
// 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.ActOnUsingDeclaration(CurScope, UsingLoc, SS,
+ return Actions.ActOnUsingDeclaration(CurScope, AS, UsingLoc, SS,
IdentLoc, TargetName, Op,
AttrList, IsTypeName);
}
@@ -335,12 +358,12 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context,
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());
@@ -348,7 +371,7 @@ Parser::DeclPtrTy Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
SkipUntil(tok::semi);
return DeclPtrTy();
}
-
+
if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "", tok::semi))
return DeclPtrTy();
@@ -357,17 +380,17 @@ Parser::DeclPtrTy Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
SkipUntil(tok::semi);
return DeclPtrTy();
}
-
+
OwningExprResult AssertMessage(ParseStringLiteralExpression());
- if (AssertMessage.isInvalid())
+ 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),
+ return Actions.ActOnStaticAssertDeclaration(StaticAssertLoc, move(AssertExpr),
move(AssertMessage));
}
@@ -380,15 +403,15 @@ void Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
SourceLocation StartLoc = ConsumeToken();
SourceLocation LParenLoc = Tok.getLocation();
-
- if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after,
+
+ if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after,
"decltype")) {
SkipUntil(tok::r_paren);
return;
}
-
+
// Parse the expression
-
+
// C++0x [dcl.type.simple]p4:
// The operand of the decltype specifier is an unevaluated operand.
EnterExpressionEvaluationContext Unevaluated(Actions,
@@ -398,22 +421,23 @@ void Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
SkipUntil(tok::r_paren);
return;
}
-
+
// Match the ')'
SourceLocation RParenLoc;
if (Tok.is(tok::r_paren))
RParenLoc = ConsumeParen();
else
MatchRHSPunctuation(tok::r_paren, LParenLoc);
-
+
if (RParenLoc.isInvalid())
return;
const char *PrevSpec = 0;
+ unsigned DiagID;
// Check for duplicate type specifiers (e.g. "int decltype(a)").
- if (DS.SetTypeSpecType(DeclSpec::TST_decltype, StartLoc, PrevSpec,
- Result.release()))
- Diag(StartLoc, diag::err_invalid_decl_spec_combination) << PrevSpec;
+ if (DS.SetTypeSpecType(DeclSpec::TST_decltype, StartLoc, PrevSpec,
+ DiagID, Result.release()))
+ Diag(StartLoc, DiagID) << PrevSpec;
}
/// ParseClassName - Parse a C++ class-name, which names a class. Note
@@ -425,12 +449,13 @@ void Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
/// class-name: [C++ 9.1]
/// identifier
/// simple-template-id
-///
+///
Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation,
- const CXXScopeSpec *SS) {
+ const CXXScopeSpec *SS,
+ bool DestrExpected) {
// Check whether we have a template-id that names a type.
if (Tok.is(tok::annot_template_id)) {
- TemplateIdAnnotation *TemplateId
+ TemplateIdAnnotation *TemplateId
= static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
if (TemplateId->Kind == TNK_Type_template) {
AnnotateTemplateIdTokenAsType(SS);
@@ -454,10 +479,12 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation,
}
// We have an identifier; check whether it is actually a type.
- TypeTy *Type = Actions.getTypeName(*Tok.getIdentifierInfo(),
- Tok.getLocation(), CurScope, SS);
+ TypeTy *Type = Actions.getTypeName(*Tok.getIdentifierInfo(),
+ Tok.getLocation(), CurScope, SS,
+ true);
if (!Type) {
- Diag(Tok, diag::err_expected_class_name);
+ Diag(Tok, DestrExpected ? diag::err_destructor_class_name
+ : diag::err_expected_class_name);
return true;
}
@@ -480,9 +507,9 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation,
/// 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
+/// [GNU] class-key attributes[opt] nested-name-specifier
/// identifier base-clause[opt]
-/// [GNU] class-key attributes[opt] nested-name-specifier[opt]
+/// [GNU] class-key attributes[opt] nested-name-specifier[opt]
/// simple-template-id base-clause[opt]
/// class-key:
/// 'class'
@@ -490,9 +517,9 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation,
/// '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
+/// 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:
@@ -520,6 +547,12 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
TagType = DeclSpec::TST_union;
}
+ if (Tok.is(tok::code_completion)) {
+ // Code completion for a struct, class, or union name.
+ Actions.CodeCompleteTag(CurScope, TagType);
+ ConsumeToken();
+ }
+
AttributeList *Attr = 0;
// If attributes exist after tag, parse them.
if (Tok.is(tok::kw___attribute))
@@ -528,10 +561,31 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// If declspecs exist after tag, parse them.
if (Tok.is(tok::kw___declspec))
Attr = ParseMicrosoftDeclSpec(Attr);
-
+
+ if (TagType == DeclSpec::TST_struct && Tok.is(tok::kw___is_pod)) {
+ // GNU libstdc++ 4.2 uses __is_pod as the name of a struct template, but
+ // __is_pod is a keyword in GCC >= 4.3. Therefore, when we see the
+ // token sequence "struct __is_pod", make __is_pod into a normal
+ // identifier rather than a keyword, to allow libstdc++ 4.2 to work
+ // properly.
+ Tok.getIdentifierInfo()->setTokenID(tok::identifier);
+ Tok.setKind(tok::identifier);
+ }
+
+ if (TagType == DeclSpec::TST_struct && Tok.is(tok::kw___is_empty)) {
+ // GNU libstdc++ 4.2 uses __is_empty as the name of a struct template, but
+ // __is_empty is a keyword in GCC >= 4.3. Therefore, when we see the
+ // token sequence "struct __is_empty", make __is_empty into a normal
+ // identifier rather than a keyword, to allow libstdc++ 4.2 to work
+ // properly.
+ Tok.getIdentifierInfo()->setTokenID(tok::identifier);
+ Tok.setKind(tok::identifier);
+ }
+
// Parse the (optional) nested-name-specifier.
CXXScopeSpec SS;
- if (getLang().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS))
+ if (getLang().CPlusPlus &&
+ ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true))
if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id))
Diag(Tok, diag::err_expected_ident);
@@ -556,7 +610,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
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();
@@ -564,19 +618,33 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
}
}
- // There are three options here. If we have 'struct foo;', then
- // this is a forward declaration. If we have 'struct foo {...' or
+ // There are four options here. If we have 'struct foo;', then this
+ // is either a forward declaration or a friend declaration, which
+ // have to be treated differently. 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;
+ Action::TagUseKind TUK;
+ if (Tok.is(tok::l_brace) || (getLang().CPlusPlus && Tok.is(tok::colon))) {
+ if (DS.isFriendSpecified()) {
+ // C++ [class.friend]p2:
+ // A class shall not be defined in a friend declaration.
+ Diag(Tok.getLocation(), diag::err_friend_decl_defines_class)
+ << SourceRange(DS.getFriendSpecLoc());
+
+ // Skip everything up to the semicolon, so that this looks like a proper
+ // friend class (or template thereof) declaration.
+ SkipUntil(tok::semi, true, true);
+ TUK = Action::TUK_Friend;
+ } else {
+ // Okay, this is a class definition.
+ TUK = Action::TUK_Definition;
+ }
+ } else if (Tok.is(tok::semi))
+ TUK = DS.isFriendSpecified() ? Action::TUK_Friend : Action::TUK_Declaration;
else
- TK = Action::TK_Reference;
+ TUK = Action::TUK_Reference;
- if (!Name && !TemplateId && TK != Action::TK_Definition) {
+ if (!Name && !TemplateId && TUK != Action::TUK_Definition) {
// We have a declaration or reference to an anonymous class.
Diag(StartLoc, diag::err_anon_type_definition)
<< DeclSpec::getSpecifierName(TagType);
@@ -590,36 +658,49 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
}
// Create the tag portion of the class or class template.
- Action::DeclResult TagOrTempResult;
+ Action::DeclResult TagOrTempResult = true; // invalid
+ Action::TypeResult TypeResult = true; // invalid
TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams;
- // FIXME: When TK == TK_Reference and we have a template-id, we need
+ // FIXME: When TUK == TUK_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) {
+ if (TemplateId) {
// Explicit specialization, class template partial specialization,
// or explicit instantiation.
- ASTTemplateArgsPtr TemplateArgsPtr(Actions,
+ ASTTemplateArgsPtr TemplateArgsPtr(Actions,
TemplateId->getTemplateArgs(),
TemplateId->getTemplateArgIsType(),
TemplateId->NumArgs);
if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation &&
- TK == Action::TK_Declaration) {
+ TUK == Action::TUK_Declaration) {
// This is an explicit instantiation of a class template.
TagOrTempResult
- = Actions.ActOnExplicitInstantiation(CurScope,
- TemplateInfo.TemplateLoc,
+ = Actions.ActOnExplicitInstantiation(CurScope,
+ TemplateInfo.ExternLoc,
+ TemplateInfo.TemplateLoc,
TagType,
- StartLoc,
+ StartLoc,
SS,
- TemplateTy::make(TemplateId->Template),
- TemplateId->TemplateNameLoc,
- TemplateId->LAngleLoc,
+ TemplateTy::make(TemplateId->Template),
+ TemplateId->TemplateNameLoc,
+ TemplateId->LAngleLoc,
TemplateArgsPtr,
TemplateId->getTemplateArgLocations(),
- TemplateId->RAngleLoc,
+ TemplateId->RAngleLoc,
Attr);
+ } else if (TUK == Action::TUK_Reference) {
+ TypeResult
+ = Actions.ActOnTemplateIdType(TemplateTy::make(TemplateId->Template),
+ TemplateId->TemplateNameLoc,
+ TemplateId->LAngleLoc,
+ TemplateArgsPtr,
+ TemplateId->getTemplateArgLocations(),
+ TemplateId->RAngleLoc);
+
+ TypeResult = Actions.ActOnTagTemplateIdType(TypeResult, TUK,
+ TagType, StartLoc);
} else {
// This is an explicit specialization or a class template
// partial specialization.
@@ -634,11 +715,11 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// 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");
+ assert(TUK == Action::TUK_Definition && "Expected a definition here");
- SourceLocation LAngleLoc
+ SourceLocation LAngleLoc
= PP.getLocForEndOfToken(TemplateInfo.TemplateLoc);
- Diag(TemplateId->TemplateNameLoc,
+ Diag(TemplateId->TemplateNameLoc,
diag::err_explicit_instantiation_with_definition)
<< SourceRange(TemplateInfo.TemplateLoc)
<< CodeModificationHint::CreateInsertion(LAngleLoc, "<>");
@@ -647,60 +728,64 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// "template<>", so that we treat this construct as a class
// template specialization.
FakedParamLists.push_back(
- Actions.ActOnTemplateParameterList(0, SourceLocation(),
+ Actions.ActOnTemplateParameterList(0, SourceLocation(),
TemplateInfo.TemplateLoc,
- LAngleLoc,
- 0, 0,
+ LAngleLoc,
+ 0, 0,
LAngleLoc));
TemplateParams = &FakedParamLists;
}
// Build the class template specialization.
TagOrTempResult
- = Actions.ActOnClassTemplateSpecialization(CurScope, TagType, TK,
+ = Actions.ActOnClassTemplateSpecialization(CurScope, TagType, TUK,
StartLoc, SS,
- TemplateTy::make(TemplateId->Template),
- TemplateId->TemplateNameLoc,
- TemplateId->LAngleLoc,
+ TemplateTy::make(TemplateId->Template),
+ TemplateId->TemplateNameLoc,
+ TemplateId->LAngleLoc,
TemplateArgsPtr,
TemplateId->getTemplateArgLocations(),
- TemplateId->RAngleLoc,
+ TemplateId->RAngleLoc,
Attr,
- Action::MultiTemplateParamsArg(Actions,
+ 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) {
+ TUK == Action::TUK_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,
+ = Actions.ActOnExplicitInstantiation(CurScope,
+ TemplateInfo.ExternLoc,
+ TemplateInfo.TemplateLoc,
+ TagType, StartLoc, SS, Name,
NameLoc, Attr);
} else {
if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation &&
- TK == Action::TK_Definition) {
+ TUK == Action::TUK_Definition) {
// FIXME: Diagnose this particular error.
}
+ bool IsDependent = false;
+
// Declaration or definition of a class type
- TagOrTempResult = Actions.ActOnTag(CurScope, TagType, TK, StartLoc, SS,
- Name, NameLoc, Attr, AS, Owned);
+ TagOrTempResult = Actions.ActOnTag(CurScope, TagType, TUK, StartLoc, SS,
+ Name, NameLoc, Attr, AS,
+ Action::MultiTemplateParamsArg(Actions,
+ TemplateParams? &(*TemplateParams)[0] : 0,
+ TemplateParams? TemplateParams->size() : 0),
+ Owned, IsDependent);
+
+ // If ActOnTag said the type was dependent, try again with the
+ // less common call.
+ if (IsDependent)
+ TypeResult = Actions.ActOnDependentTag(CurScope, TagType, TUK,
+ SS, Name, StartLoc, NameLoc);
}
// Parse the optional base clause (C++ only).
@@ -713,28 +798,33 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
ParseCXXMemberSpecification(StartLoc, TagType, TagOrTempResult.get());
else
ParseStructUnionBody(StartLoc, TagType, TagOrTempResult.get());
- else if (TK == Action::TK_Definition) {
+ else if (TUK == Action::TUK_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()) {
+ void *Result;
+ if (!TypeResult.isInvalid()) {
+ TagType = DeclSpec::TST_typename;
+ Result = TypeResult.get();
+ Owned = false;
+ } else if (!TagOrTempResult.isInvalid()) {
+ Result = TagOrTempResult.get().getAs<void>();
+ } else {
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());
+
+ const char *PrevSpec = 0;
+ unsigned DiagID;
+
+ if (DS.SetTypeSpecType(TagType, StartLoc, PrevSpec, DiagID,
+ Result, Owned))
+ Diag(StartLoc, DiagID) << PrevSpec;
}
-/// ParseBaseClause - Parse the base-clause of a C++ class [C++ class.derived].
+/// ParseBaseClause - Parse the base-clause of a C++ class [C++ class.derived].
///
/// base-clause : [C++ class.derived]
/// ':' base-specifier-list
@@ -763,7 +853,7 @@ void Parser::ParseBaseClause(DeclPtrTy ClassDecl) {
// If the next token is a comma, consume it and keep reading
// base-specifiers.
if (Tok.isNot(tok::comma)) break;
-
+
// Consume the comma.
ConsumeToken();
}
@@ -797,7 +887,7 @@ Parser::BaseResult Parser::ParseBaseSpecifier(DeclPtrTy ClassDecl) {
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)) {
@@ -813,7 +903,7 @@ Parser::BaseResult Parser::ParseBaseSpecifier(DeclPtrTy ClassDecl) {
// Parse optional '::' and optional nested-name-specifier.
CXXScopeSpec SS;
- ParseOptionalCXXScopeSpecifier(SS);
+ ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true);
// The location of the base class itself.
SourceLocation BaseLoc = Tok.getLocation();
@@ -823,10 +913,10 @@ Parser::BaseResult Parser::ParseBaseSpecifier(DeclPtrTy ClassDecl) {
TypeResult BaseType = ParseClassName(EndLocation, &SS);
if (BaseType.isInvalid())
return true;
-
- // Find the complete source range for the base-specifier.
+
+ // 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,
@@ -840,8 +930,7 @@ Parser::BaseResult Parser::ParseBaseSpecifier(DeclPtrTy ClassDecl) {
/// 'private'
/// 'protected'
/// 'public'
-AccessSpecifier Parser::getAccessSpecifierIfPresent() const
-{
+AccessSpecifier Parser::getAccessSpecifierIfPresent() const {
switch (Tok.getKind()) {
default: return AS_none;
case tok::kw_private: return AS_private;
@@ -850,6 +939,40 @@ AccessSpecifier Parser::getAccessSpecifierIfPresent() const
}
}
+void Parser::HandleMemberFunctionDefaultArgs(Declarator& DeclaratorInfo,
+ DeclPtrTy ThisDecl) {
+ // 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();
+ LateMethod->TemplateScope = CurScope->isTemplateParamScope();
+
+ // 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));
+ }
+ }
+}
+
/// ParseCXXClassMemberDeclaration - Parse a C++ class member declaration.
///
/// member-declaration:
@@ -876,17 +999,21 @@ AccessSpecifier Parser::getAccessSpecifierIfPresent() const
/// constant-initializer:
/// '=' constant-expression
///
-void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS) {
+void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
+ const ParsedTemplateInfo &TemplateInfo) {
// static_assert-declaration
if (Tok.is(tok::kw_static_assert)) {
+ // FIXME: Check for templates
SourceLocation DeclEnd;
ParseStaticAssertDeclaration(DeclEnd);
return;
}
-
+
if (Tok.is(tok::kw_template)) {
+ assert(!TemplateInfo.TemplateParams &&
+ "Nested template improperly parsed?");
SourceLocation DeclEnd;
- ParseDeclarationStartingWithTemplate(Declarator::MemberContext, DeclEnd,
+ ParseDeclarationStartingWithTemplate(Declarator::MemberContext, DeclEnd,
AS);
return;
}
@@ -896,10 +1023,12 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS) {
// __extension__ silences extension warnings in the subexpression.
ExtensionRAIIObject O(Diags); // Use RAII to do this.
ConsumeToken();
- return ParseCXXClassMemberDeclaration(AS);
+ return ParseCXXClassMemberDeclaration(AS, TemplateInfo);
}
if (Tok.is(tok::kw_using)) {
+ // FIXME: Check for template aliases
+
// Eat 'using'.
SourceLocation UsingLoc = ConsumeToken();
@@ -910,7 +1039,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS) {
else {
SourceLocation DeclEnd;
// Otherwise, it must be using-declaration.
- ParseUsingDeclaration(Declarator::MemberContext, UsingLoc, DeclEnd);
+ ParseUsingDeclaration(Declarator::MemberContext, UsingLoc, DeclEnd, AS);
}
return;
}
@@ -919,24 +1048,16 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS) {
// decl-specifier-seq:
// Parse the common declaration-specifiers piece.
DeclSpec DS;
- ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS);
+ ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class);
+
+ Action::MultiTemplateParamsArg TemplateParams(Actions,
+ TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->data() : 0,
+ TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->size() : 0);
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;
- }
+ Actions.ParsedFreeStandingDeclSpec(CurScope, DS);
+ return;
}
Declarator DeclaratorInfo(DS, Declarator::MemberContext);
@@ -974,7 +1095,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS) {
return;
}
- ParseCXXInlineMethodDef(AS, DeclaratorInfo);
+ ParseCXXInlineMethodDef(AS, DeclaratorInfo, TemplateInfo);
return;
}
}
@@ -1001,7 +1122,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS) {
if (BitfieldSize.isInvalid())
SkipUntil(tok::comma, true, true);
}
-
+
// pure-specifier:
// '= 0'
//
@@ -1034,62 +1155,44 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS) {
// 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);
+
+ DeclPtrTy ThisDecl;
+ if (DS.isFriendSpecified()) {
+ // TODO: handle initializers, bitfields, 'delete'
+ ThisDecl = Actions.ActOnFriendFunctionDecl(CurScope, DeclaratorInfo,
+ /*IsDefinition*/ false,
+ move(TemplateParams));
+ } else {
+ ThisDecl = Actions.ActOnCXXMemberDeclarator(CurScope, AS,
+ DeclaratorInfo,
+ move(TemplateParams),
+ BitfieldSize.release(),
+ Init.release(),
+ Deleted);
+ }
if (ThisDecl)
DeclsInGroup.push_back(ThisDecl);
if (DeclaratorInfo.isFunctionDeclarator() &&
- DeclaratorInfo.getDeclSpec().getStorageClassSpec()
+ 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));
- }
- }
+ HandleMemberFunctionDefaultArgs(DeclaratorInfo, 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.
DeclaratorInfo.clear();
BitfieldSize = 0;
Init = 0;
Deleted = false;
-
+
// Attributes are only allowed on the second declarator.
if (Tok.is(tok::kw___attribute)) {
SourceLocation Loc;
@@ -1131,11 +1234,11 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
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() ||
+ bool TopLevelClass = ClassStack.empty() ||
CurScope->isInCXXInlineMethodScope();
// Enter a scope for the class.
@@ -1163,7 +1266,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
// 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);
@@ -1180,12 +1283,14 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
continue;
}
+ // FIXME: Make sure we don't have a template here.
+
// 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))
@@ -1213,7 +1318,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
ParsingDef.Pop();
ClassScope.Exit();
- Actions.ActOnTagFinishDefinition(CurScope, TagDecl);
+ Actions.ActOnTagFinishDefinition(CurScope, TagDecl, RBraceLoc);
}
/// ParseConstructorInitializer - Parse a C++ constructor initializer,
@@ -1231,19 +1336,19 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
/// };
/// @endcode
///
-/// [C++] ctor-initializer:
-/// ':' mem-initializer-list
+/// [C++] ctor-initializer:
+/// ':' mem-initializer-list
///
-/// [C++] mem-initializer-list:
-/// mem-initializer
-/// mem-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())
@@ -1261,7 +1366,7 @@ void Parser::ParseConstructorInitializer(DeclPtrTy ConstructorDecl) {
}
} while (true);
- Actions.ActOnMemInitializers(ConstructorDecl, ColonLoc,
+ Actions.ActOnMemInitializers(ConstructorDecl, ColonLoc,
MemInitializers.data(), MemInitializers.size());
}
@@ -1272,14 +1377,14 @@ void Parser::ParseConstructorInitializer(DeclPtrTy ConstructorDecl) {
///
/// [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) {
// parse '::'[opt] nested-name-specifier[opt]
CXXScopeSpec SS;
- ParseOptionalCXXScopeSpecifier(SS);
+ ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
TypeTy *TemplateTypeTy = 0;
if (Tok.is(tok::annot_template_id)) {
TemplateIdAnnotation *TemplateId
@@ -1295,7 +1400,7 @@ Parser::MemInitResult Parser::ParseMemInitializer(DeclPtrTy ConstructorDecl) {
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.is(tok::identifier) ? Tok.getIdentifierInfo() : 0;
@@ -1331,7 +1436,7 @@ Parser::MemInitResult Parser::ParseMemInitializer(DeclPtrTy ConstructorDecl) {
/// exception-specification:
/// 'throw' '(' type-id-list [opt] ')'
/// [MS] 'throw' '(' '...' ')'
-///
+///
/// type-id-list:
/// type-id
/// type-id-list ',' type-id
@@ -1343,9 +1448,9 @@ bool Parser::ParseExceptionSpecification(SourceLocation &EndLoc,
&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";
}
@@ -1384,7 +1489,7 @@ bool Parser::ParseExceptionSpecification(SourceLocation &EndLoc,
/// 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()) &&
+ assert((TopLevelClass || !ClassStack.empty()) &&
"Nested class without outer class");
ClassStack.push(new ParsingClass(ClassDecl, TopLevelClass));
}
@@ -1408,7 +1513,7 @@ void Parser::DeallocateParsedClasses(Parser::ParsingClass *Class) {
/// false otherwise.
void Parser::PopParsingClass() {
assert(!ClassStack.empty() && "Mismatched push/pop for class parsing");
-
+
ParsingClass *Victim = ClassStack.top();
ClassStack.pop();
if (Victim->TopLevelClass) {
@@ -1416,7 +1521,7 @@ void Parser::PopParsingClass() {
// 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() &&
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index cd7618f..72e30e3 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -55,7 +55,7 @@ namespace prec {
/// getBinOpPrecedence - Return the precedence of the specified binary operator
/// token. This returns:
///
-static prec::Level getBinOpPrecedence(tok::TokenKind Kind,
+static prec::Level getBinOpPrecedence(tok::TokenKind Kind,
bool GreaterThanIsOperator,
bool CPlusPlus0x) {
switch (Kind) {
@@ -67,7 +67,7 @@ static prec::Level getBinOpPrecedence(tok::TokenKind Kind,
if (GreaterThanIsOperator)
return prec::Relational;
return prec::Unknown;
-
+
case tok::greatergreater:
// C++0x [temp.names]p3:
//
@@ -200,13 +200,18 @@ static prec::Level getBinOpPrecedence(tok::TokenKind Kind,
/// expression ',' assignment-expression
///
Parser::OwningExprResult Parser::ParseExpression() {
+ if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteOrdinaryName(CurScope);
+ ConsumeToken();
+ }
+
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.
+/// 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.
@@ -277,11 +282,11 @@ Parser::ParseAssignmentExprWithObjCMessageExprStart(SourceLocation LBracLoc,
Parser::OwningExprResult Parser::ParseConstantExpression() {
// C++ [basic.def.odr]p2:
- // An expression is potentially evaluated unless it appears where an
+ // An expression is potentially evaluated unless it appears where an
// integral constant expression is required (see 5.19) [...].
EnterExpressionEvaluationContext Unevaluated(Actions,
Action::Unevaluated);
-
+
OwningExprResult LHS(ParseCastExpression(false));
if (LHS.isInvalid()) return move(LHS);
@@ -292,7 +297,7 @@ Parser::OwningExprResult Parser::ParseConstantExpression() {
/// LHS and has a precedence of at least MinPrec.
Parser::OwningExprResult
Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) {
- unsigned NextTokPrec = getBinOpPrecedence(Tok.getKind(),
+ unsigned NextTokPrec = getBinOpPrecedence(Tok.getKind(),
GreaterThanIsOperator,
getLang().CPlusPlus0x);
SourceLocation ColonLoc;
@@ -407,11 +412,13 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) {
/// due to member pointers.
///
Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
- bool isAddressOfOperand) {
+ bool isAddressOfOperand,
+ bool parseParenAsExprList){
bool NotCastExpr;
OwningExprResult Res = ParseCastExpression(isUnaryExpression,
isAddressOfOperand,
- NotCastExpr);
+ NotCastExpr,
+ parseParenAsExprList);
if (NotCastExpr)
Diag(Tok, diag::err_expected_expression);
return move(Res);
@@ -463,10 +470,10 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
/// assign-expr ')'
/// [GNU] '__builtin_types_compatible_p' '(' type-name ',' type-name ')'
/// [GNU] '__null'
-/// [OBJC] '[' objc-message-expr ']'
+/// [OBJC] '[' objc-message-expr ']'
/// [OBJC] '@selector' '(' objc-selector-arg ')'
-/// [OBJC] '@protocol' '(' identifier ')'
-/// [OBJC] '@encode' '(' type-name ')'
+/// [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]
@@ -530,11 +537,12 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
///
Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
bool isAddressOfOperand,
- bool &NotCastExpr) {
+ bool &NotCastExpr,
+ bool parseParenAsExprList){
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
@@ -555,9 +563,9 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
SourceLocation LParenLoc = Tok.getLocation();
SourceLocation RParenLoc;
Res = ParseParenExpression(ParenExprType, false/*stopIfCastExr*/,
- CastTy, RParenLoc);
+ parseParenAsExprList, CastTy, RParenLoc);
if (Res.isInvalid()) return move(Res);
-
+
switch (ParenExprType) {
case SimpleExpr: break; // Nothing else to do.
case CompoundStmt: break; // Nothing else to do.
@@ -605,23 +613,23 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
}
// Support 'Class.property' notation.
- // We don't use isTokObjCMessageIdentifierReceiver(), since it allows
+ // We don't use isTokObjCMessageIdentifierReceiver(), since it allows
// 'super' (which is inappropriate here).
- if (getLang().ObjC1 &&
- Actions.getTypeName(*Tok.getIdentifierInfo(),
+ 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.
@@ -739,6 +747,8 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw_char:
case tok::kw_wchar_t:
+ case tok::kw_char16_t:
+ case tok::kw_char32_t:
case tok::kw_bool:
case tok::kw_short:
case tok::kw_int:
@@ -794,7 +804,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
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();
@@ -810,9 +820,12 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw___is_class:
case tok::kw___is_enum:
case tok::kw___is_union:
+ case tok::kw___is_empty:
case tok::kw___is_polymorphic:
case tok::kw___is_abstract:
case tok::kw___has_trivial_constructor:
+ case tok::kw___has_trivial_copy:
+ case tok::kw___has_trivial_assign:
case tok::kw___has_trivial_destructor:
return ParseUnaryTypeTrait();
@@ -826,7 +839,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
// These can be followed by postfix-expr pieces.
if (getLang().ObjC1)
return ParsePostfixExpressionSuffix(ParseObjCMessageExpression());
- // FALL THROUGH.
+ // FALL THROUGH.
default:
NotCastExpr = true;
return ExprError();
@@ -886,8 +899,14 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) {
Loc = ConsumeParen();
+ if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteCall(CurScope, LHS.get(), 0, 0);
+ ConsumeToken();
+ }
+
if (Tok.isNot(tok::r_paren)) {
- if (ParseExpressionList(ArgExprs, CommaLocs)) {
+ if (ParseExpressionList(ArgExprs, CommaLocs, &Action::CodeCompleteCall,
+ LHS.get())) {
SkipUntil(tok::r_paren);
return ExprError();
}
@@ -898,7 +917,7 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) {
MatchRHSPunctuation(tok::r_paren, Loc);
return ExprError();
}
-
+
if (!LHS.isInvalid()) {
assert((ArgExprs.size() == 0 || ArgExprs.size()-1 == CommaLocs.size())&&
"Unexpected number of commas!");
@@ -906,33 +925,117 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) {
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
+ case tok::arrow:
+ case tok::period: {
+ // postfix-expression: p-e '->' template[opt] id-expression
+ // postfix-expression: p-e '.' template[opt] id-expression
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();
+ CXXScopeSpec SS;
+ Action::TypeTy *ObjectType = 0;
+ if (getLang().CPlusPlus && !LHS.isInvalid()) {
+ LHS = Actions.ActOnStartCXXMemberReference(CurScope, move(LHS),
+ OpLoc, OpKind, ObjectType);
+ if (LHS.isInvalid())
+ break;
+ ParseOptionalCXXScopeSpecifier(SS, ObjectType, false);
}
- if (!LHS.isInvalid()) {
- LHS = Actions.ActOnMemberReferenceExpr(CurScope, move(LHS), OpLoc,
- OpKind, Tok.getLocation(),
- *Tok.getIdentifierInfo(),
- ObjCImpDecl);
+ if (Tok.is(tok::code_completion)) {
+ // Code completion for a member access expression.
+ Actions.CodeCompleteMemberReferenceExpr(CurScope, LHS.get(),
+ OpLoc, OpKind == tok::arrow);
+
+ ConsumeToken();
+ }
+
+ if (Tok.is(tok::identifier)) {
+ if (!LHS.isInvalid())
+ LHS = Actions.ActOnMemberReferenceExpr(CurScope, move(LHS), OpLoc,
+ OpKind, Tok.getLocation(),
+ *Tok.getIdentifierInfo(),
+ ObjCImpDecl, &SS);
+ ConsumeToken();
+ } else if (getLang().CPlusPlus && Tok.is(tok::tilde)) {
+ // We have a C++ pseudo-destructor or a destructor call, e.g., t.~T()
+
+ // Consume the tilde.
+ ConsumeToken();
+
+ if (!Tok.is(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident);
+ return ExprError();
+ }
+
+ if (!LHS.isInvalid())
+ LHS = Actions.ActOnDestructorReferenceExpr(CurScope, move(LHS),
+ OpLoc, OpKind,
+ Tok.getLocation(),
+ Tok.getIdentifierInfo(),
+ SS,
+ NextToken().is(tok::l_paren));
+ ConsumeToken();
+ } else if (getLang().CPlusPlus && Tok.is(tok::kw_operator)) {
+ // We have a reference to a member operator, e.g., t.operator int or
+ // t.operator+.
+ SourceLocation OperatorLoc = Tok.getLocation();
+
+ if (OverloadedOperatorKind Op = TryParseOperatorFunctionId()) {
+ if (!LHS.isInvalid())
+ LHS = Actions.ActOnOverloadedOperatorReferenceExpr(CurScope,
+ move(LHS), OpLoc,
+ OpKind,
+ OperatorLoc,
+ Op, &SS);
+ // TryParseOperatorFunctionId already consumed our token, so
+ // don't bother
+ } else if (TypeTy *ConvType = ParseConversionFunctionId()) {
+ if (!LHS.isInvalid())
+ LHS = Actions.ActOnConversionOperatorReferenceExpr(CurScope,
+ move(LHS), OpLoc,
+ OpKind,
+ OperatorLoc,
+ ConvType, &SS);
+ } else {
+ // Don't emit a diagnostic; ParseConversionFunctionId does it for us
+ return ExprError();
+ }
+ } else if (getLang().CPlusPlus && Tok.is(tok::annot_template_id)) {
+ // We have a reference to a member template along with explicitly-
+ // specified template arguments, e.g., t.f<int>.
+ TemplateIdAnnotation *TemplateId
+ = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+ if (!LHS.isInvalid()) {
+ ASTTemplateArgsPtr TemplateArgsPtr(Actions,
+ TemplateId->getTemplateArgs(),
+ TemplateId->getTemplateArgIsType(),
+ TemplateId->NumArgs);
+
+ LHS = Actions.ActOnMemberTemplateIdReferenceExpr(CurScope, move(LHS),
+ OpLoc, OpKind, SS,
+ TemplateTy::make(TemplateId->Template),
+ TemplateId->TemplateNameLoc,
+ TemplateId->LAngleLoc,
+ TemplateArgsPtr,
+ TemplateId->getTemplateArgLocations(),
+ TemplateId->RAngleLoc);
+ }
+ ConsumeToken();
+ } else {
+ Diag(Tok, diag::err_expected_ident);
+ return ExprError();
}
- 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(),
+ LHS = Actions.ActOnPostfixUnaryOp(CurScope, Tok.getLocation(),
Tok.getKind(), move(LHS));
}
ConsumeToken();
@@ -963,13 +1066,13 @@ Parser::ParseExprAfterTypeofSizeofAlignof(const Token &OpTok,
bool &isCastExpr,
TypeTy *&CastTy,
SourceRange &CastRange) {
-
- assert((OpTok.is(tok::kw_typeof) || OpTok.is(tok::kw_sizeof) ||
+
+ 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;
@@ -977,9 +1080,9 @@ Parser::ParseExprAfterTypeofSizeofAlignof(const Token &OpTok,
Diag(Tok,diag::err_expected_lparen_after_id) << OpTok.getIdentifierInfo();
return ExprError();
}
-
+
// C++0x [expr.sizeof]p1:
- // [...] The operand is either an expression, which is an unevaluated
+ // [...] The operand is either an expression, which is an unevaluated
// operand (Clause 5) [...]
//
// The GNU typeof and alignof extensions also behave as unevaluated
@@ -994,16 +1097,16 @@ Parser::ParseExprAfterTypeofSizeofAlignof(const Token &OpTok,
// expression.
ParenParseOption ExprType = CastExpr;
SourceLocation LParenLoc = Tok.getLocation(), RParenLoc;
-
+
// C++0x [expr.sizeof]p1:
- // [...] The operand is either an expression, which is an unevaluated
+ // [...] The operand is either an expression, which is an unevaluated
// operand (Clause 5) [...]
//
// The GNU typeof and alignof extensions also behave as unevaluated
// operands.
EnterExpressionEvaluationContext Unevaluated(Actions,
Action::Unevaluated);
- Operand = ParseParenExpression(ExprType, true/*stopIfCastExpr*/,
+ Operand = ParseParenExpression(ExprType, true/*stopIfCastExpr*/, false,
CastTy, RParenLoc);
CastRange = SourceRange(LParenLoc, RParenLoc);
@@ -1014,7 +1117,7 @@ Parser::ParseExprAfterTypeofSizeofAlignof(const Token &OpTok,
return ExprEmpty();
}
- // If this is a parenthesized expression, it is the start of a
+ // 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));
@@ -1039,7 +1142,7 @@ Parser::OwningExprResult Parser::ParseSizeofAlignofExpression() {
"Not a sizeof/alignof expression!");
Token OpTok = Tok;
ConsumeToken();
-
+
bool isCastExpr;
TypeTy *CastTy;
SourceRange CastRange;
@@ -1071,7 +1174,7 @@ Parser::OwningExprResult Parser::ParseSizeofAlignofExpression() {
/// [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
@@ -1123,7 +1226,7 @@ Parser::OwningExprResult Parser::ParseBuiltinPrimaryExpression() {
SkipUntil(tok::r_paren);
return ExprError();
}
-
+
if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren))
return ExprError();
@@ -1179,8 +1282,8 @@ Parser::OwningExprResult Parser::ParseBuiltinPrimaryExpression() {
} else if (Ty.isInvalid()) {
Res = ExprError();
} else {
- Res = Actions.ActOnBuiltinOffsetOf(CurScope, StartLoc, TypeLoc,
- Ty.get(), &Comps[0],
+ Res = Actions.ActOnBuiltinOffsetOf(CurScope, StartLoc, TypeLoc,
+ Ty.get(), &Comps[0],
Comps.size(), ConsumeParen());
}
break;
@@ -1260,7 +1363,8 @@ Parser::OwningExprResult Parser::ParseBuiltinPrimaryExpression() {
///
Parser::OwningExprResult
Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
- TypeTy *&CastTy, SourceLocation &RParenLoc) {
+ bool parseAsExprList, TypeTy *&CastTy,
+ SourceLocation &RParenLoc) {
assert(Tok.is(tok::l_paren) && "Not a paren expr!");
GreaterThanIsOperatorScope G(GreaterThanIsOperator, true);
SourceLocation OpenLoc = ConsumeParen();
@@ -1279,9 +1383,9 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
} 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.
@@ -1290,7 +1394,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
if (isAmbiguousTypeId && !stopIfCastExpr)
return ParseCXXAmbiguousParenExpression(ExprType, CastTy,
OpenLoc, RParenLoc);
-
+
TypeResult Ty = ParseTypeName();
// Match the ')'.
@@ -1320,14 +1424,25 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
// Parse the cast-expression that follows it next.
// TODO: For cast expression with CastTy.
- Result = ParseCastExpression(false);
+ Result = ParseCastExpression(false, false, true);
if (!Result.isInvalid())
- Result = Actions.ActOnCastExpr(OpenLoc, CastTy, RParenLoc,move(Result));
+ Result = Actions.ActOnCastExpr(CurScope, OpenLoc, CastTy, RParenLoc,
+ move(Result));
return move(Result);
}
Diag(Tok, diag::err_expected_lbrace_in_compound_literal);
return ExprError();
+ } else if (parseAsExprList) {
+ // Parse the expression-list.
+ ExprVector ArgExprs(Actions);
+ CommaLocsTy CommaLocs;
+
+ if (!ParseExpressionList(ArgExprs, CommaLocs)) {
+ ExprType = SimpleExpr;
+ Result = Actions.ActOnParenListExpr(OpenLoc, Tok.getLocation(),
+ move_arg(ArgExprs));
+ }
} else {
Result = ParseExpression();
ExprType = SimpleExpr;
@@ -1340,7 +1455,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
SkipUntil(tok::r_paren);
return ExprError();
}
-
+
if (Tok.is(tok::r_paren))
RParenLoc = ConsumeParen();
else
@@ -1401,8 +1516,19 @@ Parser::OwningExprResult Parser::ParseStringLiteralExpression() {
/// [C++] assignment-expression
/// [C++] expression-list , assignment-expression
///
-bool Parser::ParseExpressionList(ExprListTy &Exprs, CommaLocsTy &CommaLocs) {
+bool Parser::ParseExpressionList(ExprListTy &Exprs, CommaLocsTy &CommaLocs,
+ void (Action::*Completer)(Scope *S,
+ void *Data,
+ ExprTy **Args,
+ unsigned NumArgs),
+ void *Data) {
while (1) {
+ if (Tok.is(tok::code_completion)) {
+ if (Completer)
+ (Actions.*Completer)(CurScope, Data, Exprs.data(), Exprs.size());
+ ConsumeToken();
+ }
+
OwningExprResult Expr(ParseAssignmentExpression());
if (Expr.isInvalid())
return true;
@@ -1460,7 +1586,7 @@ Parser::OwningExprResult Parser::ParseBlockLiteralExpression() {
PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), CaretLoc,
"block literal parsing");
- // Enter a scope to hold everything within the block. This includes the
+ // 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.
@@ -1470,7 +1596,7 @@ Parser::OwningExprResult Parser::ParseBlockLiteralExpression() {
// 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);
@@ -1508,12 +1634,13 @@ Parser::OwningExprResult Parser::ParseBlockLiteralExpression() {
ParseBlockId();
} else {
// Otherwise, pretend we saw (void).
- ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(true, false,
+ ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(true, false,
SourceLocation(),
0, 0, 0,
false, SourceLocation(),
false, 0, 0, 0,
- CaretLoc, ParamInfo),
+ CaretLoc, CaretLoc,
+ ParamInfo),
CaretLoc);
if (Tok.is(tok::kw___attribute)) {
@@ -1534,7 +1661,7 @@ Parser::OwningExprResult Parser::ParseBlockLiteralExpression() {
Actions.ActOnBlockError(CaretLoc, CurScope);
return ExprError();
}
-
+
OwningStmtResult Stmt(ParseCompoundStatementBody());
if (!Stmt.isInvalid())
Result = Actions.ActOnBlockStmtExpr(CaretLoc, move(Stmt), CurScope);
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 1220b2d..325f085 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -16,10 +16,11 @@
#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.
+/// \brief Parse global scope or nested-name-specifier if present.
+///
+/// Parses a C++ global scope specifier ('::') or nested-name-specifier (which
+/// may be preceded by '::'). Note that this routine will not parse ::new or
+/// ::delete; it will just leave them in the token stream.
///
/// '::'[opt] nested-name-specifier
/// '::'
@@ -28,9 +29,23 @@ using namespace clang;
/// type-name '::'
/// namespace-name '::'
/// nested-name-specifier identifier '::'
-/// nested-name-specifier 'template'[opt] simple-template-id '::' [TODO]
+/// nested-name-specifier 'template'[opt] simple-template-id '::'
+///
+///
+/// \param SS the scope specifier that will be set to the parsed
+/// nested-name-specifier (or empty)
+///
+/// \param ObjectType if this nested-name-specifier is being parsed following
+/// the "." or "->" of a member access expression, this parameter provides the
+/// type of the object whose members are being accessed.
///
-bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) {
+/// \param EnteringContext whether we will be entering into the context of
+/// the nested-name-specifier after parsing it.
+///
+/// \returns true if a scope specifier was parsed.
+bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
+ Action::TypeTy *ObjectType,
+ bool EnteringContext) {
assert(getLang().CPlusPlus &&
"Call sites of this function should be guarded by checking for C++");
@@ -48,7 +63,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) {
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);
@@ -58,21 +73,48 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) {
}
while (true) {
+ if (HasScopeSpecifier) {
+ // C++ [basic.lookup.classref]p5:
+ // If the qualified-id has the form
+ //
+ // ::class-name-or-namespace-name::...
+ //
+ // the class-name-or-namespace-name is looked up in global scope as a
+ // class-name or namespace-name.
+ //
+ // To implement this, we clear out the object type as soon as we've
+ // seen a leading '::' or part of a nested-name-specifier.
+ ObjectType = 0;
+
+ if (Tok.is(tok::code_completion)) {
+ // Code completion for a nested-name-specifier, where the code
+ // code completion token follows the '::'.
+ Actions.CodeCompleteQualifiedId(CurScope, SS, EnteringContext);
+ ConsumeToken();
+ }
+ }
+
// nested-name-specifier:
// nested-name-specifier 'template'[opt] simple-template-id '::'
// Parse the optional 'template' keyword, then make sure we have
// 'identifier <' after it.
if (Tok.is(tok::kw_template)) {
+ // If we don't have a scope specifier or an object type, this isn't a
+ // nested-name-specifier, since they aren't allowed to start with
+ // 'template'.
+ if (!HasScopeSpecifier && !ObjectType)
+ break;
+
SourceLocation TemplateKWLoc = ConsumeToken();
-
+
if (Tok.isNot(tok::identifier)) {
- Diag(Tok.getLocation(),
+ 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)
@@ -80,49 +122,51 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) {
<< SourceRange(TemplateKWLoc, Tok.getLocation());
break;
}
-
- TemplateTy Template
+
+ TemplateTy Template
= Actions.ActOnDependentTemplateName(TemplateKWLoc,
*Tok.getIdentifierInfo(),
- Tok.getLocation(), SS);
+ Tok.getLocation(), SS,
+ ObjectType);
+ if (!Template)
+ break;
if (AnnotateTemplateIdToken(Template, TNK_Dependent_template_name,
&SS, TemplateKWLoc, false))
break;
-
+
continue;
}
-
+
if (Tok.is(tok::annot_template_id) && NextToken().is(tok::coloncolon)) {
- // We have
+ // 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
+ TemplateIdAnnotation *TemplateId
= static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
- if (TemplateId->Kind == TNK_Type_template ||
+ if (TemplateId->Kind == TNK_Type_template ||
TemplateId->Kind == TNK_Dependent_template_name) {
AnnotateTemplateIdTokenAsType(&SS);
- SS.setScopeRep(0);
- assert(Tok.is(tok::annot_typename) &&
+ 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,
+ Actions.ActOnCXXNestedNameSpecifier(CurScope, SS,
TypeToken.getAnnotationValue(),
TypeToken.getAnnotationRange(),
CCLoc));
@@ -131,7 +175,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) {
SS.setEndLoc(CCLoc);
continue;
}
-
+
assert(false && "FIXME: Only type template names supported here");
}
@@ -154,27 +198,32 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) {
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));
+ Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, IdLoc, CCLoc, II,
+ ObjectType, EnteringContext));
SS.setEndLoc(CCLoc);
continue;
}
-
+
// nested-name-specifier:
// type-name '<'
if (Next.is(tok::less)) {
TemplateTy Template;
- if (TemplateNameKind TNK = Actions.isTemplateName(II, CurScope,
- Template, &SS)) {
+ if (TemplateNameKind TNK = Actions.isTemplateName(CurScope, II,
+ Tok.getLocation(),
+ &SS,
+ ObjectType,
+ EnteringContext,
+ Template)) {
// 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,
@@ -192,7 +241,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) {
// nested-name-specifier, so we're done.
break;
}
-
+
return HasScopeSpecifier;
}
@@ -257,7 +306,7 @@ Parser::OwningExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) {
// '::' unqualified-id
//
CXXScopeSpec SS;
- ParseOptionalCXXScopeSpecifier(SS);
+ ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
// unqualified-id:
// identifier
@@ -295,17 +344,17 @@ Parser::OwningExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) {
}
case tok::annot_template_id: {
- TemplateIdAnnotation *TemplateId
+ TemplateIdAnnotation *TemplateId
= static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
assert((TemplateId->Kind == TNK_Function_template ||
TemplateId->Kind == TNK_Dependent_template_name) &&
"A template type name is not an ID expression");
- ASTTemplateArgsPtr TemplateArgsPtr(Actions,
+ ASTTemplateArgsPtr TemplateArgsPtr(Actions,
TemplateId->getTemplateArgs(),
TemplateId->getTemplateArgIsType(),
TemplateId->NumArgs);
-
+
OwningExprResult Result
= Actions.ActOnTemplateIdExpr(TemplateTy::make(TemplateId->Template),
TemplateId->TemplateNameLoc,
@@ -361,11 +410,11 @@ Parser::OwningExprResult Parser::ParseCXXCasts() {
return ExprError();
OwningExprResult Result = ParseExpression();
-
+
// Match the ')'.
if (Result.isInvalid())
SkipUntil(tok::r_paren);
-
+
if (Tok.is(tok::r_paren))
RParenLoc = ConsumeParen();
else
@@ -413,11 +462,11 @@ Parser::OwningExprResult Parser::ParseCXXTypeid() {
Ty.get(), RParenLoc);
} else {
// C++0x [expr.typeid]p3:
- // When typeid is applied to an expression other than an lvalue of a
- // polymorphic class type [...] The expression is an unevaluated
+ // When typeid is applied to an expression other than an lvalue of a
+ // polymorphic class type [...] The expression is an unevaluated
// operand (Clause 5).
//
- // Note that we can't tell whether the expression is an lvalue of a
+ // Note that we can't tell whether the expression is an lvalue of a
// polymorphic class type until after we've parsed the expression, so
// we the expression is potentially potentially evaluated.
EnterExpressionEvaluationContext Unevaluated(Actions,
@@ -516,6 +565,10 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
// Match the ')'.
SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ // TypeRep could be null, if it references an invalid typedef.
+ if (!TypeRep)
+ return ExprError();
+
assert((Exprs.size() == 0 || Exprs.size()-1 == CommaLocs.size())&&
"Unexpected number of commas!");
return Actions.ActOnCXXTypeConstructExpr(DS.getSourceRange(), TypeRep,
@@ -606,58 +659,65 @@ Parser::OwningExprResult Parser::ParseCXXCondition() {
void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
DS.SetRangeStart(Tok.getLocation());
const char *PrevSpec;
+ unsigned DiagID;
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:
+ default:
assert(0 && "Not a simple-type-specifier token!");
abort();
// type-name
case tok::annot_typename: {
- DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
+ DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID,
Tok.getAnnotationValue());
break;
}
-
+
// builtin types
case tok::kw_short:
- DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec);
+ DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec, DiagID);
break;
case tok::kw_long:
- DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec);
+ DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec, DiagID);
break;
case tok::kw_signed:
- DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec);
+ DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec, DiagID);
break;
case tok::kw_unsigned:
- DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec);
+ DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec, DiagID);
break;
case tok::kw_void:
- DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec);
+ DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec, DiagID);
break;
case tok::kw_char:
- DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec);
+ DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec, DiagID);
break;
case tok::kw_int:
- DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec);
+ DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec, DiagID);
break;
case tok::kw_float:
- DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec);
+ DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec, DiagID);
break;
case tok::kw_double:
- DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec);
+ DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec, DiagID);
break;
case tok::kw_wchar_t:
- DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec);
+ DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec, DiagID);
+ break;
+ case tok::kw_char16_t:
+ DS.SetTypeSpecType(DeclSpec::TST_char16, Loc, PrevSpec, DiagID);
+ break;
+ case tok::kw_char32_t:
+ DS.SetTypeSpecType(DeclSpec::TST_char32, Loc, PrevSpec, DiagID);
break;
case tok::kw_bool:
- DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec);
+ DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec, DiagID);
break;
-
+
// GNU typeof support.
case tok::kw_typeof:
ParseTypeofSpecifier(DS);
@@ -686,15 +746,16 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS) {
DS.SetRangeStart(Tok.getLocation());
const char *PrevSpec = 0;
- int isInvalid = 0;
+ unsigned DiagID;
+ bool isInvalid = 0;
// Parse one or more of the type specifiers.
- if (!ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec)) {
+ if (!ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID)) {
Diag(Tok, diag::err_operator_missing_type_specifier);
return true;
}
-
- while (ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec)) ;
+
+ while (ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID)) ;
return false;
}
@@ -774,6 +835,18 @@ Parser::TryParseOperatorFunctionId(SourceLocation *EndLoc) {
*EndLoc = Loc;
return OO_Subscript;
+ case tok::code_completion: {
+ // Code completion for the operator name.
+ Actions.CodeCompleteOperatorName(CurScope);
+
+ // Consume the 'operator' token, then replace the code-completion token
+ // with an 'operator' token and try again.
+ SourceLocation OperatorLoc = ConsumeToken();
+ Tok.setLocation(OperatorLoc);
+ Tok.setKind(tok::kw_operator);
+ return TryParseOperatorFunctionId(EndLoc);
+ }
+
default:
return OO_None;
}
@@ -824,7 +897,7 @@ Parser::TypeTy *Parser::ParseConversionFunctionId(SourceLocation *EndLoc) {
/// 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.
@@ -966,7 +1039,7 @@ void Parser::ParseDirectNewDeclarator(Declarator &D) {
SourceLocation RLoc = MatchRHSPunctuation(tok::r_square, LLoc);
D.AddTypeInfo(DeclaratorChunk::getArray(0, /*static=*/false, /*star=*/false,
- Size.release(), LLoc),
+ Size.release(), LLoc, RLoc),
RLoc);
if (RLoc.isInvalid())
@@ -1033,8 +1106,7 @@ Parser::ParseCXXDeleteExpression(bool UseGlobal, SourceLocation Start) {
return Actions.ActOnCXXDelete(Start, UseGlobal, ArrayDelete, move(Operand));
}
-static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind)
-{
+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;
@@ -1062,8 +1134,7 @@ static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind)
/// primary-expression:
/// [GNU] unary-type-trait '(' type-id ')'
///
-Parser::OwningExprResult Parser::ParseUnaryTypeTrait()
-{
+Parser::OwningExprResult Parser::ParseUnaryTypeTrait() {
UnaryTypeTrait UTT = UnaryTypeTraitFromTokKind(Tok.getKind());
SourceLocation Loc = ConsumeToken();
@@ -1118,7 +1189,7 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
// parsing a cast-expression), and then we re-introduce the cached tokens
// into the token stream and parse them appropriately.
- ParenParseOption ParseAs;
+ ParenParseOption ParseAs;
CachedTokens Toks;
// Store the tokens of the parentheses. We will parse them after we determine
@@ -1142,7 +1213,7 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
// will be consumed.
Result = ParseCastExpression(false/*isUnaryExpression*/,
false/*isAddressofOperand*/,
- NotCastExpr);
+ NotCastExpr, false);
}
// If we parsed a cast-expression, it's really a type-id, otherwise it's
@@ -1150,7 +1221,7 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
ParseAs = NotCastExpr ? SimpleExpr : CastExpr;
}
- // The current token should go after the cached tokens.
+ // 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.
@@ -1173,7 +1244,7 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
ExprType = CompoundLiteral;
return ParseCompoundLiteralExpression(Ty.get(), LParenLoc, RParenLoc);
}
-
+
// We parsed '(' type-id ')' and the thing after it wasn't a '{'.
assert(ParseAs == CastExpr);
@@ -1184,10 +1255,11 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
// Result is what ParseCastExpression returned earlier.
if (!Result.isInvalid())
- Result = Actions.ActOnCastExpr(LParenLoc, CastTy, RParenLoc,move(Result));
+ Result = Actions.ActOnCastExpr(CurScope, LParenLoc, CastTy, RParenLoc,
+ move(Result));
return move(Result);
}
-
+
// Not a compound literal, and not followed by a cast-expression.
assert(ParseAs == SimpleExpr);
@@ -1201,7 +1273,7 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
SkipUntil(tok::r_paren);
return ExprError();
}
-
+
if (Tok.is(tok::r_paren))
RParenLoc = ConsumeParen();
else
diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp
index bbc2124..6ab23fd 100644
--- a/lib/Parse/ParseInit.cpp
+++ b/lib/Parse/ParseInit.cpp
@@ -20,7 +20,7 @@ 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.
+/// false.
static bool MayBeDesignationStart(tok::TokenKind K, Preprocessor &PP) {
switch (K) {
default: return false;
@@ -70,46 +70,46 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() {
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,
+ << CodeModificationHint::CreateReplacement(SourceRange(NameLoc,
ColonLoc),
NewSyntax);
Designation D;
D.AddDesignator(Designator::getField(FieldName, SourceLocation(), NameLoc));
- return Actions.ActOnDesignatedInitializer(D, ColonLoc, true,
+ 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 ']'
@@ -123,14 +123,14 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() {
// [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 &&
+ if (Desig.getNumDesignators() == 1 &&
(Desig.getDesignator(0).isArrayDesignator() ||
Desig.getDesignator(0).isArrayRangeDesignator()))
Diag(StartLoc, diag::ext_gnu_missing_equal_designator);
@@ -151,18 +151,18 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() {
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
+ // message send, handle it now. An objc-message send is the start of
// an assignment-expression production.
- if (getLang().ObjC1 && Tok.isNot(tok::ellipsis) &&
+ 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 &&
+ if (Desig.getNumDesignators() == 1 &&
(Desig.getDesignator(0).isArrayDesignator() ||
Desig.getDesignator(0).isArrayRangeDesignator()))
Diag(StartLoc, diag::ext_gnu_missing_equal_designator);
@@ -213,7 +213,7 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() {
// 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 &&
+ if (Desig.getNumDesignators() == 1 &&
(Desig.getDesignator(0).isArrayDesignator() ||
Desig.getDesignator(0).isArrayRangeDesignator())) {
Diag(Tok, diag::ext_gnu_missing_equal_designator)
@@ -267,13 +267,13 @@ Parser::OwningExprResult Parser::ParseBraceInitializer() {
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
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index 013e26b..1d29f31 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -29,7 +29,7 @@ using namespace clang;
/// [OBJC] '@' 'end'
Parser::DeclPtrTy Parser::ParseObjCAtDirectives() {
SourceLocation AtLoc = ConsumeToken(); // the "@"
-
+
switch (Tok.getObjCKeywordID()) {
case tok::objc_class:
return ParseObjCAtClassDeclaration(AtLoc);
@@ -55,13 +55,13 @@ Parser::DeclPtrTy Parser::ParseObjCAtDirectives() {
}
///
-/// objc-class-declaration:
+/// 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);
@@ -70,17 +70,17 @@ Parser::DeclPtrTy Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
}
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());
}
@@ -91,14 +91,14 @@ Parser::DeclPtrTy Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
/// objc-category-interface
///
/// objc-class-interface:
-/// '@' 'interface' identifier objc-superclass[opt]
+/// '@' 'interface' identifier objc-superclass[opt]
/// objc-protocol-refs[opt]
-/// objc-class-instance-variables[opt]
+/// objc-class-instance-variables[opt]
/// objc-interface-decl-list
/// @end
///
/// objc-category-interface:
-/// '@' 'interface' identifier '(' identifier[opt] ')'
+/// '@' 'interface' identifier '(' identifier[opt] ')'
/// objc-protocol-refs[opt]
/// objc-interface-decl-list
/// @end
@@ -118,7 +118,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration(
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();
@@ -126,12 +126,12 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration(
// 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();
@@ -146,25 +146,27 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration(
return DeclPtrTy();
}
rparenLoc = ConsumeParen();
-
+
// Next, we need to check for any protocol references.
- SourceLocation EndProtoLoc;
+ SourceLocation LAngleLoc, EndProtoLoc;
llvm::SmallVector<DeclPtrTy, 8> ProtocolRefs;
+ llvm::SmallVector<SourceLocation, 8> ProtocolLocs;
if (Tok.is(tok::less) &&
- ParseObjCProtocolReferences(ProtocolRefs, true, EndProtoLoc))
+ ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true,
+ LAngleLoc, EndProtoLoc))
return DeclPtrTy();
-
+
if (attrList) // categories don't support attributes.
Diag(Tok, diag::err_objc_no_attributes_on_category);
-
+
DeclPtrTy CategoryType =
- Actions.ActOnStartCategoryInterface(atLoc,
+ Actions.ActOnStartCategoryInterface(atLoc,
nameId, nameLoc,
categoryId, categoryLoc,
ProtocolRefs.data(),
ProtocolRefs.size(),
EndProtoLoc);
-
+
ParseObjCInterfaceDeclList(CategoryType, tok::objc_not_keyword);
return CategoryType;
}
@@ -183,17 +185,19 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration(
}
// Next, we need to check for any protocol references.
llvm::SmallVector<Action::DeclPtrTy, 8> ProtocolRefs;
- SourceLocation EndProtoLoc;
+ llvm::SmallVector<SourceLocation, 8> ProtocolLocs;
+ SourceLocation LAngleLoc, EndProtoLoc;
if (Tok.is(tok::less) &&
- ParseObjCProtocolReferences(ProtocolRefs, true, EndProtoLoc))
+ ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true,
+ LAngleLoc, EndProtoLoc))
return DeclPtrTy();
-
- DeclPtrTy ClsType =
- Actions.ActOnStartClassInterface(atLoc, nameId, nameLoc,
+
+ DeclPtrTy ClsType =
+ Actions.ActOnStartClassInterface(atLoc, nameId, nameLoc,
superClassId, superClassLoc,
ProtocolRefs.data(), ProtocolRefs.size(),
EndProtoLoc, attrList);
-
+
if (Tok.is(tok::l_brace))
ParseObjCClassInstanceVariables(ClsType, atLoc);
@@ -219,13 +223,13 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl,
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 =
+ DeclPtrTy methodPrototype =
ParseObjCMethodPrototype(interfaceDecl, MethodImplKind);
allMethods.push_back(methodPrototype);
// Consume the ';' here, since ParseObjCMethodPrototype() is re-used for
@@ -234,17 +238,17 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl,
"", 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
@@ -252,22 +256,22 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl,
// erroneous r_brace would cause an infinite loop if not handled here.
if (Tok.is(tok::r_brace))
break;
-
+
// FIXME: as the name implies, this rule allows function definitions.
// We could pass a flag or check for functions during semantic analysis.
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();
@@ -281,7 +285,7 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl,
// 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.
@@ -291,24 +295,24 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl,
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.
+ // 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];
@@ -322,12 +326,12 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl,
<< FD.D.getSourceRange();
continue;
}
-
+
// Install the property declarator into interfaceDecl.
IdentifierInfo *SelName =
OCDS.getGetterName() ? OCDS.getGetterName() : FD.D.getIdentifier();
-
- Selector GetterSel =
+
+ Selector GetterSel =
PP.getSelectorTable().getNullarySelector(SelName);
IdentifierInfo *SetterName = OCDS.getSetterName();
Selector SetterSel;
@@ -340,7 +344,7 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl,
bool isOverridingProperty = false;
DeclPtrTy Property = Actions.ActOnProperty(CurScope, AtLoc, FD, OCDS,
GetterSel, SetterSel,
- interfaceDecl,
+ interfaceDecl,
&isOverridingProperty,
MethodImplKind);
if (!isOverridingProperty)
@@ -356,11 +360,11 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl,
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(),
+ allMethods.data(), allMethods.size(),
allProperties.data(), allProperties.size(),
allTUVariables.data(), allTUVariables.size());
}
@@ -384,18 +388,22 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl,
void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) {
assert(Tok.getKind() == tok::l_paren);
SourceLocation LHSLoc = ConsumeParen(); // consume '('
-
+
while (1) {
+ if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteObjCProperty(CurScope, DS);
+ ConsumeToken();
+ }
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"))
@@ -413,18 +421,18 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) {
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;
@@ -438,18 +446,18 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) {
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-instance-method objc-method-decl objc-method-attributes[opt]
/// objc-class-method objc-method-decl objc-method-attributes[opt]
///
/// objc-instance-method: '-'
@@ -458,13 +466,13 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) {
/// objc-method-attributes: [OBJC2]
/// __attribute__((deprecated))
///
-Parser::DeclPtrTy Parser::ParseObjCMethodPrototype(DeclPtrTy IDecl,
+Parser::DeclPtrTy Parser::ParseObjCMethodPrototype(DeclPtrTy IDecl,
tok::ObjCKeywordKind MethodImplKind) {
assert((Tok.is(tok::minus) || Tok.is(tok::plus)) && "expected +/-");
- tok::TokenKind methodType = Tok.getKind();
+ 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 ';'.
@@ -564,7 +572,7 @@ 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) &&
+ return (getLang().ObjC2 && Tok.is(tok::identifier) &&
Tok.getIdentifierInfo() == ObjCTypeQuals[objc_in]);
}
@@ -580,12 +588,12 @@ 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");
@@ -601,7 +609,7 @@ void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS) {
II = 0;
break;
}
-
+
// If this wasn't a recognized qualifier, bail out.
if (II) return;
}
@@ -613,10 +621,10 @@ void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS) {
///
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);
@@ -626,7 +634,7 @@ Parser::TypeTy *Parser::ParseObjCTypeName(ObjCDeclSpec &DS) {
if (!TypeSpec.isInvalid())
Ty = TypeSpec.get();
}
-
+
if (Tok.is(tok::r_paren))
ConsumeParen();
else if (Tok.getLocation() == TypeStartLoc) {
@@ -648,7 +656,7 @@ Parser::TypeTy *Parser::ParseObjCTypeName(ObjCDeclSpec &DS) {
/// objc-type-name objc-keyword-selector objc-parmlist[opt]
///
/// objc-keyword-selector:
-/// objc-keyword-decl
+/// objc-keyword-decl
/// objc-keyword-selector objc-keyword-decl
///
/// objc-keyword-decl:
@@ -678,7 +686,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
ObjCDeclSpec DSRet;
if (Tok.is(tok::l_paren))
ReturnType = ParseObjCTypeName(DSRet);
-
+
SourceLocation selLoc;
IdentifierInfo *SelIdent = ParseObjCSelectorPiece(selLoc);
@@ -690,14 +698,14 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
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))
+ 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,
@@ -707,17 +715,17 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
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);
@@ -731,11 +739,11 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
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);
@@ -746,9 +754,9 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
break;
// We have a selector or a colon, continue parsing.
}
-
+
bool isVariadic = false;
-
+
// Parse the (optional) parameter list.
while (Tok.is(tok::comma)) {
ConsumeToken();
@@ -759,18 +767,18 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
}
DeclSpec DS;
ParseDeclarationSpecifiers(DS);
- // Parse the declarator.
+ // 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))
+ if (getLang().ObjC2 && Tok.is(tok::kw___attribute))
MethodAttrs = ParseAttributes();
-
+
if (KeyIdents.size() == 0)
return DeclPtrTy();
Selector Sel = PP.getSelectorTable().getSelector(KeyIdents.size(),
@@ -786,13 +794,15 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
///
bool Parser::
ParseObjCProtocolReferences(llvm::SmallVectorImpl<Action::DeclPtrTy> &Protocols,
- bool WarnOnDeclarations, SourceLocation &EndLoc) {
+ llvm::SmallVectorImpl<SourceLocation> &ProtocolLocs,
+ bool WarnOnDeclarations,
+ SourceLocation &LAngleLoc, SourceLocation &EndLoc) {
assert(Tok.is(tok::less) && "expected <");
-
- ConsumeToken(); // the "<"
-
+
+ LAngleLoc = ConsumeToken(); // the "<"
+
llvm::SmallVector<IdentifierLocPair, 8> ProtocolIdents;
-
+
while (1) {
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident);
@@ -801,21 +811,22 @@ ParseObjCProtocolReferences(llvm::SmallVectorImpl<Action::DeclPtrTy> &Protocols,
}
ProtocolIdents.push_back(std::make_pair(Tok.getIdentifierInfo(),
Tok.getLocation()));
+ ProtocolLocs.push_back(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(),
@@ -841,7 +852,7 @@ ParseObjCProtocolReferences(llvm::SmallVectorImpl<Action::DeclPtrTy> &Protocols,
/// @package [OBJC2]
///
/// objc-instance-variable-decl:
-/// struct-declaration
+/// struct-declaration
///
void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl,
SourceLocation atLoc) {
@@ -852,19 +863,19 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl,
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
@@ -875,18 +886,18 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl,
case tok::objc_package:
visibility = Tok.getObjCKeywordID();
ConsumeToken();
- continue;
+ 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];
@@ -897,7 +908,7 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl,
FD.D, FD.BitfieldSize, visibility);
AllIvarDecls.push_back(Field);
}
-
+
if (Tok.is(tok::semi)) {
ConsumeToken();
} else {
@@ -920,9 +931,9 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl,
/// objc-protocol-forward-reference
///
/// objc-protocol-definition:
-/// @protocol identifier
-/// objc-protocol-refs[opt]
-/// objc-interface-decl-list
+/// @protocol identifier
+/// objc-protocol-refs[opt]
+/// objc-interface-decl-list
/// @end
///
/// objc-protocol-forward-reference:
@@ -936,7 +947,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
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();
@@ -944,14 +955,14 @@ Parser::DeclPtrTy Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
// 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,
+ 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));
@@ -967,28 +978,30 @@ Parser::DeclPtrTy Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
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[0],
ProtocolRefs.size(),
attrList);
}
-
+
// Last, and definitely not least, parse a protocol declaration.
- SourceLocation EndProtoLoc;
+ SourceLocation LAngleLoc, EndProtoLoc;
llvm::SmallVector<DeclPtrTy, 8> ProtocolRefs;
+ llvm::SmallVector<SourceLocation, 8> ProtocolLocs;
if (Tok.is(tok::less) &&
- ParseObjCProtocolReferences(ProtocolRefs, false, EndProtoLoc))
+ ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, false,
+ LAngleLoc, EndProtoLoc))
return DeclPtrTy();
-
+
DeclPtrTy ProtoType =
Actions.ActOnStartProtocolInterface(AtLoc, protocolName, nameLoc,
ProtocolRefs.data(),
@@ -1013,7 +1026,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration(
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();
@@ -1021,20 +1034,20 @@ Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration(
// 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)) {
+
+ 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 ';'
@@ -1042,7 +1055,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration(
}
rparenLoc = ConsumeParen();
DeclPtrTy ImplCatType = Actions.ActOnStartCategoryImplementation(
- atLoc, nameId, nameLoc, categoryId,
+ atLoc, nameId, nameLoc, categoryId,
categoryLoc);
ObjCImpDecl = ImplCatType;
return DeclPtrTy();
@@ -1063,11 +1076,11 @@ Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration(
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();
}
@@ -1131,7 +1144,7 @@ Parser::DeclPtrTy Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) {
Diag(Tok, diag::err_expected_ident);
return DeclPtrTy();
}
-
+
while (Tok.is(tok::identifier)) {
IdentifierInfo *propertyIvar = 0;
IdentifierInfo *propertyId = Tok.getIdentifierInfo();
@@ -1186,7 +1199,7 @@ Parser::DeclPtrTy Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) {
Diag(Tok, diag::err_expected_semi_after) << "@dynamic";
return DeclPtrTy();
}
-
+
/// objc-throw-statement:
/// throw expression[opt];
///
@@ -1288,7 +1301,7 @@ Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
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
+ // 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);
@@ -1298,9 +1311,9 @@ Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
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 ')'.
@@ -1352,11 +1365,11 @@ Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
///
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();
@@ -1364,19 +1377,19 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDefinition() {
// 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);
@@ -1390,7 +1403,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDefinition() {
// TODO: Pass argument information.
Actions.ActOnFinishFunctionBody(MDecl, move(FnBody));
-
+
// Leave the function body scope.
BodyScope.Exit();
@@ -1439,7 +1452,7 @@ Parser::OwningExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
}
}
-/// objc-message-expr:
+/// objc-message-expr:
/// '[' objc-receiver objc-message-args ']'
///
/// objc-receiver:
@@ -1472,7 +1485,7 @@ Parser::OwningExprResult Parser::ParseObjCMessageExpression() {
/// ParseObjCMessageExpressionBody - Having parsed "'[' objc-receiver", parse
/// the rest of a message expression.
-///
+///
/// objc-message-args:
/// objc-selector
/// objc-keywordarg-list
@@ -1481,7 +1494,7 @@ Parser::OwningExprResult Parser::ParseObjCMessageExpression() {
/// objc-keywordarg
/// objc-keywordarg-list objc-keywordarg
///
-/// objc-keywordarg:
+/// objc-keywordarg:
/// selector-name[opt] ':' objc-keywordexpr
///
/// objc-keywordexpr:
@@ -1501,7 +1514,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
IdentifierInfo *selIdent = ParseObjCSelectorPiece(Loc);
SourceLocation SelectorLoc = Loc;
-
+
llvm::SmallVector<IdentifierInfo *, 12> KeyIdents;
ExprVector KeyExprs(Actions);
@@ -1520,7 +1533,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
}
ConsumeToken(); // Eat the ':'.
- /// Parse the expression after ':'
+ /// Parse the expression after ':'
OwningExprResult Res(ParseAssignmentExpression());
if (Res.isInvalid()) {
// We must manually skip to a ']', otherwise the expression skipper will
@@ -1542,7 +1555,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
// Parse the, optional, argument list, comma separated.
while (Tok.is(tok::comma)) {
ConsumeToken(); // Eat the ','.
- /// Parse the expression after ','
+ /// Parse the expression after ','
OwningExprResult Res(ParseAssignmentExpression());
if (Res.isInvalid()) {
// We must manually skip to a ']', otherwise the expression skipper will
@@ -1584,7 +1597,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
// We've just parsed a keyword message.
if (ReceiverName)
return Owned(Actions.ActOnClassMessage(CurScope, ReceiverName, Sel,
- LBracLoc, NameLoc, SelectorLoc,
+ LBracLoc, NameLoc, SelectorLoc,
RBracLoc,
KeyExprs.take(), KeyExprs.size()));
return Owned(Actions.ActOnInstanceMessage(ReceiverExpr.release(), Sel,
@@ -1642,7 +1655,7 @@ Parser::ParseObjCEncodeExpression(SourceLocation AtLoc) {
if (Ty.isInvalid())
return ExprError();
- return Owned(Actions.ParseObjCEncodeExpression(AtLoc, EncLoc, LParenLoc,
+ return Owned(Actions.ParseObjCEncodeExpression(AtLoc, EncLoc, LParenLoc,
Ty.get(), RParenLoc));
}
diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp
index 58c729a..812d8e2 100644
--- a/lib/Parse/ParsePragma.cpp
+++ b/lib/Parse/ParsePragma.cpp
@@ -37,7 +37,7 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, Token &PackTok) {
IdentifierInfo *Name = 0;
Action::OwningExprResult Alignment(Actions);
SourceLocation LParenLoc = Tok.getLocation();
- PP.Lex(Tok);
+ PP.Lex(Tok);
if (Tok.is(tok::numeric_constant)) {
Alignment = Actions.ActOnNumericConstant(Tok);
if (Alignment.isInvalid())
@@ -57,12 +57,12 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, Token &PackTok) {
} 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())
@@ -72,15 +72,15 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, Token &PackTok) {
} 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;
@@ -115,7 +115,7 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, Token &PackTok) {
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);
@@ -124,57 +124,39 @@ void PragmaUnusedHandler::HandlePragma(Preprocessor &PP, Token &UnusedTok) {
return;
}
SourceLocation LParenLoc = Tok.getLocation();
-
+
// Lex the declaration reference(s).
- llvm::SmallVector<Action::ExprTy*, 5> Ex;
+ llvm::SmallVector<Token, 5> Identifiers;
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());
+ if (Tok.is(tok::identifier)) {
+ Identifiers.push_back(Tok);
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());
-
+ // Illegal token!
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());
-
+
+ // Illegal token!
PP.Diag(Tok.getLocation(), diag::warn_pragma_unused_expected_punc);
return;
}
@@ -188,10 +170,11 @@ void PragmaUnusedHandler::HandlePragma(Preprocessor &PP, Token &UnusedTok) {
// 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");
+ assert(!Identifiers.empty() && "Valid '#pragma unused' must have arguments");
- // Perform the action to handle the pragma.
- Actions.ActOnPragmaUnused(&Ex[0], Ex.size(), UnusedLoc, LParenLoc, RParenLoc);
+ // Perform the action to handle the pragma.
+ Actions.ActOnPragmaUnused(Identifiers.data(), Identifiers.size(),
+ parser.CurScope, UnusedLoc, LParenLoc, RParenLoc);
}
// #pragma weak identifier
@@ -214,7 +197,7 @@ void PragmaWeakHandler::HandlePragma(Preprocessor &PP, Token &WeakTok) {
if (Tok.is(tok::equal)) {
PP.Lex(Tok);
if (Tok.isNot(tok::identifier)) {
- PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
<< "weak";
return;
}
diff --git a/lib/Parse/ParsePragma.h b/lib/Parse/ParsePragma.h
index 39c86ee..db385c6 100644
--- a/lib/Parse/ParsePragma.h
+++ b/lib/Parse/ParsePragma.h
@@ -23,29 +23,29 @@ namespace clang {
class PragmaPackHandler : public PragmaHandler {
Action &Actions;
public:
- PragmaPackHandler(const IdentifierInfo *N, Action &A) : PragmaHandler(N),
+ PragmaPackHandler(const IdentifierInfo *N, Action &A) : PragmaHandler(N),
Actions(A) {}
-
- virtual void HandlePragma(Preprocessor &PP, Token &FirstToken);
+
+ 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);
-};
+
+ virtual void HandlePragma(Preprocessor &PP, Token &FirstToken);
+};
class PragmaWeakHandler : public PragmaHandler {
Action &Actions;
public:
PragmaWeakHandler(const IdentifierInfo *N, Action &A)
: PragmaHandler(N), Actions(A) {}
-
- virtual void HandlePragma(Preprocessor &PP, Token &FirstToken);
+
+ virtual void HandlePragma(Preprocessor &PP, Token &FirstToken);
};
} // end namespace clang
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index 955f00d..907ca80 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -71,8 +71,8 @@ using namespace clang;
///
/// [OBC] objc-throw-statement:
/// [OBC] '@' 'throw' expression ';'
-/// [OBC] '@' 'throw' ';'
-///
+/// [OBC] '@' 'throw' ';'
+///
Parser::OwningStmtResult
Parser::ParseStatementOrDeclaration(bool OnlyStatement) {
const char *SemiError = 0;
@@ -90,6 +90,11 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) {
return ParseObjCAtStatement(AtLoc);
}
+ case tok::code_completion:
+ Actions.CodeCompleteOrdinaryName(CurScope);
+ ConsumeToken();
+ return ParseStatementOrDeclaration(OnlyStatement);
+
case tok::identifier:
if (NextToken().is(tok::colon)) { // C99 6.8.1: labeled-statement
// identifier ':' statement
@@ -108,7 +113,7 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) {
Diag(Tok, diag::err_expected_statement);
return StmtError();
}
-
+
// expression[opt] ';'
OwningExprResult Expr(ParseExpression());
if (Expr.isInvalid()) {
@@ -187,7 +192,7 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) {
// Skip until we see a } or ;, but don't eat it.
SkipUntil(tok::r_brace, true, true);
}
-
+
return move(Res);
}
@@ -233,7 +238,7 @@ Parser::OwningStmtResult Parser::ParseLabeledStatement() {
///
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:
@@ -247,19 +252,24 @@ Parser::OwningStmtResult Parser::ParseCaseStatement() {
// 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'.
+
+ if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteCase(CurScope);
+ ConsumeToken();
+ }
OwningExprResult LHS(ParseConstantExpression());
if (LHS.isInvalid()) {
@@ -288,11 +298,11 @@ Parser::OwningStmtResult Parser::ParseCaseStatement() {
}
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()) {
@@ -309,15 +319,15 @@ Parser::OwningStmtResult Parser::ParseCaseStatement() {
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 {
@@ -327,11 +337,11 @@ Parser::OwningStmtResult Parser::ParseCaseStatement() {
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));
@@ -415,10 +425,10 @@ Parser::OwningStmtResult Parser::ParseCompoundStatement(bool isStmtExpr) {
/// 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(),
+ 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
@@ -496,12 +506,12 @@ bool Parser::ParseParenExprOrCondition(OwningExprResult &CondExp,
SourceLocation *RParenLocPtr) {
SourceLocation LParenLoc = ConsumeParen();
if (LParenLocPtr) *LParenLocPtr = LParenLoc;
-
+
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.
@@ -512,7 +522,7 @@ bool Parser::ParseParenExprOrCondition(OwningExprResult &CondExp,
if (Tok.isNot(tok::r_paren))
return true;
}
-
+
// Otherwise the condition is valid or the rparen is present.
SourceLocation RPLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
if (RParenLocPtr) *RParenLocPtr = RPLoc;
@@ -559,7 +569,7 @@ Parser::OwningStmtResult Parser::ParseIfStatement() {
return StmtError();
FullExprArg FullCondExp(Actions.FullExpr(CondExp));
-
+
// 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.
@@ -578,7 +588,7 @@ Parser::OwningStmtResult Parser::ParseIfStatement() {
// 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,
+ ParseScope InnerScope(this, Scope::DeclScope,
C99orCXX && Tok.isNot(tok::l_brace));
// Read the 'then' stmt.
@@ -619,14 +629,14 @@ Parser::OwningStmtResult Parser::ParseIfStatement() {
}
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
+ // 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) ||
@@ -641,7 +651,7 @@ Parser::OwningStmtResult Parser::ParseIfStatement() {
if (ElseStmt.isInvalid())
ElseStmt = Actions.ActOnNullStmt(ElseStmtLoc);
- return Actions.ActOnIfStmt(IfLoc, FullCondExp, move(ThenStmt),
+ return Actions.ActOnIfStmt(IfLoc, FullCondExp, move(ThenStmt),
ElseLoc, move(ElseStmt));
}
@@ -698,7 +708,7 @@ Parser::OwningStmtResult Parser::ParseSwitchStatement() {
// 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,
+ ParseScope InnerScope(this, Scope::DeclScope,
C99orCXX && Tok.isNot(tok::l_brace));
// Read the body statement.
@@ -763,7 +773,7 @@ Parser::OwningStmtResult Parser::ParseWhileStatement() {
return StmtError();
FullExprArg FullCond(Actions.FullExpr(Cond));
-
+
// 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.
@@ -775,7 +785,7 @@ Parser::OwningStmtResult Parser::ParseWhileStatement() {
// 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,
+ ParseScope InnerScope(this, Scope::DeclScope,
C99orCXX && Tok.isNot(tok::l_brace));
// Read the body statement.
@@ -818,7 +828,7 @@ Parser::OwningStmtResult Parser::ParseDoStatement() {
// which is entered and exited each time through the loop.
//
ParseScope InnerScope(this, Scope::DeclScope,
- (getLang().C99 || getLang().CPlusPlus) &&
+ (getLang().C99 || getLang().CPlusPlus) &&
Tok.isNot(tok::l_brace));
// Read the body statement.
@@ -847,7 +857,7 @@ Parser::OwningStmtResult Parser::ParseDoStatement() {
OwningExprResult Cond(Actions);
SourceLocation LPLoc, RPLoc;
ParseParenExprOrCondition(Cond, true, &LPLoc, &RPLoc);
-
+
DoScope.Exit();
if (Cond.isInvalid() || Body.isInvalid())
@@ -913,6 +923,11 @@ Parser::OwningStmtResult Parser::ParseForStatement() {
OwningStmtResult FirstPart(Actions);
OwningExprResult SecondPart(Actions), ThirdPart(Actions);
+ if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteOrdinaryName(CurScope);
+ ConsumeToken();
+ }
+
// Parse the first part of the for specifier.
if (Tok.is(tok::semi)) { // for (;
// no first part, eat the ';'.
@@ -926,11 +941,11 @@ Parser::OwningStmtResult Parser::ParseForStatement() {
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)
+ // ObjC: for (id x in expr)
ConsumeToken(); // consume 'in'
SecondPart = ParseExpression();
} else {
@@ -988,7 +1003,7 @@ Parser::OwningStmtResult Parser::ParseForStatement() {
// 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,
+ ParseScope InnerScope(this, Scope::DeclScope,
C99orCXXorObjC && Tok.isNot(tok::l_brace));
// Read the body statement.
@@ -1007,7 +1022,7 @@ Parser::OwningStmtResult Parser::ParseForStatement() {
return Actions.ActOnForStmt(ForLoc, LParenLoc, move(FirstPart),
move(SecondPart), move(ThirdPart),
RParenLoc, move(Body));
-
+
return Actions.ActOnObjCForCollectionStmt(ForLoc, LParenLoc,
move(FirstPart),
move(SecondPart),
@@ -1085,7 +1100,7 @@ Parser::OwningStmtResult Parser::ParseReturnStatement() {
return StmtError();
}
}
- return Actions.ActOnReturnStmt(ReturnLoc, Actions.FullExpr(R));
+ return Actions.ActOnReturnStmt(ReturnLoc, move(R));
}
/// FuzzyParseMicrosoftAsmStatement. When -fms-extensions is enabled, this
@@ -1096,7 +1111,7 @@ Parser::OwningStmtResult Parser::FuzzyParseMicrosoftAsmStatement() {
do {
ConsumeAnyToken();
} while (BraceCount > savedBraceCount && Tok.isNot(tok::eof));
- } else {
+ } 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();
@@ -1105,8 +1120,8 @@ Parser::OwningStmtResult Parser::FuzzyParseMicrosoftAsmStatement() {
do {
ConsumeAnyToken();
TokLoc = Tok.getLocation();
- } while ((SrcMgr.getInstantiationLineNumber(TokLoc) == LineNo) &&
- Tok.isNot(tok::r_brace) && Tok.isNot(tok::semi) &&
+ } while ((SrcMgr.getInstantiationLineNumber(TokLoc) == LineNo) &&
+ Tok.isNot(tok::r_brace) && Tok.isNot(tok::semi) &&
Tok.isNot(tok::eof));
}
return Actions.ActOnNullStmt(Tok.getLocation());
@@ -1196,7 +1211,7 @@ Parser::OwningStmtResult Parser::ParseAsmStatement(bool &msAsm) {
return StmtError();
assert(Names.size() == Constraints.size() &&
- Constraints.size() == Exprs.size()
+ Constraints.size() == Exprs.size()
&& "Input operand size mismatch!");
NumInputs = Names.size() - NumOutputs;
@@ -1247,22 +1262,22 @@ bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl<std::string> &Names,
// 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) {
+
+ 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();
@@ -1308,7 +1323,7 @@ Parser::DeclPtrTy Parser::ParseFunctionStatementBody(DeclPtrTy Decl) {
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.
@@ -1316,7 +1331,7 @@ Parser::DeclPtrTy Parser::ParseFunctionStatementBody(DeclPtrTy Decl) {
// If the function body could not be parsed, make a bogus compoundstmt.
if (FnBody.isInvalid())
- FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc,
+ FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc,
MultiStmtArg(Actions), false);
return Actions.ActOnFinishFunctionBody(Decl, move(FnBody));
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 57a09fb..8e63fb8 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -15,6 +15,7 @@
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/DeclSpec.h"
#include "clang/Parse/Scope.h"
+#include "llvm/Support/Compiler.h"
using namespace clang;
/// \brief Parse a template declaration, explicit instantiation, or
@@ -24,11 +25,35 @@ Parser::ParseDeclarationStartingWithTemplate(unsigned Context,
SourceLocation &DeclEnd,
AccessSpecifier AS) {
if (Tok.is(tok::kw_template) && NextToken().isNot(tok::less))
- return ParseExplicitInstantiation(ConsumeToken(), DeclEnd);
+ return ParseExplicitInstantiation(SourceLocation(), ConsumeToken(),
+ DeclEnd);
return ParseTemplateDeclarationOrSpecialization(Context, DeclEnd, AS);
}
+/// \brief RAII class that manages the template parameter depth.
+namespace {
+ class VISIBILITY_HIDDEN TemplateParameterDepthCounter {
+ unsigned &Depth;
+ unsigned AddedLevels;
+
+ public:
+ explicit TemplateParameterDepthCounter(unsigned &Depth)
+ : Depth(Depth), AddedLevels(0) { }
+
+ ~TemplateParameterDepthCounter() {
+ Depth -= AddedLevels;
+ }
+
+ void operator++() {
+ ++Depth;
+ ++AddedLevels;
+ }
+
+ operator unsigned() const { return Depth; }
+ };
+}
+
/// \brief Parse a template declaration or an explicit specialization.
///
/// Template declarations include one or more template parameter lists
@@ -48,9 +73,9 @@ 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.");
-
+ 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);
@@ -75,8 +100,9 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context,
// defining A<T>::B receives just the inner template parameter list
// (and retrieves the outer template parameter list from its
// context).
- bool isSpecialiation = true;
+ bool isSpecialization = true;
TemplateParameterLists ParamLists;
+ TemplateParameterDepthCounter Depth(TemplateParameterDepth);
do {
// Consume the 'export', if any.
SourceLocation ExportLoc;
@@ -92,27 +118,35 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context,
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;
+ if (ParseTemplateParameters(Depth, TemplateParams, LAngleLoc,
+ RAngleLoc)) {
+ // Skip until the semi-colon or a }.
+ SkipUntil(tok::r_brace, true, true);
+ if (Tok.is(tok::semi))
+ ConsumeToken();
+ return DeclPtrTy();
+ }
ParamLists.push_back(
- Actions.ActOnTemplateParameterList(ParamLists.size(), ExportLoc,
- TemplateLoc, LAngleLoc,
+ Actions.ActOnTemplateParameterList(Depth, ExportLoc,
+ TemplateLoc, LAngleLoc,
TemplateParams.data(),
TemplateParams.size(), RAngleLoc));
+
+ if (!TemplateParams.empty()) {
+ isSpecialization = false;
+ ++Depth;
+ }
} while (Tok.is(tok::kw_export) || Tok.is(tok::kw_template));
// Parse the actual template declaration.
- return ParseSingleDeclarationAfterTemplate(Context,
+ return ParseSingleDeclarationAfterTemplate(Context,
ParsedTemplateInfo(&ParamLists,
- isSpecialiation),
+ isSpecialization),
DeclEnd, AS);
}
@@ -136,7 +170,7 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context,
/// declaration. Will be AS_none for namespace-scope declarations.
///
/// \returns the new declaration.
-Parser::DeclPtrTy
+Parser::DeclPtrTy
Parser::ParseSingleDeclarationAfterTemplate(
unsigned Context,
const ParsedTemplateInfo &TemplateInfo,
@@ -145,9 +179,14 @@ Parser::ParseSingleDeclarationAfterTemplate(
assert(TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate &&
"Template information required");
+ if (Context == Declarator::MemberContext) {
+ // We are parsing a member template.
+ ParseCXXClassMemberDeclaration(AS, TemplateInfo);
+ return DeclPtrTy::make((void*)0);
+ }
+
// Parse the declaration specifiers.
DeclSpec DS;
- // FIXME: Pass TemplateLoc through for explicit template instantiations
ParseDeclarationSpecifiers(DS, TemplateInfo, AS);
if (Tok.is(tok::semi)) {
@@ -166,7 +205,7 @@ Parser::ParseSingleDeclarationAfterTemplate(
ConsumeToken();
return DeclPtrTy();
}
-
+
// If we have a declaration or declarator list, handle it.
if (isDeclarationAfterDeclarator()) {
// Parse this declaration.
@@ -181,7 +220,7 @@ Parser::ParseSingleDeclarationAfterTemplate(
}
// Eat the semi colon after the declaration.
- ExpectAndConsume(tok::semi, diag::err_expected_semi_declation);
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_declaration);
return ThisDecl;
}
@@ -217,44 +256,46 @@ Parser::ParseSingleDeclarationAfterTemplate(
/// 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,
+/// RAngleLoc will receive the positions of the '<' and '>', respectively,
/// that enclose this template parameter list.
+///
+/// \returns true if an error occurred, false otherwise.
bool Parser::ParseTemplateParameters(unsigned Depth,
TemplateParameterList &TemplateParams,
SourceLocation &LAngleLoc,
SourceLocation &RAngleLoc) {
// Get the template parameter list.
- if(!Tok.is(tok::less)) {
+ if (!Tok.is(tok::less)) {
Diag(Tok.getLocation(), diag::err_expected_less_after) << "template";
- return false;
+ return true;
}
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)) {
+ else if (ParseTemplateParameterList(Depth, TemplateParams)) {
+ if (!Tok.is(tok::greater)) {
Diag(Tok.getLocation(), diag::err_expected_greater);
- return false;
+ return true;
}
RAngleLoc = ConsumeToken();
}
- return true;
+ return false;
}
/// 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.
+/// a statement, etc.) and return false.
///
/// template-parameter-list: [C++ temp]
/// template-parameter
/// template-parameter-list ',' template-parameter
-bool
+bool
Parser::ParseTemplateParameterList(unsigned Depth,
TemplateParameterList &TemplateParams) {
- while(1) {
+ while (1) {
if (DeclPtrTy TmpParam
= ParseTemplateParameter(Depth, TemplateParams.size())) {
TemplateParams.push_back(TmpParam);
@@ -263,11 +304,11 @@ Parser::ParseTemplateParameterList(unsigned Depth,
// 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)) {
+ if (Tok.is(tok::comma)) {
ConsumeToken();
- } else if(Tok.is(tok::greater)) {
+ } else if (Tok.is(tok::greater)) {
// Don't consume this... that's done by template parser.
break;
} else {
@@ -297,16 +338,16 @@ Parser::ParseTemplateParameterList(unsigned Depth,
/// 'typename' identifier[opt] '=' type-id
/// 'template' ...[opt][C++0x] '<' template-parameter-list '>' 'class' identifier[opt]
/// 'template' '<' template-parameter-list '>' 'class' identifier[opt] = id-expression
-Parser::DeclPtrTy
+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))) {
+ 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))
+
+ if (Tok.is(tok::kw_template))
return ParseTemplateTemplateParameter(Depth, Position);
// If it's none of the above, then it must be a parameter declaration.
@@ -326,7 +367,7 @@ Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) {
/// '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'");
+ "A type-parameter starts with 'class' or 'typename'");
// Consume the 'class' or 'typename' keyword.
bool TypenameKeyword = Tok.is(tok::kw_typename);
@@ -338,33 +379,33 @@ Parser::DeclPtrTy Parser::ParseTypeParameter(unsigned Depth, unsigned Position){
if (Tok.is(tok::ellipsis)) {
Ellipsis = true;
EllipsisLoc = ConsumeToken();
-
- if (!getLang().CPlusPlus0x)
+
+ if (!getLang().CPlusPlus0x)
Diag(EllipsisLoc, diag::err_variadic_templates);
}
-
+
// Grab the template parameter name (if given)
SourceLocation NameLoc;
IdentifierInfo* ParamName = 0;
- if(Tok.is(tok::identifier)) {
+ if (Tok.is(tok::identifier)) {
ParamName = Tok.getIdentifierInfo();
NameLoc = ConsumeToken();
- } else if(Tok.is(tok::equal) || Tok.is(tok::comma) ||
- Tok.is(tok::greater)) {
+ } 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,
Ellipsis, EllipsisLoc,
KeyLoc, ParamName, NameLoc,
Depth, Position);
// Grab a default type id (if given).
- if(Tok.is(tok::equal)) {
+ if (Tok.is(tok::equal)) {
SourceLocation EqualLoc = ConsumeToken();
SourceLocation DefaultLoc = Tok.getLocation();
TypeResult DefaultType = ParseTypeName();
@@ -372,12 +413,12 @@ Parser::DeclPtrTy Parser::ParseTypeParameter(unsigned Depth, unsigned Position){
Actions.ActOnTypeParameterDefault(TypeParam, EqualLoc, DefaultLoc,
DefaultType.get());
}
-
+
return TypeParam;
}
/// ParseTemplateTemplateParameter - Handle the parsing of template
-/// template parameters.
+/// template parameters.
///
/// type-parameter: [C++ temp.param]
/// 'template' '<' template-parameter-list '>' 'class' identifier[opt]
@@ -388,20 +429,20 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
// Handle the template <...> part.
SourceLocation TemplateLoc = ConsumeToken();
- TemplateParameterList TemplateParams;
+ TemplateParameterList TemplateParams;
SourceLocation LAngleLoc, RAngleLoc;
{
ParseScope TemplateParmScope(this, Scope::TemplateParamScope);
- if(!ParseTemplateParameters(Depth + 1, TemplateParams, LAngleLoc,
- RAngleLoc)) {
+ 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)
+ if (!Tok.is(tok::kw_class)) {
+ Diag(Tok.getLocation(), diag::err_expected_class_before)
<< PP.getSpelling(Tok);
return DeclPtrTy();
}
@@ -410,10 +451,10 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
// Get the identifier, if given.
SourceLocation NameLoc;
IdentifierInfo* ParamName = 0;
- if(Tok.is(tok::identifier)) {
+ if (Tok.is(tok::identifier)) {
ParamName = Tok.getIdentifierInfo();
NameLoc = ConsumeToken();
- } else if(Tok.is(tok::equal) || Tok.is(tok::comma) || Tok.is(tok::greater)) {
+ } 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 {
@@ -421,10 +462,10 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
return DeclPtrTy();
}
- TemplateParamsTy *ParamList =
+ TemplateParamsTy *ParamList =
Actions.ActOnTemplateParameterList(Depth, SourceLocation(),
TemplateLoc, LAngleLoc,
- &TemplateParams[0],
+ &TemplateParams[0],
TemplateParams.size(),
RAngleLoc);
@@ -448,7 +489,7 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
}
/// ParseNonTypeTemplateParameter - Handle the parsing of non-type
-/// template parameters (e.g., in "template<int Size> class array;").
+/// template parameters (e.g., in "template<int Size> class array;").
///
/// template-parameter:
/// ...
@@ -460,7 +501,7 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
/// parameters.
/// FIXME: We need to make a ParseParameterDeclaration that works for
/// non-type template parameters and normal function parameters.
-Parser::DeclPtrTy
+Parser::DeclPtrTy
Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
SourceLocation StartLoc = Tok.getLocation();
@@ -483,7 +524,7 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
return DeclPtrTy();
}
- // Create the parameter.
+ // Create the parameter.
DeclPtrTy Param = Actions.ActOnNonTypeTemplateParameter(CurScope, ParamDecl,
Depth, Position);
@@ -496,16 +537,16 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
// 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);
+ GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
OwningExprResult DefaultArg = ParseAssignmentExpression();
if (DefaultArg.isInvalid())
SkipUntil(tok::comma, tok::greater, true, true);
else if (Param)
- Actions.ActOnNonTypeTemplateParameterDefault(Param, EqualLoc,
+ Actions.ActOnNonTypeTemplateParameterDefault(Param, EqualLoc,
move(DefaultArg));
}
-
+
return Param;
}
@@ -527,9 +568,9 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
/// 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
+bool
Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template,
- SourceLocation TemplateNameLoc,
+ SourceLocation TemplateNameLoc,
const CXXScopeSpec *SS,
bool ConsumeLastToken,
SourceLocation &LAngleLoc,
@@ -587,7 +628,7 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template,
return false;
}
-
+
/// \brief Replace the tokens that form a simple-template-id with an
/// annotation token containing the complete template-id.
///
@@ -626,7 +667,7 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template,
/// formed, this function returns true.
///
bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
- const CXXScopeSpec *SS,
+ const CXXScopeSpec *SS,
SourceLocation TemplateKWLoc,
bool AllowTypeAnnotation) {
assert(getLang().CPlusPlus && "Can only annotate template-ids in C++");
@@ -643,12 +684,12 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
TemplateArgIsTypeList TemplateArgIsType;
TemplateArgLocationList TemplateArgLocations;
bool Invalid = ParseTemplateIdAfterTemplateName(Template, TemplateNameLoc,
- SS, false, LAngleLoc,
- TemplateArgs,
+ SS, false, LAngleLoc,
+ TemplateArgs,
TemplateArgIsType,
TemplateArgLocations,
RAngleLoc);
-
+
if (Invalid) {
// If we failed to parse the template ID but skipped ahead to a >, we're not
// going to be able to form a token annotation. Eat the '>' if present.
@@ -663,7 +704,7 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
// Build the annotation token.
if (TNK == TNK_Type_template && AllowTypeAnnotation) {
- Action::TypeResult Type
+ Action::TypeResult Type
= Actions.ActOnTemplateIdType(Template, TemplateNameLoc,
LAngleLoc, TemplateArgsPtr,
&TemplateArgLocations[0],
@@ -682,13 +723,13 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
Tok.setLocation(SS->getBeginLoc());
else if (TemplateKWLoc.isValid())
Tok.setLocation(TemplateKWLoc);
- else
+ 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 *TemplateId
= TemplateIdAnnotation::Allocate(TemplateArgs.size());
TemplateId->TemplateNameLoc = TemplateNameLoc;
TemplateId->Name = Name;
@@ -731,21 +772,21 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
void Parser::AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS) {
assert(Tok.is(tok::annot_template_id) && "Requires template-id tokens");
- TemplateIdAnnotation *TemplateId
+ 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,
+
+ ASTTemplateArgsPtr TemplateArgsPtr(Actions,
TemplateId->getTemplateArgs(),
TemplateId->getTemplateArgIsType(),
TemplateId->NumArgs);
- Action::TypeResult Type
+ Action::TypeResult Type
= Actions.ActOnTemplateIdType(TemplateTy::make(TemplateId->Template),
TemplateId->TemplateNameLoc,
- TemplateId->LAngleLoc,
+ TemplateId->LAngleLoc,
TemplateArgsPtr,
TemplateId->getTemplateArgLocations(),
TemplateId->RAngleLoc);
@@ -798,7 +839,7 @@ void *Parser::ParseTemplateArgument(bool &ArgIsType) {
/// template-argument-list: [C++ 14.2]
/// template-argument
/// template-argument-list ',' template-argument
-bool
+bool
Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs,
TemplateArgIsTypeList &TemplateArgIsType,
TemplateArgLocationList &TemplateArgLocations) {
@@ -826,15 +867,19 @@ Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs,
return Tok.isNot(tok::greater) && Tok.isNot(tok::greatergreater);
}
-/// \brief Parse a C++ explicit template instantiation
+/// \brief Parse a C++ explicit template instantiation
/// (C++ [temp.explicit]).
///
/// explicit-instantiation:
-/// 'template' declaration
-Parser::DeclPtrTy
-Parser::ParseExplicitInstantiation(SourceLocation TemplateLoc,
+/// 'extern' [opt] 'template' declaration
+///
+/// Note that the 'extern' is a GNU extension and C++0x feature.
+Parser::DeclPtrTy
+Parser::ParseExplicitInstantiation(SourceLocation ExternLoc,
+ SourceLocation TemplateLoc,
SourceLocation &DeclEnd) {
- return ParseSingleDeclarationAfterTemplate(Declarator::FileContext,
- ParsedTemplateInfo(TemplateLoc),
+ return ParseSingleDeclarationAfterTemplate(Declarator::FileContext,
+ ParsedTemplateInfo(ExternLoc,
+ TemplateLoc),
DeclEnd, AS_none);
}
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index 02687a2..eb6e935 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -270,7 +270,7 @@ bool Parser::isCXXConditionDeclaration() {
return TPR == TPResult::True();
}
- /// \brief Determine whether the next set of tokens contains a type-id.
+ /// \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
@@ -288,7 +288,7 @@ bool Parser::isCXXConditionDeclaration() {
/// type-specifier-seq abstract-declarator[opt]
///
bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) {
-
+
isAmbiguous = false;
// C++ 8.2p2:
@@ -409,7 +409,7 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract,
while (1) {
if (Tok.is(tok::coloncolon) || Tok.is(tok::identifier))
- TryAnnotateCXXScopeToken();
+ TryAnnotateCXXScopeToken(true);
if (Tok.is(tok::star) || Tok.is(tok::amp) || Tok.is(tok::caret) ||
(Tok.is(tok::annot_cxxscope) && NextToken().is(tok::star))) {
@@ -427,8 +427,12 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract,
// direct-declarator:
// direct-abstract-declarator:
- if (Tok.is(tok::identifier) && mayHaveIdentifier) {
+ if ((Tok.is(tok::identifier) ||
+ (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier))) &&
+ mayHaveIdentifier) {
// declarator-id
+ if (Tok.is(tok::annot_cxxscope))
+ ConsumeToken();
ConsumeToken();
} else if (Tok.is(tok::l_paren)) {
ConsumeParen();
@@ -597,14 +601,14 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
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
@@ -650,7 +654,7 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
case tok::kw__Complex:
case tok::kw___attribute:
return TPResult::True();
-
+
// Microsoft
case tok::kw___declspec:
case tok::kw___cdecl:
@@ -681,6 +685,8 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
case tok::kw_char:
case tok::kw_wchar_t:
+ case tok::kw_char16_t:
+ case tok::kw_char32_t:
case tok::kw_bool:
case tok::kw_short:
case tok::kw_int:
@@ -752,7 +758,7 @@ Parser::TPResult Parser::TryParseDeclarationSpecifier() {
TryParseTypeofSpecifier();
else
ConsumeToken();
-
+
assert(Tok.is(tok::l_paren) && "Expected '('!");
return TPResult::Ambiguous();
}
@@ -874,7 +880,7 @@ Parser::TPResult Parser::TryParseParameterDeclarationClause() {
/// 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]
///
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 9771cf7..2f500a4 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -24,18 +24,18 @@ using namespace clang;
/// to the parser action.
class ActionCommentHandler : public CommentHandler {
Action &Actions;
-
+
public:
explicit ActionCommentHandler(Action &Actions) : Actions(Actions) { }
-
+
virtual void HandleComment(Preprocessor &PP, SourceRange Comment) {
Actions.ActOnComment(Comment);
}
};
Parser::Parser(Preprocessor &pp, Action &actions)
- : CrashInfo(*this), PP(pp), Actions(actions), Diags(PP.getDiagnostics()),
- GreaterThanIsOperator(true) {
+ : CrashInfo(*this), PP(pp), Actions(actions), Diags(PP.getDiagnostics()),
+ GreaterThanIsOperator(true), TemplateParameterDepth(0) {
Tok.setKind(tok::eof);
CurScope = 0;
NumCachedScopes = 0;
@@ -47,7 +47,7 @@ Parser::Parser(Preprocessor &pp, Action &actions)
PackHandler.reset(new
PragmaPackHandler(&PP.getIdentifierTable().get("pack"), actions));
PP.AddPragmaHandler(0, PackHandler.get());
-
+
UnusedHandler.reset(new
PragmaUnusedHandler(&PP.getIdentifierTable().get("unused"), actions,
*this));
@@ -56,9 +56,9 @@ Parser::Parser(Preprocessor &pp, Action &actions)
WeakHandler.reset(new
PragmaWeakHandler(&PP.getIdentifierTable().get("weak"), actions));
PP.AddPragmaHandler(0, WeakHandler.get());
-
+
CommentHandler.reset(new ActionCommentHandler(actions));
- PP.AddCommentHandler(CommentHandler.get());
+ PP.AddCommentHandler(CommentHandler.get());
}
/// If a crash happens while the parser is active, print out a line indicating
@@ -69,12 +69,12 @@ void PrettyStackTraceParserEntry::print(llvm::raw_ostream &OS) const {
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";
@@ -104,8 +104,8 @@ void Parser::SuggestParentheses(SourceLocation Loc, unsigned DK,
Diag(Loc, DK);
return;
}
-
- Diag(Loc, DK)
+
+ Diag(Loc, DK)
<< CodeModificationHint::CreateInsertion(ParenRange.getBegin(), "(")
<< CodeModificationHint::CreateInsertion(EndLoc, ")");
}
@@ -152,10 +152,10 @@ bool Parser::ExpectAndConsume(tok::TokenKind ExpectedTok, unsigned DiagID,
const char *Spelling = 0;
SourceLocation EndLoc = PP.getLocForEndOfToken(PrevTokLocation);
- if (EndLoc.isValid() &&
+ if (EndLoc.isValid() &&
(Spelling = tok::getTokenSimpleSpelling(ExpectedTok))) {
// Show what code to insert to fix this problem.
- Diag(EndLoc, DiagID)
+ Diag(EndLoc, DiagID)
<< Msg
<< CodeModificationHint::CreateInsertion(EndLoc, Spelling);
} else
@@ -365,7 +365,7 @@ void Parser::ParseTranslationUnit() {
DeclGroupPtrTy Res;
while (!ParseTopLevelDecl(Res))
/*parse them all*/;
-
+
ExitScope();
assert(CurScope == 0 && "Scope imbalance!");
}
@@ -375,7 +375,7 @@ void Parser::ParseTranslationUnit() {
/// external-declaration: [C99 6.9], declaration: [C++ dcl.dcl]
/// function-definition
/// declaration
-/// [EXT] ';'
+/// [C++0x] empty-declaration
/// [GNU] asm-definition
/// [GNU] __extension__ external-declaration
/// [OBJC] objc-class-definition
@@ -388,12 +388,18 @@ void Parser::ParseTranslationUnit() {
/// [GNU] asm-definition:
/// simple-asm-expr ';'
///
+/// [C++0x] empty-declaration:
+/// ';'
+///
+/// [C++0x/GNU] 'extern' 'template' declaration
Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration() {
DeclPtrTy SingleDecl;
switch (Tok.getKind()) {
case tok::semi:
- Diag(Tok, diag::ext_top_level_semi)
- << CodeModificationHint::CreateRemoval(SourceRange(Tok.getLocation()));
+ if (!getLang().CPlusPlus0x)
+ Diag(Tok, diag::ext_top_level_semi)
+ << CodeModificationHint::CreateRemoval(SourceRange(Tok.getLocation()));
+
ConsumeToken();
// TODO: Invoke action for top-level semicolon.
return DeclGroupPtrTy();
@@ -436,6 +442,10 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration() {
}
SingleDecl = ParseObjCMethodDefinition();
break;
+ case tok::code_completion:
+ Actions.CodeCompleteOrdinaryName(CurScope);
+ ConsumeToken();
+ return ParseExternalDeclaration();
case tok::kw_using:
case tok::kw_namespace:
case tok::kw_typedef:
@@ -447,11 +457,25 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration() {
SourceLocation DeclEnd;
return ParseDeclaration(Declarator::FileContext, DeclEnd);
}
+ case tok::kw_extern:
+ if (getLang().CPlusPlus && NextToken().is(tok::kw_template)) {
+ // Extern templates
+ SourceLocation ExternLoc = ConsumeToken();
+ SourceLocation TemplateLoc = ConsumeToken();
+ SourceLocation DeclEnd;
+ return Actions.ConvertDeclToDeclGroup(
+ ParseExplicitInstantiation(ExternLoc, TemplateLoc, DeclEnd));
+ }
+
+ // FIXME: Detect C++ linkage specifications here?
+
+ // Fall through to handle other declarations or function definitions.
+
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);
@@ -473,7 +497,7 @@ bool Parser::isDeclarationAfterDeclarator() {
/// declarator, indicates the start of a function definition.
bool Parser::isStartOfFunctionDefinition() {
return Tok.is(tok::l_brace) || // int X() {}
- (!getLang().CPlusPlus &&
+ (!getLang().CPlusPlus &&
isDeclarationSpecifier()) || // int X(f) int f; {}
(getLang().CPlusPlus &&
(Tok.is(tok::colon) || // X() : Base() {} (used for ctors)
@@ -484,7 +508,7 @@ bool Parser::isStartOfFunctionDefinition() {
/// 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.
+/// C++ template-declaration.
///
/// function-definition: [C99 6.9.1]
/// decl-specs declarator declaration-list[opt] compound-statement
@@ -515,16 +539,17 @@ Parser::ParseDeclarationOrFunctionDefinition(AccessSpecifier AS) {
// attributes here, no types, etc.
if (getLang().ObjC2 && Tok.is(tok::at)) {
SourceLocation AtLoc = ConsumeToken(); // the "@"
- if (!Tok.isObjCAtKeyword(tok::objc_interface) &&
+ 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;
-
+ unsigned DiagID;
+ if (DS.SetTypeSpecType(DeclSpec::TST_unspecified, AtLoc, PrevSpec, DiagID))
+ Diag(AtLoc, DiagID) << PrevSpec;
+
DeclPtrTy TheDecl;
if (Tok.isObjCAtKeyword(tok::objc_protocol))
TheDecl = ParseObjCAtProtocolDeclaration(AtLoc, DS.getAttributes());
@@ -561,10 +586,10 @@ Parser::ParseDeclarationOrFunctionDefinition(AccessSpecifier AS) {
DeclGroupPtrTy DG =
ParseInitDeclaratorListAfterFirstDeclarator(DeclaratorInfo);
// Eat the semi colon after the declaration.
- ExpectAndConsume(tok::semi, diag::err_expected_semi_declation);
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_declaration);
return DG;
}
-
+
if (DeclaratorInfo.isFunctionDeclarator() &&
isStartOfFunctionDefinition()) {
if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
@@ -584,7 +609,7 @@ Parser::ParseDeclarationOrFunctionDefinition(AccessSpecifier AS) {
DeclPtrTy TheDecl = ParseFunctionDefinition(DeclaratorInfo);
return Actions.ConvertDeclToDeclGroup(TheDecl);
}
-
+
if (DeclaratorInfo.isFunctionDeclarator())
Diag(Tok, diag::err_expected_fn_body);
else
@@ -619,9 +644,10 @@ Parser::DeclPtrTy Parser::ParseFunctionDefinition(Declarator &D,
// declaration-specifiers are completely optional in the grammar.
if (getLang().ImplicitInt && D.getDeclSpec().isEmpty()) {
const char *PrevSpec;
+ unsigned DiagID;
D.getMutableDeclSpec().SetTypeSpecType(DeclSpec::TST_int,
D.getIdentifierLoc(),
- PrevSpec);
+ PrevSpec, DiagID);
D.SetRangeBegin(D.getDeclSpec().getSourceRange().getBegin());
}
@@ -650,7 +676,7 @@ Parser::DeclPtrTy Parser::ParseFunctionDefinition(Declarator &D,
// Tell the actions module that we have entered a function definition with the
// specified Declarator for the function.
- DeclPtrTy Res = TemplateInfo.TemplateParams?
+ DeclPtrTy Res = TemplateInfo.TemplateParams?
Actions.ActOnStartOfFunctionTemplateDef(CurScope,
Action::MultiTemplateParamsArg(Actions,
TemplateInfo.TemplateParams->data(),
@@ -665,6 +691,8 @@ Parser::DeclPtrTy Parser::ParseFunctionDefinition(Declarator &D,
// ctor-initializer.
if (Tok.is(tok::colon))
ParseConstructorInitializer(Res);
+ else
+ Actions.ActOnDefaultCtorInitializers(Res);
return ParseFunctionStatementBody(Res);
}
@@ -858,24 +886,25 @@ Parser::OwningExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) {
///
/// This returns true if the token was annotated or an unrecoverable error
/// occurs.
-///
+///
/// 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)
+bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) {
+ 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]
+ // 'typename' '::' [opt] nested-name-specifier template [opt]
// simple-template-id
SourceLocation TypenameLoc = ConsumeToken();
CXXScopeSpec SS;
- bool HadNestedNameSpecifier = ParseOptionalCXXScopeSpecifier(SS);
+ bool HadNestedNameSpecifier
+ = ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
if (!HadNestedNameSpecifier) {
Diag(Tok.getLocation(), diag::err_expected_qualified_after_typename);
return false;
@@ -884,10 +913,10 @@ bool Parser::TryAnnotateTypeOrScopeToken() {
TypeResult Ty;
if (Tok.is(tok::identifier)) {
// FIXME: check whether the next token is '<', first!
- Ty = Actions.ActOnTypenameType(TypenameLoc, SS, *Tok.getIdentifierInfo(),
+ Ty = Actions.ActOnTypenameType(TypenameLoc, SS, *Tok.getIdentifierInfo(),
Tok.getLocation());
} else if (Tok.is(tok::annot_template_id)) {
- TemplateIdAnnotation *TemplateId
+ TemplateIdAnnotation *TemplateId
= static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
if (TemplateId->Kind == TNK_Function_template) {
Diag(Tok, diag::err_typename_refers_to_non_type_template)
@@ -896,7 +925,7 @@ bool Parser::TryAnnotateTypeOrScopeToken() {
}
AnnotateTemplateIdTokenAsType(0);
- assert(Tok.is(tok::annot_typename) &&
+ assert(Tok.is(tok::annot_typename) &&
"AnnotateTemplateIdTokenAsType isn't working properly");
if (Tok.getAnnotationValue())
Ty = Actions.ActOnTypenameType(TypenameLoc, SS, SourceLocation(),
@@ -919,11 +948,11 @@ bool Parser::TryAnnotateTypeOrScopeToken() {
CXXScopeSpec SS;
if (getLang().CPlusPlus)
- ParseOptionalCXXScopeSpecifier(SS);
+ ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, EnteringContext);
if (Tok.is(tok::identifier)) {
// Determine whether the identifier is a type name.
- if (TypeTy *Ty = Actions.getTypeName(*Tok.getIdentifierInfo(),
+ 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.
@@ -932,26 +961,28 @@ bool Parser::TryAnnotateTypeOrScopeToken() {
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.
+ // 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))
+ if (TemplateNameKind TNK
+ = Actions.isTemplateName(CurScope, *Tok.getIdentifierInfo(),
+ Tok.getLocation(), &SS,
+ /*ObjectType=*/0, EnteringContext,
+ Template))
if (AnnotateTemplateIdToken(Template, TNK, &SS)) {
// If an unrecoverable error occurred, we need to return true here,
// because the token stream is in a damaged state. We may not return
@@ -964,10 +995,10 @@ bool Parser::TryAnnotateTypeOrScopeToken() {
// 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
+ 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
@@ -981,7 +1012,7 @@ bool Parser::TryAnnotateTypeOrScopeToken() {
if (SS.isEmpty())
return Tok.isNot(tok::identifier) && Tok.isNot(tok::coloncolon);
-
+
// 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.
@@ -1003,17 +1034,17 @@ bool Parser::TryAnnotateTypeOrScopeToken() {
/// annotates C++ scope specifiers and template-ids. This returns
/// true if the token was annotated or there was an error that could not be
/// recovered from.
-///
+///
/// 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() {
+bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) {
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))
+ if (!ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, EnteringContext))
return Tok.is(tok::annot_template_id);
// Push the current token back into the token stream (or revert it if it is
diff --git a/lib/Rewrite/CMakeLists.txt b/lib/Rewrite/CMakeLists.txt
index 52670b8..ce9e1ed 100644
--- a/lib/Rewrite/CMakeLists.txt
+++ b/lib/Rewrite/CMakeLists.txt
@@ -3,7 +3,7 @@ set(LLVM_NO_RTTI 1)
add_clang_library(clangRewrite
DeltaTree.cpp
HTMLRewrite.cpp
- Rewriter.cpp
RewriteRope.cpp
+ Rewriter.cpp
TokenRewriter.cpp
)
diff --git a/lib/Rewrite/DeltaTree.cpp b/lib/Rewrite/DeltaTree.cpp
index 5d51dda..a94444b 100644
--- a/lib/Rewrite/DeltaTree.cpp
+++ b/lib/Rewrite/DeltaTree.cpp
@@ -39,7 +39,7 @@ namespace {
/// 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
@@ -47,7 +47,7 @@ namespace {
struct SourceDelta {
unsigned FileLoc;
int Delta;
-
+
static SourceDelta get(unsigned Loc, int D) {
SourceDelta Delta;
Delta.FileLoc = Loc;
@@ -71,36 +71,36 @@ namespace {
///
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 #");
@@ -110,7 +110,7 @@ namespace {
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
@@ -118,14 +118,14 @@ namespace {
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
@@ -142,14 +142,14 @@ namespace {
friend class DeltaTreeNode;
public:
DeltaTreeInteriorNode() : DeltaTreeNode(false /*nonleaf*/) {}
-
+
DeltaTreeInteriorNode(DeltaTreeNode *FirstChild)
: DeltaTreeNode(false /*nonleaf*/) {
FullDelta = FirstChild->FullDelta;
Children[0] = FirstChild;
}
-
- DeltaTreeInteriorNode(const InsertResult &IR)
+
+ DeltaTreeInteriorNode(const InsertResult &IR)
: DeltaTreeNode(false /*nonleaf*/) {
Children[0] = IR.LHS;
Children[1] = IR.RHS;
@@ -157,7 +157,7 @@ namespace {
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];
@@ -166,7 +166,7 @@ namespace {
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(); }
};
@@ -197,16 +197,16 @@ void DeltaTreeNode::RecomputeFullDeltaLocally() {
/// 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,
+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) {
@@ -230,19 +230,19 @@ bool DeltaTreeNode::DoInsertion(unsigned FileIndex, int 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))
@@ -259,21 +259,21 @@ bool DeltaTreeNode::DoInsertion(unsigned FileIndex, int Delta,
(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);
@@ -283,22 +283,22 @@ bool DeltaTreeNode::DoInsertion(unsigned FileIndex, int Delta,
InsertSide = cast<DeltaTreeInteriorNode>(InsertRes->LHS);
else
InsertSide = cast<DeltaTreeInteriorNode>(InsertRes->RHS);
-
- // We now have a non-empty interior node 'InsertSide' to insert
+
+ // 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]));
@@ -313,12 +313,12 @@ bool DeltaTreeNode::DoInsertion(unsigned FileIndex, int Delta,
/// 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)) {
@@ -332,18 +332,18 @@ void DeltaTreeNode::DoSplit(InsertResult &InsertRes) {
// 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];
@@ -374,7 +374,7 @@ static void VerifyTree(const DeltaTreeNode *N) {
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;
@@ -385,18 +385,18 @@ static void VerifyTree(const DeltaTreeNode *N) {
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
@@ -424,9 +424,9 @@ DeltaTree::~DeltaTree() {
/// 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
@@ -436,29 +436,29 @@ int DeltaTree::getDeltaAt(unsigned FileIndex) const {
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);
@@ -472,12 +472,12 @@ int DeltaTree::getDeltaAt(unsigned FileIndex) const {
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
index 69dd03a..7326890 100644
--- a/lib/Rewrite/HTMLRewrite.cpp
+++ b/lib/Rewrite/HTMLRewrite.cpp
@@ -39,10 +39,10 @@ void html::HighlightRange(Rewriter &R, SourceLocation B, SourceLocation E,
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);
}
@@ -53,13 +53,13 @@ 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));
-
+ RB.InsertTextAfter(B, StartTag);
+ RB.InsertTextBefore(E, EndTag);
+
// Scan the range to see if there is a \r or \n. If so, and if the line is
// not blank, insert tags on that line as well.
bool HadOpenTag = true;
-
+
unsigned LastNonWhiteSpace = B;
for (unsigned i = B; i != E; ++i) {
switch (BufferStart[i]) {
@@ -68,8 +68,8 @@ void html::HighlightRange(RewriteBuffer &RB, unsigned B, unsigned E,
// 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));
-
+ RB.InsertTextBefore(LastNonWhiteSpace+1, EndTag);
+
// Instead of inserting an open tag immediately after the newline, we
// wait until we see a non-whitespace character. This prevents us from
// inserting tags around blank lines, and also allows the open tag to
@@ -83,14 +83,14 @@ void html::HighlightRange(RewriteBuffer &RB, unsigned B, unsigned E,
case '\v':
// Ignore whitespace.
break;
-
+
default:
// If there is no tag open, do it now.
if (!HadOpenTag) {
- RB.InsertTextAfter(i, StartTag, strlen(StartTag));
+ RB.InsertTextAfter(i, StartTag);
HadOpenTag = true;
}
-
+
// Remember this character.
LastNonWhiteSpace = i;
break;
@@ -100,13 +100,13 @@ void html::HighlightRange(RewriteBuffer &RB, unsigned B, unsigned E,
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;
@@ -117,41 +117,42 @@ void html::EscapeText(Rewriter &R, FileID FID,
case '\r':
ColNo = 0;
break;
-
+
case ' ':
if (EscapeSpaces)
- RB.ReplaceText(FilePos, 1, "&nbsp;", 6);
+ RB.ReplaceText(FilePos, 1, "&nbsp;");
++ColNo;
break;
case '\f':
- RB.ReplaceText(FilePos, 1, "<hr>", 4);
+ RB.ReplaceText(FilePos, 1, "<hr>");
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);
+ RB.ReplaceText(FilePos, 1,
+ llvm::StringRef("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"
+ "&nbsp;&nbsp;&nbsp;", 6*NumSpaces));
else
- RB.ReplaceText(FilePos, 1, " ", NumSpaces);
+ RB.ReplaceText(FilePos, 1, llvm::StringRef(" ", NumSpaces));
ColNo += NumSpaces;
break;
}
case '<':
- RB.ReplaceText(FilePos, 1, "&lt;", 4);
+ RB.ReplaceText(FilePos, 1, "&lt;");
++ColNo;
break;
-
+
case '>':
- RB.ReplaceText(FilePos, 1, "&gt;", 4);
+ RB.ReplaceText(FilePos, 1, "&gt;");
++ColNo;
break;
-
+
case '&':
- RB.ReplaceText(FilePos, 1, "&amp;", 5);
+ RB.ReplaceText(FilePos, 1, "&amp;");
++ColNo;
break;
}
@@ -160,61 +161,61 @@ void html::EscapeText(Rewriter &R, FileID FID,
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;
+
+ 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\">";
-
+ llvm::SmallString<256> Str;
+ llvm::raw_svector_ostream OS(Str);
+
+ OS << "<tr><td class=\"num\" id=\"LN"
+ << LineNo << "\">"
+ << LineNo << "</td><td class=\"line\">";
+
if (B == E) { // Handle empty lines.
- Str += " </td></tr>";
- RB.InsertTextBefore(B, &Str[0], Str.size());
+ OS << " </td></tr>";
+ RB.InsertTextBefore(B, OS.str());
} else {
- RB.InsertTextBefore(B, &Str[0], Str.size());
- RB.InsertTextBefore(E, "</td></tr>", strlen("</td></tr>"));
+ RB.InsertTextBefore(B, OS.str());
+ RB.InsertTextBefore(E, "</td></tr>");
}
}
@@ -225,46 +226,44 @@ void html::AddLineNumbers(Rewriter& R, FileID FID) {
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) {
-
+
+ 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>"));
+ RB.InsertTextBefore(0, "<table class=\"code\">\n");
+ RB.InsertTextAfter(FileEnd - FileBeg, "</table>");
}
-void html::AddHeaderFooterInternalBuiltinCSS(Rewriter& R, FileID FID,
+void html::AddHeaderFooterInternalBuiltinCSS(Rewriter& R, FileID FID,
const char *title) {
const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FID);
@@ -278,10 +277,10 @@ void html::AddHeaderFooterInternalBuiltinCSS(Rewriter& R, FileID FID,
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"
@@ -340,10 +339,10 @@ void html::AddHeaderFooterInternalBuiltinCSS(Rewriter& R, FileID FID,
"</style>\n</head>\n<body>";
// Generate header
- R.InsertStrBefore(StartLoc, os.str());
+ R.InsertTextBefore(StartLoc, os.str());
// Generate footer
-
- R.InsertCStrAfter(EndLoc, "</body></html>\n");
+
+ R.InsertTextAfter(EndLoc, "</body></html>\n");
}
/// SyntaxHighlight - Relex the specified FileID and annotate the HTML with
@@ -356,16 +355,16 @@ void html::SyntaxHighlight(Rewriter &R, FileID FID, Preprocessor &PP) {
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
+
+ // 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.
@@ -377,7 +376,7 @@ void html::SyntaxHighlight(Rewriter &R, FileID FID, Preprocessor &PP) {
// 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,
@@ -401,7 +400,7 @@ void html::SyntaxHighlight(Rewriter &R, FileID FID, Preprocessor &PP) {
// 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;
@@ -410,16 +409,16 @@ void html::SyntaxHighlight(Rewriter &R, FileID FID, Preprocessor &PP) {
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);
}
}
@@ -443,15 +442,15 @@ 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.
@@ -462,7 +461,7 @@ void html::HighlightMacros(Rewriter &R, FileID FID, Preprocessor& PP) {
// 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.
@@ -470,30 +469,30 @@ void html::HighlightMacros(Rewriter &R, FileID FID, Preprocessor& PP) {
// 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);
@@ -503,13 +502,13 @@ void html::HighlightMacros(Rewriter &R, FileID FID, Preprocessor& PP) {
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);
@@ -519,13 +518,13 @@ void html::HighlightMacros(Rewriter &R, FileID FID, Preprocessor& PP) {
assert(SM.getFileID(LLoc.second) == FID &&
"Start and end of expansion must be in the same ultimate file!");
- std::string Expansion = PP.getSpelling(Tok);
+ std::string Expansion = EscapeText(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.
@@ -536,23 +535,23 @@ void html::HighlightMacros(Rewriter &R, FileID FID, Preprocessor& PP) {
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.
@@ -568,7 +567,7 @@ void html::HighlightMacros(Rewriter &R, FileID FID, Preprocessor& PP) {
void html::HighlightMacros(Rewriter &R, FileID FID,
PreprocessorFactory &PPF) {
-
+
llvm::OwningPtr<Preprocessor> PP(PPF.CreatePreprocessor());
HighlightMacros(R, FID, *PP);
}
diff --git a/lib/Rewrite/RewriteRope.cpp b/lib/Rewrite/RewriteRope.cpp
index 61cb02b..30bbcfa 100644
--- a/lib/Rewrite/RewriteRope.cpp
+++ b/lib/Rewrite/RewriteRope.cpp
@@ -81,24 +81,24 @@ namespace {
/// 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.
@@ -106,7 +106,7 @@ namespace {
/// 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.
@@ -114,13 +114,13 @@ namespace {
/// 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
@@ -140,11 +140,11 @@ namespace {
/// 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;
@@ -155,34 +155,34 @@ namespace {
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;
@@ -192,7 +192,7 @@ namespace {
NextLeaf->PrevLeaf = 0;
}
}
-
+
/// FullRecomputeSizeLocally - This method recomputes the 'Size' field by
/// summing the size of all RopePieces.
void FullRecomputeSizeLocally() {
@@ -200,7 +200,7 @@ namespace {
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.
@@ -208,7 +208,7 @@ namespace {
/// 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.
@@ -216,12 +216,12 @@ namespace {
/// 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();
@@ -242,7 +242,7 @@ RopePieceBTreeNode *RopePieceBTreeLeaf::split(unsigned Offset) {
// 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;
@@ -250,23 +250,23 @@ RopePieceBTreeNode *RopePieceBTreeLeaf::split(unsigned Offset) {
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);
}
@@ -292,7 +292,7 @@ RopePieceBTreeNode *RopePieceBTreeLeaf::insert(unsigned Offset,
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)
@@ -302,31 +302,31 @@ RopePieceBTreeNode *RopePieceBTreeLeaf::insert(unsigned Offset,
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);
@@ -345,42 +345,42 @@ void RopePieceBTreeLeaf::erase(unsigned Offset, unsigned NumBytes) {
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;
}
@@ -399,7 +399,7 @@ namespace {
RopePieceBTreeNode *Children[2*WidthFactor];
public:
RopePieceBTreeInterior() : RopePieceBTreeNode(false), NumChildren(0) {}
-
+
RopePieceBTreeInterior(RopePieceBTreeNode *LHS, RopePieceBTreeNode *RHS)
: RopePieceBTreeNode(false) {
Children[0] = LHS;
@@ -407,9 +407,9 @@ namespace {
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 #");
@@ -419,7 +419,7 @@ namespace {
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() {
@@ -427,8 +427,8 @@ namespace {
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.
@@ -436,8 +436,8 @@ namespace {
/// 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.
@@ -445,18 +445,18 @@ namespace {
/// 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();
+ return !N->isLeaf();
}
};
} // end anonymous namespace
@@ -471,18 +471,18 @@ 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))
+ if (RopePieceBTreeNode *RHS = getChild(i)->split(Offset-ChildOffset))
return HandleChildPiece(i, RHS);
return 0; // Done!
}
@@ -498,7 +498,7 @@ RopePieceBTreeNode *RopePieceBTreeInterior::insert(unsigned Offset,
// 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.
@@ -508,13 +508,13 @@ RopePieceBTreeNode *RopePieceBTreeInterior::insert(unsigned Offset,
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;
}
@@ -533,27 +533,27 @@ RopePieceBTreeInterior::HandleChildPiece(unsigned i, RopePieceBTreeNode *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();
@@ -565,24 +565,24 @@ RopePieceBTreeInterior::HandleChildPiece(unsigned i, RopePieceBTreeNode *RHS) {
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) {
@@ -665,19 +665,19 @@ static const RopePieceBTreeLeaf *getCN(const void *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.
@@ -691,12 +691,12 @@ void RopePieceBTreeIterator::MoveToNextPiece() {
++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().
@@ -740,7 +740,7 @@ 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);
@@ -750,7 +750,7 @@ 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);
}
@@ -766,38 +766,38 @@ void RopePieceBTree::erase(unsigned Offset, unsigned NumBytes) {
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 =
+ 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();
diff --git a/lib/Rewrite/Rewriter.cpp b/lib/Rewrite/Rewriter.cpp
index ec5a604..27a5f8b 100644
--- a/lib/Rewrite/Rewriter.cpp
+++ b/lib/Rewrite/Rewriter.cpp
@@ -26,7 +26,7 @@ void RewriteBuffer::RemoveText(unsigned OrigOffset, unsigned Size) {
unsigned RealOffset = getMappedOffset(OrigOffset, true);
assert(RealOffset+Size < Buffer.size() && "Invalid location");
-
+
// Remove the dead characters.
Buffer.erase(RealOffset, Size);
@@ -34,30 +34,29 @@ void RewriteBuffer::RemoveText(unsigned OrigOffset, unsigned Size) {
AddReplaceDelta(OrigOffset, -Size);
}
-void RewriteBuffer::InsertText(unsigned OrigOffset,
- const char *StrData, unsigned StrLen,
+void RewriteBuffer::InsertText(unsigned OrigOffset, const llvm::StringRef &Str,
bool InsertAfter) {
-
+
// Nothing to insert, exit early.
- if (StrLen == 0) return;
+ if (Str.empty()) return;
unsigned RealOffset = getMappedOffset(OrigOffset, InsertAfter);
- Buffer.insert(RealOffset, StrData, StrData+StrLen);
-
+ Buffer.insert(RealOffset, Str.begin(), Str.end());
+
// Add a delta so that future changes are offset correctly.
- AddInsertDelta(OrigOffset, StrLen);
+ AddInsertDelta(OrigOffset, Str.size());
}
/// ReplaceText - This method replaces a range of characters in the input
/// buffer with a new string. This is effectively a combined "remove+insert"
/// operation.
void RewriteBuffer::ReplaceText(unsigned OrigOffset, unsigned OrigLength,
- const char *NewStr, unsigned NewLength) {
+ const llvm::StringRef &NewStr) {
unsigned RealOffset = getMappedOffset(OrigOffset, true);
Buffer.erase(RealOffset, OrigLength);
- Buffer.insert(RealOffset, NewStr, NewStr+NewLength);
- if (OrigLength != NewLength)
- AddReplaceDelta(OrigOffset, NewLength-OrigLength);
+ Buffer.insert(RealOffset, NewStr.begin(), NewStr.end());
+ if (OrigLength != NewStr.size())
+ AddReplaceDelta(OrigOffset, NewStr.size() - OrigLength);
}
@@ -70,16 +69,16 @@ void RewriteBuffer::ReplaceText(unsigned OrigOffset, unsigned OrigLength,
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 =
@@ -90,17 +89,17 @@ int Rewriter::getRangeSize(SourceRange Range) const {
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.
+/// in different buffers, this returns an empty string.
///
/// Note that this method is not particularly efficient.
///
@@ -108,15 +107,15 @@ 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 =
@@ -124,17 +123,17 @@ std::string Rewriter::getRewritenText(SourceRange Range) const {
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);
@@ -144,7 +143,7 @@ std::string Rewriter::getRewritenText(SourceRange Range) const {
std::advance(Start, StartOff);
RewriteBuffer::iterator End = Start;
std::advance(End, EndOff-StartOff);
-
+
return std::string(Start, End);
}
@@ -162,24 +161,24 @@ unsigned Rewriter::getLocationOffsetAndFileID(SourceLocation Loc,
RewriteBuffer &Rewriter::getEditBuffer(FileID FID) {
std::map<FileID, RewriteBuffer>::iterator I =
RewriteBuffers.lower_bound(FID);
- if (I != RewriteBuffers.end() && I->first == 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) {
+bool Rewriter::InsertText(SourceLocation Loc, const llvm::StringRef &Str,
+ bool InsertAfter) {
if (!isRewritable(Loc)) return true;
FileID FID;
unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID);
- getEditBuffer(FID).InsertText(StartOffs, StrData, StrLen, InsertAfter);
+ getEditBuffer(FID).InsertText(StartOffs, Str, InsertAfter);
return false;
}
@@ -196,13 +195,12 @@ bool Rewriter::RemoveText(SourceLocation Start, unsigned Length) {
/// buffer with a new string. This is effectively a combined "remove/insert"
/// operation.
bool Rewriter::ReplaceText(SourceLocation Start, unsigned OrigLength,
- const char *NewStr, unsigned NewLength) {
+ const llvm::StringRef &NewStr) {
if (!isRewritable(Start)) return true;
FileID StartFileID;
unsigned StartOffs = getLocationOffsetAndFileID(Start, StartFileID);
-
- getEditBuffer(StartFileID).ReplaceText(StartOffs, OrigLength,
- NewStr, NewLength);
+
+ getEditBuffer(StartFileID).ReplaceText(StartOffs, OrigLength, NewStr);
return false;
}
@@ -214,14 +212,14 @@ bool Rewriter::ReplaceStmt(Stmt *From, Stmt *To) {
int Size = getRangeSize(From->getSourceRange());
if (Size == -1)
return true;
-
+
// Get the new text.
std::string SStr;
llvm::raw_string_ostream S(SStr);
To->printPretty(S, 0, PrintingPolicy(*LangOpts));
const std::string &Str = S.str();
- ReplaceText(From->getLocStart(), Size, &Str[0], Str.size());
+ ReplaceText(From->getLocStart(), Size, Str);
return false;
}
diff --git a/lib/Rewrite/TokenRewriter.cpp b/lib/Rewrite/TokenRewriter.cpp
index e17e801..0effbb1 100644
--- a/lib/Rewrite/TokenRewriter.cpp
+++ b/lib/Rewrite/TokenRewriter.cpp
@@ -21,10 +21,10 @@ 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);
@@ -39,7 +39,7 @@ TokenRewriter::TokenRewriter(FileID FID, SourceManager &SM,
Tok.setIdentifierInfo(PP.LookUpIdentifierInfo(Tok));
}
#endif
-
+
AddToken(RawTok, TokenList.end());
RawLex.LexFromRawLexer(RawTok);
}
@@ -53,10 +53,10 @@ TokenRewriter::~TokenRewriter() {
/// 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 =
+ std::map<SourceLocation, TokenRefTy>::iterator MapIt =
TokenAtLoc.find(I->getLocation());
assert(MapIt != TokenAtLoc.end() && "iterator not in rewriter?");
return MapIt->second;
@@ -65,22 +65,22 @@ TokenRewriter::TokenRefTy TokenRewriter::RemapIterator(token_iterator I) {
/// AddToken - Add the specified token into the Rewriter before the other
/// position.
-TokenRewriter::TokenRefTy
+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;
@@ -88,7 +88,7 @@ TokenRewriter::AddTokenBefore(token_iterator I, const char *Val) {
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);
diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt
index 85c67df..fd3265d 100644
--- a/lib/Sema/CMakeLists.txt
+++ b/lib/Sema/CMakeLists.txt
@@ -1,33 +1,33 @@
set(LLVM_NO_RTTI 1)
add_clang_library(clangSema
+ CodeCompleteConsumer.cpp
IdentifierResolver.cpp
JumpDiagnostics.cpp
ParseAST.cpp
Sema.cpp
SemaAccess.cpp
SemaAttr.cpp
- SemaChecking.cpp
+ SemaCXXCast.cpp
SemaCXXScopeSpec.cpp
- SemaDeclAttr.cpp
+ SemaChecking.cpp
+ SemaCodeComplete.cpp
SemaDecl.cpp
+ SemaDeclAttr.cpp
SemaDeclCXX.cpp
SemaDeclObjC.cpp
+ SemaExceptionSpec.cpp
SemaExpr.cpp
SemaExprCXX.cpp
SemaExprObjC.cpp
- SemaInherit.cpp
SemaInit.cpp
SemaLookup.cpp
- SemaNamedCast.cpp
SemaOverload.cpp
SemaStmt.cpp
SemaTemplate.cpp
SemaTemplateDeduction.cpp
SemaTemplateInstantiate.cpp
SemaTemplateInstantiateDecl.cpp
- SemaTemplateInstantiateExpr.cpp
- SemaTemplateInstantiateStmt.cpp
SemaType.cpp
)
diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp
new file mode 100644
index 0000000..c78ab5b
--- /dev/null
+++ b/lib/Sema/CodeCompleteConsumer.cpp
@@ -0,0 +1,184 @@
+//===--- CodeCompleteConsumer.cpp - Code Completion 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 implements the CodeCompleteConsumer class.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Sema/CodeCompleteConsumer.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/Parse/Scope.h"
+#include "clang/Lex/Preprocessor.h"
+#include "Sema.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cstring>
+#include <functional>
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Code completion string implementation
+//===----------------------------------------------------------------------===//
+CodeCompletionString::Chunk::Chunk(ChunkKind Kind, const char *Text)
+ : Kind(Kind), Text(0)
+{
+ assert((Kind == CK_Text || Kind == CK_Placeholder || Kind == CK_Informative)
+ && "Invalid text chunk kind");
+ char *New = new char [std::strlen(Text) + 1];
+ std::strcpy(New, Text);
+ this->Text = New;
+}
+
+CodeCompletionString::Chunk
+CodeCompletionString::Chunk::CreateText(const char *Text) {
+ return Chunk(CK_Text, Text);
+}
+
+CodeCompletionString::Chunk
+CodeCompletionString::Chunk::CreateOptional(
+ std::auto_ptr<CodeCompletionString> Optional) {
+ Chunk Result;
+ Result.Kind = CK_Optional;
+ Result.Optional = Optional.release();
+ return Result;
+}
+
+CodeCompletionString::Chunk
+CodeCompletionString::Chunk::CreatePlaceholder(const char *Placeholder) {
+ return Chunk(CK_Placeholder, Placeholder);
+}
+
+CodeCompletionString::Chunk
+CodeCompletionString::Chunk::CreateInformative(const char *Informative) {
+ return Chunk(CK_Informative, Informative);
+}
+
+void
+CodeCompletionString::Chunk::Destroy() {
+ switch (Kind) {
+ case CK_Optional:
+ delete Optional;
+ break;
+
+ case CK_Text:
+ case CK_Placeholder:
+ case CK_Informative:
+ delete [] Text;
+ break;
+ }
+}
+
+CodeCompletionString::~CodeCompletionString() {
+ std::for_each(Chunks.begin(), Chunks.end(),
+ std::mem_fun_ref(&Chunk::Destroy));
+}
+
+std::string CodeCompletionString::getAsString() const {
+ std::string Result;
+ llvm::raw_string_ostream OS(Result);
+
+ for (iterator C = begin(), CEnd = end(); C != CEnd; ++C) {
+ switch (C->Kind) {
+ case CK_Text: OS << C->Text; break;
+ case CK_Optional: OS << "{#" << C->Optional->getAsString() << "#}"; break;
+ case CK_Placeholder: OS << "<#" << C->Text << "#>"; break;
+ case CK_Informative: OS << "[#" << C->Text << "#]"; break;
+ }
+ }
+ OS.flush();
+ return Result;
+}
+
+//===----------------------------------------------------------------------===//
+// Code completion overload candidate implementation
+//===----------------------------------------------------------------------===//
+FunctionDecl *
+CodeCompleteConsumer::OverloadCandidate::getFunction() const {
+ if (getKind() == CK_Function)
+ return Function;
+ else if (getKind() == CK_FunctionTemplate)
+ return FunctionTemplate->getTemplatedDecl();
+ else
+ return 0;
+}
+
+const FunctionType *
+CodeCompleteConsumer::OverloadCandidate::getFunctionType() const {
+ switch (Kind) {
+ case CK_Function:
+ return Function->getType()->getAs<FunctionType>();
+
+ case CK_FunctionTemplate:
+ return FunctionTemplate->getTemplatedDecl()->getType()
+ ->getAs<FunctionType>();
+
+ case CK_FunctionType:
+ return Type;
+ }
+
+ return 0;
+}
+
+//===----------------------------------------------------------------------===//
+// Code completion consumer implementation
+//===----------------------------------------------------------------------===//
+
+CodeCompleteConsumer::~CodeCompleteConsumer() { }
+
+void
+PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Result *Results,
+ unsigned NumResults) {
+ // Print the results.
+ for (unsigned I = 0; I != NumResults; ++I) {
+ OS << "COMPLETION: ";
+ switch (Results[I].Kind) {
+ case Result::RK_Declaration:
+ OS << Results[I].Declaration->getNameAsString() << " : "
+ << Results[I].Rank;
+ if (Results[I].Hidden)
+ OS << " (Hidden)";
+ if (CodeCompletionString *CCS
+ = Results[I].CreateCodeCompletionString(SemaRef)) {
+ OS << " : " << CCS->getAsString();
+ delete CCS;
+ }
+
+ OS << '\n';
+ break;
+
+ case Result::RK_Keyword:
+ OS << Results[I].Keyword << " : " << Results[I].Rank << '\n';
+ break;
+ }
+ }
+
+ // Once we've printed the code-completion results, suppress remaining
+ // diagnostics.
+ // FIXME: Move this somewhere else!
+ SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics();
+}
+
+void
+PrintingCodeCompleteConsumer::ProcessOverloadCandidates(unsigned CurrentArg,
+ OverloadCandidate *Candidates,
+ unsigned NumCandidates) {
+ for (unsigned I = 0; I != NumCandidates; ++I) {
+ if (CodeCompletionString *CCS
+ = Candidates[I].CreateSignatureString(CurrentArg, SemaRef)) {
+ OS << "OVERLOAD: " << CCS->getAsString() << "\n";
+ delete CCS;
+ }
+ }
+
+ // Once we've printed the code-completion results, suppress remaining
+ // diagnostics.
+ // FIXME: Move this somewhere else!
+ SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics();
+}
diff --git a/lib/Sema/IdentifierResolver.cpp b/lib/Sema/IdentifierResolver.cpp
index ceab859..0dbf219 100644
--- a/lib/Sema/IdentifierResolver.cpp
+++ b/lib/Sema/IdentifierResolver.cpp
@@ -32,7 +32,7 @@ class IdentifierResolver::IdDeclInfoMap {
// New vectors are added when the current one is full.
std::list< std::vector<IdDeclInfo> > IDIVecs;
unsigned int CurIndex;
-
+
public:
IdDeclInfoMap() : CurIndex(VECTOR_SIZE) {}
@@ -75,7 +75,7 @@ void IdentifierResolver::IdDeclInfo::RemoveDecl(NamedDecl *D) {
assert(0 && "Didn't find this decl on its identifier's chain!");
}
-bool
+bool
IdentifierResolver::IdDeclInfo::ReplaceDecl(NamedDecl *Old, NamedDecl *New) {
for (DeclsTy::iterator I = Decls.end(); I != Decls.begin(); --I) {
if (Old == *(I-1)) {
@@ -108,7 +108,7 @@ bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx,
if (Ctx->isFunctionOrMethod()) {
// Ignore the scopes associated within transparent declaration contexts.
- while (S->getEntity() &&
+ while (S->getEntity() &&
((DeclContext *)S->getEntity())->isTransparentContext())
S = S->getParent();
@@ -134,7 +134,7 @@ bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx,
return false;
}
- return D->getDeclContext()->getLookupContext() == Ctx->getPrimaryContext();
+ return D->getDeclContext()->getLookupContext()->Equals(Ctx);
}
/// AddDecl - Link the decl to its shadowed decl chain.
@@ -200,14 +200,14 @@ void IdentifierResolver::RemoveDecl(NamedDecl *D) {
Name.setFETokenInfo(NULL);
return;
}
-
+
return toIdDeclInfo(Ptr)->RemoveDecl(D);
}
bool IdentifierResolver::ReplaceDecl(NamedDecl *Old, NamedDecl *New) {
- assert(Old->getDeclName() == New->getDeclName() &&
+ 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>();
@@ -222,7 +222,7 @@ bool IdentifierResolver::ReplaceDecl(NamedDecl *Old, NamedDecl *New) {
return false;
}
- return toIdDeclInfo(Ptr)->ReplaceDecl(Old, New);
+ return toIdDeclInfo(Ptr)->ReplaceDecl(Old, New);
}
/// begin - Returns an iterator for decls with name 'Name'.
@@ -243,7 +243,7 @@ IdentifierResolver::begin(DeclarationName Name) {
return end();
}
-void IdentifierResolver::AddDeclToIdentifierChain(IdentifierInfo *II,
+void IdentifierResolver::AddDeclToIdentifierChain(IdentifierInfo *II,
NamedDecl *D) {
void *Ptr = II->getFETokenInfo<void>();
diff --git a/lib/Sema/IdentifierResolver.h b/lib/Sema/IdentifierResolver.h
index 0b0e6b3..65f3256 100644
--- a/lib/Sema/IdentifierResolver.h
+++ b/lib/Sema/IdentifierResolver.h
@@ -99,7 +99,7 @@ public:
assert(isIterator() && "Ptr not an iterator!");
return reinterpret_cast<BaseIter>(Ptr & ~0x3);
}
-
+
friend class IdentifierResolver;
public:
iterator() : Ptr(0) {}
@@ -110,14 +110,14 @@ public:
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.
@@ -127,7 +127,7 @@ public:
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);
@@ -138,7 +138,7 @@ public:
}
uintptr_t getAsOpaqueValue() const { return Ptr; }
-
+
static iterator getFromOpaqueValue(uintptr_t P) {
iterator Result;
Result.Ptr = P;
diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp
index ae863f2..a8e31d2 100644
--- a/lib/Sema/JumpDiagnostics.cpp
+++ b/lib/Sema/JumpDiagnostics.cpp
@@ -28,7 +28,7 @@ namespace {
///
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,
@@ -38,17 +38,17 @@ class JumpScopeChecker {
/// 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;
@@ -66,15 +66,15 @@ private:
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) {
@@ -83,11 +83,13 @@ static unsigned GetDiagForGotoScopeDecl(const Decl *D) {
return diag::note_protected_by_vla;
if (VD->hasAttr<CleanupAttr>())
return diag::note_protected_by_cleanup;
+ if (VD->hasAttr<BlocksAttr>())
+ return diag::note_protected_by___block;
} else if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
if (TD->getUnderlyingType()->isVariablyModifiedType())
return diag::note_protected_by_vla_typedef;
}
-
+
return 0;
}
@@ -97,7 +99,7 @@ static unsigned GetDiagForGotoScopeDecl(const Decl *D) {
/// 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;
@@ -108,12 +110,12 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
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: ;
@@ -129,7 +131,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
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))
@@ -154,10 +156,10 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
Scopes.push_back(GotoScope(ParentScope,
diag::note_protected_by_objc_catch,
AC->getAtCatchLoc()));
- // @catches are nested and it isn't
+ // @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,
@@ -165,17 +167,17 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
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,
@@ -194,7 +196,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
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) {
+ 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,
@@ -215,14 +217,14 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
void JumpScopeChecker::VerifyJumps() {
while (!Jumps.empty()) {
Stmt *Jump = Jumps.pop_back_val();
-
- // With a goto,
+
+ // 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()) {
@@ -234,7 +236,7 @@ void JumpScopeChecker::VerifyJumps() {
}
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)) {
@@ -252,12 +254,12 @@ void JumpScopeChecker::VerifyJumps() {
// 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;
}
@@ -280,10 +282,10 @@ void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To,
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.
@@ -292,11 +294,11 @@ void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To,
// 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);
@@ -316,7 +318,7 @@ void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To,
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);
diff --git a/lib/Sema/ParseAST.cpp b/lib/Sema/ParseAST.cpp
index e2ee88a..d3f26d8 100644
--- a/lib/Sema/ParseAST.cpp
+++ b/lib/Sema/ParseAST.cpp
@@ -13,13 +13,15 @@
#include "clang/Sema/ParseAST.h"
#include "Sema.h"
+#include "clang/Sema/CodeCompleteConsumer.h"
#include "clang/Sema/SemaConsumer.h"
#include "clang/Sema/ExternalSemaSource.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ExternalASTSource.h"
#include "clang/AST/Stmt.h"
#include "clang/Parse/Parser.h"
-#include "llvm/ADT/OwningPtr.h"
+#include <cstdio>
+
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -32,7 +34,9 @@ using namespace clang;
///
void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer,
ASTContext &Ctx, bool PrintStats,
- bool CompleteTranslationUnit) {
+ bool CompleteTranslationUnit,
+ CodeCompleteConsumer *(*CreateCodeCompleter)(Sema &, void *Data),
+ void *CreateCodeCompleterData) {
// Collect global stats on Decls/Stmts (until we have a module streamer).
if (PrintStats) {
Decl::CollectingStats(true);
@@ -42,25 +46,31 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer,
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 =
+ if (ExternalSemaSource *ExternalSema =
dyn_cast<ExternalSemaSource>(External))
ExternalSema->InitializeSema(S);
External->StartTranslationUnit(Consumer);
}
- Parser::DeclGroupPtrTy ADecl;
+ CodeCompleteConsumer *CodeCompleter = 0;
+ if (CreateCodeCompleter) {
+ CodeCompleter = CreateCodeCompleter(S, CreateCodeCompleterData);
+ S.setCodeCompleteConsumer(CodeCompleter);
+ }
+ 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
@@ -68,9 +78,18 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer,
if (ADecl)
Consumer->HandleTopLevelDecl(ADecl.getAsVal<DeclGroupRef>());
};
-
+
+ // process any TopLevelDecls generated by #pragma weak
+ for (llvm::SmallVector<Decl*,2>::iterator
+ I = S.WeakTopLevelDecls().begin(),
+ E = S.WeakTopLevelDecls().end(); I != E; ++I)
+ Consumer->HandleTopLevelDecl(DeclGroupRef(*I));
+
Consumer->HandleTranslationUnit(Ctx);
+ if (CreateCodeCompleter)
+ delete CodeCompleter;
+
if (PrintStats) {
fprintf(stderr, "\nSTATISTICS:\n");
P.getActions().PrintStats();
@@ -78,7 +97,7 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer,
Decl::PrintStats();
Stmt::PrintStats();
Consumer->PrintStats();
-
+
Decl::CollectingStats(false);
Stmt::CollectingStats(false);
}
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index d1e8e21..ba05a07 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -13,15 +13,65 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "llvm/ADT/DenseMap.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/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
using namespace clang;
-/// ConvertQualTypeToStringFn - This function is used to pretty print the
+/// \brief Convert the given type to a string suitable for printing as part of
+/// a diagnostic.
+///
+/// \param Context the context in which the type was allocated
+/// \param Ty the type to print
+static std::string ConvertTypeToDiagnosticString(ASTContext &Context,
+ QualType Ty) {
+ // FIXME: Playing with std::string is really slow.
+ std::string 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();
+
+ 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 aka just because we saw an elaborated type...
+ (!isa<ElaboratedType>(Ty) ||
+ cast<ElaboratedType>(Ty)->desugar() != DesugaredTy) &&
+
+ // ...or a qualified name type...
+ (!isa<QualifiedNameType>(Ty) ||
+ cast<QualifiedNameType>(Ty)->desugar() != DesugaredTy) &&
+
+ // ...or a non-dependent template specialization.
+ (!isa<TemplateSpecializationType>(Ty) || Ty->isDependentType()) &&
+
+ // Don't desugar magic Objective-C types.
+ Ty.getUnqualifiedType() != Context.getObjCIdType() &&
+ Ty.getUnqualifiedType() != Context.getObjCClassType() &&
+ Ty.getUnqualifiedType() != Context.getObjCSelType() &&
+ Ty.getUnqualifiedType() != Context.getObjCProtoType() &&
+
+ // Not va_list.
+ Ty.getUnqualifiedType() != Context.getBuiltinVaListType()) {
+ S = "'"+S+"' (aka '";
+ S += DesugaredTy.getAsString(Context.PrintingPolicy);
+ S += "')";
+ return S;
+ }
+
+ S = "'" + S + "'";
+ return S;
+}
+
+/// 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,
@@ -29,48 +79,21 @@ static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val,
llvm::SmallVectorImpl<char> &Output,
void *Cookie) {
ASTContext &Context = *static_cast<ASTContext*>(Cookie);
-
+
std::string S;
+ bool NeedQuotes = true;
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(Context.PrintingPolicy);
- S += "')";
- Output.append(S.begin(), S.end());
- return;
- }
-
+ S = ConvertTypeToDiagnosticString(Context, Ty);
+ NeedQuotes = false;
} 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)
@@ -78,30 +101,73 @@ static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val,
else
assert(ModLen == 0 && ArgLen == 0 &&
"Invalid modifier for DeclarationName argument");
- } else {
- assert(Kind == Diagnostic::ak_nameddecl);
+ } else if (Kind == Diagnostic::ak_nameddecl) {
+ bool Qualified;
if (ModLen == 1 && Modifier[0] == 'q' && ArgLen == 0)
- S = reinterpret_cast<NamedDecl*>(Val)->getQualifiedNameAsString();
- else {
+ Qualified = true;
+ else {
assert(ModLen == 0 && ArgLen == 0 &&
"Invalid modifier for NamedDecl* argument");
- S = reinterpret_cast<NamedDecl*>(Val)->getNameAsString();
+ Qualified = false;
+ }
+ reinterpret_cast<NamedDecl*>(Val)->getNameForDiagnostic(S,
+ Context.PrintingPolicy,
+ Qualified);
+ } else if (Kind == Diagnostic::ak_nestednamespec) {
+ llvm::raw_string_ostream OS(S);
+ reinterpret_cast<NestedNameSpecifier*> (Val)->print(OS,
+ Context.PrintingPolicy);
+ NeedQuotes = false;
+ } else {
+ assert(Kind == Diagnostic::ak_declcontext);
+ DeclContext *DC = reinterpret_cast<DeclContext *> (Val);
+ NeedQuotes = false;
+ if (!DC) {
+ assert(false && "Should never have a null declaration context");
+ S = "unknown context";
+ } else if (DC->isTranslationUnit()) {
+ // FIXME: Get these strings from some localized place
+ if (Context.getLangOptions().CPlusPlus)
+ S = "the global namespace";
+ else
+ S = "the global scope";
+ } else if (TypeDecl *Type = dyn_cast<TypeDecl>(DC)) {
+ S = ConvertTypeToDiagnosticString(Context, Context.getTypeDeclType(Type));
+ NeedQuotes = false;
+ } else {
+ // FIXME: Get these strings from some localized place
+ NamedDecl *ND = cast<NamedDecl>(DC);
+ if (isa<NamespaceDecl>(ND))
+ S += "namespace ";
+ else if (isa<ObjCMethodDecl>(ND))
+ S += "method ";
+ else if (isa<FunctionDecl>(ND))
+ S += "function ";
+
+ S += "'";
+ ND->getNameForDiagnostic(S, Context.PrintingPolicy, true);
+ S += "'";
+ NeedQuotes = false;
}
}
+
+ if (NeedQuotes)
+ Output.push_back('\'');
- Output.push_back('\'');
Output.append(S.begin(), S.end());
- Output.push_back('\'');
+
+ if (NeedQuotes)
+ Output.push_back('\'');
}
static inline RecordDecl *CreateStructDecl(ASTContext &C, const char *Name) {
if (C.getLangOptions().CPlusPlus)
- return CXXRecordDecl::Create(C, TagDecl::TK_struct,
+ return CXXRecordDecl::Create(C, TagDecl::TK_struct,
C.getTranslationUnitDecl(),
SourceLocation(), &C.Idents.get(Name));
- return RecordDecl::Create(C, TagDecl::TK_struct,
+ return RecordDecl::Create(C, TagDecl::TK_struct,
C.getTranslationUnitDecl(),
SourceLocation(), &C.Idents.get(Name));
}
@@ -109,7 +175,7 @@ static inline RecordDecl *CreateStructDecl(ASTContext &C, const char *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,
@@ -121,16 +187,16 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
&Context.Idents.get("__uint128_t"),
Context.UnsignedInt128Ty), TUScope);
}
-
-
+
+
if (!PP.getLangOptions().ObjC1) return;
-
+
// Built-in ObjC types may already be set by PCHReader (hence isNull checks).
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(),
@@ -140,74 +206,72 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
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"),
+ &Context.Idents.get("Protocol"),
SourceLocation(), true);
Context.setObjCProtoType(Context.getObjCInterfaceType(ProtocolDecl));
PushOnScopeChains(ProtocolDecl, TUScope);
}
-
- // Synthesize "typedef struct objc_object { Class isa; } *id;"
+ // Create the built-in typedef for '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);
+ TypedefDecl *IdTypedef =
+ TypedefDecl::Create(
+ Context, CurContext, SourceLocation(), &Context.Idents.get("id"),
+ Context.getObjCObjectPointerType(Context.ObjCBuiltinIdTy)
+ );
PushOnScopeChains(IdTypedef, TUScope);
Context.setObjCIdType(Context.getTypeDeclType(IdTypedef));
+ Context.ObjCIdRedefinitionType = Context.getObjCIdType();
+ }
+ // Create the built-in typedef for 'Class'.
+ if (Context.getObjCClassType().isNull()) {
+ TypedefDecl *ClassTypedef =
+ TypedefDecl::Create(
+ Context, CurContext, SourceLocation(), &Context.Idents.get("Class"),
+ Context.getObjCObjectPointerType(Context.ObjCBuiltinClassTy)
+ );
+ PushOnScopeChains(ClassTypedef, TUScope);
+ Context.setObjCClassType(Context.getTypeDeclType(ClassTypedef));
+ Context.ObjCClassRedefinitionType = Context.getObjCClassType();
}
}
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()),
+ Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
+ ExternalSource(0), CodeCompleter(0), CurContext(0),
+ PreDeclaratorDC(0), CurBlock(0), PackContext(0),
+ IdResolver(pp.getLangOptions()), StdNamespace(0), StdBadAlloc(0),
GlobalNewDeleteDeclared(false), ExprEvalContext(PotentiallyEvaluated),
CompleteTranslationUnit(CompleteTranslationUnit),
NumSFINAEErrors(0), 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.
+/// 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) {
+void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty,
+ CastExpr::CastKind Kind, 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 =
+ QualType ExprBaseType =
cast<PointerType>(ExprTy.getUnqualifiedType())->getPointeeType();
QualType BaseType =
cast<PointerType>(TypeTy.getUnqualifiedType())->getPointeeType();
@@ -216,12 +280,16 @@ void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty, bool isLvalue) {
<< Expr->getSourceRange();
}
}
-
+
if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(Expr)) {
- ImpCast->setType(Ty);
- ImpCast->setLvalueCast(isLvalue);
- } else
- Expr = new (Context) ImplicitCastExpr(Ty, Expr, isLvalue);
+ if (ImpCast->getCastKind() == Kind) {
+ ImpCast->setType(Ty);
+ ImpCast->setLvalueCast(isLvalue);
+ return;
+ }
+ }
+
+ Expr = new (Context) ImplicitCastExpr(Ty, Kind, Expr, isLvalue);
}
void Sema::DeleteExpr(ExprTy *E) {
@@ -241,12 +309,24 @@ void Sema::ActOnEndOfTranslationUnit() {
// keep track of the point of instantiation (C++ [temp.point]). This means
// that name lookup that occurs within the template instantiation will
// always happen at the end of the translation unit, so it will find
- // some names that should not be found. Although this is common behavior
+ // some names that should not be found. Although this is common behavior
// for C++ compilers, it is technically wrong. In the future, we either need
// to be able to filter the results of name lookup or we need to perform
// template instantiations earlier.
PerformPendingImplicitInstantiations();
-
+
+ // Check for #pragma weak identifiers that were never declared
+ // FIXME: This will cause diagnostics to be emitted in a non-determinstic
+ // order! Iterating over a densemap like this is bad.
+ for (llvm::DenseMap<IdentifierInfo*,WeakInfo>::iterator
+ I = WeakUndeclaredIdentifiers.begin(),
+ E = WeakUndeclaredIdentifiers.end(); I != E; ++I) {
+ if (I->second.getUsed()) continue;
+
+ Diag(I->second.getLocation(), diag::warn_weak_identifier_undeclared)
+ << I->first;
+ }
+
if (!CompleteTranslationUnit)
return;
@@ -261,32 +341,31 @@ void Sema::ActOnEndOfTranslationUnit() {
// 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;
+ for (unsigned i = 0, e = TentativeDefinitionList.size(); i != e; ++i) {
+ VarDecl *VD = TentativeDefinitions.lookup(TentativeDefinitionList[i]);
- if (VD->isInvalidDecl() || !VD->isTentativeDefinition(Context))
+ // If the tentative definition was completed, it will be in the list, but
+ // not the map.
+ if (VD == 0 || VD->isInvalidDecl() || !VD->isTentativeDefinition(Context))
continue;
- if (const IncompleteArrayType *ArrayT
+ if (const IncompleteArrayType *ArrayT
= Context.getAsIncompleteArrayType(VD->getType())) {
- if (RequireCompleteType(VD->getLocation(),
+ if (RequireCompleteType(VD->getLocation(),
ArrayT->getElementType(),
- diag::err_tentative_def_incomplete_type_arr))
+ 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);
+ continue;
}
- } else if (RequireCompleteType(VD->getLocation(), VD->getType(),
+
+ // 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.getConstantArrayWithoutExprType(ArrayT->getElementType(),
+ One, ArrayType::Normal, 0);
+ VD->setType(T);
+ } else if (RequireCompleteType(VD->getLocation(), VD->getType(),
diag::err_tentative_def_incomplete_type))
VD->setInvalidDecl();
@@ -302,27 +381,30 @@ void Sema::ActOnEndOfTranslationUnit() {
// Helper functions.
//===----------------------------------------------------------------------===//
+DeclContext *Sema::getFunctionLevelDeclContext() {
+ DeclContext *DC = PreDeclaratorDC ? PreDeclaratorDC : CurContext;
+
+ while (isa<BlockDecl>(DC))
+ DC = DC->getParent();
+
+ return DC;
+}
+
/// 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();
+ DeclContext *DC = getFunctionLevelDeclContext();
return dyn_cast<FunctionDecl>(DC);
}
ObjCMethodDecl *Sema::getCurMethodDecl() {
- DeclContext *DC = CurContext;
- while (isa<BlockDecl>(DC))
- DC = DC->getParent();
+ DeclContext *DC = getFunctionLevelDeclContext();
return dyn_cast<ObjCMethodDecl>(DC);
}
NamedDecl *Sema::getCurFunctionOrMethodDecl() {
- DeclContext *DC = CurContext;
- while (isa<BlockDecl>(DC))
- DC = DC->getParent();
+ DeclContext *DC = getFunctionLevelDeclContext();
if (isa<ObjCMethodDecl>(DC) || isa<FunctionDecl>(DC))
return cast<NamedDecl>(DC);
return 0;
@@ -331,21 +413,30 @@ NamedDecl *Sema::getCurFunctionOrMethodDecl() {
Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() {
if (!this->Emit())
return;
-
+
// 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.ActiveTemplateInstantiations.back()
!= SemaRef.LastTemplateInstantiationErrorContext) {
SemaRef.PrintInstantiationStack();
- SemaRef.LastTemplateInstantiationErrorContext
+ SemaRef.LastTemplateInstantiationErrorContext
= SemaRef.ActiveTemplateInstantiations.back();
}
}
+Sema::SemaDiagnosticBuilder
+Sema::Diag(SourceLocation Loc, const PartialDiagnostic& PD) {
+ SemaDiagnosticBuilder Builder(Diag(Loc, PD.getDiagID()));
+ PD.Emit(Builder);
+
+ return Builder;
+}
+
void Sema::ActOnComment(SourceRange Comment) {
Context.Comments.push_back(Comment);
}
+
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 7af80c0..80f3663 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -18,6 +18,7 @@
#include "IdentifierResolver.h"
#include "CXXFieldCollector.h"
#include "SemaOverload.h"
+#include "SemaTemplate.h"
#include "clang/AST/Attr.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/Decl.h"
@@ -41,6 +42,7 @@ namespace llvm {
namespace clang {
class ASTContext;
class ASTConsumer;
+ class CodeCompleteConsumer;
class Preprocessor;
class Decl;
class DeclContext;
@@ -50,6 +52,7 @@ namespace clang {
class Stmt;
class Expr;
class InitListExpr;
+ class ParenListExpr;
class DesignatedInitExpr;
class CallExpr;
class DeclRefExpr;
@@ -87,8 +90,7 @@ namespace clang {
class ObjCPropertyDecl;
class ObjCContainerDecl;
class FunctionProtoType;
- class BasePaths;
- struct MemberLookupCriteria;
+ class CXXBasePaths;
class CXXTemporary;
/// BlockSemaInfo - When a block is being parsed, this contains information
@@ -98,35 +100,69 @@ struct BlockSemaInfo {
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.
QualType 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;
};
+/// \brief Holds a QualType and a DeclaratorInfo* that came out of a declarator
+/// parsing.
+///
+/// LocInfoType is a "transient" type, only needed for passing to/from Parser
+/// and Sema, when we want to preserve type source info for a parsed type.
+/// It will not participate in the type system semantics in any way.
+class LocInfoType : public Type {
+ enum {
+ // The last number that can fit in Type's TC.
+ // Avoids conflict with an existing Type class.
+ LocInfo = (1 << TypeClassBitSize) - 1
+ };
+
+ DeclaratorInfo *DeclInfo;
+
+ LocInfoType(QualType ty, DeclaratorInfo *DInfo)
+ : Type((TypeClass)LocInfo, ty, ty->isDependentType()), DeclInfo(DInfo) {
+ assert(getTypeClass() == (TypeClass)LocInfo && "LocInfo didn't fit in TC?");
+ }
+ friend class Sema;
+
+public:
+ QualType getType() const { return getCanonicalTypeInternal(); }
+ DeclaratorInfo *getDeclaratorInfo() const { return DeclInfo; }
+
+ virtual void getAsStringInternal(std::string &Str,
+ const PrintingPolicy &Policy) const;
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == (TypeClass)LocInfo;
+ }
+ static bool classof(const LocInfoType *) { return true; }
+};
+
/// Sema - This implements semantic analysis and AST building for C.
class Sema : public Action {
Sema(const Sema&); // DO NOT IMPLEMENT
@@ -142,6 +178,9 @@ public:
/// \brief Source of additional semantic information.
ExternalSemaSource *ExternalSource;
+ /// \brief Code-completion consumer.
+ CodeCompleteConsumer *CodeCompleter;
+
/// CurContext - This is the current declaration context of parsing.
DeclContext *CurContext;
@@ -165,13 +204,13 @@ public:
/// 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
+ /// ExprTemporaries - This is the stack of temporaries that are created by
/// the current full expression.
llvm::SmallVector<CXXTemporary*, 8> ExprTemporaries;
@@ -180,26 +219,22 @@ public:
/// 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
+
+ /// 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.
///
@@ -234,6 +269,37 @@ public:
/// declaration, and only the most recent tentative declaration for
/// a given variable will be recorded here.
llvm::DenseMap<DeclarationName, VarDecl *> TentativeDefinitions;
+ std::vector<DeclarationName> TentativeDefinitionList;
+
+ /// WeakUndeclaredIdentifiers - Identifiers contained in
+ /// #pragma weak before declared. rare. may alias another
+ /// identifier, declared or undeclared
+ class WeakInfo {
+ IdentifierInfo *alias; // alias (optional)
+ SourceLocation loc; // for diagnostics
+ bool used; // identifier later declared?
+ public:
+ WeakInfo()
+ : alias(0), loc(SourceLocation()), used(false) {}
+ WeakInfo(IdentifierInfo *Alias, SourceLocation Loc)
+ : alias(Alias), loc(Loc), used(false) {}
+ inline IdentifierInfo * getAlias() const { return alias; }
+ inline SourceLocation getLocation() const { return loc; }
+ void setUsed(bool Used=true) { used = Used; }
+ inline bool getUsed() { return used; }
+ bool operator==(WeakInfo RHS) const {
+ return alias == RHS.getAlias() && loc == RHS.getLocation();
+ }
+ bool operator!=(WeakInfo RHS) const { return !(*this == RHS); }
+ };
+ llvm::DenseMap<IdentifierInfo*,WeakInfo> WeakUndeclaredIdentifiers;
+
+ /// WeakTopLevelDecl - Translation-unit scoped declarations generated by
+ /// #pragma weak during processing of other Decls.
+ /// I couldn't figure out a clean way to generate these in-line, so
+ /// we store them here and handle separately -- which is a hack.
+ /// It would be best to refactor this.
+ llvm::SmallVector<Decl*,2> WeakTopLevelDecl;
IdentifierResolver IdResolver;
@@ -242,27 +308,30 @@ public:
/// 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
+ /// \brief The C++ "std" namespace, where the standard library resides.
NamespaceDecl *StdNamespace;
+ /// \brief The C++ "std::bad_alloc" class, which is defined by the C++
+ /// standard library.
+ CXXRecordDecl *StdBadAlloc;
+
/// A flag to remember whether the implicit forms of operator new and delete
/// have been declared.
bool GlobalNewDeleteDeclared;
/// The current expression evaluation context.
ExpressionEvaluationContext ExprEvalContext;
-
- typedef std::vector<std::pair<SourceLocation, Decl *> >
+
+ typedef std::vector<std::pair<SourceLocation, Decl *> >
PotentiallyReferencedDecls;
-
+
/// A stack of declarations, each element of which is a set of declarations
/// that will be marked as referenced if the corresponding potentially
/// potentially evaluated expression is potentially evaluated. Each element
/// in the stack corresponds to a PotentiallyPotentiallyEvaluated expression
/// evaluation context.
std::list<PotentiallyReferencedDecls> PotentiallyReferencedDeclStack;
-
+
/// \brief Whether the code handled by Sema should be considered a
/// complete translation unit or not.
///
@@ -274,6 +343,8 @@ public:
/// unit.
bool CompleteTranslationUnit;
+ llvm::BumpPtrAllocator BumpAlloc;
+
/// \brief The number of SFINAE diagnostics that have been trapped.
unsigned NumSFINAEErrors;
@@ -281,11 +352,11 @@ public:
/// 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
+ /// 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'.
@@ -296,7 +367,7 @@ public:
~Sema() {
if (PackContext) FreePackedContext();
}
-
+
const LangOptions &getLangOptions() const { return LangOpts; }
Diagnostic &getDiagnostics() const { return Diags; }
SourceManager &getSourceManager() const { return SourceMgr; }
@@ -318,7 +389,7 @@ public:
SemaDiagnosticBuilder(DiagnosticBuilder &DB, Sema &SemaRef, unsigned DiagID)
: DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) { }
- explicit SemaDiagnosticBuilder(Sema &SemaRef)
+ explicit SemaDiagnosticBuilder(Sema &SemaRef)
: DiagnosticBuilder(DiagnosticBuilder::Suppress), SemaRef(SemaRef) { }
~SemaDiagnosticBuilder();
@@ -331,6 +402,7 @@ public:
// deduction, and that error is one of the SFINAE errors,
// suppress the diagnostic.
++NumSFINAEErrors;
+ Diags.setLastDiagnosticIgnored();
return SemaDiagnosticBuilder(*this);
}
@@ -338,6 +410,9 @@ public:
return SemaDiagnosticBuilder(DB, *this, DiagID);
}
+ /// \brief Emit a partial diagnostic.
+ SemaDiagnosticBuilder Diag(SourceLocation Loc, const PartialDiagnostic& PD);
+
virtual void DeleteExpr(ExprTy *E);
virtual void DeleteStmt(StmtTy *S);
@@ -356,13 +431,16 @@ public:
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;
}
-
+
+ /// WeakTopLevelDeclDecls - access to #pragma weak-generated Decls
+ llvm::SmallVector<Decl*,2> &WeakTopLevelDecls() { return WeakTopLevelDecl; }
+
virtual void ActOnComment(SourceRange Comment);
//===--------------------------------------------------------------------===//
@@ -370,34 +448,51 @@ public:
//
QualType adjustParameterType(QualType T);
QualType ConvertDeclSpecToType(const DeclSpec &DS, SourceLocation DeclLoc,
- bool &IsInvalid);
+ bool &IsInvalid, QualType &SourceTy);
void ProcessTypeAttributeList(QualType &Result, const AttributeList *AL);
- QualType BuildPointerType(QualType T, unsigned Quals,
+ 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 BuildExtVectorType(QualType T, ExprArg ArraySize,
+ SourceRange Brackets, DeclarationName Entity);
+ QualType BuildExtVectorType(QualType T, ExprArg ArraySize,
SourceLocation AttrLoc);
QualType BuildFunctionType(QualType T,
QualType *ParamTypes, unsigned NumParamTypes,
bool Variadic, unsigned Quals,
SourceLocation Loc, DeclarationName Entity);
- QualType BuildMemberPointerType(QualType T, QualType Class,
- unsigned Quals, SourceLocation Loc,
+ QualType BuildMemberPointerType(QualType T, QualType Class,
+ unsigned Quals, SourceLocation Loc,
DeclarationName Entity);
QualType BuildBlockPointerType(QualType T, unsigned Quals,
SourceLocation Loc, DeclarationName Entity);
- QualType GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip = 0,
- TagDecl **OwnedDecl = 0);
+ QualType GetTypeForDeclarator(Declarator &D, Scope *S,
+ DeclaratorInfo **DInfo = 0,
+ unsigned Skip = 0, TagDecl **OwnedDecl = 0);
+ DeclaratorInfo *GetDeclaratorInfoForDeclarator(Declarator &D, QualType T,
+ unsigned Skip);
+ /// \brief Create a LocInfoType to hold the given QualType and DeclaratorInfo.
+ QualType CreateLocInfoType(QualType T, DeclaratorInfo *DInfo);
DeclarationName GetNameForDeclarator(Declarator &D);
+ static QualType GetTypeFromParser(TypeTy *Ty, DeclaratorInfo **DInfo = 0);
bool CheckSpecifiedExceptionType(QualType T, const SourceRange &Range);
bool CheckDistantExceptionSpec(QualType T);
bool CheckEquivalentExceptionSpec(
const FunctionProtoType *Old, SourceLocation OldLoc,
const FunctionProtoType *New, SourceLocation NewLoc);
+ bool CheckEquivalentExceptionSpec(
+ const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
+ const FunctionProtoType *Old, SourceLocation OldLoc,
+ const FunctionProtoType *New, SourceLocation NewLoc);
+ bool CheckExceptionSpecSubset(
+ const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
+ const FunctionProtoType *Superset, SourceLocation SuperLoc,
+ const FunctionProtoType *Subset, SourceLocation SubLoc);
+ bool CheckParamExceptionSpec(const PartialDiagnostic & NoteID,
+ const FunctionProtoType *Target, SourceLocation TargetLoc,
+ const FunctionProtoType *Source, SourceLocation SourceLoc);
QualType ObjCGetTypeForMethodDefinition(DeclPtrTy D);
@@ -405,72 +500,87 @@ public:
virtual TypeResult ActOnTypeName(Scope *S, Declarator &D);
- bool RequireCompleteType(SourceLocation Loc, QualType T, unsigned diag,
- SourceRange Range1 = SourceRange(),
- SourceRange Range2 = SourceRange(),
- QualType PrintType = QualType());
+ bool RequireCompleteType(SourceLocation Loc, QualType T,
+ const PartialDiagnostic &PD,
+ std::pair<SourceLocation,
+ PartialDiagnostic> Note =
+ std::make_pair(SourceLocation(), PDiag()));
QualType getQualifiedNameType(const CXXScopeSpec &SS, QualType T);
QualType BuildTypeofExprType(Expr *E);
QualType BuildDecltypeType(Expr *E);
-
+
//===--------------------------------------------------------------------===//
// 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.
+ /// 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 TypeTy *getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
+ Scope *S, const CXXScopeSpec *SS,
+ bool isClassName = false);
virtual DeclSpec::TST isTagName(IdentifierInfo &II, Scope *S);
+ virtual bool DiagnoseUnknownTypeName(const IdentifierInfo &II,
+ SourceLocation IILoc,
+ Scope *S,
+ const CXXScopeSpec *SS,
+ TypeTy *&SuggestedType);
virtual DeclPtrTy ActOnDeclarator(Scope *S, Declarator &D) {
return HandleDeclarator(S, D, MultiTemplateParamsArg(*this), false);
}
-
- DeclPtrTy HandleDeclarator(Scope *S, Declarator &D,
+
+ DeclPtrTy HandleDeclarator(Scope *S, Declarator &D,
MultiTemplateParamsArg TemplateParameterLists,
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);
+ QualType R, DeclaratorInfo *DInfo,
+ NamedDecl* PrevDecl, bool &Redeclaration);
NamedDecl* ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
- QualType R, NamedDecl* PrevDecl,
+ QualType R, DeclaratorInfo *DInfo,
+ NamedDecl* PrevDecl,
+ MultiTemplateParamsArg TemplateParamLists,
bool &Redeclaration);
void CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl,
bool &Redeclaration);
NamedDecl* ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
- QualType R, NamedDecl* PrevDecl,
+ QualType R, DeclaratorInfo *DInfo,
+ NamedDecl* PrevDecl,
MultiTemplateParamsArg TemplateParamLists,
bool IsFunctionDefinition,
bool &Redeclaration);
void CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl,
- bool &Redeclaration,
+ bool IsExplicitSpecialization,
+ bool &Redeclaration,
bool &OverloadableAttrRequired);
+ void CheckMain(FunctionDecl *FD);
virtual DeclPtrTy ActOnParamDeclarator(Scope *S, Declarator &D);
virtual void ActOnParamDefaultArgument(DeclPtrTy param,
SourceLocation EqualLoc,
ExprArg defarg);
- virtual void ActOnParamUnparsedDefaultArgument(DeclPtrTy param,
+ virtual void ActOnParamUnparsedDefaultArgument(DeclPtrTy param,
SourceLocation EqualLoc,
SourceLocation ArgLoc);
virtual void ActOnParamDefaultArgumentError(DeclPtrTy param);
-
+ bool SetParamDefaultArgument(ParmVarDecl *Param, ExprArg DefaultArg,
+ SourceLocation EqualLoc);
+
+
// Contains the locations of the beginning of unparsed default
// argument locations.
llvm::DenseMap<ParmVarDecl *,SourceLocation> UnparsedDefaultArgLocs;
- virtual void AddInitializerToDecl(DeclPtrTy dcl, FullExprArg init);
+ virtual void AddInitializerToDecl(DeclPtrTy dcl, ExprArg init);
void AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit);
- void ActOnUninitializedDecl(DeclPtrTy dcl);
+ void ActOnUninitializedDecl(DeclPtrTy dcl, bool TypeContainsUndeducedAuto);
virtual void SetDeclDeleted(DeclPtrTy dcl, SourceLocation DelLoc);
virtual DeclGroupPtrTy FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
DeclPtrTy *Group,
@@ -484,19 +594,19 @@ public:
virtual DeclPtrTy ActOnFinishFunctionBody(DeclPtrTy Decl, StmtArg Body);
DeclPtrTy ActOnFinishFunctionBody(DeclPtrTy Decl, StmtArg Body,
bool IsInstantiation);
-
+
/// \brief Diagnose any unused parameters in the given sequence of
/// ParmVarDecl pointers.
template<typename InputIterator>
void DiagnoseUnusedParameters(InputIterator Param, InputIterator ParamEnd) {
for (; Param != ParamEnd; ++Param) {
- if (!(*Param)->isUsed() && (*Param)->getDeclName() &&
+ if (!(*Param)->isUsed() && (*Param)->getDeclName() &&
!(*Param)->template hasAttr<UnusedAttr>())
Diag((*Param)->getLocation(), diag::warn_unused_parameter)
<< (*Param)->getDeclName();
}
}
-
+
void DiagnoseInvalidJumps(Stmt *Body);
virtual DeclPtrTy ActOnFileScopeAsmDecl(SourceLocation Loc, ExprArg expr);
@@ -507,23 +617,32 @@ public:
/// 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,
+ virtual DeclPtrTy BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
RecordDecl *Record);
- bool isAcceptableTagRedeclaration(const TagDecl *Previous,
+ bool isAcceptableTagRedeclaration(const TagDecl *Previous,
TagDecl::TagKind NewTag,
SourceLocation NewTagLoc,
const IdentifierInfo &Name);
- virtual DeclPtrTy ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
+ virtual DeclPtrTy ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
SourceLocation KWLoc, const CXXScopeSpec &SS,
IdentifierInfo *Name, SourceLocation NameLoc,
AttributeList *Attr, AccessSpecifier AS,
- bool &OwnedDecl);
-
+ MultiTemplateParamsArg TemplateParameterLists,
+ bool &OwnedDecl, bool &IsDependent);
+
+ virtual TypeResult ActOnDependentTag(Scope *S,
+ unsigned TagSpec,
+ TagUseKind TUK,
+ const CXXScopeSpec &SS,
+ IdentifierInfo *Name,
+ SourceLocation TagLoc,
+ SourceLocation NameLoc);
+
virtual void ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart,
IdentifierInfo *ClassName,
llvm::SmallVectorImpl<DeclPtrTy> &Decls);
@@ -535,12 +654,22 @@ public:
Declarator &D, Expr *BitfieldWidth,
AccessSpecifier AS);
- FieldDecl *CheckFieldDecl(DeclarationName Name, QualType T,
+ FieldDecl *CheckFieldDecl(DeclarationName Name, QualType T,
+ DeclaratorInfo *DInfo,
RecordDecl *Record, SourceLocation Loc,
bool Mutable, Expr *BitfieldWidth,
+ SourceLocation TSSL,
AccessSpecifier AS, NamedDecl *PrevDecl,
Declarator *D = 0);
-
+
+ enum CXXSpecialMember {
+ CXXDefaultConstructor = 0,
+ CXXCopyConstructor = 1,
+ CXXCopyAssignment = 2,
+ CXXDestructor = 3
+ };
+ void DiagnoseNontrivial(const RecordType* Record, CXXSpecialMember mem);
+
virtual DeclPtrTy ActOnIvar(Scope *S, SourceLocation DeclStart,
DeclPtrTy IntfDecl,
Declarator &D, ExprTy *BitfieldWidth,
@@ -560,7 +689,8 @@ public:
/// 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 void ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagDecl,
+ SourceLocation RBraceLoc);
EnumConstantDecl *CheckEnumConstant(EnumDecl *Enum,
EnumConstantDecl *LastEnumConst,
@@ -574,25 +704,27 @@ public:
SourceLocation EqualLoc, ExprTy *Val);
virtual void ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
SourceLocation RBraceLoc, DeclPtrTy EnumDecl,
- DeclPtrTy *Elements, unsigned NumElements);
+ DeclPtrTy *Elements, unsigned NumElements,
+ Scope *S, AttributeList *Attr);
DeclContext *getContainingDC(DeclContext *DC);
/// Set the current declaration context until it gets popped.
void PushDeclContext(Scope *S, DeclContext *DC);
void PopDeclContext();
-
+
/// EnterDeclaratorContext - Used when we must lookup names in the context
/// of a declarator's nested name specifier.
void EnterDeclaratorContext(Scope *S, DeclContext *DC);
void ExitDeclaratorContext(Scope *S);
-
-
+
+ DeclContext *getFunctionLevelDeclContext();
+
/// 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.
@@ -604,15 +736,35 @@ public:
NamedDecl *getCurFunctionOrMethodDecl();
/// Add this decl to the scope shadowed decl chains.
- void PushOnScopeChains(NamedDecl *D, Scope *S);
+ void PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext = true);
/// 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);
+ bool isDeclInScope(NamedDecl *&D, DeclContext *Ctx, Scope *S = 0);
+
+ /// Finds the scope corresponding to the given decl context, if it
+ /// happens to be an enclosing scope. Otherwise return NULL.
+ Scope *getScopeForDeclContext(Scope *S, DeclContext *DC) {
+ DeclContext *TargetDC = DC->getPrimaryContext();
+ do {
+ if (DeclContext *ScopeDC = (DeclContext*) S->getEntity())
+ if (ScopeDC->getPrimaryContext() == TargetDC)
+ return S;
+ } while ((S = S->getParent()));
+
+ return NULL;
}
+ /// 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.
+ };
+
/// Subroutines of ActOnDeclarator().
TypedefDecl *ParseTypedefDecl(Scope *S, Declarator &D, QualType T);
@@ -623,41 +775,52 @@ public:
bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old);
/// C++ Overloading.
- bool IsOverload(FunctionDecl *New, Decl* OldD,
+ bool IsOverload(FunctionDecl *New, Decl* OldD,
OverloadedFunctionDecl::function_iterator &MatchedDecl);
- ImplicitConversionSequence
+ ImplicitConversionSequence
TryImplicitConversion(Expr* From, QualType ToType,
- bool SuppressUserConversions = false,
- bool AllowExplicit = false,
- bool ForceRValue = false);
- bool IsStandardConversion(Expr *From, QualType ToType,
+ bool SuppressUserConversions,
+ bool AllowExplicit,
+ bool ForceRValue,
+ bool InOverloadResolution,
+ bool UserCast = false);
+ bool IsStandardConversion(Expr *From, QualType ToType,
+ bool InOverloadResolution,
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,
+ bool InOverloadResolution,
QualType& ConvertedType, bool &IncompatibleObjC);
bool isObjCPointerConversion(QualType FromType, QualType ToType,
QualType& ConvertedType, bool &IncompatibleObjC);
- bool CheckPointerConversion(Expr *From, QualType ToType);
+ bool CheckPointerConversion(Expr *From, QualType ToType,
+ CastExpr::CastKind &Kind);
bool IsMemberPointerConversion(Expr *From, QualType FromType, QualType ToType,
+ bool InOverloadResolution,
QualType &ConvertedType);
- bool CheckMemberPointerConversion(Expr *From, QualType ToType);
+ bool CheckMemberPointerConversion(Expr *From, QualType ToType,
+ CastExpr::CastKind &Kind);
bool IsQualificationConversion(QualType FromType, QualType ToType);
- bool IsUserDefinedConversion(Expr *From, QualType ToType,
+ OverloadingResult IsUserDefinedConversion(Expr *From, QualType ToType,
UserDefinedConversionSequence& User,
+ OverloadCandidateSet& Conversions,
bool AllowConversionFunctions,
- bool AllowExplicit, bool ForceRValue);
+ bool AllowExplicit, bool ForceRValue,
+ bool UserCast = false);
+ bool DiagnoseAmbiguousUserDefinedConversion(Expr *From, QualType ToType);
+
- ImplicitConversionSequence::CompareKind
+ ImplicitConversionSequence::CompareKind
CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1,
const ImplicitConversionSequence& ICS2);
- ImplicitConversionSequence::CompareKind
+ ImplicitConversionSequence::CompareKind
CompareStandardConversionSequences(const StandardConversionSequence& SCS1,
const StandardConversionSequence& SCS2);
- ImplicitConversionSequence::CompareKind
+ ImplicitConversionSequence::CompareKind
CompareQualificationConversions(const StandardConversionSequence& SCS1,
const StandardConversionSequence& SCS2);
@@ -665,11 +828,11 @@ public:
CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
const StandardConversionSequence& SCS2);
- ImplicitConversionSequence
+ ImplicitConversionSequence
TryCopyInitialization(Expr* From, QualType ToType,
- bool SuppressUserConversions = false,
- bool ForceRValue = false);
- bool PerformCopyInitialization(Expr *&From, QualType ToType,
+ bool SuppressUserConversions, bool ForceRValue,
+ bool InOverloadResolution);
+ bool PerformCopyInitialization(Expr *&From, QualType ToType,
const char *Flavor, bool Elidable = false);
ImplicitConversionSequence
@@ -679,24 +842,21 @@ public:
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.
- };
+ bool PerformObjectMemberConversion(Expr *&From, NamedDecl *Member);
+
+ // Members have to be NamespaceDecl* or TranslationUnitDecl*.
+ // TODO: make this is a typesafe union.
+ typedef llvm::SmallPtrSet<DeclContext *, 16> AssociatedNamespaceSet;
typedef llvm::SmallPtrSet<AnyFunctionDecl, 16> FunctionSet;
- typedef llvm::SmallPtrSet<NamespaceDecl *, 16> AssociatedNamespaceSet;
typedef llvm::SmallPtrSet<CXXRecordDecl *, 16> AssociatedClassSet;
- void AddOverloadCandidate(FunctionDecl *Function,
+ void AddOverloadCandidate(FunctionDecl *Function,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false,
- bool ForceRValue = false);
+ bool ForceRValue = false,
+ bool PartialOverloading = false);
void AddFunctionCandidates(const FunctionSet &Functions,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
@@ -706,6 +866,14 @@ public:
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false,
bool ForceRValue = false);
+ void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
+ bool HasExplicitTemplateArgs,
+ const TemplateArgument *ExplicitTemplateArgs,
+ unsigned NumExplicitTemplateArgs,
+ Expr *Object, Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet& CandidateSet,
+ bool SuppressUserConversions = false,
+ bool ForceRValue = false);
void AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
bool HasExplicitTemplateArgs,
const TemplateArgument *ExplicitTemplateArgs,
@@ -717,6 +885,9 @@ public:
void AddConversionCandidate(CXXConversionDecl *Conversion,
Expr *From, QualType ToType,
OverloadCandidateSet& CandidateSet);
+ void AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
+ Expr *From, QualType ToType,
+ OverloadCandidateSet &CandidateSet);
void AddSurrogateCandidate(CXXConversionDecl *Conversion,
const FunctionProtoType *Proto,
Expr *Object, Expr **Args, unsigned NumArgs,
@@ -731,29 +902,45 @@ public:
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
SourceRange OpRange = SourceRange());
- void AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
+ 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,
+ void AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
+ Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet);
void AddArgumentDependentLookupCandidates(DeclarationName Name,
Expr **Args, unsigned NumArgs,
- OverloadCandidateSet& CandidateSet);
+ bool HasExplicitTemplateArgs,
+ const TemplateArgument *ExplicitTemplateArgs,
+ unsigned NumExplicitTemplateArgs,
+ OverloadCandidateSet& CandidateSet,
+ bool PartialOverloading = false);
bool isBetterOverloadCandidate(const OverloadCandidate& Cand1,
const OverloadCandidate& Cand2);
OverloadingResult BestViableFunction(OverloadCandidateSet& CandidateSet,
SourceLocation Loc,
OverloadCandidateSet::iterator& Best);
void PrintOverloadCandidates(OverloadCandidateSet& CandidateSet,
- bool OnlyViable);
-
+ bool OnlyViable,
+ const char *Opc=0,
+ SourceLocation Loc=SourceLocation());
+
FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
bool Complain);
void FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn);
+ void AddOverloadedCallCandidates(NamedDecl *Callee,
+ DeclarationName &UnqualifiedName,
+ bool &ArgumentDependentLookup,
+ bool HasExplicitTemplateArgs,
+ const TemplateArgument *ExplicitTemplateArgs,
+ unsigned NumExplicitTemplateArgs,
+ Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet &CandidateSet,
+ bool PartialOverloading = false);
+
FunctionDecl *ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee,
DeclarationName UnqualifiedName,
bool HasExplicitTemplateArgs,
@@ -761,7 +948,7 @@ public:
unsigned NumExplicitTemplateArgs,
SourceLocation LParenLoc,
Expr **Args, unsigned NumArgs,
- SourceLocation *CommaLocs,
+ SourceLocation *CommaLocs,
SourceLocation RParenLoc,
bool &ArgumentDependentLookup);
@@ -777,23 +964,33 @@ public:
ExprResult
BuildCallToMemberFunction(Scope *S, Expr *MemExpr,
- SourceLocation LParenLoc, Expr **Args,
+ SourceLocation LParenLoc, Expr **Args,
unsigned NumArgs, SourceLocation *CommaLocs,
SourceLocation RParenLoc);
- ExprResult
+ ExprResult
BuildCallToObjectOfClassType(Scope *S, Expr *Object, SourceLocation LParenLoc,
Expr **Args, unsigned NumArgs,
- SourceLocation *CommaLocs,
+ SourceLocation *CommaLocs,
SourceLocation RParenLoc);
- ExprResult BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
- SourceLocation MemberLoc,
- IdentifierInfo &Member);
-
- /// Helpers for dealing with function parameters.
+ OwningExprResult BuildOverloadedArrowExpr(Scope *S, ExprArg Base,
+ SourceLocation OpLoc);
+
+ /// CheckCallReturnType - Checks that a call expression's return type is
+ /// complete. Returns true on failure. The location passed in is the location
+ /// that best represents the call.
+ bool CheckCallReturnType(QualType ReturnType, SourceLocation Loc,
+ CallExpr *CE, FunctionDecl *FD);
+
+ /// Helpers for dealing with blocks and functions.
+ void CheckFallThroughForFunctionDef(Decl *D, Stmt *Body);
+ void CheckFallThroughForBlock(QualType BlockTy, Stmt *Body);
bool CheckParmsForFunctionDef(FunctionDecl *FD);
void CheckCXXDefaultArguments(FunctionDecl *FD);
void CheckExtraCXXDefaultArguments(Declarator &D);
+ enum ControlFlowKind { NeverFallThrough = 0, MaybeFallThrough = 1,
+ AlwaysFallThrough = 2 };
+ ControlFlowKind CheckFallThrough(Stmt *);
Scope *getNonFieldDeclScope(Scope *S);
@@ -804,7 +1001,7 @@ public:
/// 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.
+ /// 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
@@ -851,7 +1048,7 @@ public:
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
+ /// 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.
@@ -868,66 +1065,16 @@ public:
/// 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.
+ /// 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.
+ /// (possibly NULL) @c NamedDecl* via the getAsSingleDecl() method.
+ /// This permits the common-case usage in C and Objective-C where
+ /// name lookup will always return a single declaration. Use of
+ /// this is largely deprecated; callers should handle the possibility
+ /// of multiple declarations.
+ class LookupResult {
+ public:
enum LookupKind {
/// @brief No entity found met the criteria.
NotFound = 0,
@@ -941,6 +1088,13 @@ public:
/// functions into an OverloadedFunctionDecl.
FoundOverloaded,
+ /// @brief Name lookup results in an ambiguity; use
+ /// getAmbiguityKind to figure out what kind of ambiguity
+ /// we have.
+ Ambiguous
+ };
+
+ enum AmbiguityKind {
/// Name lookup results in an ambiguity because multiple
/// entities that meet the lookup criteria were found in
/// subobjects of different types. For example:
@@ -948,7 +1102,7 @@ public:
/// struct A { void f(int); }
/// struct B { void f(double); }
/// struct C : A, B { };
- /// void test(C c) {
+ /// void test(C c) {
/// c.f(0); // error: A::f and B::f come from subobjects of different
/// // types. overload resolution is not performed.
/// }
@@ -982,125 +1136,178 @@ public:
/// }
/// }
/// @endcode
- AmbiguousReference
+ AmbiguousReference,
+
+ /// Name lookup results in an ambiguity because an entity with a
+ /// tag name was hidden by an entity with an ordinary name from
+ /// a different context.
+ /// @code
+ /// namespace A { struct Foo {}; }
+ /// namespace B { void Foo(); }
+ /// namespace C {
+ /// using namespace A;
+ /// using namespace B;
+ /// }
+ /// void test() {
+ /// C::Foo(); // error: tag 'A::Foo' is hidden by an object in a
+ /// // different namespace
+ /// }
+ /// @endcode
+ AmbiguousTagHiding
};
- static LookupResult CreateLookupResult(ASTContext &Context, NamedDecl *D);
+ typedef llvm::SmallVector<NamedDecl*, 4> DeclsTy;
+ typedef DeclsTy::const_iterator iterator;
- static LookupResult CreateLookupResult(ASTContext &Context,
- IdentifierResolver::iterator F,
- IdentifierResolver::iterator L);
+ LookupResult()
+ : Kind(NotFound),
+ Paths(0)
+ {}
+ ~LookupResult() {
+ if (Paths) deletePaths(Paths);
+ }
- static LookupResult CreateLookupResult(ASTContext &Context,
- DeclContext::lookup_iterator F,
- DeclContext::lookup_iterator L);
+ bool isAmbiguous() const {
+ return getKind() == Ambiguous;
+ }
- 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;
+ LookupKind getKind() const {
+ sanity();
+ return Kind;
}
- 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;
+ AmbiguityKind getAmbiguityKind() const {
+ assert(isAmbiguous());
+ return Ambiguity;
}
- LookupKind getKind() const;
+ iterator begin() const { return Decls.begin(); }
+ iterator end() const { return Decls.end(); }
- /// @brief Determine whether name look found something.
- operator bool() const { return getKind() != NotFound; }
+ /// \brief Return true if no decls were found
+ bool empty() const { return Decls.empty(); }
- /// @brief Determines whether the lookup resulted in an ambiguity.
- bool isAmbiguous() const {
- return StoredKind == AmbiguousLookupStoresBasePaths ||
- StoredKind == AmbiguousLookupStoresDecls;
+ /// \brief Return the base paths structure that's associated with
+ /// these results, or null if none is.
+ CXXBasePaths *getBasePaths() const {
+ return Paths;
}
- /// @brief Allows conversion of a lookup result into a
- /// declaration, with the same behavior as getAsDecl.
- operator NamedDecl*() const { return getAsDecl(); }
+ /// \brief Add a declaration to these results.
+ void addDecl(NamedDecl *D) {
+ Decls.push_back(D->getUnderlyingDecl());
+ Kind = Found;
+ }
- NamedDecl* getAsDecl() const;
+ /// \brief Add all the declarations from another set of lookup
+ /// results.
+ void addAllDecls(const LookupResult &Other) {
+ Decls.append(Other.begin(), Other.end());
+ Kind = Found;
+ }
- BasePaths *getBasePaths() const;
+ /// \brief Hides a set of declarations.
+ template <class NamedDeclSet> void hideDecls(const NamedDeclSet &Set) {
+ unsigned I = 0, N = Decls.size();
+ while (I < N) {
+ if (Set.count(Decls[I]))
+ Decls[I] = Decls[--N];
+ else
+ I++;
+ }
+ Decls.set_size(N);
+ }
- /// \brief Iterate over the results of name lookup.
+ /// \brief Resolves the kind of the lookup, possibly hiding decls.
///
- /// 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;
+ /// This should be called in any environment where lookup might
+ /// generate multiple lookup results.
+ void resolveKind();
- /// 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;
+ /// \brief Fetch this as an unambiguous single declaration
+ /// (possibly an overloaded one).
+ ///
+ /// This is deprecated; users should be written to handle
+ /// ambiguous and overloaded lookups.
+ NamedDecl *getAsSingleDecl(ASTContext &Context) const;
- iterator() : Result(0), Current(0) { }
+ /// \brief Fetch the unique decl found by this lookup. Asserts
+ /// that one was found.
+ ///
+ /// This is intended for users who have examined the result kind
+ /// and are certain that there is only one result.
+ NamedDecl *getFoundDecl() const {
+ assert(getKind() == Found && "getFoundDecl called on non-unique result");
+ return *Decls.begin();
+ }
- iterator(LookupResult *Res, uintptr_t Cur) : Result(Res), Current(Cur) { }
+ /// \brief Asks if the result is a single tag decl.
+ bool isSingleTagDecl() const {
+ return getKind() == Found && isa<TagDecl>(getFoundDecl());
+ }
- reference operator*() const;
+ /// \brief Make these results show that the name was found in
+ /// base classes of different types.
+ ///
+ /// The given paths object is copied and invalidated.
+ void setAmbiguousBaseSubobjectTypes(CXXBasePaths &P);
- pointer operator->() const { return **this; }
+ /// \brief Make these results show that the name was found in
+ /// distinct base classes of the same type.
+ ///
+ /// The given paths object is copied and invalidated.
+ void setAmbiguousBaseSubobjects(CXXBasePaths &P);
+
+ /// \brief Make these results show that the name was found in
+ /// different contexts and a tag decl was hidden by an ordinary
+ /// decl in a different context.
+ void setAmbiguousQualifiedTagHiding() {
+ setAmbiguous(AmbiguousTagHiding);
+ }
- iterator &operator++();
+ /// \brief Clears out any current state.
+ void clear() {
+ Kind = NotFound;
+ Decls.clear();
+ if (Paths) deletePaths(Paths);
+ Paths = NULL;
+ }
- iterator operator++(int) {
- iterator tmp(*this);
- ++(*this);
- return tmp;
- }
+ void print(llvm::raw_ostream &);
- friend inline bool operator==(iterator const& x, iterator const& y) {
- return x.Current == y.Current;
- }
+ private:
+ void setAmbiguous(AmbiguityKind AK) {
+ Kind = Ambiguous;
+ Ambiguity = AK;
+ }
- friend inline bool operator!=(iterator const& x, iterator const& y) {
- return x.Current != y.Current;
- }
- };
- friend class iterator;
+ void addDeclsFromBasePaths(const CXXBasePaths &P);
+
+ // Sanity checks.
+ void sanity() const {
+ assert(Kind != NotFound || Decls.size() == 0);
+ assert(Kind != Found || Decls.size() == 1);
+ assert(Kind == NotFound || Kind == Found ||
+ (Kind == Ambiguous && Ambiguity == AmbiguousBaseSubobjects)
+ || Decls.size() > 1);
+ assert((Paths != NULL) == (Kind == Ambiguous &&
+ (Ambiguity == AmbiguousBaseSubobjectTypes ||
+ Ambiguity == AmbiguousBaseSubobjects)));
+ }
- iterator begin();
- iterator end();
+ static void deletePaths(CXXBasePaths *);
- /// \brief Free the memory associated with this lookup.
- void Destroy();
+ LookupKind Kind;
+ AmbiguityKind Ambiguity; // ill-defined unless ambiguous
+ DeclsTy Decls;
+ CXXBasePaths *Paths;
};
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);
-
+ bool CppLookupName(LookupResult &R, Scope *S, DeclarationName Name,
+ LookupNameKind NameKind, bool RedeclarationOnly);
public:
/// Determines whether D is a suitable lookup result according to the
/// lookup criteria.
@@ -1115,62 +1322,75 @@ public:
case Sema::LookupObjCImplementationName:
case Sema::LookupObjCCategoryImplName:
return D->isInIdentifierNamespace(IDNS);
-
+
case Sema::LookupOperatorName:
- return D->isInIdentifierNamespace(IDNS) &&
+ 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 &&
+
+ assert(false &&
"isAcceptableLookupResult always returns before this point");
return false;
}
- LookupResult LookupName(Scope *S, DeclarationName Name,
- LookupNameKind NameKind,
- bool RedeclarationOnly = false,
- bool AllowBuiltinCreation = false,
- 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 = false,
- SourceLocation Loc = SourceLocation());
+ /// \brief Look up a name, looking for a single declaration. Return
+ /// null if no unambiguous results were found.
+ ///
+ /// It is preferable to use the elaborated form and explicitly handle
+ /// ambiguity and overloaded.
+ NamedDecl *LookupSingleName(Scope *S, DeclarationName Name,
+ LookupNameKind NameKind,
+ bool RedeclarationOnly = false) {
+ LookupResult R;
+ LookupName(R, S, Name, NameKind, RedeclarationOnly);
+ return R.getAsSingleDecl(Context);
+ }
+ bool LookupName(LookupResult &R, Scope *S,
+ DeclarationName Name,
+ LookupNameKind NameKind,
+ bool RedeclarationOnly = false,
+ bool AllowBuiltinCreation = false,
+ SourceLocation Loc = SourceLocation());
+ bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
+ DeclarationName Name,
+ LookupNameKind NameKind,
+ bool RedeclarationOnly = false);
+ bool LookupParsedName(LookupResult &R, Scope *S, const CXXScopeSpec *SS,
+ DeclarationName Name,
+ LookupNameKind NameKind,
+ bool RedeclarationOnly = false,
+ bool AllowBuiltinCreation = false,
+ SourceLocation Loc = SourceLocation(),
+ bool EnteringContext = false);
ObjCProtocolDecl *LookupProtocol(IdentifierInfo *II);
- ObjCImplementationDecl *LookupObjCImplementation(IdentifierInfo *II);
ObjCCategoryImplDecl *LookupObjCCategoryImpl(IdentifierInfo *II);
void LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
- QualType T1, QualType T2,
+ 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 &GlobalScope);
+ AssociatedClassSet &AssociatedClasses);
bool DiagnoseAmbiguousLookup(LookupResult &Result, DeclarationName Name,
- SourceLocation NameLoc,
+ SourceLocation NameLoc,
SourceRange LookupRange = SourceRange());
//@}
-
+
ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *Id);
- NamedDecl *LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID,
+ NamedDecl *LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID,
Scope *S, bool ForRedeclaration,
SourceLocation Loc);
NamedDecl *ImplicitlyDefineFunction(SourceLocation Loc, IdentifierInfo &II,
@@ -1179,7 +1399,7 @@ public:
// More parsing and symbol table subroutines.
- // Decl attributes - this routine is the top level dispatcher.
+ // Decl attributes - this routine is the top level dispatcher.
void ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD);
void ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AttrList);
@@ -1187,13 +1407,10 @@ public:
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
@@ -1204,24 +1421,24 @@ public:
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.
+ /// 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,
+ 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,
+ bool MatchTwoMethodDeclarations(const ObjCMethodDecl *Method,
const ObjCMethodDecl *PrevMethod,
- bool matchBasedOnSizeAndAlignment = false);
+ bool matchBasedOnSizeAndAlignment = false);
/// MatchAllMethodDeclarations - Check methods declaraed in interface or
/// or protocol against those declared in their implementations.
@@ -1239,15 +1456,16 @@ public:
/// 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);
+ ObjCMethodDecl *LookupInstanceMethodInGlobalPool(Selector Sel, SourceRange R,
+ bool warn=true);
/// 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);
//===--------------------------------------------------------------------===//
@@ -1266,7 +1484,7 @@ public:
SourceLocation DotDotDotLoc, ExprArg RHSVal,
SourceLocation ColonLoc);
virtual void ActOnCaseStmtBody(StmtTy *CaseStmt, StmtArg SubStmt);
-
+
virtual OwningStmtResult ActOnDefaultStmt(SourceLocation DefaultLoc,
SourceLocation ColonLoc,
StmtArg SubStmt, Scope *CurScope);
@@ -1274,13 +1492,13 @@ public:
IdentifierInfo *II,
SourceLocation ColonLoc,
StmtArg SubStmt);
- virtual OwningStmtResult ActOnIfStmt(SourceLocation IfLoc,
- FullExprArg CondVal, StmtArg ThenVal,
+ 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,
+ virtual OwningStmtResult ActOnWhileStmt(SourceLocation WhileLoc,
FullExprArg Cond, StmtArg Body);
virtual OwningStmtResult ActOnDoStmt(SourceLocation DoLoc, StmtArg Body,
SourceLocation WhileLoc,
@@ -1309,7 +1527,7 @@ public:
Scope *CurScope);
virtual OwningStmtResult ActOnReturnStmt(SourceLocation ReturnLoc,
- FullExprArg RetValExp);
+ ExprArg RetValExp);
OwningStmtResult ActOnBlockReturnStmt(SourceLocation ReturnLoc,
Expr *RetValExp);
@@ -1338,13 +1556,14 @@ public:
StmtArg Catch, StmtArg Finally);
virtual OwningStmtResult ActOnObjCAtThrowStmt(SourceLocation AtLoc,
- ExprArg Throw,
+ ExprArg Throw,
Scope *CurScope);
virtual OwningStmtResult ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc,
ExprArg SynchExpr,
StmtArg SynchBody);
VarDecl *BuildExceptionDeclaration(Scope *S, QualType ExDeclType,
+ DeclaratorInfo *DInfo,
IdentifierInfo *Name,
SourceLocation Loc,
SourceRange Range);
@@ -1358,25 +1577,29 @@ public:
MultiStmtArg Handlers);
void DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock);
+ /// DiagnoseUnusedExprResult - If the statement passed in is an expression
+ /// whose result is unused, warn.
+ void DiagnoseUnusedExprResult(const Stmt *S);
+
//===--------------------------------------------------------------------===//
// Expression Parsing Callbacks: SemaExpr.cpp.
bool DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc);
- bool DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *PD,
+ bool DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *PD,
ObjCMethodDecl *Getter,
SourceLocation Loc);
void DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
Expr **Args, unsigned NumArgs);
- virtual ExpressionEvaluationContext
+ virtual ExpressionEvaluationContext
PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext);
-
- virtual void
+
+ virtual void
PopExpressionEvaluationContext(ExpressionEvaluationContext OldContext,
ExpressionEvaluationContext NewContext);
-
+
void MarkDeclarationReferenced(SourceLocation Loc, Decl *D);
-
+
// Primary Expressions.
virtual SourceRange getExprRange(ExprTy *E) const;
@@ -1397,8 +1620,8 @@ public:
bool HasTrailingLParen,
const CXXScopeSpec &SS,
bool isAddressOfOperand);
- OwningExprResult BuildDeclRefExpr(NamedDecl *D, QualType Ty,
- SourceLocation Loc, bool TypeDependent,
+ OwningExprResult BuildDeclRefExpr(NamedDecl *D, QualType Ty,
+ SourceLocation Loc, bool TypeDependent,
bool ValueDependent,
const CXXScopeSpec *SS = 0);
VarDecl *BuildAnonymousStructUnionMemberPath(FieldDecl *Field,
@@ -1415,15 +1638,18 @@ public:
bool isAddressOfOperand = false);
OwningExprResult BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D,
bool HasTrailingLParen,
- const CXXScopeSpec *SS,
+ const CXXScopeSpec *SS,
bool isAddressOfOperand);
-
+
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);
+ virtual OwningExprResult ActOnParenListExpr(SourceLocation L,
+ SourceLocation R,
+ MultiExprArg Val);
/// ActOnStringLiteral - The specified tokens were lexed as pasted string
/// fragments (e.g. "foo" "bar" L"baz").
@@ -1432,19 +1658,19 @@ public:
// Binary/Unary Operators. 'Tok' is the token for the operator.
OwningExprResult CreateBuiltinUnaryOp(SourceLocation OpLoc,
- unsigned OpcIn,
+ unsigned OpcIn,
ExprArg InputArg);
virtual OwningExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
tok::TokenKind Op, ExprArg Input);
- OwningExprResult CreateSizeOfAlignOfExpr(QualType T, SourceLocation OpLoc,
+ OwningExprResult CreateSizeOfAlignOfExpr(QualType T, SourceLocation OpLoc,
bool isSizeOf, SourceRange R);
- OwningExprResult CreateSizeOfAlignOfExpr(Expr *E, SourceLocation OpLoc,
+ 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);
@@ -1457,18 +1683,67 @@ public:
SourceLocation LLoc,
ExprArg Idx,
SourceLocation RLoc);
+
+ OwningExprResult BuildMemberReferenceExpr(Scope *S, ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ SourceLocation MemberLoc,
+ DeclarationName MemberName,
+ DeclPtrTy ImplDecl,
+ const CXXScopeSpec *SS = 0,
+ NamedDecl *FirstQualifierInScope = 0) {
+ // FIXME: Temporary helper while we migrate existing calls to
+ // BuildMemberReferenceExpr to support explicitly-specified template
+ // arguments.
+ return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, MemberLoc,
+ MemberName, false, SourceLocation(), 0, 0,
+ SourceLocation(), ImplDecl, SS,
+ FirstQualifierInScope);
+ }
+
+ OwningExprResult BuildMemberReferenceExpr(Scope *S, ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ SourceLocation MemberLoc,
+ DeclarationName MemberName,
+ bool HasExplicitTemplateArgs,
+ SourceLocation LAngleLoc,
+ const TemplateArgument *ExplicitTemplateArgs,
+ unsigned NumExplicitTemplateArgs,
+ SourceLocation RAngleLoc,
+ DeclPtrTy ImplDecl,
+ const CXXScopeSpec *SS,
+ NamedDecl *FirstQualifierInScope = 0);
+
virtual OwningExprResult ActOnMemberReferenceExpr(Scope *S, ExprArg Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
SourceLocation MemberLoc,
IdentifierInfo &Member,
- DeclPtrTy ImplDecl);
+ DeclPtrTy ImplDecl,
+ const CXXScopeSpec *SS = 0);
+ virtual void ActOnDefaultCtorInitializers(DeclPtrTy CDtorDecl);
bool ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
FunctionDecl *FDecl,
const FunctionProtoType *Proto,
Expr **Args, unsigned NumArgs,
SourceLocation RParenLoc);
-
+ void BuildBaseOrMemberInitializers(ASTContext &C,
+ CXXConstructorDecl *Constructor,
+ CXXBaseOrMemberInitializer **Initializers,
+ unsigned NumInitializers
+ );
+
+ void DeconstructCallFunction(Expr *FnExpr,
+ NamedDecl *&Function,
+ DeclarationName &Name,
+ NestedNameSpecifier *&Qualifier,
+ SourceRange &QualifierRange,
+ bool &ArgumentDependentLookup,
+ bool &HasExplicitTemplateArguments,
+ const TemplateArgument *&ExplicitTemplateArgs,
+ unsigned &NumExplicitTemplateArgs);
+
/// 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.
@@ -1478,8 +1753,14 @@ public:
SourceLocation *CommaLocs,
SourceLocation RParenLoc);
- virtual OwningExprResult ActOnCastExpr(SourceLocation LParenLoc, TypeTy *Ty,
- SourceLocation RParenLoc, ExprArg Op);
+ virtual OwningExprResult ActOnCastExpr(Scope *S, SourceLocation LParenLoc,
+ TypeTy *Ty, SourceLocation RParenLoc,
+ ExprArg Op);
+
+ OwningExprResult MaybeConvertParenListExprToParenExpr(Scope *S, ExprArg ME);
+ OwningExprResult ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc,
+ SourceLocation RParenLoc, ExprArg E,
+ QualType Ty);
virtual OwningExprResult ActOnCompoundLiteral(SourceLocation LParenLoc,
TypeTy *Ty,
@@ -1577,7 +1858,7 @@ public:
SourceLocation IdentLoc,
IdentifierInfo *NamespcName,
AttributeList *AttrList);
-
+
void PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir);
virtual DeclPtrTy ActOnNamespaceAliasDef(Scope *CurScope,
@@ -1588,16 +1869,24 @@ public:
SourceLocation IdentLoc,
IdentifierInfo *Ident);
+ NamedDecl *BuildUsingDeclaration(SourceLocation UsingLoc,
+ const CXXScopeSpec &SS,
+ SourceLocation IdentLoc,
+ DeclarationName Name,
+ AttributeList *AttrList,
+ bool IsTypeName);
+
virtual DeclPtrTy ActOnUsingDeclaration(Scope *CurScope,
- SourceLocation UsingLoc,
- const CXXScopeSpec &SS,
- SourceLocation IdentLoc,
- IdentifierInfo *TargetName,
- OverloadedOperatorKind Op,
- AttributeList *AttrList,
- bool IsTypeName);
-
- /// AddCXXDirectInitializerToDecl - This action is called immediately after
+ AccessSpecifier AS,
+ SourceLocation UsingLoc,
+ const CXXScopeSpec &SS,
+ SourceLocation IdentLoc,
+ IdentifierInfo *TargetName,
+ OverloadedOperatorKind Op,
+ AttributeList *AttrList,
+ bool IsTypeName);
+
+ /// 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,
@@ -1608,57 +1897,79 @@ public:
/// InitializeVarWithConstructor - Creates an CXXConstructExpr
/// and sets it as the initializer for the the passed in VarDecl.
- void InitializeVarWithConstructor(VarDecl *VD,
+ bool InitializeVarWithConstructor(VarDecl *VD,
CXXConstructorDecl *Constructor,
- QualType DeclInitType,
- Expr **Exprs, unsigned NumExprs);
-
- /// MarkDestructorReferenced - Prepare for calling destructor on the
- /// constructed decl.
- void MarkDestructorReferenced(SourceLocation Loc, QualType DeclInitType);
-
- /// DefineImplicitDefaultConstructor - Checks for feasibility of
+ QualType DeclInitType,
+ MultiExprArg Exprs);
+
+ /// BuildCXXConstructExpr - Creates a complete call to a constructor,
+ /// including handling of its default argument expressions.
+ OwningExprResult BuildCXXConstructExpr(SourceLocation ConstructLoc,
+ QualType DeclInitType,
+ CXXConstructorDecl *Constructor,
+ MultiExprArg Exprs);
+
+ // FIXME: Can re remove this and have the above BuildCXXConstructExpr check if
+ // the constructor can be elidable?
+ OwningExprResult BuildCXXConstructExpr(SourceLocation ConstructLoc,
+ QualType DeclInitType,
+ CXXConstructorDecl *Constructor,
+ bool Elidable,
+ MultiExprArg Exprs);
+
+ OwningExprResult BuildCXXTemporaryObjectExpr(CXXConstructorDecl *Cons,
+ QualType writtenTy,
+ SourceLocation tyBeginLoc,
+ MultiExprArg Args,
+ SourceLocation rParenLoc);
+
+ OwningExprResult BuildCXXCastArgument(SourceLocation CastLoc,
+ QualType Ty,
+ CastExpr::CastKind Kind,
+ CXXMethodDecl *Method,
+ ExprArg Arg);
+
+ /// BuildCXXDefaultArgExpr - Creates a CXXDefaultArgExpr, instantiating
+ /// the default expr if needed.
+ OwningExprResult BuildCXXDefaultArgExpr(SourceLocation CallLoc,
+ FunctionDecl *FD,
+ ParmVarDecl *Param);
+
+ /// FinalizeVarWithDestructor - Prepare for calling destructor on the
+ /// constructed variable.
+ void FinalizeVarWithDestructor(VarDecl *VD, QualType DeclInitType);
+
+ /// DefineImplicitDefaultConstructor - Checks for feasibility of
/// defining this constructor as the default constructor.
void DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
CXXConstructorDecl *Constructor);
-
- /// DefineImplicitDestructor - Checks for feasibility of
+
+ /// DefineImplicitDestructor - Checks for feasibility of
/// defining this destructor as the default destructor.
void DefineImplicitDestructor(SourceLocation CurrentLocation,
CXXDestructorDecl *Destructor);
-
- /// DefineImplicitCopyConstructor - Checks for feasibility of
+
+ /// DefineImplicitCopyConstructor - Checks for feasibility of
/// defining this constructor as the copy constructor.
void DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
CXXConstructorDecl *Constructor,
unsigned TypeQuals);
-
+
/// DefineImplicitOverloadedAssign - Checks for feasibility of
/// defining implicit this overloaded assignment operator.
- void DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
+ void DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
CXXMethodDecl *MethodDecl);
-
+
/// getAssignOperatorMethod - Returns the default copy assignmment operator
/// for the class.
CXXMethodDecl *getAssignOperatorMethod(ParmVarDecl *Decl,
- CXXRecordDecl *ClassDecl);
+ CXXRecordDecl *ClassDecl);
/// 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 {
@@ -1669,11 +1980,17 @@ public:
CXXConstructorDecl *
PerformInitializationByConstructor(QualType ClassType,
- Expr **Args, unsigned NumArgs,
+ MultiExprArg ArgsPtr,
SourceLocation Loc, SourceRange Range,
DeclarationName InitEntity,
- InitializationKind Kind);
+ InitializationKind Kind,
+ ASTOwningVector<&ActionBase::DeleteExpr> &ConvertedArgs);
+ bool CompleteConstructorCall(CXXConstructorDecl *Constructor,
+ MultiExprArg ArgsPtr,
+ SourceLocation Loc,
+ ASTOwningVector<&ActionBase::DeleteExpr> &ConvertedArgs);
+
/// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's.
virtual OwningExprResult ActOnCXXNamedCast(SourceLocation OpLoc,
tok::TokenKind Kind,
@@ -1729,7 +2046,7 @@ public:
SourceLocation PlacementLParen,
MultiExprArg PlacementArgs,
SourceLocation PlacementRParen,
- bool ParenTypeId,
+ bool ParenTypeId,
QualType AllocType,
SourceLocation TypeLoc,
SourceRange TypeRange,
@@ -1737,7 +2054,7 @@ public:
SourceLocation ConstructorLParen,
MultiExprArg ConstructorArgs,
SourceLocation ConstructorRParen);
-
+
bool CheckAllocatedType(QualType AllocType, SourceLocation Loc,
SourceRange R);
bool FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
@@ -1775,17 +2092,62 @@ public:
TypeTy *Ty,
SourceLocation RParen);
- /// MaybeCreateCXXExprWithTemporaries - If the list of temporaries is
+ virtual OwningExprResult ActOnStartCXXMemberReference(Scope *S,
+ ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ TypeTy *&ObjectType);
+
+ virtual OwningExprResult
+ ActOnDestructorReferenceExpr(Scope *S, ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ SourceLocation ClassNameLoc,
+ IdentifierInfo *ClassName,
+ const CXXScopeSpec &SS,
+ bool HasTrailingLParen);
+
+ virtual OwningExprResult
+ ActOnOverloadedOperatorReferenceExpr(Scope *S, ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ SourceLocation ClassNameLoc,
+ OverloadedOperatorKind OverOpKind,
+ const CXXScopeSpec *SS = 0);
+ virtual OwningExprResult
+ ActOnConversionOperatorReferenceExpr(Scope *S, ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ SourceLocation ClassNameLoc,
+ TypeTy *Ty,
+ const CXXScopeSpec *SS = 0);
+
+ virtual OwningExprResult
+ ActOnMemberTemplateIdReferenceExpr(Scope *S, ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ const CXXScopeSpec &SS,
+ // FIXME: "template" keyword?
+ TemplateTy Template,
+ SourceLocation TemplateNameLoc,
+ SourceLocation LAngleLoc,
+ ASTTemplateArgsPtr TemplateArgs,
+ SourceLocation *TemplateArgLocs,
+ SourceLocation RAngleLoc);
+
+ /// MaybeCreateCXXExprWithTemporaries - If the list of temporaries is
/// non-empty, will create a new CXXExprWithTemporaries expression.
/// Otherwise, just returs the passed in expression.
Expr *MaybeCreateCXXExprWithTemporaries(Expr *SubExpr,
bool ShouldDestroyTemporaries);
-
+
virtual OwningExprResult ActOnFinishFullExpr(ExprArg Expr);
bool RequireCompleteDeclContext(const CXXScopeSpec &SS);
-
- DeclContext *computeDeclContext(const CXXScopeSpec &SS);
+
+ DeclContext *computeDeclContext(QualType T);
+ DeclContext *computeDeclContext(const CXXScopeSpec &SS,
+ bool EnteringContext = false);
bool isDependentScopeSpecifier(const CXXScopeSpec &SS);
CXXRecordDecl *getCurrentInstantiationOf(NestedNameSpecifier *NNS);
bool isUnknownSpecialization(const CXXScopeSpec &SS);
@@ -1795,17 +2157,26 @@ public:
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.
+ bool isAcceptableNestedNameSpecifier(NamedDecl *SD);
+ NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS);
+
+
+ CXXScopeTy *BuildCXXNestedNameSpecifier(Scope *S,
+ const CXXScopeSpec &SS,
+ SourceLocation IdLoc,
+ SourceLocation CCLoc,
+ IdentifierInfo &II,
+ QualType ObjectType,
+ NamedDecl *ScopeLookupResult,
+ bool EnteringContext);
+
virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S,
const CXXScopeSpec &SS,
SourceLocation IdLoc,
SourceLocation CCLoc,
- IdentifierInfo &II);
+ IdentifierInfo &II,
+ TypeTy *ObjectType,
+ bool EnteringContext);
/// ActOnCXXNestedNameSpecifier - Called during parsing of a
/// nested-name-specifier that involves a template-id, e.g.,
@@ -1827,7 +2198,7 @@ public:
/// 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);
+ virtual bool ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS);
/// ActOnCXXExitDeclaratorScope - Called when a declarator that previously
/// invoked ActOnCXXEnterDeclaratorScope(), is finished. 'SS' is the same
@@ -1848,26 +2219,28 @@ public:
virtual void ActOnCXXExitDeclInitializer(Scope *S, DeclPtrTy Dcl);
// ParseObjCStringLiteral - Parse Objective-C string literals.
- virtual ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs,
+ virtual ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs,
ExprTy **Strings,
unsigned NumStrings);
-
- Expr *BuildObjCEncodeExpression(SourceLocation AtLoc,
+
+ Expr *BuildObjCEncodeExpression(SourceLocation AtLoc,
QualType EncodedType,
- SourceLocation RParenLoc);
+ SourceLocation RParenLoc);
+ CXXMemberCallExpr *BuildCXXMemberCallExpr(Expr *Exp, CXXMethodDecl *Method);
+
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,
@@ -1897,6 +2270,7 @@ public:
virtual DeclPtrTy ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS,
Declarator &D,
+ MultiTemplateParamsArg TemplateParameterLists,
ExprTy *BitfieldWidth,
ExprTy *Init,
bool Deleted = false);
@@ -1912,12 +2286,33 @@ public:
SourceLocation *CommaLocs,
SourceLocation RParenLoc);
+ MemInitResult BuildMemberInitializer(FieldDecl *Member, Expr **Args,
+ unsigned NumArgs, SourceLocation IdLoc,
+ SourceLocation RParenLoc);
+
+ MemInitResult BuildBaseInitializer(QualType BaseType, Expr **Args,
+ unsigned NumArgs, SourceLocation IdLoc,
+ SourceLocation RParenLoc,
+ CXXRecordDecl *ClassDecl);
+
+ void setBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
+ CXXBaseOrMemberInitializer **Initializers,
+ unsigned NumInitializers,
+ llvm::SmallVectorImpl<CXXBaseSpecifier *>& Bases,
+ llvm::SmallVectorImpl<FieldDecl *>&Members);
+
+ /// computeBaseOrMembersToDestroy - Compute information in current
+ /// destructor decl's AST of bases and non-static data members which will be
+ /// implicitly destroyed. We are storing the destruction in the order that
+ /// they should occur (which is the reverse of construction order).
+ void computeBaseOrMembersToDestroy(CXXDestructorDecl *Destructor);
+
void AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl);
- virtual void ActOnMemInitializers(DeclPtrTy ConstructorDecl,
+ virtual void ActOnMemInitializers(DeclPtrTy ConstructorDecl,
SourceLocation ColonLoc,
MemInitTy **MemInits, unsigned NumMemInits);
-
+
virtual void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
DeclPtrTy TagDecl,
SourceLocation LBrac,
@@ -1930,12 +2325,14 @@ public:
virtual void ActOnFinishDelayedCXXMethodDeclaration(Scope *S,
DeclPtrTy Method);
- virtual DeclPtrTy ActOnStaticAssertDeclaration(SourceLocation AssertLoc,
+ virtual DeclPtrTy ActOnStaticAssertDeclaration(SourceLocation AssertLoc,
ExprArg AssertExpr,
ExprArg AssertMessageExpr);
-
- virtual bool ActOnFriendDecl(Scope *S, SourceLocation FriendLoc,
- DeclPtrTy Dcl);
+
+ DeclPtrTy ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
+ MultiTemplateParamsArg TemplateParams);
+ DeclPtrTy ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition,
+ MultiTemplateParamsArg TemplateParams);
QualType CheckConstructorDeclarator(Declarator &D, QualType R,
FunctionDecl::StorageClass& SC);
@@ -1954,23 +2351,22 @@ public:
CXXBaseSpecifier *CheckBaseSpecifier(CXXRecordDecl *Class,
SourceRange SpecifierRange,
bool Virtual, AccessSpecifier Access,
- QualType BaseType,
+ QualType BaseType,
SourceLocation BaseLoc);
- virtual BaseResult ActOnBaseSpecifier(DeclPtrTy classdecl,
+ virtual BaseResult ActOnBaseSpecifier(DeclPtrTy classdecl,
SourceRange SpecifierRange,
bool Virtual, AccessSpecifier Access,
- TypeTy *basetype, SourceLocation
+ TypeTy *basetype, SourceLocation
BaseLoc);
bool AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases,
unsigned NumBases);
- virtual void ActOnBaseSpecifiers(DeclPtrTy ClassDecl, BaseTy **Bases,
+ 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 IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths);
+
bool CheckDerivedToBaseConversion(QualType Derived, QualType Base,
SourceLocation Loc, SourceRange Range);
bool CheckDerivedToBaseConversion(QualType Derived, QualType Base,
@@ -1978,29 +2374,37 @@ public:
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,
+
+ std::string getAmbiguousPathsDisplayString(CXXBasePaths &Paths);
+
+ /// CheckOverridingFunctionReturnType - Checks whether the return types are
+ /// covariant, according to C++ [class.virtual]p5.
+ bool CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
const CXXMethodDecl *Old);
-
+
+ /// CheckOverridingFunctionExceptionSpec - Checks whether the exception
+ /// spec is a subset of base spec.
+ bool CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
+ const CXXMethodDecl *Old);
//===--------------------------------------------------------------------===//
// C++ Access Control
//
-
- bool SetMemberAccessSpecifier(NamedDecl *MemberDecl,
+
+ bool SetMemberAccessSpecifier(NamedDecl *MemberDecl,
NamedDecl *PrevMemberDecl,
AccessSpecifier LexicalAS);
-
- bool CheckBaseClassAccess(QualType Derived, QualType Base,
+
+ const CXXBaseSpecifier *FindInaccessibleBase(QualType Derived, QualType Base,
+ CXXBasePaths &Paths,
+ bool NoPrivileges = false);
+
+ bool CheckBaseClassAccess(QualType Derived, QualType Base,
unsigned InaccessibleBaseID,
- BasePaths& Paths, SourceLocation AccessLoc,
+ CXXBasePaths& Paths, SourceLocation AccessLoc,
DeclarationName Name);
-
-
+
+
enum AbstractDiagSelID {
AbstractNone = -1,
AbstractReturnType,
@@ -2008,8 +2412,12 @@ public:
AbstractVariableType,
AbstractFieldType
};
-
- bool RequireNonAbstractType(SourceLocation Loc, QualType T, unsigned DiagID,
+
+ bool RequireNonAbstractType(SourceLocation Loc, QualType T,
+ const PartialDiagnostic &PD,
+ const CXXRecordDecl *CurrentRD = 0);
+
+ bool RequireNonAbstractType(SourceLocation Loc, QualType T, unsigned DiagID,
AbstractDiagSelID SelID = AbstractNone,
const CXXRecordDecl *CurrentRD = 0);
@@ -2022,19 +2430,23 @@ public:
//===--------------------------------------------------------------------===//
// C++ Templates [C++ 14]
//
- virtual TemplateNameKind isTemplateName(const IdentifierInfo &II, Scope *S,
- TemplateTy &Template,
- const CXXScopeSpec *SS = 0);
+ virtual TemplateNameKind isTemplateName(Scope *S,
+ const IdentifierInfo &II,
+ SourceLocation IdLoc,
+ const CXXScopeSpec *SS,
+ TypeTy *ObjectType,
+ bool EnteringContext,
+ TemplateTy &Template);
bool DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl);
TemplateDecl *AdjustDeclIfTemplate(DeclPtrTy &Decl);
- virtual DeclPtrTy ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis,
+ virtual DeclPtrTy ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis,
SourceLocation EllipsisLoc,
SourceLocation KeyLoc,
IdentifierInfo *ParamName,
SourceLocation ParamNameLoc,
unsigned Depth, unsigned Position);
- virtual void ActOnTypeParameterDefault(DeclPtrTy TypeParam,
+ virtual void ActOnTypeParameterDefault(DeclPtrTy TypeParam,
SourceLocation EqualLoc,
SourceLocation DefaultLoc,
TypeTy *Default);
@@ -2060,21 +2472,30 @@ public:
virtual TemplateParamsTy *
ActOnTemplateParameterList(unsigned Depth,
SourceLocation ExportLoc,
- SourceLocation TemplateLoc,
+ 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);
-
+ TemplateParameterList *
+ MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
+ const CXXScopeSpec &SS,
+ TemplateParameterList **ParamLists,
+ unsigned NumParamLists,
+ bool &IsExplicitSpecialization);
+
+ DeclResult CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
+ SourceLocation KWLoc, const CXXScopeSpec &SS,
+ IdentifierInfo *Name, SourceLocation NameLoc,
+ AttributeList *Attr,
+ TemplateParameterList *TemplateParams,
+ AccessSpecifier AS);
+
+ void translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn,
+ SourceLocation *TemplateArgLocs,
+ llvm::SmallVector<TemplateArgument, 16> &TemplateArgs);
+
QualType CheckTemplateIdType(TemplateName Template,
SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
@@ -2088,32 +2509,31 @@ public:
ASTTemplateArgsPtr TemplateArgs,
SourceLocation *TemplateArgLocs,
SourceLocation RAngleLoc);
-
+
+ virtual TypeResult ActOnTagTemplateIdType(TypeResult Type,
+ TagUseKind TUK,
+ DeclSpec::TST TagSpec,
+ SourceLocation TagLoc);
+
OwningExprResult BuildTemplateIdExpr(TemplateName Template,
SourceLocation TemplateNameLoc,
SourceLocation LAngleLoc,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs,
SourceLocation RAngleLoc);
-
+
virtual OwningExprResult ActOnTemplateIdExpr(TemplateTy Template,
SourceLocation TemplateNameLoc,
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 PartialSpecialization,
- bool ExplicitInstantiation);
+ const CXXScopeSpec &SS,
+ TypeTy *ObjectType);
bool CheckClassTemplatePartialSpecializationArgs(
TemplateParameterList *TemplateParams,
@@ -2121,8 +2541,8 @@ public:
bool &MirrorsPrimaryTemplate);
virtual DeclResult
- ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
- SourceLocation KWLoc,
+ ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagUseKind TUK,
+ SourceLocation KWLoc,
const CXXScopeSpec &SS,
TemplateTy Template,
SourceLocation TemplateNameLoc,
@@ -2133,17 +2553,28 @@ public:
AttributeList *Attr,
MultiTemplateParamsArg TemplateParameterLists);
- virtual DeclPtrTy ActOnTemplateDeclarator(Scope *S,
+ virtual DeclPtrTy ActOnTemplateDeclarator(Scope *S,
MultiTemplateParamsArg TemplateParameterLists,
Declarator &D);
-
- virtual DeclPtrTy ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
+
+ virtual DeclPtrTy ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
MultiTemplateParamsArg TemplateParameterLists,
Declarator &D);
-
+
+ bool CheckFunctionTemplateSpecialization(FunctionDecl *FD,
+ bool HasExplicitTemplateArgs,
+ SourceLocation LAngleLoc,
+ const TemplateArgument *ExplicitTemplateArgs,
+ unsigned NumExplicitTemplateArgs,
+ SourceLocation RAngleLoc,
+ NamedDecl *&PrevDecl);
+ bool CheckMemberSpecialization(NamedDecl *Member, NamedDecl *&PrevDecl);
+
virtual DeclResult
- ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
- unsigned TagSpec,
+ ActOnExplicitInstantiation(Scope *S,
+ SourceLocation ExternLoc,
+ SourceLocation TemplateLoc,
+ unsigned TagSpec,
SourceLocation KWLoc,
const CXXScopeSpec &SS,
TemplateTy Template,
@@ -2155,14 +2586,21 @@ public:
AttributeList *Attr);
virtual DeclResult
- ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
- unsigned TagSpec,
+ ActOnExplicitInstantiation(Scope *S,
+ SourceLocation ExternLoc,
+ SourceLocation TemplateLoc,
+ unsigned TagSpec,
SourceLocation KWLoc,
const CXXScopeSpec &SS,
IdentifierInfo *Name,
SourceLocation NameLoc,
AttributeList *Attr);
+ virtual DeclResult ActOnExplicitInstantiation(Scope *S,
+ SourceLocation ExternLoc,
+ SourceLocation TemplateLoc,
+ Declarator &D);
+
bool CheckTemplateArgumentList(TemplateDecl *Template,
SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
@@ -2172,16 +2610,16 @@ public:
bool PartialTemplateArgs,
TemplateArgumentListBuilder &Converted);
- bool CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
+ bool CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
const TemplateArgument &Arg,
TemplateArgumentListBuilder &Converted);
bool CheckTemplateArgument(TemplateTypeParmDecl *Param, QualType Arg,
SourceLocation ArgLoc);
- bool CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
+ bool CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
NamedDecl *&Entity);
bool CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member);
- bool CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
+ bool CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
QualType InstantiatedParamType, Expr *&Arg,
TemplateArgument &Converted);
bool CheckTemplateArgument(TemplateTemplateParmDecl *Param, DeclRefExpr *Arg);
@@ -2191,9 +2629,8 @@ public:
bool IsTemplateTemplateParm = false,
SourceLocation TemplateArgLoc
= SourceLocation());
-
- bool CheckTemplateDeclScope(Scope *S,
- MultiTemplateParamsArg &TemplateParameterLists);
+
+ bool CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams);
/// \brief Called when the parser has parsed a C++ typename
/// specifier, e.g., "typename T::type".
@@ -2207,7 +2644,7 @@ public:
const IdentifierInfo &II, SourceLocation IdLoc);
/// \brief Called when the parser has parsed a C++ typename
- /// specifier that ends in a template-id, e.g.,
+ /// specifier that ends in a template-id, e.g.,
/// "typename MetaFun::template apply<T1, T2>".
///
/// \param TypenameLoc the location of the 'typename' keyword
@@ -2222,6 +2659,13 @@ public:
const IdentifierInfo &II,
SourceRange Range);
+ QualType RebuildTypeInCurrentInstantiation(QualType T, SourceLocation Loc,
+ DeclarationName Name);
+
+ std::string
+ getTemplateArgumentBindingsText(const TemplateParameterList *Params,
+ const TemplateArgumentList &Args);
+
/// \brief Describes the result of template argument deduction.
///
/// The TemplateDeductionResult enumeration describes the result of
@@ -2256,10 +2700,10 @@ public:
/// produces a type that does not match the original template
/// arguments provided.
TDK_NonDeducedMismatch,
- /// \brief When performing template argument deduction for a function
+ /// \brief When performing template argument deduction for a function
/// template, there were too many call arguments.
TDK_TooManyArguments,
- /// \brief When performing template argument deduction for a class
+ /// \brief When performing template argument deduction for a function
/// template, there were too few call arguments.
TDK_TooFewArguments,
/// \brief The explicitly-specified template arguments were not valid
@@ -2290,7 +2734,7 @@ public:
}
/// \brief Take ownership of the deduced template argument list.
- TemplateArgumentList *take() {
+ TemplateArgumentList *take() {
TemplateArgumentList *Result = Deduced;
Deduced = 0;
return Result;
@@ -2343,7 +2787,22 @@ public:
DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
const TemplateArgumentList &TemplateArgs,
TemplateDeductionInfo &Info);
-
+
+ TemplateDeductionResult
+ SubstituteExplicitTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
+ const TemplateArgument *ExplicitTemplateArgs,
+ unsigned NumExplicitTemplateArgs,
+ llvm::SmallVectorImpl<TemplateArgument> &Deduced,
+ llvm::SmallVectorImpl<QualType> &ParamTypes,
+ QualType *FunctionType,
+ TemplateDeductionInfo &Info);
+
+ TemplateDeductionResult
+ FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
+ llvm::SmallVectorImpl<TemplateArgument> &Deduced,
+ FunctionDecl *&Specialization,
+ TemplateDeductionInfo &Info);
+
TemplateDeductionResult
DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
bool HasExplicitTemplateArgs,
@@ -2352,15 +2811,50 @@ public:
Expr **Args, unsigned NumArgs,
FunctionDecl *&Specialization,
TemplateDeductionInfo &Info);
-
- void MarkDeducedTemplateParameters(const TemplateArgumentList &TemplateArgs,
+
+ TemplateDeductionResult
+ DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
+ bool HasExplicitTemplateArgs,
+ const TemplateArgument *ExplicitTemplateArgs,
+ unsigned NumExplicitTemplateArgs,
+ QualType ArgFunctionType,
+ FunctionDecl *&Specialization,
+ TemplateDeductionInfo &Info);
+
+ TemplateDeductionResult
+ DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
+ QualType ToType,
+ CXXConversionDecl *&Specialization,
+ TemplateDeductionInfo &Info);
+
+ FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
+ FunctionTemplateDecl *FT2,
+ TemplatePartialOrderingContext TPOC);
+ FunctionDecl *getMostSpecialized(FunctionDecl **Specializations,
+ unsigned NumSpecializations,
+ TemplatePartialOrderingContext TPOC,
+ SourceLocation Loc,
+ const PartialDiagnostic &NoneDiag,
+ const PartialDiagnostic &AmbigDiag,
+ const PartialDiagnostic &CandidateDiag,
+ unsigned *Index = 0);
+
+ ClassTemplatePartialSpecializationDecl *
+ getMoreSpecializedPartialSpecialization(
+ ClassTemplatePartialSpecializationDecl *PS1,
+ ClassTemplatePartialSpecializationDecl *PS2);
+
+ void MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs,
+ bool OnlyDeduced,
+ llvm::SmallVectorImpl<bool> &Used);
+ void MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate,
llvm::SmallVectorImpl<bool> &Deduced);
-
+
//===--------------------------------------------------------------------===//
// C++ Template Instantiation
//
- const TemplateArgumentList &getTemplateInstantiationArgs(NamedDecl *D);
+ MultiLevelTemplateArgumentList getTemplateInstantiationArgs(NamedDecl *D);
/// \brief A template instantiation that is currently in progress.
struct ActiveTemplateInstantiation {
@@ -2377,10 +2871,15 @@ public:
/// FIXME: Use a TemplateArgumentList
DefaultTemplateArgumentInstantiation,
- /// We are substituting explicit template arguments provided for
+ /// We are instantiating a default argument for a function.
+ /// The Entity is the ParmVarDecl, and TemplateArgs/NumTemplateArgs
+ /// provides the template arguments as specified.
+ DefaultFunctionArgumentInstantiation,
+
+ /// We are substituting explicit template arguments provided for
/// a function template. The entity is a FunctionTemplateDecl.
ExplicitTemplateArgumentSubstitution,
-
+
/// We are substituting template argument determined as part of
/// template argument deduction for either a class template
/// partial specialization or a function template. The
@@ -2407,6 +2906,9 @@ public:
/// template instantiation.
SourceRange InstantiationRange;
+ ActiveTemplateInstantiation() : Kind(TemplateInstantiation), Entity(0),
+ TemplateArgs(0), NumTemplateArgs(0) {}
+
friend bool operator==(const ActiveTemplateInstantiation &X,
const ActiveTemplateInstantiation &Y) {
if (X.Kind != Y.Kind)
@@ -2422,7 +2924,9 @@ public:
case DefaultTemplateArgumentInstantiation:
case ExplicitTemplateArgumentSubstitution:
case DeducedTemplateArgumentSubstitution:
+ case DefaultFunctionArgumentInstantiation:
return X.TemplateArgs == Y.TemplateArgs;
+
}
return true;
@@ -2440,7 +2944,7 @@ public:
/// requires another template instantiation, additional
/// instantiations are pushed onto the stack up to a
/// user-configurable limit LangOptions::InstantiationDepth.
- llvm::SmallVector<ActiveTemplateInstantiation, 16>
+ llvm::SmallVector<ActiveTemplateInstantiation, 16>
ActiveTemplateInstantiations;
/// \brief The last template from which a template instantiation
@@ -2486,7 +2990,7 @@ public:
unsigned NumTemplateArgs,
ActiveTemplateInstantiation::InstantiationKind Kind,
SourceRange InstantiationRange = SourceRange());
-
+
/// \brief Note that we are instantiating as part of template
/// argument deduction for a class template partial
/// specialization.
@@ -2496,6 +3000,12 @@ public:
unsigned NumTemplateArgs,
SourceRange InstantiationRange = SourceRange());
+ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+ ParmVarDecl *Param,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ SourceRange InstantiationRange = SourceRange());
+
/// \brief Note that we have finished instantiating this template.
void Clear();
@@ -2514,7 +3024,7 @@ public:
InstantiatingTemplate(const InstantiatingTemplate&); // not implemented
- InstantiatingTemplate&
+ InstantiatingTemplate&
operator=(const InstantiatingTemplate&); // not implemented
};
@@ -2541,8 +3051,8 @@ public:
~SFINAETrap() { SemaRef.NumSFINAEErrors = PrevSFINAEErrors; }
/// \brief Determine whether any SFINAE errors have been trapped.
- bool hasErrorOccurred() const {
- return SemaRef.NumSFINAEErrors > PrevSFINAEErrors;
+ bool hasErrorOccurred() const {
+ return SemaRef.NumSFINAEErrors > PrevSFINAEErrors;
}
};
@@ -2584,7 +3094,7 @@ public:
public:
LocalInstantiationScope(Sema &SemaRef)
- : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope) {
+ : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope) {
SemaRef.CurrentInstantiationScope = this;
}
@@ -2619,85 +3129,89 @@ public:
/// \brief An entity for which implicit template instantiation is required.
///
- /// The source location associated with the declaration is the first place in
+ /// The source location associated with the declaration is the first place in
/// the source code where the declaration was "used". It is not necessarily
- /// the point of instantiation (which will be either before or after the
+ /// the point of instantiation (which will be either before or after the
/// namespace-scope declaration that triggered this implicit instantiation),
/// However, it is the location that diagnostics should generally refer to,
/// because users will need to know what code triggered the instantiation.
typedef std::pair<ValueDecl *, SourceLocation> PendingImplicitInstantiation;
-
+
/// \brief The queue of implicit template instantiations that are required
/// but have not yet been performed.
std::deque<PendingImplicitInstantiation> PendingImplicitInstantiations;
void PerformPendingImplicitInstantiations();
-
- 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);
+ QualType SubstType(QualType T,
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ SourceLocation Loc, DeclarationName Entity);
- Decl *InstantiateDecl(Decl *D, DeclContext *Owner,
- const TemplateArgumentList &TemplateArgs);
+ OwningExprResult SubstExpr(Expr *E,
+ const MultiLevelTemplateArgumentList &TemplateArgs);
- bool
- InstantiateBaseSpecifiers(CXXRecordDecl *Instantiation,
- CXXRecordDecl *Pattern,
- const TemplateArgumentList &TemplateArgs);
+ OwningStmtResult SubstStmt(Stmt *S,
+ const MultiLevelTemplateArgumentList &TemplateArgs);
+
+ Decl *SubstDecl(Decl *D, DeclContext *Owner,
+ const MultiLevelTemplateArgumentList &TemplateArgs);
+
+ bool
+ SubstBaseSpecifiers(CXXRecordDecl *Instantiation,
+ CXXRecordDecl *Pattern,
+ const MultiLevelTemplateArgumentList &TemplateArgs);
bool
InstantiateClass(SourceLocation PointOfInstantiation,
CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern,
- const TemplateArgumentList &TemplateArgs,
- bool ExplicitInstantiation);
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ TemplateSpecializationKind TSK,
+ bool Complain = true);
- bool
+ bool
InstantiateClassTemplateSpecialization(
ClassTemplateSpecializationDecl *ClassTemplateSpec,
- bool ExplicitInstantiation);
+ TemplateSpecializationKind TSK,
+ bool Complain = true);
void InstantiateClassMembers(SourceLocation PointOfInstantiation,
CXXRecordDecl *Instantiation,
- const TemplateArgumentList &TemplateArgs);
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ TemplateSpecializationKind TSK);
void InstantiateClassTemplateSpecializationMembers(
SourceLocation PointOfInstantiation,
- ClassTemplateSpecializationDecl *ClassTemplateSpec);
+ ClassTemplateSpecializationDecl *ClassTemplateSpec,
+ TemplateSpecializationKind TSK);
NestedNameSpecifier *
- InstantiateNestedNameSpecifier(NestedNameSpecifier *NNS,
- SourceRange Range,
- const TemplateArgumentList &TemplateArgs);
+ SubstNestedNameSpecifier(NestedNameSpecifier *NNS,
+ SourceRange Range,
+ const MultiLevelTemplateArgumentList &TemplateArgs);
TemplateName
- InstantiateTemplateName(TemplateName Name, SourceLocation Loc,
- const TemplateArgumentList &TemplateArgs);
- TemplateArgument Instantiate(TemplateArgument Arg,
- const TemplateArgumentList &TemplateArgs);
+ SubstTemplateName(TemplateName Name, SourceLocation Loc,
+ const MultiLevelTemplateArgumentList &TemplateArgs);
+ TemplateArgument Subst(TemplateArgument Arg,
+ const MultiLevelTemplateArgumentList &TemplateArgs);
void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
FunctionDecl *Function,
bool Recursive = false);
- void InstantiateVariableDefinition(VarDecl *Var);
+ void InstantiateStaticDataMemberDefinition(
+ SourceLocation PointOfInstantiation,
+ VarDecl *Var,
+ bool Recursive = false);
+
+ void InstantiateMemInitializers(CXXConstructorDecl *New,
+ const CXXConstructorDecl *Tmpl,
+ const MultiLevelTemplateArgumentList &TemplateArgs);
+
+ NamedDecl *FindInstantiatedDecl(NamedDecl *D,
+ const MultiLevelTemplateArgumentList &TemplateArgs);
+ DeclContext *FindInstantiatedContext(DeclContext *DC,
+ const MultiLevelTemplateArgumentList &TemplateArgs);
- 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,
@@ -2708,7 +3222,7 @@ public:
unsigned NumProtoRefs,
SourceLocation EndProtoLoc,
AttributeList *AttrList);
-
+
virtual DeclPtrTy ActOnCompatiblityAlias(
SourceLocation AtCompatibilityAliasLoc,
IdentifierInfo *AliasName, SourceLocation AliasLocation,
@@ -2718,14 +3232,14 @@ public:
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,
@@ -2734,78 +3248,82 @@ public:
const DeclPtrTy *ProtoRefs,
unsigned NumProtoRefs,
SourceLocation EndProtoLoc);
-
+
virtual DeclPtrTy ActOnStartClassImplementation(
SourceLocation AtClassImplLoc,
IdentifierInfo *ClassName, SourceLocation ClassLoc,
- IdentifierInfo *SuperClassname,
+ IdentifierInfo *SuperClassname,
SourceLocation SuperClassLoc);
-
+
virtual DeclPtrTy ActOnStartCategoryImplementation(
SourceLocation AtCatImplLoc,
- IdentifierInfo *ClassName,
+ 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.
+
+ /// 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,
+ void CheckObjCPropertyAttributes(QualType PropertyTy,
SourceLocation Loc,
unsigned &Attributes);
void ProcessPropertyDecl(ObjCPropertyDecl *property, ObjCContainerDecl *DC);
- void DiagnosePropertyMismatch(ObjCPropertyDecl *Property,
+ void DiagnosePropertyMismatch(ObjCPropertyDecl *Property,
ObjCPropertyDecl *SuperProperty,
const IdentifierInfo *Name);
void ComparePropertiesInBaseAndSuper(ObjCInterfaceDecl *IDecl);
-
+
+ void CompareMethodParamsInBaseAndSuper(Decl *IDecl,
+ ObjCMethodDecl *MethodDecl,
+ bool IsInstance);
+
void MergeProtocolPropertiesIntoClass(Decl *CDecl,
DeclPtrTy MergeProtocols);
-
- void DiagnoseClassExtensionDupMethods(ObjCCategoryDecl *CAT,
+
+ 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,
+
+ 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,
+ tok::TokenKind MethodType,
+ DeclPtrTy ClassDecl, ObjCDeclSpec &ReturnQT, TypeTy *ReturnType,
Selector Sel,
// optional arguments. The number of types/arguments is obtained
// from the Sel.getNumArgs().
@@ -2818,24 +3336,24 @@ public:
// 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,
+ 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,
+ IdentifierInfo *receivingClassName, Selector Sel, SourceLocation lbrac,
+ SourceLocation receiverLoc, SourceLocation selectorLoc,SourceLocation rbrac,
ExprTy **ArgExprs, unsigned NumArgs);
// ActOnInstanceMessage - used for both unary and keyword messages.
@@ -2843,23 +3361,27 @@ public:
// is obtained from NumArgs.
virtual ExprResult ActOnInstanceMessage(
ExprTy *receiver, Selector Sel,
- SourceLocation lbrac, SourceLocation receiverLoc, SourceLocation rbrac,
+ 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 PragmaLoc,
SourceLocation LParenLoc,
SourceLocation RParenLoc);
-
+
/// ActOnPragmaUnused - Called on well-formed '#pragma unused'.
- virtual void ActOnPragmaUnused(ExprTy **Exprs, unsigned NumExprs,
- SourceLocation PragmaLoc,
+ virtual void ActOnPragmaUnused(const Token *Identifiers,
+ unsigned NumIdentifiers, Scope *curScope,
+ SourceLocation PragmaLoc,
SourceLocation LParenLoc,
SourceLocation RParenLoc);
+ NamedDecl *DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II);
+ void DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W);
+
/// ActOnPragmaWeakID - Called on well formed #pragma weak ident.
virtual void ActOnPragmaWeakID(IdentifierInfo* WeakName,
SourceLocation PragmaLoc,
@@ -2875,25 +3397,27 @@ public:
/// 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);
+ void ImpCastExprToType(Expr *&Expr, QualType Type,
+ CastExpr::CastKind Kind = CastExpr::CK_Unknown,
+ 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);
+ Expr *UsualUnaryConversions(Expr *&expr);
// DefaultFunctionArrayConversion - converts functions and arrays
- // to their respective pointers (C99 6.3.2.1).
+ // 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
+ // 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);
@@ -2901,26 +3425,21 @@ public:
enum VariadicCallType {
VariadicFunction,
VariadicBlock,
- VariadicMethod
+ VariadicMethod,
+ VariadicConstructor
};
-
+
// 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
+ // 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
@@ -2930,15 +3449,15 @@ public:
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,
@@ -2960,25 +3479,25 @@ public:
/// 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
+
+ /// IntToBlockPointer - The assignment converts an int to a block
/// pointer. We disallow this.
IntToBlockPointer,
- /// IncompatibleBlockPointer - The assignment is between two block
+ /// 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.
@@ -2986,39 +3505,46 @@ public:
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.
+
+ /// 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,
+
+ // CheckSingleAssignmentConstraints - Currently used by
+ // CheckAssignmentOperands, and ActOnReturnStmt. Prior to type checking,
// this routine performs the default function/array converions.
- AssignConvertType CheckSingleAssignmentConstraints(QualType lhs,
+ 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,
+ AssignConvertType CheckTransparentUnionArgumentConstraints(QualType lhs,
Expr *&rExpr);
-
+
// Helper function for CheckAssignmentConstraints (C99 6.5.16.1p1)
- AssignConvertType CheckPointerTypesForAssignment(QualType lhsType,
+ AssignConvertType CheckPointerTypesForAssignment(QualType lhsType,
QualType rhsType);
-
+
// Helper function for CheckAssignmentConstraints involving two
// block pointer types.
- AssignConvertType CheckBlockPointerTypesForAssignment(QualType lhsType,
+ AssignConvertType CheckBlockPointerTypesForAssignment(QualType lhsType,
QualType rhsType);
bool IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType);
- bool PerformImplicitConversion(Expr *&From, QualType ToType,
+ bool CheckExceptionSpecCompatibility(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,
+ bool PerformImplicitConversion(Expr *&From, QualType ToType,
+ const char *Flavor,
+ bool AllowExplicit,
+ bool Elidable,
+ ImplicitConversionSequence& ICS);
+ bool PerformImplicitConversion(Expr *&From, QualType ToType,
const ImplicitConversionSequence& ICS,
const char *Flavor);
bool PerformImplicitConversion(Expr *&From, QualType ToType,
@@ -3065,7 +3591,7 @@ public:
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,
@@ -3073,19 +3599,20 @@ public:
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);
-
+ const 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]).
@@ -3115,48 +3642,70 @@ public:
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.
+ SourceLocation DeclLoc,
+ bool SuppressUserConversions,
+ bool AllowExplicit,
+ bool ForceRValue,
+ ImplicitConversionSequence *ICS = 0);
+
+ /// CheckCastTypes - Check type constraints for casting between types under
+ /// C semantics, or forward to CXXCheckCStyleCast in C++.
+ bool CheckCastTypes(SourceRange TyRange, QualType CastTy, Expr *&CastExpr,
+ CastExpr::CastKind &Kind,
+ CXXMethodDecl *& ConversionDecl,
+ bool FunctionalStyle = false);
+
+ // 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);
-
- // CheckExtVectorCast - check type constraints for extended vectors.
+
+ // CheckExtVectorCast - check type constraints for extended 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,
// or vectors and the element type of that vector.
// returns true if the cast is invalid
bool CheckExtVectorCast(SourceRange R, QualType VectorTy, QualType Ty);
-
- /// CheckMessageArgumentTypes - Check types in an Obj-C message send.
+
+ /// CXXCheckCStyleCast - Check constraints of a C-style or function-style
+ /// cast under C++ semantics.
+ bool CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr,
+ CastExpr::CastKind &Kind, bool FunctionalStyle,
+ CXXMethodDecl *&ConversionDecl);
+
+ /// 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);
+ QualType &ReturnType);
+
+ /// CheckBooleanCondition - Diagnose problems involving the use of
+ /// the given expression as a boolean condition (e.g. in an if
+ /// statement). Also performs the standard function and array
+ /// decays, possibly changing the input variable.
+ ///
+ /// \param Loc - A location associated with the condition, e.g. the
+ /// 'if' keyword.
+ /// \return true iff there were any errors
+ bool CheckBooleanCondition(Expr *&CondExpr, SourceLocation Loc);
+
+ /// DiagnoseAssignmentAsCondition - Given that an expression is
+ /// being used as a boolean condition, warn if it's an assignment.
+ void DiagnoseAssignmentAsCondition(Expr *E);
/// 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,
+ 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
@@ -3171,23 +3720,67 @@ public:
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.
+ /// 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);
+ /// Can optionally return whether the bit-field is of width 0
+ bool VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName,
+ QualType FieldTy, const Expr *BitWidth,
+ bool *ZeroWidth = 0);
+
+ /// adjustFunctionParamType - Converts the type of a function parameter to a
+ // type that can be passed as an argument type to
+ /// ASTContext::getFunctionType.
+ ///
+ /// C++ [dcl.fct]p3: "...Any cv-qualifier modifying a parameter type is
+ /// deleted. Such cv-qualifiers affect only the definition of the parameter
+ /// within the body of the function; they do not affect the function type.
+ QualType adjustFunctionParamType(QualType T) const {
+ if (!Context.getLangOptions().CPlusPlus)
+ return T;
+ return
+ T->isDependentType() ? T.getUnqualifiedType()
+ : T.getDesugaredType().getUnqualifiedType();
+
+ }
+ /// \name Code completion
+ //@{
+ void setCodeCompleteConsumer(CodeCompleteConsumer *CCC);
+ virtual void CodeCompleteOrdinaryName(Scope *S);
+ virtual void CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *Base,
+ SourceLocation OpLoc,
+ bool IsArrow);
+ virtual void CodeCompleteTag(Scope *S, unsigned TagSpec);
+ virtual void CodeCompleteCase(Scope *S);
+ virtual void CodeCompleteCall(Scope *S, ExprTy *Fn,
+ ExprTy **Args, unsigned NumArgs);
+ virtual void CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS,
+ bool EnteringContext);
+ virtual void CodeCompleteUsing(Scope *S);
+ virtual void CodeCompleteUsingDirective(Scope *S);
+ virtual void CodeCompleteNamespaceDecl(Scope *S);
+ virtual void CodeCompleteNamespaceAliasDecl(Scope *S);
+ virtual void CodeCompleteOperatorName(Scope *S);
+
+ virtual void CodeCompleteObjCProperty(Scope *S, ObjCDeclSpec &ODS);
+ //@}
+
//===--------------------------------------------------------------------===//
// Extra semantic analysis beyond the C type system
private:
- Action::OwningExprResult CheckFunctionCall(FunctionDecl *FDecl,
- CallExpr *TheCall);
-
- Action::OwningExprResult CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall);
+ bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall);
+ bool CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall);
+
SourceLocation getLocationOfStringLiteralByte(const StringLiteral *SL,
unsigned ByteNo) const;
+ bool CheckablePrintfAttr(const FormatAttr *Format, CallExpr *TheCall);
bool CheckObjCString(Expr *Arg);
+
+ Action::OwningExprResult CheckBuiltinFunctionCall(unsigned BuiltinID,
+ CallExpr *TheCall);
bool SemaBuiltinVAStart(CallExpr *TheCall);
bool SemaBuiltinUnorderedCompare(CallExpr *TheCall);
+ bool SemaBuiltinUnaryFP(CallExpr *TheCall);
bool SemaBuiltinStackAddress(CallExpr *TheCall);
public:
@@ -3195,19 +3788,20 @@ public:
Action::OwningExprResult SemaBuiltinShuffleVector(CallExpr *TheCall);
private:
- bool SemaBuiltinPrefetch(CallExpr *TheCall);
+ bool SemaBuiltinPrefetch(CallExpr *TheCall);
bool SemaBuiltinObjectSize(CallExpr *TheCall);
bool SemaBuiltinLongjmp(CallExpr *TheCall);
bool SemaBuiltinAtomicOverloaded(CallExpr *TheCall);
+ bool SemaBuiltinEHReturnDataRegNo(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,
+ void CheckNonNullArguments(const NonNullAttr *NonNull,
const CallExpr *TheCall);
- void CheckPrintfArguments(const CallExpr *TheCall, bool HasVAListArg,
+ void CheckPrintfArguments(const CallExpr *TheCall, bool HasVAListArg,
unsigned format_idx, unsigned firstDataArg);
void CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
SourceLocation ReturnLoc);
@@ -3221,12 +3815,12 @@ 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(); }
};
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index bae69ac..21f83a5 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -11,15 +11,16 @@
//
//===----------------------------------------------------------------------===//
-#include "SemaInherit.h"
#include "Sema.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/DeclCXX.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,
+bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl,
NamedDecl *PrevMemberDecl,
AccessSpecifier LexicalAS) {
if (!PrevMemberDecl) {
@@ -27,52 +28,49 @@ bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl,
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)
+ 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) {
+/// Find a class on the derivation path between Derived and Base that is
+/// inaccessible. If @p NoPrivileges is true, special access rights (members
+/// and friends) are not considered.
+const CXXBaseSpecifier *Sema::FindInaccessibleBase(
+ QualType Derived, QualType Base, CXXBasePaths &Paths, bool NoPrivileges) {
Base = Context.getCanonicalType(Base).getUnqualifiedType();
- assert(!Paths.isAmbiguous(Base) &&
+ 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;
+
+ const CXXBaseSpecifier *InaccessibleBase = 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();
+ for (CXXBasePaths::paths_iterator Path = Paths.begin(), PathsEnd = Paths.end();
Path != PathsEnd; ++Path) {
-
+
bool FoundInaccessibleBase = false;
-
- for (BasePath::const_iterator Element = Path->begin(),
+
+ for (CXXBasePath::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");
@@ -81,44 +79,59 @@ bool Sema::CheckBaseClassAccess(QualType Derived, QualType Base,
break;
case AS_private:
// FIXME: Check if the current function/class is a friend.
- if (CurrentClassDecl != Element->Class)
+ if (NoPrivileges || CurrentClassDecl != Element->Class)
FoundInaccessibleBase = true;
break;
- case AS_protected:
+ case AS_protected:
// FIXME: Implement
break;
}
-
+
if (FoundInaccessibleBase) {
- InacessibleBase = Base;
+ InaccessibleBase = Base;
break;
}
}
-
+
if (!FoundInaccessibleBase) {
// We found a path to the base, our work here is done.
- InacessibleBase = 0;
- break;
+ return 0;
}
}
- if (InacessibleBase) {
- Diag(AccessLoc, InaccessibleBaseID)
+ assert(InaccessibleBase && "no path found, but no inaccessible base");
+ return InaccessibleBase;
+}
+
+/// 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,
+ CXXBasePaths &Paths, SourceLocation AccessLoc,
+ DeclarationName Name) {
+
+ if (!getLangOptions().AccessControl)
+ return false;
+ const CXXBaseSpecifier *InaccessibleBase = FindInaccessibleBase(
+ Derived, Base, Paths);
+
+ if (InaccessibleBase) {
+ Diag(AccessLoc, InaccessibleBaseID)
<< Derived << Base << Name;
- AccessSpecifier AS = InacessibleBase->getAccessSpecifierAsWritten();
-
+ AccessSpecifier AS = InaccessibleBase->getAccessSpecifierAsWritten();
+
// If there's no written access specifier, then the inheritance specifier
// is implicitly private.
if (AS == AS_none)
- Diag(InacessibleBase->getSourceRange().getBegin(),
+ Diag(InaccessibleBase->getSourceRange().getBegin(),
diag::note_inheritance_implicitly_private_here);
else
- Diag(InacessibleBase->getSourceRange().getBegin(),
+ Diag(InaccessibleBase->getSourceRange().getBegin(),
diag::note_inheritance_specifier_here) << AS;
return true;
}
-
+
return false;
}
diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp
index 1bf8444..0a5335a 100644
--- a/lib/Sema/SemaAttr.cpp
+++ b/lib/Sema/SemaAttr.cpp
@@ -32,8 +32,8 @@ namespace {
/// Stack - Entries in the #pragma pack stack, consisting of saved
/// alignments and optional names.
stack_ty Stack;
-
- public:
+
+ public:
PragmaPackStack() : Alignment(0) {}
void setAlignment(unsigned A) { Alignment = A; }
@@ -56,14 +56,14 @@ 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;
@@ -74,7 +74,7 @@ bool PragmaPackStack::pop(IdentifierInfo *Name) {
return true;
}
}
-
+
return false;
}
@@ -93,8 +93,8 @@ unsigned Sema::getPragmaPackAlignment() const {
return 0;
}
-void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name,
- ExprTy *alignment, SourceLocation PragmaLoc,
+void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name,
+ ExprTy *alignment, SourceLocation PragmaLoc,
SourceLocation LParenLoc, SourceLocation RParenLoc) {
Expr *Alignment = static_cast<Expr *>(alignment);
@@ -102,7 +102,7 @@ void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name,
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) ||
@@ -115,12 +115,12 @@ void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name,
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);
@@ -140,15 +140,15 @@ void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name,
Context->push(Name);
// Set the new alignment if specified.
if (Alignment)
- Context->setAlignment(AlignmentVal);
+ 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);
-
+ 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
@@ -170,42 +170,34 @@ void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name,
}
}
-void Sema::ActOnPragmaUnused(ExprTy **Exprs, unsigned NumExprs,
+void Sema::ActOnPragmaUnused(const Token *Identifiers, unsigned NumIdentifiers,
+ Scope *curScope,
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();;
+ for (unsigned i = 0; i < NumIdentifiers; ++i) {
+ const Token &Tok = Identifiers[i];
+ IdentifierInfo *Name = Tok.getIdentifierInfo();
+ LookupResult Lookup;
+ LookupParsedName(Lookup, curScope, NULL, Name,LookupOrdinaryName,
+ false, true, Tok.getLocation());
+ // FIXME: Handle Lookup.isAmbiguous?
- if (!isa<VarDecl>(d) || !cast<VarDecl>(d)->hasLocalStorage()) {
- ErrorExpr = Ex;
- break;
+ NamedDecl *ND = Lookup.getAsSingleDecl(Context);
+
+ if (!ND) {
+ Diag(PragmaLoc, diag::warn_pragma_unused_undeclared_var)
+ << Name << SourceRange(Tok.getLocation());
+ continue;
}
- }
-
- // 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);
+
+ if (!isa<VarDecl>(ND) || !cast<VarDecl>(ND)->hasLocalStorage()) {
+ Diag(PragmaLoc, diag::warn_pragma_unused_expected_localvar)
+ << Name << SourceRange(Tok.getLocation());
+ continue;
+ }
+
+ ND->addAttr(::new (Context) UnusedAttr());
}
}
diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp
new file mode 100644
index 0000000..69d1f92
--- /dev/null
+++ b/lib/Sema/SemaCXXCast.cpp
@@ -0,0 +1,1128 @@
+//===--- 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 "clang/AST/ExprCXX.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/CXXInheritance.h"
+#include "clang/Basic/PartialDiagnostic.h"
+#include "llvm/ADT/SmallVector.h"
+#include <set>
+using namespace clang;
+
+enum TryCastResult {
+ TC_NotApplicable, ///< The cast method is not applicable.
+ TC_Success, ///< The cast method is appropriate and successful.
+ TC_Failed ///< The cast method is appropriate, but failed. A
+ ///< diagnostic has been emitted.
+};
+
+enum CastType {
+ CT_Const, ///< const_cast
+ CT_Static, ///< static_cast
+ CT_Reinterpret, ///< reinterpret_cast
+ CT_Dynamic, ///< dynamic_cast
+ CT_CStyle, ///< (Type)expr
+ CT_Functional ///< Type(expr)
+};
+
+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,
+ CastExpr::CastKind &Kind);
+static void CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
+ const SourceRange &OpRange,
+ CastExpr::CastKind &Kind,
+ CXXMethodDecl *&ConversionDecl);
+static void CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
+ const SourceRange &OpRange,
+ const SourceRange &DestRange,
+ CastExpr::CastKind &Kind);
+
+static bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType);
+
+// The Try functions attempt a specific way of casting. If they succeed, they
+// return TC_Success. If their way of casting is not appropriate for the given
+// arguments, they return TC_NotApplicable and *may* set diag to a diagnostic
+// to emit if no other way succeeds. If their way of casting is appropriate but
+// fails, they return TC_Failed and *must* set diag; they can set it to 0 if
+// they emit a specialized diagnostic.
+// All diagnostics returned by these functions must expect the same three
+// arguments:
+// %0: Cast Type (a value from the CastType enumeration)
+// %1: Source Type
+// %2: Destination Type
+static TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr,
+ QualType DestType, unsigned &msg);
+static TryCastResult TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr,
+ QualType DestType, bool CStyle,
+ const SourceRange &OpRange,
+ unsigned &msg);
+static TryCastResult TryStaticPointerDowncast(Sema &Self, QualType SrcType,
+ QualType DestType, bool CStyle,
+ const SourceRange &OpRange,
+ unsigned &msg);
+static TryCastResult TryStaticDowncast(Sema &Self, QualType SrcType,
+ QualType DestType, bool CStyle,
+ const SourceRange &OpRange,
+ QualType OrigSrcType,
+ QualType OrigDestType, unsigned &msg);
+static TryCastResult TryStaticMemberPointerUpcast(Sema &Self, QualType SrcType,
+ QualType DestType,bool CStyle,
+ const SourceRange &OpRange,
+ unsigned &msg);
+static TryCastResult TryStaticImplicitCast(Sema &Self, Expr *SrcExpr,
+ QualType DestType, bool CStyle,
+ const SourceRange &OpRange,
+ unsigned &msg,
+ CastExpr::CastKind &Kind,
+ CXXMethodDecl *&ConversionDecl);
+static TryCastResult TryStaticCast(Sema &Self, Expr *SrcExpr,
+ QualType DestType, bool CStyle,
+ const SourceRange &OpRange,
+ unsigned &msg,
+ CastExpr::CastKind &Kind,
+ CXXMethodDecl *&ConversionDecl);
+static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType,
+ bool CStyle, unsigned &msg);
+static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr,
+ QualType DestType, bool CStyle,
+ const SourceRange &OpRange,
+ unsigned &msg,
+ CastExpr::CastKind &Kind);
+
+/// 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>();
+ // FIXME: Preserve type source info.
+ QualType DestType = GetTypeFromParser(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: {
+ CastExpr::CastKind Kind = CastExpr::CK_Unknown;
+ if (!TypeDependent)
+ CheckDynamicCast(*this, Ex, DestType, OpRange, DestRange, Kind);
+ return Owned(new (Context)CXXDynamicCastExpr(DestType.getNonReferenceType(),
+ Kind, Ex, DestType, OpLoc));
+ }
+ case tok::kw_reinterpret_cast: {
+ CastExpr::CastKind Kind = CastExpr::CK_Unknown;
+ if (!TypeDependent)
+ CheckReinterpretCast(*this, Ex, DestType, OpRange, DestRange, Kind);
+ return Owned(new (Context) CXXReinterpretCastExpr(
+ DestType.getNonReferenceType(),
+ Kind, Ex, DestType, OpLoc));
+ }
+ case tok::kw_static_cast: {
+ CastExpr::CastKind Kind = CastExpr::CK_Unknown;
+ if (!TypeDependent) {
+ CXXMethodDecl *Method = 0;
+
+ CheckStaticCast(*this, Ex, DestType, OpRange, Kind, Method);
+
+ if (Method) {
+ OwningExprResult CastArg
+ = BuildCXXCastArgument(OpLoc, DestType.getNonReferenceType(),
+ Kind, Method, Owned(Ex));
+ if (CastArg.isInvalid())
+ return ExprError();
+
+ Ex = CastArg.takeAs<Expr>();
+ }
+ }
+
+ return Owned(new (Context) CXXStaticCastExpr(DestType.getNonReferenceType(),
+ Kind, Ex, DestType, OpLoc));
+ }
+ }
+
+ return ExprError();
+}
+
+/// 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<Qualifiers, 8> cv1, cv2;
+
+ // Find the qualifications.
+ while (Self.UnwrapSimilarPointerTypes(UnwrappedSrcType, UnwrappedDestType)) {
+ cv1.push_back(UnwrappedSrcType.getQualifiers());
+ cv2.push_back(UnwrappedDestType.getQualifiers());
+ }
+ 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;
+ ASTContext &Context = Self.Context;
+ for (llvm::SmallVector<Qualifiers, 8>::reverse_iterator i1 = cv1.rbegin(),
+ i2 = cv2.rbegin();
+ i1 != cv1.rend(); ++i1, ++i2) {
+ SrcConstruct
+ = Context.getPointerType(Context.getQualifiedType(SrcConstruct, *i1));
+ DestConstruct
+ = Context.getPointerType(Context.getQualifiedType(DestConstruct, *i2));
+ }
+
+ // Test if they're compatible.
+ return SrcConstruct != DestConstruct &&
+ !Self.IsQualificationConversion(SrcConstruct, DestConstruct);
+}
+
+/// CheckDynamicCast - Check that a dynamic_cast\<DestType\>(SrcExpr) is valid.
+/// Refer to C++ 5.2.7 for details. Dynamic casts are used mostly for runtime-
+/// checked downcasts in class hierarchies.
+static void
+CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
+ const SourceRange &OpRange,
+ const SourceRange &DestRange, CastExpr::CastKind &Kind) {
+ 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->getAs<PointerType>();
+ const ReferenceType *DestReference = DestType->getAs<ReferenceType>();
+ 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->getAs<RecordType>();
+ if (DestPointee->isVoidType()) {
+ assert(DestPointer && "Reference to void is not possible");
+ } else if (DestRecord) {
+ if (Self.RequireCompleteType(OpRange.getBegin(), DestPointee,
+ PDiag(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->getAs<PointerType>()) {
+ 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)
+ << CT_Dynamic << OrigSrcType << OrigDestType << OpRange;
+ }
+ SrcPointee = SrcType;
+ } else {
+ SrcPointee = SrcType;
+ }
+
+ const RecordType *SrcRecord = SrcPointee->getAs<RecordType>();
+ if (SrcRecord) {
+ if (Self.RequireCompleteType(OpRange.getBegin(), SrcPointee,
+ PDiag(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)
+ << CT_Dynamic << OrigSrcType << OrigDestType << 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);
+ Kind = CastExpr::CK_DerivedToBase;
+ // 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.
+ Kind = CastExpr::CK_Dynamic;
+}
+
+/// 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) {
+ if (!DestType->isLValueReferenceType())
+ Self.DefaultFunctionArrayConversion(SrcExpr);
+
+ unsigned msg = diag::err_bad_cxx_cast_generic;
+ if (TryConstCast(Self, SrcExpr, DestType, /*CStyle*/false, msg) != TC_Success
+ && msg != 0)
+ Self.Diag(OpRange.getBegin(), msg) << CT_Const
+ << SrcExpr->getType() << DestType << OpRange;
+}
+
+/// 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,
+ CastExpr::CastKind &Kind) {
+ if (!DestType->isLValueReferenceType())
+ Self.DefaultFunctionArrayConversion(SrcExpr);
+
+ unsigned msg = diag::err_bad_cxx_cast_generic;
+ if (TryReinterpretCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange,
+ msg, Kind)
+ != TC_Success && msg != 0)
+ Self.Diag(OpRange.getBegin(), msg) << CT_Reinterpret
+ << SrcExpr->getType() << DestType << OpRange;
+}
+
+
+/// 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, CastExpr::CastKind &Kind,
+ CXXMethodDecl *&ConversionDecl) {
+ // This test is outside everything else because it's the only case where
+ // a non-lvalue-reference target type does not lead to decay.
+ // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void".
+ if (DestType->isVoidType()) {
+ return;
+ }
+
+ if (!DestType->isLValueReferenceType())
+ Self.DefaultFunctionArrayConversion(SrcExpr);
+
+ unsigned msg = diag::err_bad_cxx_cast_generic;
+ if (TryStaticCast(Self, SrcExpr, DestType, /*CStyle*/false,OpRange, msg,
+ Kind, ConversionDecl)
+ != TC_Success && msg != 0)
+ Self.Diag(OpRange.getBegin(), msg) << CT_Static
+ << SrcExpr->getType() << DestType << OpRange;
+}
+
+/// TryStaticCast - Check if a static cast can be performed, and do so if
+/// possible. If @p CStyle, ignore access restrictions on hierarchy casting
+/// and casting away constness.
+static TryCastResult TryStaticCast(Sema &Self, Expr *SrcExpr,
+ QualType DestType, bool CStyle,
+ const SourceRange &OpRange, unsigned &msg,
+ CastExpr::CastKind &Kind,
+ CXXMethodDecl *&ConversionDecl) {
+ // 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.
+
+ // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void".
+ // Done outside this function.
+
+ TryCastResult tcr;
+
+ // C++ 5.2.9p5, reference downcast.
+ // See the function for details.
+ // DR 427 specifies that this is to be applied before paragraph 2.
+ tcr = TryStaticReferenceDowncast(Self, SrcExpr, DestType, CStyle,OpRange,msg);
+ if (tcr != TC_NotApplicable)
+ return tcr;
+
+ // 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".
+ tcr = TryLValueToRValueCast(Self, SrcExpr, DestType, msg);
+ if (tcr != TC_NotApplicable)
+ return tcr;
+
+ // C++ 5.2.9p2: An expression e can be explicitly converted to a type T
+ // [...] if the declaration "T t(e);" is well-formed, [...].
+ tcr = TryStaticImplicitCast(Self, SrcExpr, DestType, CStyle, OpRange, msg,
+ Kind, ConversionDecl);
+ if (tcr != TC_NotApplicable)
+ return tcr;
+
+ // 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.
+ // In the CStyle case, the earlier attempt to const_cast should have taken
+ // care of reverse qualification conversions.
+
+ QualType OrigSrcType = SrcExpr->getType();
+
+ 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 TC_Success;
+ }
+
+ // Reverse pointer upcast. C++ 4.10p3 specifies pointer upcast.
+ // C++ 5.2.9p8 additionally disallows a cast path through virtual inheritance.
+ tcr = TryStaticPointerDowncast(Self, SrcType, DestType, CStyle, OpRange, msg);
+ if (tcr != TC_NotApplicable)
+ return tcr;
+
+ // 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.
+ tcr = TryStaticMemberPointerUpcast(Self, SrcType, DestType, CStyle,
+ OpRange, msg);
+ if (tcr != TC_NotApplicable)
+ return tcr;
+
+ // 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->getAs<PointerType>()) {
+ QualType SrcPointee = SrcPointer->getPointeeType();
+ if (SrcPointee->isVoidType()) {
+ if (const PointerType *DestPointer = DestType->getAs<PointerType>()) {
+ QualType DestPointee = DestPointer->getPointeeType();
+ if (DestPointee->isIncompleteOrObjectType()) {
+ // This is definitely the intended conversion, but it might fail due
+ // to a const violation.
+ if (!CStyle && !DestPointee.isAtLeastAsQualifiedAs(SrcPointee)) {
+ msg = diag::err_bad_cxx_cast_const_away;
+ return TC_Failed;
+ }
+ return TC_Success;
+ }
+ }
+ }
+ }
+
+ // We tried everything. Everything! Nothing works! :-(
+ return TC_NotApplicable;
+}
+
+/// Tests whether a conversion according to N2844 is valid.
+TryCastResult
+TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType,
+ unsigned &msg) {
+ // 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->getAs<RValueReferenceType>();
+ if (!R)
+ return TC_NotApplicable;
+
+ if (SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid)
+ return TC_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.
+ // FIXME: Should allow casting away constness if CStyle.
+ bool DerivedToBase;
+ if (Self.CompareReferenceRelationship(SrcExpr->getType(), R->getPointeeType(),
+ DerivedToBase) <
+ Sema::Ref_Compatible_With_Added_Qualification) {
+ msg = diag::err_bad_lvalue_to_rvalue_cast;
+ return TC_Failed;
+ }
+
+ // FIXME: Similar to CheckReferenceInit, we actually need more AST annotation
+ // than nothing.
+ return TC_Success;
+}
+
+/// Tests whether a conversion according to C++ 5.2.9p5 is valid.
+TryCastResult
+TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr, QualType DestType,
+ bool CStyle, const SourceRange &OpRange,
+ unsigned &msg) {
+ // 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.
+
+ const ReferenceType *DestReference = DestType->getAs<ReferenceType>();
+ if (!DestReference) {
+ return TC_NotApplicable;
+ }
+ bool RValueRef = DestReference->isRValueReferenceType();
+ if (!RValueRef && SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid) {
+ // We know the left side is an lvalue reference, so we can suggest a reason.
+ msg = diag::err_bad_cxx_cast_rvalue;
+ return TC_NotApplicable;
+ }
+
+ QualType DestPointee = DestReference->getPointeeType();
+
+ return TryStaticDowncast(Self, SrcExpr->getType(), DestPointee, CStyle,
+ OpRange, SrcExpr->getType(), DestType, msg);
+}
+
+/// Tests whether a conversion according to C++ 5.2.9p8 is valid.
+TryCastResult
+TryStaticPointerDowncast(Sema &Self, QualType SrcType, QualType DestType,
+ bool CStyle, const SourceRange &OpRange,
+ unsigned &msg) {
+ // 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 *DestPointer = DestType->getAs<PointerType>();
+ if (!DestPointer) {
+ return TC_NotApplicable;
+ }
+
+ const PointerType *SrcPointer = SrcType->getAs<PointerType>();
+ if (!SrcPointer) {
+ msg = diag::err_bad_static_cast_pointer_nonpointer;
+ return TC_NotApplicable;
+ }
+
+ return TryStaticDowncast(Self, SrcPointer->getPointeeType(),
+ DestPointer->getPointeeType(), CStyle,
+ OpRange, SrcType, DestType, msg);
+}
+
+/// 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.
+TryCastResult
+TryStaticDowncast(Sema &Self, QualType SrcType, QualType DestType,
+ bool CStyle, const SourceRange &OpRange, QualType OrigSrcType,
+ QualType OrigDestType, unsigned &msg) {
+ // Downcast can only happen in class hierarchies, so we need classes.
+ if (!DestType->isRecordType() || !SrcType->isRecordType()) {
+ return TC_NotApplicable;
+ }
+
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/!CStyle,
+ /*DetectVirtual=*/true);
+ if (!Self.IsDerivedFrom(DestType, SrcType, Paths)) {
+ return TC_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, unless we're in C-style mode.
+ if (!CStyle && !DestType.isAtLeastAsQualifiedAs(SrcType)) {
+ msg = diag::err_bad_cxx_cast_const_away;
+ return TC_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.
+ if (!Paths.isRecordingPaths()) {
+ Paths.clear();
+ Paths.setRecordingPaths(true);
+ Self.IsDerivedFrom(DestType, SrcType, Paths);
+ }
+ std::string PathDisplayStr;
+ std::set<unsigned> DisplayedPaths;
+ for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end();
+ PI != PE; ++PI) {
+ if (DisplayedPaths.insert(PI->back().SubobjectNumber).second) {
+ // We haven't displayed a path to this particular base
+ // class subobject yet.
+ PathDisplayStr += "\n ";
+ for (CXXBasePath::const_reverse_iterator EI = PI->rbegin(),
+ EE = PI->rend();
+ EI != EE; ++EI)
+ PathDisplayStr += EI->Base->getType().getAsString() + " -> ";
+ PathDisplayStr += DestType.getAsString();
+ }
+ }
+
+ Self.Diag(OpRange.getBegin(), diag::err_ambiguous_base_to_derived_cast)
+ << SrcType.getUnqualifiedType() << DestType.getUnqualifiedType()
+ << PathDisplayStr << OpRange;
+ msg = 0;
+ return TC_Failed;
+ }
+
+ if (Paths.getDetectedVirtual() != 0) {
+ QualType VirtualBase(Paths.getDetectedVirtual(), 0);
+ Self.Diag(OpRange.getBegin(), diag::err_static_downcast_via_virtual)
+ << OrigSrcType << OrigDestType << VirtualBase << OpRange;
+ msg = 0;
+ return TC_Failed;
+ }
+
+ if (!CStyle && Self.CheckBaseClassAccess(DestType, SrcType,
+ diag::err_downcast_from_inaccessible_base, Paths,
+ OpRange.getBegin(), DeclarationName())) {
+ msg = 0;
+ return TC_Failed;
+ }
+
+ return TC_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 [...].
+///
+TryCastResult
+TryStaticMemberPointerUpcast(Sema &Self, QualType SrcType, QualType DestType,
+ bool CStyle, const SourceRange &OpRange,
+ unsigned &msg) {
+ const MemberPointerType *DestMemPtr = DestType->getAs<MemberPointerType>();
+ if (!DestMemPtr)
+ return TC_NotApplicable;
+ const MemberPointerType *SrcMemPtr = SrcType->getAs<MemberPointerType>();
+ if (!SrcMemPtr) {
+ msg = diag::err_bad_static_cast_member_pointer_nonmp;
+ return TC_NotApplicable;
+ }
+
+ // T == T, modulo cv
+ if (Self.Context.getCanonicalType(
+ SrcMemPtr->getPointeeType().getUnqualifiedType()) !=
+ Self.Context.getCanonicalType(DestMemPtr->getPointeeType().
+ getUnqualifiedType()))
+ return TC_NotApplicable;
+
+ // B base of D
+ QualType SrcClass(SrcMemPtr->getClass(), 0);
+ QualType DestClass(DestMemPtr->getClass(), 0);
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/!CStyle,
+ /*DetectVirtual=*/true);
+ if (!Self.IsDerivedFrom(SrcClass, DestClass, Paths)) {
+ return TC_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;
+ msg = 0;
+ return TC_Failed;
+ }
+
+ if (const RecordType *VBase = Paths.getDetectedVirtual()) {
+ Self.Diag(OpRange.getBegin(), diag::err_memptr_conv_via_virtual)
+ << SrcClass << DestClass << QualType(VBase, 0) << OpRange;
+ msg = 0;
+ return TC_Failed;
+ }
+
+ if (!CStyle && Self.CheckBaseClassAccess(DestType, SrcType,
+ diag::err_downcast_from_inaccessible_base, Paths,
+ OpRange.getBegin(), DeclarationName())) {
+ msg = 0;
+ return TC_Failed;
+ }
+
+ return TC_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 [...].
+TryCastResult
+TryStaticImplicitCast(Sema &Self, Expr *SrcExpr, QualType DestType,
+ bool CStyle, const SourceRange &OpRange, unsigned &msg,
+ CastExpr::CastKind &Kind,
+ CXXMethodDecl *&ConversionDecl) {
+ if (DestType->isRecordType()) {
+ if (Self.RequireCompleteType(OpRange.getBegin(), DestType,
+ diag::err_bad_dynamic_cast_incomplete)) {
+ msg = 0;
+ return TC_Failed;
+ }
+ }
+
+ 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.
+ // On the other hand, if we're checking a C-style cast, we've still got
+ // the reinterpret_cast way. In that case, we pass an ICS so we don't
+ // get error messages.
+ ImplicitConversionSequence ICS;
+ bool failed = Self.CheckReferenceInit(SrcExpr, DestType,
+ OpRange.getBegin(),
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false,
+ /*ForceRValue=*/false,
+ CStyle ? &ICS : 0);
+ if (!failed)
+ return TC_Success;
+ if (CStyle)
+ return TC_NotApplicable;
+ // If we didn't pass the ICS, we already got an error message.
+ msg = 0;
+ return TC_Failed;
+ }
+
+ // FIXME: To get a proper error from invalid conversions here, we need to
+ // reimplement more of this.
+ // FIXME: This does not actually perform the conversion, and thus does not
+ // check for ambiguity or access.
+ ImplicitConversionSequence ICS =
+ Self.TryImplicitConversion(SrcExpr, DestType,
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/true,
+ /*ForceRValue=*/false,
+ /*InOverloadResolution=*/false,
+ /*one of user provided casts*/true);
+
+ if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion)
+ return TC_NotApplicable;
+
+ if (ICS.ConversionKind == ImplicitConversionSequence::UserDefinedConversion) {
+ ConversionDecl = cast<CXXMethodDecl>(ICS.UserDefined.ConversionFunction);
+ if (isa<CXXConstructorDecl>(ConversionDecl))
+ Kind = CastExpr::CK_ConstructorConversion;
+ else if (isa<CXXConversionDecl>(ConversionDecl))
+ Kind = CastExpr::CK_UserDefinedConversion;
+ } else if (ICS.ConversionKind ==
+ ImplicitConversionSequence::StandardConversion) {
+ // FIXME: Set the cast kind depending on which types of conversions we have.
+ }
+
+ return TC_Success;
+}
+
+/// TryConstCast - See if a const_cast from source to destination is allowed,
+/// and perform it if it is.
+static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType,
+ bool CStyle, unsigned &msg) {
+ DestType = Self.Context.getCanonicalType(DestType);
+ QualType SrcType = SrcExpr->getType();
+ if (const LValueReferenceType *DestTypeTmp =
+ DestType->getAs<LValueReferenceType>()) {
+ if (SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid) {
+ // Cannot const_cast non-lvalue to lvalue reference type. But if this
+ // is C-style, static_cast might find a way, so we simply suggest a
+ // message and tell the parent to keep searching.
+ msg = diag::err_bad_cxx_cast_rvalue;
+ return TC_NotApplicable;
+ }
+
+ // 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);
+ }
+
+ // 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 [...]
+ if (!CStyle)
+ msg = diag::err_bad_const_cast_dest;
+ return TC_NotApplicable;
+ }
+ 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.
+ if (!CStyle)
+ msg = diag::err_bad_const_cast_dest;
+ return TC_NotApplicable;
+ }
+ 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();
+ }
+
+ // Since we're dealing in canonical types, the remainder must be the same.
+ if (SrcType != DestType)
+ return TC_NotApplicable;
+
+ return TC_Success;
+}
+
+static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr,
+ QualType DestType, bool CStyle,
+ const SourceRange &OpRange,
+ unsigned &msg,
+ CastExpr::CastKind &Kind) {
+ QualType OrigDestType = DestType, OrigSrcType = SrcExpr->getType();
+
+ DestType = Self.Context.getCanonicalType(DestType);
+ QualType SrcType = SrcExpr->getType();
+ if (const ReferenceType *DestTypeTmp = DestType->getAs<ReferenceType>()) {
+ bool LValue = DestTypeTmp->isLValueReferenceType();
+ if (LValue && SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid) {
+ // Cannot cast non-lvalue to reference type. See the similar comment in
+ // const_cast.
+ msg = diag::err_bad_cxx_cast_rvalue;
+ return TC_NotApplicable;
+ }
+
+ // 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);
+ }
+
+ // Canonicalize source for comparison.
+ SrcType = Self.Context.getCanonicalType(SrcType);
+
+ const MemberPointerType *DestMemPtr = DestType->getAs<MemberPointerType>(),
+ *SrcMemPtr = SrcType->getAs<MemberPointerType>();
+ 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())
+ return TC_NotApplicable;
+
+ // C++ 5.2.10p2: The reinterpret_cast operator shall not cast away
+ // constness.
+ // A reinterpret_cast followed by a const_cast can, though, so in C-style,
+ // we accept it.
+ if (!CStyle && CastsAwayConstness(Self, SrcType, DestType)) {
+ msg = diag::err_bad_cxx_cast_const_away;
+ return TC_Failed;
+ }
+
+ // A valid member pointer cast.
+ return TC_Success;
+ }
+
+ // 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)) {
+ msg = diag::err_bad_reinterpret_cast_small_int;
+ return TC_Failed;
+ }
+ Kind = CastExpr::CK_PointerToIntegral;
+ return TC_Success;
+ }
+
+ bool destIsVector = DestType->isVectorType();
+ bool srcIsVector = SrcType->isVectorType();
+ if (srcIsVector || destIsVector) {
+ bool srcIsScalar = SrcType->isIntegralType() && !SrcType->isEnumeralType();
+ bool destIsScalar =
+ DestType->isIntegralType() && !DestType->isEnumeralType();
+
+ // Check if this is a cast between a vector and something else.
+ if (!(srcIsScalar && destIsVector) && !(srcIsVector && destIsScalar) &&
+ !(srcIsVector && destIsVector))
+ return TC_NotApplicable;
+
+ // If both types have the same size, we can successfully cast.
+ if (Self.Context.getTypeSize(SrcType) == Self.Context.getTypeSize(DestType))
+ return TC_Success;
+
+ if (destIsScalar)
+ msg = diag::err_bad_cxx_cast_vector_to_scalar_different_size;
+ else if (srcIsScalar)
+ msg = diag::err_bad_cxx_cast_scalar_to_vector_different_size;
+ else
+ msg = diag::err_bad_cxx_cast_vector_to_vector_different_size;
+
+ return TC_Failed;
+ }
+
+ 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.
+ return TC_NotApplicable;
+ }
+
+ 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 TC_Success;
+ }
+
+ // 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)) {
+ msg = diag::err_bad_reinterpret_cast_small_int;
+ return TC_Failed;
+ }
+ Kind = CastExpr::CK_PointerToIntegral;
+ return TC_Success;
+ }
+
+ 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.
+ Kind = CastExpr::CK_IntegralToPointer;
+ return TC_Success;
+ }
+
+ if (!destIsPtr || !srcIsPtr) {
+ // With the valid non-pointer conversions out of the way, we can be even
+ // more stringent.
+ return TC_NotApplicable;
+ }
+
+ // C++ 5.2.10p2: The reinterpret_cast operator shall not cast away constness.
+ // The C-style cast operator can.
+ if (!CStyle && CastsAwayConstness(Self, SrcType, DestType)) {
+ msg = diag::err_bad_cxx_cast_const_away;
+ return TC_Failed;
+ }
+
+ // 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 TC_Success;
+ }
+
+ // 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_cast_fn_obj) << OpRange;
+ return TC_Success;
+ }
+
+ if (DestType->isFunctionPointerType()) {
+ // See above.
+ if (!Self.getLangOptions().CPlusPlus0x)
+ Self.Diag(OpRange.getBegin(), diag::ext_cast_fn_obj) << OpRange;
+ return TC_Success;
+ }
+
+ // 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.
+ Kind = CastExpr::CK_BitCast;
+ return TC_Success;
+}
+
+bool Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr,
+ CastExpr::CastKind &Kind, bool FunctionalStyle,
+ CXXMethodDecl *&ConversionDecl) {
+ // This test is outside everything else because it's the only case where
+ // a non-lvalue-reference target type does not lead to decay.
+ // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void".
+ if (CastTy->isVoidType())
+ return false;
+
+ // If the type is dependent, we won't do any other semantic analysis now.
+ if (CastTy->isDependentType() || CastExpr->isTypeDependent())
+ return false;
+
+ if (!CastTy->isLValueReferenceType())
+ DefaultFunctionArrayConversion(CastExpr);
+
+ // C++ [expr.cast]p5: The conversions performed by
+ // - a const_cast,
+ // - a static_cast,
+ // - a static_cast followed by a const_cast,
+ // - a reinterpret_cast, or
+ // - a reinterpret_cast followed by a const_cast,
+ // can be performed using the cast notation of explicit type conversion.
+ // [...] If a conversion can be interpreted in more than one of the ways
+ // listed above, the interpretation that appears first in the list is used,
+ // even if a cast resulting from that interpretation is ill-formed.
+ // In plain language, this means trying a const_cast ...
+ unsigned msg = diag::err_bad_cxx_cast_generic;
+ TryCastResult tcr = TryConstCast(*this, CastExpr, CastTy, /*CStyle*/true,
+ msg);
+ if (tcr == TC_NotApplicable) {
+ // ... or if that is not possible, a static_cast, ignoring const, ...
+ tcr = TryStaticCast(*this, CastExpr, CastTy, /*CStyle*/true, R, msg,
+ Kind, ConversionDecl);
+ if (tcr == TC_NotApplicable) {
+ // ... and finally a reinterpret_cast, ignoring const.
+ tcr = TryReinterpretCast(*this, CastExpr, CastTy, /*CStyle*/true, R, msg,
+ Kind);
+ }
+ }
+
+ if (tcr != TC_Success && msg != 0)
+ Diag(R.getBegin(), msg) << (FunctionalStyle ? CT_Functional : CT_CStyle)
+ << CastExpr->getType() << CastTy << R;
+
+ return tcr != TC_Success;
+}
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index a14bcd5..10c138c 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -14,26 +14,89 @@
#include "Sema.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/NestedNameSpecifier.h"
+#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Parse/DeclSpec.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
+/// \brief Compute the DeclContext that is associated with the given type.
+///
+/// \param T the type for which we are attempting to find a DeclContext.
+///
+/// \returns the declaration context represented by the type T,
+/// or NULL if the declaration context cannot be computed (e.g., because it is
+/// dependent and not the current instantiation).
+DeclContext *Sema::computeDeclContext(QualType T) {
+ if (const TagType *Tag = T->getAs<TagType>())
+ return Tag->getDecl();
+
+ return 0;
+}
+
/// \brief Compute the DeclContext that is associated with the given
/// scope specifier.
-DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS) {
+///
+/// \param SS the C++ scope specifier as it appears in the source
+///
+/// \param EnteringContext when true, we will be entering the context of
+/// this scope specifier, so we can retrieve the declaration context of a
+/// class template or class template partial specialization even if it is
+/// not the current instantiation.
+///
+/// \returns the declaration context represented by the scope specifier @p SS,
+/// or NULL if the declaration context cannot be computed (e.g., because it is
+/// dependent and not the current instantiation).
+DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS,
+ bool EnteringContext) {
if (!SS.isSet() || SS.isInvalid())
return 0;
- NestedNameSpecifier *NNS
+ 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;
+
+ if (EnteringContext) {
+ if (const TemplateSpecializationType *SpecType
+ = dyn_cast_or_null<TemplateSpecializationType>(NNS->getAsType())) {
+ // We are entering the context of the nested name specifier, so try to
+ // match the nested name specifier to either a primary class template
+ // or a class template partial specialization.
+ if (ClassTemplateDecl *ClassTemplate
+ = dyn_cast_or_null<ClassTemplateDecl>(
+ SpecType->getTemplateName().getAsTemplateDecl())) {
+ QualType ContextType
+ = Context.getCanonicalType(QualType(SpecType, 0));
+
+ // If the type of the nested name specifier is the same as the
+ // injected class name of the named class template, we're entering
+ // into that class template definition.
+ QualType Injected = ClassTemplate->getInjectedClassNameType(Context);
+ if (Context.hasSameType(Injected, ContextType))
+ return ClassTemplate->getTemplatedDecl();
+
+ // If the type of the nested name specifier is the same as the
+ // type of one of the class template's class template partial
+ // specializations, we're entering into the definition of that
+ // class template partial specialization.
+ if (ClassTemplatePartialSpecializationDecl *PartialSpec
+ = ClassTemplate->findPartialSpecialization(ContextType))
+ return PartialSpec;
+ }
+ } else if (const RecordType *RecordT
+ = dyn_cast_or_null<RecordType>(NNS->getAsType())) {
+ // The nested name specifier refers to a member of a class template.
+ return RecordT->getDecl();
+ }
+ }
+
+ return 0;
}
switch (NNS->getKind()) {
@@ -46,7 +109,7 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS) {
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate: {
- const TagType *Tag = NNS->getAsType()->getAsTagType();
+ const TagType *Tag = NNS->getAsType()->getAs<TagType>();
assert(Tag && "Non-tag type in nested-name-specifier");
return Tag->getDecl();
} break;
@@ -63,7 +126,7 @@ bool Sema::isDependentScopeSpecifier(const CXXScopeSpec &SS) {
if (!SS.isSet() || SS.isInvalid())
return false;
- NestedNameSpecifier *NNS
+ NestedNameSpecifier *NNS
= static_cast<NestedNameSpecifier *>(SS.getScopeRep());
return NNS->isDependent();
}
@@ -75,7 +138,7 @@ bool Sema::isUnknownSpecialization(const CXXScopeSpec &SS) {
if (!isDependentScopeSpecifier(SS))
return false;
- NestedNameSpecifier *NNS
+ NestedNameSpecifier *NNS
= static_cast<NestedNameSpecifier *>(SS.getScopeRep());
return getCurrentInstantiationOf(NNS) == 0;
}
@@ -89,6 +152,9 @@ CXXRecordDecl *Sema::getCurrentInstantiationOf(NestedNameSpecifier *NNS) {
assert(getLangOptions().CPlusPlus && "Only callable in C++");
assert(NNS->isDependent() && "Only dependent nested-name-specifier allowed");
+ if (!NNS->getAsType())
+ return 0;
+
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.
@@ -108,7 +174,7 @@ CXXRecordDecl *Sema::getCurrentInstantiationOf(NestedNameSpecifier *NNS) {
if (!Record)
continue;
- // If this record type is not dependent,
+ // If this record type is not dependent,
if (!Record->isDependentType())
return 0;
@@ -126,27 +192,29 @@ CXXRecordDecl *Sema::getCurrentInstantiationOf(NestedNameSpecifier *NNS) {
// 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
+ // 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)
+ // pattern is the name of the parameter pack.
+ // (FIXME: parameter packs)
//
// 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)
+ if (Context.getCanonicalType(Context.getTypeDeclType(Record)) == T)
return Record;
-
+
if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate()) {
- QualType InjectedClassName
+ QualType InjectedClassName
= Template->getInjectedClassNameType(Context);
if (T == Context.getCanonicalType(InjectedClassName))
return Template->getTemplatedDecl();
}
+ // FIXME: check for class template partial specializations
}
return 0;
@@ -164,20 +232,20 @@ CXXRecordDecl *Sema::getCurrentInstantiationOf(NestedNameSpecifier *NNS) {
bool Sema::RequireCompleteDeclContext(const CXXScopeSpec &SS) {
if (!SS.isSet() || SS.isInvalid())
return false;
-
- DeclContext *DC = computeDeclContext(SS);
+
+ DeclContext *DC = computeDeclContext(SS, true);
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();
+ const TagType *TagT = Context.getTypeDeclType(Tag)->getAs<TagType>();
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());
+ PDiag(diag::err_incomplete_nested_name_spec)
+ << SS.getRange());
}
return false;
@@ -190,72 +258,222 @@ Sema::CXXScopeTy *Sema::ActOnCXXGlobalScopeSpecifier(Scope *S,
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,
+/// \brief Determines whether the given declaration is an valid acceptable
+/// result for name lookup of a nested-name-specifier.
+bool Sema::isAcceptableNestedNameSpecifier(NamedDecl *SD) {
+ if (!SD)
+ return false;
+
+ // Namespace and namespace aliases are fine.
+ if (isa<NamespaceDecl>(SD) || isa<NamespaceAliasDecl>(SD))
+ return true;
+
+ if (!isa<TypeDecl>(SD))
+ return false;
+
+ // 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(cast<TypeDecl>(SD));
+ if (T->isDependentType())
+ return true;
+ else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
+ if (TD->getUnderlyingType()->isRecordType() ||
+ (Context.getLangOptions().CPlusPlus0x &&
+ TD->getUnderlyingType()->isEnumeralType()))
+ return true;
+ } else if (isa<RecordDecl>(SD) ||
+ (Context.getLangOptions().CPlusPlus0x && isa<EnumDecl>(SD)))
+ return true;
+
+ return false;
+}
+
+/// \brief If the given nested-name-specifier begins with a bare identifier
+/// (e.g., Base::), perform name lookup for that identifier as a
+/// nested-name-specifier within the given scope, and return the result of that
+/// name lookup.
+NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) {
+ if (!S || !NNS)
+ return 0;
+
+ while (NNS->getPrefix())
+ NNS = NNS->getPrefix();
+
+ if (NNS->getKind() != NestedNameSpecifier::Identifier)
+ return 0;
+
+ LookupResult Found;
+ LookupName(Found, S, NNS->getAsIdentifier(), LookupNestedNameSpecifierName);
+ assert(!Found.isAmbiguous() && "Cannot handle ambiguities here yet");
+
+ NamedDecl *Result = Found.getAsSingleDecl(Context);
+ if (isAcceptableNestedNameSpecifier(Result))
+ return Result;
+
+ return 0;
+}
+
+/// \brief Build a new nested-name-specifier for "identifier::", as described
+/// by ActOnCXXNestedNameSpecifier.
+///
+/// This routine differs only slightly from ActOnCXXNestedNameSpecifier, in
+/// that it contains an extra parameter \p ScopeLookupResult, which provides
+/// the result of name lookup within the scope of the nested-name-specifier
+/// that was computed at template definitino time.
+Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
const CXXScopeSpec &SS,
SourceLocation IdLoc,
SourceLocation CCLoc,
- IdentifierInfo &II) {
- NestedNameSpecifier *Prefix
+ IdentifierInfo &II,
+ QualType ObjectType,
+ NamedDecl *ScopeLookupResult,
+ bool EnteringContext) {
+ 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))
+ // Determine where to perform name lookup
+ DeclContext *LookupCtx = 0;
+ bool isDependent = false;
+ if (!ObjectType.isNull()) {
+ // This nested-name-specifier occurs in a member access expression, e.g.,
+ // x->B::f, and we are looking into the type of the object.
+ assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist");
+ LookupCtx = computeDeclContext(ObjectType);
+ isDependent = ObjectType->isDependentType();
+ } else if (SS.isSet()) {
+ // This nested-name-specifier occurs after another nested-name-specifier,
+ // so long into the context associated with the prior nested-name-specifier.
+ LookupCtx = computeDeclContext(SS, EnteringContext);
+ isDependent = isDependentScopeSpecifier(SS);
+ }
+
+ LookupResult Found;
+ bool ObjectTypeSearchedInScope = false;
+ if (LookupCtx) {
+ // Perform "qualified" name lookup into the declaration context we
+ // computed, which is either the type of the base of a member access
+ // expression or the declaration context associated with a prior
+ // nested-name-specifier.
+
+ // The declaration context must be complete.
+ if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(SS))
+ return 0;
+
+ LookupQualifiedName(Found, LookupCtx, &II, LookupNestedNameSpecifierName,
+ false);
+
+ if (!ObjectType.isNull() && Found.getKind() == LookupResult::NotFound) {
+ // C++ [basic.lookup.classref]p4:
+ // If the id-expression in a class member access is a qualified-id of
+ // the form
+ //
+ // class-name-or-namespace-name::...
+ //
+ // the class-name-or-namespace-name following the . or -> operator is
+ // looked up both in the context of the entire postfix-expression and in
+ // the scope of the class of the object expression. If the name is found
+ // only in the scope of the class of the object expression, the name
+ // shall refer to a class-name. If the name is found only in the
+ // context of the entire postfix-expression, the name shall refer to a
+ // class-name or namespace-name. [...]
+ //
+ // Qualified name lookup into a class will not find a namespace-name,
+ // so we do not need to diagnoste that case specifically. However,
+ // this qualified name lookup may find nothing. In that case, perform
+ // unqualified name lookup in the given scope (if available) or
+ // reconstruct the result from when name lookup was performed at template
+ // definition time.
+ if (S)
+ LookupName(Found, S, &II, LookupNestedNameSpecifierName);
+ else if (ScopeLookupResult)
+ Found.addDecl(ScopeLookupResult);
+
+ ObjectTypeSearchedInScope = true;
+ }
+ } else if (isDependent) {
+ // We were not able to compute the declaration context for a dependent
+ // base object type or prior nested-name-specifier, so this
+ // nested-name-specifier refers to an unknown specialization. Just build
+ // a dependent nested-name-specifier.
+ if (!Prefix)
+ return NestedNameSpecifier::Create(Context, &II);
+
return NestedNameSpecifier::Create(Context, Prefix, &II);
+ } else {
+ // Perform unqualified name lookup in the current scope.
+ LookupName(Found, S, &II, LookupNestedNameSpecifierName);
+ }
- NamedDecl *SD = LookupParsedName(S, &SS, &II, LookupNestedNameSpecifierName);
+ // FIXME: Deal with ambiguities cleanly.
+ NamedDecl *SD = Found.getAsSingleDecl(Context);
+ if (isAcceptableNestedNameSpecifier(SD)) {
+ if (!ObjectType.isNull() && !ObjectTypeSearchedInScope) {
+ // C++ [basic.lookup.classref]p4:
+ // [...] If the name is found in both contexts, the
+ // class-name-or-namespace-name shall refer to the same entity.
+ //
+ // We already found the name in the scope of the object. Now, look
+ // into the current scope (the scope of the postfix-expression) to
+ // see if we can find the same name there. As above, if there is no
+ // scope, reconstruct the result from the template instantiation itself.
+ NamedDecl *OuterDecl;
+ if (S) {
+ LookupResult FoundOuter;
+ LookupName(FoundOuter, S, &II, LookupNestedNameSpecifierName);
+ // FIXME: Handle ambiguities!
+ OuterDecl = FoundOuter.getAsSingleDecl(Context);
+ } else
+ OuterDecl = ScopeLookupResult;
+
+ if (isAcceptableNestedNameSpecifier(OuterDecl) &&
+ OuterDecl->getCanonicalDecl() != SD->getCanonicalDecl() &&
+ (!isa<TypeDecl>(OuterDecl) || !isa<TypeDecl>(SD) ||
+ !Context.hasSameType(
+ Context.getTypeDeclType(cast<TypeDecl>(OuterDecl)),
+ Context.getTypeDeclType(cast<TypeDecl>(SD))))) {
+ Diag(IdLoc, diag::err_nested_name_member_ref_lookup_ambiguous)
+ << &II;
+ Diag(SD->getLocation(), diag::note_ambig_member_ref_object_type)
+ << ObjectType;
+ Diag(OuterDecl->getLocation(), diag::note_ambig_member_ref_scope);
+
+ // Fall through so that we'll pick the name we found in the object type,
+ // since that's probably what the user wanted anyway.
+ }
+ }
- 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());
- }
-
+ // FIXME: It would be nice to maintain the namespace alias name, then
+ // see through that alias when resolving the nested-name-specifier down to
+ // a declaration context.
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.
+ QualType T = Context.getTypeDeclType(cast<TypeDecl>(SD));
+ return NestedNameSpecifier::Create(Context, Prefix, false,
+ T.getTypePtr());
}
// 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);
+ if (!SD) {
+ Found.clear();
+ LookupName(Found, S, &II, LookupOrdinaryName);
+ SD = Found.getAsSingleDecl(Context);
+ }
+
unsigned DiagID;
if (SD)
DiagID = diag::err_expected_class_or_namespace;
- else if (SS.isSet())
- DiagID = diag::err_typecheck_no_member;
- else
+ else if (SS.isSet()) {
+ Diag(IdLoc, diag::err_no_member) << &II << LookupCtx << SS.getRange();
+ return 0;
+ } else
DiagID = diag::err_undeclared_var_use;
if (SS.isSet())
@@ -266,14 +484,32 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
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.
+Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
+ const CXXScopeSpec &SS,
+ SourceLocation IdLoc,
+ SourceLocation CCLoc,
+ IdentifierInfo &II,
+ TypeTy *ObjectTypePtr,
+ bool EnteringContext) {
+ return BuildCXXNestedNameSpecifier(S, SS, IdLoc, CCLoc, II,
+ QualType::getFromOpaquePtr(ObjectTypePtr),
+ /*ScopeLookupResult=*/0, EnteringContext);
+}
+
Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
const CXXScopeSpec &SS,
TypeTy *Ty,
SourceRange TypeRange,
SourceLocation CCLoc) {
- NestedNameSpecifier *Prefix
+ NestedNameSpecifier *Prefix
= static_cast<NestedNameSpecifier *>(SS.getScopeRep());
- QualType T = QualType::getFromOpaquePtr(Ty);
+ QualType T = GetTypeFromParser(Ty);
return NestedNameSpecifier::Create(Context, Prefix, /*FIXME:*/false,
T.getTypePtr());
}
@@ -284,9 +520,18 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
/// 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) {
+bool Sema::ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
assert(SS.isSet() && "Parser passed invalid CXXScopeSpec.");
- EnterDeclaratorContext(S, computeDeclContext(SS));
+ if (DeclContext *DC = computeDeclContext(SS, true)) {
+ // Before we enter a declarator's context, we need to make sure that
+ // it is a complete declaration context.
+ if (!DC->isDependentContext() && RequireCompleteDeclContext(SS))
+ return true;
+
+ EnterDeclaratorContext(S, DC);
+ }
+
+ return false;
}
/// ActOnCXXExitDeclaratorScope - Called when a declarator that previously
@@ -296,6 +541,8 @@ void Sema::ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
/// defining scope.
void Sema::ActOnCXXExitDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
assert(SS.isSet() && "Parser passed invalid CXXScopeSpec.");
- assert(S->getEntity() == computeDeclContext(SS) && "Context imbalance!");
- ExitDeclaratorContext(S);
+ if (SS.isInvalid())
+ return;
+ if (computeDeclContext(SS, true))
+ ExitDeclaratorContext(S);
}
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 4eed018..92bf83f 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This file implements extra semantic analysis beyond what is enforced
+// This file implements extra semantic analysis beyond what is enforced
// by the C type system.
//
//===----------------------------------------------------------------------===//
@@ -32,14 +32,14 @@ using namespace clang;
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.
@@ -51,65 +51,71 @@ SourceLocation Sema::getLocationOfStringLiteralByte(const StringLiteral *SL,
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 =
+ 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;
}
}
+/// CheckablePrintfAttr - does a function call have a "printf" attribute
+/// and arguments that merit checking?
+bool Sema::CheckablePrintfAttr(const FormatAttr *Format, CallExpr *TheCall) {
+ if (Format->getType() == "printf") return true;
+ if (Format->getType() == "printf0") {
+ // printf0 allows null "format" string; if so don't check format/args
+ unsigned format_idx = Format->getFormatIdx() - 1;
+ if (format_idx < TheCall->getNumArgs()) {
+ Expr *Format = TheCall->getArg(format_idx)->IgnoreParenCasts();
+ if (!Format->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull))
+ return true;
+ }
+ }
+ return false;
+}
-/// 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) {
+Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, 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)) {
+ switch (BuiltinID) {
case Builtin::BI__builtin___CFStringMakeConstantString:
assert(TheCall->getNumArgs() == 1 &&
"Wrong # arguments to builtin CFStringMakeConstantString");
if (CheckObjCString(TheCall->getArg(0)))
return ExprError();
- return move(TheCallResult);
+ break;
case Builtin::BI__builtin_stdarg_start:
case Builtin::BI__builtin_va_start:
if (SemaBuiltinVAStart(TheCall))
return ExprError();
- return move(TheCallResult);
+ break;
case Builtin::BI__builtin_isgreater:
case Builtin::BI__builtin_isgreaterequal:
case Builtin::BI__builtin_isless:
@@ -118,12 +124,24 @@ Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
case Builtin::BI__builtin_isunordered:
if (SemaBuiltinUnorderedCompare(TheCall))
return ExprError();
- return move(TheCallResult);
+ break;
+ case Builtin::BI__builtin_isfinite:
+ case Builtin::BI__builtin_isinf:
+ case Builtin::BI__builtin_isinf_sign:
+ case Builtin::BI__builtin_isnan:
+ case Builtin::BI__builtin_isnormal:
+ if (SemaBuiltinUnaryFP(TheCall))
+ return ExprError();
+ break;
case Builtin::BI__builtin_return_address:
case Builtin::BI__builtin_frame_address:
if (SemaBuiltinStackAddress(TheCall))
return ExprError();
- return move(TheCallResult);
+ break;
+ case Builtin::BI__builtin_eh_return_data_regno:
+ if (SemaBuiltinEHReturnDataRegNo(TheCall))
+ return ExprError();
+ break;
case Builtin::BI__builtin_shufflevector:
return SemaBuiltinShuffleVector(TheCall);
// TheCall will be freed by the smart pointer here, but that's fine, since
@@ -131,15 +149,15 @@ Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
case Builtin::BI__builtin_prefetch:
if (SemaBuiltinPrefetch(TheCall))
return ExprError();
- return move(TheCallResult);
+ break;
case Builtin::BI__builtin_object_size:
if (SemaBuiltinObjectSize(TheCall))
return ExprError();
- return move(TheCallResult);
+ break;
case Builtin::BI__builtin_longjmp:
if (SemaBuiltinLongjmp(TheCall))
return ExprError();
- return move(TheCallResult);
+ break;
case Builtin::BI__sync_fetch_and_add:
case Builtin::BI__sync_fetch_and_sub:
case Builtin::BI__sync_fetch_and_or:
@@ -158,61 +176,76 @@ Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
case Builtin::BI__sync_lock_release:
if (SemaBuiltinAtomicOverloaded(TheCall))
return ExprError();
- return move(TheCallResult);
+ break;
}
+ return move(TheCallResult);
+}
+
+/// CheckFunctionCall - Check a direct function call for various correctness
+/// and safety properties not strictly enforced by the C type system.
+bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *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 false;
+
// 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") {
+ if (CheckablePrintfAttr(Format, TheCall)) {
bool HasVAListArg = Format->getFirstArg() == 0;
if (!HasVAListArg) {
- if (const FunctionProtoType *Proto
- = FDecl->getType()->getAsFunctionProtoType())
+ if (const FunctionProtoType *Proto
+ = FDecl->getType()->getAs<FunctionProtoType>())
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);
-}
+ for (const NonNullAttr *NonNull = FDecl->getAttr<NonNullAttr>(); NonNull;
+ NonNull = NonNull->getNext<NonNullAttr>())
+ CheckNonNullArguments(NonNull, TheCall);
-Action::OwningExprResult
-Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall) {
+ return false;
+}
- OwningExprResult TheCallResult(Owned(TheCall));
+bool Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall) {
// Printf checking.
const FormatAttr *Format = NDecl->getAttr<FormatAttr>();
if (!Format)
- return move(TheCallResult);
+ return false;
+
const VarDecl *V = dyn_cast<VarDecl>(NDecl);
if (!V)
- return move(TheCallResult);
+ return false;
+
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 false;
+
+ if (!CheckablePrintfAttr(Format, TheCall))
+ return false;
+
+ bool HasVAListArg = Format->getFirstArg() == 0;
+ if (!HasVAListArg) {
+ const FunctionType *FT =
+ Ty->getAs<BlockPointerType>()->getPointeeType()->getAs<FunctionType>();
+ if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT))
+ HasVAListArg = !Proto->isVariadic();
}
- return move(TheCallResult);
+ CheckPrintfArguments(TheCall, HasVAListArg, Format->getFormatIdx() - 1,
+ HasVAListArg ? 0 : Format->getFirstArg() - 1);
+
+ return false;
}
/// SemaBuiltinAtomicOverloaded - We have a call to a function like
@@ -231,7 +264,7 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) {
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
@@ -240,9 +273,9 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) {
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() &&
+
+ QualType ValType = FirstArg->getType()->getAs<PointerType>()->getPointeeType();
+ if (!ValType->isIntegerType() && !ValType->isPointerType() &&
!ValType->isBlockPointerType())
return Diag(DRE->getLocStart(),
diag::err_atomic_builtin_must_be_pointer_intptr)
@@ -254,7 +287,7 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) {
#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),
@@ -262,21 +295,21 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) {
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
-
+#undef BUILTIN_ROW
+
// Determine the index of the size.
unsigned SizeIndex;
switch (Context.getTypeSize(ValType)/8) {
@@ -289,12 +322,12 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) {
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 BuiltinID = FDecl->getBuiltinID();
unsigned BuiltinIndex, NumFixed = 1;
switch (BuiltinID) {
default: assert(0 && "Unknown overloaded atomic builtin!");
@@ -304,14 +337,14 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) {
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;
@@ -326,36 +359,37 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) {
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 =
+ FunctionDecl *NewBuiltinDecl =
cast<FunctionDecl>(LazilyCreateBuiltin(NewBuiltinII, NewBuiltinID,
TUScope, false, DRE->getLocStart()));
const FunctionProtoType *BuiltinFT =
- NewBuiltinDecl->getType()->getAsFunctionProtoType();
- ValType = BuiltinFT->getArgType(0)->getAsPointerType()->getPointeeType();
-
+ NewBuiltinDecl->getType()->getAs<FunctionProtoType>();
+ ValType = BuiltinFT->getArgType(0)->getAs<PointerType>()->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);
+ ImpCastExprToType(FirstArg, BuiltinFT->getArgType(0), CastExpr::CK_Unknown,
+ /*isLvalue=*/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)) {
@@ -364,32 +398,35 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) {
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))
+ CastExpr::CastKind Kind = CastExpr::CK_Unknown;
+ CXXMethodDecl *ConversionDecl = 0;
+ if (CheckCastTypes(Arg->getSourceRange(), ValType, Arg, Kind,
+ ConversionDecl))
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);
+ // FIXME: Do this check.
+ ImpCastExprToType(Arg, ValType, Kind, /*isLvalue=*/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());
@@ -400,7 +437,7 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) {
/// 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
+/// "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).
@@ -413,10 +450,10 @@ bool Sema::CheckObjCString(Expr *Arg) {
<< 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),
@@ -425,7 +462,7 @@ bool Sema::CheckObjCString(Expr *Arg) {
break;
}
}
-
+
return false;
}
@@ -437,7 +474,7 @@ bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) {
Diag(TheCall->getArg(2)->getLocStart(),
diag::err_typecheck_call_too_many_args)
<< 0 /*function call*/ << Fn->getSourceRange()
- << SourceRange(TheCall->getArg(2)->getLocStart(),
+ << SourceRange(TheCall->getArg(2)->getLocStart(),
(*(TheCall->arg_end()-1))->getLocEnd());
return true;
}
@@ -460,17 +497,17 @@ bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) {
} 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).
@@ -485,9 +522,9 @@ bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) {
SecondArgIsLastNamedArgument = PV == LastArg;
}
}
-
+
if (!SecondArgIsLastNamedArgument)
- Diag(TheCall->getArg(1)->getLocStart(),
+ Diag(TheCall->getArg(1)->getLocStart(),
diag::warn_second_parameter_of_va_start_not_last_named_argument);
return false;
}
@@ -499,12 +536,12 @@ bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall) {
return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args)
<< 0 /*function call*/;
if (TheCall->getNumArgs() > 2)
- return Diag(TheCall->getArg(2)->getLocStart(),
+ 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);
@@ -517,18 +554,45 @@ bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall) {
// 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(),
+ return Diag(OrigArg0->getLocStart(),
diag::err_typecheck_call_invalid_ordered_compare)
<< OrigArg0->getType() << OrigArg1->getType()
<< SourceRange(OrigArg0->getLocStart(), OrigArg1->getLocEnd());
-
+
+ return false;
+}
+
+/// SemaBuiltinUnorderedCompare - Handle functions like __builtin_isnan and
+/// friends. This is declared to take (...), so we have to check everything.
+bool Sema::SemaBuiltinUnaryFP(CallExpr *TheCall) {
+ if (TheCall->getNumArgs() < 1)
+ return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args)
+ << 0 /*function call*/;
+ if (TheCall->getNumArgs() > 1)
+ return Diag(TheCall->getArg(1)->getLocStart(),
+ diag::err_typecheck_call_too_many_args)
+ << 0 /*function call*/
+ << SourceRange(TheCall->getArg(1)->getLocStart(),
+ (*(TheCall->arg_end()-1))->getLocEnd());
+
+ Expr *OrigArg = TheCall->getArg(0);
+
+ if (OrigArg->isTypeDependent())
+ return false;
+
+ // This operation requires a floating-point number
+ if (!OrigArg->getType()->isRealFloatingType())
+ return Diag(OrigArg->getLocStart(),
+ diag::err_typecheck_call_invalid_unary_fp)
+ << OrigArg->getType() << OrigArg->getSourceRange();
+
return false;
}
@@ -540,7 +604,7 @@ bool Sema::SemaBuiltinStackAddress(CallExpr *TheCall) {
!TheCall->getArg(0)->isValueDependent() &&
!TheCall->getArg(0)->isIntegerConstantExpr(Context, &Loc))
return Diag(Loc, diag::err_stack_const_level) << TheCall->getSourceRange();
-
+
return false;
}
@@ -557,23 +621,23 @@ Action::OwningExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
!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(),
+ << 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(),
+ << SourceRange(TheCall->getArg(0)->getLocStart(),
TheCall->getArg(1)->getLocEnd());
return ExprError();
}
- numElements = FAType->getAsVectorType()->getNumElements();
+ numElements = FAType->getAs<VectorType>()->getNumElements();
if (TheCall->getNumArgs() != numElements+2) {
if (TheCall->getNumArgs() < numElements+2)
return ExprError(Diag(TheCall->getLocEnd(),
@@ -609,8 +673,8 @@ Action::OwningExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
TheCall->setArg(i, 0);
}
- return Owned(new (Context) ShuffleVectorExpr(exprs.begin(), exprs.size(),
- exprs[0]->getType(),
+ return Owned(new (Context) ShuffleVectorExpr(Context, exprs.begin(),
+ exprs.size(), exprs[0]->getType(),
TheCall->getCallee()->getLocStart(),
TheCall->getRParenLoc()));
}
@@ -634,11 +698,11 @@ bool Sema::SemaBuiltinPrefetch(CallExpr *TheCall) {
QualType RWType = Arg->getType();
- const BuiltinType *BT = RWType->getAsBuiltinType();
+ const BuiltinType *BT = RWType->getAs<BuiltinType>();
llvm::APSInt Result;
if (!BT || BT->getKind() != BuiltinType::Int)
return Diag(TheCall->getLocStart(), diag::err_prefetch_invalid_argument)
- << SourceRange(Arg->getLocStart(), Arg->getLocEnd());
+ << Arg->getSourceRange();
if (Arg->isValueDependent())
continue;
@@ -646,24 +710,36 @@ bool Sema::SemaBuiltinPrefetch(CallExpr *TheCall) {
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());
+ << "0" << "1" << Arg->getSourceRange();
} else {
if (Result.getSExtValue() < 0 || Result.getSExtValue() > 3)
return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range)
- << "0" << "3" << SourceRange(Arg->getLocStart(), Arg->getLocEnd());
+ << "0" << "3" << Arg->getSourceRange();
}
}
return false;
}
+/// SemaBuiltinEHReturnDataRegNo - Handle __builtin_eh_return_data_regno, the
+/// operand must be an integer constant.
+bool Sema::SemaBuiltinEHReturnDataRegNo(CallExpr *TheCall) {
+ llvm::APSInt Result;
+ if (!TheCall->getArg(0)->isIntegerConstantExpr(Result, Context))
+ return Diag(TheCall->getLocStart(), diag::err_expr_not_ice)
+ << TheCall->getArg(0)->getSourceRange();
+
+ 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).
@@ -672,8 +748,8 @@ bool Sema::SemaBuiltinObjectSize(CallExpr *TheCall) {
if (Arg->isTypeDependent())
return false;
- QualType ArgType = Arg->getType();
- const BuiltinType *BT = ArgType->getAsBuiltinType();
+ QualType ArgType = Arg->getType();
+ const BuiltinType *BT = ArgType->getAs<BuiltinType>();
llvm::APSInt Result(32);
if (!BT || BT->getKind() != BuiltinType::Int)
return Diag(TheCall->getLocStart(), diag::err_object_size_invalid_argument)
@@ -737,10 +813,10 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall,
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())) {
@@ -749,19 +825,18 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall,
if (const ArrayType *AT = Context.getAsArrayType(T)) {
isConstant = AT->getElementType().isConstant(Context);
- }
- else if (const PointerType *PT = T->getAsPointerType()) {
- isConstant = T.isConstant(Context) &&
+ } else if (const PointerType *PT = T->getAs<PointerType>()) {
+ 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);
}
-
+
// 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
@@ -784,66 +859,67 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall,
if (isa<ParmVarDecl>(VD))
return true;
}
-
+
return false;
}
case Stmt::CallExprClass: {
const CallExpr *CE = cast<CallExpr>(E);
- if (const ImplicitCastExpr *ICE
+ if (const ImplicitCastExpr *ICE
= dyn_cast<ImplicitCastExpr>(CE->getCallee())) {
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ICE->getSubExpr())) {
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(DRE->getDecl())) {
if (const FormatArgAttr *FA = FD->getAttr<FormatArgAttr>()) {
unsigned ArgIndex = FA->getFormatIdx();
const Expr *Arg = CE->getArg(ArgIndex - 1);
-
- return SemaCheckStringLiteral(Arg, TheCall, HasVAListArg,
+
+ return SemaCheckStringLiteral(Arg, 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,
+ CheckPrintfString(StrE, E, TheCall, HasVAListArg, format_idx,
firstDataArg);
return true;
}
-
+
return false;
}
-
+
default:
return false;
}
}
void
-Sema::CheckNonNullArguments(const NonNullAttr *NonNull, const CallExpr *TheCall)
-{
+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))
+ if (ArgExpr->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNotNull))
Diag(TheCall->getCallee()->getLocStart(), diag::warn_null_arg)
<< ArgExpr->getSourceRange();
}
}
/// CheckPrintfArguments - Check calls to printf (and similar functions) for
-/// correct use of format strings.
+/// correct use of format strings.
///
/// HasVAListArg - A predicate indicating whether the printf-like
/// function is passed an explicit va_arg argument (e.g., vprintf)
@@ -892,30 +968,30 @@ Sema::CheckNonNullArguments(const NonNullAttr *NonNull, const CallExpr *TheCall)
///
/// For now, we ONLY do (1), (3), (5), (6), (7), and (8).
void
-Sema::CheckPrintfArguments(const CallExpr *TheCall, bool HasVAListArg,
+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.
+ // 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
+ // 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
+ // 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))
@@ -924,11 +1000,11 @@ Sema::CheckPrintfArguments(const CallExpr *TheCall, bool HasVAListArg,
// 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(TheCall->getArg(format_idx)->getLocStart(),
diag::warn_printf_nonliteral_noargs)
<< OrigFormatExpr->getSourceRange();
else
- Diag(TheCall->getArg(format_idx)->getLocStart(),
+ Diag(TheCall->getArg(format_idx)->getLocStart(),
diag::warn_printf_nonliteral)
<< OrigFormatExpr->getSourceRange();
}
@@ -954,7 +1030,7 @@ void Sema::CheckPrintfString(const StringLiteral *FExpr,
// CHECK: empty format string?
unsigned StrLen = FExpr->getByteLength();
-
+
if (StrLen == 0) {
Diag(FExpr->getLocStart(), diag::warn_printf_empty_format_string)
<< OrigFormatExpr->getSourceRange();
@@ -967,7 +1043,7 @@ void Sema::CheckPrintfString(const StringLiteral *FExpr,
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;
@@ -980,17 +1056,17 @@ void Sema::CheckPrintfString(const StringLiteral *FExpr,
// 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,
@@ -1000,7 +1076,7 @@ void Sema::CheckPrintfString(const StringLiteral *FExpr,
<< OrigFormatExpr->getSourceRange();
return;
}
-
+
// Ordinary characters (not processing a format conversion).
if (CurrentState == state_OrdChr) {
if (Str[StrIdx] == '%') {
@@ -1012,10 +1088,10 @@ void Sema::CheckPrintfString(const StringLiteral *FExpr,
// Seen '%'. Now processing a format conversion.
switch (Str[StrIdx]) {
- // Handle dynamic precision or width specifier.
+ // Handle dynamic precision or width specifier.
case '*': {
++numConversions;
-
+
if (!HasVAListArg) {
if (numConversions > numDataArgs) {
SourceLocation Loc = getLocationOfStringLiteralByte(FExpr, StrIdx);
@@ -1026,39 +1102,39 @@ void Sema::CheckPrintfString(const StringLiteral *FExpr,
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 (const BuiltinType *BT = E->getType()->getAs<BuiltinType>())
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;
+
+ 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.
+ // FIXME: additional checks will go into the following cases.
case 'i':
case 'd':
- case 'o':
- case 'u':
+ case 'o':
+ case 'u':
case 'x':
case 'X':
case 'D':
@@ -1076,7 +1152,7 @@ void Sema::CheckPrintfString(const StringLiteral *FExpr,
case 'C':
case 'S':
case 's':
- case 'p':
+ case 'p':
++numConversions;
CurrentState = state_OrdChr;
break;
@@ -1092,21 +1168,21 @@ void Sema::CheckPrintfString(const StringLiteral *FExpr,
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;
+ if (ObjCFExpr != NULL)
+ CurrentState = state_OrdChr;
else {
// Issue a warning: invalid format conversion.
- SourceLocation Loc =
+ SourceLocation Loc =
getLocationOfStringLiteralByte(FExpr, LastConversionIdx);
-
+
Diag(Loc, diag::warn_printf_invalid_conversion)
<< std::string(Str+LastConversionIdx,
Str+std::min(LastConversionIdx+2, StrLen))
@@ -1114,7 +1190,7 @@ void Sema::CheckPrintfString(const StringLiteral *FExpr,
}
++numConversions;
break;
-
+
// Handle "%%"
case '%':
// Sanity check: Was the first "%" character the previous one?
@@ -1122,23 +1198,23 @@ void Sema::CheckPrintfString(const StringLiteral *FExpr,
// conversion, and that the current "%" character is the start
// of a new conversion.
if (StrIdx - LastConversionIdx == 1)
- CurrentState = state_OrdChr;
+ 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.
@@ -1150,21 +1226,21 @@ void Sema::CheckPrintfString(const StringLiteral *FExpr,
// 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();
}
@@ -1187,25 +1263,22 @@ static DeclRefExpr* EvalAddr(Expr* E);
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();
+ RetValExp = RetValExp->IgnoreParenCasts();
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()) {
+ } else if (lhsType->isReferenceType()) {
+ // Perform checking for stack values returned by reference.
// Check for a reference to the stack
if (DeclRefExpr *DR = EvalVal(RetValExp))
Diag(DR->getLocStart(), diag::warn_ret_stack_ref)
@@ -1223,7 +1296,7 @@ Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
///
/// 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
+/// At the base case of the recursion is a check for a DeclRefExpr* in
/// the refers to a stack variable.
///
/// This implementation handles:
@@ -1236,11 +1309,11 @@ Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
/// * 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() ||
+ assert((E->getType()->isAnyPointerType() ||
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.
@@ -1253,28 +1326,28 @@ static DeclRefExpr* EvalAddr(Expr *E) {
// 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);
}
@@ -1283,7 +1356,7 @@ static DeclRefExpr* EvalAddr(Expr *E) {
// 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))
@@ -1291,7 +1364,7 @@ static DeclRefExpr* EvalAddr(Expr *E) {
return EvalAddr(C->getRHS());
}
-
+
// For casts, we need to handle conversions from arrays to
// pointer values, and pointer-to-pointer conversions.
case Stmt::ImplicitCastExprClass:
@@ -1299,7 +1372,7 @@ static DeclRefExpr* EvalAddr(Expr *E) {
case Stmt::CXXFunctionalCastExprClass: {
Expr* SubExpr = cast<CastExpr>(E)->getSubExpr();
QualType T = SubExpr->getType();
-
+
if (SubExpr->getType()->isPointerType() ||
SubExpr->getType()->isBlockPointerType() ||
SubExpr->getType()->isObjCQualifiedIdType())
@@ -1309,7 +1382,7 @@ static DeclRefExpr* EvalAddr(Expr *E) {
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
@@ -1317,9 +1390,9 @@ static DeclRefExpr* EvalAddr(Expr *E) {
// 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:
+ // handle references to objects.
+ case Stmt::CXXStaticCastExprClass:
+ case Stmt::CXXDynamicCastExprClass:
case Stmt::CXXConstCastExprClass:
case Stmt::CXXReinterpretCastExprClass: {
Expr *S = cast<CXXNamedCastExpr>(E)->getSubExpr();
@@ -1328,62 +1401,62 @@ static DeclRefExpr* EvalAddr(Expr *E) {
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::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;
-
+ 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.
@@ -1396,18 +1469,18 @@ static DeclRefExpr* EvalVal(Expr *E) {
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;
@@ -1421,7 +1494,7 @@ static DeclRefExpr* EvalVal(Expr *E) {
/// 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();
@@ -1431,8 +1504,8 @@ void Sema::CheckFloatComparison(SourceLocation loc, Expr* lex, Expr *rex) {
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
@@ -1442,25 +1515,24 @@ void Sema::CheckFloatComparison(SourceLocation loc, Expr* lex, Expr *rex) {
if (FloatingLiteral* FLL = dyn_cast<FloatingLiteral>(LeftExprSansParen)) {
if (FLL->isExact())
EmitWarning = false;
- }
- else
+ } 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)
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
new file mode 100644
index 0000000..3981b8d
--- /dev/null
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -0,0 +1,1432 @@
+//===---------------- SemaCodeComplete.cpp - Code Completion ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the code-completion semantic actions.
+//
+//===----------------------------------------------------------------------===//
+#include "Sema.h"
+#include "clang/Sema/CodeCompleteConsumer.h"
+#include "clang/AST/ExprCXX.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/StringExtras.h"
+#include <list>
+#include <map>
+#include <vector>
+
+using namespace clang;
+
+/// \brief Set the code-completion consumer for semantic analysis.
+void Sema::setCodeCompleteConsumer(CodeCompleteConsumer *CCC) {
+ assert(((CodeCompleter != 0) != (CCC != 0)) &&
+ "Already set or cleared a code-completion consumer?");
+ CodeCompleter = CCC;
+}
+
+namespace {
+ /// \brief A container of code-completion results.
+ class ResultBuilder {
+ public:
+ /// \brief The type of a name-lookup filter, which can be provided to the
+ /// name-lookup routines to specify which declarations should be included in
+ /// the result set (when it returns true) and which declarations should be
+ /// filtered out (returns false).
+ typedef bool (ResultBuilder::*LookupFilter)(NamedDecl *) const;
+
+ typedef CodeCompleteConsumer::Result Result;
+
+ private:
+ /// \brief The actual results we have found.
+ std::vector<Result> Results;
+
+ /// \brief A record of all of the declarations we have found and placed
+ /// into the result set, used to ensure that no declaration ever gets into
+ /// the result set twice.
+ llvm::SmallPtrSet<Decl*, 16> AllDeclsFound;
+
+ /// \brief A mapping from declaration names to the declarations that have
+ /// this name within a particular scope and their index within the list of
+ /// results.
+ typedef std::multimap<DeclarationName,
+ std::pair<NamedDecl *, unsigned> > ShadowMap;
+
+ /// \brief The semantic analysis object for which results are being
+ /// produced.
+ Sema &SemaRef;
+
+ /// \brief If non-NULL, a filter function used to remove any code-completion
+ /// results that are not desirable.
+ LookupFilter Filter;
+
+ /// \brief A list of shadow maps, which is used to model name hiding at
+ /// different levels of, e.g., the inheritance hierarchy.
+ std::list<ShadowMap> ShadowMaps;
+
+ public:
+ explicit ResultBuilder(Sema &SemaRef, LookupFilter Filter = 0)
+ : SemaRef(SemaRef), Filter(Filter) { }
+
+ /// \brief Set the filter used for code-completion results.
+ void setFilter(LookupFilter Filter) {
+ this->Filter = Filter;
+ }
+
+ typedef std::vector<Result>::iterator iterator;
+ iterator begin() { return Results.begin(); }
+ iterator end() { return Results.end(); }
+
+ Result *data() { return Results.empty()? 0 : &Results.front(); }
+ unsigned size() const { return Results.size(); }
+ bool empty() const { return Results.empty(); }
+
+ /// \brief Add a new result to this result set (if it isn't already in one
+ /// of the shadow maps), or replace an existing result (for, e.g., a
+ /// redeclaration).
+ ///
+ /// \param R the result to add (if it is unique).
+ ///
+ /// \param R the context in which this result will be named.
+ void MaybeAddResult(Result R, DeclContext *CurContext = 0);
+
+ /// \brief Enter into a new scope.
+ void EnterNewScope();
+
+ /// \brief Exit from the current scope.
+ void ExitScope();
+
+ /// \name Name lookup predicates
+ ///
+ /// These predicates can be passed to the name lookup functions to filter the
+ /// results of name lookup. All of the predicates have the same type, so that
+ ///
+ //@{
+ bool IsOrdinaryName(NamedDecl *ND) const;
+ bool IsNestedNameSpecifier(NamedDecl *ND) const;
+ bool IsEnum(NamedDecl *ND) const;
+ bool IsClassOrStruct(NamedDecl *ND) const;
+ bool IsUnion(NamedDecl *ND) const;
+ bool IsNamespace(NamedDecl *ND) const;
+ bool IsNamespaceOrAlias(NamedDecl *ND) const;
+ bool IsType(NamedDecl *ND) const;
+ bool IsMember(NamedDecl *ND) const;
+ //@}
+ };
+}
+
+/// \brief Determines whether the given hidden result could be found with
+/// some extra work, e.g., by qualifying the name.
+///
+/// \param Hidden the declaration that is hidden by the currenly \p Visible
+/// declaration.
+///
+/// \param Visible the declaration with the same name that is already visible.
+///
+/// \returns true if the hidden result can be found by some mechanism,
+/// false otherwise.
+static bool canHiddenResultBeFound(const LangOptions &LangOpts,
+ NamedDecl *Hidden, NamedDecl *Visible) {
+ // In C, there is no way to refer to a hidden name.
+ if (!LangOpts.CPlusPlus)
+ return false;
+
+ DeclContext *HiddenCtx = Hidden->getDeclContext()->getLookupContext();
+
+ // There is no way to qualify a name declared in a function or method.
+ if (HiddenCtx->isFunctionOrMethod())
+ return false;
+
+ return HiddenCtx != Visible->getDeclContext()->getLookupContext();
+}
+
+/// \brief Compute the qualification required to get from the current context
+/// (\p CurContext) to the target context (\p TargetContext).
+///
+/// \param Context the AST context in which the qualification will be used.
+///
+/// \param CurContext the context where an entity is being named, which is
+/// typically based on the current scope.
+///
+/// \param TargetContext the context in which the named entity actually
+/// resides.
+///
+/// \returns a nested name specifier that refers into the target context, or
+/// NULL if no qualification is needed.
+static NestedNameSpecifier *
+getRequiredQualification(ASTContext &Context,
+ DeclContext *CurContext,
+ DeclContext *TargetContext) {
+ llvm::SmallVector<DeclContext *, 4> TargetParents;
+
+ for (DeclContext *CommonAncestor = TargetContext;
+ CommonAncestor && !CommonAncestor->Encloses(CurContext);
+ CommonAncestor = CommonAncestor->getLookupParent()) {
+ if (CommonAncestor->isTransparentContext() ||
+ CommonAncestor->isFunctionOrMethod())
+ continue;
+
+ TargetParents.push_back(CommonAncestor);
+ }
+
+ NestedNameSpecifier *Result = 0;
+ while (!TargetParents.empty()) {
+ DeclContext *Parent = TargetParents.back();
+ TargetParents.pop_back();
+
+ if (NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(Parent))
+ Result = NestedNameSpecifier::Create(Context, Result, Namespace);
+ else if (TagDecl *TD = dyn_cast<TagDecl>(Parent))
+ Result = NestedNameSpecifier::Create(Context, Result,
+ false,
+ Context.getTypeDeclType(TD).getTypePtr());
+ else
+ assert(Parent->isTranslationUnit());
+ }
+
+ return Result;
+}
+
+void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
+ assert(!ShadowMaps.empty() && "Must enter into a results scope");
+
+ if (R.Kind != Result::RK_Declaration) {
+ // For non-declaration results, just add the result.
+ Results.push_back(R);
+ return;
+ }
+
+ // Skip unnamed entities.
+ if (!R.Declaration->getDeclName())
+ return;
+
+ // Look through using declarations.
+ if (UsingDecl *Using = dyn_cast<UsingDecl>(R.Declaration))
+ MaybeAddResult(Result(Using->getTargetDecl(), R.Rank, R.Qualifier),
+ CurContext);
+
+ // Handle each declaration in an overload set separately.
+ if (OverloadedFunctionDecl *Ovl
+ = dyn_cast<OverloadedFunctionDecl>(R.Declaration)) {
+ for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
+ FEnd = Ovl->function_end();
+ F != FEnd; ++F)
+ MaybeAddResult(Result(*F, R.Rank, R.Qualifier), CurContext);
+
+ return;
+ }
+
+ Decl *CanonDecl = R.Declaration->getCanonicalDecl();
+ unsigned IDNS = CanonDecl->getIdentifierNamespace();
+
+ // Friend declarations and declarations introduced due to friends are never
+ // added as results.
+ if (isa<FriendDecl>(CanonDecl) ||
+ (IDNS & (Decl::IDNS_OrdinaryFriend | Decl::IDNS_TagFriend)))
+ return;
+
+ if (const IdentifierInfo *Id = R.Declaration->getIdentifier()) {
+ // __va_list_tag is a freak of nature. Find it and skip it.
+ if (Id->isStr("__va_list_tag") || Id->isStr("__builtin_va_list"))
+ return;
+
+ // Filter out names reserved for the implementation (C99 7.1.3,
+ // C++ [lib.global.names]). Users don't need to see those.
+ if (Id->getLength() >= 2) {
+ const char *Name = Id->getName();
+ if (Name[0] == '_' &&
+ (Name[1] == '_' || (Name[1] >= 'A' && Name[1] <= 'Z')))
+ return;
+ }
+ }
+
+ // C++ constructors are never found by name lookup.
+ if (isa<CXXConstructorDecl>(CanonDecl))
+ return;
+
+ // Filter out any unwanted results.
+ if (Filter && !(this->*Filter)(R.Declaration))
+ return;
+
+ ShadowMap &SMap = ShadowMaps.back();
+ ShadowMap::iterator I, IEnd;
+ for (llvm::tie(I, IEnd) = SMap.equal_range(R.Declaration->getDeclName());
+ I != IEnd; ++I) {
+ NamedDecl *ND = I->second.first;
+ unsigned Index = I->second.second;
+ if (ND->getCanonicalDecl() == CanonDecl) {
+ // This is a redeclaration. Always pick the newer declaration.
+ I->second.first = R.Declaration;
+ Results[Index].Declaration = R.Declaration;
+
+ // Pick the best rank of the two.
+ Results[Index].Rank = std::min(Results[Index].Rank, R.Rank);
+
+ // We're done.
+ return;
+ }
+ }
+
+ // This is a new declaration in this scope. However, check whether this
+ // declaration name is hidden by a similarly-named declaration in an outer
+ // scope.
+ std::list<ShadowMap>::iterator SM, SMEnd = ShadowMaps.end();
+ --SMEnd;
+ for (SM = ShadowMaps.begin(); SM != SMEnd; ++SM) {
+ for (llvm::tie(I, IEnd) = SM->equal_range(R.Declaration->getDeclName());
+ I != IEnd; ++I) {
+ // A tag declaration does not hide a non-tag declaration.
+ if (I->second.first->getIdentifierNamespace() == Decl::IDNS_Tag &&
+ (IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary |
+ Decl::IDNS_ObjCProtocol)))
+ continue;
+
+ // Protocols are in distinct namespaces from everything else.
+ if (((I->second.first->getIdentifierNamespace() & Decl::IDNS_ObjCProtocol)
+ || (IDNS & Decl::IDNS_ObjCProtocol)) &&
+ I->second.first->getIdentifierNamespace() != IDNS)
+ continue;
+
+ // The newly-added result is hidden by an entry in the shadow map.
+ if (canHiddenResultBeFound(SemaRef.getLangOptions(), R.Declaration,
+ I->second.first)) {
+ // Note that this result was hidden.
+ R.Hidden = true;
+ R.QualifierIsInformative = false;
+
+ if (!R.Qualifier)
+ R.Qualifier = getRequiredQualification(SemaRef.Context,
+ CurContext,
+ R.Declaration->getDeclContext());
+ } else {
+ // This result was hidden and cannot be found; don't bother adding
+ // it.
+ return;
+ }
+
+ break;
+ }
+ }
+
+ // Make sure that any given declaration only shows up in the result set once.
+ if (!AllDeclsFound.insert(CanonDecl))
+ return;
+
+ // If the filter is for nested-name-specifiers, then this result starts a
+ // nested-name-specifier.
+ if ((Filter == &ResultBuilder::IsNestedNameSpecifier) ||
+ (Filter == &ResultBuilder::IsMember &&
+ isa<CXXRecordDecl>(R.Declaration) &&
+ cast<CXXRecordDecl>(R.Declaration)->isInjectedClassName()))
+ R.StartsNestedNameSpecifier = true;
+
+ // If this result is supposed to have an informative qualifier, add one.
+ if (R.QualifierIsInformative && !R.Qualifier &&
+ !R.StartsNestedNameSpecifier) {
+ DeclContext *Ctx = R.Declaration->getDeclContext();
+ if (NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(Ctx))
+ R.Qualifier = NestedNameSpecifier::Create(SemaRef.Context, 0, Namespace);
+ else if (TagDecl *Tag = dyn_cast<TagDecl>(Ctx))
+ R.Qualifier = NestedNameSpecifier::Create(SemaRef.Context, 0, false,
+ SemaRef.Context.getTypeDeclType(Tag).getTypePtr());
+ else
+ R.QualifierIsInformative = false;
+ }
+
+ // Insert this result into the set of results and into the current shadow
+ // map.
+ SMap.insert(std::make_pair(R.Declaration->getDeclName(),
+ std::make_pair(R.Declaration, Results.size())));
+ Results.push_back(R);
+}
+
+/// \brief Enter into a new scope.
+void ResultBuilder::EnterNewScope() {
+ ShadowMaps.push_back(ShadowMap());
+}
+
+/// \brief Exit from the current scope.
+void ResultBuilder::ExitScope() {
+ ShadowMaps.pop_back();
+}
+
+/// \brief Determines whether this given declaration will be found by
+/// ordinary name lookup.
+bool ResultBuilder::IsOrdinaryName(NamedDecl *ND) const {
+ unsigned IDNS = Decl::IDNS_Ordinary;
+ if (SemaRef.getLangOptions().CPlusPlus)
+ IDNS |= Decl::IDNS_Tag;
+
+ return ND->getIdentifierNamespace() & IDNS;
+}
+
+/// \brief Determines whether the given declaration is suitable as the
+/// start of a C++ nested-name-specifier, e.g., a class or namespace.
+bool ResultBuilder::IsNestedNameSpecifier(NamedDecl *ND) const {
+ // Allow us to find class templates, too.
+ if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(ND))
+ ND = ClassTemplate->getTemplatedDecl();
+
+ return SemaRef.isAcceptableNestedNameSpecifier(ND);
+}
+
+/// \brief Determines whether the given declaration is an enumeration.
+bool ResultBuilder::IsEnum(NamedDecl *ND) const {
+ return isa<EnumDecl>(ND);
+}
+
+/// \brief Determines whether the given declaration is a class or struct.
+bool ResultBuilder::IsClassOrStruct(NamedDecl *ND) const {
+ // Allow us to find class templates, too.
+ if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(ND))
+ ND = ClassTemplate->getTemplatedDecl();
+
+ if (RecordDecl *RD = dyn_cast<RecordDecl>(ND))
+ return RD->getTagKind() == TagDecl::TK_class ||
+ RD->getTagKind() == TagDecl::TK_struct;
+
+ return false;
+}
+
+/// \brief Determines whether the given declaration is a union.
+bool ResultBuilder::IsUnion(NamedDecl *ND) const {
+ // Allow us to find class templates, too.
+ if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(ND))
+ ND = ClassTemplate->getTemplatedDecl();
+
+ if (RecordDecl *RD = dyn_cast<RecordDecl>(ND))
+ return RD->getTagKind() == TagDecl::TK_union;
+
+ return false;
+}
+
+/// \brief Determines whether the given declaration is a namespace.
+bool ResultBuilder::IsNamespace(NamedDecl *ND) const {
+ return isa<NamespaceDecl>(ND);
+}
+
+/// \brief Determines whether the given declaration is a namespace or
+/// namespace alias.
+bool ResultBuilder::IsNamespaceOrAlias(NamedDecl *ND) const {
+ return isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND);
+}
+
+/// \brief Brief determines whether the given declaration is a namespace or
+/// namespace alias.
+bool ResultBuilder::IsType(NamedDecl *ND) const {
+ return isa<TypeDecl>(ND);
+}
+
+/// \brief Since every declaration found within a class is a member that we
+/// care about, always returns true. This predicate exists mostly to
+/// communicate to the result builder that we are performing a lookup for
+/// member access.
+bool ResultBuilder::IsMember(NamedDecl *ND) const {
+ return true;
+}
+
+// Find the next outer declaration context corresponding to this scope.
+static DeclContext *findOuterContext(Scope *S) {
+ for (S = S->getParent(); S; S = S->getParent())
+ if (S->getEntity())
+ return static_cast<DeclContext *>(S->getEntity())->getPrimaryContext();
+
+ return 0;
+}
+
+/// \brief Collect the results of searching for members within the given
+/// declaration context.
+///
+/// \param Ctx the declaration context from which we will gather results.
+///
+/// \param Rank the rank given to results in this declaration context.
+///
+/// \param Visited the set of declaration contexts that have already been
+/// visited. Declaration contexts will only be visited once.
+///
+/// \param Results the result set that will be extended with any results
+/// found within this declaration context (and, for a C++ class, its bases).
+///
+/// \param InBaseClass whether we are in a base class.
+///
+/// \returns the next higher rank value, after considering all of the
+/// names within this declaration context.
+static unsigned CollectMemberLookupResults(DeclContext *Ctx,
+ unsigned Rank,
+ DeclContext *CurContext,
+ llvm::SmallPtrSet<DeclContext *, 16> &Visited,
+ ResultBuilder &Results,
+ bool InBaseClass = false) {
+ // Make sure we don't visit the same context twice.
+ if (!Visited.insert(Ctx->getPrimaryContext()))
+ return Rank;
+
+ // Enumerate all of the results in this context.
+ typedef CodeCompleteConsumer::Result Result;
+ Results.EnterNewScope();
+ for (DeclContext *CurCtx = Ctx->getPrimaryContext(); CurCtx;
+ CurCtx = CurCtx->getNextContext()) {
+ for (DeclContext::decl_iterator D = CurCtx->decls_begin(),
+ DEnd = CurCtx->decls_end();
+ D != DEnd; ++D) {
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(*D))
+ Results.MaybeAddResult(Result(ND, Rank, 0, InBaseClass), CurContext);
+ }
+ }
+
+ // Traverse the contexts of inherited classes.
+ if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx)) {
+ for (CXXRecordDecl::base_class_iterator B = Record->bases_begin(),
+ BEnd = Record->bases_end();
+ B != BEnd; ++B) {
+ QualType BaseType = B->getType();
+
+ // Don't look into dependent bases, because name lookup can't look
+ // there anyway.
+ if (BaseType->isDependentType())
+ continue;
+
+ const RecordType *Record = BaseType->getAs<RecordType>();
+ if (!Record)
+ continue;
+
+ // FIXME: It would be nice to be able to determine whether referencing
+ // a particular member would be ambiguous. For example, given
+ //
+ // struct A { int member; };
+ // struct B { int member; };
+ // struct C : A, B { };
+ //
+ // void f(C *c) { c->### }
+ // accessing 'member' would result in an ambiguity. However, code
+ // completion could be smart enough to qualify the member with the
+ // base class, e.g.,
+ //
+ // c->B::member
+ //
+ // or
+ //
+ // c->A::member
+
+ // Collect results from this base class (and its bases).
+ CollectMemberLookupResults(Record->getDecl(), Rank, CurContext, Visited,
+ Results, /*InBaseClass=*/true);
+ }
+ }
+
+ // FIXME: Look into base classes in Objective-C!
+
+ Results.ExitScope();
+ return Rank + 1;
+}
+
+/// \brief Collect the results of searching for members within the given
+/// declaration context.
+///
+/// \param Ctx the declaration context from which we will gather results.
+///
+/// \param InitialRank the initial rank given to results in this declaration
+/// context. Larger rank values will be used for, e.g., members found in
+/// base classes.
+///
+/// \param Results the result set that will be extended with any results
+/// found within this declaration context (and, for a C++ class, its bases).
+///
+/// \returns the next higher rank value, after considering all of the
+/// names within this declaration context.
+static unsigned CollectMemberLookupResults(DeclContext *Ctx,
+ unsigned InitialRank,
+ DeclContext *CurContext,
+ ResultBuilder &Results) {
+ llvm::SmallPtrSet<DeclContext *, 16> Visited;
+ return CollectMemberLookupResults(Ctx, InitialRank, CurContext, Visited,
+ Results);
+}
+
+/// \brief Collect the results of searching for declarations within the given
+/// scope and its parent scopes.
+///
+/// \param S the scope in which we will start looking for declarations.
+///
+/// \param InitialRank the initial rank given to results in this scope.
+/// Larger rank values will be used for results found in parent scopes.
+///
+/// \param CurContext the context from which lookup results will be found.
+///
+/// \param Results the builder object that will receive each result.
+static unsigned CollectLookupResults(Scope *S,
+ TranslationUnitDecl *TranslationUnit,
+ unsigned InitialRank,
+ DeclContext *CurContext,
+ ResultBuilder &Results) {
+ if (!S)
+ return InitialRank;
+
+ // FIXME: Using directives!
+
+ unsigned NextRank = InitialRank;
+ Results.EnterNewScope();
+ if (S->getEntity() &&
+ !((DeclContext *)S->getEntity())->isFunctionOrMethod()) {
+ // Look into this scope's declaration context, along with any of its
+ // parent lookup contexts (e.g., enclosing classes), up to the point
+ // where we hit the context stored in the next outer scope.
+ DeclContext *Ctx = (DeclContext *)S->getEntity();
+ DeclContext *OuterCtx = findOuterContext(S);
+
+ for (; Ctx && Ctx->getPrimaryContext() != OuterCtx;
+ Ctx = Ctx->getLookupParent()) {
+ if (Ctx->isFunctionOrMethod())
+ continue;
+
+ NextRank = CollectMemberLookupResults(Ctx, NextRank + 1, CurContext,
+ Results);
+ }
+ } else if (!S->getParent()) {
+ // Look into the translation unit scope. We walk through the translation
+ // unit's declaration context, because the Scope itself won't have all of
+ // the declarations if we loaded a precompiled header.
+ // FIXME: We would like the translation unit's Scope object to point to the
+ // translation unit, so we don't need this special "if" branch. However,
+ // doing so would force the normal C++ name-lookup code to look into the
+ // translation unit decl when the IdentifierInfo chains would suffice.
+ // Once we fix that problem (which is part of a more general "don't look
+ // in DeclContexts unless we have to" optimization), we can eliminate the
+ // TranslationUnit parameter entirely.
+ NextRank = CollectMemberLookupResults(TranslationUnit, NextRank + 1,
+ CurContext, Results);
+ } else {
+ // Walk through the declarations in this Scope.
+ for (Scope::decl_iterator D = S->decl_begin(), DEnd = S->decl_end();
+ D != DEnd; ++D) {
+ if (NamedDecl *ND = dyn_cast<NamedDecl>((Decl *)((*D).get())))
+ Results.MaybeAddResult(CodeCompleteConsumer::Result(ND, NextRank),
+ CurContext);
+ }
+
+ NextRank = NextRank + 1;
+ }
+
+ // Lookup names in the parent scope.
+ NextRank = CollectLookupResults(S->getParent(), TranslationUnit, NextRank,
+ CurContext, Results);
+ Results.ExitScope();
+
+ return NextRank;
+}
+
+/// \brief Add type specifiers for the current language as keyword results.
+static void AddTypeSpecifierResults(const LangOptions &LangOpts, unsigned Rank,
+ ResultBuilder &Results) {
+ typedef CodeCompleteConsumer::Result Result;
+ Results.MaybeAddResult(Result("short", Rank));
+ Results.MaybeAddResult(Result("long", Rank));
+ Results.MaybeAddResult(Result("signed", Rank));
+ Results.MaybeAddResult(Result("unsigned", Rank));
+ Results.MaybeAddResult(Result("void", Rank));
+ Results.MaybeAddResult(Result("char", Rank));
+ Results.MaybeAddResult(Result("int", Rank));
+ Results.MaybeAddResult(Result("float", Rank));
+ Results.MaybeAddResult(Result("double", Rank));
+ Results.MaybeAddResult(Result("enum", Rank));
+ Results.MaybeAddResult(Result("struct", Rank));
+ Results.MaybeAddResult(Result("union", Rank));
+
+ if (LangOpts.C99) {
+ // C99-specific
+ Results.MaybeAddResult(Result("_Complex", Rank));
+ Results.MaybeAddResult(Result("_Imaginary", Rank));
+ Results.MaybeAddResult(Result("_Bool", Rank));
+ }
+
+ if (LangOpts.CPlusPlus) {
+ // C++-specific
+ Results.MaybeAddResult(Result("bool", Rank));
+ Results.MaybeAddResult(Result("class", Rank));
+ Results.MaybeAddResult(Result("typename", Rank));
+ Results.MaybeAddResult(Result("wchar_t", Rank));
+
+ if (LangOpts.CPlusPlus0x) {
+ Results.MaybeAddResult(Result("char16_t", Rank));
+ Results.MaybeAddResult(Result("char32_t", Rank));
+ Results.MaybeAddResult(Result("decltype", Rank));
+ }
+ }
+
+ // GNU extensions
+ if (LangOpts.GNUMode) {
+ // FIXME: Enable when we actually support decimal floating point.
+ // Results.MaybeAddResult(Result("_Decimal32", Rank));
+ // Results.MaybeAddResult(Result("_Decimal64", Rank));
+ // Results.MaybeAddResult(Result("_Decimal128", Rank));
+ Results.MaybeAddResult(Result("typeof", Rank));
+ }
+}
+
+/// \brief Add function parameter chunks to the given code completion string.
+static void AddFunctionParameterChunks(ASTContext &Context,
+ FunctionDecl *Function,
+ CodeCompletionString *Result) {
+ CodeCompletionString *CCStr = Result;
+
+ for (unsigned P = 0, N = Function->getNumParams(); P != N; ++P) {
+ ParmVarDecl *Param = Function->getParamDecl(P);
+
+ if (Param->hasDefaultArg()) {
+ // When we see an optional default argument, put that argument and
+ // the remaining default arguments into a new, optional string.
+ CodeCompletionString *Opt = new CodeCompletionString;
+ CCStr->AddOptionalChunk(std::auto_ptr<CodeCompletionString>(Opt));
+ CCStr = Opt;
+ }
+
+ if (P != 0)
+ CCStr->AddTextChunk(", ");
+
+ // Format the placeholder string.
+ std::string PlaceholderStr;
+ if (Param->getIdentifier())
+ PlaceholderStr = Param->getIdentifier()->getName();
+
+ Param->getType().getAsStringInternal(PlaceholderStr,
+ Context.PrintingPolicy);
+
+ // Add the placeholder string.
+ CCStr->AddPlaceholderChunk(PlaceholderStr.c_str());
+ }
+
+ if (const FunctionProtoType *Proto
+ = Function->getType()->getAs<FunctionProtoType>())
+ if (Proto->isVariadic())
+ CCStr->AddPlaceholderChunk(", ...");
+}
+
+/// \brief Add template parameter chunks to the given code completion string.
+static void AddTemplateParameterChunks(ASTContext &Context,
+ TemplateDecl *Template,
+ CodeCompletionString *Result,
+ unsigned MaxParameters = 0) {
+ CodeCompletionString *CCStr = Result;
+ bool FirstParameter = true;
+
+ TemplateParameterList *Params = Template->getTemplateParameters();
+ TemplateParameterList::iterator PEnd = Params->end();
+ if (MaxParameters)
+ PEnd = Params->begin() + MaxParameters;
+ for (TemplateParameterList::iterator P = Params->begin(); P != PEnd; ++P) {
+ bool HasDefaultArg = false;
+ std::string PlaceholderStr;
+ if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*P)) {
+ if (TTP->wasDeclaredWithTypename())
+ PlaceholderStr = "typename";
+ else
+ PlaceholderStr = "class";
+
+ if (TTP->getIdentifier()) {
+ PlaceholderStr += ' ';
+ PlaceholderStr += TTP->getIdentifier()->getName();
+ }
+
+ HasDefaultArg = TTP->hasDefaultArgument();
+ } else if (NonTypeTemplateParmDecl *NTTP
+ = dyn_cast<NonTypeTemplateParmDecl>(*P)) {
+ if (NTTP->getIdentifier())
+ PlaceholderStr = NTTP->getIdentifier()->getName();
+ NTTP->getType().getAsStringInternal(PlaceholderStr,
+ Context.PrintingPolicy);
+ HasDefaultArg = NTTP->hasDefaultArgument();
+ } else {
+ assert(isa<TemplateTemplateParmDecl>(*P));
+ TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*P);
+
+ // Since putting the template argument list into the placeholder would
+ // be very, very long, we just use an abbreviation.
+ PlaceholderStr = "template<...> class";
+ if (TTP->getIdentifier()) {
+ PlaceholderStr += ' ';
+ PlaceholderStr += TTP->getIdentifier()->getName();
+ }
+
+ HasDefaultArg = TTP->hasDefaultArgument();
+ }
+
+ if (HasDefaultArg) {
+ // When we see an optional default argument, put that argument and
+ // the remaining default arguments into a new, optional string.
+ CodeCompletionString *Opt = new CodeCompletionString;
+ CCStr->AddOptionalChunk(std::auto_ptr<CodeCompletionString>(Opt));
+ CCStr = Opt;
+ }
+
+ if (FirstParameter)
+ FirstParameter = false;
+ else
+ CCStr->AddTextChunk(", ");
+
+ // Add the placeholder string.
+ CCStr->AddPlaceholderChunk(PlaceholderStr.c_str());
+ }
+}
+
+/// \brief Add a qualifier to the given code-completion string, if the
+/// provided nested-name-specifier is non-NULL.
+void AddQualifierToCompletionString(CodeCompletionString *Result,
+ NestedNameSpecifier *Qualifier,
+ bool QualifierIsInformative,
+ ASTContext &Context) {
+ if (!Qualifier)
+ return;
+
+ std::string PrintedNNS;
+ {
+ llvm::raw_string_ostream OS(PrintedNNS);
+ Qualifier->print(OS, Context.PrintingPolicy);
+ }
+ if (QualifierIsInformative)
+ Result->AddInformativeChunk(PrintedNNS.c_str());
+ else
+ Result->AddTextChunk(PrintedNNS.c_str());
+}
+
+/// \brief If possible, create a new code completion string for the given
+/// result.
+///
+/// \returns Either a new, heap-allocated code completion string describing
+/// how to use this result, or NULL to indicate that the string or name of the
+/// result is all that is needed.
+CodeCompletionString *
+CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) {
+ if (Kind != RK_Declaration)
+ return 0;
+
+ NamedDecl *ND = Declaration;
+
+ if (FunctionDecl *Function = dyn_cast<FunctionDecl>(ND)) {
+ CodeCompletionString *Result = new CodeCompletionString;
+ AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
+ S.Context);
+ Result->AddTextChunk(Function->getNameAsString().c_str());
+ Result->AddTextChunk("(");
+ AddFunctionParameterChunks(S.Context, Function, Result);
+ Result->AddTextChunk(")");
+ return Result;
+ }
+
+ if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(ND)) {
+ CodeCompletionString *Result = new CodeCompletionString;
+ AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
+ S.Context);
+ FunctionDecl *Function = FunTmpl->getTemplatedDecl();
+ Result->AddTextChunk(Function->getNameAsString().c_str());
+
+ // Figure out which template parameters are deduced (or have default
+ // arguments).
+ llvm::SmallVector<bool, 16> Deduced;
+ S.MarkDeducedTemplateParameters(FunTmpl, Deduced);
+ unsigned LastDeducibleArgument;
+ for (LastDeducibleArgument = Deduced.size(); LastDeducibleArgument > 0;
+ --LastDeducibleArgument) {
+ if (!Deduced[LastDeducibleArgument - 1]) {
+ // C++0x: Figure out if the template argument has a default. If so,
+ // the user doesn't need to type this argument.
+ // FIXME: We need to abstract template parameters better!
+ bool HasDefaultArg = false;
+ NamedDecl *Param = FunTmpl->getTemplateParameters()->getParam(
+ LastDeducibleArgument - 1);
+ if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
+ HasDefaultArg = TTP->hasDefaultArgument();
+ else if (NonTypeTemplateParmDecl *NTTP
+ = dyn_cast<NonTypeTemplateParmDecl>(Param))
+ HasDefaultArg = NTTP->hasDefaultArgument();
+ else {
+ assert(isa<TemplateTemplateParmDecl>(Param));
+ HasDefaultArg
+ = cast<TemplateTemplateParmDecl>(Param)->hasDefaultArgument();
+ }
+
+ if (!HasDefaultArg)
+ break;
+ }
+ }
+
+ if (LastDeducibleArgument) {
+ // Some of the function template arguments cannot be deduced from a
+ // function call, so we introduce an explicit template argument list
+ // containing all of the arguments up to the first deducible argument.
+ Result->AddTextChunk("<");
+ AddTemplateParameterChunks(S.Context, FunTmpl, Result,
+ LastDeducibleArgument);
+ Result->AddTextChunk(">");
+ }
+
+ // Add the function parameters
+ Result->AddTextChunk("(");
+ AddFunctionParameterChunks(S.Context, Function, Result);
+ Result->AddTextChunk(")");
+ return Result;
+ }
+
+ if (TemplateDecl *Template = dyn_cast<TemplateDecl>(ND)) {
+ CodeCompletionString *Result = new CodeCompletionString;
+ AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
+ S.Context);
+ Result->AddTextChunk(Template->getNameAsString().c_str());
+ Result->AddTextChunk("<");
+ AddTemplateParameterChunks(S.Context, Template, Result);
+ Result->AddTextChunk(">");
+ return Result;
+ }
+
+ if (Qualifier || StartsNestedNameSpecifier) {
+ CodeCompletionString *Result = new CodeCompletionString;
+ AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
+ S.Context);
+ Result->AddTextChunk(ND->getNameAsString().c_str());
+ if (StartsNestedNameSpecifier)
+ Result->AddTextChunk("::");
+ return Result;
+ }
+
+ return 0;
+}
+
+CodeCompletionString *
+CodeCompleteConsumer::OverloadCandidate::CreateSignatureString(
+ unsigned CurrentArg,
+ Sema &S) const {
+ CodeCompletionString *Result = new CodeCompletionString;
+ FunctionDecl *FDecl = getFunction();
+ const FunctionProtoType *Proto
+ = dyn_cast<FunctionProtoType>(getFunctionType());
+ if (!FDecl && !Proto) {
+ // Function without a prototype. Just give the return type and a
+ // highlighted ellipsis.
+ const FunctionType *FT = getFunctionType();
+ Result->AddTextChunk(
+ FT->getResultType().getAsString(S.Context.PrintingPolicy).c_str());
+ Result->AddTextChunk("(");
+ Result->AddPlaceholderChunk("...");
+ Result->AddTextChunk("(");
+ return Result;
+ }
+
+ if (FDecl)
+ Result->AddTextChunk(FDecl->getNameAsString().c_str());
+ else
+ Result->AddTextChunk(
+ Proto->getResultType().getAsString(S.Context.PrintingPolicy).c_str());
+
+ Result->AddTextChunk("(");
+ unsigned NumParams = FDecl? FDecl->getNumParams() : Proto->getNumArgs();
+ for (unsigned I = 0; I != NumParams; ++I) {
+ if (I)
+ Result->AddTextChunk(", ");
+
+ std::string ArgString;
+ QualType ArgType;
+
+ if (FDecl) {
+ ArgString = FDecl->getParamDecl(I)->getNameAsString();
+ ArgType = FDecl->getParamDecl(I)->getOriginalType();
+ } else {
+ ArgType = Proto->getArgType(I);
+ }
+
+ ArgType.getAsStringInternal(ArgString, S.Context.PrintingPolicy);
+
+ if (I == CurrentArg)
+ Result->AddPlaceholderChunk(ArgString.c_str());
+ else
+ Result->AddTextChunk(ArgString.c_str());
+ }
+
+ if (Proto && Proto->isVariadic()) {
+ Result->AddTextChunk(", ");
+ if (CurrentArg < NumParams)
+ Result->AddTextChunk("...");
+ else
+ Result->AddPlaceholderChunk("...");
+ }
+ Result->AddTextChunk(")");
+
+ return Result;
+}
+
+namespace {
+ struct SortCodeCompleteResult {
+ typedef CodeCompleteConsumer::Result Result;
+
+ bool isEarlierDeclarationName(DeclarationName X, DeclarationName Y) const {
+ if (X.getNameKind() != Y.getNameKind())
+ return X.getNameKind() < Y.getNameKind();
+
+ return llvm::LowercaseString(X.getAsString())
+ < llvm::LowercaseString(Y.getAsString());
+ }
+
+ bool operator()(const Result &X, const Result &Y) const {
+ // Sort first by rank.
+ if (X.Rank < Y.Rank)
+ return true;
+ else if (X.Rank > Y.Rank)
+ return false;
+
+ // Result kinds are ordered by decreasing importance.
+ if (X.Kind < Y.Kind)
+ return true;
+ else if (X.Kind > Y.Kind)
+ return false;
+
+ // Non-hidden names precede hidden names.
+ if (X.Hidden != Y.Hidden)
+ return !X.Hidden;
+
+ // Non-nested-name-specifiers precede nested-name-specifiers.
+ if (X.StartsNestedNameSpecifier != Y.StartsNestedNameSpecifier)
+ return !X.StartsNestedNameSpecifier;
+
+ // Ordering depends on the kind of result.
+ switch (X.Kind) {
+ case Result::RK_Declaration:
+ // Order based on the declaration names.
+ return isEarlierDeclarationName(X.Declaration->getDeclName(),
+ Y.Declaration->getDeclName());
+
+ case Result::RK_Keyword:
+ return strcmp(X.Keyword, Y.Keyword) < 0;
+ }
+
+ // Silence GCC warning.
+ return false;
+ }
+ };
+}
+
+static void HandleCodeCompleteResults(CodeCompleteConsumer *CodeCompleter,
+ CodeCompleteConsumer::Result *Results,
+ unsigned NumResults) {
+ // Sort the results by rank/kind/etc.
+ std::stable_sort(Results, Results + NumResults, SortCodeCompleteResult());
+
+ if (CodeCompleter)
+ CodeCompleter->ProcessCodeCompleteResults(Results, NumResults);
+}
+
+void Sema::CodeCompleteOrdinaryName(Scope *S) {
+ ResultBuilder Results(*this, &ResultBuilder::IsOrdinaryName);
+ CollectLookupResults(S, Context.getTranslationUnitDecl(), 0, CurContext,
+ Results);
+ HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size());
+}
+
+void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE,
+ SourceLocation OpLoc,
+ bool IsArrow) {
+ if (!BaseE || !CodeCompleter)
+ return;
+
+ typedef CodeCompleteConsumer::Result Result;
+
+ Expr *Base = static_cast<Expr *>(BaseE);
+ QualType BaseType = Base->getType();
+
+ if (IsArrow) {
+ if (const PointerType *Ptr = BaseType->getAs<PointerType>())
+ BaseType = Ptr->getPointeeType();
+ else if (BaseType->isObjCObjectPointerType())
+ /*Do nothing*/ ;
+ else
+ return;
+ }
+
+ ResultBuilder Results(*this, &ResultBuilder::IsMember);
+ unsigned NextRank = 0;
+
+ if (const RecordType *Record = BaseType->getAs<RecordType>()) {
+ NextRank = CollectMemberLookupResults(Record->getDecl(), NextRank,
+ Record->getDecl(), Results);
+
+ if (getLangOptions().CPlusPlus) {
+ if (!Results.empty()) {
+ // The "template" keyword can follow "->" or "." in the grammar.
+ // However, we only want to suggest the template keyword if something
+ // is dependent.
+ bool IsDependent = BaseType->isDependentType();
+ if (!IsDependent) {
+ for (Scope *DepScope = S; DepScope; DepScope = DepScope->getParent())
+ if (DeclContext *Ctx = (DeclContext *)DepScope->getEntity()) {
+ IsDependent = Ctx->isDependentContext();
+ break;
+ }
+ }
+
+ if (IsDependent)
+ Results.MaybeAddResult(Result("template", NextRank++));
+ }
+
+ // We could have the start of a nested-name-specifier. Add those
+ // results as well.
+ Results.setFilter(&ResultBuilder::IsNestedNameSpecifier);
+ CollectLookupResults(S, Context.getTranslationUnitDecl(), NextRank,
+ CurContext, Results);
+ }
+
+ // Hand off the results found for code completion.
+ HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size());
+
+ // We're done!
+ return;
+ }
+}
+
+void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) {
+ if (!CodeCompleter)
+ return;
+
+ typedef CodeCompleteConsumer::Result Result;
+ ResultBuilder::LookupFilter Filter = 0;
+ switch ((DeclSpec::TST)TagSpec) {
+ case DeclSpec::TST_enum:
+ Filter = &ResultBuilder::IsEnum;
+ break;
+
+ case DeclSpec::TST_union:
+ Filter = &ResultBuilder::IsUnion;
+ break;
+
+ case DeclSpec::TST_struct:
+ case DeclSpec::TST_class:
+ Filter = &ResultBuilder::IsClassOrStruct;
+ break;
+
+ default:
+ assert(false && "Unknown type specifier kind in CodeCompleteTag");
+ return;
+ }
+
+ ResultBuilder Results(*this, Filter);
+ unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(),
+ 0, CurContext, Results);
+
+ if (getLangOptions().CPlusPlus) {
+ // We could have the start of a nested-name-specifier. Add those
+ // results as well.
+ Results.setFilter(&ResultBuilder::IsNestedNameSpecifier);
+ CollectLookupResults(S, Context.getTranslationUnitDecl(), NextRank,
+ CurContext, Results);
+ }
+
+ HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size());
+}
+
+void Sema::CodeCompleteCase(Scope *S) {
+ if (getSwitchStack().empty() || !CodeCompleter)
+ return;
+
+ SwitchStmt *Switch = getSwitchStack().back();
+ if (!Switch->getCond()->getType()->isEnumeralType())
+ return;
+
+ // Code-complete the cases of a switch statement over an enumeration type
+ // by providing the list of
+ EnumDecl *Enum = Switch->getCond()->getType()->getAs<EnumType>()->getDecl();
+
+ // Determine which enumerators we have already seen in the switch statement.
+ // FIXME: Ideally, we would also be able to look *past* the code-completion
+ // token, in case we are code-completing in the middle of the switch and not
+ // at the end. However, we aren't able to do so at the moment.
+ llvm::SmallPtrSet<EnumConstantDecl *, 8> EnumeratorsSeen;
+ NestedNameSpecifier *Qualifier = 0;
+ for (SwitchCase *SC = Switch->getSwitchCaseList(); SC;
+ SC = SC->getNextSwitchCase()) {
+ CaseStmt *Case = dyn_cast<CaseStmt>(SC);
+ if (!Case)
+ continue;
+
+ Expr *CaseVal = Case->getLHS()->IgnoreParenCasts();
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CaseVal))
+ if (EnumConstantDecl *Enumerator
+ = dyn_cast<EnumConstantDecl>(DRE->getDecl())) {
+ // We look into the AST of the case statement to determine which
+ // enumerator was named. Alternatively, we could compute the value of
+ // the integral constant expression, then compare it against the
+ // values of each enumerator. However, value-based approach would not
+ // work as well with C++ templates where enumerators declared within a
+ // template are type- and value-dependent.
+ EnumeratorsSeen.insert(Enumerator);
+
+ // If this is a qualified-id, keep track of the nested-name-specifier
+ // so that we can reproduce it as part of code completion, e.g.,
+ //
+ // switch (TagD.getKind()) {
+ // case TagDecl::TK_enum:
+ // break;
+ // case XXX
+ //
+ // At the XXX, our completions are TagDecl::TK_union,
+ // TagDecl::TK_struct, and TagDecl::TK_class, rather than TK_union,
+ // TK_struct, and TK_class.
+ if (QualifiedDeclRefExpr *QDRE = dyn_cast<QualifiedDeclRefExpr>(DRE))
+ Qualifier = QDRE->getQualifier();
+ }
+ }
+
+ if (getLangOptions().CPlusPlus && !Qualifier && EnumeratorsSeen.empty()) {
+ // If there are no prior enumerators in C++, check whether we have to
+ // qualify the names of the enumerators that we suggest, because they
+ // may not be visible in this scope.
+ Qualifier = getRequiredQualification(Context, CurContext,
+ Enum->getDeclContext());
+
+ // FIXME: Scoped enums need to start with "EnumDecl" as the context!
+ }
+
+ // Add any enumerators that have not yet been mentioned.
+ ResultBuilder Results(*this);
+ Results.EnterNewScope();
+ for (EnumDecl::enumerator_iterator E = Enum->enumerator_begin(),
+ EEnd = Enum->enumerator_end();
+ E != EEnd; ++E) {
+ if (EnumeratorsSeen.count(*E))
+ continue;
+
+ Results.MaybeAddResult(CodeCompleteConsumer::Result(*E, 0, Qualifier));
+ }
+ Results.ExitScope();
+
+ HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size());
+}
+
+namespace {
+ struct IsBetterOverloadCandidate {
+ Sema &S;
+
+ public:
+ explicit IsBetterOverloadCandidate(Sema &S) : S(S) { }
+
+ bool
+ operator()(const OverloadCandidate &X, const OverloadCandidate &Y) const {
+ return S.isBetterOverloadCandidate(X, Y);
+ }
+ };
+}
+
+void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn,
+ ExprTy **ArgsIn, unsigned NumArgs) {
+ if (!CodeCompleter)
+ return;
+
+ Expr *Fn = (Expr *)FnIn;
+ Expr **Args = (Expr **)ArgsIn;
+
+ // Ignore type-dependent call expressions entirely.
+ if (Fn->isTypeDependent() ||
+ Expr::hasAnyTypeDependentArguments(Args, NumArgs))
+ return;
+
+ NamedDecl *Function;
+ DeclarationName UnqualifiedName;
+ NestedNameSpecifier *Qualifier;
+ SourceRange QualifierRange;
+ bool ArgumentDependentLookup;
+ bool HasExplicitTemplateArgs;
+ const TemplateArgument *ExplicitTemplateArgs;
+ unsigned NumExplicitTemplateArgs;
+
+ DeconstructCallFunction(Fn,
+ Function, UnqualifiedName, Qualifier, QualifierRange,
+ ArgumentDependentLookup, HasExplicitTemplateArgs,
+ ExplicitTemplateArgs, NumExplicitTemplateArgs);
+
+
+ // FIXME: What if we're calling something that isn't a function declaration?
+ // FIXME: What if we're calling a pseudo-destructor?
+ // FIXME: What if we're calling a member function?
+
+ // Build an overload candidate set based on the functions we find.
+ OverloadCandidateSet CandidateSet;
+ AddOverloadedCallCandidates(Function, UnqualifiedName,
+ ArgumentDependentLookup, HasExplicitTemplateArgs,
+ ExplicitTemplateArgs, NumExplicitTemplateArgs,
+ Args, NumArgs,
+ CandidateSet,
+ /*PartialOverloading=*/true);
+
+ // Sort the overload candidate set by placing the best overloads first.
+ std::stable_sort(CandidateSet.begin(), CandidateSet.end(),
+ IsBetterOverloadCandidate(*this));
+
+ // Add the remaining viable overload candidates as code-completion reslults.
+ typedef CodeCompleteConsumer::OverloadCandidate ResultCandidate;
+ llvm::SmallVector<ResultCandidate, 8> Results;
+
+ for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(),
+ CandEnd = CandidateSet.end();
+ Cand != CandEnd; ++Cand) {
+ if (Cand->Viable)
+ Results.push_back(ResultCandidate(Cand->Function));
+ }
+ CodeCompleter->ProcessOverloadCandidates(NumArgs, Results.data(),
+ Results.size());
+}
+
+void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS,
+ bool EnteringContext) {
+ if (!SS.getScopeRep() || !CodeCompleter)
+ return;
+
+ DeclContext *Ctx = computeDeclContext(SS, EnteringContext);
+ if (!Ctx)
+ return;
+
+ ResultBuilder Results(*this);
+ unsigned NextRank = CollectMemberLookupResults(Ctx, 0, Ctx, Results);
+
+ // The "template" keyword can follow "::" in the grammar, but only
+ // put it into the grammar if the nested-name-specifier is dependent.
+ NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep();
+ if (!Results.empty() && NNS->isDependent())
+ Results.MaybeAddResult(CodeCompleteConsumer::Result("template", NextRank));
+
+ HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size());
+}
+
+void Sema::CodeCompleteUsing(Scope *S) {
+ if (!CodeCompleter)
+ return;
+
+ ResultBuilder Results(*this, &ResultBuilder::IsNestedNameSpecifier);
+ Results.EnterNewScope();
+
+ // If we aren't in class scope, we could see the "namespace" keyword.
+ if (!S->isClassScope())
+ Results.MaybeAddResult(CodeCompleteConsumer::Result("namespace", 0));
+
+ // After "using", we can see anything that would start a
+ // nested-name-specifier.
+ CollectLookupResults(S, Context.getTranslationUnitDecl(), 0,
+ CurContext, Results);
+ Results.ExitScope();
+
+ HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size());
+}
+
+void Sema::CodeCompleteUsingDirective(Scope *S) {
+ if (!CodeCompleter)
+ return;
+
+ // After "using namespace", we expect to see a namespace name or namespace
+ // alias.
+ ResultBuilder Results(*this, &ResultBuilder::IsNamespaceOrAlias);
+ Results.EnterNewScope();
+ CollectLookupResults(S, Context.getTranslationUnitDecl(), 0, CurContext,
+ Results);
+ Results.ExitScope();
+ HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size());
+}
+
+void Sema::CodeCompleteNamespaceDecl(Scope *S) {
+ if (!CodeCompleter)
+ return;
+
+ ResultBuilder Results(*this, &ResultBuilder::IsNamespace);
+ DeclContext *Ctx = (DeclContext *)S->getEntity();
+ if (!S->getParent())
+ Ctx = Context.getTranslationUnitDecl();
+
+ if (Ctx && Ctx->isFileContext()) {
+ // We only want to see those namespaces that have already been defined
+ // within this scope, because its likely that the user is creating an
+ // extended namespace declaration. Keep track of the most recent
+ // definition of each namespace.
+ std::map<NamespaceDecl *, NamespaceDecl *> OrigToLatest;
+ for (DeclContext::specific_decl_iterator<NamespaceDecl>
+ NS(Ctx->decls_begin()), NSEnd(Ctx->decls_end());
+ NS != NSEnd; ++NS)
+ OrigToLatest[NS->getOriginalNamespace()] = *NS;
+
+ // Add the most recent definition (or extended definition) of each
+ // namespace to the list of results.
+ Results.EnterNewScope();
+ for (std::map<NamespaceDecl *, NamespaceDecl *>::iterator
+ NS = OrigToLatest.begin(), NSEnd = OrigToLatest.end();
+ NS != NSEnd; ++NS)
+ Results.MaybeAddResult(CodeCompleteConsumer::Result(NS->second, 0),
+ CurContext);
+ Results.ExitScope();
+ }
+
+ HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size());
+}
+
+void Sema::CodeCompleteNamespaceAliasDecl(Scope *S) {
+ if (!CodeCompleter)
+ return;
+
+ // After "namespace", we expect to see a namespace or alias.
+ ResultBuilder Results(*this, &ResultBuilder::IsNamespaceOrAlias);
+ CollectLookupResults(S, Context.getTranslationUnitDecl(), 0, CurContext,
+ Results);
+ HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size());
+}
+
+void Sema::CodeCompleteOperatorName(Scope *S) {
+ if (!CodeCompleter)
+ return;
+
+ typedef CodeCompleteConsumer::Result Result;
+ ResultBuilder Results(*this, &ResultBuilder::IsType);
+ Results.EnterNewScope();
+
+ // Add the names of overloadable operators.
+#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
+ if (std::strcmp(Spelling, "?")) \
+ Results.MaybeAddResult(Result(Spelling, 0));
+#include "clang/Basic/OperatorKinds.def"
+
+ // Add any type names visible from the current scope
+ unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(),
+ 0, CurContext, Results);
+
+ // Add any type specifiers
+ AddTypeSpecifierResults(getLangOptions(), 0, Results);
+
+ // Add any nested-name-specifiers
+ Results.setFilter(&ResultBuilder::IsNestedNameSpecifier);
+ CollectLookupResults(S, Context.getTranslationUnitDecl(), NextRank + 1,
+ CurContext, Results);
+ Results.ExitScope();
+
+ HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size());
+}
+
+void Sema::CodeCompleteObjCProperty(Scope *S, ObjCDeclSpec &ODS) {
+ if (!CodeCompleter)
+ return;
+ unsigned Attributes = ODS.getPropertyAttributes();
+
+ typedef CodeCompleteConsumer::Result Result;
+ ResultBuilder Results(*this);
+ Results.EnterNewScope();
+ if (!(Attributes & ObjCDeclSpec::DQ_PR_readonly))
+ Results.MaybeAddResult(CodeCompleteConsumer::Result("readonly", 0));
+ if (!(Attributes & ObjCDeclSpec::DQ_PR_assign))
+ Results.MaybeAddResult(CodeCompleteConsumer::Result("assign", 0));
+ if (!(Attributes & ObjCDeclSpec::DQ_PR_readwrite))
+ Results.MaybeAddResult(CodeCompleteConsumer::Result("readwrite", 0));
+ if (!(Attributes & ObjCDeclSpec::DQ_PR_retain))
+ Results.MaybeAddResult(CodeCompleteConsumer::Result("retain", 0));
+ if (!(Attributes & ObjCDeclSpec::DQ_PR_copy))
+ Results.MaybeAddResult(CodeCompleteConsumer::Result("copy", 0));
+ if (!(Attributes & ObjCDeclSpec::DQ_PR_nonatomic))
+ Results.MaybeAddResult(CodeCompleteConsumer::Result("nonatomic", 0));
+ if (!(Attributes & ObjCDeclSpec::DQ_PR_setter))
+ Results.MaybeAddResult(CodeCompleteConsumer::Result("setter", 0));
+ if (!(Attributes & ObjCDeclSpec::DQ_PR_getter))
+ Results.MaybeAddResult(CodeCompleteConsumer::Result("getter", 0));
+ Results.ExitScope();
+ HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size());
+}
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 1fd5697..606b33f 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -12,28 +12,34 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
-#include "SemaInherit.h"
#include "clang/AST/APValue.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtCXX.h"
+#include "clang/AST/StmtObjC.h"
#include "clang/Parse/DeclSpec.h"
-#include "clang/Basic/TargetInfo.h"
+#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
// FIXME: layering (ideally, Sema shouldn't be dependent on Lex API's)
#include "clang/Lex/Preprocessor.h"
-#include "clang/Lex/HeaderSearch.h"
-#include "llvm/ADT/SmallSet.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/STLExtras.h"
#include <algorithm>
+#include <cstring>
#include <functional>
+#include <queue>
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.
+/// 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))
@@ -57,7 +63,8 @@ Sema::DeclGroupPtrTy Sema::ConvertDeclToDeclGroup(DeclPtrTy Ptr) {
/// 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) {
+ Scope *S, const CXXScopeSpec *SS,
+ bool isClassName) {
// 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)
@@ -67,11 +74,20 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
//
// 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;
+ if (SS && isUnknownSpecialization(*SS)) {
+ if (!isClassName)
+ return 0;
+
+ // We know from the grammar that this name refers to a type, so build a
+ // TypenameType node to describe the type.
+ // FIXME: Record somewhere that this TypenameType node has no "typename"
+ // keyword associated with it.
+ return CheckTypenameType((NestedNameSpecifier *)SS->getScopeRep(),
+ II, SS->getRange()).getAsOpaquePtr();
+ }
- LookupResult Result
- = LookupParsedName(S, SS, &II, LookupOrdinaryName, false, false);
+ LookupResult Result;
+ LookupParsedName(Result, S, SS, &II, LookupOrdinaryName, false, false);
NamedDecl *IIDecl = 0;
switch (Result.getKind()) {
@@ -79,15 +95,21 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
case LookupResult::FoundOverloaded:
return 0;
- case LookupResult::AmbiguousBaseSubobjectTypes:
- case LookupResult::AmbiguousBaseSubobjects:
- case LookupResult::AmbiguousReference: {
+ case LookupResult::Ambiguous: {
+ // Recover from type-hiding ambiguities by hiding the type. We'll
+ // do the lookup again when looking for an object, and we can
+ // diagnose the error then. If we don't do this, then the error
+ // about hiding the type will be immediately followed by an error
+ // that only makes sense if the identifier was treated like a type.
+ if (Result.getAmbiguityKind() == LookupResult::AmbiguousTagHiding)
+ return 0;
+
// 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() <
+ if (!IIDecl ||
+ (*Res)->getLocation().getRawEncoding() <
IIDecl->getLocation().getRawEncoding())
IIDecl = *Res;
}
@@ -100,7 +122,6 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
// 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;
}
@@ -113,17 +134,17 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
}
case LookupResult::Found:
- IIDecl = Result.getAsDecl();
+ IIDecl = Result.getFoundDecl();
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
@@ -143,7 +164,7 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
} 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;
@@ -164,9 +185,10 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
/// 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);
+ LookupResult R;
+ LookupName(R, S, &II, LookupTagName, false, false);
if (R.getKind() == LookupResult::Found)
- if (const TagDecl *TD = dyn_cast<TagDecl>(R.getAsDecl())) {
+ if (const TagDecl *TD = dyn_cast<TagDecl>(R.getAsSingleDecl(Context))) {
switch (TD->getTagKind()) {
case TagDecl::TK_struct: return DeclSpec::TST_struct;
case TagDecl::TK_union: return DeclSpec::TST_union;
@@ -174,24 +196,60 @@ DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) {
case TagDecl::TK_enum: return DeclSpec::TST_enum;
}
}
-
+
return DeclSpec::TST_unspecified;
}
+bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II,
+ SourceLocation IILoc,
+ Scope *S,
+ const CXXScopeSpec *SS,
+ TypeTy *&SuggestedType) {
+ // We don't have anything to suggest (yet).
+ SuggestedType = 0;
+
+ // FIXME: Should we move the logic that tries to recover from a missing tag
+ // (struct, union, enum) from Parser::ParseImplicitInt here, instead?
+
+ if (!SS)
+ Diag(IILoc, diag::err_unknown_typename) << &II;
+ else if (DeclContext *DC = computeDeclContext(*SS, false))
+ Diag(IILoc, diag::err_typename_nested_not_found)
+ << &II << DC << SS->getRange();
+ else if (isDependentScopeSpecifier(*SS)) {
+ Diag(SS->getRange().getBegin(), diag::err_typename_missing)
+ << (NestedNameSpecifier *)SS->getScopeRep() << II.getName()
+ << SourceRange(SS->getRange().getBegin(), IILoc)
+ << CodeModificationHint::CreateInsertion(SS->getRange().getBegin(),
+ "typename ");
+ SuggestedType = ActOnTypenameType(SourceLocation(), *SS, II, IILoc).get();
+ } else {
+ assert(SS && SS->isInvalid() &&
+ "Invalid scope specifier has already been diagnosed");
+ }
+
+ return true;
+}
-
+// Determines the context to return to after temporarily entering a
+// context. This depends in an unnecessarily complicated way on the
+// exact ordering of callbacks from the parser.
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->isOutOfLine())
- 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();
+
+ // Functions defined inline within classes aren't parsed until we've
+ // finished parsing the top-level class, so the top-level class is
+ // the context we'll need to return to.
+ if (isa<FunctionDecl>(DC)) {
+ DC = DC->getLexicalParent();
+
+ // A function not defined within a class will always return to its
+ // lexical context.
+ if (!isa<CXXRecordDecl>(DC))
+ return DC;
+
+ // A C++ inline method/friend is parsed *after* the topmost class
+ // it was declared in is fully parsed ("complete"); the topmost
+ // class is the context we need to return to.
while (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC->getLexicalParent()))
DC = RD;
@@ -260,103 +318,84 @@ static bool AllowOverloadingOfFunction(Decl *PrevDecl, ASTContext &Context) {
}
/// Add this decl to the scope shadowed decl chains.
-void Sema::PushOnScopeChains(NamedDecl *D, Scope *S) {
+void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) {
// 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() &&
+ 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(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;
- }
- }
- }
+ if (AddToContext)
+ CurContext->addDecl(D);
- // 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)) ||
- isa<FunctionTemplateDecl>(D)) {
- // We are pushing the name of a function or function template,
- // which might be an overloaded name.
- IdentifierResolver::iterator Redecl
- = std::find_if(IdResolver.begin(D->getDeclName()),
- IdResolver.end(),
- std::bind1st(std::mem_fun(&NamedDecl::declarationReplaces),
- D));
- 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;
- }
+ // Out-of-line function and variable definitions should not be pushed into
+ // scope.
+ if ((isa<FunctionTemplateDecl>(D) &&
+ cast<FunctionTemplateDecl>(D)->getTemplatedDecl()->isOutOfLine()) ||
+ (isa<FunctionDecl>(D) && cast<FunctionDecl>(D)->isOutOfLine()) ||
+ (isa<VarDecl>(D) && cast<VarDecl>(D)->isOutOfLine()))
+ return;
+
+ // If this replaces anything in the current scope,
+ IdentifierResolver::iterator I = IdResolver.begin(D->getDeclName()),
+ IEnd = IdResolver.end();
+ for (; I != IEnd; ++I) {
+ if (S->isDeclScope(DeclPtrTy::make(*I)) && D->declarationReplaces(*I)) {
+ S->RemoveDecl(DeclPtrTy::make(*I));
+ IdResolver.RemoveDecl(*I);
+
+ // Should only need to replace one decl.
+ break;
}
}
+ S->AddDecl(DeclPtrTy::make(D));
IdResolver.AddDecl(D);
}
+bool Sema::isDeclInScope(NamedDecl *&D, DeclContext *Ctx, Scope *S) {
+ if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(D)) {
+ // Look inside the overload set to determine if any of the declarations
+ // are in scope. (Possibly) build a new overload set containing only
+ // those declarations that are in scope.
+ OverloadedFunctionDecl *NewOvl = 0;
+ bool FoundInScope = false;
+ for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
+ FEnd = Ovl->function_end();
+ F != FEnd; ++F) {
+ NamedDecl *FD = F->get();
+ if (!isDeclInScope(FD, Ctx, S)) {
+ if (!NewOvl && F != Ovl->function_begin()) {
+ NewOvl = OverloadedFunctionDecl::Create(Context,
+ F->get()->getDeclContext(),
+ F->get()->getDeclName());
+ D = NewOvl;
+ for (OverloadedFunctionDecl::function_iterator
+ First = Ovl->function_begin();
+ First != F; ++First)
+ NewOvl->addOverload(*First);
+ }
+ } else {
+ FoundInScope = true;
+ if (NewOvl)
+ NewOvl->addOverload(*F);
+ }
+ }
+
+ return FoundInScope;
+ }
+
+ return IdResolver.isDeclInScope(D, Ctx, Context, S);
+}
+
void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
if (S->decl_empty()) return;
assert((S->getFlags() & (Scope::DeclScope | Scope::TemplateParamScope)) &&
- "Scope shouldn't contain decls!");
+ "Scope shouldn't contain decls!");
for (Scope::decl_iterator I = S->decl_begin(), E = S->decl_end();
I != E; ++I) {
@@ -368,6 +407,12 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
if (!D->getDeclName()) continue;
+ // Diagnose unused variables in this scope.
+ if (!D->isUsed() && !D->hasAttr<UnusedAttr>() && isa<VarDecl>(D) &&
+ !isa<ParmVarDecl>(D) && !isa<ImplicitParamDecl>(D) &&
+ D->getDeclContext()->isFunctionOrMethod())
+ Diag(D->getLocation(), diag::warn_unused_variable) << D->getDeclName();
+
// Remove this name from our lexical scope.
IdResolver.RemoveDecl(D);
}
@@ -378,8 +423,8 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
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);
-
+ NamedDecl *IDecl = LookupSingleName(TUScope, Id, LookupOrdinaryName);
+
return dyn_cast_or_null<ObjCInterfaceDecl>(IDecl);
}
@@ -392,7 +437,7 @@ ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *Id) {
/// struct S6 {
/// enum { BAR } e;
/// };
-///
+///
/// void test_S6() {
/// struct S6 a;
/// a.e = BAR;
@@ -408,7 +453,7 @@ ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *Id) {
/// contain non-field names.
Scope *Sema::getNonFieldDeclScope(Scope *S) {
while (((S->getFlags() & Scope::DeclScope) == 0) ||
- (S->getEntity() &&
+ (S->getEntity() &&
((DeclContext *)S->getEntity())->isTransparentContext()) ||
(S->isClassScope() && !getLangOptions().CPlusPlus))
S = S->getParent();
@@ -418,9 +463,9 @@ Scope *Sema::getNonFieldDeclScope(Scope *S) {
void Sema::InitBuiltinVaListType() {
if (!Context.getBuiltinVaListType().isNull())
return;
-
+
IdentifierInfo *VaIdent = &Context.Idents.get("__builtin_va_list");
- NamedDecl *VaDecl = LookupName(TUScope, VaIdent, LookupOrdinaryName);
+ NamedDecl *VaDecl = LookupSingleName(TUScope, VaIdent, LookupOrdinaryName);
TypedefDecl *VaTypedef = cast<TypedefDecl>(VaDecl);
Context.setBuiltinVaListType(Context.getTypedefType(VaTypedef));
}
@@ -438,17 +483,23 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
InitBuiltinVaListType();
ASTContext::GetBuiltinTypeError Error;
- QualType R = Context.GetBuiltinType(BID, Error);
+ QualType R = Context.GetBuiltinType(BID, Error);
switch (Error) {
case ASTContext::GE_None:
// Okay
break;
- case ASTContext::GE_Missing_FILE:
+ case ASTContext::GE_Missing_stdio:
if (ForRedeclaration)
Diag(Loc, diag::err_implicit_decl_requires_stdio)
<< Context.BuiltinInfo.GetName(BID);
return 0;
+
+ case ASTContext::GE_Missing_setjmp:
+ if (ForRedeclaration)
+ Diag(Loc, diag::err_implicit_decl_requires_setjmp)
+ << Context.BuiltinInfo.GetName(BID);
+ return 0;
}
if (!ForRedeclaration && Context.BuiltinInfo.isPredefinedLibFunction(BID)) {
@@ -465,7 +516,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
FunctionDecl *New = FunctionDecl::Create(Context,
Context.getTranslationUnitDecl(),
- Loc, II, R,
+ Loc, II, R, /*DInfo=*/0,
FunctionDecl::Extern, false,
/*hasPrototype=*/true);
New->setImplicit();
@@ -476,12 +527,13 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
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));
+ FT->getArgType(i), /*DInfo=*/0,
+ VarDecl::None, 0));
New->setParams(Context, Params.data(), Params.size());
}
-
- AddKnownFunctionAttributes(New);
-
+
+ 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
@@ -493,18 +545,6 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
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
@@ -515,25 +555,26 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) {
// 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:
+ case 2:
if (!TypeID->isStr("id"))
break;
- Context.setObjCIdType(Context.getTypeDeclType(New));
- objc_types = true;
- break;
+ Context.ObjCIdRedefinitionType = New->getUnderlyingType();
+ // Install the built-in type for 'id', ignoring the current definition.
+ New->setTypeForDecl(Context.getObjCIdType().getTypePtr());
+ return;
case 5:
if (!TypeID->isStr("Class"))
break;
- Context.setObjCClassType(Context.getTypeDeclType(New));
+ Context.ObjCClassRedefinitionType = New->getUnderlyingType();
+ // Install the built-in type for 'Class', ignoring the current definition.
+ New->setTypeForDecl(Context.getObjCClassType().getTypePtr());
return;
case 3:
if (!TypeID->isStr("SEL"))
@@ -551,14 +592,14 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) {
// Verify the old decl was also a type.
TypeDecl *Old = dyn_cast<TypeDecl>(OldD);
if (!Old) {
- Diag(New->getLocation(), diag::err_redefinition_different_kind)
+ 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.
+ // Determine the "old" type we'll use for checking and diagnostics.
QualType OldType;
if (TypedefDecl *OldTypedef = dyn_cast<TypedefDecl>(Old))
OldType = OldTypedef->getUnderlyingType();
@@ -568,8 +609,8 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) {
// If the typedef types are not identical, reject them in all languages and
// with any extensions enabled.
- if (OldType != New->getUnderlyingType() &&
- Context.getCanonicalType(OldType) !=
+ if (OldType != New->getUnderlyingType() &&
+ Context.getCanonicalType(OldType) !=
Context.getCanonicalType(New->getUnderlyingType())) {
Diag(New->getLocation(), diag::err_redefinition_different_typedef)
<< New->getUnderlyingType() << OldType;
@@ -577,8 +618,8 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) {
Diag(Old->getLocation(), diag::note_previous_definition);
return New->setInvalidDecl();
}
-
- if (objc_types || getLangOptions().Microsoft)
+
+ if (getLangOptions().Microsoft)
return;
// C++ [dcl.typedef]p2:
@@ -602,7 +643,7 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) {
(Context.getSourceManager().isInSystemHeader(Old->getLocation()) ||
Context.getSourceManager().isInSystemHeader(New->getLocation())))
return;
-
+
Diag(New->getLocation(), diag::warn_redefinition_of_typedef)
<< New->getDeclName();
Diag(Old->getLocation(), diag::note_previous_definition);
@@ -611,7 +652,7 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) {
/// DeclhasAttr - returns true if decl Declaration already has the target
/// attribute.
-static bool
+static bool
DeclHasAttr(const Decl *decl, const Attr *target) {
for (const Attr *attr = decl->getAttrs(); attr; attr = attr->getNext())
if (attr->getKind() == target->getKind())
@@ -651,15 +692,15 @@ struct GNUCompatibleParamWarning {
///
/// Returns true if there was an error, false otherwise.
bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
- assert(!isa<OverloadedFunctionDecl>(OldD) &&
+ assert(!isa<OverloadedFunctionDecl>(OldD) &&
"Cannot merge with an overloaded function declaration");
// Verify the old decl was also a function.
FunctionDecl *Old = 0;
- if (FunctionTemplateDecl *OldFunctionTemplate
+ if (FunctionTemplateDecl *OldFunctionTemplate
= dyn_cast<FunctionTemplateDecl>(OldD))
Old = OldFunctionTemplate->getTemplatedDecl();
- else
+ else
Old = dyn_cast<FunctionDecl>(OldD);
if (!Old) {
Diag(New->getLocation(), diag::err_redefinition_different_kind)
@@ -675,12 +716,12 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
PrevDiag = diag::note_previous_definition;
else if (Old->isImplicit())
PrevDiag = diag::note_previous_implicit_declaration;
- else
+ 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) {
@@ -693,11 +734,11 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
if (getLangOptions().CPlusPlus) {
// (C++98 13.1p2):
// Certain function declarations cannot be overloaded:
- // -- Function declarations that differ only in the return type
+ // -- Function declarations that differ only in the return type
// cannot be overloaded.
- QualType OldReturnType
+ QualType OldReturnType
= cast<FunctionType>(OldQType.getTypePtr())->getResultType();
- QualType NewReturnType
+ QualType NewReturnType
= cast<FunctionType>(NewQType.getTypePtr())->getResultType();
if (OldReturnType != NewReturnType) {
Diag(New->getLocation(), diag::err_ovl_diff_return_type);
@@ -707,11 +748,10 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
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
+ if (OldMethod && NewMethod && !NewMethod->getFriendObjectKind() &&
+ NewMethod->getLexicalDeclContext()->isRecord()) {
+ // -- 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);
@@ -732,7 +772,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
NewDiag = diag::err_conv_function_redeclared;
else
NewDiag = diag::err_member_redeclared;
-
+
Diag(New->getLocation(), NewDiag);
Diag(Old->getLocation(), PrevDiag) << Old << Old->getType();
}
@@ -750,8 +790,8 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
// 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 FunctionType *OldFuncType = OldQType->getAs<FunctionType>();
+ const FunctionType *NewFuncType = NewQType->getAs<FunctionType>();
const FunctionProtoType *OldProto = 0;
if (isa<FunctionNoProtoType>(NewFuncType) &&
(OldProto = dyn_cast<FunctionProtoType>(OldFuncType))) {
@@ -769,20 +809,20 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
// Synthesize a parameter for each argument type.
llvm::SmallVector<ParmVarDecl*, 16> Params;
- for (FunctionProtoType::arg_type_iterator
- ParamType = OldProto->arg_type_begin(),
+ 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);
+ *ParamType, /*DInfo=*/0,
+ VarDecl::None, 0);
Param->setImplicit();
Params.push_back(Param);
}
New->setParams(Context, Params.data(), Params.size());
- }
+ }
return MergeCompatibleFunctionDecls(New, Old);
}
@@ -800,29 +840,29 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
// C99 6.9.1p8.
if (!getLangOptions().CPlusPlus &&
Old->hasPrototype() && !New->hasPrototype() &&
- New->getType()->getAsFunctionProtoType() &&
+ New->getType()->getAs<FunctionProtoType>() &&
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();
-
+ const FunctionProtoType *OldProto
+ = Old->getType()->getAs<FunctionProtoType>();
+ const FunctionProtoType *NewProto
+ = New->getType()->getAs<FunctionProtoType>();
+
// 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();
+ 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(),
+ if (Context.typesAreCompatible(OldParm->getType(),
NewProto->getArgType(Idx))) {
ArgTypes.push_back(NewParm->getType());
} else if (Context.typesAreCompatible(OldParm->getType(),
NewParm->getType())) {
- GNUCompatibleParamWarning Warn
+ GNUCompatibleParamWarning Warn
= { OldParm, NewParm, NewProto->getArgType(Idx) };
Warnings.push_back(Warn);
ArgTypes.push_back(NewParm->getType());
@@ -836,7 +876,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
diag::ext_param_promoted_not_compatible_with_prototype)
<< Warnings[Warn].PromotedType
<< Warnings[Warn].OldParm->getType();
- Diag(Warnings[Warn].OldParm->getLocation(),
+ Diag(Warnings[Warn].OldParm->getLocation(),
diag::note_previous_declaration);
}
@@ -851,7 +891,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
// 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)) {
+ if (unsigned BuiltinID = Old->getBuiltinID()) {
// The user has declared a builtin function with an incompatible
// signature.
if (Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) {
@@ -876,7 +916,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
}
/// \brief Completes the merge of two function declarations that are
-/// known to be compatible.
+/// known to be compatible.
///
/// This routine handles the merging of attributes and other
/// properties of function declarations form the old declaration to
@@ -889,25 +929,10 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) {
MergeAttributes(New, Old, Context);
// Merge the storage class.
- if (Old->getStorageClass() != FunctionDecl::Extern)
+ if (Old->getStorageClass() != FunctionDecl::Extern &&
+ Old->getStorageClass() != FunctionDecl::None)
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();
@@ -915,7 +940,7 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) {
// Merge the "deleted" flag.
if (Old->isDeleted())
New->setDeleted();
-
+
if (getLangOptions().CPlusPlus)
return MergeCXXFunctionDecl(New, Old);
@@ -926,16 +951,16 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) {
/// 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
+/// 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) {
@@ -952,11 +977,24 @@ void Sema::MergeVarDecl(VarDecl *New, Decl *OldD) {
if (getLangOptions().CPlusPlus) {
if (Context.hasSameType(New->getType(), Old->getType()))
MergedT = New->getType();
+ // C++ [basic.types]p7:
+ // [...] The declared type of an array object might be an array of
+ // unknown size and therefore be incomplete at one point in a
+ // translation unit and complete later on; [...]
+ else if (Old->getType()->isIncompleteArrayType() &&
+ New->getType()->isArrayType()) {
+ CanQual<ArrayType> OldArray
+ = Context.getCanonicalType(Old->getType())->getAs<ArrayType>();
+ CanQual<ArrayType> NewArray
+ = Context.getCanonicalType(New->getType())->getAs<ArrayType>();
+ if (OldArray->getElementType() == NewArray->getElementType())
+ MergedT = New->getType();
+ }
} else {
MergedT = Context.mergeTypes(New->getType(), Old->getType());
}
if (MergedT.isNull()) {
- Diag(New->getLocation(), diag::err_redefinition_different_type)
+ Diag(New->getLocation(), diag::err_redefinition_different_type)
<< New->getDeclName();
Diag(Old->getLocation(), diag::note_previous_definition);
return New->setInvalidDecl();
@@ -970,7 +1008,7 @@ void Sema::MergeVarDecl(VarDecl *New, Decl *OldD) {
Diag(Old->getLocation(), diag::note_previous_definition);
return New->setInvalidDecl();
}
- // C99 6.2.2p4:
+ // 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
@@ -989,7 +1027,7 @@ void Sema::MergeVarDecl(VarDecl *New, Decl *OldD) {
}
// 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() &&
@@ -1013,6 +1051,214 @@ void Sema::MergeVarDecl(VarDecl *New, Decl *OldD) {
New->setPreviousDeclaration(Old);
}
+/// CheckFallThrough - Check that we don't fall off the end of a
+/// Statement that should return a value.
+///
+/// \returns AlwaysFallThrough iff we always fall off the end of the statement,
+/// MaybeFallThrough iff we might or might not fall off the end and
+/// NeverFallThrough iff we never fall off the end of the statement. We assume
+/// that functions not marked noreturn will return.
+Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) {
+ llvm::OwningPtr<CFG> cfg (CFG::buildCFG(Root, &Context));
+
+ // FIXME: They should never return 0, fix that, delete this code.
+ if (cfg == 0)
+ return NeverFallThrough;
+ // The CFG leaves in dead things, and we don't want to dead code paths to
+ // confuse us, so we mark all live things first.
+ std::queue<CFGBlock*> workq;
+ llvm::BitVector live(cfg->getNumBlockIDs());
+ // Prep work queue
+ workq.push(&cfg->getEntry());
+ // Solve
+ while (!workq.empty()) {
+ CFGBlock *item = workq.front();
+ workq.pop();
+ live.set(item->getBlockID());
+ for (CFGBlock::succ_iterator I=item->succ_begin(),
+ E=item->succ_end();
+ I != E;
+ ++I) {
+ if ((*I) && !live[(*I)->getBlockID()]) {
+ live.set((*I)->getBlockID());
+ workq.push(*I);
+ }
+ }
+ }
+
+ // Now we know what is live, we check the live precessors of the exit block
+ // and look for fall through paths, being careful to ignore normal returns,
+ // and exceptional paths.
+ bool HasLiveReturn = false;
+ bool HasFakeEdge = false;
+ bool HasPlainEdge = false;
+ for (CFGBlock::succ_iterator I=cfg->getExit().pred_begin(),
+ E = cfg->getExit().pred_end();
+ I != E;
+ ++I) {
+ CFGBlock& B = **I;
+ if (!live[B.getBlockID()])
+ continue;
+ if (B.size() == 0) {
+ // A labeled empty statement, or the entry block...
+ HasPlainEdge = true;
+ continue;
+ }
+ Stmt *S = B[B.size()-1];
+ if (isa<ReturnStmt>(S)) {
+ HasLiveReturn = true;
+ continue;
+ }
+ if (isa<ObjCAtThrowStmt>(S)) {
+ HasFakeEdge = true;
+ continue;
+ }
+ if (isa<CXXThrowExpr>(S)) {
+ HasFakeEdge = true;
+ continue;
+ }
+ bool NoReturnEdge = false;
+ if (CallExpr *C = dyn_cast<CallExpr>(S)) {
+ Expr *CEE = C->getCallee()->IgnoreParenCasts();
+ if (CEE->getType().getNoReturnAttr()) {
+ NoReturnEdge = true;
+ HasFakeEdge = true;
+ } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) {
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(DRE->getDecl())) {
+ if (FD->hasAttr<NoReturnAttr>()) {
+ NoReturnEdge = true;
+ HasFakeEdge = true;
+ }
+ }
+ }
+ }
+ // FIXME: Add noreturn message sends.
+ if (NoReturnEdge == false)
+ HasPlainEdge = true;
+ }
+ if (!HasPlainEdge)
+ return NeverFallThrough;
+ if (HasFakeEdge || HasLiveReturn)
+ return MaybeFallThrough;
+ // This says AlwaysFallThrough for calls to functions that are not marked
+ // noreturn, that don't return. If people would like this warning to be more
+ // accurate, such functions should be marked as noreturn.
+ return AlwaysFallThrough;
+}
+
+/// CheckFallThroughForFunctionDef - Check that we don't fall off the end of a
+/// function that should return a value. Check that we don't fall off the end
+/// of a noreturn function. We assume that functions and blocks not marked
+/// noreturn will return.
+void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body) {
+ // FIXME: Would be nice if we had a better way to control cascading errors,
+ // but for now, avoid them. The problem is that when Parse sees:
+ // int foo() { return a; }
+ // The return is eaten and the Sema code sees just:
+ // int foo() { }
+ // which this code would then warn about.
+ if (getDiagnostics().hasErrorOccurred())
+ return;
+ bool ReturnsVoid = false;
+ bool HasNoReturn = false;
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ // If the result type of the function is a dependent type, we don't know
+ // whether it will be void or not, so don't
+ if (FD->getResultType()->isDependentType())
+ return;
+ if (FD->getResultType()->isVoidType())
+ ReturnsVoid = true;
+ if (FD->hasAttr<NoReturnAttr>())
+ HasNoReturn = true;
+ } else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ if (MD->getResultType()->isVoidType())
+ ReturnsVoid = true;
+ if (MD->hasAttr<NoReturnAttr>())
+ HasNoReturn = true;
+ }
+
+ // Short circuit for compilation speed.
+ if ((Diags.getDiagnosticLevel(diag::warn_maybe_falloff_nonvoid_function)
+ == Diagnostic::Ignored || ReturnsVoid)
+ && (Diags.getDiagnosticLevel(diag::warn_noreturn_function_has_return_expr)
+ == Diagnostic::Ignored || !HasNoReturn)
+ && (Diags.getDiagnosticLevel(diag::warn_suggest_noreturn_block)
+ == Diagnostic::Ignored || !ReturnsVoid))
+ return;
+ // FIXME: Function try block
+ if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) {
+ switch (CheckFallThrough(Body)) {
+ case MaybeFallThrough:
+ if (HasNoReturn)
+ Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function);
+ else if (!ReturnsVoid)
+ Diag(Compound->getRBracLoc(),diag::warn_maybe_falloff_nonvoid_function);
+ break;
+ case AlwaysFallThrough:
+ if (HasNoReturn)
+ Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function);
+ else if (!ReturnsVoid)
+ Diag(Compound->getRBracLoc(), diag::warn_falloff_nonvoid_function);
+ break;
+ case NeverFallThrough:
+ if (ReturnsVoid)
+ Diag(Compound->getLBracLoc(), diag::warn_suggest_noreturn_function);
+ break;
+ }
+ }
+}
+
+/// CheckFallThroughForBlock - Check that we don't fall off the end of a block
+/// that should return a value. Check that we don't fall off the end of a
+/// noreturn block. We assume that functions and blocks not marked noreturn
+/// will return.
+void Sema::CheckFallThroughForBlock(QualType BlockTy, Stmt *Body) {
+ // FIXME: Would be nice if we had a better way to control cascading errors,
+ // but for now, avoid them. The problem is that when Parse sees:
+ // int foo() { return a; }
+ // The return is eaten and the Sema code sees just:
+ // int foo() { }
+ // which this code would then warn about.
+ if (getDiagnostics().hasErrorOccurred())
+ return;
+ bool ReturnsVoid = false;
+ bool HasNoReturn = false;
+ if (const FunctionType *FT = BlockTy->getPointeeType()->getAs<FunctionType>()) {
+ if (FT->getResultType()->isVoidType())
+ ReturnsVoid = true;
+ if (FT->getNoReturnAttr())
+ HasNoReturn = true;
+ }
+
+ // Short circuit for compilation speed.
+ if (ReturnsVoid
+ && !HasNoReturn
+ && (Diags.getDiagnosticLevel(diag::warn_suggest_noreturn_block)
+ == Diagnostic::Ignored || !ReturnsVoid))
+ return;
+ // FIXME: Funtion try block
+ if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) {
+ switch (CheckFallThrough(Body)) {
+ case MaybeFallThrough:
+ if (HasNoReturn)
+ Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr);
+ else if (!ReturnsVoid)
+ Diag(Compound->getRBracLoc(), diag::err_maybe_falloff_nonvoid_block);
+ break;
+ case AlwaysFallThrough:
+ if (HasNoReturn)
+ Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr);
+ else if (!ReturnsVoid)
+ Diag(Compound->getRBracLoc(), diag::err_falloff_nonvoid_block);
+ break;
+ case NeverFallThrough:
+ if (ReturnsVoid)
+ Diag(Compound->getLBracLoc(), diag::warn_suggest_noreturn_block);
+ break;
+ }
+ }
+}
+
/// 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
@@ -1034,10 +1280,10 @@ bool Sema::CheckParmsForFunctionDef(FunctionDecl *FD) {
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 &&
+ if (Param->getIdentifier() == 0 &&
!Param->isImplicit() &&
!getLangOptions().CPlusPlus)
Diag(Param->getLocation(), diag::err_parameter_name_omitted);
@@ -1056,17 +1302,31 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) {
// FIXME: Warn on useless const/volatile
// FIXME: Warn on useless static/extern/typedef/private_extern/mutable
// FIXME: Warn on useless attributes
+ Decl *TagD = 0;
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
+ TagD = static_cast<Decl *>(DS.getTypeRep());
+
+ if (!TagD) // We probably had an error
return DeclPtrTy();
- Tag = dyn_cast<TagDecl>(static_cast<Decl *>(DS.getTypeRep()));
+ // Note that the above type specs guarantee that the
+ // type rep is a Decl, whereas in many of the others
+ // it's a Type.
+ Tag = dyn_cast<TagDecl>(TagD);
}
+ if (DS.isFriendSpecified()) {
+ // If we're dealing with a class template decl, assume that the
+ // template routines are handling it.
+ if (TagD && isa<ClassTemplateDecl>(TagD))
+ return DeclPtrTy();
+ return ActOnFriendTypeDecl(S, DS, MultiTemplateParamsArg(*this, 0, 0));
+ }
+
if (RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag)) {
if (!Record->getDeclName() && Record->isDefinition() &&
DS.getStorageClassSpec() != DeclSpec::SCS_typedef) {
@@ -1084,8 +1344,8 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) {
if (Record->getDeclName() && getLangOptions().Microsoft)
return DeclPtrTy::make(Tag);
}
-
- if (!DS.isMissingDeclaratorOk() &&
+
+ 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.
@@ -1100,7 +1360,7 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) {
<< DS.getSourceRange();
return DeclPtrTy();
}
-
+
return DeclPtrTy::make(Tag);
}
@@ -1127,14 +1387,16 @@ bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner,
FEnd = AnonRecord->field_end();
F != FEnd; ++F) {
if ((*F)->getDeclName()) {
- NamedDecl *PrevDecl = LookupQualifiedName(Owner, (*F)->getDeclName(),
- LookupOrdinaryName, true);
+ LookupResult R;
+ LookupQualifiedName(R, Owner, (*F)->getDeclName(),
+ LookupOrdinaryName, true);
+ NamedDecl *PrevDecl = R.getAsSingleDecl(Context);
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
+ unsigned diagKind
= AnonRecord->isUnion()? diag::err_anonymous_union_member_redecl
: diag::err_anonymous_struct_member_redecl;
Diag((*F)->getLocation(), diagKind)
@@ -1152,10 +1414,10 @@ bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner,
IdResolver.AddDecl(*F);
}
} else if (const RecordType *InnerRecordType
- = (*F)->getType()->getAsRecordType()) {
+ = (*F)->getType()->getAs<RecordType>()) {
RecordDecl *InnerRecord = InnerRecordType->getDecl();
if (InnerRecord->isAnonymousStructOrUnion())
- Invalid = Invalid ||
+ Invalid = Invalid ||
InjectAnonymousStructOrUnionMembers(S, Owner, InnerRecord);
}
}
@@ -1166,7 +1428,7 @@ bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner,
/// 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.
+/// are a GNU C and GNU C++ extension.
Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
RecordDecl *Record) {
DeclContext *Owner = Record->getDeclContext();
@@ -1176,40 +1438,42 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
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;
+ unsigned DiagID;
// 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) &&
+ (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);
- }
+ DS.SetStorageClassSpec(DeclSpec::SCS_static, SourceLocation(),
+ PrevSpec, DiagID);
+ }
// 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(DS.getStorageClassSpecLoc(),
diag::err_anonymous_union_with_storage_spec);
Invalid = true;
// Recover by removing the storage specifier.
DS.SetStorageClassSpec(DeclSpec::SCS_unspecified, SourceLocation(),
- PrevSpec);
+ PrevSpec, DiagID);
}
- // C++ [class.union]p2:
+ // 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. ]
@@ -1255,7 +1519,7 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
Invalid = true;
}
}
- }
+ }
if (!Record->isUnion() && !Owner->isRecord()) {
Diag(Record->getLocation(), diag::err_anonymous_struct_not_member)
@@ -1263,12 +1527,14 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
Invalid = true;
}
- // Create a declaration for this anonymous struct/union.
+ // 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,
+ /*IdentifierInfo=*/0,
Context.getTypeDeclType(Record),
+ // FIXME: Type source info.
+ /*DInfo=*/0,
/*BitWidth=*/0, /*Mutable=*/false);
Anon->setAccess(AS_public);
if (getLangOptions().CPlusPlus)
@@ -1293,9 +1559,11 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
}
Anon = VarDecl::Create(Context, Owner, Record->getLocation(),
- /*IdentifierInfo=*/0,
+ /*IdentifierInfo=*/0,
Context.getTypeDeclType(Record),
- SC, DS.getSourceRange().getBegin());
+ // FIXME: Type source info.
+ /*DInfo=*/0,
+ SC);
}
Anon->setImplicit();
@@ -1315,7 +1583,7 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
// 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.
+ // InjectAnonymousStructOrUnionMembers.
Record->setAnonymousStructOrUnion(true);
if (Invalid)
@@ -1338,28 +1606,39 @@ DeclarationName Sema::GetNameForDeclarator(Declarator &D) {
return DeclarationName(D.getIdentifier());
case Declarator::DK_Constructor: {
- QualType Ty = QualType::getFromOpaquePtr(D.getDeclaratorIdType());
- Ty = Context.getCanonicalType(Ty);
- return Context.DeclarationNames.getCXXConstructorName(Ty);
+ QualType Ty = GetTypeFromParser(D.getDeclaratorIdType());
+ return Context.DeclarationNames.getCXXConstructorName(
+ Context.getCanonicalType(Ty));
}
case Declarator::DK_Destructor: {
- QualType Ty = QualType::getFromOpaquePtr(D.getDeclaratorIdType());
- Ty = Context.getCanonicalType(Ty);
- return Context.DeclarationNames.getCXXDestructorName(Ty);
+ QualType Ty = GetTypeFromParser(D.getDeclaratorIdType());
+ return Context.DeclarationNames.getCXXDestructorName(
+ Context.getCanonicalType(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);
+ QualType Ty = GetTypeFromParser(D.getDeclaratorIdType());
+ return Context.DeclarationNames.getCXXConversionFunctionName(
+ Context.getCanonicalType(Ty));
}
case Declarator::DK_Operator:
assert(D.getIdentifier() == 0 && "operator names have no identifier");
return Context.DeclarationNames.getCXXOperatorName(
D.getOverloadedOperator());
+
+ case Declarator::DK_TemplateId: {
+ TemplateName Name
+ = TemplateName::getFromVoidPointer(D.getTemplateId()->Template);
+ if (TemplateDecl *Template = Name.getAsTemplateDecl())
+ return Template->getDeclName();
+ if (OverloadedFunctionDecl *Ovl = Name.getAsOverloadedFunctionDecl())
+ return Ovl->getDeclName();
+
+ return DeclarationName();
+ }
}
assert(false && "Unknown name kind");
@@ -1389,8 +1668,8 @@ static bool isNearlyMatchingFunction(ASTContext &Context,
return true;
}
-Sema::DeclPtrTy
-Sema::HandleDeclarator(Scope *S, Declarator &D,
+Sema::DeclPtrTy
+Sema::HandleDeclarator(Scope *S, Declarator &D,
MultiTemplateParamsArg TemplateParamLists,
bool IsFunctionDefinition) {
DeclarationName Name = GetNameForDeclarator(D);
@@ -1404,18 +1683,44 @@ Sema::HandleDeclarator(Scope *S, Declarator &D,
<< 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();
-
+
+ // If this is an out-of-line definition of a member of a class template
+ // or class template partial specialization, we may need to rebuild the
+ // type specifier in the declarator. See RebuildTypeInCurrentInstantiation()
+ // for more information.
+ // FIXME: cope with decltype(expr) and typeof(expr) once the rebuilder can
+ // handle expressions properly.
+ DeclSpec &DS = const_cast<DeclSpec&>(D.getDeclSpec());
+ if (D.getCXXScopeSpec().isSet() && !D.getCXXScopeSpec().isInvalid() &&
+ isDependentScopeSpecifier(D.getCXXScopeSpec()) &&
+ (DS.getTypeSpecType() == DeclSpec::TST_typename ||
+ DS.getTypeSpecType() == DeclSpec::TST_typeofType ||
+ DS.getTypeSpecType() == DeclSpec::TST_typeofExpr ||
+ DS.getTypeSpecType() == DeclSpec::TST_decltype)) {
+ if (DeclContext *DC = computeDeclContext(D.getCXXScopeSpec(), true)) {
+ // FIXME: Preserve type source info.
+ QualType T = GetTypeFromParser(DS.getTypeRep());
+ EnterDeclaratorContext(S, DC);
+ T = RebuildTypeInCurrentInstantiation(T, D.getIdentifierLoc(), Name);
+ ExitDeclaratorContext(S);
+ if (T.isNull())
+ return DeclPtrTy();
+ DS.UpdateTypeRep(T.getAsOpaquePtr());
+ }
+ }
+
DeclContext *DC;
NamedDecl *PrevDecl;
NamedDecl *New;
- QualType R = GetTypeForDeclarator(D, S);
+ DeclaratorInfo *DInfo = 0;
+ QualType R = GetTypeForDeclarator(D, S, &DInfo);
// See if this is a redefinition of a variable in the same scope.
if (D.getCXXScopeSpec().isInvalid()) {
@@ -1431,20 +1736,43 @@ Sema::HandleDeclarator(Scope *S, Declarator &D,
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef)
/* Do nothing*/;
else if (R->isFunctionType()) {
- if (CurContext->isFunctionOrMethod())
+ if (CurContext->isFunctionOrMethod() ||
+ D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static)
NameKind = LookupRedeclarationWithLinkage;
} else if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_extern)
NameKind = LookupRedeclarationWithLinkage;
+ else if (CurContext->getLookupContext()->isTranslationUnit() &&
+ D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static)
+ NameKind = LookupRedeclarationWithLinkage;
DC = CurContext;
- PrevDecl = LookupName(S, Name, NameKind, true,
- D.getDeclSpec().getStorageClassSpec() !=
- DeclSpec::SCS_static,
- D.getIdentifierLoc());
+ LookupResult R;
+ LookupName(R, S, Name, NameKind, true,
+ NameKind == LookupRedeclarationWithLinkage,
+ D.getIdentifierLoc());
+ PrevDecl = R.getAsSingleDecl(Context);
} else { // Something like "int foo::x;"
- DC = computeDeclContext(D.getCXXScopeSpec());
- // FIXME: RequireCompleteDeclContext(D.getCXXScopeSpec()); ?
- PrevDecl = LookupQualifiedName(DC, Name, LookupOrdinaryName, true);
+ DC = computeDeclContext(D.getCXXScopeSpec(), true);
+
+ if (!DC) {
+ // If we could not compute the declaration context, it's because the
+ // declaration context is dependent but does not refer to a class,
+ // class template, or class template partial specialization. Complain
+ // and return early, to avoid the coming semantic disaster.
+ Diag(D.getIdentifierLoc(),
+ diag::err_template_qualified_declarator_no_match)
+ << (NestedNameSpecifier*)D.getCXXScopeSpec().getScopeRep()
+ << D.getCXXScopeSpec().getRange();
+ return DeclPtrTy();
+ }
+
+ if (!DC->isDependentContext() &&
+ RequireCompleteDeclContext(D.getCXXScopeSpec()))
+ return DeclPtrTy();
+
+ LookupResult Res;
+ LookupQualifiedName(Res, DC, Name, LookupOrdinaryName, true);
+ PrevDecl = Res.getAsSingleDecl(Context);
// C++ 7.3.1.2p2:
// Members (including explicit specializations of templates) of a named
@@ -1467,11 +1795,11 @@ Sema::HandleDeclarator(Scope *S, Declarator &D,
//
// In this case, PrevDecl will point to the overload set
// containing the two f's declared in X, but neither of them
- // matches.
+ // matches.
// First check whether we named the global scope.
if (isa<TranslationUnitDecl>(DC)) {
- Diag(D.getIdentifierLoc(), diag::err_invalid_declarator_global_scope)
+ 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.
@@ -1480,7 +1808,7 @@ Sema::HandleDeclarator(Scope *S, Declarator &D,
SourceRange R = D.getCXXScopeSpec().getRange();
if (isa<FunctionDecl>(CurContext))
Diag(L, diag::err_invalid_declarator_in_function) << Name << R;
- else
+ else
Diag(L, diag::err_invalid_declarator_scope)
<< Name << cast<NamedDecl>(DC) << R;
D.setInvalidType();
@@ -1489,10 +1817,10 @@ Sema::HandleDeclarator(Scope *S, Declarator &D,
if (PrevDecl && PrevDecl->isTemplateParameter()) {
// Maybe we will complain about the shadowed template parameter.
- if (!D.isInvalidType())
+ if (!D.isInvalidType())
if (DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl))
D.setInvalidType();
-
+
// Just pretend that we didn't see the previous declaration.
PrevDecl = 0;
}
@@ -1511,24 +1839,28 @@ Sema::HandleDeclarator(Scope *S, Declarator &D,
Diag(D.getIdentifierLoc(), diag::err_template_typedef);
return DeclPtrTy();
}
-
- New = ActOnTypedefDeclarator(S, D, DC, R, PrevDecl, Redeclaration);
+
+ New = ActOnTypedefDeclarator(S, D, DC, R, DInfo, PrevDecl, Redeclaration);
} else if (R->isFunctionType()) {
- New = ActOnFunctionDeclarator(S, D, DC, R, PrevDecl,
+ New = ActOnFunctionDeclarator(S, D, DC, R, DInfo, PrevDecl,
move(TemplateParamLists),
IsFunctionDefinition, Redeclaration);
} else {
- New = ActOnVariableDeclarator(S, D, DC, R, PrevDecl, Redeclaration);
+ New = ActOnVariableDeclarator(S, D, DC, R, DInfo, PrevDecl,
+ move(TemplateParamLists),
+ 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()))
+
+ // If this has an identifier and is not an invalid redeclaration or
+ // function template specialization, add it to the scope stack.
+ if (Name && !(Redeclaration && New->isInvalidDecl()) &&
+ !(isa<FunctionDecl>(New) &&
+ cast<FunctionDecl>(New)->isFunctionTemplateSpecialization()))
PushOnScopeChains(New, S);
-
+
return DeclPtrTy::make(New);
}
@@ -1544,14 +1876,16 @@ static QualType TryToFixInvalidVariablyModifiedType(QualType T,
// constant expression folding, like struct {char x[(int)(char*)2];}
SizeIsNegative = false;
- if (const PointerType* PTy = dyn_cast<PointerType>(T)) {
+ QualifierCollector Qs;
+ const Type *Ty = Qs.strip(T);
+
+ if (const PointerType* PTy = dyn_cast<PointerType>(Ty)) {
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;
+ return Qs.apply(FixedType);
}
const VariableArrayType* VLATy = dyn_cast<VariableArrayType>(T);
@@ -1560,7 +1894,7 @@ static QualType TryToFixInvalidVariablyModifiedType(QualType T,
// FIXME: We should probably handle this case
if (VLATy->getElementType()->isVariablyModifiedType())
return QualType();
-
+
Expr::EvalResult EvalResult;
if (!VLATy->getSizeExpr() ||
!VLATy->getSizeExpr()->Evaluate(EvalResult, Context) ||
@@ -1568,9 +1902,18 @@ static QualType TryToFixInvalidVariablyModifiedType(QualType T,
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);
+ if (Res >= llvm::APSInt(Res.getBitWidth(), Res.isUnsigned())) {
+ Expr* ArySizeExpr = VLATy->getSizeExpr();
+ // FIXME: here we could "steal" (how?) ArySizeExpr from the VLA,
+ // so as to transfer ownership to the ConstantArrayWithExpr.
+ // Alternatively, we could "clone" it (how?).
+ // Since we don't know how to do things above, we just use the
+ // very same Expr*.
+ return Context.getConstantArrayWithExprType(VLATy->getElementType(),
+ Res, ArySizeExpr,
+ ArrayType::Normal, 0,
+ VLATy->getBracketsRange());
+ }
SizeIsNegative = true;
return QualType();
@@ -1578,7 +1921,7 @@ static QualType TryToFixInvalidVariablyModifiedType(QualType T,
/// \brief Register the given locally-scoped external C declaration so
/// that it can be found later for redeclarations
-void
+void
Sema::RegisterLocallyScopedExternCDecl(NamedDecl *ND, NamedDecl *PrevDecl,
Scope *S) {
assert(ND->getLexicalDeclContext()->isFunctionOrMethod() &&
@@ -1609,21 +1952,22 @@ 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(D.getDeclSpec().getInlineSpecLoc(),
diag::err_inline_non_function);
if (D.getDeclSpec().isVirtualSpecified())
- Diag(D.getDeclSpec().getVirtualSpecLoc(),
+ Diag(D.getDeclSpec().getVirtualSpecLoc(),
diag::err_virtual_non_function);
if (D.getDeclSpec().isExplicitSpecified())
- Diag(D.getDeclSpec().getExplicitSpecLoc(),
+ Diag(D.getDeclSpec().getExplicitSpecLoc(),
diag::err_explicit_non_function);
}
NamedDecl*
Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
- QualType R, Decl* PrevDecl, bool &Redeclaration) {
+ QualType R, DeclaratorInfo *DInfo,
+ NamedDecl* PrevDecl, bool &Redeclaration) {
// Typedef declarators cannot be qualified (C++ [dcl.meaning]p1).
if (D.getCXXScopeSpec().isSet()) {
Diag(D.getIdentifierLoc(), diag::err_qualified_typedef_declarator)
@@ -1645,7 +1989,7 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
TypedefDecl *NewTD = ParseTypedefDecl(S, D, R);
if (!NewTD) return 0;
-
+
if (D.isInvalidType())
NewTD->setInvalidDecl();
@@ -1663,7 +2007,7 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
QualType T = NewTD->getUnderlyingType();
if (T->isVariablyModifiedType()) {
CurFunctionNeedsScopeChecking = true;
-
+
if (S->getFnParent() == 0) {
bool SizeIsNegative;
QualType FixedTy =
@@ -1682,6 +2026,19 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
}
}
}
+
+ // If this is the C FILE type, notify the AST context.
+ if (IdentifierInfo *II = NewTD->getIdentifier())
+ if (!NewTD->isInvalidDecl() &&
+ NewTD->getDeclContext()->getLookupContext()->isTranslationUnit()) {
+ if (II->isStr("FILE"))
+ Context.setFILEDecl(NewTD);
+ else if (II->isStr("jmp_buf"))
+ Context.setjmp_bufDecl(NewTD);
+ else if (II->isStr("sigjmp_buf"))
+ Context.setsigjmp_bufDecl(NewTD);
+ }
+
return NewTD;
}
@@ -1697,13 +2054,13 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
///
/// \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
+static bool
isOutOfScopePreviousDeclaration(NamedDecl *PrevDecl, DeclContext *DC,
ASTContext &Context) {
if (!PrevDecl)
@@ -1737,10 +2094,10 @@ isOutOfScopePreviousDeclaration(NamedDecl *PrevDecl, DeclContext *DC,
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() !=
+ if (OuterContext->getPrimaryContext() !=
PrevOuterContext->getPrimaryContext())
return false;
}
@@ -1752,7 +2109,9 @@ isOutOfScopePreviousDeclaration(NamedDecl *PrevDecl, DeclContext *DC,
NamedDecl*
Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
- QualType R,NamedDecl* PrevDecl,
+ QualType R, DeclaratorInfo *DInfo,
+ NamedDecl* PrevDecl,
+ MultiTemplateParamsArg TemplateParamLists,
bool &Redeclaration) {
DeclarationName Name = GetNameForDeclarator(D);
@@ -1792,7 +2151,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// 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())
@@ -1805,7 +2164,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
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(D.getDeclSpec().getStorageClassSpecLoc(),
diag::err_static_out_of_line)
<< CodeModificationHint::CreateRemoval(
SourceRange(D.getDeclSpec().getStorageClassSpecLoc()));
@@ -1815,22 +2174,48 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (SC == VarDecl::Static) {
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC)) {
if (RD->isLocalClass())
- Diag(D.getIdentifierLoc(),
+ Diag(D.getIdentifierLoc(),
diag::err_static_data_member_not_allowed_in_local_class)
<< Name << RD->getDeclName();
}
}
-
-
- // The variable can not
- NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(),
- II, R, SC,
- // FIXME: Move to DeclGroup...
- D.getDeclSpec().getSourceRange().getBegin());
+
+ // Match up the template parameter lists with the scope specifier, then
+ // determine whether we have a template or a template specialization.
+ bool isExplicitSpecialization = false;
+ if (TemplateParameterList *TemplateParams
+ = MatchTemplateParametersToScopeSpecifier(
+ D.getDeclSpec().getSourceRange().getBegin(),
+ D.getCXXScopeSpec(),
+ (TemplateParameterList**)TemplateParamLists.get(),
+ TemplateParamLists.size(),
+ isExplicitSpecialization)) {
+ if (TemplateParams->size() > 0) {
+ // There is no such thing as a variable template.
+ Diag(D.getIdentifierLoc(), diag::err_template_variable)
+ << II
+ << SourceRange(TemplateParams->getTemplateLoc(),
+ TemplateParams->getRAngleLoc());
+ return 0;
+ } else {
+ // There is an extraneous 'template<>' for this variable. Complain
+ // about it, but allow the declaration of the variable.
+ Diag(TemplateParams->getTemplateLoc(),
+ diag::err_template_variable_noparams)
+ << II
+ << SourceRange(TemplateParams->getTemplateLoc(),
+ TemplateParams->getRAngleLoc());
+
+ isExplicitSpecialization = true;
+ }
+ }
+
+ NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(),
+ II, R, DInfo, SC);
if (D.isInvalidType())
NewVD->setInvalidDecl();
-
+
if (D.getDeclSpec().isThreadSpecified()) {
if (NewVD->hasLocalStorage())
Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_thread_non_global);
@@ -1850,7 +2235,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// 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);
+ StringLiteral *SE = cast<StringLiteral>(E);
NewVD->addAttr(::new (Context) AsmLabelAttr(std::string(SE->getStrData(),
SE->getByteLength())));
}
@@ -1861,8 +2246,8 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (PrevDecl && !isDeclInScope(PrevDecl, DC, S) &&
!(NewVD->hasLinkage() &&
isOutOfScopePreviousDeclaration(PrevDecl, DC, Context)))
- PrevDecl = 0;
-
+ PrevDecl = 0;
+
// Merge the decl with the existing one if appropriate.
if (PrevDecl) {
if (isa<FieldDecl>(PrevDecl) && D.getCXXScopeSpec().isSet()) {
@@ -1875,16 +2260,31 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
}
} else if (D.getCXXScopeSpec().isSet()) {
// No previous declaration in the qualifying scope.
- Diag(D.getIdentifierLoc(), diag::err_typecheck_no_member)
- << Name << D.getCXXScopeSpec().getRange();
+ Diag(D.getIdentifierLoc(), diag::err_no_member)
+ << Name << computeDeclContext(D.getCXXScopeSpec(), true)
+ << D.getCXXScopeSpec().getRange();
NewVD->setInvalidDecl();
}
CheckVariableDeclaration(NewVD, PrevDecl, Redeclaration);
+ // This is an explicit specialization of a static data member. Check it.
+ if (isExplicitSpecialization && !NewVD->isInvalidDecl() &&
+ CheckMemberSpecialization(NewVD, PrevDecl))
+ NewVD->setInvalidDecl();
+
+ // attributes declared post-definition are currently ignored
+ if (PrevDecl) {
+ const VarDecl *Def = 0, *PrevVD = dyn_cast<VarDecl>(PrevDecl);
+ if (PrevVD->getDefinition(Def) && D.hasAttributes()) {
+ Diag(NewVD->getLocation(), diag::warn_attribute_precede_definition);
+ Diag(Def->getLocation(), diag::note_previous_definition);
+ }
+ }
+
// If this is a locally-scoped extern C variable, update the map of
// such variables.
- if (CurContext->isFunctionOrMethod() && NewVD->isExternC(Context) &&
+ if (CurContext->isFunctionOrMethod() && NewVD->isExternC() &&
!NewVD->isInvalidDecl())
RegisterLocallyScopedExternCDecl(NewVD, PrevDecl, S);
@@ -1906,17 +2306,17 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl,
// 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,
+ diag::err_abstract_type_in_decl,
AbstractVariableType))
return NewVD->setInvalidDecl();
@@ -1934,21 +2334,22 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl,
Diag(NewVD->getLocation(), diag::warn_attribute_weak_on_local);
bool isVM = T->isVariablyModifiedType();
- if (isVM || NewVD->hasAttr<CleanupAttr>())
+ if (isVM || NewVD->hasAttr<CleanupAttr>() ||
+ NewVD->hasAttr<BlocksAttr>())
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];
+ // 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;
@@ -1959,8 +2360,8 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl,
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);
@@ -1968,12 +2369,12 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl,
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)) {
+ if (!PrevDecl && NewVD->isExternC()) {
// Since we did not find anything by this name and we're declaring
// an extern "C" variable, look for a non-visible extern "C"
// declaration with the same name.
@@ -1993,7 +2394,7 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl,
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();
@@ -2005,9 +2406,43 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl,
}
}
-NamedDecl*
+static bool isUsingDecl(Decl *D) {
+ return isa<UsingDecl>(D) || isa<UnresolvedUsingDecl>(D);
+}
+
+/// \brief Data used with FindOverriddenMethod
+struct FindOverriddenMethodData {
+ Sema *S;
+ CXXMethodDecl *Method;
+};
+
+/// \brief Member lookup function that determines whether a given C++
+/// method overrides a method in a base class, to be used with
+/// CXXRecordDecl::lookupInBases().
+static bool FindOverriddenMethod(CXXBaseSpecifier *Specifier,
+ CXXBasePath &Path,
+ void *UserData) {
+ RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl();
+
+ FindOverriddenMethodData *Data
+ = reinterpret_cast<FindOverriddenMethodData*>(UserData);
+ for (Path.Decls = BaseRecord->lookup(Data->Method->getDeclName());
+ Path.Decls.first != Path.Decls.second;
+ ++Path.Decls.first) {
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(*Path.Decls.first)) {
+ OverloadedFunctionDecl::function_iterator MatchedDecl;
+ if (MD->isVirtual() && !Data->S->IsOverload(Data->Method, MD, MatchedDecl))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+NamedDecl*
Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
- QualType R, NamedDecl* PrevDecl,
+ QualType R, DeclaratorInfo *DInfo,
+ NamedDecl* PrevDecl,
MultiTemplateParamsArg TemplateParamLists,
bool IsFunctionDefinition, bool &Redeclaration) {
assert(R.getTypePtr()->isFunctionType());
@@ -2019,7 +2454,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
case DeclSpec::SCS_auto:
case DeclSpec::SCS_register:
case DeclSpec::SCS_mutable:
- Diag(D.getDeclSpec().getStorageClassSpecLoc(),
+ Diag(D.getDeclSpec().getStorageClassSpecLoc(),
diag::err_typecheck_sclass_func);
D.setInvalidType();
break;
@@ -2032,11 +2467,11 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// block scope shall have no explicit storage-class specifier
// other than extern
// See also (C++ [dcl.stc]p4).
- Diag(D.getDeclSpec().getStorageClassSpecLoc(),
+ Diag(D.getDeclSpec().getStorageClassSpecLoc(),
diag::err_static_block_func);
SC = FunctionDecl::None;
} else
- SC = FunctionDecl::Static;
+ SC = FunctionDecl::Static;
break;
}
case DeclSpec::SCS_private_extern: SC = FunctionDecl::PrivateExtern;break;
@@ -2045,35 +2480,43 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (D.getDeclSpec().isThreadSpecified())
Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread);
+ bool isFriend = D.getDeclSpec().isFriendSpecified();
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.
+ // the class has been completely parsed.
if (!DC->isRecord() &&
- RequireNonAbstractType(D.getIdentifierLoc(),
- R->getAsFunctionType()->getResultType(),
- diag::err_abstract_type_in_decl,
+ RequireNonAbstractType(D.getIdentifierLoc(),
+ R->getAs<FunctionType>()->getResultType(),
+ diag::err_abstract_type_in_decl,
AbstractReturnType))
D.setInvalidType();
-
+
// Do not allow returning a objc interface by-value.
- if (R->getAsFunctionType()->getResultType()->isObjCInterfaceType()) {
+ if (R->getAs<FunctionType>()->getResultType()->isObjCInterfaceType()) {
Diag(D.getIdentifierLoc(),
diag::err_object_cannot_be_passed_returned_by_value) << 0
- << R->getAsFunctionType()->getResultType();
+ << R->getAs<FunctionType>()->getResultType();
D.setInvalidType();
}
- // Check that we can declare a template here.
- if (TemplateParamLists.size() &&
- CheckTemplateDeclScope(S, TemplateParamLists))
- return 0;
-
bool isVirtualOkay = false;
FunctionDecl *NewFD;
+
+ if (isFriend) {
+ // DC is the namespace in which the function is being declared.
+ assert((DC->isFileContext() || PrevDecl) && "previously-undeclared "
+ "friend function being created in a non-namespace context");
+
+ // C++ [class.friend]p5
+ // A function can be defined in a friend declaration of a
+ // class . . . . Such a function is implicitly inline.
+ isInline |= IsFunctionDefinition;
+ }
+
if (D.getKind() == Declarator::DK_Constructor) {
// This is a C++ constructor declaration.
assert(DC->isRecord() &&
@@ -2082,19 +2525,19 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
R = CheckConstructorDeclarator(D, R, SC);
// Create the new declaration
- NewFD = CXXConstructorDecl::Create(Context,
+ NewFD = CXXConstructorDecl::Create(Context,
cast<CXXRecordDecl>(DC),
- D.getIdentifierLoc(), Name, R,
+ D.getIdentifierLoc(), Name, R, DInfo,
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,
+ D.getIdentifierLoc(), Name, R,
isInline,
/*isImplicitlyDeclared=*/false);
@@ -2105,10 +2548,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// 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());
+ Name, R, DInfo, SC, isInline,
+ /*hasPrototype=*/true);
D.setInvalidType();
}
} else if (D.getKind() == Declarator::DK_Conversion) {
@@ -2117,29 +2558,29 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
diag::err_conv_function_not_member);
return 0;
}
-
+
CheckConversionDeclarator(D, R, SC);
NewFD = CXXConversionDecl::Create(Context, cast<CXXRecordDecl>(DC),
- D.getIdentifierLoc(), Name, R,
+ D.getIdentifierLoc(), Name, R, DInfo,
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
+ // 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
+ // 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,
+ D.getIdentifierLoc(), Name, R, DInfo,
(SC == FunctionDecl::Static), isInline);
isVirtualOkay = (SC != FunctionDecl::Static);
@@ -2150,44 +2591,56 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// - 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 =
+ 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());
+ Name, R, DInfo, SC, isInline, HasPrototype);
}
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.
+ // scope specifier, or is the object of a friend declaration, the
+ // lexical context will be different from the semantic context.
NewFD->setLexicalDeclContext(CurContext);
- // If there is a template parameter list, then we are dealing with a
- // template declaration or specialization.
+ // Match up the template parameter lists with the scope specifier, then
+ // determine whether we have a template or a template specialization.
FunctionTemplateDecl *FunctionTemplate = 0;
- if (TemplateParamLists.size()) {
- // FIXME: member templates!
- TemplateParameterList *TemplateParams
- = static_cast<TemplateParameterList *>(*TemplateParamLists.release());
-
+ bool isExplicitSpecialization = false;
+ bool isFunctionTemplateSpecialization = false;
+ if (TemplateParameterList *TemplateParams
+ = MatchTemplateParametersToScopeSpecifier(
+ D.getDeclSpec().getSourceRange().getBegin(),
+ D.getCXXScopeSpec(),
+ (TemplateParameterList**)TemplateParamLists.get(),
+ TemplateParamLists.size(),
+ isExplicitSpecialization)) {
if (TemplateParams->size() > 0) {
// This is a function template
- FunctionTemplate = FunctionTemplateDecl::Create(Context, CurContext,
+
+ // Check that we can declare a template here.
+ if (CheckTemplateDeclScope(S, TemplateParams))
+ return 0;
+
+ FunctionTemplate = FunctionTemplateDecl::Create(Context, DC,
NewFD->getLocation(),
Name, TemplateParams,
NewFD);
+ FunctionTemplate->setLexicalDeclContext(CurContext);
NewFD->setDescribedFunctionTemplate(FunctionTemplate);
} else {
- // FIXME: Handle function template specializations
+ // This is a function template specialization.
+ isFunctionTemplateSpecialization = true;
}
+
+ // FIXME: Free this memory properly.
+ TemplateParamLists.release();
}
// C++ [dcl.fct.spec]p5:
@@ -2197,7 +2650,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
//
if (isVirtual && !NewFD->isInvalidDecl()) {
if (!isVirtualOkay) {
- Diag(D.getDeclSpec().getVirtualSpecLoc(),
+ Diag(D.getDeclSpec().getVirtualSpecLoc(),
diag::err_virtual_non_function);
} else if (!CurContext->isRecord()) {
// 'virtual' was specified outside of the class.
@@ -2210,28 +2663,47 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
CXXRecordDecl *CurClass = cast<CXXRecordDecl>(DC);
CurClass->setAggregate(false);
CurClass->setPOD(false);
+ CurClass->setEmpty(false);
CurClass->setPolymorphic(true);
CurClass->setHasTrivialConstructor(false);
+ CurClass->setHasTrivialCopyConstructor(false);
+ CurClass->setHasTrivialCopyAssignment(false);
+ }
+ }
+
+ if (isFriend) {
+ if (FunctionTemplate) {
+ FunctionTemplate->setObjectOfFriendDecl(
+ /* PreviouslyDeclared= */ PrevDecl != NULL);
+ FunctionTemplate->setAccess(AS_public);
}
+ else
+ NewFD->setObjectOfFriendDecl(/* PreviouslyDeclared= */ PrevDecl != NULL);
+
+ NewFD->setAccess(AS_public);
}
+
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(),
+ CXXBasePaths Paths;
+ FindOverriddenMethodData Data;
+ Data.Method = NewMD;
+ Data.S = this;
+ if (cast<CXXRecordDecl>(DC)->lookupInBases(&FindOverriddenMethod, &Data,
+ Paths)) {
+ for (CXXBasePaths::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))
+ if (!CheckOverridingFunctionReturnType(NewMD, OldMD) &&
+ !CheckOverridingFunctionExceptionSpec(NewMD, OldMD))
NewMD->addOverriddenMethod(OldMD);
}
}
}
}
-
- if (SC == FunctionDecl::Static && isa<CXXMethodDecl>(NewFD) &&
+
+ 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
@@ -2240,7 +2712,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// Complain about the 'static' specifier if it's on an out-of-line
// member function definition.
- Diag(D.getDeclSpec().getStorageClassSpecLoc(),
+ Diag(D.getDeclSpec().getStorageClassSpecLoc(),
diag::err_static_out_of_line)
<< CodeModificationHint::CreateRemoval(
SourceRange(D.getDeclSpec().getStorageClassSpecLoc()));
@@ -2249,7 +2721,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// 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);
+ StringLiteral *SE = cast<StringLiteral>(E);
NewFD->addAttr(::new (Context) AsmLabelAttr(std::string(SE->getStrData(),
SE->getByteLength())));
}
@@ -2278,11 +2750,15 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
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>());
+ for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) {
+ ParmVarDecl *Param = FTI.ArgInfo[i].Param.getAs<ParmVarDecl>();
+ assert(Param->getDeclContext() != NewFD && "Was set before ?");
+ Param->setDeclContext(NewFD);
+ Params.push_back(Param);
+ }
}
-
- } else if (const FunctionProtoType *FT = R->getAsFunctionProtoType()) {
+
+ } else if (const FunctionProtoType *FT = R->getAs<FunctionProtoType>()) {
// 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.
@@ -2291,13 +2767,14 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// 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);
+ *AI, /*DInfo=*/0,
+ VarDecl::None, 0);
Param->setImplicit();
Params.push_back(Param);
}
@@ -2307,7 +2784,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
}
// 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.
@@ -2316,27 +2793,80 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
isOutOfScopePreviousDeclaration(PrevDecl, DC, Context)))
PrevDecl = 0;
+ // If the declarator is a template-id, translate the parser's template
+ // argument list into our AST format.
+ bool HasExplicitTemplateArgs = false;
+ llvm::SmallVector<TemplateArgument, 16> TemplateArgs;
+ SourceLocation LAngleLoc, RAngleLoc;
+ if (D.getKind() == Declarator::DK_TemplateId) {
+ TemplateIdAnnotation *TemplateId = D.getTemplateId();
+ ASTTemplateArgsPtr TemplateArgsPtr(*this,
+ TemplateId->getTemplateArgs(),
+ TemplateId->getTemplateArgIsType(),
+ TemplateId->NumArgs);
+ translateTemplateArguments(TemplateArgsPtr,
+ TemplateId->getTemplateArgLocations(),
+ TemplateArgs);
+ TemplateArgsPtr.release();
+
+ HasExplicitTemplateArgs = true;
+ LAngleLoc = TemplateId->LAngleLoc;
+ RAngleLoc = TemplateId->RAngleLoc;
+
+ if (FunctionTemplate) {
+ // FIXME: Diagnose function template with explicit template
+ // arguments.
+ HasExplicitTemplateArgs = false;
+ } else if (!isFunctionTemplateSpecialization &&
+ !D.getDeclSpec().isFriendSpecified()) {
+ // We have encountered something that the user meant to be a
+ // specialization (because it has explicitly-specified template
+ // arguments) but that was not introduced with a "template<>" (or had
+ // too few of them).
+ Diag(D.getIdentifierLoc(), diag::err_template_spec_needs_header)
+ << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc)
+ << CodeModificationHint::CreateInsertion(
+ D.getDeclSpec().getSourceRange().getBegin(),
+ "template<> ");
+ isFunctionTemplateSpecialization = true;
+ }
+ }
+
+ if (isFunctionTemplateSpecialization) {
+ if (CheckFunctionTemplateSpecialization(NewFD, HasExplicitTemplateArgs,
+ LAngleLoc, TemplateArgs.data(),
+ TemplateArgs.size(), RAngleLoc,
+ PrevDecl))
+ NewFD->setInvalidDecl();
+ } else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD) &&
+ CheckMemberSpecialization(NewFD, PrevDecl))
+ NewFD->setInvalidDecl();
+
// Perform semantic checking on the function declaration.
bool OverloadableAttrRequired = false; // FIXME: HACK!
- CheckFunctionDeclaration(NewFD, PrevDecl, Redeclaration,
- /*FIXME:*/OverloadableAttrRequired);
+ CheckFunctionDeclaration(NewFD, PrevDecl, isExplicitSpecialization,
+ 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) {
+ // Note that this is not the case for explicit specializations of
+ // function templates or member functions of class templates, per
+ // C++ [temp.expl.spec]p2.
+ if (!IsFunctionDefinition && !isFriend &&
+ !isFunctionTemplateSpecialization && !isExplicitSpecialization) {
Diag(NewFD->getLocation(), diag::err_out_of_line_declaration)
<< D.getCXXScopeSpec().getRange();
NewFD->setInvalidDecl();
- } else if (!Redeclaration && (!PrevDecl || !isa<UsingDecl>(PrevDecl))) {
+ } else if (!Redeclaration && (!PrevDecl || !isUsingDecl(PrevDecl))) {
// 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,
+ // 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
//
@@ -2344,12 +2874,12 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// 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();
+ << Name << DC << D.getCXXScopeSpec().getRange();
NewFD->setInvalidDecl();
-
- LookupResult Prev = LookupQualifiedName(DC, Name, LookupOrdinaryName,
- true);
- assert(!Prev.isAmbiguous() &&
+
+ LookupResult Prev;
+ LookupQualifiedName(Prev, 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) {
@@ -2357,7 +2887,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
isNearlyMatchingFunction(Context, cast<FunctionDecl>(*Func), NewFD))
Diag((*Func)->getLocation(), diag::note_member_def_close_match);
}
-
+
PrevDecl = 0;
}
}
@@ -2367,6 +2897,16 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// FIXME: This needs to happen before we merge declarations. Then,
// let attribute merging cope with attribute conflicts.
ProcessDeclAttributes(S, NewFD, D);
+
+ // attributes declared post-definition are currently ignored
+ if (Redeclaration && PrevDecl) {
+ const FunctionDecl *Def, *PrevFD = dyn_cast<FunctionDecl>(PrevDecl);
+ if (PrevFD && PrevFD->getBody(Def) && D.hasAttributes()) {
+ Diag(NewFD->getLocation(), diag::warn_attribute_precede_definition);
+ Diag(Def->getLocation(), diag::note_previous_definition);
+ }
+ }
+
AddKnownFunctionAttributes(NewFD);
if (OverloadableAttrRequired && !NewFD->getAttr<OverloadableAttr>()) {
@@ -2375,14 +2915,14 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing)
<< Redeclaration << NewFD;
if (PrevDecl)
- Diag(PrevDecl->getLocation(),
+ 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)
+ if (CurContext->isFunctionOrMethod() && NewFD->isExternC()
&& !NewFD->isInvalidDecl())
RegisterLocallyScopedExternCDecl(NewFD, PrevDecl, S);
@@ -2391,10 +2931,10 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (FunctionTemplate && NewFD->isInvalidDecl())
FunctionTemplate->setInvalidDecl();
-
+
if (FunctionTemplate)
return FunctionTemplate;
-
+
return NewFD;
}
@@ -2408,8 +2948,12 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
/// that have been instantiated via C++ template instantiation (called
/// via InstantiateDecl).
///
+/// \param IsExplicitSpecialiation whether this new function declaration is
+/// an explicit specialization of the previous declaration.
+///
/// This sets NewFD->isInvalidDecl() to true if there was an error.
void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl,
+ bool IsExplicitSpecialization,
bool &Redeclaration,
bool &OverloadableAttrRequired) {
// If NewFD is already known erroneous, don't do any of this checking.
@@ -2423,51 +2967,11 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl,
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);
+ if (NewFD->isMain())
+ CheckMain(NewFD);
// Check for a previous declaration of this name.
- if (!PrevDecl && NewFD->isExternC(Context)) {
+ if (!PrevDecl && NewFD->isExternC()) {
// Since we did not find anything by this name and we're declaring
// an extern "C" function, look for a non-visible extern "C"
// declaration with the same name.
@@ -2492,24 +2996,23 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl,
// Functions marked "overloadable" must have a prototype (that
// we can't get through declaration merging).
- if (!NewFD->getType()->getAsFunctionProtoType()) {
+ if (!NewFD->getType()->getAs<FunctionProtoType>()) {
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(),
+ NewFD->getType()->getAs<FunctionType>()->getResultType(),
0, 0, true, 0);
NewFD->setType(R);
return NewFD->setInvalidDecl();
}
}
- if (PrevDecl &&
- (!AllowOverloadingOfFunction(PrevDecl, Context) ||
- !IsOverload(NewFD, PrevDecl, MatchedDecl)) &&
- !isa<UsingDecl>(PrevDecl)) {
+ if (PrevDecl &&
+ (!AllowOverloadingOfFunction(PrevDecl, Context) ||
+ !IsOverload(NewFD, PrevDecl, MatchedDecl)) && !isUsingDecl(PrevDecl)) {
Redeclaration = true;
Decl *OldDecl = PrevDecl;
@@ -2519,23 +3022,160 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl,
OldDecl = *MatchedDecl;
// NewFD and OldDecl represent declarations that need to be
- // merged.
+ // merged.
if (MergeFunctionDecl(NewFD, OldDecl))
return NewFD->setInvalidDecl();
if (FunctionTemplateDecl *OldTemplateDecl
- = dyn_cast<FunctionTemplateDecl>(OldDecl))
- NewFD->setPreviousDeclaration(OldTemplateDecl->getTemplatedDecl());
- else
+ = dyn_cast<FunctionTemplateDecl>(OldDecl)) {
+ NewFD->setPreviousDeclaration(OldTemplateDecl->getTemplatedDecl());
+ FunctionTemplateDecl *NewTemplateDecl
+ = NewFD->getDescribedFunctionTemplate();
+ assert(NewTemplateDecl && "Template/non-template mismatch");
+ if (CXXMethodDecl *Method
+ = dyn_cast<CXXMethodDecl>(NewTemplateDecl->getTemplatedDecl())) {
+ Method->setAccess(OldTemplateDecl->getAccess());
+ NewTemplateDecl->setAccess(OldTemplateDecl->getAccess());
+ }
+
+ // If this is an explicit specialization of a member that is a function
+ // template, mark it as a member specialization.
+ if (IsExplicitSpecialization &&
+ NewTemplateDecl->getInstantiatedFromMemberTemplate()) {
+ NewTemplateDecl->setMemberSpecialization();
+ assert(OldTemplateDecl->isMemberSpecialization());
+ }
+ } else {
+ if (isa<CXXMethodDecl>(NewFD)) // Set access for out-of-line definitions
+ NewFD->setAccess(OldDecl->getAccess());
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);
+ // 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());
+ QualType ClassType = Context.getTypeDeclType(Record);
+ if (!ClassType->isDependentType()) {
+ DeclarationName Name
+ = Context.DeclarationNames.getCXXDestructorName(
+ Context.getCanonicalType(ClassType));
+ if (NewFD->getDeclName() != Name) {
+ Diag(NewFD->getLocation(), diag::err_destructor_name);
+ return NewFD->setInvalidDecl();
+ }
+ }
+ 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.
+ // FIXME: C++0x: don't do this for "= default" destructors
+ 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();
+
+ // 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 (!CurContext->isRecord())
+ CheckCXXDefaultArguments(NewFD);
+ }
+}
+
+void Sema::CheckMain(FunctionDecl* FD) {
+ // C++ [basic.start.main]p3: A program that declares main to be inline
+ // or static is ill-formed.
+ // C99 6.7.4p4: In a hosted environment, the inline function specifier
+ // shall not appear in a declaration of main.
+ // static main is not an error under C99, but we should warn about it.
+ bool isInline = FD->isInline();
+ bool isStatic = FD->getStorageClass() == FunctionDecl::Static;
+ if (isInline || isStatic) {
+ unsigned diagID = diag::warn_unusual_main_decl;
+ if (isInline || getLangOptions().CPlusPlus)
+ diagID = diag::err_unusual_main_decl;
+
+ int which = isStatic + (isInline << 1) - 1;
+ Diag(FD->getLocation(), diagID) << which;
+ }
+
+ QualType T = FD->getType();
+ assert(T->isFunctionType() && "function decl is not of function type");
+ const FunctionType* FT = T->getAs<FunctionType>();
+
+ if (!Context.hasSameUnqualifiedType(FT->getResultType(), Context.IntTy)) {
+ // TODO: add a replacement fixit to turn the return type into 'int'.
+ Diag(FD->getTypeSpecStartLoc(), diag::err_main_returns_nonint);
+ FD->setInvalidDecl(true);
+ }
+
+ // Treat protoless main() as nullary.
+ if (isa<FunctionNoProtoType>(FT)) return;
+
+ const FunctionProtoType* FTP = cast<const FunctionProtoType>(FT);
+ unsigned nparams = FTP->getNumArgs();
+ assert(FD->getNumParams() == nparams);
+
+ if (nparams > 3) {
+ Diag(FD->getLocation(), diag::err_main_surplus_args) << nparams;
+ FD->setInvalidDecl(true);
+ nparams = 3;
+ }
+
+ // FIXME: a lot of the following diagnostics would be improved
+ // if we had some location information about types.
+
+ QualType CharPP =
+ Context.getPointerType(Context.getPointerType(Context.CharTy));
+ QualType Expected[] = { Context.IntTy, CharPP, CharPP };
+
+ for (unsigned i = 0; i < nparams; ++i) {
+ QualType AT = FTP->getArgType(i);
+
+ bool mismatch = true;
+
+ if (Context.hasSameUnqualifiedType(AT, Expected[i]))
+ mismatch = false;
+ else if (Expected[i] == CharPP) {
+ // As an extension, the following forms are okay:
+ // char const **
+ // char const * const *
+ // char * const *
+
+ QualifierCollector qs;
+ const PointerType* PT;
+ if ((PT = qs.strip(AT)->getAs<PointerType>()) &&
+ (PT = qs.strip(PT->getPointeeType())->getAs<PointerType>()) &&
+ (QualType(qs.strip(PT->getPointeeType()), 0) == Context.CharTy)) {
+ qs.removeConst();
+ mismatch = !qs.empty();
+ }
+ }
+
+ if (mismatch) {
+ Diag(FD->getLocation(), diag::err_main_arg_wrong) << i << Expected[i];
+ // TODO: suggest replacing given type with expected type
+ FD->setInvalidDecl(true);
+ }
+ }
+
+ if (nparams == 1 && !FD->isInvalidDecl()) {
+ Diag(FD->getLocation(), diag::warn_main_one_arg);
+ }
}
bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) {
@@ -2554,8 +3194,8 @@ bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) {
return true;
}
-void Sema::AddInitializerToDecl(DeclPtrTy dcl, FullExprArg init) {
- AddInitializerToDecl(dcl, init.release(), /*DirectInit=*/false);
+void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init) {
+ AddInitializerToDecl(dcl, move(init), /*DirectInit=*/false);
}
/// AddInitializerToDecl - Adds the initializer Init to the
@@ -2567,7 +3207,7 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
// 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.
@@ -2616,7 +3256,7 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
const VarDecl *Def = 0;
if (VDecl->getDefinition(Def)) {
- Diag(VDecl->getLocation(), diag::err_redefinition)
+ Diag(VDecl->getLocation(), diag::err_redefinition)
<< VDecl->getDeclName();
Diag(Def->getLocation(), diag::note_previous_definition);
VDecl->setInvalidDecl();
@@ -2639,7 +3279,7 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
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()) {
@@ -2647,7 +3287,7 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
CheckForConstantInitializer(Init, DclT);
}
}
- } else if (VDecl->isStaticDataMember() &&
+ } else if (VDecl->isStaticDataMember() &&
VDecl->getLexicalDeclContext()->isRecord()) {
// This is an in-class initialization for a static data member, e.g.,
//
@@ -2663,7 +3303,7 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
// 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() &&
+ if (!T->isDependentType() &&
(!Context.getCanonicalType(T).isConstQualified() ||
!T->isIntegralType())) {
Diag(VDecl->getLocation(), diag::err_member_initialization)
@@ -2678,7 +3318,7 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
if (!Init->isTypeDependent() &&
!Init->getType()->isIntegralType()) {
// We have a non-dependent, non-integral or enumeration type.
- Diag(Init->getSourceRange().getBegin(),
+ Diag(Init->getSourceRange().getBegin(),
diag::err_in_class_initializer_non_integral_type)
<< Init->getType() << Init->getSourceRange();
VDecl->setInvalidDecl();
@@ -2701,7 +3341,7 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
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()) {
@@ -2710,14 +3350,16 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
}
}
// If the type changed, it means we had an incomplete type that was
- // completed by the initializer. For example:
+ // 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);
}
-
+
+ Init = MaybeCreateCXXExprWithTemporaries(Init,
+ /*ShouldDestroyTemporaries=*/true);
// Attach the initializer to the decl.
VDecl->setInit(Context, Init);
@@ -2725,17 +3367,15 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
// 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);
+ bool Deleted = TentativeDefinitions.erase(VDecl->getDeclName());
+ assert(Deleted && "Unrecorded tentative definition?"); Deleted=Deleted;
}
return;
}
-void Sema::ActOnUninitializedDecl(DeclPtrTy dcl) {
+void Sema::ActOnUninitializedDecl(DeclPtrTy dcl,
+ bool TypeContainsUndeducedAuto) {
Decl *RealDecl = dcl.getAs<Decl>();
// If there is no declaration, there was an error parsing it. Just ignore it.
@@ -2746,8 +3386,20 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl) {
QualType Type = Var->getType();
// Record tentative definitions.
- if (Var->isTentativeDefinition(Context))
- TentativeDefinitions[Var->getDeclName()] = Var;
+ if (Var->isTentativeDefinition(Context)) {
+ std::pair<llvm::DenseMap<DeclarationName, VarDecl *>::iterator, bool>
+ InsertPair =
+ TentativeDefinitions.insert(std::make_pair(Var->getDeclName(), Var));
+
+ // Keep the latest definition in the map. If we see 'int i; int i;' we
+ // want the second one in the map.
+ InsertPair.first->second = Var;
+
+ // However, for the list, we don't care about the order, just make sure
+ // that there are no dupes for a given declaration name.
+ if (InsertPair.second)
+ TentativeDefinitionList.push_back(Var->getDeclName());
+ }
// C++ [dcl.init.ref]p3:
// The initializer can be omitted for a reference only in a
@@ -2763,46 +3415,72 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl) {
return;
}
+ // C++0x [dcl.spec.auto]p3
+ if (TypeContainsUndeducedAuto) {
+ Diag(Var->getLocation(), diag::err_auto_var_requires_init)
+ << Var->getDeclName() << Type;
+ Var->setInvalidDecl();
+ return;
+ }
+
+ // C++ [temp.expl.spec]p15:
+ // An explicit specialization of a static data member of a template is a
+ // definition if the declaration includes an initializer; otherwise, it
+ // is a declaration.
+ if (Var->isStaticDataMember() &&
+ Var->getInstantiatedFromStaticDataMember() &&
+ Var->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+ 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.
+ //
+ // FIXME: Diagnose the "user-declared default constructor" bit.
if (getLangOptions().CPlusPlus) {
QualType InitType = Type;
if (const ArrayType *Array = Context.getAsArrayType(Type))
InitType = Array->getElementType();
- if ((!Var->hasExternalStorage() && !Var->isExternC(Context)) &&
+ if ((!Var->hasExternalStorage() && !Var->isExternC()) &&
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,
+ if (!RequireCompleteType(Var->getLocation(), InitType,
+ diag::err_invalid_incomplete_type_use)) {
+ ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
+
+ CXXConstructorDecl *Constructor
+ = PerformInitializationByConstructor(InitType,
+ MultiExprArg(*this, 0, 0),
Var->getLocation(),
SourceRange(Var->getLocation(),
Var->getLocation()),
Var->getDeclName(),
- IK_Default);
- if (!Constructor)
+ IK_Default,
+ ConstructorArgs);
+
+ // FIXME: Location info for the variable initialization?
+ if (!Constructor)
+ Var->setInvalidDecl();
+ else {
+ // FIXME: Cope with initialization of arrays
+ if (!Constructor->isTrivial() &&
+ InitializeVarWithConstructor(Var, Constructor, InitType,
+ move_arg(ConstructorArgs)))
+ Var->setInvalidDecl();
+
+ FinalizeVarWithDestructor(Var, InitType);
+ }
+ } else {
Var->setInvalidDecl();
- else {
- if (!RD->hasTrivialConstructor())
- InitializeVarWithConstructor(Var, Constructor, InitType, 0, 0);
- // FIXME. Must do all that is needed to destroy the object
- // on scope exit. For now, just mark the destructor as used.
- MarkDestructorReferenced(Var->getLocation(), InitType);
}
}
}
#if 0
// FIXME: Temporarily disabled because we are not properly parsing
- // linkage specifications on declarations, e.g.,
+ // linkage specifications on declarations, e.g.,
//
// extern "C" const CGPoint CGPointerZero;
//
@@ -2844,7 +3522,7 @@ Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
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) {
@@ -2852,38 +3530,40 @@ Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
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,
+ 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
+ // File scope. 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. 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)) {
+ if (IDecl->isTentativeDefinition(Context) && !IDecl->isInvalidDecl()) {
+ if (const IncompleteArrayType *ArrayT
+ = Context.getAsIncompleteArrayType(T)) {
+ if (RequireCompleteType(IDecl->getLocation(),
+ ArrayT->getElementType(),
+ diag::err_illegal_decl_array_incomplete_type))
+ IDecl->setInvalidDecl();
+ } else if (IDecl->getStorageClass() == VarDecl::Static) {
// 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
+ // a tentative definition and has internal linkage (C99 6.2.2p3), the
// declared type shall not be an incomplete type.
- IDecl->setInvalidDecl();
+ // NOTE: code such as the following
+ // static struct s;
+ // struct s { int a; };
+ // is accepted by gcc. Hence here we issue a warning instead of
+ // an error and we do not invalidate the static declaration.
+ // NOTE: to avoid multiple warnings, only check the first declaration.
+ if (IDecl->getPreviousDeclaration() == 0)
+ RequireCompleteType(IDecl->getLocation(), T,
+ diag::ext_typecheck_decl_incomplete_type);
}
}
}
@@ -2894,7 +3574,7 @@ Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
/// ActOnParamDeclarator - Called from Parser::ParseFunctionDeclarator()
/// to introduce parameters into function prototype scope.
-Sema::DeclPtrTy
+Sema::DeclPtrTy
Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
const DeclSpec &DS = D.getDeclSpec();
@@ -2917,10 +3597,12 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
// parameter (C++ only).
if (getLangOptions().CPlusPlus)
CheckExtraCXXDefaultArguments(D);
-
+
+ DeclaratorInfo *DInfo = 0;
TagDecl *OwnedDecl = 0;
- QualType parmDeclType = GetTypeForDeclarator(D, S, /*Skip=*/0, &OwnedDecl);
-
+ QualType parmDeclType = GetTypeForDeclarator(D, S, &DInfo, /*Skip=*/0,
+ &OwnedDecl);
+
if (getLangOptions().CPlusPlus && OwnedDecl && OwnedDecl->isDefinition()) {
// C++ [dcl.fct]p6:
// Types shall not be defined in return or parameter types.
@@ -2933,7 +3615,7 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
// 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 (NamedDecl *PrevDecl = LookupSingleName(S, II, LookupOrdinaryName)) {
if (PrevDecl->isTemplateParameter()) {
// Maybe we will complain about the shadowed template parameter.
DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl);
@@ -2951,26 +3633,26 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
// 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,
+ // 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,
+ New = ParmVarDecl::Create(Context, CurContext,
D.getIdentifierLoc(), II,
- parmDeclType, StorageClass,
+ parmDeclType, DInfo, StorageClass,
0);
else // keep track of both the adjusted and unadjusted types
- New = OriginalParmVarDecl::Create(Context, CurContext,
- D.getIdentifierLoc(), II, T,
+ New = OriginalParmVarDecl::Create(Context, CurContext,
+ D.getIdentifierLoc(), II, T, DInfo,
parmDeclType, StorageClass, 0);
-
+
if (D.isInvalidType())
New->setInvalidDecl();
@@ -2981,14 +3663,25 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
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();
}
-
+
+ // ISO/IEC TR 18037 S6.7.3: "The type of an object with automatic storage
+ // duration shall not be qualified by an address-space qualifier."
+ // Since all parameters have automatic store duration, they can not have
+ // an address space.
+ if (T.getAddressSpace() != 0) {
+ Diag(D.getIdentifierLoc(),
+ diag::err_arg_with_address_space);
+ New->setInvalidDecl();
+ }
+
+
// Add the parameter declaration into this scope.
S->AddDecl(DeclPtrTy::make(New));
if (II)
@@ -3025,14 +3718,15 @@ void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D,
// type.
DeclSpec DS;
const char* PrevSpec; // unused
- DS.SetTypeSpecType(DeclSpec::TST_int, FTI.ArgInfo[i].IdentLoc,
- PrevSpec);
+ unsigned DiagID; // unused
+ DS.SetTypeSpecType(DeclSpec::TST_int, FTI.ArgInfo[i].IdentLoc,
+ PrevSpec, DiagID);
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,
@@ -3043,12 +3737,12 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope,
DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun;
if (FTI.hasPrototype) {
- // FIXME: Diagnose arguments without names in C.
+ // FIXME: Diagnose arguments without names in C.
}
-
+
Scope *ParentScope = FnBodyScope->getParent();
- DeclPtrTy DP = HandleDeclarator(ParentScope, D,
+ DeclPtrTy DP = HandleDeclarator(ParentScope, D,
MultiTemplateParamsArg(*this),
/*IsFunctionDefinition=*/true);
return ActOnStartOfFunctionDef(FnBodyScope, DP);
@@ -3057,10 +3751,16 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope,
Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) {
if (!D)
return D;
- FunctionDecl *FD = cast<FunctionDecl>(D.getAs<Decl>());
+ FunctionDecl *FD = 0;
+
+ if (FunctionTemplateDecl *FunTmpl
+ = dyn_cast<FunctionTemplateDecl>(D.getAs<Decl>()))
+ FD = FunTmpl->getTemplatedDecl();
+ else
+ FD = cast<FunctionDecl>(D.getAs<Decl>());
CurFunctionNeedsScopeChecking = false;
-
+
// See if this is a redefinition.
const FunctionDecl *Definition;
if (FD->getBody(Definition)) {
@@ -3069,7 +3769,7 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) {
}
// Builtin functions cannot be defined.
- if (unsigned BuiltinID = FD->getBuiltinID(Context)) {
+ if (unsigned BuiltinID = FD->getBuiltinID()) {
if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) {
Diag(FD->getLocation(), diag::err_builtin_definition) << FD;
FD->setInvalidDecl();
@@ -3126,7 +3826,7 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) {
// Checking attributes of current function definition
// dllimport attribute.
- if (FD->getAttr<DLLImportAttr>() &&
+ if (FD->getAttr<DLLImportAttr>() &&
(!FD->getAttr<DLLExportAttr>())) {
// dllimport attribute cannot be applied to definition.
if (!(FD->getAttr<DLLImportAttr>())->isInherited()) {
@@ -3155,23 +3855,39 @@ 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)) {
+
+ FunctionDecl *FD = 0;
+ FunctionTemplateDecl *FunTmpl = dyn_cast_or_null<FunctionTemplateDecl>(dcl);
+ if (FunTmpl)
+ FD = FunTmpl->getTemplatedDecl();
+ else
+ FD = dyn_cast_or_null<FunctionDecl>(dcl);
+
+ if (FD) {
FD->setBody(Body);
-
+ if (FD->isMain())
+ // C and C++ allow for main to automagically return 0.
+ // Implements C++ [basic.start.main]p5 and C99 5.1.2.2.3.
+ FD->setHasImplicitReturnZero(true);
+ else
+ CheckFallThroughForFunctionDef(FD, Body);
+
if (!FD->isInvalidDecl())
DiagnoseUnusedParameters(FD->param_begin(), FD->param_end());
-
+
// C++ [basic.def.odr]p2:
// [...] A virtual member function is used if it is not pure. [...]
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FD))
if (Method->isVirtual() && !Method->isPure())
MarkDeclarationReferenced(Method->getLocation(), Method);
-
+
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);
-
+ CheckFallThroughForFunctionDef(MD, Body);
+ MD->setEndLoc(Body->getLocEnd());
+
if (!MD->isInvalidDecl())
DiagnoseUnusedParameters(MD->param_begin(), MD->param_end());
} else {
@@ -3184,21 +3900,21 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
// 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.
@@ -3207,7 +3923,7 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
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
@@ -3231,17 +3947,20 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
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))
+ // 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 (FD && isa<CXXConstructorDecl>(FD) && isa<CXXTryStmt>(Body))
DiagnoseReturnInConstructorExceptionHandler(cast<CXXTryStmt>(Body));
+ if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(dcl))
+ computeBaseOrMembersToDestroy(Destructor);
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,
+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
@@ -3256,25 +3975,26 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
}
// Extension in C99. Legal in C90, but warn about it.
- if (getLangOptions().C99)
+ static const unsigned int BuiltinLen = strlen("__builtin_");
+ if (II.getLength() > BuiltinLen &&
+ std::equal(II.getName(), II.getName() + BuiltinLen, "__builtin_"))
+ Diag(Loc, diag::warn_builtin_unknown) << &II;
+ else 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);
+ unsigned DiagID;
+ bool Error = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, Dummy, DiagID);
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),
+ false, 0,0,0, Loc, Loc, D),
SourceLocation());
D.SetIdentifier(&II, Loc);
@@ -3282,8 +4002,8 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
DeclContext *PrevDC = CurContext;
CurContext = Context.getTranslationUnitDecl();
-
- FunctionDecl *FD =
+
+ FunctionDecl *FD =
dyn_cast<FunctionDecl>(ActOnDeclarator(TUScope, D).getAs<Decl>());
FD->setImplicit();
@@ -3306,7 +4026,7 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
// If this is a built-in function, map its builtin attributes to
// actual attributes.
- if (unsigned BuiltinID = FD->getBuiltinID(Context)) {
+ if (unsigned BuiltinID = FD->getBuiltinID()) {
// Handle printf-formatting attributes.
unsigned FormatIdx;
bool HasVAListArg;
@@ -3324,15 +4044,18 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
if (!FD->getAttr<ConstAttr>())
FD->addAttr(::new (Context) ConstAttr());
}
+
+ if (Context.BuiltinInfo.isNoReturn(BuiltinID))
+ FD->addAttr(::new (Context) NoReturnAttr());
}
IdentifierInfo *Name = FD->getIdentifier();
if (!Name)
return;
- if ((!getLangOptions().CPlusPlus &&
+ if ((!getLangOptions().CPlusPlus &&
FD->getDeclContext()->isTranslationUnit()) ||
(isa<LinkageSpecDecl>(FD->getDeclContext()) &&
- cast<LinkageSpecDecl>(FD->getDeclContext())->getLanguage() ==
+ cast<LinkageSpecDecl>(FD->getDeclContext())->getLanguage() ==
LinkageSpecDecl::lang_c)) {
// Okay: this could be a libc/libm/Objective-C function we know
// about.
@@ -3340,13 +4063,16 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
return;
if (Name->isStr("NSLog") || Name->isStr("NSLogv")) {
+ // FIXME: NSLog and NSLogv should be target specific
if (const FormatAttr *Format = FD->getAttr<FormatAttr>()) {
// FIXME: We known better than our headers.
const_cast<FormatAttr *>(Format)->setType("printf");
- } else
+ } else
FD->addAttr(::new (Context) FormatAttr("printf", 1,
Name->isStr("NSLogv") ? 0 : 2));
} else if (Name->isStr("asprintf") || Name->isStr("vasprintf")) {
+ // FIXME: asprintf and vasprintf aren't C99 functions. Should they be
+ // target-specific builtins, perhaps?
if (!FD->getAttr<FormatAttr>())
FD->addAttr(::new (Context) FormatAttr("printf", 2,
Name->isStr("vasprintf") ? 0 : 3));
@@ -3356,16 +4082,16 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
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(),
+ D.getIdentifier(),
T);
-
- if (TagType *TT = dyn_cast<TagType>(T)) {
+
+ if (const TagType *TT = T->getAs<TagType>()) {
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())
@@ -3382,7 +4108,7 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T) {
/// 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,
+bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous,
TagDecl::TagKind NewTag,
SourceLocation NewTagLoc,
const IdentifierInfo &Name) {
@@ -3402,7 +4128,7 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous,
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.
@@ -3423,33 +4149,58 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous,
/// 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
+/// TagSpec indicates what kind of tag this is. TUK indicates whether this is a
/// reference/declaration/definition of a tag.
-Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
+Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
SourceLocation KWLoc, const CXXScopeSpec &SS,
IdentifierInfo *Name, SourceLocation NameLoc,
AttributeList *Attr, AccessSpecifier AS,
- bool &OwnedDecl) {
+ MultiTemplateParamsArg TemplateParameterLists,
+ bool &OwnedDecl, bool &IsDependent) {
// If this is not a definition, it must have a name.
- assert((Name != 0 || TK == TK_Definition) &&
+ assert((Name != 0 || TUK == TUK_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;
+ TagDecl::TagKind Kind = TagDecl::getTagKindForTypeSpec(TagSpec);
+
+ // FIXME: Check explicit specializations more carefully.
+ bool isExplicitSpecialization = false;
+ if (TUK != TUK_Reference) {
+ if (TemplateParameterList *TemplateParams
+ = MatchTemplateParametersToScopeSpecifier(KWLoc, SS,
+ (TemplateParameterList**)TemplateParameterLists.get(),
+ TemplateParameterLists.size(),
+ isExplicitSpecialization)) {
+ if (TemplateParams->size() > 0) {
+ // This is a declaration or definition of a class template (which may
+ // be a member of another template).
+ OwnedDecl = false;
+ DeclResult Result = CheckClassTemplate(S, TagSpec, TUK, KWLoc,
+ SS, Name, NameLoc, Attr,
+ TemplateParams,
+ AS);
+ TemplateParameterLists.release();
+ return Result.get();
+ } else {
+ // The "template<>" header is extraneous.
+ Diag(TemplateParams->getTemplateLoc(), diag::err_template_tag_noparams)
+ << ElaboratedType::getNameForTagKind(Kind) << Name;
+ isExplicitSpecialization = true;
+ }
+ }
+
+ TemplateParameterLists.release();
}
-
+
DeclContext *SearchDC = CurContext;
DeclContext *DC = CurContext;
NamedDecl *PrevDecl = 0;
-
+ bool isStdBadAlloc = false;
bool Invalid = false;
+ bool RedeclarationOnly = (TUK != TUK_Reference);
+
if (Name && SS.isNotEmpty()) {
// We have a nested-name tag ('struct foo::bar').
@@ -3459,18 +4210,35 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
goto CreateNewDecl;
}
+ // If this is a friend or a reference to a class in a dependent
+ // context, don't try to make a decl for it.
+ if (TUK == TUK_Friend || TUK == TUK_Reference) {
+ DC = computeDeclContext(SS, false);
+ if (!DC) {
+ IsDependent = true;
+ return DeclPtrTy();
+ }
+ }
+
if (RequireCompleteDeclContext(SS))
return DeclPtrTy::make((Decl *)0);
- DC = computeDeclContext(SS);
+ DC = computeDeclContext(SS, true);
SearchDC = DC;
// Look-up name inside 'foo::'.
- PrevDecl
- = dyn_cast_or_null<TagDecl>(
- LookupQualifiedName(DC, Name, LookupTagName, true).getAsDecl());
+ LookupResult R;
+ LookupQualifiedName(R, DC, Name, LookupTagName, RedeclarationOnly);
+
+ if (R.isAmbiguous()) {
+ DiagnoseAmbiguousLookup(R, Name, NameLoc, SS.getRange());
+ return DeclPtrTy();
+ }
+
+ if (R.getKind() == LookupResult::Found)
+ PrevDecl = dyn_cast<TagDecl>(R.getFoundDecl());
// A tag 'foo::bar' must already exist.
- if (PrevDecl == 0) {
+ if (!PrevDecl) {
Diag(NameLoc, diag::err_not_tag_in_scope) << Name << SS.getRange();
Name = 0;
Invalid = true;
@@ -3482,8 +4250,8 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
// 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));
+ LookupResult R;
+ LookupName(R, S, Name, LookupTagName, RedeclarationOnly);
if (R.isAmbiguous()) {
DiagnoseAmbiguousLookup(R, Name, NameLoc);
// FIXME: This is not best way to recover from case like:
@@ -3494,11 +4262,10 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
Name = 0;
PrevDecl = 0;
Invalid = true;
- }
- else
- PrevDecl = R;
+ } else
+ PrevDecl = R.getAsSingleDecl(Context);
- if (!getLangOptions().CPlusPlus && TK != TK_Reference) {
+ if (!getLangOptions().CPlusPlus && TUK != TUK_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
@@ -3515,23 +4282,37 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
PrevDecl = 0;
}
+ if (getLangOptions().CPlusPlus && Name && DC && StdNamespace &&
+ DC->Equals(StdNamespace) && Name->isStr("bad_alloc")) {
+ // This is a declaration of or a reference to "std::bad_alloc".
+ isStdBadAlloc = true;
+
+ if (!PrevDecl && StdBadAlloc) {
+ // std::bad_alloc has been implicitly declared (but made invisible to
+ // name lookup). Fill in this implicit declaration as the previous
+ // declaration, so that the declarations get chained appropriately.
+ PrevDecl = StdBadAlloc;
+ }
+ }
+
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)) {
+ if (TUK == TUK_Reference || TUK == TUK_Friend ||
+ 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
+ bool SafeToContinue
= (PrevTagDecl->getTagKind() != TagDecl::TK_enum &&
Kind != TagDecl::TK_enum);
if (SafeToContinue)
- Diag(KWLoc, diag::err_use_with_wrong_tag)
+ Diag(KWLoc, diag::err_use_with_wrong_tag)
<< Name
<< CodeModificationHint::CreateReplacement(SourceRange(KWLoc),
PrevTagDecl->getKindName());
@@ -3539,7 +4320,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
Diag(KWLoc, diag::err_use_with_wrong_tag) << Name;
Diag(PrevDecl->getLocation(), diag::note_previous_use);
- if (SafeToContinue)
+ if (SafeToContinue)
Kind = PrevTagDecl->getTagKind();
else {
// Recover by making this an anonymous redefinition.
@@ -3556,27 +4337,35 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
// 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)
+ if (TUK == TUK_Reference || TUK == TUK_Friend)
return DeclPtrTy::make(PrevDecl);
// Diagnose attempts to redefine a tag.
- if (TK == TK_Definition) {
+ if (TUK == TUK_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;
+ // If we're defining a specialization and the previous definition
+ // is from an implicit instantiation, don't emit an error
+ // here; we'll catch this in the general case below.
+ if (!isExplicitSpecialization ||
+ !isa<CXXRecordDecl>(Def) ||
+ cast<CXXRecordDecl>(Def)->getTemplateSpecializationKind()
+ == TSK_ExplicitSpecialization) {
+ 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(PrevTagDecl->getLocation(),
diag::note_previous_definition);
Name = 0;
PrevDecl = 0;
@@ -3589,10 +4378,11 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
}
}
// If we get here we have (another) forward declaration or we
- // have a definition. Just create a new decl.
+ // 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
+ // 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;
@@ -3617,10 +4407,10 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
PrevDecl = 0;
}
}
- } else if (TK == TK_Reference && SS.isEmpty() && Name &&
+ } else if (TUK == TUK_Reference && SS.isEmpty() && Name &&
(Kind != TagDecl::TK_enum || !getLangOptions().CPlusPlus)) {
// C++ [basic.scope.pdecl]p5:
- // -- for an elaborated-type-specifier of the form
+ // -- for an elaborated-type-specifier of the form
//
// class-key identifier
//
@@ -3641,26 +4431,38 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
//
// Find the context where we'll be declaring the tag.
// FIXME: We would like to maintain the current DeclContext as the
- // lexical context,
+ // lexical context,
while (SearchDC->isRecord())
SearchDC = SearchDC->getParent();
// Find the scope where we'll be declaring the tag.
- while (S->isClassScope() ||
+ while (S->isClassScope() ||
(getLangOptions().CPlusPlus && S->isFunctionPrototypeScope()) ||
((S->getFlags() & Scope::DeclScope) == 0) ||
- (S->getEntity() &&
+ (S->getEntity() &&
((DeclContext *)S->getEntity())->isTransparentContext()))
S = S->getParent();
+
+ } else if (TUK == TUK_Friend && SS.isEmpty() && Name) {
+ // C++ [namespace.memdef]p3:
+ // If a friend declaration in a non-local class first declares a
+ // class or function, the friend class or function is a member of
+ // the innermost enclosing namespace.
+ while (!SearchDC->isFileContext())
+ SearchDC = SearchDC->getParent();
+
+ // The entity of a decl scope is a DeclContext; see PushDeclContext.
+ while (S->getEntity() != SearchDC)
+ 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.
@@ -3669,10 +4471,10 @@ CreateNewDecl:
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,
+ New = EnumDecl::Create(Context, SearchDC, Loc, Name, KWLoc,
cast_or_null<EnumDecl>(PrevDecl));
// If this is an undefined enum, warn.
- if (TK != TK_Definition && !Invalid) {
+ if (TUK != TUK_Definition && !Invalid) {
unsigned DK = getLangOptions().CPlusPlus? diag::err_forward_ref_enum
: diag::ext_forward_ref_enum;
Diag(Loc, DK);
@@ -3682,12 +4484,15 @@ CreateNewDecl:
// 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)
+ if (getLangOptions().CPlusPlus) {
// FIXME: Look for a way to use RecordDecl for simple structs.
- New = CXXRecordDecl::Create(Context, Kind, SearchDC, Loc, Name,
+ New = CXXRecordDecl::Create(Context, Kind, SearchDC, Loc, Name, KWLoc,
cast_or_null<CXXRecordDecl>(PrevDecl));
- else
- New = RecordDecl::Create(Context, Kind, SearchDC, Loc, Name,
+
+ if (isStdBadAlloc && (!StdBadAlloc || StdBadAlloc->isImplicit()))
+ StdBadAlloc = cast<CXXRecordDecl>(New);
+ } else
+ New = RecordDecl::Create(Context, Kind, SearchDC, Loc, Name, KWLoc,
cast_or_null<RecordDecl>(PrevDecl));
}
@@ -3704,7 +4509,7 @@ CreateNewDecl:
// the #pragma tokens are effectively skipped over during the
// parsing of the struct).
if (unsigned Alignment = getPragmaPackAlignment())
- New->addAttr(::new (Context) PackedAttr(Alignment * 8));
+ New->addAttr(::new (Context) PragmaPackAttr(Alignment * 8));
}
if (getLangOptions().CPlusPlus && SS.isEmpty() && Name && !Invalid) {
@@ -3713,12 +4518,14 @@ CreateNewDecl:
// 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);
+ LookupResult Lookup;
+ LookupName(Lookup, S, Name, LookupOrdinaryName, true);
TypedefDecl *PrevTypedef = 0;
- if (Lookup.getKind() == LookupResult::Found)
- PrevTypedef = dyn_cast<TypedefDecl>(Lookup.getAsDecl());
+ if (NamedDecl *Prev = Lookup.getAsSingleDecl(Context))
+ PrevTypedef = dyn_cast<TypedefDecl>(Prev);
- if (PrevTypedef && isDeclInScope(PrevTypedef, SearchDC, S) &&
+ NamedDecl *PrevTypedefNamed = PrevTypedef;
+ if (PrevTypedef && isDeclInScope(PrevTypedefNamed, SearchDC, S) &&
Context.getCanonicalType(Context.getTypeDeclType(PrevTypedef)) !=
Context.getCanonicalType(Context.getTypeDeclType(New))) {
Diag(Loc, diag::err_tag_definition_of_typedef)
@@ -3729,6 +4536,11 @@ CreateNewDecl:
}
}
+ // If this is a specialization of a member class (of a class template),
+ // check the specialization.
+ if (isExplicitSpecialization && CheckMemberSpecialization(New, PrevDecl))
+ Invalid = true;
+
if (Invalid)
New->setInvalidDecl();
@@ -3744,21 +4556,45 @@ CreateNewDecl:
// lexical context will be different from the semantic context.
New->setLexicalDeclContext(CurContext);
+ // Mark this as a friend decl if applicable.
+ if (TUK == TUK_Friend)
+ New->setObjectOfFriendDecl(/* PreviouslyDeclared = */ PrevDecl != NULL);
+
// Set the access specifier.
- if (!Invalid)
+ if (!Invalid && TUK != TUK_Friend)
SetMemberAccessSpecifier(New, PrevDecl, AS);
- if (TK == TK_Definition)
+ if (TUK == TUK_Definition)
New->startDefinition();
-
+
// If this has an identifier, add it to the scope stack.
- if (Name) {
+ if (TUK == TUK_Friend) {
+ // We might be replacing an existing declaration in the lookup tables;
+ // if so, borrow its access specifier.
+ if (PrevDecl)
+ New->setAccess(PrevDecl->getAccess());
+
+ // Friend tag decls are visible in fairly strange ways.
+ if (!CurContext->isDependentContext()) {
+ DeclContext *DC = New->getDeclContext()->getLookupContext();
+ DC->makeDeclVisibleInContext(New, /* Recoverable = */ false);
+ if (Scope *EnclosingScope = getScopeForDeclContext(S, DC))
+ PushOnScopeChains(New, EnclosingScope, /* AddToContext = */ false);
+ }
+ } else if (Name) {
S = getNonFieldDeclScope(S);
PushOnScopeChains(New, S);
} else {
CurContext->addDecl(New);
}
+ // If this is the C FILE type, notify the AST context.
+ if (IdentifierInfo *II = New->getIdentifier())
+ if (!New->isInvalidDecl() &&
+ New->getDeclContext()->getLookupContext()->isTranslationUnit() &&
+ II->isStr("FILE"))
+ Context.setFILEDecl(New);
+
OwnedDecl = true;
return DeclPtrTy::make(New);
}
@@ -3774,7 +4610,7 @@ void Sema::ActOnTagStartDefinition(Scope *S, DeclPtrTy TagD) {
FieldCollector->StartClass();
if (Record->getIdentifier()) {
- // C++ [class]p2:
+ // 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
@@ -3782,21 +4618,25 @@ void Sema::ActOnTagStartDefinition(Scope *S, DeclPtrTy TagD) {
CXXRecordDecl *InjectedClassName
= CXXRecordDecl::Create(Context, Record->getTagKind(),
CurContext, Record->getLocation(),
- Record->getIdentifier(), Record);
+ Record->getIdentifier(),
+ Record->getTagKeywordLoc(),
+ Record);
InjectedClassName->setImplicit();
InjectedClassName->setAccess(AS_public);
if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate())
InjectedClassName->setDescribedClassTemplate(Template);
PushOnScopeChains(InjectedClassName, S);
- assert(InjectedClassName->isInjectedClassName() &&
+ assert(InjectedClassName->isInjectedClassName() &&
"Broken injected-class-name");
}
}
}
-void Sema::ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagD) {
+void Sema::ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagD,
+ SourceLocation RBraceLoc) {
AdjustDeclIfTemplate(TagD);
TagDecl *Tag = cast<TagDecl>(TagD.getAs<Decl>());
+ Tag->setRBraceLoc(RBraceLoc);
if (isa<CXXRecordDecl>(Tag))
FieldCollector->FinishClass();
@@ -3809,9 +4649,13 @@ void Sema::ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagD) {
}
// Note that FieldName may be null for anonymous bitfields.
-bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName,
- QualType FieldTy, const Expr *BitWidth) {
-
+bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName,
+ QualType FieldTy, const Expr *BitWidth,
+ bool *ZeroWidth) {
+ // Default to true; that shouldn't confuse checks for emptiness
+ if (ZeroWidth)
+ *ZeroWidth = true;
+
// 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()) {
@@ -3834,13 +4678,16 @@ bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName,
if (VerifyIntegerConstantExpression(BitWidth, &Value))
return true;
+ if (Value != 0 && ZeroWidth)
+ *ZeroWidth = false;
+
// 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)
+ 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);
@@ -3863,7 +4710,7 @@ bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName,
/// 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,
+ SourceLocation DeclStart,
Declarator &D, ExprTy *BitfieldWidth) {
FieldDecl *Res = HandleField(S, cast_or_null<RecordDecl>(TagD.getAs<Decl>()),
DeclStart, D, static_cast<Expr*>(BitfieldWidth),
@@ -3880,8 +4727,9 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
IdentifierInfo *II = D.getIdentifier();
SourceLocation Loc = DeclStart;
if (II) Loc = D.getIdentifierLoc();
-
- QualType T = GetTypeForDeclarator(D, S);
+
+ DeclaratorInfo *DInfo = 0;
+ QualType T = GetTypeForDeclarator(D, S, &DInfo);
if (getLangOptions().CPlusPlus)
CheckExtraCXXDefaultArguments(D);
@@ -3890,7 +4738,7 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
if (D.getDeclSpec().isThreadSpecified())
Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread);
- NamedDecl *PrevDecl = LookupName(S, II, LookupMemberName, true);
+ NamedDecl *PrevDecl = LookupSingleName(S, II, LookupMemberName, true);
if (PrevDecl && PrevDecl->isTemplateParameter()) {
// Maybe we will complain about the shadowed template parameter.
@@ -3902,10 +4750,12 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
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);
+ bool Mutable
+ = (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_mutable);
+ SourceLocation TSSL = D.getSourceRange().getBegin();
+ FieldDecl *NewFD
+ = CheckFieldDecl(II, T, DInfo, Record, Loc, Mutable, BitWidth, TSSL,
+ 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.
@@ -3926,10 +4776,12 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
///
/// \returns a new FieldDecl.
///
-/// \todo The Declarator argument is a hack. It will be removed once
-FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
+/// \todo The Declarator argument is a hack. It will be removed once
+FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
+ DeclaratorInfo *DInfo,
RecordDecl *Record, SourceLocation Loc,
- bool Mutable, Expr *BitWidth,
+ bool Mutable, Expr *BitWidth,
+ SourceLocation TSSL,
AccessSpecifier AS, NamedDecl *PrevDecl,
Declarator *D) {
IdentifierInfo *II = Name.getAsIdentifierInfo();
@@ -3957,25 +4809,26 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
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,
+ if (RequireNonAbstractType(Loc, T, diag::err_abstract_type_in_decl,
AbstractFieldType))
InvalidDecl = true;
-
+
+ bool ZeroWidth = false;
// If this is declared as a bit-field, check the bit-field.
- if (BitWidth && VerifyBitField(Loc, II, T, BitWidth)) {
+ if (BitWidth && VerifyBitField(Loc, II, T, BitWidth, &ZeroWidth)) {
InvalidDecl = true;
DeleteExpr(BitWidth);
BitWidth = 0;
+ ZeroWidth = false;
}
-
- FieldDecl *NewFD = FieldDecl::Create(Context, Record, Loc, II, T, BitWidth,
- Mutable);
+
+ FieldDecl *NewFD = FieldDecl::Create(Context, Record, Loc, II, T, DInfo,
+ BitWidth, Mutable);
if (InvalidDecl)
NewFD->setInvalidDecl();
@@ -3985,8 +4838,61 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
NewFD->setInvalidDecl();
}
- if (getLangOptions().CPlusPlus && !T->isPODType())
- cast<CXXRecordDecl>(Record)->setPOD(false);
+ if (getLangOptions().CPlusPlus) {
+ QualType EltTy = Context.getBaseElementType(T);
+
+ CXXRecordDecl* CXXRecord = cast<CXXRecordDecl>(Record);
+
+ if (!T->isPODType())
+ CXXRecord->setPOD(false);
+ if (!ZeroWidth)
+ CXXRecord->setEmpty(false);
+
+ if (const RecordType *RT = EltTy->getAs<RecordType>()) {
+ CXXRecordDecl* RDecl = cast<CXXRecordDecl>(RT->getDecl());
+
+ if (!RDecl->hasTrivialConstructor())
+ CXXRecord->setHasTrivialConstructor(false);
+ if (!RDecl->hasTrivialCopyConstructor())
+ CXXRecord->setHasTrivialCopyConstructor(false);
+ if (!RDecl->hasTrivialCopyAssignment())
+ CXXRecord->setHasTrivialCopyAssignment(false);
+ if (!RDecl->hasTrivialDestructor())
+ CXXRecord->setHasTrivialDestructor(false);
+
+ // C++ 9.5p1: An object of a class with a non-trivial
+ // constructor, a non-trivial copy constructor, a non-trivial
+ // destructor, or a non-trivial copy assignment operator
+ // cannot be a member of a union, nor can an array of such
+ // objects.
+ // TODO: C++0x alters this restriction significantly.
+ if (Record->isUnion()) {
+ // We check for copy constructors before constructors
+ // because otherwise we'll never get complaints about
+ // copy constructors.
+
+ const CXXSpecialMember invalid = (CXXSpecialMember) -1;
+
+ CXXSpecialMember member;
+ if (!RDecl->hasTrivialCopyConstructor())
+ member = CXXCopyConstructor;
+ else if (!RDecl->hasTrivialConstructor())
+ member = CXXDefaultConstructor;
+ else if (!RDecl->hasTrivialCopyAssignment())
+ member = CXXCopyAssignment;
+ else if (!RDecl->hasTrivialDestructor())
+ member = CXXDestructor;
+ else
+ member = invalid;
+
+ if (member != invalid) {
+ Diag(Loc, diag::err_illegal_union_member) << Name << member;
+ DiagnoseNontrivial(RT, member);
+ NewFD->setInvalidDecl();
+ }
+ }
+ }
+ }
// FIXME: We need to pass in the attributes given an AST
// representation, not a parser representation.
@@ -4013,7 +4919,131 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
return NewFD;
}
-/// TranslateIvarVisibility - Translate visibility from a token ID to an
+/// DiagnoseNontrivial - Given that a class has a non-trivial
+/// special member, figure out why.
+void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
+ QualType QT(T, 0U);
+ CXXRecordDecl* RD = cast<CXXRecordDecl>(T->getDecl());
+
+ // Check whether the member was user-declared.
+ switch (member) {
+ case CXXDefaultConstructor:
+ if (RD->hasUserDeclaredConstructor()) {
+ typedef CXXRecordDecl::ctor_iterator ctor_iter;
+ for (ctor_iter ci = RD->ctor_begin(), ce = RD->ctor_end(); ci != ce; ++ci)
+ if (!ci->isImplicitlyDefined(Context)) {
+ SourceLocation CtorLoc = ci->getLocation();
+ Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member;
+ return;
+ }
+
+ assert(0 && "found no user-declared constructors");
+ return;
+ }
+ break;
+
+ case CXXCopyConstructor:
+ if (RD->hasUserDeclaredCopyConstructor()) {
+ SourceLocation CtorLoc =
+ RD->getCopyConstructor(Context, 0)->getLocation();
+ Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member;
+ return;
+ }
+ break;
+
+ case CXXCopyAssignment:
+ if (RD->hasUserDeclaredCopyAssignment()) {
+ // FIXME: this should use the location of the copy
+ // assignment, not the type.
+ SourceLocation TyLoc = RD->getSourceRange().getBegin();
+ Diag(TyLoc, diag::note_nontrivial_user_defined) << QT << member;
+ return;
+ }
+ break;
+
+ case CXXDestructor:
+ if (RD->hasUserDeclaredDestructor()) {
+ SourceLocation DtorLoc = RD->getDestructor(Context)->getLocation();
+ Diag(DtorLoc, diag::note_nontrivial_user_defined) << QT << member;
+ return;
+ }
+ break;
+ }
+
+ typedef CXXRecordDecl::base_class_iterator base_iter;
+
+ // Virtual bases and members inhibit trivial copying/construction,
+ // but not trivial destruction.
+ if (member != CXXDestructor) {
+ // Check for virtual bases. vbases includes indirect virtual bases,
+ // so we just iterate through the direct bases.
+ for (base_iter bi = RD->bases_begin(), be = RD->bases_end(); bi != be; ++bi)
+ if (bi->isVirtual()) {
+ SourceLocation BaseLoc = bi->getSourceRange().getBegin();
+ Diag(BaseLoc, diag::note_nontrivial_has_virtual) << QT << 1;
+ return;
+ }
+
+ // Check for virtual methods.
+ typedef CXXRecordDecl::method_iterator meth_iter;
+ for (meth_iter mi = RD->method_begin(), me = RD->method_end(); mi != me;
+ ++mi) {
+ if (mi->isVirtual()) {
+ SourceLocation MLoc = mi->getSourceRange().getBegin();
+ Diag(MLoc, diag::note_nontrivial_has_virtual) << QT << 0;
+ return;
+ }
+ }
+ }
+
+ bool (CXXRecordDecl::*hasTrivial)() const;
+ switch (member) {
+ case CXXDefaultConstructor:
+ hasTrivial = &CXXRecordDecl::hasTrivialConstructor; break;
+ case CXXCopyConstructor:
+ hasTrivial = &CXXRecordDecl::hasTrivialCopyConstructor; break;
+ case CXXCopyAssignment:
+ hasTrivial = &CXXRecordDecl::hasTrivialCopyAssignment; break;
+ case CXXDestructor:
+ hasTrivial = &CXXRecordDecl::hasTrivialDestructor; break;
+ default:
+ assert(0 && "unexpected special member"); return;
+ }
+
+ // Check for nontrivial bases (and recurse).
+ for (base_iter bi = RD->bases_begin(), be = RD->bases_end(); bi != be; ++bi) {
+ const RecordType *BaseRT = bi->getType()->getAs<RecordType>();
+ assert(BaseRT);
+ CXXRecordDecl *BaseRecTy = cast<CXXRecordDecl>(BaseRT->getDecl());
+ if (!(BaseRecTy->*hasTrivial)()) {
+ SourceLocation BaseLoc = bi->getSourceRange().getBegin();
+ Diag(BaseLoc, diag::note_nontrivial_has_nontrivial) << QT << 1 << member;
+ DiagnoseNontrivial(BaseRT, member);
+ return;
+ }
+ }
+
+ // Check for nontrivial members (and recurse).
+ typedef RecordDecl::field_iterator field_iter;
+ for (field_iter fi = RD->field_begin(), fe = RD->field_end(); fi != fe;
+ ++fi) {
+ QualType EltTy = Context.getBaseElementType((*fi)->getType());
+ if (const RecordType *EltRT = EltTy->getAs<RecordType>()) {
+ CXXRecordDecl* EltRD = cast<CXXRecordDecl>(EltRT->getDecl());
+
+ if (!(EltRD->*hasTrivial)()) {
+ SourceLocation FLoc = (*fi)->getLocation();
+ Diag(FLoc, diag::note_nontrivial_has_nontrivial) << QT << 0 << member;
+ DiagnoseNontrivial(EltRT, member);
+ return;
+ }
+ }
+ }
+
+ assert(0 && "found no explanation for non-trivial member");
+}
+
+/// TranslateIvarVisibility - Translate visibility from a token ID to an
/// AST enum value.
static ObjCIvarDecl::AccessControl
TranslateIvarVisibility(tok::ObjCKeywordKind ivarVisibility) {
@@ -4026,24 +5056,25 @@ TranslateIvarVisibility(tok::ObjCKeywordKind ivarVisibility) {
}
}
-/// ActOnIvar - Each ivar field of an objective-c class is passed into this
+/// 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,
+ SourceLocation DeclStart,
DeclPtrTy IntfDecl,
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);
-
+
+ DeclaratorInfo *DInfo = 0;
+ QualType T = GetTypeForDeclarator(D, S, &DInfo);
+
if (BitWidth) {
// 6.7.2.1p3, 6.7.2.1p4
if (VerifyBitField(Loc, II, T, BitWidth)) {
@@ -4053,43 +5084,42 @@ Sema::DeclPtrTy Sema::ActOnIvar(Scope *S,
}
} 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 =
+ ObjCIvarDecl::AccessControl ac =
Visibility != tok::objc_not_keyword ? TranslateIvarVisibility(Visibility)
: ObjCIvarDecl::None;
// Must set ivar's DeclContext to its enclosing interface.
Decl *EnclosingDecl = IntfDecl.getAs<Decl>();
DeclContext *EnclosingContext;
- if (ObjCImplementationDecl *IMPDecl =
+ if (ObjCImplementationDecl *IMPDecl =
dyn_cast<ObjCImplementationDecl>(EnclosingDecl)) {
// Case of ivar declared in an implementation. Context is that of its class.
ObjCInterfaceDecl* IDecl = IMPDecl->getClassInterface();
assert(IDecl && "No class- ActOnIvar");
EnclosingContext = cast_or_null<DeclContext>(IDecl);
- }
- else
+ } else
EnclosingContext = dyn_cast<DeclContext>(EnclosingDecl);
assert(EnclosingContext && "null DeclContext for ivar - ActOnIvar");
-
+
// Construct the decl.
- ObjCIvarDecl *NewID = ObjCIvarDecl::Create(Context,
- EnclosingContext, Loc, II, T,ac,
- (Expr *)BitfieldWidth);
-
+ ObjCIvarDecl *NewID = ObjCIvarDecl::Create(Context,
+ EnclosingContext, Loc, II, T,
+ DInfo, ac, (Expr *)BitfieldWidth);
+
if (II) {
- NamedDecl *PrevDecl = LookupName(S, II, LookupMemberName, true);
+ NamedDecl *PrevDecl = LookupSingleName(S, II, LookupMemberName, true);
if (PrevDecl && isDeclInScope(PrevDecl, EnclosingContext, S)
&& !isa<TagDecl>(PrevDecl)) {
Diag(Loc, diag::err_duplicate_member) << II;
@@ -4100,7 +5130,7 @@ Sema::DeclPtrTy Sema::ActOnIvar(Scope *S,
// Process attributes attached to the ivar.
ProcessDeclAttributes(S, NewID, D);
-
+
if (D.isInvalidType())
NewID->setInvalidDecl();
@@ -4121,7 +5151,7 @@ void Sema::ActOnFields(Scope* S,
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()) {
@@ -4129,7 +5159,7 @@ void Sema::ActOnFields(Scope* S,
return;
}
-
+
// Verify that all the fields are okay.
unsigned NumNamedMembers = 0;
llvm::SmallVector<FieldDecl*, 32> RecFields;
@@ -4137,7 +5167,7 @@ void Sema::ActOnFields(Scope* S,
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();
@@ -4145,12 +5175,12 @@ void Sema::ActOnFields(Scope* S,
// 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
@@ -4182,13 +5212,13 @@ void Sema::ActOnFields(Scope* S,
if (Record)
Record->setHasFlexibleArrayMember(true);
} else if (!FDTy->isDependentType() &&
- RequireCompleteType(FD->getLocation(), FD->getType(),
+ RequireCompleteType(FD->getLocation(), FD->getType(),
diag::err_field_incomplete)) {
// Incomplete type
FD->setInvalidDecl();
EnclosingDecl->setInvalidDecl();
continue;
- } else if (const RecordType *FDTTy = FDTy->getAsRecordType()) {
+ } else if (const RecordType *FDTTy = FDTy->getAs<RecordType>()) {
if (FDTTy->getDecl()->hasFlexibleArrayMember()) {
// If this is a member of a union, then entire union becomes "flexible".
if (Record && Record->isUnion()) {
@@ -4210,13 +5240,20 @@ void Sema::ActOnFields(Scope* S,
}
}
}
+ if (Record && FDTTy->getDecl()->hasObjectMember())
+ Record->setHasObjectMember(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;
- }
+ } else if (getLangOptions().ObjC1 &&
+ getLangOptions().getGCMode() != LangOptions::NonGC &&
+ Record &&
+ (FD->getType()->isObjCObjectPointerType() ||
+ FD->getType().isObjCGCStrong()))
+ Record->setHasObjectMember(true);
// Keep track of the number of named members.
if (FD->getIdentifier())
++NumNamedMembers;
@@ -4239,7 +5276,7 @@ void Sema::ActOnFields(Scope* S,
// 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(),
+ for (ObjCInterfaceDecl::ivar_iterator IVI = ID->ivar_begin(),
IVE = ID->ivar_end(); IVI != IVE; ++IVI) {
ObjCIvarDecl* Ivar = (*IVI);
@@ -4253,7 +5290,7 @@ void Sema::ActOnFields(Scope* S,
}
}
}
- } else if (ObjCImplementationDecl *IMPDecl =
+ } else if (ObjCImplementationDecl *IMPDecl =
dyn_cast<ObjCImplementationDecl>(EnclosingDecl)) {
assert(IMPDecl && "ActOnFields - missing ObjCImplementationDecl");
for (unsigned I = 0, N = RecFields.size(); I != N; ++I)
@@ -4294,7 +5331,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
EltTy = Val->getType();
}
}
-
+
if (!Val) {
if (LastEnumConst) {
// Assign the last value + 1.
@@ -4304,7 +5341,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
// 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.
@@ -4312,10 +5349,10 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
EnumVal.zextOrTrunc(static_cast<uint32_t>(Context.getTypeSize(EltTy)));
}
}
-
+
val.release();
return EnumConstantDecl::Create(Context, Enum, IdLoc, Id, EltTy,
- Val, EnumVal);
+ Val, EnumVal);
}
@@ -4332,10 +5369,10 @@ Sema::DeclPtrTy Sema::ActOnEnumConstant(Scope *S, DeclPtrTy theEnumDecl,
// 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);
+ NamedDecl *PrevDecl = LookupSingleName(S, Id, LookupOrdinaryName);
if (PrevDecl && PrevDecl->isTemplateParameter()) {
// Maybe we will complain about the shadowed template parameter.
DiagnoseTemplateParameterShadow(IdLoc, PrevDecl);
@@ -4371,28 +5408,34 @@ Sema::DeclPtrTy Sema::ActOnEnumConstant(Scope *S, DeclPtrTy theEnumDecl,
void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
SourceLocation RBraceLoc, DeclPtrTy EnumDeclX,
- DeclPtrTy *Elements, unsigned NumElements) {
+ DeclPtrTy *Elements, unsigned NumElements,
+ Scope *S, AttributeList *Attr) {
EnumDecl *Enum = cast<EnumDecl>(EnumDeclX.getAs<Decl>());
QualType EnumType = Context.getTypeDeclType(Enum);
-
+
+ if (Attr)
+ ProcessDeclAttributeList(S, Enum, Attr);
+
// TODO: If the result value doesn't fit in an int, it must be a long or long
// long value. ISO C does not support this, but GCC does as an extension,
// emit a warning.
unsigned IntWidth = Context.Target.getIntWidth();
-
+ unsigned CharWidth = Context.Target.getCharWidth();
+ unsigned ShortWidth = Context.Target.getShortWidth();
+
// 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 &&
@@ -4405,7 +5448,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
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,
@@ -4416,28 +5459,39 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
// Keep track of whether every enum element has type int (very commmon).
if (AllElementsInt)
- AllElementsInt = ECD->getType() == Context.IntTy;
+ 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.
+ // FIXME: Support -fshort-enums.
QualType BestType;
unsigned BestWidth;
-
+
+ bool Packed = Enum->getAttr<PackedAttr>() ? true : false;
+
if (NumNegativeBits) {
- // If there is a negative value, figure out the smallest integer type (of
+ // If there is a negative value, figure out the smallest integer type (of
// int/long/longlong) that fits.
- if (NumNegativeBits <= IntWidth && NumPositiveBits < IntWidth) {
+ // If it's packed, check also if it fits a char or a short.
+ if (Packed && NumNegativeBits <= CharWidth && NumPositiveBits < CharWidth) {
+ BestType = Context.SignedCharTy;
+ BestWidth = CharWidth;
+ } else if (Packed && NumNegativeBits <= ShortWidth &&
+ NumPositiveBits < ShortWidth) {
+ BestType = Context.ShortTy;
+ BestWidth = ShortWidth;
+ }
+ else 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;
@@ -4446,7 +5500,15 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
} else {
// If there is no negative value, figure out which of uint, ulong, ulonglong
// fits.
- if (NumPositiveBits <= IntWidth) {
+ // If it's packed, check also if it fits a char or a short.
+ if (Packed && NumPositiveBits <= CharWidth) {
+ BestType = Context.UnsignedCharTy;
+ BestWidth = CharWidth;
+ } else if (Packed && NumPositiveBits <= ShortWidth) {
+ BestType = Context.UnsignedShortTy;
+ BestWidth = ShortWidth;
+ }
+ else if (NumPositiveBits <= IntWidth) {
BestType = Context.UnsignedIntTy;
BestWidth = IntWidth;
} else if (NumPositiveBits <=
@@ -4459,7 +5521,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
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) {
@@ -4481,7 +5543,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
if (getLangOptions().CPlusPlus)
// C++ [dcl.enum]p4: Following the closing brace of an
// enum-specifier, each enumerator has the type of its
- // enumeration.
+ // enumeration.
ECD->setType(EnumType);
continue; // Already int type.
}
@@ -4508,7 +5570,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
if (getLangOptions().CPlusPlus)
// C++ [dcl.enum]p4: Following the closing brace of an
// enum-specifier, each enumerator has the type of its
- // enumeration.
+ // enumeration.
ECD->setType(EnumType);
continue;
} else {
@@ -4521,20 +5583,22 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
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(),
+ ECD->setInitExpr(new (Context) ImplicitCastExpr(NewTy,
+ CastExpr::CK_Unknown,
+ 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.
+ // enumeration.
ECD->setType(EnumType);
else
ECD->setType(NewTy);
}
-
+
Enum->completeDefinition(Context, BestType);
}
@@ -4551,15 +5615,15 @@ Sema::DeclPtrTy Sema::ActOnFileScopeAsmDecl(SourceLocation Loc,
void Sema::ActOnPragmaWeakID(IdentifierInfo* Name,
SourceLocation PragmaLoc,
SourceLocation NameLoc) {
- Decl *PrevDecl = LookupName(TUScope, Name, LookupOrdinaryName);
+ Decl *PrevDecl = LookupSingleName(TUScope, Name, LookupOrdinaryName);
- // FIXME: This implementation is an ugly hack!
if (PrevDecl) {
PrevDecl->addAttr(::new (Context) WeakAttr());
- return;
+ } else {
+ (void)WeakUndeclaredIdentifiers.insert(
+ std::pair<IdentifierInfo*,WeakInfo>
+ (Name, WeakInfo((IdentifierInfo*)0, NameLoc)));
}
- Diag(PragmaLoc, diag::err_unsupported_pragma_weak);
- return;
}
void Sema::ActOnPragmaWeakAlias(IdentifierInfo* Name,
@@ -4567,14 +5631,15 @@ void Sema::ActOnPragmaWeakAlias(IdentifierInfo* Name,
SourceLocation PragmaLoc,
SourceLocation NameLoc,
SourceLocation AliasNameLoc) {
- Decl *PrevDecl = LookupName(TUScope, Name, LookupOrdinaryName);
+ Decl *PrevDecl = LookupSingleName(TUScope, AliasName, LookupOrdinaryName);
+ WeakInfo W = WeakInfo(Name, NameLoc);
- // FIXME: This implementation is an ugly hack!
if (PrevDecl) {
- PrevDecl->addAttr(::new (Context) AliasAttr(AliasName->getName()));
- PrevDecl->addAttr(::new (Context) WeakAttr());
- return;
+ if (!PrevDecl->hasAttr<AliasAttr>())
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(PrevDecl))
+ DeclApplyPragmaWeak(TUScope, ND, W);
+ } else {
+ (void)WeakUndeclaredIdentifiers.insert(
+ std::pair<IdentifierInfo*,WeakInfo>(AliasName, W));
}
- Diag(PragmaLoc, diag::err_unsupported_pragma_weak);
- return;
}
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 2b71df7..50ebb49 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -17,46 +17,53 @@
#include "clang/AST/Expr.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Parse/DeclSpec.h"
-#include <llvm/ADT/StringExtras.h>
+#include "llvm/ADT/StringExtras.h"
using namespace clang;
//===----------------------------------------------------------------------===//
// Helper functions
//===----------------------------------------------------------------------===//
-static const FunctionType *getFunctionType(Decl *d, bool blocksToo = true) {
+static const FunctionType *getFunctionType(const Decl *d,
+ bool blocksToo = true) {
QualType Ty;
- if (ValueDecl *decl = dyn_cast<ValueDecl>(d))
+ if (const ValueDecl *decl = dyn_cast<ValueDecl>(d))
Ty = decl->getType();
- else if (FieldDecl *decl = dyn_cast<FieldDecl>(d))
+ else if (const FieldDecl *decl = dyn_cast<FieldDecl>(d))
Ty = decl->getType();
- else if (TypedefDecl* decl = dyn_cast<TypedefDecl>(d))
+ else if (const TypedefDecl* decl = dyn_cast<TypedefDecl>(d))
Ty = decl->getUnderlyingType();
else
return 0;
-
+
if (Ty->isFunctionPointerType())
- Ty = Ty->getAsPointerType()->getPointeeType();
+ Ty = Ty->getAs<PointerType>()->getPointeeType();
else if (blocksToo && Ty->isBlockPointerType())
- Ty = Ty->getAsBlockPointerType()->getPointeeType();
+ Ty = Ty->getAs<BlockPointerType>()->getPointeeType();
- return Ty->getAsFunctionType();
+ return Ty->getAs<FunctionType>();
}
// 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).
+static bool isFunction(const Decl *d) {
+ return getFunctionType(d, false) != NULL;
+}
+
+/// 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);
+static bool isFunctionOrMethod(const Decl *d) {
+ return isFunction(d)|| 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) {
+static bool isFunctionOrMethodOrBlock(const Decl *d) {
if (isFunctionOrMethod(d))
return true;
// check for block is more involved.
@@ -70,7 +77,7 @@ static bool isFunctionOrMethodOrBlock(Decl *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) {
+static bool hasFunctionProto(const Decl *d) {
if (const FunctionType *FnTy = getFunctionType(d))
return isa<FunctionProtoType>(FnTy);
else {
@@ -82,7 +89,7 @@ static bool hasFunctionProto(Decl *d) {
/// 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) {
+static unsigned getFunctionOrMethodNumArgs(const Decl *d) {
if (const FunctionType *FnTy = getFunctionType(d))
return cast<FunctionProtoType>(FnTy)->getNumArgs();
if (const BlockDecl *BD = dyn_cast<BlockDecl>(d))
@@ -90,22 +97,22 @@ static unsigned getFunctionOrMethodNumArgs(Decl *d) {
return cast<ObjCMethodDecl>(d)->param_size();
}
-static QualType getFunctionOrMethodArgType(Decl *d, unsigned Idx) {
+static QualType getFunctionOrMethodArgType(const 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) {
+static QualType getFunctionOrMethodResultType(const Decl *d) {
if (const FunctionType *FnTy = getFunctionType(d))
return cast<FunctionProtoType>(FnTy)->getResultType();
return cast<ObjCMethodDecl>(d)->getResultType();
}
-static bool isFunctionOrMethodVariadic(Decl *d) {
+static bool isFunctionOrMethodVariadic(const Decl *d) {
if (const FunctionType *FnTy = getFunctionType(d)) {
const FunctionProtoType *proto = cast<FunctionProtoType>(FnTy);
return proto->isVariadic();
@@ -117,30 +124,30 @@ static bool isFunctionOrMethodVariadic(Decl *d) {
}
static inline bool isNSStringType(QualType T, ASTContext &Ctx) {
- const PointerType *PT = T->getAsPointerType();
+ const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>();
if (!PT)
return false;
-
- const ObjCInterfaceType *ClsT =PT->getPointeeType()->getAsObjCInterfaceType();
+
+ const ObjCInterfaceType *ClsT =PT->getPointeeType()->getAs<ObjCInterfaceType>();
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();
+ const PointerType *PT = T->getAs<PointerType>();
if (!PT)
return false;
- const RecordType *RT = PT->getPointeeType()->getAsRecordType();
+ const RecordType *RT = PT->getPointeeType()->getAs<RecordType>();
if (!RT)
return false;
-
+
const RecordDecl *RD = RT->getDecl();
if (RD->getTagKind() != TagDecl::TK_struct)
return false;
@@ -156,14 +163,14 @@ static inline bool isCFStringType(QualType T, ASTContext &Ctx) {
// least add some helper functions to check most argument patterns (#
// and types of args).
-static void HandleExtVectorTypeAttr(Scope *scope, Decl *d,
+static void HandleExtVectorTypeAttr(Scope *scope, 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();
Expr *sizeExpr;
@@ -187,21 +194,20 @@ static void HandleExtVectorTypeAttr(Scope *scope, Decl *d,
QualType T = S.BuildExtVectorType(curType, S.Owned(sizeExpr), Attr.getLoc());
if (!T.isNull()) {
tDecl->setUnderlyingType(T);
-
+
// 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.
+/// 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))
@@ -213,7 +219,7 @@ static void HandleVectorSizeAttr(Decl *D, const AttributeList &Attr, Sema &S) {
<< "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;
@@ -226,8 +232,8 @@ static void HandleVectorSizeAttr(Decl *D, const AttributeList &Attr, Sema &S) {
<< "vector_size" << sizeExpr->getSourceRange();
return;
}
- // navigate to the base type - we need to provide for vector pointers,
- // vector arrays, and functions returning vectors.
+ // 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;
@@ -252,8 +258,8 @@ static void HandleVectorSizeAttr(Decl *D, const AttributeList &Attr, Sema &S) {
}
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);
-
+ 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)
@@ -265,14 +271,14 @@ static void HandleVectorSizeAttr(Decl *D, const AttributeList &Attr, Sema &S) {
<< 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
+ else
cast<TypedefDecl>(D)->setUnderlyingType(CurType);
}
@@ -282,9 +288,9 @@ static void HandlePackedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
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));
+ TD->addAttr(::new (S.Context) PackedAttr);
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.
@@ -293,7 +299,7 @@ static void HandlePackedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored_for_field_of_type)
<< Attr.getName() << FD->getType();
else
- FD->addAttr(::new (S.Context) PackedAttr(1));
+ FD->addAttr(::new (S.Context) PackedAttr);
} else
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
}
@@ -304,7 +310,7 @@ static void HandleIBOutletAttr(Decl *d, const AttributeList &Attr, Sema &S) {
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))
@@ -314,23 +320,23 @@ static void HandleIBOutletAttr(Decl *d, const AttributeList &Attr, Sema &S) {
}
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
+ // 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);
@@ -339,38 +345,38 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) {
<< "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()) {
+ QualType T = getFunctionOrMethodArgType(d, x);
+ if (!T->isAnyPointerType() && !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 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())
+ if (T->isAnyPointerType() || T->isBlockPointerType())
NonNullArgs.push_back(I);
}
-
+
if (NonNullArgs.empty()) {
S.Diag(Attr.getLoc(), diag::warn_attribute_nonnull_no_pointers);
return;
@@ -389,26 +395,26 @@ static void HandleAliasAttr(Decl *d, const AttributeList &Attr, Sema &S) {
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,
+static void HandleAlwaysInlineAttr(Decl *d, const AttributeList &Attr,
Sema &S) {
// check the attribute arguments.
if (Attr.getNumArgs() != 0) {
@@ -421,10 +427,28 @@ static void HandleAlwaysInlineAttr(Decl *d, const AttributeList &Attr,
<< Attr.getName() << 0 /*function*/;
return;
}
-
+
d->addAttr(::new (S.Context) AlwaysInlineAttr());
}
+static void HandleMallocAttr(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 FunctionDecl *FD = dyn_cast<FunctionDecl>(d)) {
+ QualType RetTy = FD->getResultType();
+ if (RetTy->isAnyPointerType() || RetTy->isBlockPointerType()) {
+ d->addAttr(::new (S.Context) MallocAttr());
+ return;
+ }
+ }
+
+ S.Diag(Attr.getLoc(), diag::warn_attribute_malloc_pointer_only);
+}
+
static bool HandleCommonNoReturnAttr(Decl *d, const AttributeList &Attr,
Sema &S) {
// check the attribute arguments.
@@ -441,18 +465,18 @@ static bool HandleCommonNoReturnAttr(Decl *d, const AttributeList &Attr,
return false;
}
}
-
+
return true;
}
static void HandleNoReturnAttr(Decl *d, const AttributeList &Attr, Sema &S) {
- if (HandleCommonNoReturnAttr(d, Attr, 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))
+ if (HandleCommonNoReturnAttr(d, Attr, S))
d->addAttr(::new (S.Context) AnalyzerNoReturnAttr());
}
@@ -462,13 +486,13 @@ static void HandleUnusedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
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());
}
@@ -478,7 +502,7 @@ static void HandleUsedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
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";
@@ -489,7 +513,7 @@ static void HandleUsedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
<< Attr.getName() << 2 /*variable and function*/;
return;
}
-
+
d->addAttr(::new (S.Context) UsedAttr());
}
@@ -499,7 +523,7 @@ static void HandleConstructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
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) {
@@ -512,7 +536,7 @@ static void HandleConstructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
}
priority = Idx.getZExtValue();
}
-
+
if (!isa<FunctionDecl>(d)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << 0 /*function*/;
@@ -528,7 +552,7 @@ static void HandleDestructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
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) {
@@ -541,7 +565,7 @@ static void HandleDestructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
}
priority = Idx.getZExtValue();
}
-
+
if (!isa<FunctionDecl>(d)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << 0 /*function*/;
@@ -557,7 +581,7 @@ static void HandleDeprecatedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
-
+
d->addAttr(::new (S.Context) DeprecatedAttr());
}
@@ -567,7 +591,7 @@ static void HandleUnavailableAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
-
+
d->addAttr(::new (S.Context) UnavailableAttr());
}
@@ -577,21 +601,21 @@ static void HandleVisibilityAttr(Decl *d, const AttributeList &Attr, Sema &S) {
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))
@@ -604,7 +628,7 @@ static void HandleVisibilityAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::warn_attribute_unknown_visibility) << TypeStr;
return;
}
-
+
d->addAttr(::new (S.Context) VisibilityAttr(type));
}
@@ -614,13 +638,13 @@ static void HandleObjCExceptionAttr(Decl *D, const AttributeList &Attr,
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());
}
@@ -632,7 +656,7 @@ static void HandleObjCNSObject(Decl *D, const AttributeList &Attr, Sema &S) {
if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
QualType T = TD->getUnderlyingType();
if (!T->isPointerType() ||
- !T->getAsPointerType()->getPointeeType()->isRecordType()) {
+ !T->getAs<PointerType>()->getPointeeType()->isRecordType()) {
S.Diag(TD->getLocation(), diag::err_nsobject_attribute);
return;
}
@@ -640,7 +664,7 @@ static void HandleObjCNSObject(Decl *D, const AttributeList &Attr, Sema &S) {
D->addAttr(::new (S.Context) ObjCNSObjectAttr());
}
-static void
+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;
@@ -656,17 +680,17 @@ HandleOverloadableAttr(Decl *D, const AttributeList &Attr, Sema &S) {
}
static void HandleBlocksAttr(Decl *d, const AttributeList &Attr, Sema &S) {
- if (!Attr.getParameterName()) {
+ 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;
@@ -675,7 +699,7 @@ static void HandleBlocksAttr(Decl *d, const AttributeList &Attr, Sema &S) {
<< "blocks" << Attr.getParameterName();
return;
}
-
+
d->addAttr(::new (S.Context) BlocksAttr(type));
}
@@ -685,8 +709,8 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) {
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));
@@ -697,7 +721,7 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
sentinel = Idx.getZExtValue();
-
+
if (sentinel < 0) {
S.Diag(Attr.getLoc(), diag::err_attribute_sentinel_less_than_zero)
<< E->getSourceRange();
@@ -715,7 +739,7 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) {
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.
@@ -726,39 +750,38 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) {
}
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(d)) {
- const FunctionType *FT = FD->getType()->getAsFunctionType();
+ const FunctionType *FT = FD->getType()->getAs<FunctionType>();
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.
+ // 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();
+ const FunctionType *FT = Ty->isFunctionPointerType() ? getFunctionType(d)
+ : Ty->getAs<BlockPointerType>()->getPointeeType()->getAs<FunctionType>();
if (!cast<FunctionProtoType>(FT)->isVariadic()) {
int m = Ty->isFunctionPointerType() ? 0 : 1;
S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << m;
return;
}
- }
- else {
+ } else {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << 6 /*function, method or block */;
return;
@@ -785,7 +808,7 @@ static void HandleWarnUnusedResult(Decl *D, const AttributeList &Attr, Sema &S)
<< Attr.getName() << 0 /*function*/;
return;
}
-
+
Fn->addAttr(::new (S.Context) WarnUnusedResultAttr());
}
@@ -796,13 +819,26 @@ static void HandleWeakAttr(Decl *D, const AttributeList &Attr, Sema &S) {
return;
}
+ /* weak only applies to non-static declarations */
+ bool isStatic = false;
+ if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ isStatic = VD->getStorageClass() == VarDecl::Static;
+ } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ isStatic = FD->getStorageClass() == FunctionDecl::Static;
+ }
+ if (isStatic) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_weak_static) <<
+ dyn_cast<NamedDecl>(D)->getNameAsString();
+ 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());
}
@@ -811,7 +847,7 @@ static void HandleWeakImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
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;
@@ -830,7 +866,7 @@ static void HandleWeakImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
// Merge should handle any subsequent violations.
if (isDef) {
- S.Diag(Attr.getLoc(),
+ S.Diag(Attr.getLoc(),
diag::warn_attribute_weak_import_invalid_on_definition)
<< "weak_import" << 2 /*variable and function*/;
return;
@@ -904,8 +940,8 @@ static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
return;
}
- // Currently, the dllexport attribute is ignored for inlined functions,
- // unless the -fkeep-inline-functions flag has been used. Warning is emitted;
+ // 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";
@@ -947,15 +983,25 @@ static void HandleSectionAttr(Decl *D, const AttributeList &Attr, Sema &S) {
// 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)));
+ Expr *ArgExpr = static_cast<Expr *>(Attr.getArg(0));
+ StringLiteral *SE = dyn_cast<StringLiteral>(ArgExpr);
if (!SE) {
- // FIXME
- S.Diag(Attr.getLoc(), diag::err_attribute_annotate_no_string);
+ S.Diag(ArgExpr->getLocStart(), diag::err_attribute_not_string) << "section";
+ return;
+ }
+
+ std::string SectionStr(SE->getStrData(), SE->getByteLength());
+
+ // If the target wants to validate the section specifier, make it happen.
+ std::string Error = S.Context.Target.isValidSectionSpecifier(SectionStr);
+ if (Error.empty()) {
+ D->addAttr(::new (S.Context) SectionAttr(SectionStr));
return;
}
- D->addAttr(::new (S.Context) SectionAttr(std::string(SE->getStrData(),
- SE->getByteLength())));
+
+ S.Diag(SE->getLocStart(), diag::err_attribute_section_invalid_for_target)
+ << Error;
+
}
static void HandleStdCallAttr(Decl *d, const AttributeList &Attr, Sema &S) {
@@ -1011,7 +1057,7 @@ static void HandleNothrowAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
-
+
d->addAttr(::new (S.Context) NoThrowAttr());
}
@@ -1021,7 +1067,7 @@ static void HandleConstAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
-
+
d->addAttr(::new (S.Context) ConstAttr());
}
@@ -1031,7 +1077,7 @@ static void HandlePureAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
-
+
d->addAttr(::new (S.Context) PureAttr());
}
@@ -1039,33 +1085,34 @@ 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()) {
+
+ 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);
+ NamedDecl *CleanupDecl
+ = S.LookupSingleName(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) <<
@@ -1078,24 +1125,24 @@ static void HandleCleanupAttr(Decl *d, const AttributeList &Attr, Sema &S) {
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(),
+ 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) {
+/// 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;
@@ -1105,9 +1152,8 @@ static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) {
<< 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.
+ // 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
@@ -1118,46 +1164,46 @@ static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) {
<< "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())) {
+ !Ty->getAs<PointerType>()->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")
+ << (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())) {
+ !Ty->getAs<PointerType>()->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")
+ << (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
+/// 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()) {
@@ -1177,9 +1223,6 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
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;
@@ -1197,19 +1240,23 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
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 7: Supported = !memcmp(Format, "printf0", 7) ||
+ !memcmp(Format, "strfmon", 7) ||
+ !memcmp(Format, "cmn_err", 7); break;
case 8:
Supported = (is_strftime = !memcmp(Format, "strftime", 8)) ||
(is_NSString = !memcmp(Format, "NSString", 8)) ||
+ !memcmp(Format, "vcmn_err", 8) ||
+ !memcmp(Format, "zcmn_err", 8) ||
(is_CFString = !memcmp(Format, "CFString", 8));
break;
}
-
+
if (!Supported) {
S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported)
<< "format" << Attr.getParameterName()->getName();
@@ -1225,6 +1272,16 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
+ // FIXME: We should handle the implicit 'this' parameter in a more generic
+ // way that can be used for other arguments.
+ bool HasImplicitThisParam = false;
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(d)) {
+ if (MD->isInstance()) {
+ HasImplicitThisParam = true;
+ NumArgs++;
+ }
+ }
+
if (Idx.getZExtValue() < FirstIdx || Idx.getZExtValue() > NumArgs) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
<< "format" << 2 << IdxExpr->getSourceRange();
@@ -1233,7 +1290,9 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// FIXME: Do we need to bounds check?
unsigned ArgIdx = Idx.getZExtValue() - 1;
-
+
+ if (HasImplicitThisParam) ArgIdx--;
+
// make sure the format string is really a string
QualType Ty = getFunctionOrMethodArgType(d, ArgIdx);
@@ -1251,9 +1310,9 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_format_attribute_not)
<< "an NSString" << IdxExpr->getSourceRange();
return;
- }
+ }
} else if (!Ty->isPointerType() ||
- !Ty->getAsPointerType()->getPointeeType()->isCharType()) {
+ !Ty->getAs<PointerType>()->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();
@@ -1321,7 +1380,7 @@ static void HandleTransparentUnionAttr(Decl *d, const AttributeList &Attr,
}
if (!RD->isDefinition()) {
- S.Diag(Attr.getLoc(),
+ S.Diag(Attr.getLoc(),
diag::warn_transparent_union_attribute_not_definition);
return;
}
@@ -1336,7 +1395,7 @@ static void HandleTransparentUnionAttr(Decl *d, const AttributeList &Attr,
FieldDecl *FirstField = *Field;
QualType FirstType = FirstField->getType();
if (FirstType->isFloatingType() || FirstType->isVectorType()) {
- S.Diag(FirstField->getLocation(),
+ S.Diag(FirstField->getLocation(),
diag::warn_transparent_union_attribute_floating);
return;
}
@@ -1349,13 +1408,13 @@ static void HandleTransparentUnionAttr(Decl *d, const AttributeList &Attr,
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)
+ unsigned FieldBits = isSize? S.Context.getTypeSize(FieldType)
: S.Context.getTypeAlign(FieldType);
- S.Diag(Field->getLocation(),
+ 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(),
+ S.Diag(FirstField->getLocation(),
diag::note_transparent_union_first_field_size_align)
<< isSize << FirstBits;
return;
@@ -1371,13 +1430,13 @@ static void HandleAnnotateAttr(Decl *d, const AttributeList &Attr, Sema &S) {
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);
-
+ 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);
+ S.Diag(ArgExpr->getLocStart(), diag::err_attribute_not_string) <<"annotate";
return;
}
d->addAttr(::new (S.Context) AnnotateAttr(std::string(SE->getStrData(),
@@ -1399,7 +1458,7 @@ static void HandleAlignedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
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)) {
@@ -1408,7 +1467,7 @@ static void HandleAlignedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
if (!llvm::isPowerOf2_64(Alignment.getZExtValue())) {
- S.Diag(Attr.getLoc(), diag::err_attribute_aligned_not_power_of_two)
+ S.Diag(Attr.getLoc(), diag::err_attribute_aligned_not_power_of_two)
<< alignmentExpr->getSourceRange();
return;
}
@@ -1416,13 +1475,12 @@ static void HandleAlignedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
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.
+/// 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.
@@ -1495,7 +1553,7 @@ static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) {
return;
}
- if (!OldTy->getAsBuiltinType() && !OldTy->isComplexType())
+ if (!OldTy->getAs<BuiltinType>() && !OldTy->isComplexType())
S.Diag(Attr.getLoc(), diag::err_mode_not_primitive);
else if (IntegerMode) {
if (!OldTy->isIntegralType())
@@ -1581,7 +1639,7 @@ static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) {
cast<ValueDecl>(D)->setType(NewTy);
}
-static void HandleNodebugAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+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;
@@ -1593,24 +1651,24 @@ static void HandleNodebugAttr(Decl *d, const AttributeList &Attr, Sema &S) {
<< Attr.getName() << 0 /*function*/;
return;
}
-
- d->addAttr(::new (S.Context) NodebugAttr());
+
+ d->addAttr(::new (S.Context) NoDebugAttr());
}
-static void HandleNoinlineAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+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());
+
+ d->addAttr(::new (S.Context) NoInlineAttr());
}
static void HandleGNUInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) {
@@ -1619,19 +1677,19 @@ static void HandleGNUInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) {
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());
}
@@ -1679,23 +1737,26 @@ 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 */;
+ SourceLocation L = Attr.getLoc();
+ S.Diag(d->getLocStart(), diag::warn_attribute_wrong_decl_type)
+ << SourceRange(L, L) << 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;
+
+ if (!(S.Context.isObjCNSObjectType(RetTy) || RetTy->getAs<PointerType>()
+ || RetTy->getAs<ObjCObjectPointerType>())) {
+ SourceLocation L = Attr.getLoc();
+ S.Diag(d->getLocStart(), diag::warn_ns_attribute_wrong_return_type)
+ << SourceRange(L, L) << Attr.getName();
+ return;
}
-
+
switch (Attr.getKind()) {
default:
assert(0 && "invalid ownership attribute");
@@ -1716,7 +1777,8 @@ static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &Attr,
/// 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(Scope *scope, Decl *D, const AttributeList &Attr, Sema &S) {
+static void ProcessDeclAttribute(Scope *scope, Decl *D,
+ const AttributeList &Attr, Sema &S) {
if (Attr.isDeclspecAttribute())
// FIXME: Try to deal with __declspec attributes!
return;
@@ -1724,14 +1786,15 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, const AttributeList &Att
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.
+ // 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:
+ case AttributeList::AT_always_inline:
HandleAlwaysInlineAttr (D, Attr, S); break;
case AttributeList::AT_analyzer_noreturn:
- HandleAnalyzerNoReturnAttr (D, Attr, S); break;
+ 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;
@@ -1746,6 +1809,7 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, const AttributeList &Att
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_malloc: HandleMallocAttr (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;
@@ -1783,10 +1847,10 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, const AttributeList &Att
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_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::IgnoredAttribute:
case AttributeList::AT_no_instrument_function: // Interacts with -pg.
// Just ignore
break;
@@ -1805,14 +1869,66 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *Attr
}
}
+/// DeclClonePragmaWeak - clone existing decl (maybe definition),
+/// #pragma weak needs a non-definition decl and source may not have one
+NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II) {
+ assert(isa<FunctionDecl>(ND) || isa<VarDecl>(ND));
+ NamedDecl *NewD = 0;
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
+ NewD = FunctionDecl::Create(FD->getASTContext(), FD->getDeclContext(),
+ FD->getLocation(), DeclarationName(II),
+ FD->getType(), FD->getDeclaratorInfo());
+ } else if (VarDecl *VD = dyn_cast<VarDecl>(ND)) {
+ NewD = VarDecl::Create(VD->getASTContext(), VD->getDeclContext(),
+ VD->getLocation(), II,
+ VD->getType(), VD->getDeclaratorInfo(),
+ VD->getStorageClass());
+ }
+ return NewD;
+}
+
+/// DeclApplyPragmaWeak - A declaration (maybe definition) needs #pragma weak
+/// applied to it, possibly with an alias.
+void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W) {
+ if (W.getUsed()) return; // only do this once
+ W.setUsed(true);
+ if (W.getAlias()) { // clone decl, impersonate __attribute(weak,alias(...))
+ IdentifierInfo *NDId = ND->getIdentifier();
+ NamedDecl *NewD = DeclClonePragmaWeak(ND, W.getAlias());
+ NewD->addAttr(::new (Context) AliasAttr(NDId->getName()));
+ NewD->addAttr(::new (Context) WeakAttr());
+ WeakTopLevelDecl.push_back(NewD);
+ // FIXME: "hideous" code from Sema::LazilyCreateBuiltin
+ // to insert Decl at TU scope, sorry.
+ DeclContext *SavedContext = CurContext;
+ CurContext = Context.getTranslationUnitDecl();
+ PushOnScopeChains(NewD, S);
+ CurContext = SavedContext;
+ } else { // just add weak to existing
+ ND->addAttr(::new (Context) WeakAttr());
+ }
+}
+
/// ProcessDeclAttributes - Given a declarator (PD) with attributes indicated in
/// it, apply them to D. This is a bit tricky because PD can have attributes
/// specified in many different places, and we need to find and apply them all.
void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) {
+ // Handle #pragma weak
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
+ if (ND->hasLinkage()) {
+ WeakInfo W = WeakUndeclaredIdentifiers.lookup(ND->getIdentifier());
+ if (W != WeakInfo()) {
+ // Identifier referenced by #pragma weak before it was declared
+ DeclApplyPragmaWeak(S, ND, W);
+ WeakUndeclaredIdentifiers[ND->getIdentifier()] = W;
+ }
+ }
+ }
+
// Apply decl attributes from the DeclSpec if present.
if (const AttributeList *Attrs = PD.getDeclSpec().getAttributes())
ProcessDeclAttributeList(S, 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;
@@ -1820,7 +1936,7 @@ void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) {
for (unsigned i = 0, e = PD.getNumTypeObjects(); i != e; ++i)
if (const AttributeList *Attrs = PD.getTypeObject(i).getAttrs())
ProcessDeclAttributeList(S, D, Attrs);
-
+
// Finally, apply any attributes on the decl itself.
if (const AttributeList *Attrs = PD.getAttributes())
ProcessDeclAttributeList(S, D, Attrs);
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 75ceb19..acb2a67 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -12,18 +12,20 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
-#include "SemaInherit.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/TypeOrdering.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/Basic/PartialDiagnostic.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>
+#include <set>
using namespace clang;
@@ -37,13 +39,13 @@ namespace {
/// 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
+ class VISIBILITY_HIDDEN CheckDefaultArgumentVisitor
: public StmtVisitor<CheckDefaultArgumentVisitor, bool> {
Expr *DefaultArg;
Sema *S;
public:
- CheckDefaultArgumentVisitor(Expr *defarg, Sema *s)
+ CheckDefaultArgumentVisitor(Expr *defarg, Sema *s)
: DefaultArg(defarg), S(s) {}
bool VisitExpr(Expr *Node);
@@ -54,7 +56,7 @@ namespace {
/// 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(),
+ for (Stmt::child_iterator I = Node->child_begin(),
E = Node->child_end(); I != E; ++I)
IsInvalid |= Visit(*I);
return IsInvalid;
@@ -74,7 +76,7 @@ namespace {
// 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(),
+ 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)) {
@@ -82,7 +84,7 @@ namespace {
// Local variables shall not be used in default argument
// expressions.
if (VDecl->isBlockVarDecl())
- return S->Diag(DRE->getSourceRange().getBegin(),
+ return S->Diag(DRE->getSourceRange().getBegin(),
diag::err_param_default_argument_references_local)
<< VDecl->getDeclName() << DefaultArg->getSourceRange();
}
@@ -101,15 +103,48 @@ namespace {
}
}
+bool
+Sema::SetParamDefaultArgument(ParmVarDecl *Param, ExprArg DefaultArg,
+ SourceLocation EqualLoc) {
+ QualType ParamType = Param->getType();
+
+ if (RequireCompleteType(Param->getLocation(), Param->getType(),
+ diag::err_typecheck_decl_incomplete_type)) {
+ Param->setInvalidDecl();
+ return true;
+ }
+
+ Expr *Arg = (Expr *)DefaultArg.get();
+
+ // 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).
+ if (CheckInitializerTypes(Arg, ParamType, EqualLoc,
+ Param->getDeclName(), /*DirectInit=*/false))
+ return true;
+
+ Arg = MaybeCreateCXXExprWithTemporaries(Arg, /*DestroyTemps=*/false);
+
+ // Okay: add the default argument to the parameter
+ Param->setDefaultArg(Arg);
+
+ DefaultArg.release();
+
+ return false;
+}
+
/// 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,
+Sema::ActOnParamDefaultArgument(DeclPtrTy param, SourceLocation EqualLoc,
ExprArg defarg) {
if (!param || !defarg.get())
return;
-
+
ParmVarDecl *Param = cast<ParmVarDecl>(param.getAs<Decl>());
UnparsedDefaultArgLocs.erase(Param);
@@ -124,25 +159,6 @@ Sema::ActOnParamDefaultArgument(DeclPtrTy param, SourceLocation EqualLoc,
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())) {
@@ -150,27 +166,23 @@ Sema::ActOnParamDefaultArgument(DeclPtrTy param, SourceLocation EqualLoc,
return;
}
- DefaultArgPtr = MaybeCreateCXXExprWithTemporaries(DefaultArg.take(),
- /*DestroyTemps=*/false);
-
- // Okay: add the default argument to the parameter
- Param->setDefaultArg(DefaultArgPtr);
+ SetParamDefaultArgument(Param, move(DefaultArg), EqualLoc);
}
/// 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,
+void Sema::ActOnParamUnparsedDefaultArgument(DeclPtrTy param,
SourceLocation EqualLoc,
SourceLocation ArgLoc) {
if (!param)
return;
-
+
ParmVarDecl *Param = cast<ParmVarDecl>(param.getAs<Decl>());
if (Param)
Param->setUnparsedDefaultArg();
-
+
UnparsedDefaultArgLocs[Param] = ArgLoc;
}
@@ -179,11 +191,11 @@ void Sema::ActOnParamUnparsedDefaultArgument(DeclPtrTy param,
void Sema::ActOnParamDefaultArgumentError(DeclPtrTy param) {
if (!param)
return;
-
+
ParmVarDecl *Param = cast<ParmVarDecl>(param.getAs<Decl>());
-
+
Param->setInvalidDecl();
-
+
UnparsedDefaultArgLocs.erase(Param);
}
@@ -230,7 +242,6 @@ 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
@@ -242,25 +253,97 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) {
// arguments supplied in this or previous declarations. A
// default argument shall not be redefined by a later
// declaration (not even to the same value).
+ //
+ // C++ [dcl.fct.default]p6:
+ // Except for member functions of class templates, the default arguments
+ // in a member function definition that appears outside of the class
+ // definition are added to the set of default arguments provided by the
+ // member function declaration in the class definition.
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(),
+ if (OldParam->hasDefaultArg() && NewParam->hasDefaultArg()) {
+ Diag(NewParam->getLocation(),
diag::err_param_default_argument_redefinition)
- << NewParam->getDefaultArg()->getSourceRange();
- Diag(OldParam->getLocation(), diag::note_previous_definition);
+ << NewParam->getDefaultArgRange();
+
+ // Look for the function declaration where the default argument was
+ // actually written, which may be a declaration prior to Old.
+ for (FunctionDecl *Older = Old->getPreviousDeclaration();
+ Older; Older = Older->getPreviousDeclaration()) {
+ if (!Older->getParamDecl(p)->hasDefaultArg())
+ break;
+
+ OldParam = Older->getParamDecl(p);
+ }
+
+ Diag(OldParam->getLocation(), diag::note_previous_definition)
+ << OldParam->getDefaultArgRange();
Invalid = true;
- } else if (OldParam->getDefaultArg()) {
+ } else if (OldParam->hasDefaultArg()) {
// Merge the old default argument into the new parameter
- NewParam->setDefaultArg(OldParam->getDefaultArg());
+ if (OldParam->hasUninstantiatedDefaultArg())
+ NewParam->setUninstantiatedDefaultArg(
+ OldParam->getUninstantiatedDefaultArg());
+ else
+ NewParam->setDefaultArg(OldParam->getDefaultArg());
+ } else if (NewParam->hasDefaultArg()) {
+ if (New->getDescribedFunctionTemplate()) {
+ // Paragraph 4, quoted above, only applies to non-template functions.
+ Diag(NewParam->getLocation(),
+ diag::err_param_default_argument_template_redecl)
+ << NewParam->getDefaultArgRange();
+ Diag(Old->getLocation(), diag::note_template_prev_declaration)
+ << false;
+ } else if (New->getTemplateSpecializationKind()
+ != TSK_ImplicitInstantiation &&
+ New->getTemplateSpecializationKind() != TSK_Undeclared) {
+ // C++ [temp.expr.spec]p21:
+ // Default function arguments shall not be specified in a declaration
+ // or a definition for one of the following explicit specializations:
+ // - the explicit specialization of a function template;
+ // - the explicit specialization of a member function template;
+ // - the explicit specialization of a member function of a class
+ // template where the class template specialization to which the
+ // member function specialization belongs is implicitly
+ // instantiated.
+ Diag(NewParam->getLocation(), diag::err_template_spec_default_arg)
+ << (New->getTemplateSpecializationKind() ==TSK_ExplicitSpecialization)
+ << New->getDeclName()
+ << NewParam->getDefaultArgRange();
+ } else if (New->getDeclContext()->isDependentContext()) {
+ // C++ [dcl.fct.default]p6 (DR217):
+ // Default arguments for a member function of a class template shall
+ // be specified on the initial declaration of the member function
+ // within the class template.
+ //
+ // Reading the tea leaves a bit in DR217 and its reference to DR205
+ // leads me to the conclusion that one cannot add default function
+ // arguments for an out-of-line definition of a member function of a
+ // dependent type.
+ int WhichKind = 2;
+ if (CXXRecordDecl *Record
+ = dyn_cast<CXXRecordDecl>(New->getDeclContext())) {
+ if (Record->getDescribedClassTemplate())
+ WhichKind = 0;
+ else if (isa<ClassTemplatePartialSpecializationDecl>(Record))
+ WhichKind = 1;
+ else
+ WhichKind = 2;
+ }
+
+ Diag(NewParam->getLocation(),
+ diag::err_param_default_argument_member_template_redecl)
+ << WhichKind
+ << NewParam->getDefaultArgRange();
+ }
}
}
if (CheckEquivalentExceptionSpec(
- Old->getType()->getAsFunctionProtoType(), Old->getLocation(),
- New->getType()->getAsFunctionProtoType(), New->getLocation())) {
+ Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(),
+ New->getType()->getAs<FunctionProtoType>(), New->getLocation())) {
Invalid = true;
}
@@ -277,7 +360,7 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) {
// Find first parameter with a default argument
for (p = 0; p < NumParams; ++p) {
ParmVarDecl *Param = FD->getParamDecl(p);
- if (Param->getDefaultArg())
+ if (Param->hasDefaultArg())
break;
}
@@ -288,19 +371,19 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) {
// 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) {
+ for (; p < NumParams; ++p) {
ParmVarDecl *Param = FD->getParamDecl(p);
- if (!Param->getDefaultArg()) {
+ if (!Param->hasDefaultArg()) {
if (Param->isInvalidDecl())
/* We already complained about this parameter. */;
else if (Param->getIdentifier())
- Diag(Param->getLocation(),
+ Diag(Param->getLocation(),
diag::err_param_default_argument_missing_name)
<< Param->getIdentifier();
else
- Diag(Param->getLocation(),
+ Diag(Param->getLocation(),
diag::err_param_default_argument_missing);
-
+
LastMissingDefaultArg = p;
}
}
@@ -329,7 +412,7 @@ bool Sema::isCurrentClassName(const IdentifierInfo &II, Scope *,
const CXXScopeSpec *SS) {
CXXRecordDecl *CurDecl;
if (SS && SS->isSet() && !SS->isInvalid()) {
- DeclContext *DC = computeDeclContext(*SS);
+ DeclContext *DC = computeDeclContext(*SS, true);
CurDecl = dyn_cast_or_null<CXXRecordDecl>(DC);
} else
CurDecl = dyn_cast_or_null<CXXRecordDecl>(CurContext);
@@ -340,7 +423,7 @@ bool Sema::isCurrentClassName(const IdentifierInfo &II, Scope *,
return false;
}
-/// \brief Check the validity of a C++ base class specifier.
+/// \brief Check the validity of a C++ base class specifier.
///
/// \returns a new CXXBaseSpecifier if well-formed, emits diagnostics
/// and returns NULL otherwise.
@@ -348,7 +431,7 @@ CXXBaseSpecifier *
Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
SourceRange SpecifierRange,
bool Virtual, AccessSpecifier Access,
- QualType BaseType,
+ QualType BaseType,
SourceLocation BaseLoc) {
// C++ [class.union]p1:
// A union shall not have base classes.
@@ -359,7 +442,7 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
}
if (BaseType->isDependentType())
- return new CXXBaseSpecifier(SpecifierRange, Virtual,
+ return new (Context) CXXBaseSpecifier(SpecifierRange, Virtual,
Class->getTagKind() == RecordDecl::TK_class,
Access, BaseType);
@@ -379,16 +462,21 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
// 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))
+ if (RequireCompleteType(BaseLoc, BaseType,
+ PDiag(diag::err_incomplete_base_class)
+ << SpecifierRange))
return 0;
- // If the base class is polymorphic, the new one is, too.
- RecordDecl *BaseDecl = BaseType->getAsRecordType()->getDecl();
+ // If the base class is polymorphic or isn't empty, the new one is/isn't, too.
+ RecordDecl *BaseDecl = BaseType->getAs<RecordType>()->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())
+ CXXRecordDecl * CXXBaseDecl = cast<CXXRecordDecl>(BaseDecl);
+ assert(CXXBaseDecl && "Base type is not a C++ type");
+ if (!CXXBaseDecl->isEmpty())
+ Class->setEmpty(false);
+ if (CXXBaseDecl->isPolymorphic())
Class->setPolymorphic(true);
// C++ [dcl.init.aggr]p1:
@@ -400,33 +488,59 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
// C++ [class.ctor]p5:
// A constructor is trivial if its class has no virtual base classes.
Class->setHasTrivialConstructor(false);
+
+ // C++ [class.copy]p6:
+ // A copy constructor is trivial if its class has no virtual base classes.
+ Class->setHasTrivialCopyConstructor(false);
+
+ // C++ [class.copy]p11:
+ // A copy assignment operator is trivial if its class has no virtual
+ // base classes.
+ Class->setHasTrivialCopyAssignment(false);
+
+ // C++0x [meta.unary.prop] is_empty:
+ // T is a class type, but not a union type, with ... no virtual base
+ // classes
+ Class->setEmpty(false);
} else {
// C++ [class.ctor]p5:
- // A constructor is trivial if all the direct base classes of its
+ // A constructor is trivial if all the direct base classes of its
// class have trivial constructors.
- Class->setHasTrivialConstructor(cast<CXXRecordDecl>(BaseDecl)->
- hasTrivialConstructor());
+ if (!cast<CXXRecordDecl>(BaseDecl)->hasTrivialConstructor())
+ Class->setHasTrivialConstructor(false);
+
+ // C++ [class.copy]p6:
+ // A copy constructor is trivial if all the direct base classes of its
+ // class have trivial copy constructors.
+ if (!cast<CXXRecordDecl>(BaseDecl)->hasTrivialCopyConstructor())
+ Class->setHasTrivialCopyConstructor(false);
+
+ // C++ [class.copy]p11:
+ // A copy assignment operator is trivial if all the direct base classes
+ // of its class have trivial copy assignment operators.
+ if (!cast<CXXRecordDecl>(BaseDecl)->hasTrivialCopyAssignment())
+ Class->setHasTrivialCopyAssignment(false);
}
// 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());
-
+ if (!cast<CXXRecordDecl>(BaseDecl)->hasTrivialDestructor())
+ Class->setHasTrivialDestructor(false);
+
// Create the base specifier.
// FIXME: Allocate via ASTContext?
- return new CXXBaseSpecifier(SpecifierRange, Virtual,
- Class->getTagKind() == RecordDecl::TK_class,
+ return new (Context) 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 {
+/// example:
+/// class foo : public bar, virtual private baz {
/// 'public bar' and 'virtual private baz' are each base-specifiers.
-Sema::BaseResult
+Sema::BaseResult
Sema::ActOnBaseSpecifier(DeclPtrTy classdecl, SourceRange SpecifierRange,
bool Virtual, AccessSpecifier Access,
TypeTy *basetype, SourceLocation BaseLoc) {
@@ -435,12 +549,12 @@ Sema::ActOnBaseSpecifier(DeclPtrTy classdecl, SourceRange SpecifierRange,
AdjustDeclIfTemplate(classdecl);
CXXRecordDecl *Class = cast<CXXRecordDecl>(classdecl.getAs<Decl>());
- QualType BaseType = QualType::getFromOpaquePtr(basetype);
+ QualType BaseType = GetTypeFromParser(basetype);
if (CXXBaseSpecifier *BaseSpec = CheckBaseSpecifier(Class, SpecifierRange,
Virtual, Access,
BaseType, BaseLoc))
return BaseSpec;
-
+
return true;
}
@@ -461,7 +575,7 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases,
unsigned NumGoodBases = 0;
bool Invalid = false;
for (unsigned idx = 0; idx < NumBases; ++idx) {
- QualType NewBaseType
+ QualType NewBaseType
= Context.getCanonicalType(Bases[idx]->getType());
NewBaseType = NewBaseType.getUnqualifiedType();
@@ -476,7 +590,7 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases,
// Delete the duplicate base class specifier; we're going to
// overwrite its pointer later.
- delete Bases[idx];
+ Context.Deallocate(Bases[idx]);
Invalid = true;
} else {
@@ -492,7 +606,7 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases,
// 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];
+ Context.Deallocate(Bases[idx]);
return Invalid;
}
@@ -500,7 +614,7 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases,
/// ActOnBaseSpecifiers - Attach the given base specifiers to the
/// class, after checking whether there are any duplicate base
/// classes.
-void Sema::ActOnBaseSpecifiers(DeclPtrTy ClassDecl, BaseTy **Bases,
+void Sema::ActOnBaseSpecifiers(DeclPtrTy ClassDecl, BaseTy **Bases,
unsigned NumBases) {
if (!ClassDecl || !Bases || !NumBases)
return;
@@ -510,6 +624,139 @@ void Sema::ActOnBaseSpecifiers(DeclPtrTy ClassDecl, BaseTy **Bases,
(CXXBaseSpecifier**)(Bases), NumBases);
}
+/// \brief Determine whether the type \p Derived is a C++ class that is
+/// derived from the type \p Base.
+bool Sema::IsDerivedFrom(QualType Derived, QualType Base) {
+ if (!getLangOptions().CPlusPlus)
+ return false;
+
+ const RecordType *DerivedRT = Derived->getAs<RecordType>();
+ if (!DerivedRT)
+ return false;
+
+ const RecordType *BaseRT = Base->getAs<RecordType>();
+ if (!BaseRT)
+ return false;
+
+ CXXRecordDecl *DerivedRD = cast<CXXRecordDecl>(DerivedRT->getDecl());
+ CXXRecordDecl *BaseRD = cast<CXXRecordDecl>(BaseRT->getDecl());
+ return DerivedRD->isDerivedFrom(BaseRD);
+}
+
+/// \brief Determine whether the type \p Derived is a C++ class that is
+/// derived from the type \p Base.
+bool Sema::IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths) {
+ if (!getLangOptions().CPlusPlus)
+ return false;
+
+ const RecordType *DerivedRT = Derived->getAs<RecordType>();
+ if (!DerivedRT)
+ return false;
+
+ const RecordType *BaseRT = Base->getAs<RecordType>();
+ if (!BaseRT)
+ return false;
+
+ CXXRecordDecl *DerivedRD = cast<CXXRecordDecl>(DerivedRT->getDecl());
+ CXXRecordDecl *BaseRD = cast<CXXRecordDecl>(BaseRT->getDecl());
+ return DerivedRD->isDerivedFrom(BaseRD, Paths);
+}
+
+/// 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.
+ CXXBasePaths 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(CXXBasePaths &Paths) {
+ std::string PathDisplayStr;
+ std::set<unsigned> DisplayedPaths;
+ for (CXXBasePaths::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 += Context.getTypeDeclType(Paths.getOrigin()).getAsString();
+ for (CXXBasePath::const_iterator Element = Path->begin();
+ Element != Path->end(); ++Element)
+ PathDisplayStr += " -> " + Element->Base->getType().getAsString();
+ }
+ }
+
+ return PathDisplayStr;
+}
+
//===----------------------------------------------------------------------===//
// C++ class member Handling
//===----------------------------------------------------------------------===//
@@ -520,6 +767,7 @@ void Sema::ActOnBaseSpecifiers(DeclPtrTy ClassDecl, BaseTy **Bases,
/// any.
Sema::DeclPtrTy
Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
+ MultiTemplateParamsArg TemplateParameterLists,
ExprTy *BW, ExprTy *InitExpr, bool Deleted) {
const DeclSpec &DS = D.getDeclSpec();
DeclarationName Name = GetNameForDeclarator(D);
@@ -529,6 +777,8 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
bool isFunc = D.isFunctionDeclarator();
+ assert(!DS.isFriendSpecified());
+
// 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
@@ -546,7 +796,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
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();
@@ -585,7 +835,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
// typedef int f();
// f a;
//
- QualType TDType = QualType::getFromOpaquePtr(DS.getTypeRep());
+ QualType TDType = GetTypeFromParser(DS.getTypeRep());
isFunc = TDType->isFunctionType();
}
@@ -595,11 +845,13 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
Decl *Member;
if (isInstField) {
+ // FIXME: Check for template parameters!
Member = HandleField(S, cast<CXXRecordDecl>(CurContext), Loc, D, BitWidth,
AS);
assert(Member && "HandleField never returns null");
} else {
- Member = ActOnDeclarator(S, D).getAs<Decl>();
+ Member = HandleDeclarator(S, D, move(TemplateParameterLists), false)
+ .getAs<Decl>();
if (!Member) {
if (BitWidth) DeleteExpr(BitWidth);
return DeclPtrTy();
@@ -622,16 +874,21 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
// 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()
+ << Name << cast<ValueDecl>(Member)->getType()
<< BitWidth->getSourceRange();
}
-
+
DeleteExpr(BitWidth);
BitWidth = 0;
Member->setInvalidDecl();
}
Member->setAccess(AS);
+
+ // If we have declared a member function template, set the access of the
+ // templated declaration as well.
+ if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(Member))
+ FunTmpl->getTemplatedDecl()->setAccess(AS);
}
assert((Name || isInstField) && "No identifier for non-field ?");
@@ -649,7 +906,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
}
/// ActOnMemInitializer - Handle a C++ member initializer.
-Sema::MemInitResult
+Sema::MemInitResult
Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
Scope *S,
const CXXScopeSpec &SS,
@@ -662,8 +919,10 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
SourceLocation RParenLoc) {
if (!ConstructorD)
return true;
-
- CXXConstructorDecl *Constructor
+
+ AdjustDeclIfTemplate(ConstructorD);
+
+ CXXConstructorDecl *Constructor
= dyn_cast<CXXConstructorDecl>(ConstructorD.getAs<Decl>());
if (!Constructor) {
// The user wrote a constructor initializer on a function that is
@@ -688,141 +947,657 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
if (!SS.getScopeRep() && !TemplateTypeTy) {
// Look for a member, first.
FieldDecl *Member = 0;
- DeclContext::lookup_result Result
+ DeclContext::lookup_result Result
= ClassDecl->lookup(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,
- IdLoc);
- }
+ if (Member)
+ return BuildMemberInitializer(Member, (Expr**)Args, NumArgs, IdLoc,
+ RParenLoc);
}
// It didn't name a member, so see if it names a class.
- TypeTy *BaseTy = TemplateTypeTy ? TemplateTypeTy
+ TypeTy *BaseTy = TemplateTypeTy ? TemplateTypeTy
: getTypeName(*MemberOrBase, IdLoc, S, &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() && !BaseType->isDependentType())
- 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;
+ QualType BaseType = GetTypeFromParser(BaseTy);
+
+ return BuildBaseInitializer(BaseType, (Expr **)Args, NumArgs, IdLoc,
+ RParenLoc, ClassDecl);
+}
+
+Sema::MemInitResult
+Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args,
+ unsigned NumArgs, SourceLocation IdLoc,
+ SourceLocation RParenLoc) {
+ bool HasDependentArg = false;
+ for (unsigned i = 0; i < NumArgs; i++)
+ HasDependentArg |= Args[i]->isTypeDependent();
+
+ CXXConstructorDecl *C = 0;
+ QualType FieldType = Member->getType();
+ if (const ArrayType *Array = Context.getAsArrayType(FieldType))
+ FieldType = Array->getElementType();
+ if (FieldType->isDependentType()) {
+ // Can't check init for dependent type.
+ } else if (FieldType->getAs<RecordType>()) {
+ if (!HasDependentArg) {
+ ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
+
+ C = PerformInitializationByConstructor(FieldType,
+ MultiExprArg(*this,
+ (void**)Args,
+ NumArgs),
+ IdLoc,
+ SourceRange(IdLoc, RParenLoc),
+ Member->getDeclName(), IK_Direct,
+ ConstructorArgs);
+
+ if (C) {
+ // Take over the constructor arguments as our own.
+ NumArgs = ConstructorArgs.size();
+ Args = (Expr **)ConstructorArgs.take();
+ }
}
+ } else if (NumArgs != 1 && NumArgs != 0) {
+ return Diag(IdLoc, diag::err_mem_initializer_mismatch)
+ << Member->getDeclName() << SourceRange(IdLoc, RParenLoc);
+ } else if (!HasDependentArg) {
+ Expr *NewExp;
+ if (NumArgs == 0) {
+ if (FieldType->isReferenceType()) {
+ Diag(IdLoc, diag::err_null_intialized_reference_member)
+ << Member->getDeclName();
+ return Diag(Member->getLocation(), diag::note_declared_at);
+ }
+ NewExp = new (Context) CXXZeroInitValueExpr(FieldType, IdLoc, RParenLoc);
+ NumArgs = 1;
+ }
+ else
+ NewExp = (Expr*)Args[0];
+ if (PerformCopyInitialization(NewExp, FieldType, "passing"))
+ return true;
+ Args[0] = NewExp;
}
-
- // 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;
+ // FIXME: Perform direct initialization of the member.
+ return new (Context) CXXBaseOrMemberInitializer(Member, (Expr **)Args,
+ NumArgs, C, IdLoc, RParenLoc);
+}
+
+Sema::MemInitResult
+Sema::BuildBaseInitializer(QualType BaseType, Expr **Args,
+ unsigned NumArgs, SourceLocation IdLoc,
+ SourceLocation RParenLoc, CXXRecordDecl *ClassDecl) {
+ bool HasDependentArg = false;
+ for (unsigned i = 0; i < NumArgs; i++)
+ HasDependentArg |= Args[i]->isTypeDependent();
+
+ if (!BaseType->isDependentType()) {
+ 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.
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
+ /*DetectVirtual=*/false);
+ if (IsDerivedFrom(Context.getTypeDeclType(ClassDecl), BaseType, Paths)) {
+ for (CXXBasePaths::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)
+ << BaseType << SourceRange(IdLoc, RParenLoc);
+ // C++ [base.class.init]p2:
+ // Unless the mem-initializer-id names a nonstatic data membeer of the
+ // constructor's class ot a direst or virtual base of that class, the
+ // mem-initializer is ill-formed.
+ if (!DirectBaseSpec && !VirtualBaseSpec)
+ return Diag(IdLoc, diag::err_not_direct_base_or_virtual)
+ << BaseType << ClassDecl->getNameAsCString()
+ << SourceRange(IdLoc, RParenLoc);
}
- // 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);
- // C++ [base.class.init]p2:
- // Unless the mem-initializer-id names a nonstatic data membeer of the
- // constructor's class ot a direst or virtual base of that class, the
- // mem-initializer is ill-formed.
- if (!DirectBaseSpec && !VirtualBaseSpec)
- return Diag(IdLoc, diag::err_not_direct_base_or_virtual)
- << BaseType << ClassDecl->getNameAsCString()
- << SourceRange(IdLoc, RParenLoc);
-
+ CXXConstructorDecl *C = 0;
+ if (!BaseType->isDependentType() && !HasDependentArg) {
+ DeclarationName Name = Context.DeclarationNames.getCXXConstructorName(
+ Context.getCanonicalType(BaseType));
+ ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
+
+ C = PerformInitializationByConstructor(BaseType,
+ MultiExprArg(*this,
+ (void**)Args, NumArgs),
+ IdLoc, SourceRange(IdLoc, RParenLoc),
+ Name, IK_Direct,
+ ConstructorArgs);
+ if (C) {
+ // Take over the constructor arguments as our own.
+ NumArgs = ConstructorArgs.size();
+ Args = (Expr **)ConstructorArgs.take();
+ }
+ }
+
+ return new (Context) CXXBaseOrMemberInitializer(BaseType, (Expr **)Args,
+ NumArgs, C, IdLoc, RParenLoc);
+}
+
+void
+Sema::setBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
+ CXXBaseOrMemberInitializer **Initializers,
+ unsigned NumInitializers,
+ llvm::SmallVectorImpl<CXXBaseSpecifier *>& Bases,
+ llvm::SmallVectorImpl<FieldDecl *>&Fields) {
+ // We need to build the initializer AST according to order of construction
+ // and not what user specified in the Initializers list.
+ CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Constructor->getDeclContext());
+ llvm::SmallVector<CXXBaseOrMemberInitializer*, 32> AllToInit;
+ llvm::DenseMap<const void *, CXXBaseOrMemberInitializer*> AllBaseFields;
+ bool HasDependentBaseInit = false;
+
+ for (unsigned i = 0; i < NumInitializers; i++) {
+ CXXBaseOrMemberInitializer *Member = Initializers[i];
+ if (Member->isBaseInitializer()) {
+ if (Member->getBaseClass()->isDependentType())
+ HasDependentBaseInit = true;
+ AllBaseFields[Member->getBaseClass()->getAs<RecordType>()] = Member;
+ } else {
+ AllBaseFields[Member->getMember()] = Member;
+ }
+ }
+
+ if (HasDependentBaseInit) {
+ // FIXME. This does not preserve the ordering of the initializers.
+ // Try (with -Wreorder)
+ // template<class X> struct A {};
+ // template<class X> struct B : A<X> {
+ // B() : x1(10), A<X>() {}
+ // int x1;
+ // };
+ // B<int> x;
+ // On seeing one dependent type, we should essentially exit this routine
+ // while preserving user-declared initializer list. When this routine is
+ // called during instantiatiation process, this routine will rebuild the
+ // oderdered initializer list correctly.
+
+ // If we have a dependent base initialization, we can't determine the
+ // association between initializers and bases; just dump the known
+ // initializers into the list, and don't try to deal with other bases.
+ for (unsigned i = 0; i < NumInitializers; i++) {
+ CXXBaseOrMemberInitializer *Member = Initializers[i];
+ if (Member->isBaseInitializer())
+ AllToInit.push_back(Member);
+ }
+ } else {
+ // Push virtual bases before others.
+ for (CXXRecordDecl::base_class_iterator VBase =
+ ClassDecl->vbases_begin(),
+ E = ClassDecl->vbases_end(); VBase != E; ++VBase) {
+ if (VBase->getType()->isDependentType())
+ continue;
+ if (CXXBaseOrMemberInitializer *Value =
+ AllBaseFields.lookup(VBase->getType()->getAs<RecordType>())) {
+ CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl());
+ assert(BaseDecl && "setBaseOrMemberInitializers - BaseDecl null");
+ if (CXXConstructorDecl *Ctor = BaseDecl->getDefaultConstructor(Context))
+ MarkDeclarationReferenced(Value->getSourceLocation(), Ctor);
+ AllToInit.push_back(Value);
+ }
+ else {
+ CXXRecordDecl *VBaseDecl =
+ cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl());
+ assert(VBaseDecl && "setBaseOrMemberInitializers - VBaseDecl null");
+ CXXConstructorDecl *Ctor = VBaseDecl->getDefaultConstructor(Context);
+ if (!Ctor)
+ Bases.push_back(VBase);
+ else
+ MarkDeclarationReferenced(Constructor->getLocation(), Ctor);
+
+ CXXBaseOrMemberInitializer *Member =
+ new (Context) CXXBaseOrMemberInitializer(VBase->getType(), 0, 0,
+ Ctor,
+ SourceLocation(),
+ SourceLocation());
+ AllToInit.push_back(Member);
+ }
+ }
+
+ for (CXXRecordDecl::base_class_iterator Base =
+ ClassDecl->bases_begin(),
+ E = ClassDecl->bases_end(); Base != E; ++Base) {
+ // Virtuals are in the virtual base list and already constructed.
+ if (Base->isVirtual())
+ continue;
+ // Skip dependent types.
+ if (Base->getType()->isDependentType())
+ continue;
+ if (CXXBaseOrMemberInitializer *Value =
+ AllBaseFields.lookup(Base->getType()->getAs<RecordType>())) {
+ CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ assert(BaseDecl && "setBaseOrMemberInitializers - BaseDecl null");
+ if (CXXConstructorDecl *Ctor = BaseDecl->getDefaultConstructor(Context))
+ MarkDeclarationReferenced(Value->getSourceLocation(), Ctor);
+ AllToInit.push_back(Value);
+ }
+ else {
+ CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ assert(BaseDecl && "setBaseOrMemberInitializers - BaseDecl null");
+ CXXConstructorDecl *Ctor = BaseDecl->getDefaultConstructor(Context);
+ if (!Ctor)
+ Bases.push_back(Base);
+ else
+ MarkDeclarationReferenced(Constructor->getLocation(), Ctor);
+
+ CXXBaseOrMemberInitializer *Member =
+ new (Context) CXXBaseOrMemberInitializer(Base->getType(), 0, 0,
+ BaseDecl->getDefaultConstructor(Context),
+ SourceLocation(),
+ SourceLocation());
+ AllToInit.push_back(Member);
+ }
+ }
+ }
+
+ // non-static data members.
+ for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
+ E = ClassDecl->field_end(); Field != E; ++Field) {
+ if ((*Field)->isAnonymousStructOrUnion()) {
+ if (const RecordType *FieldClassType =
+ Field->getType()->getAs<RecordType>()) {
+ CXXRecordDecl *FieldClassDecl
+ = cast<CXXRecordDecl>(FieldClassType->getDecl());
+ for (RecordDecl::field_iterator FA = FieldClassDecl->field_begin(),
+ EA = FieldClassDecl->field_end(); FA != EA; FA++) {
+ if (CXXBaseOrMemberInitializer *Value = AllBaseFields.lookup(*FA)) {
+ // 'Member' is the anonymous union field and 'AnonUnionMember' is
+ // set to the anonymous union data member used in the initializer
+ // list.
+ Value->setMember(*Field);
+ Value->setAnonUnionMember(*FA);
+ AllToInit.push_back(Value);
+ break;
+ }
+ }
+ }
+ continue;
+ }
+ if (CXXBaseOrMemberInitializer *Value = AllBaseFields.lookup(*Field)) {
+ QualType FT = (*Field)->getType();
+ if (const RecordType* RT = FT->getAs<RecordType>()) {
+ CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RT->getDecl());
+ assert(FieldRecDecl && "setBaseOrMemberInitializers - BaseDecl null");
+ if (CXXConstructorDecl *Ctor =
+ FieldRecDecl->getDefaultConstructor(Context))
+ MarkDeclarationReferenced(Value->getSourceLocation(), Ctor);
+ }
+ AllToInit.push_back(Value);
+ continue;
+ }
+
+ QualType FT = Context.getBaseElementType((*Field)->getType());
+ if (const RecordType* RT = FT->getAs<RecordType>()) {
+ CXXConstructorDecl *Ctor =
+ cast<CXXRecordDecl>(RT->getDecl())->getDefaultConstructor(Context);
+ if (!Ctor && !FT->isDependentType())
+ Fields.push_back(*Field);
+ CXXBaseOrMemberInitializer *Member =
+ new (Context) CXXBaseOrMemberInitializer((*Field), 0, 0,
+ Ctor,
+ SourceLocation(),
+ SourceLocation());
+ AllToInit.push_back(Member);
+ if (Ctor)
+ MarkDeclarationReferenced(Constructor->getLocation(), Ctor);
+ if (FT.isConstQualified() && (!Ctor || Ctor->isTrivial())) {
+ Diag(Constructor->getLocation(), diag::err_unintialized_member_in_ctor)
+ << Context.getTagDeclType(ClassDecl) << 1 << (*Field)->getDeclName();
+ Diag((*Field)->getLocation(), diag::note_declared_at);
+ }
+ }
+ else if (FT->isReferenceType()) {
+ Diag(Constructor->getLocation(), diag::err_unintialized_member_in_ctor)
+ << Context.getTagDeclType(ClassDecl) << 0 << (*Field)->getDeclName();
+ Diag((*Field)->getLocation(), diag::note_declared_at);
+ }
+ else if (FT.isConstQualified()) {
+ Diag(Constructor->getLocation(), diag::err_unintialized_member_in_ctor)
+ << Context.getTagDeclType(ClassDecl) << 1 << (*Field)->getDeclName();
+ Diag((*Field)->getLocation(), diag::note_declared_at);
+ }
+ }
+
+ NumInitializers = AllToInit.size();
+ if (NumInitializers > 0) {
+ Constructor->setNumBaseOrMemberInitializers(NumInitializers);
+ CXXBaseOrMemberInitializer **baseOrMemberInitializers =
+ new (Context) CXXBaseOrMemberInitializer*[NumInitializers];
+
+ Constructor->setBaseOrMemberInitializers(baseOrMemberInitializers);
+ for (unsigned Idx = 0; Idx < NumInitializers; ++Idx)
+ baseOrMemberInitializers[Idx] = AllToInit[Idx];
+ }
+}
+
+void
+Sema::BuildBaseOrMemberInitializers(ASTContext &C,
+ CXXConstructorDecl *Constructor,
+ CXXBaseOrMemberInitializer **Initializers,
+ unsigned NumInitializers
+ ) {
+ llvm::SmallVector<CXXBaseSpecifier *, 4>Bases;
+ llvm::SmallVector<FieldDecl *, 4>Members;
+
+ setBaseOrMemberInitializers(Constructor,
+ Initializers, NumInitializers, Bases, Members);
+ for (unsigned int i = 0; i < Bases.size(); i++)
+ Diag(Bases[i]->getSourceRange().getBegin(),
+ diag::err_missing_default_constructor) << 0 << Bases[i]->getType();
+ for (unsigned int i = 0; i < Members.size(); i++)
+ Diag(Members[i]->getLocation(), diag::err_missing_default_constructor)
+ << 1 << Members[i]->getType();
+}
+
+static void *GetKeyForTopLevelField(FieldDecl *Field) {
+ // For anonymous unions, use the class declaration as the key.
+ if (const RecordType *RT = Field->getType()->getAs<RecordType>()) {
+ if (RT->getDecl()->isAnonymousStructOrUnion())
+ return static_cast<void *>(RT->getDecl());
+ }
+ return static_cast<void *>(Field);
+}
+
+static void *GetKeyForBase(QualType BaseType) {
+ if (const RecordType *RT = BaseType->getAs<RecordType>())
+ return (void *)RT;
+
+ assert(0 && "Unexpected base type!");
+ return 0;
+}
- return new CXXBaseOrMemberInitializer(BaseType, (Expr **)Args, NumArgs,
- IdLoc);
+static void *GetKeyForMember(CXXBaseOrMemberInitializer *Member,
+ bool MemberMaybeAnon = false) {
+ // For fields injected into the class via declaration of an anonymous union,
+ // use its anonymous union class declaration as the unique key.
+ if (Member->isMemberInitializer()) {
+ FieldDecl *Field = Member->getMember();
+
+ // After BuildBaseOrMemberInitializers call, Field is the anonymous union
+ // data member of the class. Data member used in the initializer list is
+ // in AnonUnionMember field.
+ if (MemberMaybeAnon && Field->isAnonymousStructOrUnion())
+ Field = Member->getAnonUnionMember();
+ if (Field->getDeclContext()->isRecord()) {
+ RecordDecl *RD = cast<RecordDecl>(Field->getDeclContext());
+ if (RD->isAnonymousStructOrUnion())
+ return static_cast<void *>(RD);
+ }
+ return static_cast<void *>(Field);
+ }
+
+ return GetKeyForBase(QualType(Member->getBaseClass(), 0));
}
-void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
+void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
SourceLocation ColonLoc,
MemInitTy **MemInits, unsigned NumMemInits) {
if (!ConstructorDecl)
return;
-
- CXXConstructorDecl *Constructor
+
+ AdjustDeclIfTemplate(ConstructorDecl);
+
+ CXXConstructorDecl *Constructor
= dyn_cast<CXXConstructorDecl>(ConstructorDecl.getAs<Decl>());
-
+
if (!Constructor) {
Diag(ColonLoc, diag::err_only_constructors_take_base_inits);
return;
}
- llvm::DenseMap<void*, CXXBaseOrMemberInitializer *>Members;
- bool err = false;
+
+ if (!Constructor->isDependentContext()) {
+ llvm::DenseMap<void*, CXXBaseOrMemberInitializer *>Members;
+ bool err = false;
+ for (unsigned i = 0; i < NumMemInits; i++) {
+ CXXBaseOrMemberInitializer *Member =
+ static_cast<CXXBaseOrMemberInitializer*>(MemInits[i]);
+ void *KeyToMember = GetKeyForMember(Member);
+ CXXBaseOrMemberInitializer *&PrevMember = Members[KeyToMember];
+ if (!PrevMember) {
+ PrevMember = Member;
+ continue;
+ }
+ if (FieldDecl *Field = Member->getMember())
+ Diag(Member->getSourceLocation(),
+ diag::error_multiple_mem_initialization)
+ << Field->getNameAsString();
+ else {
+ Type *BaseClass = Member->getBaseClass();
+ assert(BaseClass && "ActOnMemInitializers - neither field or base");
+ Diag(Member->getSourceLocation(),
+ diag::error_multiple_base_initialization)
+ << QualType(BaseClass, 0);
+ }
+ Diag(PrevMember->getSourceLocation(), diag::note_previous_initializer)
+ << 0;
+ err = true;
+ }
+
+ if (err)
+ return;
+ }
+
+ BuildBaseOrMemberInitializers(Context, Constructor,
+ reinterpret_cast<CXXBaseOrMemberInitializer **>(MemInits),
+ NumMemInits);
+
+ if (Constructor->isDependentContext())
+ return;
+
+ if (Diags.getDiagnosticLevel(diag::warn_base_initialized) ==
+ Diagnostic::Ignored &&
+ Diags.getDiagnosticLevel(diag::warn_field_initialized) ==
+ Diagnostic::Ignored)
+ return;
+
+ // Also issue warning if order of ctor-initializer list does not match order
+ // of 1) base class declarations and 2) order of non-static data members.
+ llvm::SmallVector<const void*, 32> AllBaseOrMembers;
+
+ CXXRecordDecl *ClassDecl
+ = cast<CXXRecordDecl>(Constructor->getDeclContext());
+ // Push virtual bases before others.
+ for (CXXRecordDecl::base_class_iterator VBase =
+ ClassDecl->vbases_begin(),
+ E = ClassDecl->vbases_end(); VBase != E; ++VBase)
+ AllBaseOrMembers.push_back(GetKeyForBase(VBase->getType()));
+
+ for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
+ E = ClassDecl->bases_end(); Base != E; ++Base) {
+ // Virtuals are alread in the virtual base list and are constructed
+ // first.
+ if (Base->isVirtual())
+ continue;
+ AllBaseOrMembers.push_back(GetKeyForBase(Base->getType()));
+ }
+
+ for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
+ E = ClassDecl->field_end(); Field != E; ++Field)
+ AllBaseOrMembers.push_back(GetKeyForTopLevelField(*Field));
+
+ int Last = AllBaseOrMembers.size();
+ int curIndex = 0;
+ CXXBaseOrMemberInitializer *PrevMember = 0;
for (unsigned i = 0; i < NumMemInits; i++) {
- CXXBaseOrMemberInitializer *Member =
+ CXXBaseOrMemberInitializer *Member =
static_cast<CXXBaseOrMemberInitializer*>(MemInits[i]);
- void *KeyToMember = Member->getBaseOrMember();
- // For fields injected into the class via declaration of an anonymous union,
- // use its anonymous union class declaration as the unique key.
- if (FieldDecl *Field = Member->getMember())
- if (Field->getDeclContext()->isRecord() &&
- cast<RecordDecl>(Field->getDeclContext())->isAnonymousStructOrUnion())
- KeyToMember = static_cast<void *>(Field->getDeclContext());
- CXXBaseOrMemberInitializer *&PrevMember = Members[KeyToMember];
- if (!PrevMember) {
- PrevMember = Member;
- continue;
+ void *MemberInCtorList = GetKeyForMember(Member, true);
+
+ for (; curIndex < Last; curIndex++)
+ if (MemberInCtorList == AllBaseOrMembers[curIndex])
+ break;
+ if (curIndex == Last) {
+ assert(PrevMember && "Member not in member list?!");
+ // Initializer as specified in ctor-initializer list is out of order.
+ // Issue a warning diagnostic.
+ if (PrevMember->isBaseInitializer()) {
+ // Diagnostics is for an initialized base class.
+ Type *BaseClass = PrevMember->getBaseClass();
+ Diag(PrevMember->getSourceLocation(),
+ diag::warn_base_initialized)
+ << QualType(BaseClass, 0);
+ } else {
+ FieldDecl *Field = PrevMember->getMember();
+ Diag(PrevMember->getSourceLocation(),
+ diag::warn_field_initialized)
+ << Field->getNameAsString();
+ }
+ // Also the note!
+ if (FieldDecl *Field = Member->getMember())
+ Diag(Member->getSourceLocation(),
+ diag::note_fieldorbase_initialized_here) << 0
+ << Field->getNameAsString();
+ else {
+ Type *BaseClass = Member->getBaseClass();
+ Diag(Member->getSourceLocation(),
+ diag::note_fieldorbase_initialized_here) << 1
+ << QualType(BaseClass, 0);
+ }
+ for (curIndex = 0; curIndex < Last; curIndex++)
+ if (MemberInCtorList == AllBaseOrMembers[curIndex])
+ break;
}
- if (FieldDecl *Field = Member->getMember())
- Diag(Member->getSourceLocation(),
- diag::error_multiple_mem_initialization)
- << Field->getNameAsString();
- else {
- Type *BaseClass = Member->getBaseClass();
- assert(BaseClass && "ActOnMemInitializers - neither field or base");
- Diag(Member->getSourceLocation(),
- diag::error_multiple_base_initialization)
- << BaseClass->getDesugaredType(true);
+ PrevMember = Member;
+ }
+}
+
+void
+Sema::computeBaseOrMembersToDestroy(CXXDestructorDecl *Destructor) {
+ CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Destructor->getDeclContext());
+ llvm::SmallVector<uintptr_t, 32> AllToDestruct;
+
+ for (CXXRecordDecl::base_class_iterator VBase = ClassDecl->vbases_begin(),
+ E = ClassDecl->vbases_end(); VBase != E; ++VBase) {
+ if (VBase->getType()->isDependentType())
+ continue;
+ // Skip over virtual bases which have trivial destructors.
+ CXXRecordDecl *BaseClassDecl
+ = cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl());
+ if (BaseClassDecl->hasTrivialDestructor())
+ continue;
+ if (const CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context))
+ MarkDeclarationReferenced(Destructor->getLocation(),
+ const_cast<CXXDestructorDecl*>(Dtor));
+
+ uintptr_t Member =
+ reinterpret_cast<uintptr_t>(VBase->getType().getTypePtr())
+ | CXXDestructorDecl::VBASE;
+ AllToDestruct.push_back(Member);
+ }
+ for (CXXRecordDecl::base_class_iterator Base =
+ ClassDecl->bases_begin(),
+ E = ClassDecl->bases_end(); Base != E; ++Base) {
+ if (Base->isVirtual())
+ continue;
+ if (Base->getType()->isDependentType())
+ continue;
+ // Skip over virtual bases which have trivial destructors.
+ CXXRecordDecl *BaseClassDecl
+ = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ if (BaseClassDecl->hasTrivialDestructor())
+ continue;
+ if (const CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context))
+ MarkDeclarationReferenced(Destructor->getLocation(),
+ const_cast<CXXDestructorDecl*>(Dtor));
+ uintptr_t Member =
+ reinterpret_cast<uintptr_t>(Base->getType().getTypePtr())
+ | CXXDestructorDecl::DRCTNONVBASE;
+ AllToDestruct.push_back(Member);
+ }
+
+ // non-static data members.
+ for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
+ E = ClassDecl->field_end(); Field != E; ++Field) {
+ QualType FieldType = Context.getBaseElementType((*Field)->getType());
+
+ if (const RecordType* RT = FieldType->getAs<RecordType>()) {
+ // Skip over virtual bases which have trivial destructors.
+ CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
+ if (FieldClassDecl->hasTrivialDestructor())
+ continue;
+ if (const CXXDestructorDecl *Dtor =
+ FieldClassDecl->getDestructor(Context))
+ MarkDeclarationReferenced(Destructor->getLocation(),
+ const_cast<CXXDestructorDecl*>(Dtor));
+ uintptr_t Member = reinterpret_cast<uintptr_t>(*Field);
+ AllToDestruct.push_back(Member);
}
- Diag(PrevMember->getSourceLocation(), diag::note_previous_initializer)
- << 0;
- err = true;
}
- if (!err)
- Constructor->setBaseOrMemberInitializers(Context,
- reinterpret_cast<CXXBaseOrMemberInitializer **>(MemInits),
- NumMemInits);
+
+ unsigned NumDestructions = AllToDestruct.size();
+ if (NumDestructions > 0) {
+ Destructor->setNumBaseOrMemberDestructions(NumDestructions);
+ uintptr_t *BaseOrMemberDestructions =
+ new (Context) uintptr_t [NumDestructions];
+ // Insert in reverse order.
+ for (int Idx = NumDestructions-1, i=0 ; Idx >= 0; --Idx)
+ BaseOrMemberDestructions[i++] = AllToDestruct[Idx];
+ Destructor->setBaseOrMemberDestructions(BaseOrMemberDestructions);
+ }
+}
+
+void Sema::ActOnDefaultCtorInitializers(DeclPtrTy CDtorDecl) {
+ if (!CDtorDecl)
+ return;
+
+ AdjustDeclIfTemplate(CDtorDecl);
+
+ if (CXXConstructorDecl *Constructor
+ = dyn_cast<CXXConstructorDecl>(CDtorDecl.getAs<Decl>()))
+ BuildBaseOrMemberInitializers(Context,
+ Constructor,
+ (CXXBaseOrMemberInitializer **)0, 0);
}
namespace {
@@ -836,58 +1611,58 @@ namespace {
private:
MethodList Methods;
-
+
void Collect(const CXXRecordDecl* RD, MethodList& Methods);
-
+
public:
- PureVirtualMethodCollector(ASTContext &Ctx, const CXXRecordDecl* RD)
+ 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,
+
+ 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()) {
+ if (const RecordType *RT = Base->getType()->getAs<RecordType>()) {
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(), e = RD->decls_end();
+ for (RecordDecl::decl_iterator i = RD->decls_begin(), e = RD->decls_end();
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 the method is pure 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) {
@@ -896,82 +1671,92 @@ namespace {
}
}
}
-
- // Now go through the methods and zero out all the ones we know are
+
+ // 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,
+
+bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T,
unsigned DiagID, AbstractDiagSelID SelID,
const CXXRecordDecl *CurrentRD) {
-
+ if (SelID == -1)
+ return RequireNonAbstractType(Loc, T,
+ PDiag(DiagID), CurrentRD);
+ else
+ return RequireNonAbstractType(Loc, T,
+ PDiag(DiagID) << SelID, CurrentRD);
+}
+
+bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T,
+ const PartialDiagnostic &PD,
+ const CXXRecordDecl *CurrentRD) {
if (!getLangOptions().CPlusPlus)
return false;
-
+
if (const ArrayType *AT = Context.getAsArrayType(T))
- return RequireNonAbstractType(Loc, AT->getElementType(), DiagID, SelID,
+ return RequireNonAbstractType(Loc, AT->getElementType(), PD,
CurrentRD);
-
- if (const PointerType *PT = T->getAsPointerType()) {
+
+ if (const PointerType *PT = T->getAs<PointerType>()) {
// Find the innermost pointer type.
- while (const PointerType *T = PT->getPointeeType()->getAsPointerType())
+ while (const PointerType *T = PT->getPointeeType()->getAs<PointerType>())
PT = T;
-
+
if (const ArrayType *AT = Context.getAsArrayType(PT->getPointeeType()))
- return RequireNonAbstractType(Loc, AT->getElementType(), DiagID, SelID,
- CurrentRD);
+ return RequireNonAbstractType(Loc, AT->getElementType(), PD, CurrentRD);
}
-
- const RecordType *RT = T->getAsRecordType();
+
+ const RecordType *RT = T->getAs<RecordType>();
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;
-
+
+ Diag(Loc, PD) << RD->getDeclName();
+
// 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 =
+
+ 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) <<
+
+ 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
+ class VISIBILITY_HIDDEN AbstractClassUsageDiagnoser
: public DeclVisitor<AbstractClassUsageDiagnoser, bool> {
Sema &SemaRef;
CXXRecordDecl *AbstractClass;
-
+
bool VisitDeclContext(const DeclContext *DC) {
bool Invalid = false;
@@ -981,7 +1766,7 @@ namespace {
return Invalid;
}
-
+
public:
AbstractClassUsageDiagnoser(Sema& SemaRef, CXXRecordDecl *ac)
: SemaRef(SemaRef), AbstractClass(ac) {
@@ -992,36 +1777,36 @@ namespace {
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
+ // because that requires
return VisitDeclContext(FD);
}
-
+
// Check the return type.
- QualType RTy = FD->getType()->getAsFunctionType()->getResultType();
- bool Invalid =
+ QualType RTy = FD->getType()->getAs<FunctionType>()->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(),
+ for (FunctionDecl::param_const_iterator I = FD->param_begin(),
E = FD->param_end(); I != E; ++I) {
const ParmVarDecl *VD = *I;
- Invalid |=
+ Invalid |=
SemaRef.RequireNonAbstractType(VD->getLocation(),
- VD->getOriginalType(),
- diag::err_abstract_type_in_decl,
+ 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;
}
};
@@ -1033,7 +1818,7 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
SourceLocation RBrac) {
if (!TagDecl)
return;
-
+
AdjustDeclIfTemplate(TagDecl);
ActOnFields(S, RLoc, TagDecl,
(DeclPtrTy*)FieldCollector->getCurFields(),
@@ -1044,37 +1829,13 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
// Collect all the pure virtual methods and see if this is an abstract
// class after all.
PureVirtualMethodCollector Collector(Context, RD);
- if (!Collector.empty())
+ if (!Collector.empty())
RD->setAbstract(true);
}
-
- if (RD->isAbstract())
+
+ if (RD->isAbstract())
AbstractClassUsageDiagnoser(*this, RD);
-
- if (RD->hasTrivialConstructor() || RD->hasTrivialDestructor()) {
- for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
- 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);
}
@@ -1085,8 +1846,8 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
/// [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);
+ CanQualType ClassType
+ = Context.getCanonicalType(Context.getTypeDeclType(ClassDecl));
// FIXME: Implicit declarations have exception specifications, which are
// the union of the specifications of the implicitly called functions.
@@ -1098,18 +1859,20 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
// 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
+ DeclarationName Name
= Context.DeclarationNames.getCXXConstructorName(ClassType);
- CXXConstructorDecl *DefaultCon =
+ CXXConstructorDecl *DefaultCon =
CXXConstructorDecl::Create(Context, ClassDecl,
ClassDecl->getLocation(), Name,
Context.getFunctionType(Context.VoidTy,
0, 0, false, 0),
+ /*DInfo=*/0,
/*isExplicit=*/false,
/*isInline=*/true,
/*isImplicitlyDeclared=*/true);
DefaultCon->setAccess(AS_public);
DefaultCon->setImplicit();
+ DefaultCon->setTrivial(ClassDecl->hasTrivialConstructor());
ClassDecl->addDecl(DefaultCon);
}
@@ -1133,8 +1896,8 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
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
+ = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ HasConstCopyConstructor
= BaseClassDecl->hasConstCopyConstructor(Context);
}
@@ -1148,10 +1911,10 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
QualType FieldType = (*Field)->getType();
if (const ArrayType *Array = Context.getAsArrayType(FieldType))
FieldType = Array->getElementType();
- if (const RecordType *FieldClassType = FieldType->getAsRecordType()) {
- const CXXRecordDecl *FieldClassDecl
+ if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
+ const CXXRecordDecl *FieldClassDecl
= cast<CXXRecordDecl>(FieldClassType->getDecl());
- HasConstCopyConstructor
+ HasConstCopyConstructor
= FieldClassDecl->hasConstCopyConstructor(Context);
}
}
@@ -1167,7 +1930,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
// An implicitly-declared copy constructor is an inline public
// member of its class.
- DeclarationName Name
+ DeclarationName Name
= Context.DeclarationNames.getCXXConstructorName(ClassType);
CXXConstructorDecl *CopyConstructor
= CXXConstructorDecl::Create(Context, ClassDecl,
@@ -1175,17 +1938,20 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
Context.getFunctionType(Context.VoidTy,
&ArgType, 1,
false, 0),
+ /*DInfo=*/0,
/*isExplicit=*/false,
/*isInline=*/true,
/*isImplicitlyDeclared=*/true);
CopyConstructor->setAccess(AS_public);
CopyConstructor->setImplicit();
+ CopyConstructor->setTrivial(ClassDecl->hasTrivialCopyConstructor());
// Add the parameter to the constructor.
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyConstructor,
ClassDecl->getLocation(),
/*IdentifierInfo=*/0,
- ArgType, VarDecl::None, 0);
+ ArgType, /*DInfo=*/0,
+ VarDecl::None, 0);
CopyConstructor->setParams(Context, &FromParam, 1);
ClassDecl->addDecl(CopyConstructor);
}
@@ -1213,8 +1979,10 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
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);
+ = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ const CXXMethodDecl *MD = 0;
+ HasConstCopyAssignment = BaseClassDecl->hasConstCopyAssignment(Context,
+ MD);
}
// -- for all the nonstatic data members of X that are of a class
@@ -1227,11 +1995,12 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
QualType FieldType = (*Field)->getType();
if (const ArrayType *Array = Context.getAsArrayType(FieldType))
FieldType = Array->getElementType();
- if (const RecordType *FieldClassType = FieldType->getAsRecordType()) {
+ if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
const CXXRecordDecl *FieldClassDecl
= cast<CXXRecordDecl>(FieldClassType->getDecl());
+ const CXXMethodDecl *MD = 0;
HasConstCopyAssignment
- = FieldClassDecl->hasConstCopyAssignment(Context);
+ = FieldClassDecl->hasConstCopyAssignment(Context, MD);
}
}
@@ -1253,15 +2022,18 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
CXXMethodDecl::Create(Context, ClassDecl, ClassDecl->getLocation(), Name,
Context.getFunctionType(RetType, &ArgType, 1,
false, 0),
- /*isStatic=*/false, /*isInline=*/true);
+ /*DInfo=*/0, /*isStatic=*/false, /*isInline=*/true);
CopyAssignment->setAccess(AS_public);
CopyAssignment->setImplicit();
+ CopyAssignment->setTrivial(ClassDecl->hasTrivialCopyAssignment());
+ CopyAssignment->setCopyAssignment(true);
// Add the parameter to the operator.
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyAssignment,
ClassDecl->getLocation(),
/*IdentifierInfo=*/0,
- ArgType, VarDecl::None, 0);
+ ArgType, /*DInfo=*/0,
+ VarDecl::None, 0);
CopyAssignment->setParams(Context, &FromParam, 1);
// Don't call addedAssignmentOperator. There is no way to distinguish an
@@ -1274,9 +2046,9 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
// If a class has no user-declared destructor, a destructor is
// declared implicitly. An implicitly-declared destructor is an
// inline public member of its class.
- DeclarationName Name
+ DeclarationName Name
= Context.DeclarationNames.getCXXDestructorName(ClassType);
- CXXDestructorDecl *Destructor
+ CXXDestructorDecl *Destructor
= CXXDestructorDecl::Create(Context, ClassDecl,
ClassDecl->getLocation(), Name,
Context.getFunctionType(Context.VoidTy,
@@ -1285,16 +2057,25 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
/*isImplicitlyDeclared=*/true);
Destructor->setAccess(AS_public);
Destructor->setImplicit();
+ Destructor->setTrivial(ClassDecl->hasTrivialDestructor());
ClassDecl->addDecl(Destructor);
}
}
void Sema::ActOnReenterTemplateScope(Scope *S, DeclPtrTy TemplateD) {
- TemplateDecl *Template = TemplateD.getAs<TemplateDecl>();
- if (!Template)
+ Decl *D = TemplateD.getAs<Decl>();
+ if (!D)
+ return;
+
+ TemplateParameterList *Params = 0;
+ if (TemplateDecl *Template = dyn_cast<TemplateDecl>(D))
+ Params = Template->getTemplateParameters();
+ else if (ClassTemplatePartialSpecializationDecl *PartialSpec
+ = dyn_cast<ClassTemplatePartialSpecializationDecl>(D))
+ Params = PartialSpec->getTemplateParameters();
+ else
return;
- TemplateParameterList *Params = Template->getTemplateParameters();
for (TemplateParameterList::iterator Param = Params->begin(),
ParamEnd = Params->end();
Param != ParamEnd; ++Param) {
@@ -1317,10 +2098,12 @@ void Sema::ActOnReenterTemplateScope(Scope *S, DeclPtrTy TemplateD) {
void Sema::ActOnStartDelayedCXXMethodDeclaration(Scope *S, DeclPtrTy MethodD) {
if (!MethodD)
return;
-
+
+ AdjustDeclIfTemplate(MethodD);
+
CXXScopeSpec SS;
FunctionDecl *Method = cast<FunctionDecl>(MethodD.getAs<Decl>());
- QualType ClassTy
+ QualType ClassTy
= Context.getTypeDeclType(cast<RecordDecl>(Method->getDeclContext()));
SS.setScopeRep(
NestedNameSpecifier::Create(Context, 0, false, ClassTy.getTypePtr()));
@@ -1335,7 +2118,7 @@ void Sema::ActOnStartDelayedCXXMethodDeclaration(Scope *S, DeclPtrTy MethodD) {
void Sema::ActOnDelayedCXXMethodParameter(Scope *S, DeclPtrTy ParamD) {
if (!ParamD)
return;
-
+
ParmVarDecl *Param = cast<ParmVarDecl>(ParamD.getAs<Decl>());
// If this parameter has an unparsed default argument, clear it out
@@ -1357,10 +2140,12 @@ void Sema::ActOnDelayedCXXMethodParameter(Scope *S, DeclPtrTy ParamD) {
void Sema::ActOnFinishDelayedCXXMethodDeclaration(Scope *S, DeclPtrTy MethodD) {
if (!MethodD)
return;
-
+
+ AdjustDeclIfTemplate(MethodD);
+
FunctionDecl *Method = cast<FunctionDecl>(MethodD.getAs<Decl>());
CXXScopeSpec SS;
- QualType ClassTy
+ QualType ClassTy
= Context.getTypeDeclType(cast<RecordDecl>(Method->getDeclContext()));
SS.setScopeRep(
NestedNameSpecifier::Create(Context, 0, false, ClassTy.getTypePtr()));
@@ -1408,26 +2193,26 @@ QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R,
D.setInvalidType();
SC = FunctionDecl::None;
}
-
+
DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun;
if (FTI.TypeQuals != 0) {
- if (FTI.TypeQuals & QualType::Const)
+ if (FTI.TypeQuals & Qualifiers::Const)
Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_constructor)
<< "const" << SourceRange(D.getIdentifierLoc());
- if (FTI.TypeQuals & QualType::Volatile)
+ if (FTI.TypeQuals & Qualifiers::Volatile)
Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_constructor)
<< "volatile" << SourceRange(D.getIdentifierLoc());
- if (FTI.TypeQuals & QualType::Restrict)
+ if (FTI.TypeQuals & Qualifiers::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();
+ const FunctionProtoType *Proto = R->getAs<FunctionProtoType>();
return Context.getFunctionType(Context.VoidTy, Proto->arg_type_begin(),
Proto->getNumArgs(),
Proto->isVariadic(), 0);
@@ -1437,7 +2222,7 @@ QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R,
/// well-formedness, issuing any diagnostics required. Returns true if
/// the constructor declarator is invalid.
void Sema::CheckConstructor(CXXConstructorDecl *Constructor) {
- CXXRecordDecl *ClassDecl
+ CXXRecordDecl *ClassDecl
= dyn_cast<CXXRecordDecl>(Constructor->getDeclContext());
if (!ClassDecl)
return Constructor->setInvalidDecl();
@@ -1448,8 +2233,8 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) {
// either there are no other parameters or else all other
// parameters have default arguments.
if (!Constructor->isInvalidDecl() &&
- ((Constructor->getNumParams() == 1) ||
- (Constructor->getNumParams() > 1 &&
+ ((Constructor->getNumParams() == 1) ||
+ (Constructor->getNumParams() > 1 &&
Constructor->getParamDecl(1)->hasDefaultArg()))) {
QualType ParamType = Constructor->getParamDecl(0)->getType();
QualType ClassTy = Context.getTagDeclType(ClassDecl);
@@ -1460,12 +2245,12 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) {
Constructor->setInvalidDecl();
}
}
-
+
// Notify the class that we've added a constructor.
ClassDecl->addedConstructor(Context, Constructor);
}
-static inline bool
+static inline bool
FTIHasSingleVoidArgument(DeclaratorChunk::FunctionTypeInfo &FTI) {
return (FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 &&
FTI.ArgInfo[0].Param &&
@@ -1485,7 +2270,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D,
// (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());
+ QualType DeclaratorType = GetTypeFromParser(D.getDeclaratorIdType());
if (isa<TypedefType>(DeclaratorType)) {
Diag(D.getIdentifierLoc(), diag::err_destructor_typedef_name)
<< DeclaratorType;
@@ -1521,16 +2306,16 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D,
<< 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)
+ if (FTI.TypeQuals & Qualifiers::Const)
Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_destructor)
<< "const" << SourceRange(D.getIdentifierLoc());
- if (FTI.TypeQuals & QualType::Volatile)
+ if (FTI.TypeQuals & Qualifiers::Volatile)
Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_destructor)
<< "volatile" << SourceRange(D.getIdentifierLoc());
- if (FTI.TypeQuals & QualType::Restrict)
+ if (FTI.TypeQuals & Qualifiers::Restrict)
Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_destructor)
<< "restrict" << SourceRange(D.getIdentifierLoc());
D.setInvalidType();
@@ -1545,7 +2330,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D,
D.setInvalidType();
}
- // Make sure the destructor isn't variadic.
+ // Make sure the destructor isn't variadic.
if (FTI.isVariadic) {
Diag(D.getIdentifierLoc(), diag::err_destructor_variadic);
D.setInvalidType();
@@ -1569,8 +2354,8 @@ 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.”
+ // 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)
@@ -1594,7 +2379,7 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
}
// Make sure we don't have any parameters.
- if (R->getAsFunctionProtoType()->getNumArgs() > 0) {
+ if (R->getAs<FunctionProtoType>()->getNumArgs() > 0) {
Diag(D.getIdentifierLoc(), diag::err_conv_function_with_params);
// Delete the parameters.
@@ -1602,8 +2387,8 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
D.setInvalidType();
}
- // Make sure the conversion function isn't variadic.
- if (R->getAsFunctionProtoType()->isVariadic() && !D.isInvalidType()) {
+ // Make sure the conversion function isn't variadic.
+ if (R->getAs<FunctionProtoType>()->isVariadic() && !D.isInvalidType()) {
Diag(D.getIdentifierLoc(), diag::err_conv_function_variadic);
D.setInvalidType();
}
@@ -1611,7 +2396,7 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
// 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());
+ QualType ConvType = GetTypeFromParser(D.getDeclaratorIdType());
if (ConvType->isArrayType()) {
Diag(D.getIdentifierLoc(), diag::err_conv_function_to_array);
ConvType = Context.getPointerType(ConvType);
@@ -1624,13 +2409,13 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
// 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());
+ // return type.
+ R = Context.getFunctionType(ConvType, 0, 0, false,
+ R->getAs<FunctionProtoType>()->getTypeQuals());
// C++0x explicit conversion operators.
if (D.getDeclSpec().isExplicitSpecified() && !getLangOptions().CPlusPlus0x)
- Diag(D.getDeclSpec().getExplicitSpecLoc(),
+ Diag(D.getDeclSpec().getExplicitSpecLoc(),
diag::warn_explicit_conversion_functions)
<< SourceRange(D.getDeclSpec().getExplicitSpecLoc());
}
@@ -1642,9 +2427,6 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
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.
@@ -1658,9 +2440,9 @@ Sema::DeclPtrTy Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) {
// 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
+ QualType ClassType
= Context.getCanonicalType(Context.getTypeDeclType(ClassDecl));
- if (const ReferenceType *ConvTypeRef = ConvType->getAsReferenceType())
+ if (const ReferenceType *ConvTypeRef = ConvType->getAs<ReferenceType>())
ConvType = ConvTypeRef->getPointeeType();
if (ConvType->isRecordType()) {
ConvType = Context.getCanonicalType(ConvType).getUnqualifiedType();
@@ -1676,20 +2458,26 @@ Sema::DeclPtrTy Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) {
}
if (Conversion->getPreviousDeclaration()) {
+ const NamedDecl *ExpectedPrevDecl = Conversion->getPreviousDeclaration();
+ if (FunctionTemplateDecl *ConversionTemplate
+ = Conversion->getDescribedFunctionTemplate())
+ ExpectedPrevDecl = ConversionTemplate->getPreviousDeclaration();
OverloadedFunctionDecl *Conversions = ClassDecl->getConversionFunctions();
- for (OverloadedFunctionDecl::function_iterator
+ for (OverloadedFunctionDecl::function_iterator
Conv = Conversions->function_begin(),
ConvEnd = Conversions->function_end();
Conv != ConvEnd; ++Conv) {
- if (*Conv
- == cast_or_null<NamedDecl>(Conversion->getPreviousDeclaration())) {
+ if (*Conv == ExpectedPrevDecl) {
*Conv = Conversion;
return DeclPtrTy::make(Conversion);
}
}
assert(Conversion->isInvalidDecl() && "Conversion should not get here.");
- } else
- ClassDecl->addConversionFunction(Context, Conversion);
+ } else if (FunctionTemplateDecl *ConversionTemplate
+ = Conversion->getDescribedFunctionTemplate())
+ ClassDecl->addConversionFunction(ConversionTemplate);
+ else if (!Conversion->getPrimaryTemplate()) // ignore specializations
+ ClassDecl->addConversionFunction(Conversion);
return DeclPtrTy::make(Conversion);
}
@@ -1718,9 +2506,9 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
// 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);
-
+ NamedDecl *PrevDecl
+ = LookupSingleName(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
@@ -1728,7 +2516,7 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
OrigNS->setNextNamespace(Namespc);
Namespc->setOriginalNamespace(OrigNS->getOriginalNamespace());
- // Remove the previous declaration from the scope.
+ // Remove the previous declaration from the scope.
if (DeclRegionScope->isDeclScope(DeclPtrTy::make(OrigNS))) {
IdResolver.RemoveDecl(OrigNS);
DeclRegionScope->RemoveDecl(DeclPtrTy::make(OrigNS));
@@ -1740,11 +2528,57 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
Diag(PrevDecl->getLocation(), diag::note_previous_definition);
Namespc->setInvalidDecl();
// Continue on to push Namespc as current DeclContext and return it.
- }
+ } else if (II->isStr("std") &&
+ CurContext->getLookupContext()->isTranslationUnit()) {
+ // This is the first "real" definition of the namespace "std", so update
+ // our cache of the "std" namespace to point at this definition.
+ if (StdNamespace) {
+ // We had already defined a dummy namespace "std". Link this new
+ // namespace definition to the dummy namespace "std".
+ StdNamespace->setNextNamespace(Namespc);
+ StdNamespace->setLocation(IdentLoc);
+ Namespc->setOriginalNamespace(StdNamespace->getOriginalNamespace());
+ }
+
+ // Make our StdNamespace cache point at the first real definition of the
+ // "std" namespace.
+ StdNamespace = Namespc;
+ }
PushOnScopeChains(Namespc, DeclRegionScope);
} else {
- // FIXME: Handle anonymous namespaces
+ // Anonymous namespaces.
+
+ // C++ [namespace.unnamed]p1. An unnamed-namespace-definition
+ // behaves as if it were replaced by
+ // namespace unique { /* empty body */ }
+ // using namespace unique;
+ // namespace unique { namespace-body }
+ // where all occurrences of 'unique' in a translation unit are
+ // replaced by the same identifier and this identifier differs
+ // from all other identifiers in the entire program.
+
+ // We just create the namespace with an empty name and then add an
+ // implicit using declaration, just like the standard suggests.
+ //
+ // CodeGen enforces the "universally unique" aspect by giving all
+ // declarations semantically contained within an anonymous
+ // namespace internal linkage.
+
+ assert(Namespc->isAnonymousNamespace());
+ CurContext->addDecl(Namespc);
+
+ UsingDirectiveDecl* UD
+ = UsingDirectiveDecl::Create(Context, CurContext,
+ /* 'using' */ LBrace,
+ /* 'namespace' */ SourceLocation(),
+ /* qualifier */ SourceRange(),
+ /* NNS */ NULL,
+ /* identifier */ SourceLocation(),
+ Namespc,
+ /* Ancestor */ CurContext);
+ UD->setImplicit();
+ CurContext->addDecl(UD);
}
// Although we could have an invalid decl (i.e. the namespace name is a
@@ -1781,13 +2615,14 @@ Sema::DeclPtrTy Sema::ActOnUsingDirective(Scope *S,
UsingDirectiveDecl *UDir = 0;
// Lookup namespace name.
- LookupResult R = LookupParsedName(S, &SS, NamespcName,
- LookupNamespaceName, false);
+ LookupResult R;
+ LookupParsedName(R, S, &SS, NamespcName, LookupNamespaceName, false);
if (R.isAmbiguous()) {
DiagnoseAmbiguousLookup(R, NamespcName, IdentLoc);
return DeclPtrTy();
}
- if (NamedDecl *NS = R) {
+ if (!R.empty()) {
+ NamedDecl *NS = R.getFoundDecl();
assert(isa<NamespaceDecl>(NS) && "expected namespace decl");
// C++ [namespace.udir]p1:
// A using-directive specifies that the names in the nominated
@@ -1796,8 +2631,8 @@ Sema::DeclPtrTy Sema::ActOnUsingDirective(Scope *S,
// 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”. ]
+ // namespace. [Note: in this context, "contains" means "contains
+ // directly or indirectly". ]
// Find enclosing context containing both using-directive and
// nominated namespace.
@@ -1805,9 +2640,9 @@ Sema::DeclPtrTy Sema::ActOnUsingDirective(Scope *S,
while (CommonAncestor && !CommonAncestor->Encloses(CurContext))
CommonAncestor = CommonAncestor->getParent();
- UDir = UsingDirectiveDecl::Create(Context,
+ UDir = UsingDirectiveDecl::Create(Context,
CurContext, UsingLoc,
- NamespcLoc,
+ NamespcLoc,
SS.getRange(),
(NestedNameSpecifier *)SS.getScopeRep(),
IdentLoc,
@@ -1837,45 +2672,124 @@ void Sema::PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir) {
Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S,
- SourceLocation UsingLoc,
- const CXXScopeSpec &SS,
- SourceLocation IdentLoc,
- IdentifierInfo *TargetName,
- OverloadedOperatorKind Op,
- AttributeList *AttrList,
- bool IsTypeName) {
- assert(!SS.isInvalid() && "Invalid CXXScopeSpec.");
+ AccessSpecifier AS,
+ SourceLocation UsingLoc,
+ const CXXScopeSpec &SS,
+ SourceLocation IdentLoc,
+ IdentifierInfo *TargetName,
+ OverloadedOperatorKind Op,
+ AttributeList *AttrList,
+ bool IsTypeName) {
assert((TargetName || Op) && "Invalid TargetName.");
- assert(IdentLoc.isValid() && "Invalid TargetName location.");
assert(S->getFlags() & Scope::DeclScope && "Invalid Scope.");
- UsingDecl *UsingAlias = 0;
-
DeclarationName Name;
if (TargetName)
Name = TargetName;
else
Name = Context.DeclarationNames.getCXXOperatorName(Op);
-
- // Lookup target name.
- LookupResult R = LookupParsedName(S, &SS, Name, LookupOrdinaryName, false);
- if (NamedDecl *NS = R) {
- if (IsTypeName && !isa<TypeDecl>(NS)) {
- Diag(IdentLoc, diag::err_using_typename_non_type);
- }
- UsingAlias = UsingDecl::Create(Context, CurContext, IdentLoc, SS.getRange(),
- NS->getLocation(), UsingLoc, NS,
- static_cast<NestedNameSpecifier *>(SS.getScopeRep()),
- IsTypeName);
- PushOnScopeChains(UsingAlias, S);
- } else {
- Diag(IdentLoc, diag::err_using_requires_qualname) << SS.getRange();
+ NamedDecl *UD = BuildUsingDeclaration(UsingLoc, SS, IdentLoc,
+ Name, AttrList, IsTypeName);
+ if (UD) {
+ PushOnScopeChains(UD, S);
+ UD->setAccess(AS);
}
+ return DeclPtrTy::make(UD);
+}
+
+NamedDecl *Sema::BuildUsingDeclaration(SourceLocation UsingLoc,
+ const CXXScopeSpec &SS,
+ SourceLocation IdentLoc,
+ DeclarationName Name,
+ AttributeList *AttrList,
+ bool IsTypeName) {
+ assert(!SS.isInvalid() && "Invalid CXXScopeSpec.");
+ assert(IdentLoc.isValid() && "Invalid TargetName location.");
+
// FIXME: We ignore attributes for now.
delete AttrList;
- return DeclPtrTy::make(UsingAlias);
+
+ if (SS.isEmpty()) {
+ Diag(IdentLoc, diag::err_using_requires_qualname);
+ return 0;
+ }
+
+ NestedNameSpecifier *NNS =
+ static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+
+ if (isUnknownSpecialization(SS)) {
+ return UnresolvedUsingDecl::Create(Context, CurContext, UsingLoc,
+ SS.getRange(), NNS,
+ IdentLoc, Name, IsTypeName);
+ }
+
+ DeclContext *LookupContext = 0;
+
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(CurContext)) {
+ // C++0x N2914 [namespace.udecl]p3:
+ // A using-declaration used as a member-declaration shall refer to a member
+ // of a base class of the class being defined, shall refer to a member of an
+ // anonymous union that is a member of a base class of the class being
+ // defined, or shall refer to an enumerator for an enumeration type that is
+ // a member of a base class of the class being defined.
+ const Type *Ty = NNS->getAsType();
+ if (!Ty || !IsDerivedFrom(Context.getTagDeclType(RD), QualType(Ty, 0))) {
+ Diag(SS.getRange().getBegin(),
+ diag::err_using_decl_nested_name_specifier_is_not_a_base_class)
+ << NNS << RD->getDeclName();
+ return 0;
+ }
+
+ QualType BaseTy = Context.getCanonicalType(QualType(Ty, 0));
+ LookupContext = BaseTy->getAs<RecordType>()->getDecl();
+ } else {
+ // C++0x N2914 [namespace.udecl]p8:
+ // A using-declaration for a class member shall be a member-declaration.
+ if (NNS->getKind() == NestedNameSpecifier::TypeSpec) {
+ Diag(IdentLoc, diag::err_using_decl_can_not_refer_to_class_member)
+ << SS.getRange();
+ return 0;
+ }
+
+ // C++0x N2914 [namespace.udecl]p9:
+ // In a using-declaration, a prefix :: refers to the global namespace.
+ if (NNS->getKind() == NestedNameSpecifier::Global)
+ LookupContext = Context.getTranslationUnitDecl();
+ else
+ LookupContext = NNS->getAsNamespace();
+ }
+
+
+ // Lookup target name.
+ LookupResult R;
+ LookupQualifiedName(R, LookupContext, Name, LookupOrdinaryName);
+
+ if (R.empty()) {
+ Diag(IdentLoc, diag::err_no_member)
+ << Name << LookupContext << SS.getRange();
+ return 0;
+ }
+
+ // FIXME: handle ambiguity?
+ NamedDecl *ND = R.getAsSingleDecl(Context);
+
+ if (IsTypeName && !isa<TypeDecl>(ND)) {
+ Diag(IdentLoc, diag::err_using_typename_non_type);
+ return 0;
+ }
+
+ // C++0x N2914 [namespace.udecl]p6:
+ // A using-declaration shall not name a namespace.
+ if (isa<NamespaceDecl>(ND)) {
+ Diag(IdentLoc, diag::err_using_decl_can_not_refer_to_namespace)
+ << SS.getRange();
+ return 0;
+ }
+
+ return UsingDecl::Create(Context, CurContext, IdentLoc, SS.getRange(),
+ ND->getLocation(), UsingLoc, ND, NNS, IsTypeName);
}
/// getNamespaceDecl - Returns the namespace a decl represents. If the decl
@@ -1886,26 +2800,29 @@ static inline NamespaceDecl *getNamespaceDecl(NamedDecl *D) {
return dyn_cast_or_null<NamespaceDecl>(D);
}
-Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S,
+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);
+ LookupResult R;
+ LookupParsedName(R, 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 (NamedDecl *PrevDecl
+ = LookupSingleName(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
+ // 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))
+ if (!R.isAmbiguous() && !R.empty() &&
+ AD->getNamespace() == getNamespaceDecl(R.getFoundDecl()))
return DeclPtrTy();
}
-
+
unsigned DiagID = isa<NamespaceDecl>(PrevDecl) ? diag::err_redefinition :
diag::err_redefinition_different_kind;
Diag(AliasLoc, DiagID) << Alias;
@@ -1917,18 +2834,18 @@ Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S,
DiagnoseAmbiguousLookup(R, Ident, IdentLoc);
return DeclPtrTy();
}
-
- if (!R) {
+
+ if (R.empty()) {
Diag(NamespaceLoc, diag::err_expected_namespace_name) << SS.getRange();
return DeclPtrTy();
}
-
+
NamespaceAliasDecl *AliasDecl =
- NamespaceAliasDecl::Create(Context, CurContext, NamespaceLoc, AliasLoc,
- Alias, SS.getRange(),
+ NamespaceAliasDecl::Create(Context, CurContext, NamespaceLoc, AliasLoc,
+ Alias, SS.getRange(),
(NestedNameSpecifier *)SS.getScopeRep(),
- IdentLoc, R);
-
+ IdentLoc, R.getFoundDecl());
+
CurContext->addDecl(AliasDecl);
return DeclPtrTy::make(AliasDecl);
}
@@ -1938,11 +2855,11 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
assert((Constructor->isImplicit() && Constructor->isDefaultConstructor() &&
!Constructor->isUsed()) &&
"DefineImplicitDefaultConstructor - call it for implicit default ctor");
-
+
CXXRecordDecl *ClassDecl
= cast<CXXRecordDecl>(Constructor->getDeclContext());
assert(ClassDecl && "DefineImplicitDefaultConstructor - invalid constructor");
- // Before the implicitly-declared default constructor for a class is
+ // Before the implicitly-declared default constructor for a class is
// implicitly defined, all the implicitly-declared default constructors
// for its base class and its non-static data members shall have been
// implicitly defined.
@@ -1950,16 +2867,16 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
E = ClassDecl->bases_end(); Base != E; ++Base) {
CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAsRecordType()->getDecl());
+ = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
if (!BaseClassDecl->hasTrivialConstructor()) {
- if (CXXConstructorDecl *BaseCtor =
+ if (CXXConstructorDecl *BaseCtor =
BaseClassDecl->getDefaultConstructor(Context))
MarkDeclarationReferenced(CurrentLocation, BaseCtor);
else {
- Diag(CurrentLocation, diag::err_defining_default_ctor)
- << Context.getTagDeclType(ClassDecl) << 1
+ Diag(CurrentLocation, diag::err_defining_default_ctor)
+ << Context.getTagDeclType(ClassDecl) << 0
<< Context.getTagDeclType(BaseClassDecl);
- Diag(BaseClassDecl->getLocation(), diag::note_previous_class_decl)
+ Diag(BaseClassDecl->getLocation(), diag::note_previous_class_decl)
<< Context.getTagDeclType(BaseClassDecl);
err = true;
}
@@ -1970,32 +2887,31 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
QualType FieldType = Context.getCanonicalType((*Field)->getType());
if (const ArrayType *Array = Context.getAsArrayType(FieldType))
FieldType = Array->getElementType();
- if (const RecordType *FieldClassType = FieldType->getAsRecordType()) {
+ if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
CXXRecordDecl *FieldClassDecl
= cast<CXXRecordDecl>(FieldClassType->getDecl());
if (!FieldClassDecl->hasTrivialConstructor()) {
- if (CXXConstructorDecl *FieldCtor =
+ if (CXXConstructorDecl *FieldCtor =
FieldClassDecl->getDefaultConstructor(Context))
MarkDeclarationReferenced(CurrentLocation, FieldCtor);
else {
- Diag(CurrentLocation, diag::err_defining_default_ctor)
- << Context.getTagDeclType(ClassDecl) << 0 <<
+ Diag(CurrentLocation, diag::err_defining_default_ctor)
+ << Context.getTagDeclType(ClassDecl) << 1 <<
Context.getTagDeclType(FieldClassDecl);
- Diag(FieldClassDecl->getLocation(), diag::note_previous_class_decl)
+ Diag((*Field)->getLocation(), diag::note_field_decl);
+ Diag(FieldClassDecl->getLocation(), diag::note_previous_class_decl)
<< Context.getTagDeclType(FieldClassDecl);
err = true;
}
}
- }
- else if (FieldType->isReferenceType()) {
- Diag(CurrentLocation, diag::err_unintialized_member)
- << Context.getTagDeclType(ClassDecl) << 0 << (*Field)->getNameAsCString();
+ } else if (FieldType->isReferenceType()) {
+ Diag(CurrentLocation, diag::err_unintialized_member)
+ << Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName();
Diag((*Field)->getLocation(), diag::note_declared_at);
err = true;
- }
- else if (FieldType.isConstQualified()) {
- Diag(CurrentLocation, diag::err_unintialized_member)
- << Context.getTagDeclType(ClassDecl) << 1 << (*Field)->getNameAsCString();
+ } else if (FieldType.isConstQualified()) {
+ Diag(CurrentLocation, diag::err_unintialized_member)
+ << Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName();
Diag((*Field)->getLocation(), diag::note_declared_at);
err = true;
}
@@ -2007,47 +2923,47 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
}
void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
- CXXDestructorDecl *Destructor) {
+ CXXDestructorDecl *Destructor) {
assert((Destructor->isImplicit() && !Destructor->isUsed()) &&
"DefineImplicitDestructor - call it for implicit default dtor");
-
+
CXXRecordDecl *ClassDecl
= cast<CXXRecordDecl>(Destructor->getDeclContext());
assert(ClassDecl && "DefineImplicitDestructor - invalid destructor");
// C++ [class.dtor] p5
- // Before the implicitly-declared default destructor for a class is
+ // Before the implicitly-declared default destructor for a class is
// implicitly defined, all the implicitly-declared default destructors
// for its base class and its non-static data members shall have been
// implicitly defined.
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
E = ClassDecl->bases_end(); Base != E; ++Base) {
CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAsRecordType()->getDecl());
+ = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
if (!BaseClassDecl->hasTrivialDestructor()) {
- if (CXXDestructorDecl *BaseDtor =
+ if (CXXDestructorDecl *BaseDtor =
const_cast<CXXDestructorDecl*>(BaseClassDecl->getDestructor(Context)))
MarkDeclarationReferenced(CurrentLocation, BaseDtor);
else
- assert(false &&
+ assert(false &&
"DefineImplicitDestructor - missing dtor in a base class");
}
}
-
+
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
E = ClassDecl->field_end(); Field != E; ++Field) {
QualType FieldType = Context.getCanonicalType((*Field)->getType());
if (const ArrayType *Array = Context.getAsArrayType(FieldType))
FieldType = Array->getElementType();
- if (const RecordType *FieldClassType = FieldType->getAsRecordType()) {
+ if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
CXXRecordDecl *FieldClassDecl
= cast<CXXRecordDecl>(FieldClassType->getDecl());
if (!FieldClassDecl->hasTrivialDestructor()) {
- if (CXXDestructorDecl *FieldDtor =
+ if (CXXDestructorDecl *FieldDtor =
const_cast<CXXDestructorDecl*>(
FieldClassDecl->getDestructor(Context)))
MarkDeclarationReferenced(CurrentLocation, FieldDtor);
else
- assert(false &&
+ assert(false &&
"DefineImplicitDestructor - missing dtor in class of a data member");
}
}
@@ -2061,10 +2977,10 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
MethodDecl->getOverloadedOperator() == OO_Equal &&
!MethodDecl->isUsed()) &&
"DefineImplicitOverloadedAssign - call it for implicit assignment op");
-
+
CXXRecordDecl *ClassDecl
= cast<CXXRecordDecl>(MethodDecl->getDeclContext());
-
+
// C++[class.copy] p12
// Before the implicitly-declared copy assignment operator for a class is
// implicitly defined, all implicitly-declared copy assignment operators
@@ -2074,8 +2990,8 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
E = ClassDecl->bases_end(); Base != E; ++Base) {
CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAsRecordType()->getDecl());
- if (CXXMethodDecl *BaseAssignOpMethod =
+ = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ if (CXXMethodDecl *BaseAssignOpMethod =
getAssignOperatorMethod(MethodDecl->getParamDecl(0), BaseClassDecl))
MarkDeclarationReferenced(CurrentLocation, BaseAssignOpMethod);
}
@@ -2084,30 +3000,28 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
QualType FieldType = Context.getCanonicalType((*Field)->getType());
if (const ArrayType *Array = Context.getAsArrayType(FieldType))
FieldType = Array->getElementType();
- if (const RecordType *FieldClassType = FieldType->getAsRecordType()) {
+ if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
CXXRecordDecl *FieldClassDecl
= cast<CXXRecordDecl>(FieldClassType->getDecl());
- if (CXXMethodDecl *FieldAssignOpMethod =
+ if (CXXMethodDecl *FieldAssignOpMethod =
getAssignOperatorMethod(MethodDecl->getParamDecl(0), FieldClassDecl))
MarkDeclarationReferenced(CurrentLocation, FieldAssignOpMethod);
- }
- else if (FieldType->isReferenceType()) {
- Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
- << Context.getTagDeclType(ClassDecl) << 0 << (*Field)->getNameAsCString();
- Diag((*Field)->getLocation(), diag::note_declared_at);
+ } else if (FieldType->isReferenceType()) {
+ Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
+ << Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName();
+ Diag(Field->getLocation(), diag::note_declared_at);
Diag(CurrentLocation, diag::note_first_required_here);
err = true;
- }
- else if (FieldType.isConstQualified()) {
- Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
- << Context.getTagDeclType(ClassDecl) << 1 << (*Field)->getNameAsCString();
- Diag((*Field)->getLocation(), diag::note_declared_at);
+ } else if (FieldType.isConstQualified()) {
+ Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
+ << Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName();
+ Diag(Field->getLocation(), diag::note_declared_at);
Diag(CurrentLocation, diag::note_first_required_here);
err = true;
}
}
if (!err)
- MethodDecl->setUsed();
+ MethodDecl->setUsed();
}
CXXMethodDecl *
@@ -2116,24 +3030,22 @@ Sema::getAssignOperatorMethod(ParmVarDecl *ParmDecl,
QualType LHSType = Context.getTypeDeclType(ClassDecl);
QualType RHSType(LHSType);
// If class's assignment operator argument is const/volatile qualified,
- // look for operator = (const/volatile B&). Otherwise, look for
+ // look for operator = (const/volatile B&). Otherwise, look for
// operator = (B&).
- if (ParmDecl->getType().isConstQualified())
- RHSType.addConst();
- if (ParmDecl->getType().isVolatileQualified())
- RHSType.addVolatile();
- ExprOwningPtr<Expr> LHS(this, new (Context) DeclRefExpr(ParmDecl,
- LHSType,
+ RHSType = Context.getCVRQualifiedType(RHSType,
+ ParmDecl->getType().getCVRQualifiers());
+ ExprOwningPtr<Expr> LHS(this, new (Context) DeclRefExpr(ParmDecl,
+ LHSType,
SourceLocation()));
- ExprOwningPtr<Expr> RHS(this, new (Context) DeclRefExpr(ParmDecl,
- RHSType,
+ ExprOwningPtr<Expr> RHS(this, new (Context) DeclRefExpr(ParmDecl,
+ RHSType,
SourceLocation()));
Expr *Args[2] = { &*LHS, &*RHS };
OverloadCandidateSet CandidateSet;
- AddMemberOperatorCandidates(clang::OO_Equal, SourceLocation(), Args, 2,
+ AddMemberOperatorCandidates(clang::OO_Equal, SourceLocation(), Args, 2,
CandidateSet);
OverloadCandidateSet::iterator Best;
- if (BestViableFunction(CandidateSet,
+ if (BestViableFunction(CandidateSet,
ClassDecl->getLocation(), Best) == OR_Success)
return cast<CXXMethodDecl>(Best->Function);
assert(false &&
@@ -2144,24 +3056,24 @@ Sema::getAssignOperatorMethod(ParmVarDecl *ParmDecl,
void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
CXXConstructorDecl *CopyConstructor,
unsigned TypeQuals) {
- assert((CopyConstructor->isImplicit() &&
+ assert((CopyConstructor->isImplicit() &&
CopyConstructor->isCopyConstructor(Context, TypeQuals) &&
!CopyConstructor->isUsed()) &&
"DefineImplicitCopyConstructor - call it for implicit copy ctor");
-
+
CXXRecordDecl *ClassDecl
= cast<CXXRecordDecl>(CopyConstructor->getDeclContext());
assert(ClassDecl && "DefineImplicitCopyConstructor - invalid constructor");
// C++ [class.copy] p209
- // Before the implicitly-declared copy constructor for a class is
+ // Before the implicitly-declared copy constructor for a class is
// implicitly defined, all the implicitly-declared copy constructors
// for its base class and its non-static data members shall have been
// implicitly defined.
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin();
Base != ClassDecl->bases_end(); ++Base) {
CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAsRecordType()->getDecl());
- if (CXXConstructorDecl *BaseCopyCtor =
+ = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ if (CXXConstructorDecl *BaseCopyCtor =
BaseClassDecl->getCopyConstructor(Context, TypeQuals))
MarkDeclarationReferenced(CurrentLocation, BaseCopyCtor);
}
@@ -2171,10 +3083,10 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
QualType FieldType = Context.getCanonicalType((*Field)->getType());
if (const ArrayType *Array = Context.getAsArrayType(FieldType))
FieldType = Array->getElementType();
- if (const RecordType *FieldClassType = FieldType->getAsRecordType()) {
+ if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
CXXRecordDecl *FieldClassDecl
= cast<CXXRecordDecl>(FieldClassType->getDecl());
- if (CXXConstructorDecl *FieldCopyCtor =
+ if (CXXConstructorDecl *FieldCopyCtor =
FieldClassDecl->getCopyConstructor(Context, TypeQuals))
MarkDeclarationReferenced(CurrentLocation, FieldCopyCtor);
}
@@ -2182,27 +3094,92 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
CopyConstructor->setUsed();
}
-void Sema::InitializeVarWithConstructor(VarDecl *VD,
+Sema::OwningExprResult
+Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
+ CXXConstructorDecl *Constructor,
+ MultiExprArg ExprArgs) {
+ bool Elidable = false;
+
+ // C++ [class.copy]p15:
+ // Whenever a temporary class object is copied using a copy constructor, and
+ // this object and the copy have the same cv-unqualified type, an
+ // implementation is permitted to treat the original and the copy as two
+ // different ways of referring to the same object and not perform a copy at
+ // all, even if the class copy constructor or destructor have side effects.
+
+ // FIXME: Is this enough?
+ if (Constructor->isCopyConstructor(Context)) {
+ Expr *E = ((Expr **)ExprArgs.get())[0];
+ while (CXXBindTemporaryExpr *BE = dyn_cast<CXXBindTemporaryExpr>(E))
+ E = BE->getSubExpr();
+ if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E))
+ if (ICE->getCastKind() == CastExpr::CK_NoOp)
+ E = ICE->getSubExpr();
+
+ if (isa<CallExpr>(E) || isa<CXXTemporaryObjectExpr>(E))
+ Elidable = true;
+ }
+
+ return BuildCXXConstructExpr(ConstructLoc, DeclInitType, Constructor,
+ Elidable, move(ExprArgs));
+}
+
+/// BuildCXXConstructExpr - Creates a complete call to a constructor,
+/// including handling of its default argument expressions.
+Sema::OwningExprResult
+Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
+ CXXConstructorDecl *Constructor, bool Elidable,
+ MultiExprArg ExprArgs) {
+ unsigned NumExprs = ExprArgs.size();
+ Expr **Exprs = (Expr **)ExprArgs.release();
+
+ return Owned(CXXConstructExpr::Create(Context, DeclInitType, Constructor,
+ Elidable, Exprs, NumExprs));
+}
+
+Sema::OwningExprResult
+Sema::BuildCXXTemporaryObjectExpr(CXXConstructorDecl *Constructor,
+ QualType Ty,
+ SourceLocation TyBeginLoc,
+ MultiExprArg Args,
+ SourceLocation RParenLoc) {
+ unsigned NumExprs = Args.size();
+ Expr **Exprs = (Expr **)Args.release();
+
+ return Owned(new (Context) CXXTemporaryObjectExpr(Context, Constructor, Ty,
+ TyBeginLoc, Exprs,
+ NumExprs, RParenLoc));
+}
+
+
+bool Sema::InitializeVarWithConstructor(VarDecl *VD,
CXXConstructorDecl *Constructor,
- QualType DeclInitType,
- Expr **Exprs, unsigned NumExprs) {
- Expr *Temp = CXXConstructExpr::Create(Context, DeclInitType, Constructor,
- false, Exprs, NumExprs);
+ QualType DeclInitType,
+ MultiExprArg Exprs) {
+ OwningExprResult TempResult =
+ BuildCXXConstructExpr(VD->getLocation(), DeclInitType, Constructor,
+ move(Exprs));
+ if (TempResult.isInvalid())
+ return true;
+
+ Expr *Temp = TempResult.takeAs<Expr>();
MarkDeclarationReferenced(VD->getLocation(), Constructor);
+ Temp = MaybeCreateCXXExprWithTemporaries(Temp, /*DestroyTemps=*/true);
VD->setInit(Context, Temp);
+
+ return false;
}
-void Sema::MarkDestructorReferenced(SourceLocation Loc, QualType DeclInitType)
-{
+void Sema::FinalizeVarWithDestructor(VarDecl *VD, QualType DeclInitType) {
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(
- DeclInitType->getAsRecordType()->getDecl());
+ DeclInitType->getAs<RecordType>()->getDecl());
if (!ClassDecl->hasTrivialDestructor())
- if (CXXDestructorDecl *Destructor =
+ if (CXXDestructorDecl *Destructor =
const_cast<CXXDestructorDecl*>(ClassDecl->getDestructor(Context)))
- MarkDeclarationReferenced(Loc, Destructor);
+ MarkDeclarationReferenced(VD->getLocation(), Destructor);
}
-/// AddCXXDirectInitializerToDecl - This action is called immediately after
+/// 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,
@@ -2218,7 +3195,7 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl,
// the initializer.
if (RealDecl == 0)
return;
-
+
VarDecl *VDecl = dyn_cast<VarDecl>(RealDecl);
if (!VDecl) {
Diag(RealDecl->getLocation(), diag::err_illegal_initializer);
@@ -2226,9 +3203,7 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl,
return;
}
- // FIXME: Need to handle dependent types and expressions here.
-
- // We will treat direct-initialization as a copy-initialization:
+ // We will represent direct-initialization similarly to copy-initialization:
// int x(1); -as-> int x = 1;
// ClassType x(a,b,c); -as-> ClassType x = ClassType(a,b,c);
//
@@ -2238,6 +3213,24 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl,
// exactly form was it (like the CodeGen) can handle both cases without
// special case code.
+ // If either the declaration has a dependent type or if any of the expressions
+ // is type-dependent, we represent the initialization via a ParenListExpr for
+ // later use during template instantiation.
+ if (VDecl->getType()->isDependentType() ||
+ Expr::hasAnyTypeDependentArguments((Expr **)Exprs.get(), Exprs.size())) {
+ // Let clients know that initialization was done with a direct initializer.
+ VDecl->setCXXDirectInitializer(true);
+
+ // Store the initialization expressions as a ParenListExpr.
+ unsigned NumExprs = Exprs.size();
+ VDecl->setInit(Context,
+ new (Context) ParenListExpr(Context, LParenLoc,
+ (Expr **)Exprs.release(),
+ NumExprs, RParenLoc));
+ return;
+ }
+
+
// C++ 8.5p11:
// The form of initialization (using parentheses or '=') is generally
// insignificant, but does matter when the entity being initialized has a
@@ -2254,23 +3247,25 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl,
}
if (VDecl->getType()->isRecordType()) {
+ ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
+
CXXConstructorDecl *Constructor
= PerformInitializationByConstructor(DeclInitType,
- (Expr **)Exprs.get(), NumExprs,
+ move(Exprs),
VDecl->getLocation(),
SourceRange(VDecl->getLocation(),
RParenLoc),
VDecl->getDeclName(),
- IK_Direct);
+ IK_Direct,
+ ConstructorArgs);
if (!Constructor)
RealDecl->setInvalidDecl();
else {
VDecl->setCXXDirectInitializer(true);
- InitializeVarWithConstructor(VDecl, Constructor, DeclInitType,
- (Expr**)Exprs.release(), NumExprs);
- // FIXME. Must do all that is needed to destroy the object
- // on scope exit. For now, just mark the destructor as used.
- MarkDestructorReferenced(VDecl->getLocation(), DeclInitType);
+ if (InitializeVarWithConstructor(VDecl, Constructor, DeclInitType,
+ move_arg(ConstructorArgs)))
+ RealDecl->setInvalidDecl();
+ FinalizeVarWithDestructor(VDecl, DeclInitType);
}
return;
}
@@ -2291,31 +3286,41 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl,
/*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.
+/// \brief Perform initialization by constructor (C++ [dcl.init]p14), which
+/// may occur as part of direct-initialization or copy-initialization.
+///
+/// \param ClassType the type of the object being initialized, which must have
+/// class type.
+///
+/// \param ArgsPtr the arguments provided to initialize the object
+///
+/// \param Loc the source location where the initialization occurs
+///
+/// \param Range the source range that covers the entire initialization
+///
+/// \param InitEntity the name of the entity being initialized, if known
+///
+/// \param Kind the type of initialization being performed
+///
+/// \param ConvertedArgs a vector that will be filled in with the
+/// appropriately-converted arguments to the constructor (if initialization
+/// succeeded).
+///
+/// \returns the constructor used to initialize the object, if successful.
+/// Otherwise, emits a diagnostic and returns NULL.
CXXConstructorDecl *
Sema::PerformInitializationByConstructor(QualType ClassType,
- Expr **Args, unsigned NumArgs,
+ MultiExprArg ArgsPtr,
SourceLocation Loc, SourceRange Range,
DeclarationName InitEntity,
- InitializationKind Kind) {
- const RecordType *ClassRec = ClassType->getAsRecordType();
+ InitializationKind Kind,
+ ASTOwningVector<&ActionBase::DeleteExpr> &ConvertedArgs) {
+ const RecordType *ClassRec = ClassType->getAs<RecordType>();
assert(ClassRec && "Can only initialize a class type here");
-
- // C++ [dcl.init]p14:
- //
+ Expr **Args = (Expr **)ArgsPtr.get();
+ unsigned NumArgs = ArgsPtr.size();
+
+ // 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
@@ -2330,17 +3335,31 @@ Sema::PerformInitializationByConstructor(QualType ClassType,
OverloadCandidateSet CandidateSet;
// Add constructors to the overload set.
- DeclarationName ConstructorName
+ DeclarationName ConstructorName
= Context.DeclarationNames.getCXXConstructorName(
Context.getCanonicalType(ClassType.getUnqualifiedType()));
DeclContext::lookup_const_iterator Con, ConEnd;
for (llvm::tie(Con, ConEnd) = ClassDecl->lookup(ConstructorName);
Con != ConEnd; ++Con) {
- CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con);
+ // Find the constructor (which may be a template).
+ CXXConstructorDecl *Constructor = 0;
+ FunctionTemplateDecl *ConstructorTmpl= dyn_cast<FunctionTemplateDecl>(*Con);
+ if (ConstructorTmpl)
+ Constructor
+ = cast<CXXConstructorDecl>(ConstructorTmpl->getTemplatedDecl());
+ else
+ Constructor = cast<CXXConstructorDecl>(*Con);
+
if ((Kind == IK_Direct) ||
- (Kind == IK_Copy && Constructor->isConvertingConstructor()) ||
- (Kind == IK_Default && Constructor->isDefaultConstructor()))
- AddOverloadCandidate(Constructor, Args, NumArgs, CandidateSet);
+ (Kind == IK_Copy &&
+ Constructor->isConvertingConstructor(/*AllowExplicit=*/false)) ||
+ (Kind == IK_Default && Constructor->isDefaultConstructor())) {
+ if (ConstructorTmpl)
+ AddTemplateOverloadCandidate(ConstructorTmpl, false, 0, 0,
+ Args, NumArgs, CandidateSet);
+ else
+ AddOverloadCandidate(Constructor, Args, NumArgs, CandidateSet);
+ }
}
// FIXME: When we decide not to synthesize the implicitly-declared
@@ -2349,9 +3368,10 @@ Sema::PerformInitializationByConstructor(QualType ClassType,
OverloadCandidateSet::iterator Best;
switch (BestViableFunction(CandidateSet, Loc, Best)) {
case OR_Success:
- // We found a constructor. Return it.
- return cast<CXXConstructorDecl>(Best->Function);
-
+ // We found a constructor. Break out so that we can convert the arguments
+ // appropriately.
+ break;
+
case OR_No_Viable_Function:
if (InitEntity)
Diag(Loc, diag::err_ovl_no_viable_function_in_init)
@@ -2361,7 +3381,7 @@ Sema::PerformInitializationByConstructor(QualType ClassType,
<< ClassType << Range;
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
return 0;
-
+
case OR_Ambiguous:
if (InitEntity)
Diag(Loc, diag::err_ovl_ambiguous_init) << InitEntity << Range;
@@ -2382,8 +3402,85 @@ Sema::PerformInitializationByConstructor(QualType ClassType,
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
return 0;
}
+
+ // Convert the arguments, fill in default arguments, etc.
+ CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Best->Function);
+ if (CompleteConstructorCall(Constructor, move(ArgsPtr), Loc, ConvertedArgs))
+ return 0;
- return 0;
+ return Constructor;
+}
+
+/// \brief Given a constructor and the set of arguments provided for the
+/// constructor, convert the arguments and add any required default arguments
+/// to form a proper call to this constructor.
+///
+/// \returns true if an error occurred, false otherwise.
+bool
+Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
+ MultiExprArg ArgsPtr,
+ SourceLocation Loc,
+ ASTOwningVector<&ActionBase::DeleteExpr> &ConvertedArgs) {
+ // FIXME: This duplicates a lot of code from Sema::ConvertArgumentsForCall.
+ unsigned NumArgs = ArgsPtr.size();
+ Expr **Args = (Expr **)ArgsPtr.get();
+
+ const FunctionProtoType *Proto
+ = Constructor->getType()->getAs<FunctionProtoType>();
+ assert(Proto && "Constructor without a prototype?");
+ unsigned NumArgsInProto = Proto->getNumArgs();
+ unsigned NumArgsToCheck = NumArgs;
+
+ // If too few arguments are available, we'll fill in the rest with defaults.
+ if (NumArgs < NumArgsInProto) {
+ NumArgsToCheck = NumArgsInProto;
+ ConvertedArgs.reserve(NumArgsInProto);
+ } else {
+ ConvertedArgs.reserve(NumArgs);
+ if (NumArgs > NumArgsInProto)
+ NumArgsToCheck = NumArgsInProto;
+ }
+
+ // Convert arguments
+ for (unsigned i = 0; i != NumArgsToCheck; i++) {
+ QualType ProtoArgType = Proto->getArgType(i);
+
+ Expr *Arg;
+ if (i < NumArgs) {
+ Arg = Args[i];
+
+ // Pass the argument.
+ if (PerformCopyInitialization(Arg, ProtoArgType, "passing"))
+ return true;
+
+ Args[i] = 0;
+ } else {
+ ParmVarDecl *Param = Constructor->getParamDecl(i);
+
+ OwningExprResult DefArg = BuildCXXDefaultArgExpr(Loc, Constructor, Param);
+ if (DefArg.isInvalid())
+ return true;
+
+ Arg = DefArg.takeAs<Expr>();
+ }
+
+ ConvertedArgs.push_back(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];
+ if (DefaultVariadicArgumentPromotion(Arg, VariadicConstructor))
+ return true;
+
+ ConvertedArgs.push_back(Arg);
+ Args[i] = 0;
+ }
+ }
+
+ return false;
}
/// CompareReferenceRelationship - Compare the two types T1 and T2 to
@@ -2393,8 +3490,8 @@ Sema::PerformInitializationByConstructor(QualType ClassType,
/// 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,
+Sema::ReferenceCompareResult
+Sema::CompareReferenceRelationship(QualType T1, QualType T2,
bool& DerivedToBase) {
assert(!T1->isReferenceType() &&
"T1 must be the pointee type of the reference type");
@@ -2406,8 +3503,8 @@ Sema::CompareReferenceRelationship(QualType T1, QualType T2,
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
+ // 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;
@@ -2420,7 +3517,7 @@ Sema::CompareReferenceRelationship(QualType T1, QualType T2,
// least).
// C++ [dcl.init.ref]p4:
- // "cv1 T1” is reference-compatible with “cv2 T2” if T1 is
+ // "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
@@ -2450,27 +3547,28 @@ Sema::CompareReferenceRelationship(QualType T1, QualType T2,
/// When @p AllowExplicit, we also permit explicit user-defined
/// conversion functions.
/// When @p ForceRValue, we unconditionally treat the initializer as an rvalue.
-bool
+bool
Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
- ImplicitConversionSequence *ICS,
+ SourceLocation DeclLoc,
bool SuppressUserConversions,
- bool AllowExplicit, bool ForceRValue) {
+ bool AllowExplicit, bool ForceRValue,
+ ImplicitConversionSequence *ICS) {
assert(DeclType->isReferenceType() && "Reference init needs a reference");
- QualType T1 = DeclType->getAsReferenceType()->getPointeeType();
+ QualType T1 = DeclType->getAs<ReferenceType>()->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,
+ 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()))
+ if (DiagnoseUseOfDecl(Fn, DeclLoc))
return true;
FixOverloadedFunctionReference(Init, Fn);
@@ -2485,7 +3583,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
bool DerivedToBase = false;
Expr::isLvalueResult InitLvalue = ForceRValue ? Expr::LV_InvalidExpression :
Init->isLvalue(Context);
- ReferenceCompareResult RefRelationship
+ ReferenceCompareResult RefRelationship
= CompareReferenceRelationship(T1, T2, DerivedToBase);
// Most paths end in a failed conversion.
@@ -2493,8 +3591,8 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
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:
+ // A reference to type "cv1 T1" is initialized by an expression
+ // of type "cv2 T2" as follows:
// -- If the initializer expression
@@ -2505,14 +3603,14 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
// A&& r = b;
if (isRValRef && InitLvalue == Expr::LV_Valid) {
if (!ICS)
- Diag(Init->getSourceRange().getBegin(), diag::err_lvalue_to_rvalue_ref)
+ Diag(DeclLoc, 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
+ // -- 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).
@@ -2546,40 +3644,54 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
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);
+ CastExpr::CastKind CK = CastExpr::CK_NoOp;
+ if (DerivedToBase)
+ CK = CastExpr::CK_DerivedToBase;
+ else if(CheckExceptionSpecCompatibility(Init, T1))
+ return true;
+ ImpCastExprToType(Init, T1, CK, /*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”
+ // 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());
+ if (!isRValRef && !SuppressUserConversions && T2->isRecordType() &&
+ !RequireCompleteType(SourceLocation(), T2, 0)) {
+ CXXRecordDecl *T2RecordDecl
+ = dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl());
OverloadCandidateSet CandidateSet;
- OverloadedFunctionDecl *Conversions
- = T2RecordDecl->getConversionFunctions();
- for (OverloadedFunctionDecl::function_iterator Func
+ OverloadedFunctionDecl *Conversions
+ = T2RecordDecl->getVisibleConversionFunctions();
+ for (OverloadedFunctionDecl::function_iterator Func
= Conversions->function_begin();
Func != Conversions->function_end(); ++Func) {
- CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func);
-
+ FunctionTemplateDecl *ConvTemplate
+ = dyn_cast<FunctionTemplateDecl>(*Func);
+ CXXConversionDecl *Conv;
+ if (ConvTemplate)
+ Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
+ else
+ 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);
+ (AllowExplicit || !Conv->isExplicit())) {
+ if (ConvTemplate)
+ AddTemplateConversionCandidate(ConvTemplate, Init, DeclType,
+ CandidateSet);
+ else
+ AddConversionCandidate(Conv, Init, DeclType, CandidateSet);
+ }
}
OverloadCandidateSet::iterator Best;
- switch (BestViableFunction(CandidateSet, Init->getLocStart(), Best)) {
+ switch (BestViableFunction(CandidateSet, DeclLoc, Best)) {
case OR_Success:
// This is a direct binding.
BindsDirectly = true;
@@ -2604,17 +3716,33 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
"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);
+ OwningExprResult InitConversion =
+ BuildCXXCastArgument(DeclLoc, QualType(),
+ CastExpr::CK_UserDefinedConversion,
+ cast<CXXMethodDecl>(Best->Function),
+ Owned(Init));
+ Init = InitConversion.takeAs<Expr>();
+
+ if (CheckExceptionSpecCompatibility(Init, T1))
+ return true;
+ ImpCastExprToType(Init, T1, CastExpr::CK_UserDefinedConversion,
+ /*isLvalue=*/true);
}
break;
case OR_Ambiguous:
- assert(false && "Ambiguous reference binding conversions not implemented.");
+ if (ICS) {
+ for (OverloadCandidateSet::iterator Cand = CandidateSet.begin();
+ Cand != CandidateSet.end(); ++Cand)
+ if (Cand->Viable)
+ ICS->ConversionFunctionSet.push_back(Cand->Function);
+ break;
+ }
+ Diag(DeclLoc, diag::err_ref_init_ambiguous) << DeclType << Init->getType()
+ << Init->getSourceRange();
+ PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
return true;
-
+
case OR_No_Viable_Function:
case OR_Deleted:
// There was no suitable conversion, or we found a deleted
@@ -2622,7 +3750,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
break;
}
}
-
+
if (BindsDirectly) {
// C++ [dcl.init.ref]p4:
// [...] In all cases where the reference-related or
@@ -2636,9 +3764,8 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
// 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(),
+ if (DerivedToBase)
+ return CheckDerivedToBaseConversion(T2, T1, DeclLoc,
Init->getSourceRange());
else
return false;
@@ -2647,25 +3774,24 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
// -- 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 (!isRValRef && T1.getCVRQualifiers() != Qualifiers::Const) {
if (!ICS)
- Diag(Init->getSourceRange().getBegin(),
- diag::err_not_reference_to_const_init)
+ Diag(DeclLoc, 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
+ // 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 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
@@ -2693,14 +3819,17 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
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);
+ CastExpr::CastKind CK = CastExpr::CK_NoOp;
+ if (DerivedToBase)
+ CK = CastExpr::CK_DerivedToBase;
+ else if(CheckExceptionSpecCompatibility(Init, T1))
+ return true;
+ ImpCastExprToType(Init, T1, CK, /*isLvalue=*/false);
}
return false;
}
- // -- Otherwise, a temporary of type “cv1 T1” is created and
+ // -- 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
@@ -2713,8 +3842,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
// 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)
+ Diag(DeclLoc, diag::err_reference_init_drops_quals)
<< T1 << (InitLvalue != Expr::LV_Valid? "temporary" : "value")
<< T2 << Init->getSourceRange();
return true;
@@ -2728,8 +3856,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
if (SuppressUserConversions && RefRelationship == Ref_Incompatible &&
(T1->isRecordType() || T2->isRecordType())) {
if (!ICS)
- Diag(Init->getSourceRange().getBegin(),
- diag::err_typecheck_convert_incompatible)
+ Diag(DeclLoc, diag::err_typecheck_convert_incompatible)
<< DeclType << Init->getType() << "initializing" << Init->getSourceRange();
return true;
}
@@ -2737,7 +3864,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
// 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
@@ -2747,19 +3874,48 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
// 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);
+ *ICS = TryImplicitConversion(Init, T1, SuppressUserConversions,
+ /*AllowExplicit=*/false,
+ /*ForceRValue=*/false,
+ /*InOverloadResolution=*/false);
+
// 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 ==
+ } 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");
+ ImplicitConversionSequence Conversions;
+ bool badConversion = PerformImplicitConversion(Init, T1, "initializing",
+ false, false,
+ Conversions);
+ if (badConversion) {
+ if ((Conversions.ConversionKind ==
+ ImplicitConversionSequence::BadConversion)
+ && !Conversions.ConversionFunctionSet.empty()) {
+ Diag(DeclLoc,
+ diag::err_lvalue_to_rvalue_ambig_ref) << Init->getSourceRange();
+ for (int j = Conversions.ConversionFunctionSet.size()-1;
+ j >= 0; j--) {
+ FunctionDecl *Func = Conversions.ConversionFunctionSet[j];
+ Diag(Func->getLocation(), diag::err_ovl_candidate);
+ }
+ }
+ else {
+ if (isRValRef)
+ Diag(DeclLoc, diag::err_lvalue_to_rvalue_ref)
+ << Init->getSourceRange();
+ else
+ Diag(DeclLoc, diag::err_invalid_initialization)
+ << DeclType << Init->getType() << Init->getSourceRange();
+ }
+ }
+ return badConversion;
}
}
@@ -2772,7 +3928,7 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
OverloadedOperatorKind Op = FnDecl->getOverloadedOperator();
- // C++ [over.oper]p5:
+ // 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
@@ -2815,13 +3971,13 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
// An operator function cannot have default arguments (8.3.6),
// except where explicitly stated below.
//
- // Only the function-call operator allows default arguments
+ // 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(),
+ return Diag((*Param)->getLocation(),
diag::err_operator_overload_default_arg)
<< FnDecl->getDeclName();
else if (Expr *DefArg = (*Param)->getDefaultArg())
@@ -2846,7 +4002,7 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
// [...] 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()
+ unsigned NumParams = FnDecl->getNumParams()
+ (isa<CXXMethodDecl>(FnDecl)? 1 : 0);
if (Op != OO_Call &&
((NumParams == 1 && !CanBeUnaryOperator) ||
@@ -2870,7 +4026,7 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
// Overloaded operators other than operator() cannot be variadic.
if (Op != OO_Call &&
- FnDecl->getType()->getAsFunctionProtoType()->isVariadic()) {
+ FnDecl->getType()->getAs<FunctionProtoType>()->isVariadic()) {
return Diag(FnDecl->getLocation(), diag::err_operator_overload_variadic)
<< FnDecl->getDeclName();
}
@@ -2895,12 +4051,12 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
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())
+ if (const BuiltinType *BT = LastParam->getType()->getAs<BuiltinType>())
ParamIsInt = BT->getKind() == BuiltinType::Int;
if (!ParamIsInt)
return Diag(LastParam->getLocation(),
- diag::err_operator_overload_post_incdec_must_be_int)
+ diag::err_operator_overload_post_incdec_must_be_int)
<< LastParam->getType() << (Op == OO_MinusMinus);
}
@@ -2910,6 +4066,7 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
assert(isa<CXXMethodDecl>(FnDecl) &&
"Overloaded = not member, but not filtered.");
CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl);
+ Method->setCopyAssignment(true);
Method->getParent()->addedAssignmentOperator(Context, Method);
}
@@ -2938,11 +4095,11 @@ Sema::DeclPtrTy Sema::ActOnStartLinkageSpecification(Scope *S,
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,
+ LangLoc, Language,
LBraceLoc.isValid());
CurContext->addDecl(D);
PushDeclContext(S, D);
@@ -2965,6 +4122,7 @@ Sema::DeclPtrTy Sema::ActOnFinishLinkageSpecification(Scope *S,
/// occurs within a C++ catch clause, returning the newly-created
/// variable.
VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType,
+ DeclaratorInfo *DInfo,
IdentifierInfo *Name,
SourceLocation Loc,
SourceRange Range) {
@@ -2980,7 +4138,7 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType,
// 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()) {
+ if (!ExDeclType->isDependentType() && ExDeclType->isRValueReferenceType()) {
Diag(Loc, diag::err_catch_rvalue_ref) << Range;
Invalid = true;
}
@@ -2988,11 +4146,11 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType,
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()) {
+ if (const PointerType *Ptr = BaseType->getAs<PointerType>()) {
BaseType = Ptr->getPointeeType();
Mode = 1;
DK = diag::err_catch_incomplete_ptr;
- } else if(const ReferenceType *Ref = BaseType->getAsReferenceType()) {
+ } else if (const ReferenceType *Ref = BaseType->getAs<ReferenceType>()) {
// For the purpose of error recovery, we treat rvalue refs like lvalue refs.
BaseType = Ref->getPointeeType();
Mode = 2;
@@ -3002,7 +4160,7 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType,
!BaseType->isDependentType() && RequireCompleteType(Loc, BaseType, DK))
Invalid = true;
- if (!Invalid && !ExDeclType->isDependentType() &&
+ if (!Invalid && !ExDeclType->isDependentType() &&
RequireNonAbstractType(Loc, ExDeclType,
diag::err_abstract_type_in_decl,
AbstractVariableType))
@@ -3013,9 +4171,8 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType,
// FIXME: Need to check for abstract classes.
- VarDecl *ExDecl = VarDecl::Create(Context, CurContext, Loc,
- Name, ExDeclType, VarDecl::None,
- Range.getBegin());
+ VarDecl *ExDecl = VarDecl::Create(Context, CurContext, Loc,
+ Name, ExDeclType, DInfo, VarDecl::None);
if (Invalid)
ExDecl->setInvalidDecl();
@@ -3026,11 +4183,12 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType,
/// ActOnExceptionDeclarator - Parsed the exception-declarator in a C++ catch
/// handler.
Sema::DeclPtrTy Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) {
- QualType ExDeclType = GetTypeForDeclarator(D, S);
+ DeclaratorInfo *DInfo = 0;
+ QualType ExDeclType = GetTypeForDeclarator(D, S, &DInfo);
bool Invalid = D.isInvalidType();
IdentifierInfo *II = D.getIdentifier();
- if (NamedDecl *PrevDecl = LookupName(S, II, LookupOrdinaryName)) {
+ if (NamedDecl *PrevDecl = LookupSingleName(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)));
@@ -3046,14 +4204,14 @@ Sema::DeclPtrTy Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) {
Invalid = true;
}
- VarDecl *ExDecl = BuildExceptionDeclaration(S, ExDeclType,
+ VarDecl *ExDecl = BuildExceptionDeclaration(S, ExDeclType, DInfo,
D.getIdentifier(),
D.getIdentifierLoc(),
D.getDeclSpec().getSourceRange());
if (Invalid)
ExDecl->setInvalidDecl();
-
+
// Add the exception declaration into this scope.
if (II)
PushOnScopeChains(ExDecl, S);
@@ -3064,11 +4222,11 @@ Sema::DeclPtrTy Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) {
return DeclPtrTy::make(ExDecl);
}
-Sema::DeclPtrTy Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc,
+Sema::DeclPtrTy Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc,
ExprArg assertexpr,
ExprArg assertmessageexpr) {
Expr *AssertExpr = (Expr *)assertexpr.get();
- StringLiteral *AssertMessage =
+ StringLiteral *AssertMessage =
cast<StringLiteral>((Expr *)assertmessageexpr.get());
if (!AssertExpr->isTypeDependent() && !AssertExpr->isValueDependent()) {
@@ -3080,32 +4238,305 @@ Sema::DeclPtrTy Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc,
}
if (Value == 0) {
- std::string str(AssertMessage->getStrData(),
+ std::string str(AssertMessage->getStrData(),
AssertMessage->getByteLength());
- Diag(AssertLoc, diag::err_static_assert_failed)
+ Diag(AssertLoc, diag::err_static_assert_failed)
<< str << AssertExpr->getSourceRange();
}
}
-
+
assertexpr.release();
assertmessageexpr.release();
- Decl *Decl = StaticAssertDecl::Create(Context, CurContext, AssertLoc,
+ Decl *Decl = StaticAssertDecl::Create(Context, CurContext, AssertLoc,
AssertExpr, AssertMessage);
-
+
CurContext->addDecl(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;
+/// Handle a friend type declaration. This works in tandem with
+/// ActOnTag.
+///
+/// Notes on friend class templates:
+///
+/// We generally treat friend class declarations as if they were
+/// declaring a class. So, for example, the elaborated type specifier
+/// in a friend declaration is required to obey the restrictions of a
+/// class-head (i.e. no typedefs in the scope chain), template
+/// parameters are required to match up with simple template-ids, &c.
+/// However, unlike when declaring a template specialization, it's
+/// okay to refer to a template specialization without an empty
+/// template parameter declaration, e.g.
+/// friend class A<T>::B<unsigned>;
+/// We permit this as a special case; if there are any template
+/// parameters present at all, require proper matching, i.e.
+/// template <> template <class T> friend class A<int>::B;
+Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S,
+ const DeclSpec &DS,
+ MultiTemplateParamsArg TempParams) {
+ SourceLocation Loc = DS.getSourceRange().getBegin();
+
+ assert(DS.isFriendSpecified());
+ assert(DS.getStorageClassSpec() == DeclSpec::SCS_unspecified);
+
+ // Try to convert the decl specifier to a type. This works for
+ // friend templates because ActOnTag never produces a ClassTemplateDecl
+ // for a TUK_Friend.
+ bool invalid = false;
+ QualType SourceTy;
+ QualType T = ConvertDeclSpecToType(DS, Loc, invalid, SourceTy);
+ if (invalid) return DeclPtrTy();
+
+ // This is definitely an error in C++98. It's probably meant to
+ // be forbidden in C++0x, too, but the specification is just
+ // poorly written.
+ //
+ // The problem is with declarations like the following:
+ // template <T> friend A<T>::foo;
+ // where deciding whether a class C is a friend or not now hinges
+ // on whether there exists an instantiation of A that causes
+ // 'foo' to equal C. There are restrictions on class-heads
+ // (which we declare (by fiat) elaborated friend declarations to
+ // be) that makes this tractable.
+ //
+ // FIXME: handle "template <> friend class A<T>;", which
+ // is possibly well-formed? Who even knows?
+ if (TempParams.size() && !isa<ElaboratedType>(T)) {
+ Diag(Loc, diag::err_tagless_friend_type_template)
+ << DS.getSourceRange();
+ return DeclPtrTy();
}
-
- return false;
+
+ // C++ [class.friend]p2:
+ // An elaborated-type-specifier shall be used in a friend declaration
+ // for a class.*
+ // * The class-key of the elaborated-type-specifier is required.
+ // This is one of the rare places in Clang where it's legitimate to
+ // ask about the "spelling" of the type.
+ if (!getLangOptions().CPlusPlus0x && !isa<ElaboratedType>(T)) {
+ // If we evaluated the type to a record type, suggest putting
+ // a tag in front.
+ if (const RecordType *RT = T->getAs<RecordType>()) {
+ RecordDecl *RD = RT->getDecl();
+
+ std::string InsertionText = std::string(" ") + RD->getKindName();
+
+ Diag(DS.getTypeSpecTypeLoc(), diag::err_unelaborated_friend_type)
+ << (unsigned) RD->getTagKind()
+ << T
+ << SourceRange(DS.getFriendSpecLoc())
+ << CodeModificationHint::CreateInsertion(DS.getTypeSpecTypeLoc(),
+ InsertionText);
+ return DeclPtrTy();
+ }else {
+ Diag(DS.getFriendSpecLoc(), diag::err_unexpected_friend)
+ << DS.getSourceRange();
+ return DeclPtrTy();
+ }
+ }
+
+ // Enum types cannot be friends.
+ if (T->getAs<EnumType>()) {
+ Diag(DS.getTypeSpecTypeLoc(), diag::err_enum_friend)
+ << SourceRange(DS.getFriendSpecLoc());
+ return DeclPtrTy();
+ }
+
+ // C++98 [class.friend]p1: A friend of a class is a function
+ // or class that is not a member of the class . . .
+ // But that's a silly restriction which nobody implements for
+ // inner classes, and C++0x removes it anyway, so we only report
+ // this (as a warning) if we're being pedantic.
+ if (!getLangOptions().CPlusPlus0x)
+ if (const RecordType *RT = T->getAs<RecordType>())
+ if (RT->getDecl()->getDeclContext() == CurContext)
+ Diag(DS.getFriendSpecLoc(), diag::ext_friend_inner_class);
+
+ Decl *D;
+ if (TempParams.size())
+ D = FriendTemplateDecl::Create(Context, CurContext, Loc,
+ TempParams.size(),
+ (TemplateParameterList**) TempParams.release(),
+ T.getTypePtr(),
+ DS.getFriendSpecLoc());
+ else
+ D = FriendDecl::Create(Context, CurContext, Loc, T.getTypePtr(),
+ DS.getFriendSpecLoc());
+ D->setAccess(AS_public);
+ CurContext->addDecl(D);
+
+ return DeclPtrTy::make(D);
+}
+
+Sema::DeclPtrTy
+Sema::ActOnFriendFunctionDecl(Scope *S,
+ Declarator &D,
+ bool IsDefinition,
+ MultiTemplateParamsArg TemplateParams) {
+ const DeclSpec &DS = D.getDeclSpec();
+
+ assert(DS.isFriendSpecified());
+ assert(DS.getStorageClassSpec() == DeclSpec::SCS_unspecified);
+
+ SourceLocation Loc = D.getIdentifierLoc();
+ DeclaratorInfo *DInfo = 0;
+ QualType T = GetTypeForDeclarator(D, S, &DInfo);
+
+ // C++ [class.friend]p1
+ // A friend of a class is a function or class....
+ // Note that this sees through typedefs, which is intended.
+ // It *doesn't* see through dependent types, which is correct
+ // according to [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 a function type, the program
+ // is ill-formed.
+ if (!T->isFunctionType()) {
+ Diag(Loc, diag::err_unexpected_friend);
+
+ // It might be worthwhile to try to recover by creating an
+ // appropriate declaration.
+ return DeclPtrTy();
+ }
+
+ // C++ [namespace.memdef]p3
+ // - If a friend declaration in a non-local class first declares a
+ // class or function, the friend class or function is a member
+ // of the innermost enclosing namespace.
+ // - The name of the friend is not found by simple name lookup
+ // until a matching declaration is provided in that namespace
+ // scope (either before or after the class declaration granting
+ // friendship).
+ // - If a friend function is called, its name may be found by the
+ // name lookup that considers functions from namespaces and
+ // classes associated with the types of the function arguments.
+ // - When looking for a prior declaration of a class or a function
+ // declared as a friend, scopes outside the innermost enclosing
+ // namespace scope are not considered.
+
+ CXXScopeSpec &ScopeQual = D.getCXXScopeSpec();
+ DeclarationName Name = GetNameForDeclarator(D);
+ assert(Name);
+
+ // The context we found the declaration in, or in which we should
+ // create the declaration.
+ DeclContext *DC;
+
+ // FIXME: handle local classes
+
+ // Recover from invalid scope qualifiers as if they just weren't there.
+ NamedDecl *PrevDecl = 0;
+ if (!ScopeQual.isInvalid() && ScopeQual.isSet()) {
+ // FIXME: RequireCompleteDeclContext
+ DC = computeDeclContext(ScopeQual);
+
+ // FIXME: handle dependent contexts
+ if (!DC) return DeclPtrTy();
+
+ LookupResult R;
+ LookupQualifiedName(R, DC, Name, LookupOrdinaryName, true);
+ PrevDecl = R.getAsSingleDecl(Context);
+
+ // If searching in that context implicitly found a declaration in
+ // a different context, treat it like it wasn't found at all.
+ // TODO: better diagnostics for this case. Suggesting the right
+ // qualified scope would be nice...
+ if (!PrevDecl || !PrevDecl->getDeclContext()->Equals(DC)) {
+ D.setInvalidType();
+ Diag(Loc, diag::err_qualified_friend_not_found) << Name << T;
+ return DeclPtrTy();
+ }
+
+ // C++ [class.friend]p1: A friend of a class is a function or
+ // class that is not a member of the class . . .
+ if (DC->Equals(CurContext))
+ Diag(DS.getFriendSpecLoc(), diag::err_friend_is_member);
+
+ // Otherwise walk out to the nearest namespace scope looking for matches.
+ } else {
+ // TODO: handle local class contexts.
+
+ DC = CurContext;
+ while (true) {
+ // Skip class contexts. If someone can cite chapter and verse
+ // for this behavior, that would be nice --- it's what GCC and
+ // EDG do, and it seems like a reasonable intent, but the spec
+ // really only says that checks for unqualified existing
+ // declarations should stop at the nearest enclosing namespace,
+ // not that they should only consider the nearest enclosing
+ // namespace.
+ while (DC->isRecord())
+ DC = DC->getParent();
+
+ LookupResult R;
+ LookupQualifiedName(R, DC, Name, LookupOrdinaryName, true);
+ PrevDecl = R.getAsSingleDecl(Context);
+
+ // TODO: decide what we think about using declarations.
+ if (PrevDecl)
+ break;
+
+ if (DC->isFileContext()) break;
+ DC = DC->getParent();
+ }
+
+ // C++ [class.friend]p1: A friend of a class is a function or
+ // class that is not a member of the class . . .
+ // C++0x changes this for both friend types and functions.
+ // Most C++ 98 compilers do seem to give an error here, so
+ // we do, too.
+ if (PrevDecl && DC->Equals(CurContext) && !getLangOptions().CPlusPlus0x)
+ Diag(DS.getFriendSpecLoc(), diag::err_friend_is_member);
+ }
+
+ if (DC->isFileContext()) {
+ // This implies that it has to be an operator or function.
+ if (D.getKind() == Declarator::DK_Constructor ||
+ D.getKind() == Declarator::DK_Destructor ||
+ D.getKind() == Declarator::DK_Conversion) {
+ Diag(Loc, diag::err_introducing_special_friend) <<
+ (D.getKind() == Declarator::DK_Constructor ? 0 :
+ D.getKind() == Declarator::DK_Destructor ? 1 : 2);
+ return DeclPtrTy();
+ }
+ }
+
+ bool Redeclaration = false;
+ NamedDecl *ND = ActOnFunctionDeclarator(S, D, DC, T, DInfo, PrevDecl,
+ move(TemplateParams),
+ IsDefinition,
+ Redeclaration);
+ if (!ND) return DeclPtrTy();
+
+ assert(ND->getDeclContext() == DC);
+ assert(ND->getLexicalDeclContext() == CurContext);
+
+ // Add the function declaration to the appropriate lookup tables,
+ // adjusting the redeclarations list as necessary. We don't
+ // want to do this yet if the friending class is dependent.
+ //
+ // Also update the scope-based lookup if the target context's
+ // lookup context is in lexical scope.
+ if (!CurContext->isDependentContext()) {
+ DC = DC->getLookupContext();
+ DC->makeDeclVisibleInContext(ND, /* Recoverable=*/ false);
+ if (Scope *EnclosingScope = getScopeForDeclContext(S, DC))
+ PushOnScopeChains(ND, EnclosingScope, /*AddToContext=*/ false);
+ }
+
+ FriendDecl *FrD = FriendDecl::Create(Context, CurContext,
+ D.getIdentifierLoc(), ND,
+ DS.getFriendSpecLoc());
+ FrD->setAccess(AS_public);
+ CurContext->addDecl(FrD);
+
+ return DeclPtrTy::make(ND);
}
void Sema::SetDeclDeleted(DeclPtrTy dcl, SourceLocation DelLoc) {
+ AdjustDeclIfTemplate(dcl);
+
Decl *Dcl = dcl.getAs<Decl>();
FunctionDecl *Fn = dyn_cast<FunctionDecl>(Dcl);
if (!Fn) {
@@ -3142,21 +4573,21 @@ void Sema::DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock) {
}
}
-bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
+bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
const CXXMethodDecl *Old) {
- QualType NewTy = New->getType()->getAsFunctionType()->getResultType();
- QualType OldTy = Old->getType()->getAsFunctionType()->getResultType();
+ QualType NewTy = New->getType()->getAs<FunctionType>()->getResultType();
+ QualType OldTy = Old->getType()->getAs<FunctionType>()->getResultType();
QualType CNewTy = Context.getCanonicalType(NewTy);
QualType COldTy = Context.getCanonicalType(OldTy);
- if (CNewTy == COldTy &&
+ 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)) {
@@ -3169,14 +4600,14 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
OldClassTy = OldRT->getPointeeType();
}
}
-
+
// The return types aren't either both pointers or references to a class type.
if (NewClassTy.isNull()) {
- Diag(New->getLocation(),
+ 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;
}
@@ -3189,9 +4620,9 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
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,
+ 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?
@@ -3200,7 +4631,7 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
return true;
}
}
-
+
// The qualifiers of the return types must be the same.
if (CNewTy.getCVRQualifiers() != COldTy.getCVRQualifiers()) {
Diag(New->getLocation(),
@@ -3209,7 +4640,7 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
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)) {
@@ -3219,7 +4650,7 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
Diag(Old->getLocation(), diag::note_overridden_virtual_function);
return true;
};
-
+
return false;
}
@@ -3229,6 +4660,8 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
/// static data member of class X, names should be looked up in the scope of
/// class X.
void Sema::ActOnCXXEnterDeclInitializer(Scope *S, DeclPtrTy Dcl) {
+ AdjustDeclIfTemplate(Dcl);
+
Decl *D = Dcl.getAs<Decl>();
// If there is no declaration, there was an error parsing it.
if (D == 0)
@@ -3238,13 +4671,13 @@ void Sema::ActOnCXXEnterDeclInitializer(Scope *S, DeclPtrTy Dcl) {
// int foo::bar;
if (!D->isOutOfLine())
return;
-
+
// C++ [basic.lookup.unqual]p13
//
// A name used in the definition of a static data member of class X
// (after the qualified-id of the static member) is looked up as if the name
// was used in a member function of X.
-
+
// Change current context into the context of the initializing declaration.
EnterDeclaratorContext(S, D->getDeclContext());
}
@@ -3252,6 +4685,8 @@ void Sema::ActOnCXXEnterDeclInitializer(Scope *S, DeclPtrTy Dcl) {
/// ActOnCXXExitDeclInitializer - Invoked after we are finished parsing an
/// initializer for the declaration 'Dcl'.
void Sema::ActOnCXXExitDeclInitializer(Scope *S, DeclPtrTy Dcl) {
+ AdjustDeclIfTemplate(Dcl);
+
Decl *D = Dcl.getAs<Decl>();
// If there is no declaration, there was an error parsing it.
if (D == 0)
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index 5cf48d6..22a5179 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -25,10 +25,10 @@ bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property,
if (GetterMethod &&
GetterMethod->getResultType() != property->getType()) {
AssignConvertType result = Incompatible;
- if (Context.isObjCObjectPointerType(property->getType()))
+ if (property->getType()->isObjCObjectPointerType())
result = CheckAssignmentConstraints(GetterMethod->getResultType(), property->getType());
if (result != Compatible) {
- Diag(Loc, diag::warn_accessor_property_type_mismatch)
+ Diag(Loc, diag::warn_accessor_property_type_mismatch)
<< property->getDeclName()
<< GetterMethod->getSelector();
Diag(GetterMethod->getLocation(), diag::note_declared_at);
@@ -43,7 +43,7 @@ bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property,
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;
@@ -55,7 +55,7 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, DeclPtrTy D) {
AddInstanceMethodToGlobalPool(MDecl);
else
AddFactoryMethodToGlobalPool(MDecl);
-
+
// Allow all of Sema to see that we are entering a method definition.
PushDeclContext(FnBodyScope, MDecl);
@@ -64,7 +64,7 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, DeclPtrTy D) {
// Insert the invisible arguments, self and _cmd!
MDecl->createImplicitParams(Context, MDecl->getClassInterface());
-
+
PushOnScopeChains(MDecl->getSelfDecl(), FnBodyScope);
PushOnScopeChains(MDecl->getCmdDecl(), FnBodyScope);
@@ -82,9 +82,9 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
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);
+ NamedDecl *PrevDecl = LookupSingleName(TUScope, ClassName, LookupOrdinaryName);
if (PrevDecl && PrevDecl->isTemplateParameter()) {
// Maybe we will complain about the shadowed template parameter.
DiagnoseTemplateParameterShadow(ClassLoc, PrevDecl);
@@ -96,7 +96,7 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
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?
@@ -111,72 +111,78 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
} else {
IDecl->setLocation(AtInterfaceLoc);
IDecl->setForwardDecl(false);
+ IDecl->setClassLoc(ClassLoc);
}
} else {
- IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtInterfaceLoc,
+ IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtInterfaceLoc,
ClassName, ClassLoc);
if (AttrList)
ProcessDeclAttributeList(TUScope, 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);
+ PrevDecl = LookupSingleName(TUScope, SuperName, LookupOrdinaryName);
+ if (PrevDecl == IDecl) {
+ Diag(SuperLoc, diag::err_recursive_superclass)
+ << SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc);
+ IDecl->setLocEnd(ClassLoc);
+ } else {
+ 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->getAs<ObjCInterfaceType>()->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);
}
}
-
- // 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);
}
-
- 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);
}
@@ -184,12 +190,12 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
/// 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,
+ IdentifierInfo *AliasName,
SourceLocation AliasLocation,
IdentifierInfo *ClassName,
SourceLocation ClassLocation) {
// Look for previous declaration of alias name
- NamedDecl *ADecl = LookupName(TUScope, AliasName, LookupOrdinaryName);
+ NamedDecl *ADecl = LookupSingleName(TUScope, AliasName, LookupOrdinaryName);
if (ADecl) {
if (isa<ObjCCompatibleAliasDecl>(ADecl))
Diag(AliasLocation, diag::warn_previous_alias_decl);
@@ -199,13 +205,13 @@ Sema::DeclPtrTy Sema::ActOnCompatiblityAlias(SourceLocation AtLoc,
return DeclPtrTy();
}
// Check for class declaration
- NamedDecl *CDeclU = LookupName(TUScope, ClassName, LookupOrdinaryName);
+ NamedDecl *CDeclU = LookupSingleName(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()) {
+ if (NamedDecl *IDecl = T->getAs<ObjCInterfaceType>()->getDecl()) {
ClassName = IDecl->getIdentifier();
- CDeclU = LookupName(TUScope, ClassName, LookupOrdinaryName);
+ CDeclU = LookupSingleName(TUScope, ClassName, LookupOrdinaryName);
}
}
}
@@ -216,11 +222,11 @@ Sema::DeclPtrTy Sema::ActOnCompatiblityAlias(SourceLocation AtLoc,
Diag(CDeclU->getLocation(), diag::note_previous_declaration);
return DeclPtrTy();
}
-
+
// Everything checked out, instantiate a new alias declaration AST.
- ObjCCompatibleAliasDecl *AliasDecl =
+ ObjCCompatibleAliasDecl *AliasDecl =
ObjCCompatibleAliasDecl::Create(Context, CurContext, AtLoc, AliasName, CDecl);
-
+
if (!CheckObjCDeclScope(AliasDecl))
PushOnScopeChains(AliasDecl, TUScope);
@@ -230,17 +236,16 @@ Sema::DeclPtrTy Sema::ActOnCompatiblityAlias(SourceLocation AtLoc,
void Sema::CheckForwardProtocolDeclarationForCircularDependency(
IdentifierInfo *PName,
SourceLocation &Ploc, SourceLocation PrevLoc,
- const ObjCList<ObjCProtocolDecl> &PList)
-{
+ 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,
+ CheckForwardProtocolDeclarationForCircularDependency(PName, Ploc,
PDecl->getLocation(), PDecl->getReferencedProtocols());
}
}
@@ -267,16 +272,16 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc,
return DeclPtrTy::make(PDecl);
}
ObjCList<ObjCProtocolDecl> PList;
- PList.set((ObjCProtocolDecl *const*)ProtoRefs, NumProtoRefs, Context);
+ 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,
+ PDecl = ObjCProtocolDecl::Create(Context, CurContext,
AtProtoInterfaceLoc,ProtocolName);
PushOnScopeChains(PDecl, TUScope);
PDecl->setForwardDecl(false);
@@ -288,8 +293,8 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc,
PDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,Context);
PDecl->setLocEnd(EndProtoLoc);
}
-
- CheckObjCDeclScope(PDecl);
+
+ CheckObjCDeclScope(PDecl);
return DeclPtrTy::make(PDecl);
}
@@ -308,7 +313,7 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations,
<< ProtocolId[i].first;
continue;
}
-
+
(void)DiagnoseUseOfDecl(PDecl, ProtocolId[i].second);
// If this is a forward declaration and we are supposed to warn in this
@@ -324,12 +329,12 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations,
/// attributes and types and warns on a variety of inconsistencies.
///
void
-Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property,
+Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property,
ObjCPropertyDecl *SuperProperty,
const IdentifierInfo *inheritedName) {
- ObjCPropertyDecl::PropertyAttributeKind CAttr =
+ ObjCPropertyDecl::PropertyAttributeKind CAttr =
Property->getPropertyAttributes();
- ObjCPropertyDecl::PropertyAttributeKind SAttr =
+ ObjCPropertyDecl::PropertyAttributeKind SAttr =
SuperProperty->getPropertyAttributes();
if ((CAttr & ObjCPropertyDecl::OBJC_PR_readonly)
&& (SAttr & ObjCPropertyDecl::OBJC_PR_readwrite))
@@ -343,27 +348,27 @@ Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property,
!= (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;
+ << Property->getDeclName() << "setter" << inheritedName;
if (Property->getGetterName() != SuperProperty->getGetterName())
Diag(Property->getLocation(), diag::warn_property_attribute)
<< Property->getDeclName() << "getter" << inheritedName;
- QualType LHSType =
+ QualType LHSType =
Context.getCanonicalType(SuperProperty->getType());
- QualType RHSType =
+ 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))
+ if (Context.ObjCQualifiedIdTypesAreCompatible(LHSType, RHSType, false))
return;
Diag(Property->getLocation(), diag::warn_property_types_are_incompatible)
<< Property->getType() << SuperProperty->getType() << inheritedName;
@@ -387,7 +392,7 @@ void Sema::ComparePropertiesInBaseAndSuper(ObjCInterfaceDecl *IDecl) {
E = IDecl->prop_end(); I != E; ++I) {
ObjCPropertyDecl *PDecl = (*I);
if (SuperPDecl->getIdentifier() == PDecl->getIdentifier())
- DiagnosePropertyMismatch(PDecl, SuperPDecl,
+ DiagnosePropertyMismatch(PDecl, SuperPDecl,
SDecl->getIdentifier());
}
}
@@ -450,7 +455,7 @@ void Sema::MergeProtocolPropertiesIntoClass(Decl *CDecl,
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(),
@@ -470,7 +475,7 @@ void Sema::MergeProtocolPropertiesIntoClass(Decl *CDecl,
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(),
@@ -487,7 +492,7 @@ void Sema::MergeProtocolPropertiesIntoClass(Decl *CDecl,
/// DiagnoseClassExtensionDupMethods - Check for duplicate declaration of
/// a class method in its extension.
///
-void Sema::DiagnoseClassExtensionDupMethods(ObjCCategoryDecl *CAT,
+void Sema::DiagnoseClassExtensionDupMethods(ObjCCategoryDecl *CAT,
ObjCInterfaceDecl *ID) {
if (!ID)
return; // Possibly due to previous error
@@ -520,12 +525,12 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc,
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,
+ PDecl = ObjCProtocolDecl::Create(Context, CurContext,
IdentList[i].second, Ident);
PushOnScopeChains(PDecl, TUScope);
}
@@ -533,8 +538,8 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc,
ProcessDeclAttributeList(TUScope, PDecl, attrList);
Protocols.push_back(PDecl);
}
-
- ObjCForwardProtocolDecl *PDecl =
+
+ ObjCForwardProtocolDecl *PDecl =
ObjCForwardProtocolDecl::Create(Context, CurContext, AtProtocolLoc,
&Protocols[0], Protocols.size());
CurContext->addDecl(PDecl);
@@ -550,7 +555,7 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
const DeclPtrTy *ProtoRefs,
unsigned NumProtoRefs,
SourceLocation EndProtoLoc) {
- ObjCCategoryDecl *CDecl =
+ ObjCCategoryDecl *CDecl =
ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, CategoryName);
// FIXME: PushOnScopeChains?
CurContext->addDecl(CDecl);
@@ -564,7 +569,7 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
}
CDecl->setClassInterface(IDecl);
-
+
// If the interface is deprecated, warn about it.
(void)DiagnoseUseOfDecl(IDecl, ClassLoc);
@@ -583,10 +588,15 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
CDecl->insertNextClassCategory();
if (NumProtoRefs) {
- CDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,Context);
+ CDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,
+ Context);
CDecl->setLocEnd(EndProtoLoc);
+ // Protocols in the class extension belong to the class.
+ if (!CDecl->getIdentifier())
+ IDecl->mergeClassExtensionProtocolList((ObjCProtocolDecl**)ProtoRefs,
+ NumProtoRefs,Context);
}
-
+
CheckObjCDeclScope(CDecl);
return DeclPtrTy::make(CDecl);
}
@@ -599,7 +609,20 @@ Sema::DeclPtrTy Sema::ActOnStartCategoryImplementation(
IdentifierInfo *ClassName, SourceLocation ClassLoc,
IdentifierInfo *CatName, SourceLocation CatLoc) {
ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName);
- ObjCCategoryImplDecl *CDecl =
+ ObjCCategoryDecl *CatIDecl = 0;
+ if (IDecl) {
+ CatIDecl = IDecl->FindCategoryDeclaration(CatName);
+ if (!CatIDecl) {
+ // Category @implementation with no corresponding @interface.
+ // Create and install one.
+ CatIDecl = ObjCCategoryDecl::Create(Context, CurContext, SourceLocation(),
+ CatName);
+ CatIDecl->setClassInterface(IDecl);
+ CatIDecl->insertNextClassCategory();
+ }
+ }
+
+ ObjCCategoryImplDecl *CDecl =
ObjCCategoryImplDecl::Create(Context, CurContext, AtCatImplLoc, CatName,
IDecl);
/// Check that class of this category is already completely declared.
@@ -609,10 +632,17 @@ Sema::DeclPtrTy Sema::ActOnStartCategoryImplementation(
// FIXME: PushOnScopeChains?
CurContext->addDecl(CDecl);
- /// TODO: Check that CatName, category name, is not used in another
- // implementation.
- ObjCCategoryImpls.push_back(CDecl);
-
+ /// Check that CatName, category name, is not used in another implementation.
+ if (CatIDecl) {
+ if (CatIDecl->getImplementation()) {
+ Diag(ClassLoc, diag::err_dup_implementation_category) << ClassName
+ << CatName;
+ Diag(CatIDecl->getImplementation()->getLocation(),
+ diag::note_previous_definition);
+ } else
+ CatIDecl->setImplementation(CDecl);
+ }
+
CheckObjCDeclScope(CDecl);
return DeclPtrTy::make(CDecl);
}
@@ -620,34 +650,35 @@ Sema::DeclPtrTy Sema::ActOnStartCategoryImplementation(
Sema::DeclPtrTy Sema::ActOnStartClassImplementation(
SourceLocation AtClassImplLoc,
IdentifierInfo *ClassName, SourceLocation ClassLoc,
- IdentifierInfo *SuperClassname,
+ IdentifierInfo *SuperClassname,
SourceLocation SuperClassLoc) {
ObjCInterfaceDecl* IDecl = 0;
// Check for another declaration kind with the same name.
- NamedDecl *PrevDecl = LookupName(TUScope, ClassName, LookupOrdinaryName);
+ NamedDecl *PrevDecl
+ = LookupSingleName(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);
+ 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);
+ PrevDecl = LookupSingleName(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);
+ SDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
if (!SDecl)
Diag(SuperClassLoc, diag::err_undef_superclass)
<< SuperClassname << ClassName;
@@ -660,14 +691,14 @@ Sema::DeclPtrTy Sema::ActOnStartClassImplementation(
}
}
}
-
+
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,
+ IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtClassImplLoc,
ClassName, ClassLoc, false, true);
IDecl->setSuperClass(SDecl);
IDecl->setLocEnd(ClassLoc);
@@ -679,20 +710,24 @@ Sema::DeclPtrTy Sema::ActOnStartClassImplementation(
// declaration; the user cannot reopen it.
IDecl->setForwardDecl(false);
}
-
- ObjCImplementationDecl* IMPDecl =
- ObjCImplementationDecl::Create(Context, CurContext, AtClassImplLoc,
+
+ 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))
+ if (IDecl->getImplementation()) {
// FIXME: Don't leak everything!
Diag(ClassLoc, diag::err_dup_implementation_class) << ClassName;
- else // add it to the list.
+ Diag(IDecl->getImplementation()->getLocation(),
+ diag::note_previous_definition);
+ } else { // add it to the list.
+ IDecl->setImplementation(IMPDecl);
PushOnScopeChains(IMPDecl, TUScope);
+ }
return DeclPtrTy::make(IMPDecl);
}
@@ -714,21 +749,21 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl,
// 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
+ 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())) {
@@ -745,7 +780,7 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl,
<< 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)
@@ -754,7 +789,7 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl,
}
--numIvars;
}
-
+
if (numIvars > 0)
Diag(ivars[j]->getLocation(), diag::err_inconsistant_ivar_count);
else if (IVI != IVE)
@@ -774,22 +809,23 @@ 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)
+ !Context.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()))
+ Context.QualifiedIdConformsQualifiedId((*IF)->getType(),
+ (*IM)->getType()))
continue;
-
- Diag((*IM)->getLocation(), diag::warn_conflicting_param_types)
+
+ Diag((*IM)->getLocation(), diag::warn_conflicting_param_types)
<< ImpMethodDecl->getDeclName() << (*IF)->getType()
<< (*IM)->getType();
Diag((*IF)->getLocation(), diag::note_previous_definition);
@@ -804,43 +840,41 @@ bool Sema::isPropertyReadonly(ObjCPropertyDecl *PDecl,
// by far the most common case.
if (!PDecl->isReadOnly())
return false;
- // Even if property is ready only, if interface has a user defined setter,
+ // Even if property is ready only, if interface has a user defined setter,
// it is not considered read only.
if (IDecl->getInstanceMethod(PDecl->getSetterName()))
return false;
-
+
// Main class has the property as 'readonly'. Must search
- // through the category list to see if the property's
+ // 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.
+ // Even if property is ready only, if a category has a user defined setter,
+ // it is not considered read only.
if (Category->getInstanceMethod(PDecl->getSetterName()))
return false;
- ObjCPropertyDecl *P =
+ ObjCPropertyDecl *P =
Category->FindPropertyDeclaration(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 =
+ if (ObjCImplementationDecl *IMD =
dyn_cast<ObjCImplementationDecl>(OMD->getDeclContext())) {
if (IMD->getInstanceMethod(PDecl->getSetterName()))
return false;
- }
- else if (ObjCCategoryImplDecl *CIMD =
- dyn_cast<ObjCCategoryImplDecl>(OMD->getDeclContext())) {
+ } else if (ObjCCategoryImplDecl *CIMD =
+ dyn_cast<ObjCCategoryImplDecl>(OMD->getDeclContext())) {
if (CIMD->getInstanceMethod(PDecl->getSetterName()))
return false;
}
}
// Lastly, look through the implementation (if one is in scope).
- if (ObjCImplementationDecl *ImpDecl
- = LookupObjCImplementation(IDecl->getIdentifier()))
+ if (ObjCImplementationDecl *ImpDecl = IDecl->getImplementation())
if (ImpDecl->getInstanceMethod(PDecl->getSetterName()))
return false;
// If all fails, look at the super class.
@@ -866,11 +900,11 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
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
+ // 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
+ // 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");
@@ -880,7 +914,7 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
// 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
@@ -888,24 +922,24 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
// check unimplemented instance methods.
if (!NSIDecl)
- for (ObjCProtocolDecl::instmeth_iterator I = PDecl->instmeth_begin(),
+ for (ObjCProtocolDecl::instmeth_iterator I = PDecl->instmeth_begin(),
E = PDecl->instmeth_end(); I != E; ++I) {
ObjCMethodDecl *method = *I;
- if (method->getImplementationControl() != ObjCMethodDecl::Optional &&
+ if (method->getImplementationControl() != ObjCMethodDecl::Optional &&
!method->isSynthesized() && !InsMap.count(method->getSelector()) &&
- (!Super ||
+ (!Super ||
!Super->lookupInstanceMethod(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 =
+ ObjCMethodDecl *MethodInClass =
IDecl->lookupInstanceMethod(method->getSelector());
if (!MethodInClass || !MethodInClass->isSynthesized())
WarnUndefinedMethod(ImpLoc, method, IncompleteImpl);
}
}
// check unimplemented class methods
- for (ObjCProtocolDecl::classmeth_iterator
+ for (ObjCProtocolDecl::classmeth_iterator
I = PDecl->classmeth_begin(), E = PDecl->classmeth_end();
I != E; ++I) {
ObjCMethodDecl *method = *I;
@@ -930,8 +964,7 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
ObjCImplDecl* IMPDecl,
ObjCContainerDecl* CDecl,
bool &IncompleteImpl,
- bool ImmediateClass)
-{
+ 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(),
@@ -939,28 +972,27 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
if (InsMapSeen.count((*I)->getSelector()))
continue;
InsMapSeen.insert((*I)->getSelector());
- if (!(*I)->isSynthesized() &&
+ if (!(*I)->isSynthesized() &&
!InsMap.count((*I)->getSelector())) {
if (ImmediateClass)
WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl);
continue;
- }
- else {
- ObjCMethodDecl *ImpMethodDecl =
+ } else {
+ ObjCMethodDecl *ImpMethodDecl =
IMPDecl->getInstanceMethod((*I)->getSelector());
- ObjCMethodDecl *IntfMethodDecl =
+ ObjCMethodDecl *IntfMethodDecl =
CDecl->getInstanceMethod((*I)->getSelector());
- assert(IntfMethodDecl &&
+ 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
+ for (ObjCInterfaceDecl::classmeth_iterator
I = CDecl->classmeth_begin(), E = CDecl->classmeth_end(); I != E; ++I) {
if (ClsMapSeen.count((*I)->getSelector()))
continue;
@@ -968,11 +1000,10 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
if (!ClsMap.count((*I)->getSelector())) {
if (ImmediateClass)
WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl);
- }
- else {
+ } else {
ObjCMethodDecl *ImpMethodDecl =
IMPDecl->getClassMethod((*I)->getSelector());
- ObjCMethodDecl *IntfMethodDecl =
+ ObjCMethodDecl *IntfMethodDecl =
CDecl->getClassMethod((*I)->getSelector());
WarnConflictingTypedMethods(ImpMethodDecl, IntfMethodDecl);
}
@@ -981,26 +1012,26 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
// 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,
+ MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
+ IMPDecl,
(*PI), IncompleteImpl, false);
if (I->getSuperClass())
MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
- IMPDecl,
+ IMPDecl,
I->getSuperClass(), IncompleteImpl, false);
}
}
-void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
- ObjCContainerDecl* CDecl,
+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
+ for (ObjCImplementationDecl::instmeth_iterator
I = IMPDecl->instmeth_begin(), E = IMPDecl->instmeth_end(); 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.
@@ -1012,7 +1043,7 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
continue;
ObjCPropertyImplDecl *PI = 0;
// Is there a matching propery synthesize/dynamic?
- for (ObjCImplDecl::propimpl_iterator
+ for (ObjCImplDecl::propimpl_iterator
I = IMPDecl->propimpl_begin(),
EI = IMPDecl->propimpl_end(); I != EI; ++I)
if ((*I)->getPropertyDecl() == Prop) {
@@ -1022,44 +1053,44 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
if (PI)
continue;
if (!InsMap.count(Prop->getGetterName())) {
- Diag(Prop->getLocation(),
- diag::warn_setter_getter_impl_required)
+ 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)
+ 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
+ for (ObjCImplementationDecl::classmeth_iterator
I = IMPDecl->classmeth_begin(),
E = IMPDecl->classmeth_end(); 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,
+ 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,
+ CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl,
InsMap, ClsMap, I);
// Check class extensions (unnamed categories)
for (ObjCCategoryDecl *Categories = I->getCategoryList();
@@ -1070,24 +1101,29 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
}
}
} 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());
+ // For extended class, unimplemented methods in its protocols will
+ // be reported in the primary class.
+ if (C->getIdentifier()) {
+ 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 -
+/// 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);
+ NamedDecl *PrevDecl
+ = LookupSingleName(TUScope, IdentList[i], LookupOrdinaryName);
if (PrevDecl && PrevDecl->isTemplateParameter()) {
// Maybe we will complain about the shadowed template parameter.
DiagnoseTemplateParameterShadow(AtClassLoc, PrevDecl);
@@ -1101,30 +1137,32 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
// typedef NSObject < XCElementTogglerP > XCElementToggler;
// @class XCElementToggler;
//
- // FIXME: Make an extension?
+ // 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 =
+ } 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);
+ 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);
+ IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtClassLoc,
+ IdentList[i],
+ // FIXME: need to get the 'real'
+ // identifier loc from the parser.
+ AtClassLoc, true);
PushOnScopeChains(IDecl, TUScope);
}
Interfaces.push_back(IDecl);
}
-
+
ObjCClassDecl *CDecl = ObjCClassDecl::Create(Context, CurContext, AtClassLoc,
&Interfaces[0],
Interfaces.size());
@@ -1137,12 +1175,12 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
/// 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,
+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)
@@ -1154,11 +1192,11 @@ bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *Method,
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());
@@ -1183,7 +1221,7 @@ bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *Method,
///
/// 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,
+Sema::MethodPool::iterator Sema::ReadMethodPool(Selector Sel,
bool isInstance) {
assert(ExternalSource && "We need an external AST source");
assert(InstanceMethodPool.find(Sel) == InstanceMethodPool.end() &&
@@ -1194,12 +1232,12 @@ Sema::MethodPool::iterator Sema::ReadMethodPool(Selector Sel,
// 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;
@@ -1225,21 +1263,22 @@ void Sema::AddInstanceMethodToGlobalPool(ObjCMethodDecl *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) {
+ObjCMethodDecl *Sema::LookupInstanceMethodInGlobalPool(Selector Sel,
+ SourceRange R,
+ bool warn) {
llvm::DenseMap<Selector, ObjCMethodList>::iterator Pos
= InstanceMethodPool.find(Sel);
if (Pos == InstanceMethodPool.end()) {
@@ -1251,12 +1290,12 @@ ObjCMethodDecl *Sema::LookupInstanceMethodInGlobalPool(Selector Sel,
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;
+ issueWarning = warn;
}
if (issueWarning && (MethList.Method && MethList.Next)) {
Diag(R.getBegin(), diag::warn_multiple_method_decl) << Sel << R;
@@ -1288,11 +1327,11 @@ void Sema::AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method) {
} 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;
+
+ 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".
@@ -1302,12 +1341,12 @@ void Sema::AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method) {
}
}
-ObjCMethodDecl *Sema::LookupFactoryMethodInGlobalPool(Selector Sel,
+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))
+ if (ExternalSource && !InstanceMethodPool.count(Sel))
Pos = ReadMethodPool(Sel, /*isInstance=*/false);
else
return 0;
@@ -1315,7 +1354,7 @@ ObjCMethodDecl *Sema::LookupFactoryMethodInGlobalPool(Selector Sel,
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.
@@ -1333,28 +1372,28 @@ ObjCMethodDecl *Sema::LookupFactoryMethodInGlobalPool(Selector Sel,
return MethList.Method;
}
-/// ProcessPropertyDecl - Make sure that any user-defined setter/getter methods
+/// 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,
+void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
ObjCContainerDecl *CD) {
ObjCMethodDecl *GetterMethod, *SetterMethod;
-
- GetterMethod = CD->getInstanceMethod(property->getGetterName());
+
+ GetterMethod = CD->getInstanceMethod(property->getGetterName());
SetterMethod = CD->getInstanceMethod(property->getSetterName());
- DiagnosePropertyAccessorMismatch(property, GetterMethod,
+ DiagnosePropertyAccessorMismatch(property, GetterMethod,
property->getLocation());
-
+
if (SetterMethod) {
- if (Context.getCanonicalType(SetterMethod->getResultType())
+ 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)
+ Diag(property->getLocation(),
+ diag::warn_accessor_property_type_mismatch)
<< property->getDeclName()
<< SetterMethod->getSelector();
Diag(SetterMethod->getLocation(), diag::note_declared_at);
@@ -1369,14 +1408,14 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
// 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
+ // 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 :
+ 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(GetterMethod);
} else
@@ -1390,22 +1429,23 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
// 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
+ // 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(),
+ SetterMethod = ObjCMethodDecl::Create(Context, property->getLocation(),
+ property->getLocation(),
+ property->getSetterName(),
Context.VoidTy, CD, true, false, true,
- (property->getPropertyImplementation() ==
- ObjCPropertyDecl::Optional) ?
- ObjCMethodDecl::Optional :
+ (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->getLocation(),
property->getIdentifier(),
property->getType(),
+ /*DInfo=*/0,
VarDecl::None,
0);
SetterMethod->setMethodParams(Context, &Argument, 1);
@@ -1416,7 +1456,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
SetterMethod->setSynthesized(true);
property->setSetterMethodDecl(SetterMethod);
}
- // Add any synthesized methods to the global pool. This allows us to
+ // 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
@@ -1429,9 +1469,46 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
// }
//
if (GetterMethod)
- AddInstanceMethodToGlobalPool(GetterMethod);
+ AddInstanceMethodToGlobalPool(GetterMethod);
if (SetterMethod)
- AddInstanceMethodToGlobalPool(SetterMethod);
+ AddInstanceMethodToGlobalPool(SetterMethod);
+}
+
+/// CompareMethodParamsInBaseAndSuper - This routine compares methods with
+/// identical selector names in current and its super classes and issues
+/// a warning if any of their argument types are incompatible.
+void Sema::CompareMethodParamsInBaseAndSuper(Decl *ClassDecl,
+ ObjCMethodDecl *Method,
+ bool IsInstance) {
+ ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(ClassDecl);
+ if (ID == 0) return;
+
+ while (ObjCInterfaceDecl *SD = ID->getSuperClass()) {
+ ObjCMethodDecl *SuperMethodDecl =
+ SD->lookupMethod(Method->getSelector(), IsInstance);
+ if (SuperMethodDecl == 0) {
+ ID = SD;
+ continue;
+ }
+ ObjCMethodDecl::param_iterator ParamI = Method->param_begin(),
+ E = Method->param_end();
+ ObjCMethodDecl::param_iterator PrevI = SuperMethodDecl->param_begin();
+ for (; ParamI != E; ++ParamI, ++PrevI) {
+ // Number of parameters are the same and is guaranteed by selector match.
+ assert(PrevI != SuperMethodDecl->param_end() && "Param mismatch");
+ QualType T1 = Context.getCanonicalType((*ParamI)->getType());
+ QualType T2 = Context.getCanonicalType((*PrevI)->getType());
+ // If type of arguement of method in this class does not match its
+ // respective argument type in the super class method, issue warning;
+ if (!Context.typesAreCompatible(T1, T2)) {
+ Diag((*ParamI)->getLocation(), diag::ext_typecheck_base_super)
+ << T1 << T2;
+ Diag(SuperMethodDecl->getLocation(), diag::note_previous_declaration);
+ return;
+ }
+ }
+ ID = SD;
+ }
}
// Note: For class/category implemenations, allMethods/allProperties is
@@ -1447,8 +1524,8 @@ void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl,
// should be true.
if (!ClassDecl)
return;
-
- bool isInterfaceDeclKind =
+
+ bool isInterfaceDeclKind =
isa<ObjCInterfaceDecl>(ClassDecl) || isa<ObjCCategoryDecl>(ClassDecl)
|| isa<ObjCProtocolDecl>(ClassDecl);
bool checkIdenticalMethods = isa<ObjCImplementationDecl>(ClassDecl);
@@ -1467,9 +1544,9 @@ void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl,
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)
+ bool match = PrevMethod ? MatchTwoMethodDeclarations(Method, PrevMethod)
: false;
- if ((isInterfaceDeclKind && PrevMethod && !match)
+ if ((isInterfaceDeclKind && PrevMethod && !match)
|| (checkIdenticalMethods && match)) {
Diag(Method->getLocation(), diag::err_duplicate_method_decl)
<< Method->getDeclName();
@@ -1479,14 +1556,16 @@ void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl,
InsMap[Method->getSelector()] = Method;
/// The following allows us to typecheck messages to "id".
AddInstanceMethodToGlobalPool(Method);
+ // verify that the instance method conforms to the same definition of
+ // parent methods if it shadows one.
+ CompareMethodParamsInBaseAndSuper(ClassDecl, Method, true);
}
- }
- else {
+ } else {
/// Check for class method of the same name with incompatible types
const ObjCMethodDecl *&PrevMethod = ClsMap[Method->getSelector()];
- bool match = PrevMethod ? MatchTwoMethodDeclarations(Method, PrevMethod)
+ bool match = PrevMethod ? MatchTwoMethodDeclarations(Method, PrevMethod)
: false;
- if ((isInterfaceDeclKind && PrevMethod && !match)
+ if ((isInterfaceDeclKind && PrevMethod && !match)
|| (checkIdenticalMethods && match)) {
Diag(Method->getLocation(), diag::err_duplicate_method_decl)
<< Method->getDeclName();
@@ -1496,17 +1575,20 @@ void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl,
ClsMap[Method->getSelector()] = Method;
/// The following allows us to typecheck messages to "Class".
AddFactoryMethodToGlobalPool(Method);
+ // verify that the class method conforms to the same definition of
+ // parent methods if it shadows one.
+ CompareMethodParamsInBaseAndSuper(ClassDecl, Method, false);
}
}
}
if (ObjCInterfaceDecl *I = dyn_cast<ObjCInterfaceDecl>(ClassDecl)) {
- // Compares properties declared in this class to those of its
+ // 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
+ // 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
@@ -1525,13 +1607,13 @@ void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl,
CDecl->setAtEndLoc(AtEndLoc);
}
if (ObjCImplementationDecl *IC=dyn_cast<ObjCImplementationDecl>(ClassDecl)) {
- IC->setLocEnd(AtEndLoc);
+ IC->setAtEndLoc(AtEndLoc);
if (ObjCInterfaceDecl* IDecl = IC->getClassInterface())
ImplMethodsVsClassMethods(IC, IDecl);
- } else if (ObjCCategoryImplDecl* CatImplClass =
+ } else if (ObjCCategoryImplDecl* CatImplClass =
dyn_cast<ObjCCategoryImplDecl>(ClassDecl)) {
- CatImplClass->setLocEnd(AtEndLoc);
-
+ CatImplClass->setAtEndLoc(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()) {
@@ -1560,7 +1642,7 @@ void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl,
/// 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
+static Decl::ObjCDeclQualifier
CvtQTToAstBitMask(ObjCDeclSpec::ObjCDeclQualifier PQTVal) {
Decl::ObjCDeclQualifier ret = Decl::OBJC_TQ_None;
if (PQTVal & ObjCDeclSpec::DQ_In)
@@ -1595,13 +1677,14 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration(
// Make sure we can establish a context for the method.
if (!ClassDecl) {
Diag(MethodLoc, diag::error_missing_method_context);
+ FunctionLabelMap.clear();
return DeclPtrTy();
}
QualType resultDeclType;
-
+
if (ReturnType) {
- resultDeclType = QualType::getFromOpaquePtr(ReturnType);
-
+ resultDeclType = GetTypeFromParser(ReturnType);
+
// Methods cannot return interface types. All ObjC objects are
// passed by reference.
if (resultDeclType->isObjCInterfaceType()) {
@@ -1611,54 +1694,56 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration(
}
} else // get the type for "id".
resultDeclType = Context.getObjCIdType();
-
- ObjCMethodDecl* ObjCMethod =
+
+ ObjCMethodDecl* ObjCMethod =
ObjCMethodDecl::Create(Context, MethodLoc, EndLoc, Sel, resultDeclType,
- cast<DeclContext>(ClassDecl),
+ cast<DeclContext>(ClassDecl),
MethodType == tok::minus, isVariadic,
false,
- MethodDeclKind == tok::objc_optional ?
- ObjCMethodDecl::Optional :
+ 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);
+ UnpromotedArgType = ArgType = GetTypeFromParser(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,
+ /*DInfo=*/0, //FIXME: Pass info here.
VarDecl::None, 0);
else
Param = OriginalParmVarDecl::Create(Context, ObjCMethod,
ArgInfo[i].NameLoc,
ArgInfo[i].Name, ArgType,
+ /*DInfo=*/0, //FIXME: Pass info here.
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(TUScope, Param, ArgInfo[i].ArgAttrs);
-
+
Params.push_back(Param);
}
@@ -1669,12 +1754,12 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration(
if (AttrList)
ProcessDeclAttributeList(TUScope, 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
+
+ // 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 =
+ if (ObjCImplementationDecl *ImpDecl =
dyn_cast<ObjCImplementationDecl>(ClassDecl)) {
if (MethodType == tok::minus) {
PrevMethod = ImpDecl->getInstanceMethod(Sel);
@@ -1685,9 +1770,8 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration(
}
if (AttrList)
Diag(EndLoc, diag::warn_attribute_method_def);
- }
- else if (ObjCCategoryImplDecl *CatImpDecl =
- dyn_cast<ObjCCategoryImplDecl>(ClassDecl)) {
+ } else if (ObjCCategoryImplDecl *CatImpDecl =
+ dyn_cast<ObjCCategoryImplDecl>(ClassDecl)) {
if (MethodType == tok::minus) {
PrevMethod = CatImpDecl->getInstanceMethod(Sel);
CatImpDecl->addInstanceMethod(ObjCMethod);
@@ -1703,11 +1787,11 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration(
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,
+void Sema::CheckObjCPropertyAttributes(QualType PropertyTy,
SourceLocation Loc,
unsigned &Attributes) {
// FIXME: Improve the reported location.
@@ -1724,8 +1808,8 @@ void Sema::CheckObjCPropertyAttributes(QualType PropertyTy,
"assign" :
(Attributes & ObjCDeclSpec::DQ_PR_copy) ?
"copy" : "retain";
-
- Diag(Loc, (Attributes & (ObjCDeclSpec::DQ_PR_readwrite)) ?
+
+ Diag(Loc, (Attributes & (ObjCDeclSpec::DQ_PR_readwrite)) ?
diag::err_objc_property_attr_mutually_exclusive :
diag::warn_objc_property_attr_mutually_exclusive)
<< "readonly" << which;
@@ -1733,7 +1817,9 @@ void Sema::CheckObjCPropertyAttributes(QualType PropertyTy,
// Check for copy or retain on non-object types.
if ((Attributes & (ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain)) &&
- !Context.isObjCObjectPointerType(PropertyTy)) {
+ !PropertyTy->isObjCObjectPointerType() &&
+ !PropertyTy->isBlockPointerType() &&
+ !Context.isObjCNSObjectType(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);
@@ -1745,7 +1831,7 @@ void Sema::CheckObjCPropertyAttributes(QualType PropertyTy,
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";
@@ -1764,15 +1850,15 @@ void Sema::CheckObjCPropertyAttributes(QualType PropertyTy,
if (!(Attributes & (ObjCDeclSpec::DQ_PR_assign | ObjCDeclSpec::DQ_PR_copy |
ObjCDeclSpec::DQ_PR_retain)) &&
!(Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
- Context.isObjCObjectPointerType(PropertyTy)) {
+ PropertyTy->isObjCObjectPointerType()) {
// Skip this warning in gc-only mode.
- if (getLangOptions().getGCMode() != LangOptions::GCOnly)
+ 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>
@@ -1785,7 +1871,7 @@ void Sema::CheckObjCPropertyAttributes(QualType PropertyTy,
Diag(Loc, diag::warn_objc_property_copy_missing_on_block);
}
-Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
+Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
FieldDeclarator &FD,
ObjCDeclSpec &ODS,
Selector GetterSel,
@@ -1797,11 +1883,11 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
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
+ // 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) &&
+ (isReadWrite &&
+ !(Attributes & ObjCDeclSpec::DQ_PR_retain) &&
!(Attributes & ObjCDeclSpec::DQ_PR_copy)));
QualType T = GetTypeForDeclarator(FD.D, S);
Decl *ClassDecl = ClassCategory.getAs<Decl>();
@@ -1810,20 +1896,20 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
CheckObjCPropertyAttributes(T, AtLoc, Attributes);
if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl))
if (!CDecl->getIdentifier()) {
- // This is a continuation class. property requires special
+ // 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
+ for (ObjCInterfaceDecl::prop_iterator
I = CCPrimary->prop_begin(), E = CCPrimary->prop_end();
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!
@@ -1838,12 +1924,11 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
if (Attributes & ObjCDeclSpec::DQ_PR_copy)
PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy);
PIDecl->setSetterName(SetterSel);
- }
- else
- Diag(AtLoc, diag::err_use_continuation_class)
+ } else
+ Diag(AtLoc, diag::err_use_continuation_class)
<< CCPrimary->getDeclName();
*isOverridingProperty = true;
- // Make sure setter decl is synthesized, and added to primary
+ // Make sure setter decl is synthesized, and added to primary
// class's list.
ProcessPropertyDecl(PIDecl, CCPrimary);
return DeclPtrTy();
@@ -1855,52 +1940,72 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
Diag(CDecl->getLocation(), diag::err_continuation_class);
*isOverridingProperty = true;
return DeclPtrTy();
- }
+ }
}
+ // Issue a warning if property is 'assign' as default and its object, which is
+ // gc'able conforms to NSCopying protocol
+ if (getLangOptions().getGCMode() != LangOptions::NonGC &&
+ isAssign && !(Attributes & ObjCDeclSpec::DQ_PR_assign))
+ if (T->isObjCObjectPointerType()) {
+ QualType InterfaceTy = T->getPointeeType();
+ if (const ObjCInterfaceType *OIT =
+ InterfaceTy->getAs<ObjCInterfaceType>()) {
+ ObjCInterfaceDecl *IDecl = OIT->getDecl();
+ if (IDecl)
+ if (ObjCProtocolDecl* PNSCopying =
+ LookupProtocol(&Context.Idents.get("NSCopying")))
+ if (IDecl->ClassImplementsProtocol(PNSCopying, true))
+ Diag(AtLoc, diag::warn_implements_nscopying)
+ << FD.D.getIdentifier();
+ }
+ }
+ if (T->isObjCInterfaceType())
+ Diag(FD.D.getIdentifierLoc(), diag::err_statically_allocated_object);
+
DeclContext *DC = dyn_cast<DeclContext>(ClassDecl);
assert(DC && "ClassDecl is not a DeclContext");
ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC,
- FD.D.getIdentifierLoc(),
+ FD.D.getIdentifierLoc(),
FD.D.getIdentifier(), T);
DC->addDecl(PDecl);
-
+
if (T->isArrayType() || T->isFunctionType()) {
Diag(AtLoc, diag::err_property_type) << T;
PDecl->setInvalidDecl();
}
-
+
ProcessDeclAttributes(S, 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)
@@ -1910,7 +2015,7 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
// Make sure setter/getters are declared here.
if (CCPrimary)
ProcessPropertyDecl(PDecl, CCPrimary);
-
+
return DeclPtrTy::make(PDecl);
}
@@ -1918,9 +2023,9 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
/// builds the AST node for a property implementation declaration; declared
/// as @synthesize or @dynamic.
///
-Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc,
+Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc,
SourceLocation PropertyLoc,
- bool Synthesize,
+ bool Synthesize,
DeclPtrTy ClassCatImpDecl,
IdentifierInfo *PropertyId,
IdentifierInfo *PropertyIvar) {
@@ -1940,29 +2045,28 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc,
IDecl = IC->getClassInterface();
// We always synthesize an interface for an implementation
// without an interface decl. So, IDecl is always non-zero.
- assert(IDecl &&
+ assert(IDecl &&
"ActOnPropertyImplDecl - @implementation without @interface");
-
+
// Look for this property declaration in the @implementation's @interface
property = IDecl->FindPropertyDeclaration(PropertyId);
if (!property) {
Diag(PropertyLoc, diag::error_bad_property_decl) << IDecl->getDeclName();
return DeclPtrTy();
}
- }
- else if ((CatImplClass = dyn_cast<ObjCCategoryImplDecl>(ClassImpDecl))) {
+ } 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 =
+ 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)
@@ -1990,10 +2094,10 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc,
Ivar = IDecl->lookupInstanceVariable(PropertyIvar, ClassDeclared);
if (!Ivar) {
DeclContext *EnclosingContext = cast_or_null<DeclContext>(IDecl);
- assert(EnclosingContext &&
+ assert(EnclosingContext &&
"null DeclContext for synthesized ivar - ActOnPropertyImplDecl");
- Ivar = ObjCIvarDecl::Create(Context, EnclosingContext, PropertyLoc,
- PropertyIvar, PropType,
+ Ivar = ObjCIvarDecl::Create(Context, EnclosingContext, PropertyLoc,
+ PropertyIvar, PropType, /*Dinfo=*/0,
ObjCIvarDecl::Public,
(Expr *)0);
Ivar->setLexicalDeclContext(IDecl);
@@ -2001,35 +2105,34 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc,
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
+ // 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) {
+ } else if (getLangOptions().ObjCNonFragileABI &&
+ ClassDeclared != IDecl) {
Diag(PropertyLoc, diag::error_ivar_in_superclass_use)
- << property->getDeclName() << Ivar->getDeclName()
+ << 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
+ // 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 &&
+ if (lhsType != rhsType &&
lhsType->isArithmeticType()) {
Diag(PropertyLoc, diag::error_property_ivar_type)
<< property->getDeclName() << Ivar->getDeclName();
@@ -2042,78 +2145,77 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc,
<< property->getDeclName() << Ivar->getDeclName();
// Fall thru - see previous comment
}
- if ((Context.isObjCObjectPointerType(property->getType()) ||
+ if ((property->getType()->isObjCObjectPointerType() ||
PropType.isObjCGCStrong()) && IvarType.isObjCGCWeak() &&
getLangOptions().getGCMode() != LangOptions::NonGC) {
Diag(PropertyLoc, diag::error_strong_property)
<< property->getDeclName() << Ivar->getDeclName();
- // Fall thru - see previous comment
+ // 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 *PIDecl =
+ ObjCPropertyImplDecl::Create(Context, CurContext, AtLoc, PropertyLoc,
+ property,
+ (Synthesize ?
+ ObjCPropertyImplDecl::Synthesize
: ObjCPropertyImplDecl::Dynamic),
Ivar);
if (IC) {
if (Synthesize)
- if (ObjCPropertyImplDecl *PPIDecl =
+ if (ObjCPropertyImplDecl *PPIDecl =
IC->FindPropertyImplIvarDecl(PropertyIvar)) {
- Diag(PropertyLoc, diag::error_duplicate_ivar_use)
- << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier()
+ Diag(PropertyLoc, diag::error_duplicate_ivar_use)
+ << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier()
<< PropertyIvar;
Diag(PPIDecl->getLocation(), diag::note_previous_use);
}
-
- if (ObjCPropertyImplDecl *PPIDecl
+
+ if (ObjCPropertyImplDecl *PPIDecl
= IC->FindPropertyImplDecl(PropertyId)) {
Diag(PropertyLoc, diag::error_property_implemented) << PropertyId;
Diag(PPIDecl->getLocation(), diag::note_previous_declaration);
return DeclPtrTy();
}
IC->addPropertyImplementation(PIDecl);
- }
- else {
+ } else {
if (Synthesize)
- if (ObjCPropertyImplDecl *PPIDecl =
+ if (ObjCPropertyImplDecl *PPIDecl =
CatImplClass->FindPropertyImplIvarDecl(PropertyIvar)) {
- Diag(PropertyLoc, diag::error_duplicate_ivar_use)
- << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier()
+ Diag(PropertyLoc, diag::error_duplicate_ivar_use)
+ << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier()
<< PropertyIvar;
Diag(PPIDecl->getLocation(), diag::note_previous_use);
}
-
- if (ObjCPropertyImplDecl *PPIDecl =
+
+ if (ObjCPropertyImplDecl *PPIDecl =
CatImplClass->FindPropertyImplDecl(PropertyId)) {
Diag(PropertyLoc, diag::error_property_implemented) << PropertyId;
Diag(PPIDecl->getLocation(), diag::note_previous_declaration);
return DeclPtrTy();
- }
+ }
CatImplClass->addPropertyImplementation(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;
}
/// 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,
+void Sema::ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart,
IdentifierInfo *ClassName,
llvm::SmallVectorImpl<DeclPtrTy> &Decls) {
// Check that ClassName is a valid class
@@ -2126,7 +2228,7 @@ void Sema::ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart,
Diag(DeclStart, diag::err_atdef_nonfragile_interface);
return;
}
-
+
// Collect the instance variables
llvm::SmallVector<FieldDecl*, 32> RecFields;
Context.CollectObjCIvars(Class, RecFields);
@@ -2139,7 +2241,7 @@ void Sema::ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart,
ID->getBitWidth());
Decls.push_back(Sema::DeclPtrTy::make(FD));
}
-
+
// Introduce all of these fields into the appropriate scope.
for (llvm::SmallVectorImpl<DeclPtrTy>::iterator D = Decls.begin();
D != Decls.end(); ++D) {
diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp
new file mode 100644
index 0000000..bdd00b8
--- /dev/null
+++ b/lib/Sema/SemaExceptionSpec.cpp
@@ -0,0 +1,320 @@
+//===--- SemaExceptionSpec.cpp - C++ Exception Specifications ---*- 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++ exception specification testing.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Sema.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
+#include "llvm/ADT/SmallPtrSet.h"
+
+namespace clang {
+
+static const FunctionProtoType *GetUnderlyingFunction(QualType T)
+{
+ if (const PointerType *PtrTy = T->getAs<PointerType>())
+ T = PtrTy->getPointeeType();
+ else if (const ReferenceType *RefTy = T->getAs<ReferenceType>())
+ T = RefTy->getPointeeType();
+ else if (const MemberPointerType *MPTy = T->getAs<MemberPointerType>())
+ T = MPTy->getPointeeType();
+ return T->getAs<FunctionProtoType>();
+}
+
+/// 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. But
+ // perhaps RequireCompleteType itself should contain this logic?
+
+ // C++ 15.4p2: A type denoted in an exception-specification shall not denote
+ // an incomplete type.
+ if (RequireCompleteType(Range.getBegin(), T,
+ PDiag(diag::err_incomplete_in_exception_spec) << /*direct*/0 << Range))
+ return true;
+
+ // C++ 15.4p2: A type denoted in an exception-specification shall not denote
+ // an incomplete type a pointer or reference to an incomplete type, other
+ // than (cv) void*.
+ int kind;
+ if (const PointerType* IT = T->getAs<PointerType>()) {
+ T = IT->getPointeeType();
+ kind = 1;
+ } else if (const ReferenceType* IT = T->getAs<ReferenceType>()) {
+ T = IT->getPointeeType();
+ kind = 2;
+ } else
+ return false;
+
+ if (!T->isVoidType() && RequireCompleteType(Range.getBegin(), T,
+ PDiag(diag::err_incomplete_in_exception_spec) << /*direct*/kind << Range))
+ return true;
+
+ 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->getAs<PointerType>())
+ T = PT->getPointeeType();
+ else if (const MemberPointerType *PT = T->getAs<MemberPointerType>())
+ T = PT->getPointeeType();
+ else
+ return false;
+
+ const FunctionProtoType *FnT = T->getAs<FunctionProtoType>();
+ if (!FnT)
+ return false;
+
+ return FnT->hasExceptionSpec();
+}
+
+/// CheckEquivalentExceptionSpec - Check if the two types have equivalent
+/// exception specifications. Exception specifications are equivalent if
+/// they allow exactly the same set of exception types. It does not matter how
+/// that is achieved. See C++ [except.spec]p2.
+bool Sema::CheckEquivalentExceptionSpec(
+ const FunctionProtoType *Old, SourceLocation OldLoc,
+ const FunctionProtoType *New, SourceLocation NewLoc) {
+ return CheckEquivalentExceptionSpec(diag::err_mismatched_exception_spec,
+ diag::note_previous_declaration,
+ Old, OldLoc, New, NewLoc);
+}
+
+/// CheckEquivalentExceptionSpec - Check if the two types have equivalent
+/// exception specifications. Exception specifications are equivalent if
+/// they allow exactly the same set of exception types. It does not matter how
+/// that is achieved. See C++ [except.spec]p2.
+bool Sema::CheckEquivalentExceptionSpec(
+ const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
+ const FunctionProtoType *Old, SourceLocation OldLoc,
+ const FunctionProtoType *New, SourceLocation NewLoc) {
+ bool OldAny = !Old->hasExceptionSpec() || Old->hasAnyExceptionSpec();
+ bool NewAny = !New->hasExceptionSpec() || New->hasAnyExceptionSpec();
+ if (OldAny && NewAny)
+ return false;
+ if (OldAny || NewAny) {
+ Diag(NewLoc, DiagID);
+ if (NoteID.getDiagID() != 0)
+ Diag(OldLoc, NoteID);
+ return true;
+ }
+
+ bool Success = true;
+ // Both have a definite exception spec. Collect the first set, then compare
+ // to the second.
+ llvm::SmallPtrSet<CanQualType, 8> OldTypes, NewTypes;
+ for (FunctionProtoType::exception_iterator I = Old->exception_begin(),
+ E = Old->exception_end(); I != E; ++I)
+ OldTypes.insert(Context.getCanonicalType(*I).getUnqualifiedType());
+
+ for (FunctionProtoType::exception_iterator I = New->exception_begin(),
+ E = New->exception_end(); I != E && Success; ++I) {
+ CanQualType TypePtr = Context.getCanonicalType(*I).getUnqualifiedType();
+ if(OldTypes.count(TypePtr))
+ NewTypes.insert(TypePtr);
+ else
+ Success = false;
+ }
+
+ Success = Success && OldTypes.size() == NewTypes.size();
+
+ if (Success) {
+ return false;
+ }
+ Diag(NewLoc, DiagID);
+ if (NoteID.getDiagID() != 0)
+ Diag(OldLoc, NoteID);
+ return true;
+}
+
+/// CheckExceptionSpecSubset - Check whether the second function type's
+/// exception specification is a subset (or equivalent) of the first function
+/// type. This is used by override and pointer assignment checks.
+bool Sema::CheckExceptionSpecSubset(
+ const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
+ const FunctionProtoType *Superset, SourceLocation SuperLoc,
+ const FunctionProtoType *Subset, SourceLocation SubLoc) {
+ // FIXME: As usual, we could be more specific in our error messages, but
+ // that better waits until we've got types with source locations.
+
+ if (!SubLoc.isValid())
+ SubLoc = SuperLoc;
+
+ // If superset contains everything, we're done.
+ if (!Superset->hasExceptionSpec() || Superset->hasAnyExceptionSpec())
+ return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc);
+
+ // It does not. If the subset contains everything, we've failed.
+ if (!Subset->hasExceptionSpec() || Subset->hasAnyExceptionSpec()) {
+ Diag(SubLoc, DiagID);
+ if (NoteID.getDiagID() != 0)
+ Diag(SuperLoc, NoteID);
+ return true;
+ }
+
+ // Neither contains everything. Do a proper comparison.
+ for (FunctionProtoType::exception_iterator SubI = Subset->exception_begin(),
+ SubE = Subset->exception_end(); SubI != SubE; ++SubI) {
+ // Take one type from the subset.
+ QualType CanonicalSubT = Context.getCanonicalType(*SubI);
+ // Unwrap pointers and references so that we can do checks within a class
+ // hierarchy. Don't unwrap member pointers; they don't have hierarchy
+ // conversions on the pointee.
+ bool SubIsPointer = false;
+ if (const ReferenceType *RefTy = CanonicalSubT->getAs<ReferenceType>())
+ CanonicalSubT = RefTy->getPointeeType();
+ if (const PointerType *PtrTy = CanonicalSubT->getAs<PointerType>()) {
+ CanonicalSubT = PtrTy->getPointeeType();
+ SubIsPointer = true;
+ }
+ bool SubIsClass = CanonicalSubT->isRecordType();
+ CanonicalSubT = CanonicalSubT.getUnqualifiedType();
+
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
+ /*DetectVirtual=*/false);
+
+ bool Contained = false;
+ // Make sure it's in the superset.
+ for (FunctionProtoType::exception_iterator SuperI =
+ Superset->exception_begin(), SuperE = Superset->exception_end();
+ SuperI != SuperE; ++SuperI) {
+ QualType CanonicalSuperT = Context.getCanonicalType(*SuperI);
+ // SubT must be SuperT or derived from it, or pointer or reference to
+ // such types.
+ if (const ReferenceType *RefTy = CanonicalSuperT->getAs<ReferenceType>())
+ CanonicalSuperT = RefTy->getPointeeType();
+ if (SubIsPointer) {
+ if (const PointerType *PtrTy = CanonicalSuperT->getAs<PointerType>())
+ CanonicalSuperT = PtrTy->getPointeeType();
+ else {
+ continue;
+ }
+ }
+ CanonicalSuperT = CanonicalSuperT.getUnqualifiedType();
+ // If the types are the same, move on to the next type in the subset.
+ if (CanonicalSubT == CanonicalSuperT) {
+ Contained = true;
+ break;
+ }
+
+ // Otherwise we need to check the inheritance.
+ if (!SubIsClass || !CanonicalSuperT->isRecordType())
+ continue;
+
+ Paths.clear();
+ if (!IsDerivedFrom(CanonicalSubT, CanonicalSuperT, Paths))
+ continue;
+
+ if (Paths.isAmbiguous(CanonicalSuperT))
+ continue;
+
+ if (FindInaccessibleBase(CanonicalSubT, CanonicalSuperT, Paths, true))
+ continue;
+
+ Contained = true;
+ break;
+ }
+ if (!Contained) {
+ Diag(SubLoc, DiagID);
+ if (NoteID.getDiagID() != 0)
+ Diag(SuperLoc, NoteID);
+ return true;
+ }
+ }
+ // We've run half the gauntlet.
+ return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc);
+}
+
+static bool CheckSpecForTypesEquivalent(Sema &S,
+ const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
+ QualType Target, SourceLocation TargetLoc,
+ QualType Source, SourceLocation SourceLoc)
+{
+ const FunctionProtoType *TFunc = GetUnderlyingFunction(Target);
+ if (!TFunc)
+ return false;
+ const FunctionProtoType *SFunc = GetUnderlyingFunction(Source);
+ if (!SFunc)
+ return false;
+
+ return S.CheckEquivalentExceptionSpec(DiagID, NoteID, TFunc, TargetLoc,
+ SFunc, SourceLoc);
+}
+
+/// CheckParamExceptionSpec - Check if the parameter and return types of the
+/// two functions have equivalent exception specs. This is part of the
+/// assignment and override compatibility check. We do not check the parameters
+/// of parameter function pointers recursively, as no sane programmer would
+/// even be able to write such a function type.
+bool Sema::CheckParamExceptionSpec(const PartialDiagnostic & NoteID,
+ const FunctionProtoType *Target, SourceLocation TargetLoc,
+ const FunctionProtoType *Source, SourceLocation SourceLoc)
+{
+ if (CheckSpecForTypesEquivalent(*this,
+ PDiag(diag::err_deep_exception_specs_differ) << 0, 0,
+ Target->getResultType(), TargetLoc,
+ Source->getResultType(), SourceLoc))
+ return true;
+
+ // We shouldn't even be testing this unless the arguments are otherwise
+ // compatible.
+ assert(Target->getNumArgs() == Source->getNumArgs() &&
+ "Functions have different argument counts.");
+ for (unsigned i = 0, E = Target->getNumArgs(); i != E; ++i) {
+ if (CheckSpecForTypesEquivalent(*this,
+ PDiag(diag::err_deep_exception_specs_differ) << 1, 0,
+ Target->getArgType(i), TargetLoc,
+ Source->getArgType(i), SourceLoc))
+ return true;
+ }
+ return false;
+}
+
+bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType)
+{
+ // First we check for applicability.
+ // Target type must be a function, function pointer or function reference.
+ const FunctionProtoType *ToFunc = GetUnderlyingFunction(ToType);
+ if (!ToFunc)
+ return false;
+
+ // SourceType must be a function or function pointer.
+ const FunctionProtoType *FromFunc = GetUnderlyingFunction(From->getType());
+ if (!FromFunc)
+ return false;
+
+ // Now we've got the correct types on both sides, check their compatibility.
+ // This means that the source of the conversion can only throw a subset of
+ // the exceptions of the target, and any exception specs on arguments or
+ // return types must be equivalent.
+ return CheckExceptionSpecSubset(diag::err_incompatible_exception_specs,
+ 0, ToFunc, From->getSourceRange().getBegin(),
+ FromFunc, SourceLocation());
+}
+
+bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
+ const CXXMethodDecl *Old) {
+ return CheckExceptionSpecSubset(diag::err_override_exception_spec,
+ diag::note_overridden_virtual_function,
+ Old->getType()->getAs<FunctionProtoType>(),
+ Old->getLocation(),
+ New->getType()->getAs<FunctionProtoType>(),
+ New->getLocation());
+}
+
+} // end namespace clang
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index a5e5083..d8e49c7 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -14,18 +14,20 @@
#include "Sema.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.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/PartialDiagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/LiteralSupport.h"
+#include "clang/Lex/Preprocessor.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.
///
@@ -44,12 +46,12 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc) {
// 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)) {
@@ -57,14 +59,14 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc) {
// ObjCImplementationDecl.
if (ObjCImplementationDecl *Impl
= dyn_cast<ObjCImplementationDecl>(MD->getParent())) {
-
+
MD = Impl->getClassInterface()->getMethod(MD->getSelector(),
MD->isInstanceMethod());
isSilenced |= MD && MD->getAttr<DeprecatedAttr>();
}
}
}
-
+
if (!isSilenced)
Diag(Loc, diag::warn_deprecated) << D->getDeclName();
}
@@ -88,18 +90,17 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc) {
}
/// DiagnoseSentinelCalls - This routine checks on method dispatch calls
-/// (and other functions in future), which have been declared with sentinel
+/// (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)
-{
+ Expr **Args, unsigned NumArgs) {
const SentinelAttr *attr = D->getAttr<SentinelAttr>();
- if (!attr)
+ 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;
@@ -116,8 +117,7 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
}
warnNotEnoughArgs = (P != E || i >= NumArgs);
isMethod = 1;
- }
- else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ } 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) {
@@ -127,14 +127,13 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
++i;
}
warnNotEnoughArgs = (P != E || i >= NumArgs);
- }
- else if (VarDecl *V = dyn_cast<VarDecl>(D)) {
+ } 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();
+ const FunctionType *FT = Ty->isFunctionPointerType()
+ ? Ty->getAs<PointerType>()->getPointeeType()->getAs<FunctionType>()
+ : Ty->getAs<BlockPointerType>()->getPointeeType()->getAs<FunctionType>();
if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT)) {
unsigned NumArgsInProto = Proto->getNumArgs();
unsigned k;
@@ -148,11 +147,9 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
}
if (Ty->isBlockPointerType())
isMethod = 2;
- }
- else
+ } else
return;
- }
- else
+ } else
return;
if (warnNotEnoughArgs) {
@@ -176,7 +173,8 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
}
Expr *sentinelExpr = Args[sentinel];
if (sentinelExpr && (!sentinelExpr->getType()->isPointerType() ||
- !sentinelExpr->isNullPointerConstant(Context))) {
+ !sentinelExpr->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNull))) {
Diag(Loc, diag::warn_missing_sentinel) << isMethod;
Diag(D->getLocation(), diag::note_sentinel_here) << isMethod;
}
@@ -198,7 +196,8 @@ void Sema::DefaultFunctionArrayConversion(Expr *&E) {
assert(!Ty.isNull() && "DefaultFunctionArrayConversion - missing type");
if (Ty->isFunctionType())
- ImpCastExprToType(E, Context.getPointerType(Ty));
+ ImpCastExprToType(E, Context.getPointerType(Ty),
+ CastExpr::CK_FunctionToPointerDecay);
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
@@ -213,54 +212,20 @@ void Sema::DefaultFunctionArrayConversion(Expr *&E) {
//
if (getLangOptions().C99 || getLangOptions().CPlusPlus ||
E->isLvalue(Context) == Expr::LV_Valid)
- ImpCastExprToType(E, Context.getArrayDecayedType(Ty));
+ ImpCastExprToType(E, Context.getArrayDecayedType(Ty),
+ CastExpr::CK_ArrayToPointerDecay);
}
}
-/// \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
+/// 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
@@ -274,33 +239,33 @@ Expr *Sema::UsualUnaryConversions(Expr *&Expr) {
// value is converted to an int; otherwise, it is converted to an
// unsigned int. These are called the integer promotions. All
// other types are unchanged by the integer promotions.
+ QualType PTy = Context.isPromotableBitField(Expr);
+ if (!PTy.isNull()) {
+ ImpCastExprToType(Expr, PTy);
+ return Expr;
+ }
if (Ty->isPromotableIntegerType()) {
- ImpCastExprToType(Expr, Context.IntTy);
+ QualType PT = Context.getPromotedIntegerType(Ty);
+ ImpCastExprToType(Expr, PT);
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
+/// 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 (const BuiltinType *BT = Ty->getAs<BuiltinType>())
if (BT->getKind() == BuiltinType::Float)
return ImpCastExprToType(Expr, Context.DoubleTy);
-
+
UsualUnaryConversions(Expr);
}
@@ -310,14 +275,14 @@ void Sema::DefaultArgumentPromotion(Expr *&Expr) {
/// 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;
@@ -328,7 +293,7 @@ bool Sema::DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT) {
/// 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
+/// 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.
@@ -339,11 +304,11 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr,
UsualUnaryConversions(rhsExpr);
- // For conversion purposes, we ignore any qualifiers.
+ // For conversion purposes, we ignore any qualifiers.
// For example, "const float" and "float" are equivalent.
QualType lhs =
Context.getCanonicalType(lhsExpr->getType()).getUnqualifiedType();
- QualType rhs =
+ QualType rhs =
Context.getCanonicalType(rhsExpr->getType()).getUnqualifiedType();
// If both types are identical, no conversion is needed.
@@ -356,159 +321,20 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr,
return lhs;
// Perform bitfield promotions.
- QualType LHSBitfieldPromoteTy = isPromotableBitField(lhsExpr, Context);
+ QualType LHSBitfieldPromoteTy = Context.isPromotableBitField(lhsExpr);
if (!LHSBitfieldPromoteTy.isNull())
lhs = LHSBitfieldPromoteTy;
- QualType RHSBitfieldPromoteTy = isPromotableBitField(rhsExpr, Context);
+ QualType RHSBitfieldPromoteTy = Context.isPromotableBitField(rhsExpr);
if (!RHSBitfieldPromoteTy.isNull())
rhs = RHSBitfieldPromoteTy;
- QualType destType = UsualArithmeticConversionsType(lhs, rhs);
+ QualType destType = Context.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
//===----------------------------------------------------------------------===//
@@ -546,9 +372,9 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) {
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(),
+ return Owned(StringLiteral::Create(Context, Literal.GetString(),
Literal.GetStringLength(),
Literal.AnyWide, StrTy,
&StringTokLocs[0],
@@ -569,7 +395,7 @@ static bool ShouldSnapshotBlockValueReference(BlockSemaInfo *CurBlock,
// 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;
@@ -580,7 +406,7 @@ static bool ShouldSnapshotBlockValueReference(BlockSemaInfo *CurBlock,
if (const VarDecl *Var = dyn_cast<VarDecl>(VD))
if (!Var->hasLocalStorage())
return false;
-
+
// Blocks that have these can't be constant.
CurBlock->hasBlockDeclRefExprs = true;
@@ -594,15 +420,15 @@ static bool ShouldSnapshotBlockValueReference(BlockSemaInfo *CurBlock,
// 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,
@@ -628,35 +454,35 @@ Sema::BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc,
const CXXScopeSpec *SS) {
if (Context.getCanonicalType(Ty) == Context.UndeducedAutoTy) {
Diag(Loc,
- diag::err_auto_variable_cannot_appear_in_own_initializer)
+ diag::err_auto_variable_cannot_appear_in_own_initializer)
<< D->getDeclName();
return ExprError();
}
-
+
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) {
if (const FunctionDecl *FD = MD->getParent()->isLocalClass()) {
if (VD->hasLocalStorage() && VD->getDeclContext() != CurContext) {
- Diag(Loc, diag::err_reference_to_local_var_in_enclosing_function)
+ Diag(Loc, diag::err_reference_to_local_var_in_enclosing_function)
<< D->getIdentifier() << FD->getDeclName();
- Diag(D->getLocation(), diag::note_local_variable_declared_here)
+ Diag(D->getLocation(), diag::note_local_variable_declared_here)
<< D->getIdentifier();
return ExprError();
}
}
}
}
-
+
MarkDeclarationReferenced(Loc, D);
-
+
Expr *E;
if (SS && !SS->isEmpty()) {
- E = new (Context) QualifiedDeclRefExpr(D, Ty, Loc, TypeDependent,
+ E = new (Context) QualifiedDeclRefExpr(D, Ty, Loc, TypeDependent,
ValueDependent, SS->getRange(),
static_cast<NestedNameSpecifier *>(SS->getScopeRep()));
} else
E = new (Context) DeclRefExpr(D, Ty, Loc, TypeDependent, ValueDependent);
-
+
return Owned(E);
}
@@ -665,14 +491,14 @@ Sema::BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc,
/// is Record.
static Decl *getObjectForAnonymousRecordDecl(ASTContext &Context,
RecordDecl *Record) {
- assert(Record->isAnonymousStructOrUnion() &&
+ 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(),
+ for (DeclContext::decl_iterator D = Ctx->decls_begin(),
DEnd = Ctx->decls_end();
D != DEnd; ++D) {
if (*D == Record) {
@@ -721,7 +547,7 @@ VarDecl *Sema::BuildAnonymousStructUnionMemberPath(FieldDecl *Field,
break;
}
Ctx = Ctx->getParent();
- } while (Ctx->isRecord() &&
+ } while (Ctx->isRecord() &&
cast<RecordDecl>(Ctx)->isAnonymousStructOrUnion());
return BaseObject;
@@ -733,7 +559,7 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
Expr *BaseObjectExpr,
SourceLocation OpLoc) {
llvm::SmallVector<FieldDecl *, 4> AnonFields;
- VarDecl *BaseObject = BuildAnonymousStructUnionMemberPath(Field,
+ VarDecl *BaseObject = BuildAnonymousStructUnionMemberPath(Field,
AnonFields);
// Build the expression that refers to the base object, from
@@ -741,7 +567,7 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
// of the anonymous union objects and, eventually, the field we
// found via name lookup.
bool BaseObjectIsPointer = false;
- unsigned ExtraQuals = 0;
+ Qualifiers BaseQuals;
if (BaseObject) {
// BaseObject is an anonymous struct/union variable (and is,
// therefore, not part of another non-anonymous record).
@@ -749,29 +575,30 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
MarkDeclarationReferenced(Loc, BaseObject);
BaseObjectExpr = new (Context) DeclRefExpr(BaseObject,BaseObject->getType(),
SourceLocation());
- ExtraQuals
- = Context.getCanonicalType(BaseObject->getType()).getCVRQualifiers();
+ BaseQuals
+ = Context.getCanonicalType(BaseObject->getType()).getQualifiers();
} 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()) {
+ if (const PointerType *ObjectPtr = ObjectType->getAs<PointerType>()) {
BaseObjectIsPointer = true;
ObjectType = ObjectPtr->getPointeeType();
}
- ExtraQuals = Context.getCanonicalType(ObjectType).getCVRQualifiers();
+ BaseQuals
+ = Context.getCanonicalType(ObjectType).getQualifiers();
} 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
+ QualType AnonFieldType
= Context.getTagDeclType(
cast<RecordDecl>(AnonFields.back()->getDeclContext()));
QualType ThisType = Context.getTagDeclType(MD->getParent());
- if ((Context.getCanonicalType(AnonFieldType)
+ if ((Context.getCanonicalType(AnonFieldType)
== Context.getCanonicalType(ThisType)) ||
IsDerivedFrom(ThisType, AnonFieldType)) {
// Our base object expression is "this".
@@ -783,10 +610,10 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
return ExprError(Diag(Loc,diag::err_invalid_member_use_in_static_method)
<< Field->getDeclName());
}
- ExtraQuals = MD->getTypeQualifiers();
+ BaseQuals = Qualifiers::fromCVRMask(MD->getTypeQualifiers());
}
- if (!BaseObjectExpr)
+ if (!BaseObjectExpr)
return ExprError(Diag(Loc, diag::err_invalid_non_static_member_use)
<< Field->getDeclName());
}
@@ -794,20 +621,35 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
// Build the implicit member references to the field of the
// anonymous struct/union.
Expr *Result = BaseObjectExpr;
+ Qualifiers ResultQuals = BaseQuals;
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);
- }
+ Qualifiers MemberTypeQuals =
+ Context.getCanonicalType(MemberType).getQualifiers();
+
+ // CVR attributes from the base are picked up by members,
+ // except that 'mutable' members don't pick up 'const'.
+ if ((*FI)->isMutable())
+ ResultQuals.removeConst();
+
+ // GC attributes are never picked up by members.
+ ResultQuals.removeObjCGCAttr();
+
+ // TR 18037 does not allow fields to be declared with address spaces.
+ assert(!MemberTypeQuals.hasAddressSpace());
+
+ Qualifiers NewQuals = ResultQuals + MemberTypeQuals;
+ if (NewQuals != MemberTypeQuals)
+ MemberType = Context.getQualifiedType(MemberType, NewQuals);
+
MarkDeclarationReferenced(Loc, *FI);
+ // FIXME: Might this end up being a qualified name?
Result = new (Context) MemberExpr(Result, BaseObjectIsPointer, *FI,
OpLoc, MemberType);
BaseObjectIsPointer = false;
- ExtraQuals = Context.getCanonicalType(MemberType).getCVRQualifiers();
+ ResultQuals = NewQuals;
}
return Owned(Result);
@@ -835,7 +677,7 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
Sema::OwningExprResult
Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
DeclarationName Name, bool HasTrailingLParen,
- const CXXScopeSpec *SS,
+ const CXXScopeSpec *SS,
bool isAddressOfOperand) {
// Could be enum-constant, value decl, instance variable, etc.
if (SS && SS->isInvalid())
@@ -848,12 +690,13 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
// 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())));
+ Loc, SS->getRange(),
+ static_cast<NestedNameSpecifier *>(SS->getScopeRep()),
+ isAddressOfOperand));
}
- LookupResult Lookup = LookupParsedName(S, SS, Name, LookupOrdinaryName,
- false, true, Loc);
+ LookupResult Lookup;
+ LookupParsedName(Lookup, S, SS, Name, LookupOrdinaryName, false, true, Loc);
if (Lookup.isAmbiguous()) {
DiagnoseAmbiguousLookup(Lookup, Name, Loc,
@@ -861,8 +704,8 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
: SourceRange());
return ExprError();
}
-
- NamedDecl *D = Lookup.getAsDecl();
+
+ NamedDecl *D = Lookup.getAsSingleDecl(Context);
// If this reference is in an Objective-C method, then ivar lookup happens as
// well.
@@ -870,8 +713,8 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
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
+ // 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();
@@ -880,12 +723,12 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
// 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.
@@ -901,15 +744,15 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
// 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);
+ OwningExprResult SelfExpr = ActOnIdentifierExpr(S, SourceLocation(),
+ II, false);
MarkDeclarationReferenced(Loc, IV);
- return Owned(new (Context)
- ObjCIvarRefExpr(IV, IV->getType(), Loc,
+ return Owned(new (Context)
+ ObjCIvarRefExpr(IV, IV->getType(), Loc,
SelfExpr.takeAs<Expr>(), true, true));
}
}
- }
- else if (getCurMethodDecl()->isInstanceMethod()) {
+ } else if (getCurMethodDecl()->isInstanceMethod()) {
// We should warn if a local variable hides an ivar.
ObjCInterfaceDecl *IFace = getCurMethodDecl()->getClassInterface();
ObjCInterfaceDecl *ClassDeclared;
@@ -922,10 +765,10 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
// 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()));
+ T = Context.getObjCObjectPointerType(Context.getObjCInterfaceType(
+ getCurMethodDecl()->getClassInterface()));
else
T = Context.getObjCClassType();
return Owned(new (Context) ObjCSuperExpr(Loc, T));
@@ -934,7 +777,7 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
// Determine whether this name might be a candidate for
// argument-dependent lookup.
- bool ADL = getLangOptions().CPlusPlus && (!SS || !SS->isSet()) &&
+ bool ADL = getLangOptions().CPlusPlus && (!SS || !SS->isSet()) &&
HasTrailingLParen;
if (ADL && D == 0) {
@@ -960,8 +803,9 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
// 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());
+ return ExprError(Diag(Loc, diag::err_no_member)
+ << Name << computeDeclContext(*SS, false)
+ << SS->getRange());
else if (Name.getNameKind() == DeclarationName::CXXOperatorName ||
Name.getNameKind() == DeclarationName::CXXConversionFunctionName)
return ExprError(Diag(Loc, diag::err_undeclared_use)
@@ -970,18 +814,18 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
return ExprError(Diag(Loc, diag::err_undeclared_var_use) << Name);
}
}
-
+
if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
// 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() &&
+ if (CheckS->isWithinElse() &&
CheckS->getControlParent()->isDeclScope(DeclPtrTy::make(Var))) {
if (Var->getType()->isBooleanType())
ExprError(Diag(Loc, diag::warn_value_always_false)
@@ -991,7 +835,7 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
<< Var->getDeclName());
break;
}
-
+
// Move up one more control parent to check again.
CheckS = CheckS->getControlParent();
if (CheckS)
@@ -1010,24 +854,66 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
QualType T = Func->getType();
QualType NoProtoType = T;
- if (const FunctionProtoType *Proto = T->getAsFunctionProtoType())
+ if (const FunctionProtoType *Proto = T->getAs<FunctionProtoType>())
NoProtoType = Context.getFunctionNoProtoType(Proto->getResultType());
return BuildDeclRefExpr(Func, NoProtoType, Loc, false, false, SS);
}
}
-
+
return BuildDeclarationNameExpr(Loc, D, HasTrailingLParen, SS, isAddressOfOperand);
}
+/// \brief Cast member's object to its own class if necessary.
+bool
+Sema::PerformObjectMemberConversion(Expr *&From, NamedDecl *Member) {
+ if (FieldDecl *FD = dyn_cast<FieldDecl>(Member))
+ if (CXXRecordDecl *RD =
+ dyn_cast<CXXRecordDecl>(FD->getDeclContext())) {
+ QualType DestType =
+ Context.getCanonicalType(Context.getTypeDeclType(RD));
+ if (DestType->isDependentType() || From->getType()->isDependentType())
+ return false;
+ QualType FromRecordType = From->getType();
+ QualType DestRecordType = DestType;
+ if (FromRecordType->getAs<PointerType>()) {
+ DestType = Context.getPointerType(DestType);
+ FromRecordType = FromRecordType->getPointeeType();
+ }
+ if (!Context.hasSameUnqualifiedType(FromRecordType, DestRecordType) &&
+ CheckDerivedToBaseConversion(FromRecordType,
+ DestRecordType,
+ From->getSourceRange().getBegin(),
+ From->getSourceRange()))
+ return true;
+ ImpCastExprToType(From, DestType, CastExpr::CK_DerivedToBase,
+ /*isLvalue=*/true);
+ }
+ return false;
+}
+
+/// \brief Build a MemberExpr AST node.
+static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow,
+ const CXXScopeSpec *SS, NamedDecl *Member,
+ SourceLocation Loc, QualType Ty) {
+ if (SS && SS->isSet())
+ return MemberExpr::Create(C, Base, isArrow,
+ (NestedNameSpecifier *)SS->getScopeRep(),
+ SS->getRange(), Member, Loc,
+ // FIXME: Explicit template argument lists
+ false, SourceLocation(), 0, 0, SourceLocation(),
+ Ty);
+
+ return new (C) MemberExpr(Base, isArrow, Member, Loc, Ty);
+}
/// \brief Complete semantic analysis for a reference to the given declaration.
Sema::OwningExprResult
Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D,
bool HasTrailingLParen,
- const CXXScopeSpec *SS,
+ const CXXScopeSpec *SS,
bool isAddressOfOperand) {
assert(D && "Cannot refer to a NULL declaration");
DeclarationName Name = D->getDeclName();
-
+
// 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.
@@ -1060,7 +946,7 @@ Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D,
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) {
if (!MD->isStatic()) {
- // C++ [class.mfct.nonstatic]p2:
+ // 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
@@ -1072,45 +958,74 @@ Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D,
Ctx = FD->getDeclContext();
MemberType = FD->getType();
- if (const ReferenceType *RefType = MemberType->getAsReferenceType())
+ if (const ReferenceType *RefType = MemberType->getAs<ReferenceType>())
MemberType = RefType->getPointeeType();
- else if (!FD->isMutable()) {
- unsigned combinedQualifiers
- = MemberType.getCVRQualifiers() | MD->getTypeQualifiers();
- MemberType = MemberType.getQualifiedType(combinedQualifiers);
- }
+ else if (!FD->isMutable())
+ MemberType
+ = Context.getQualifiedType(MemberType,
+ Qualifiers::fromCVRMask(MD->getTypeQualifiers()));
} else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
if (!Method->isStatic()) {
Ctx = Method->getParent();
MemberType = Method->getType();
}
- } else if (OverloadedFunctionDecl *Ovl
+ } else if (FunctionTemplateDecl *FunTmpl
+ = dyn_cast<FunctionTemplateDecl>(D)) {
+ if (CXXMethodDecl *Method
+ = dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl())) {
+ if (!Method->isStatic()) {
+ Ctx = Method->getParent();
+ MemberType = Context.OverloadTy;
+ }
+ }
+ } else if (OverloadedFunctionDecl *Ovl
= dyn_cast<OverloadedFunctionDecl>(D)) {
- for (OverloadedFunctionDecl::function_iterator
+ // FIXME: We need an abstraction for iterating over one or more function
+ // templates or functions. This code is far too repetitive!
+ 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;
- }
+ CXXMethodDecl *DMethod = 0;
+ if (FunctionTemplateDecl *FunTmpl
+ = dyn_cast<FunctionTemplateDecl>(*Func))
+ DMethod = dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl());
+ else
+ DMethod = dyn_cast<CXXMethodDecl>(*Func);
+
+ if (DMethod && !DMethod->isStatic()) {
+ Ctx = DMethod->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)
+ 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));
MarkDeclarationReferenced(Loc, D);
- return Owned(new (Context) MemberExpr(This, true, D,
- Loc, MemberType));
+ if (PerformObjectMemberConversion(This, D))
+ return ExprError();
+
+ bool ShouldCheckUse = true;
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
+ // Don't diagnose the use of a virtual member function unless it's
+ // explicitly qualified.
+ if (MD->isVirtual() && (!SS || !SS->isSet()))
+ ShouldCheckUse = false;
+ }
+
+ if (ShouldCheckUse && DiagnoseUseOfDecl(D, Loc))
+ return ExprError();
+ return Owned(BuildMemberExpr(Context, This, true, SS, D,
+ Loc, MemberType));
}
}
}
@@ -1145,13 +1060,18 @@ Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D,
else if (TemplateDecl *Template = dyn_cast<TemplateDecl>(D))
return BuildDeclRefExpr(Template, Context.OverloadTy, Loc,
false, false, SS);
+ else if (UnresolvedUsingDecl *UD = dyn_cast<UnresolvedUsingDecl>(D))
+ return BuildDeclRefExpr(UD, Context.DependentTy, Loc,
+ /*TypeDependent=*/true,
+ /*ValueDependent=*/true, 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.
- bool ADL = getLangOptions().CPlusPlus && (!SS || !SS->isSet()) &&
+ bool ADL = getLangOptions().CPlusPlus && (!SS || !SS->isSet()) &&
HasTrailingLParen;
if (!(ADL && isa<FunctionDecl>(VD)) && DiagnoseUseOfDecl(VD, Loc))
return ExprError();
@@ -1177,9 +1097,9 @@ Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D,
// This is to record that a 'const' was actually synthesize and added.
bool constAdded = !ExprTy.isConstQualified();
// Variable will be bound by-copy, make it const within the closure.
-
+
ExprTy.addConst();
- return Owned(new (Context) BlockDeclRefExpr(VD, ExprTy, Loc, false,
+ return Owned(new (Context) BlockDeclRefExpr(VD, ExprTy, Loc, false,
constAdded));
}
// If this reference is not in a block or if the referenced variable is
@@ -1189,7 +1109,7 @@ Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D,
bool ValueDependent = false;
if (getLangOptions().CPlusPlus) {
// C++ [temp.dep.expr]p3:
- // An id-expression is type-dependent if it contains:
+ // An id-expression is type-dependent if it contains:
// - an identifier that was declared with a dependent type,
if (VD->getType()->isDependentType())
TypeDependent = true;
@@ -1226,7 +1146,7 @@ Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D,
// - a constant with integral or enumeration type and is
// initialized with an expression that is value-dependent
else if (const VarDecl *Dcl = dyn_cast<VarDecl>(VD)) {
- if (Dcl->getType().getCVRQualifiers() == QualType::Const &&
+ if (Dcl->getType().getCVRQualifiers() == Qualifiers::Const &&
Dcl->getInit()) {
ValueDependent = Dcl->getInit()->isValueDependent();
}
@@ -1250,21 +1170,24 @@ Sema::OwningExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc,
// 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 {
+
+ Decl *currentDecl = getCurFunctionOrMethodDecl();
+ if (!currentDecl) {
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;
+ currentDecl = Context.getTranslationUnitDecl();
}
+ QualType ResTy;
+ if (cast<DeclContext>(currentDecl)->isDependentContext()) {
+ ResTy = Context.DependentTy;
+ } else {
+ unsigned Length =
+ PredefinedExpr::ComputeName(Context, IT, currentDecl).length();
- llvm::APInt LengthI(32, Length + 1);
- QualType ResTy = Context.CharTy.getQualifiedType(QualType::Const);
- ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal, 0);
+ llvm::APInt LengthI(32, Length + 1);
+ ResTy = Context.CharTy.withConst();
+ ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal, 0);
+ }
return Owned(new (Context) PredefinedExpr(Loc, ResTy, IT));
}
@@ -1304,7 +1227,7 @@ Action::OwningExprResult Sema::ActOnNumericConstant(const Token &Tok) {
// Get the spelling of the token, which eliminates trigraphs, etc.
unsigned ActualLength = PP.getSpelling(Tok, ThisTokBegin);
- NumericLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength,
+ NumericLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength,
Tok.getLocation(), PP);
if (Literal.hadError)
return ExprError();
@@ -1417,7 +1340,7 @@ Action::OwningExprResult Sema::ActOnNumericConstant(const Token &Tok) {
// If this is an imaginary literal, create the ImaginaryLiteral wrapper.
if (Literal.isImaginary)
- Res = new (Context) ImaginaryLiteral(Res,
+ Res = new (Context) ImaginaryLiteral(Res,
Context.getComplexType(Res->getType()));
return Owned(Res);
@@ -1446,27 +1369,27 @@ bool Sema::CheckSizeOfAlignOfOperand(QualType exprType,
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))
+ isSizeof ? diag::err_sizeof_incomplete_type :
+ PDiag(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;
}
@@ -1474,7 +1397,7 @@ bool Sema::CheckAlignOfExpr(Expr *E, SourceLocation OpLoc,
const SourceRange &ExprRange) {
E = E->IgnoreParens();
- // alignof decl is always ok.
+ // alignof decl is always ok.
if (isa<DeclRefExpr>(E))
return false;
@@ -1490,15 +1413,15 @@ bool Sema::CheckAlignOfExpr(Expr *E, SourceLocation OpLoc,
// 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()))
+ if (isa<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,
+Action::OwningExprResult
+Sema::CreateSizeOfAlignOfExpr(QualType T, SourceLocation OpLoc,
bool isSizeOf, SourceRange R) {
if (T.isNull())
return ExprError();
@@ -1515,8 +1438,8 @@ Sema::CreateSizeOfAlignOfExpr(QualType T, SourceLocation OpLoc,
/// \brief Build a sizeof or alignof expression given an expression
/// operand.
-Action::OwningExprResult
-Sema::CreateSizeOfAlignOfExpr(Expr *E, SourceLocation OpLoc,
+Action::OwningExprResult
+Sema::CreateSizeOfAlignOfExpr(Expr *E, SourceLocation OpLoc,
bool isSizeOf, SourceRange R) {
// Verify that the operand is valid.
bool isInvalid = false;
@@ -1550,9 +1473,10 @@ Sema::ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType,
if (TyOrEx == 0) return ExprError();
if (isType) {
- QualType ArgTy = QualType::getFromOpaquePtr(TyOrEx);
+ // FIXME: Preserve type source info.
+ QualType ArgTy = GetTypeFromParser(TyOrEx);
return CreateSizeOfAlignOfExpr(ArgTy, OpLoc, isSizeof, ArgRange);
- }
+ }
// Get the end location.
Expr *ArgEx = (Expr *)TyOrEx;
@@ -1568,15 +1492,15 @@ Sema::ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType,
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())
+ if (const ComplexType *CT = V->getType()->getAs<ComplexType>())
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");
@@ -1588,6 +1512,8 @@ QualType Sema::CheckRealImagOperand(Expr *&V, SourceLocation Loc, bool isReal) {
Action::OwningExprResult
Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
tok::TokenKind Kind, ExprArg Input) {
+ // Since this might be a postfix expression, get rid of ParenListExprs.
+ Input = MaybeConvertParenListExprToParenExpr(S, move(Input));
Expr *Arg = (Expr *)Input.get();
UnaryOperator::Opcode Opc;
@@ -1612,9 +1538,9 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
// 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,
+ Expr *Args[2] = {
+ Arg,
+ new (Context) IntegerLiteral(llvm::APInt(Context.Target.getIntWidth(), 0,
/*isSigned=*/true), Context.IntTy, SourceLocation())
};
@@ -1646,9 +1572,7 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
}
// Determine the result type
- QualType ResultTy
- = FnDecl->getType()->getAsFunctionType()->getResultType();
- ResultTy = ResultTy.getNonReferenceType();
+ QualType ResultTy = FnDecl->getResultType().getNonReferenceType();
// Build the actual expression node.
Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(),
@@ -1657,9 +1581,17 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
Input.release();
Args[0] = Arg;
- return Owned(new (Context) CXXOperatorCallExpr(Context, OverOp, FnExpr,
- Args, 2, ResultTy,
- OpLoc));
+
+ ExprOwningPtr<CXXOperatorCallExpr>
+ TheCall(this, new (Context) CXXOperatorCallExpr(Context, OverOp,
+ FnExpr, Args, 2,
+ ResultTy, OpLoc));
+
+ if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall.get(),
+ FnDecl))
+ return ExprError();
+ return Owned(TheCall.release());
+
} else {
// We matched a built-in operator. Convert the arguments, then
// break out so that we will build the appropriate built-in
@@ -1672,11 +1604,19 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
}
}
- 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_No_Viable_Function: {
+ // No viable function; try checking this as a built-in operator, which
+ // will fail and provide a diagnostic. Then, print the overload
+ // candidates.
+ OwningExprResult Result = CreateBuiltinUnaryOp(OpLoc, Opc, move(Input));
+ assert(Result.isInvalid() &&
+ "C++ postfix-unary operator overloading is missing candidates!");
+ if (Result.isInvalid())
+ PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
+
+ return move(Result);
+ }
+
case OR_Ambiguous:
Diag(OpLoc, diag::err_ovl_ambiguous_oper)
<< UnaryOperator::getOpcodeStr(Opc)
@@ -1698,17 +1638,17 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
// 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));
+ Input = Arg;
+ return CreateBuiltinUnaryOp(OpLoc, Opc, move(Input));
}
Action::OwningExprResult
Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc,
ExprArg Idx, SourceLocation RLoc) {
+ // Since this might be a postfix expression, get rid of ParenListExprs.
+ Base = MaybeConvertParenListExprToParenExpr(S, move(Base));
+
Expr *LHSExp = static_cast<Expr*>(Base.get()),
*RHSExp = static_cast<Expr*>(Idx.get());
@@ -1720,12 +1660,12 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc,
Context.DependentTy, RLoc));
}
- if (getLangOptions().CPlusPlus &&
+ if (getLangOptions().CPlusPlus &&
(LHSExp->getType()->isRecordType() ||
LHSExp->getType()->isEnumeralType() ||
RHSExp->getType()->isRecordType() ||
RHSExp->getType()->isEnumeralType())) {
- // Add the appropriate overloaded operators (C++ [over.match.oper])
+ // Add the appropriate overloaded operators (C++ [over.match.oper])
// to the candidate set.
OverloadCandidateSet CandidateSet;
Expr *Args[2] = { LHSExp, RHSExp };
@@ -1746,7 +1686,7 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc,
// Convert the arguments.
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
if (PerformObjectArgumentInitialization(LHSExp, Method) ||
- PerformCopyInitialization(RHSExp,
+ PerformCopyInitialization(RHSExp,
FnDecl->getParamDecl(0)->getType(),
"passing"))
return ExprError();
@@ -1762,9 +1702,7 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc,
}
// Determine the result type
- QualType ResultTy
- = FnDecl->getType()->getAsFunctionType()->getResultType();
- ResultTy = ResultTy.getNonReferenceType();
+ QualType ResultTy = FnDecl->getResultType().getNonReferenceType();
// Build the actual expression node.
Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(),
@@ -1775,9 +1713,16 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc,
Idx.release();
Args[0] = LHSExp;
Args[1] = RHSExp;
- return Owned(new (Context) CXXOperatorCallExpr(Context, OO_Subscript,
- FnExpr, Args, 2,
- ResultTy, LLoc));
+
+ ExprOwningPtr<CXXOperatorCallExpr>
+ TheCall(this, new (Context) CXXOperatorCallExpr(Context, OO_Subscript,
+ FnExpr, Args, 2,
+ ResultTy, RLoc));
+ if (CheckCallReturnType(FnDecl->getResultType(), LLoc, TheCall.get(),
+ FnDecl))
+ return ExprError();
+
+ return Owned(TheCall.release());
} else {
// We matched a built-in operator. Convert the arguments, then
// break out so that we will build the appropriate built-in
@@ -1834,16 +1779,27 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc,
BaseExpr = LHSExp;
IndexExpr = RHSExp;
ResultType = Context.DependentTy;
- } else if (const PointerType *PTy = LHSTy->getAsPointerType()) {
+ } else if (const PointerType *PTy = LHSTy->getAs<PointerType>()) {
+ BaseExpr = LHSExp;
+ IndexExpr = RHSExp;
+ ResultType = PTy->getPointeeType();
+ } else if (const PointerType *PTy = RHSTy->getAs<PointerType>()) {
+ // Handle the uncommon case of "123[Ptr]".
+ BaseExpr = RHSExp;
+ IndexExpr = LHSExp;
+ ResultType = PTy->getPointeeType();
+ } else if (const ObjCObjectPointerType *PTy =
+ LHSTy->getAs<ObjCObjectPointerType>()) {
BaseExpr = LHSExp;
IndexExpr = RHSExp;
ResultType = PTy->getPointeeType();
- } else if (const PointerType *PTy = RHSTy->getAsPointerType()) {
+ } else if (const ObjCObjectPointerType *PTy =
+ RHSTy->getAs<ObjCObjectPointerType>()) {
// Handle the uncommon case of "123[Ptr]".
BaseExpr = RHSExp;
IndexExpr = LHSExp;
ResultType = PTy->getPointeeType();
- } else if (const VectorType *VTy = LHSTy->getAsVectorType()) {
+ } else if (const VectorType *VTy = LHSTy->getAs<VectorType>()) {
BaseExpr = LHSExp; // vectors: V[123]
IndexExpr = RHSExp;
@@ -1862,7 +1818,7 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc,
BaseExpr = LHSExp;
IndexExpr = RHSExp;
- ResultType = LHSTy->getAsPointerType()->getPointeeType();
+ ResultType = LHSTy->getAs<PointerType>()->getPointeeType();
} else if (RHSTy->isArrayType()) {
// Same as previous, except for 123[f().a] case
Diag(RHSExp->getLocStart(), diag::ext_subscript_non_lvalue) <<
@@ -1872,38 +1828,45 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc,
BaseExpr = RHSExp;
IndexExpr = LHSExp;
- ResultType = RHSTy->getAsPointerType()->getPointeeType();
+ ResultType = RHSTy->getAs<PointerType>()->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())
+ if (!(IndexExpr->getType()->isIntegerType() &&
+ IndexExpr->getType()->isScalarType()) && !IndexExpr->isTypeDependent())
return ExprError(Diag(LLoc, diag::err_typecheck_subscript_not_integer)
<< IndexExpr->getSourceRange());
+ if ((IndexExpr->getType()->isSpecificBuiltinType(BuiltinType::Char_S) ||
+ IndexExpr->getType()->isSpecificBuiltinType(BuiltinType::Char_U))
+ && !IndexExpr->isTypeDependent())
+ Diag(LLoc, diag::warn_subscript_is_char) << 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)
+ // 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()))
+ RequireCompleteType(LLoc, ResultType,
+ PDiag(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,
@@ -1912,11 +1875,12 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc,
QualType Sema::
CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc,
- IdentifierInfo &CompName, SourceLocation CompLoc) {
- const ExtVectorType *vecType = baseType->getAsExtVectorType();
+ const IdentifierInfo *CompName,
+ SourceLocation CompLoc) {
+ const ExtVectorType *vecType = baseType->getAs<ExtVectorType>();
// The vector accessor can't exceed the number of elements.
- const char *compStr = CompName.getName();
+ 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
@@ -1953,7 +1917,7 @@ CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc,
// Ensure no component accessor exceeds the width of the vector type it
// operates on.
if (!HalvingSwizzle) {
- compStr = CompName.getName();
+ compStr = CompName->getName();
if (HexSwizzle)
compStr++;
@@ -1981,7 +1945,7 @@ CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc,
// 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();
+ : CompName->getLength();
if (HexSwizzle)
CompSize--;
@@ -1999,18 +1963,18 @@ CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc,
}
static Decl *FindGetterNameDeclFromProtocolList(const ObjCProtocolDecl*PDecl,
- IdentifierInfo &Member,
+ IdentifierInfo *Member,
const Selector &Sel,
ASTContext &Context) {
-
- if (ObjCPropertyDecl *PD = PDecl->FindPropertyDeclaration(&Member))
+
+ if (ObjCPropertyDecl *PD = PDecl->FindPropertyDeclaration(Member))
return PD;
if (ObjCMethodDecl *OMD = PDecl->getInstanceMethod(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,
+ if (Decl *D = FindGetterNameDeclFromProtocolList(*I, Member, Sel,
Context))
return D;
}
@@ -2018,14 +1982,14 @@ static Decl *FindGetterNameDeclFromProtocolList(const ObjCProtocolDecl*PDecl,
}
static Decl *FindGetterNameDecl(const ObjCObjectPointerType *QIdTy,
- IdentifierInfo &Member,
+ IdentifierInfo *Member,
const Selector &Sel,
ASTContext &Context) {
// Check protocols on qualified interfaces.
Decl *GDecl = 0;
for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(),
E = QIdTy->qual_end(); I != E; ++I) {
- if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(&Member)) {
+ if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) {
GDecl = PD;
break;
}
@@ -2047,101 +2011,213 @@ static Decl *FindGetterNameDecl(const ObjCObjectPointerType *QIdTy,
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(Sel);
-
- if (!Method && IFace->getSuperClass())
- return FindMethodInNestedImplementations(IFace->getSuperClass(), Sel);
- return Method;
-}
-
Action::OwningExprResult
-Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
+Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
tok::TokenKind OpKind, SourceLocation MemberLoc,
- IdentifierInfo &Member,
- DeclPtrTy ObjCImpDecl) {
+ DeclarationName MemberName,
+ bool HasExplicitTemplateArgs,
+ SourceLocation LAngleLoc,
+ const TemplateArgument *ExplicitTemplateArgs,
+ unsigned NumExplicitTemplateArgs,
+ SourceLocation RAngleLoc,
+ DeclPtrTy ObjCImpDecl, const CXXScopeSpec *SS,
+ NamedDecl *FirstQualifierInScope) {
+ if (SS && SS->isInvalid())
+ return ExprError();
+
+ // Since this might be a postfix expression, get rid of ParenListExprs.
+ Base = MaybeConvertParenListExprToParenExpr(S, move(Base));
+
Expr *BaseExpr = Base.takeAs<Expr>();
- assert(BaseExpr && "no record expression");
+ assert(BaseExpr && "no base expression");
// Perform default conversions.
DefaultFunctionArrayConversion(BaseExpr);
QualType BaseType = BaseExpr->getType();
+ // If this is an Objective-C pseudo-builtin and a definition is provided then
+ // use that.
+ if (BaseType->isObjCIdType()) {
+ // We have an 'id' type. Rather than fall through, we check if this
+ // is a reference to 'isa'.
+ if (BaseType != Context.ObjCIdRedefinitionType) {
+ BaseType = Context.ObjCIdRedefinitionType;
+ ImpCastExprToType(BaseExpr, BaseType);
+ }
+ }
assert(!BaseType.isNull() && "no type for member expression");
+ // Handle properties on ObjC 'Class' types.
+ if (OpKind == tok::period && BaseType->isObjCClassType()) {
+ // Also must look for a getter name which uses property syntax.
+ IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
+ 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(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(SetterSel);
+ if (!Setter) {
+ // If this reference is in an @implementation, also check for 'private'
+ // methods.
+ Setter = IFace->lookupPrivateInstanceMethod(SetterSel);
+ }
+ // Look through local category implementations associated with the class.
+ if (!Setter)
+ Setter = IFace->getCategoryClassMethod(SetterSel);
+
+ if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc))
+ return ExprError();
+
+ if (Getter || Setter) {
+ QualType PType;
+
+ if (Getter)
+ PType = Getter->getResultType();
+ else
+ // Get the expression type from Setter's incoming parameter.
+ PType = (*(Setter->param_end() -1))->getType();
+ // FIXME: we must check that the setter has property type.
+ return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(Getter,
+ PType,
+ Setter, MemberLoc, BaseExpr));
+ }
+ return ExprError(Diag(MemberLoc, diag::err_property_not_found)
+ << MemberName << BaseType);
+ }
+ }
+
+ if (BaseType->isObjCClassType() &&
+ BaseType != Context.ObjCClassRedefinitionType) {
+ BaseType = Context.ObjCClassRedefinitionType;
+ ImpCastExprToType(BaseExpr, BaseType);
+ }
+
// 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())
+ if (BaseType->isDependentType()) {
+ NestedNameSpecifier *Qualifier = 0;
+ if (SS) {
+ Qualifier = static_cast<NestedNameSpecifier *>(SS->getScopeRep());
+ if (!FirstQualifierInScope)
+ FirstQualifierInScope = FindFirstQualifierInScope(S, Qualifier);
+ }
+
+ return Owned(CXXUnresolvedMemberExpr::Create(Context, BaseExpr, true,
+ OpLoc, Qualifier,
+ SS? SS->getRange() : SourceRange(),
+ FirstQualifierInScope,
+ MemberName,
+ MemberLoc,
+ HasExplicitTemplateArgs,
+ LAngleLoc,
+ ExplicitTemplateArgs,
+ NumExplicitTemplateArgs,
+ RAngleLoc));
+ }
+ else if (const PointerType *PT = BaseType->getAs<PointerType>())
BaseType = PT->getPointeeType();
- else if (getLangOptions().CPlusPlus && BaseType->isRecordType())
- return Owned(BuildOverloadedArrowExpr(S, BaseExpr, OpLoc,
- MemberLoc, Member));
+ else if (BaseType->isObjCObjectPointerType())
+ ;
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
+ } 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();
+ const PointerType *PT = BaseType->getAs<PointerType>();
+
+ if (!PT || (getLangOptions().ObjC1 &&
+ !PT->getPointeeType()->isRecordType())) {
+ NestedNameSpecifier *Qualifier = 0;
+ if (SS) {
+ Qualifier = static_cast<NestedNameSpecifier *>(SS->getScopeRep());
+ if (!FirstQualifierInScope)
+ FirstQualifierInScope = FindFirstQualifierInScope(S, Qualifier);
+ }
- if (!PT || (getLangOptions().ObjC1 &&
- !PT->getPointeeType()->isRecordType()))
- return Owned(new (Context) CXXUnresolvedMemberExpr(Context,
- BaseExpr, false,
- OpLoc,
- DeclarationName(&Member),
- MemberLoc));
+ return Owned(CXXUnresolvedMemberExpr::Create(Context,
+ BaseExpr, false,
+ OpLoc,
+ Qualifier,
+ SS? SS->getRange() : SourceRange(),
+ FirstQualifierInScope,
+ MemberName,
+ MemberLoc,
+ HasExplicitTemplateArgs,
+ LAngleLoc,
+ ExplicitTemplateArgs,
+ NumExplicitTemplateArgs,
+ RAngleLoc));
+ }
}
- }
// Handle field access to simple records. This also handles access to fields
// of the ObjC 'id' struct.
- if (const RecordType *RTy = BaseType->getAsRecordType()) {
+ if (const RecordType *RTy = BaseType->getAs<RecordType>()) {
RecordDecl *RDecl = RTy->getDecl();
if (RequireCompleteType(OpLoc, BaseType,
- diag::err_typecheck_incomplete_tag,
- BaseExpr->getSourceRange()))
+ PDiag(diag::err_typecheck_incomplete_tag)
+ << BaseExpr->getSourceRange()))
return ExprError();
+ DeclContext *DC = RDecl;
+ if (SS && SS->isSet()) {
+ // If the member name was a qualified-id, look into the
+ // nested-name-specifier.
+ DC = computeDeclContext(*SS, false);
+
+ // FIXME: If DC is not computable, we should build a
+ // CXXUnresolvedMemberExpr.
+ assert(DC && "Cannot handle non-computable dependent contexts in lookup");
+ }
+
// 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());
+ LookupResult Result;
+ LookupQualifiedName(Result, DC, MemberName, LookupMemberName, false);
+
+ if (Result.empty())
+ return ExprError(Diag(MemberLoc, diag::err_no_member)
+ << MemberName << DC << BaseExpr->getSourceRange());
if (Result.isAmbiguous()) {
- DiagnoseAmbiguousLookup(Result, DeclarationName(&Member),
- MemberLoc, BaseExpr->getSourceRange());
+ DiagnoseAmbiguousLookup(Result, MemberName, MemberLoc,
+ BaseExpr->getSourceRange());
return ExprError();
}
-
- NamedDecl *MemberDecl = Result;
+
+ NamedDecl *MemberDecl = Result.getAsSingleDecl(Context);
+
+ if (SS && SS->isSet()) {
+ TypeDecl* TyD = cast<TypeDecl>(MemberDecl->getDeclContext());
+ QualType BaseTypeCanon
+ = Context.getCanonicalType(BaseType).getUnqualifiedType();
+ QualType MemberTypeCanon
+ = Context.getCanonicalType(Context.getTypeDeclType(TyD));
+
+ if (BaseTypeCanon != MemberTypeCanon &&
+ !IsDerivedFrom(BaseTypeCanon, MemberTypeCanon))
+ return ExprError(Diag(SS->getBeginLoc(),
+ diag::err_not_direct_base_or_virtual)
+ << MemberTypeCanon << BaseTypeCanon);
+ }
// If the decl being referenced had an error, return an error for this
// sub-expr without emitting another error, in order to avoid cascading
@@ -2149,8 +2225,16 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
if (MemberDecl->isInvalidDecl())
return ExprError();
+ bool ShouldCheckUse = true;
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MemberDecl)) {
+ // Don't diagnose the use of a virtual member function unless it's
+ // explicitly qualified.
+ if (MD->isVirtual() && (!SS || !SS->isSet()))
+ ShouldCheckUse = false;
+ }
+
// Check the use of this field
- if (DiagnoseUseOfDecl(MemberDecl, MemberLoc))
+ if (ShouldCheckUse && DiagnoseUseOfDecl(MemberDecl, MemberLoc))
return ExprError();
if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl)) {
@@ -2161,137 +2245,253 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
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())
+ if (const ReferenceType *Ref = MemberType->getAs<ReferenceType>())
MemberType = Ref->getPointeeType();
else {
- unsigned combinedQualifiers =
- MemberType.getCVRQualifiers() | BaseType.getCVRQualifiers();
- if (FD->isMutable())
- combinedQualifiers &= ~QualType::Const;
- MemberType = MemberType.getQualifiedType(combinedQualifiers);
+ Qualifiers BaseQuals = BaseType.getQualifiers();
+ BaseQuals.removeObjCGCAttr();
+ if (FD->isMutable()) BaseQuals.removeConst();
+
+ Qualifiers MemberQuals
+ = Context.getCanonicalType(MemberType).getQualifiers();
+
+ Qualifiers Combined = BaseQuals + MemberQuals;
+ if (Combined != MemberQuals)
+ MemberType = Context.getQualifiedType(MemberType, Combined);
}
MarkDeclarationReferenced(MemberLoc, FD);
- return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow, FD,
- MemberLoc, MemberType));
+ if (PerformObjectMemberConversion(BaseExpr, FD))
+ return ExprError();
+ return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
+ FD, MemberLoc, MemberType));
}
-
+
if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) {
MarkDeclarationReferenced(MemberLoc, MemberDecl);
- return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow,
- Var, MemberLoc,
- Var->getType().getNonReferenceType()));
+ return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
+ Var, MemberLoc,
+ Var->getType().getNonReferenceType()));
}
if (FunctionDecl *MemberFn = dyn_cast<FunctionDecl>(MemberDecl)) {
MarkDeclarationReferenced(MemberLoc, MemberDecl);
- return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow,
- MemberFn, MemberLoc,
- MemberFn->getType()));
+ return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
+ MemberFn, MemberLoc,
+ MemberFn->getType()));
+ }
+ if (FunctionTemplateDecl *FunTmpl
+ = dyn_cast<FunctionTemplateDecl>(MemberDecl)) {
+ MarkDeclarationReferenced(MemberLoc, MemberDecl);
+
+ if (HasExplicitTemplateArgs)
+ return Owned(MemberExpr::Create(Context, BaseExpr, OpKind == tok::arrow,
+ (NestedNameSpecifier *)(SS? SS->getScopeRep() : 0),
+ SS? SS->getRange() : SourceRange(),
+ FunTmpl, MemberLoc, true,
+ LAngleLoc, ExplicitTemplateArgs,
+ NumExplicitTemplateArgs, RAngleLoc,
+ Context.OverloadTy));
+
+ return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
+ FunTmpl, MemberLoc,
+ Context.OverloadTy));
}
if (OverloadedFunctionDecl *Ovl
- = dyn_cast<OverloadedFunctionDecl>(MemberDecl))
- return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow, Ovl,
- MemberLoc, Context.OverloadTy));
+ = dyn_cast<OverloadedFunctionDecl>(MemberDecl)) {
+ if (HasExplicitTemplateArgs)
+ return Owned(MemberExpr::Create(Context, BaseExpr, OpKind == tok::arrow,
+ (NestedNameSpecifier *)(SS? SS->getScopeRep() : 0),
+ SS? SS->getRange() : SourceRange(),
+ Ovl, MemberLoc, true,
+ LAngleLoc, ExplicitTemplateArgs,
+ NumExplicitTemplateArgs, RAngleLoc,
+ Context.OverloadTy));
+
+ return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
+ Ovl, MemberLoc, Context.OverloadTy));
+ }
if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) {
MarkDeclarationReferenced(MemberLoc, MemberDecl);
- return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow,
- Enum, MemberLoc, Enum->getType()));
+ return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
+ Enum, MemberLoc, Enum->getType()));
}
if (isa<TypeDecl>(MemberDecl))
return ExprError(Diag(MemberLoc,diag::err_typecheck_member_reference_type)
- << DeclarationName(&Member) << int(OpKind == tok::arrow));
+ << MemberName << 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));
+ << MemberName << int(OpKind == tok::arrow));
+ }
+
+ // Handle pseudo-destructors (C++ [expr.pseudo]). Since anything referring
+ // into a record type was handled above, any destructor we see here is a
+ // pseudo-destructor.
+ if (MemberName.getNameKind() == DeclarationName::CXXDestructorName) {
+ // C++ [expr.pseudo]p2:
+ // The left hand side of the dot operator shall be of scalar type. The
+ // left hand side of the arrow operator shall be of pointer to scalar
+ // type.
+ if (!BaseType->isScalarType())
+ return Owned(Diag(OpLoc, diag::err_pseudo_dtor_base_not_scalar)
+ << BaseType << BaseExpr->getSourceRange());
+
+ // [...] The type designated by the pseudo-destructor-name shall be the
+ // same as the object type.
+ if (!MemberName.getCXXNameType()->isDependentType() &&
+ !Context.hasSameUnqualifiedType(BaseType, MemberName.getCXXNameType()))
+ return Owned(Diag(OpLoc, diag::err_pseudo_dtor_type_mismatch)
+ << BaseType << MemberName.getCXXNameType()
+ << BaseExpr->getSourceRange() << SourceRange(MemberLoc));
+
+ // [...] Furthermore, the two type-names in a pseudo-destructor-name of
+ // the form
+ //
+ // ::[opt] nested-name-specifier[opt] type-name :: ̃ type-name
+ //
+ // shall designate the same scalar type.
+ //
+ // FIXME: DPG can't see any way to trigger this particular clause, so it
+ // isn't checked here.
+
+ // FIXME: We've lost the precise spelling of the type by going through
+ // DeclarationName. Can we do better?
+ return Owned(new (Context) CXXPseudoDestructorExpr(Context, BaseExpr,
+ OpKind == tok::arrow,
+ OpLoc,
+ (NestedNameSpecifier *)(SS? SS->getScopeRep() : 0),
+ SS? SS->getRange() : SourceRange(),
+ MemberName.getCXXNameType(),
+ MemberLoc));
}
// 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(&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();
+ if ((OpKind == tok::arrow && BaseType->isObjCObjectPointerType()) ||
+ (OpKind == tok::period && BaseType->isObjCInterfaceType())) {
+ const ObjCObjectPointerType *OPT = BaseType->getAs<ObjCObjectPointerType>();
+ const ObjCInterfaceType *IFaceT =
+ OPT ? OPT->getInterfaceType() : BaseType->getAs<ObjCInterfaceType>();
+ if (IFaceT) {
+ IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
+
+ ObjCInterfaceDecl *IDecl = IFaceT->getDecl();
+ ObjCInterfaceDecl *ClassDeclared;
+ ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared);
- // 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();
+ if (IV) {
+ // 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 != IDecl ||
+ ClassOfMethodDecl != ClassDeclared)
+ Diag(MemberLoc, diag::error_private_ivar_access)
+ << IV->getDeclName();
+ } else if (!IDecl->isSuperClassOf(ClassOfMethodDecl))
+ // @protected
+ Diag(MemberLoc, diag::error_protected_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 Owned(new (Context) ObjCIvarRefExpr(IV, IV->getType(),
+ MemberLoc, BaseExpr,
+ OpKind == tok::arrow));
+ }
+ return ExprError(Diag(MemberLoc, diag::err_typecheck_member_reference_ivar)
+ << IDecl->getDeclName() << MemberName
+ << BaseExpr->getSourceRange());
}
- return ExprError(Diag(MemberLoc, diag::err_typecheck_member_reference_ivar)
- << IFTy->getDecl()->getDeclName() << &Member
- << BaseExpr->getSourceRange());
}
+ // Handle properties on 'id' and qualified "id".
+ if (OpKind == tok::period && (BaseType->isObjCIdType() ||
+ BaseType->isObjCQualifiedIdType())) {
+ const ObjCObjectPointerType *QIdTy = BaseType->getAs<ObjCObjectPointerType>();
+ IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
+ // 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)
+ << MemberName << BaseType);
+ }
// 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();
+ const ObjCObjectPointerType *OPT;
+ if (OpKind == tok::period &&
+ (OPT = BaseType->getAsObjCInterfacePointerType())) {
+ const ObjCInterfaceType *IFaceT = OPT->getInterfaceType();
+ ObjCInterfaceDecl *IFace = IFaceT->getDecl();
+ IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
// Search for a declared property first.
- if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(&Member)) {
+ if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(Member)) {
// Check whether we can reference this property.
if (DiagnoseUseOfDecl(PD, MemberLoc))
return ExprError();
QualType ResTy = PD->getType();
- Selector Sel = PP.getSelectorTable().getNullarySelector(&Member);
+ Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(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(&Member)) {
+ for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(),
+ E = OPT->qual_end(); I != E; ++I)
+ if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) {
// Check whether we can reference this property.
if (DiagnoseUseOfDecl(PD, MemberLoc))
return ExprError();
@@ -2299,27 +2499,32 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
MemberLoc, BaseExpr));
}
+ for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(),
+ E = OPT->qual_end(); I != E; ++I)
+ if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(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);
+ Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel);
// If this reference is in an @implementation, check for 'private' methods.
if (!Getter)
- Getter = FindMethodInNestedImplementations(IFace, Sel);
+ Getter = IFace->lookupPrivateInstanceMethod(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(Sel);
- }
- }
+ if (!Getter)
+ Getter = IFace->getCategoryInstanceMethod(Sel);
if (Getter) {
// Check if we can reference this property.
if (DiagnoseUseOfDecl(Getter, MemberLoc))
@@ -2327,22 +2532,18 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
}
// 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);
+ Selector SetterSel =
+ SelectorTable::constructSetterName(PP.getIdentifierTable(),
+ PP.getSelectorTable(), Member);
ObjCMethodDecl *Setter = IFace->lookupInstanceMethod(SetterSel);
if (!Setter) {
// If this reference is in an @implementation, also check for 'private'
// methods.
- Setter = FindMethodInNestedImplementations(IFace, SetterSel);
+ Setter = IFace->lookupPrivateInstanceMethod(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(SetterSel);
- }
- }
+ if (!Setter)
+ Setter = IFace->getCategoryInstanceMethod(SetterSel);
if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc))
return ExprError();
@@ -2352,107 +2553,31 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
if (Getter)
PType = Getter->getResultType();
- else {
- for (ObjCMethodDecl::param_iterator PI = Setter->param_begin(),
- E = Setter->param_end(); PI != E; ++PI)
- PType = (*PI)->getType();
- }
+ else
+ // Get the expression type from Setter's incoming parameter.
+ PType = (*(Setter->param_end() -1))->getType();
// FIXME: we must check that the setter has property type.
- return Owned(new (Context) ObjCKVCRefExpr(Getter, PType,
+ return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(Getter, PType,
Setter, MemberLoc, BaseExpr));
}
return ExprError(Diag(MemberLoc, diag::err_property_not_found)
- << &Member << BaseType);
- }
- // Handle properties on qualified "id" protocols.
- const ObjCObjectPointerType *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);
+ << MemberName << 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(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(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(SetterSel);
- }
- }
- if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc))
- return ExprError();
+ // Handle the following exceptional case (*Obj).isa.
+ if (OpKind == tok::period &&
+ BaseType->isSpecificBuiltinType(BuiltinType::ObjCId) &&
+ MemberName.getAsIdentifierInfo()->isStr("isa"))
+ return Owned(new (Context) ObjCIsaExpr(BaseExpr, false, MemberLoc,
+ Context.getObjCIdType()));
- 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()) {
+ IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
QualType ret = CheckExtVectorComponent(BaseType, OpLoc, Member, MemberLoc);
if (ret.isNull())
return ExprError();
- return Owned(new (Context) ExtVectorElementExpr(ret, BaseExpr, Member,
+ return Owned(new (Context) ExtVectorElementExpr(ret, BaseExpr, *Member,
MemberLoc));
}
@@ -2462,10 +2587,10 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
// 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 ||
+ if (BaseType == Context.OverloadTy ||
BaseType->isFunctionType() ||
- (BaseType->isPointerType() &&
- BaseType->getAsPointerType()->isFunctionType())) {
+ (BaseType->isPointerType() &&
+ BaseType->getAs<PointerType>()->isFunctionType())) {
SourceLocation Loc = PP.getLocForEndOfToken(BaseExpr->getLocEnd());
Diag(Loc, diag::note_member_reference_needs_call)
<< CodeModificationHint::CreateInsertion(Loc, "()");
@@ -2474,6 +2599,63 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
return ExprError();
}
+Action::OwningExprResult
+Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
+ tok::TokenKind OpKind, SourceLocation MemberLoc,
+ IdentifierInfo &Member,
+ DeclPtrTy ObjCImpDecl, const CXXScopeSpec *SS) {
+ return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, MemberLoc,
+ DeclarationName(&Member), ObjCImpDecl, SS);
+}
+
+Sema::OwningExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
+ FunctionDecl *FD,
+ ParmVarDecl *Param) {
+ if (Param->hasUnparsedDefaultArg()) {
+ Diag (CallLoc,
+ diag::err_use_of_default_argument_to_function_declared_later) <<
+ FD << cast<CXXRecordDecl>(FD->getDeclContext())->getDeclName();
+ Diag(UnparsedDefaultArgLocs[Param],
+ diag::note_default_argument_declared_here);
+ } else {
+ if (Param->hasUninstantiatedDefaultArg()) {
+ Expr *UninstExpr = Param->getUninstantiatedDefaultArg();
+
+ // Instantiate the expression.
+ MultiLevelTemplateArgumentList ArgList = getTemplateInstantiationArgs(FD);
+
+ InstantiatingTemplate Inst(*this, CallLoc, Param,
+ ArgList.getInnermost().getFlatArgumentList(),
+ ArgList.getInnermost().flat_size());
+
+ OwningExprResult Result = SubstExpr(UninstExpr, ArgList);
+ if (Result.isInvalid())
+ return ExprError();
+
+ if (SetParamDefaultArgument(Param, move(Result),
+ /*FIXME:EqualLoc*/
+ UninstExpr->getSourceRange().getBegin()))
+ return ExprError();
+ }
+
+ Expr *DefaultExpr = Param->getDefaultArg();
+
+ // If the default expression creates temporaries, we need to
+ // push them to the current stack of expression temporaries so they'll
+ // be properly destroyed.
+ if (CXXExprWithTemporaries *E
+ = dyn_cast_or_null<CXXExprWithTemporaries>(DefaultExpr)) {
+ assert(!E->shouldDestroyTemporaries() &&
+ "Can't destroy temporaries in a default argument expr!");
+ for (unsigned I = 0, N = E->getNumTemporaries(); I != N; ++I)
+ ExprTemporaries.push_back(E->getTemporary(I));
+ }
+ }
+
+ // We already type-checked the argument, so we know it works.
+ return Owned(CXXDefaultArgExpr::Create(Context, Param));
+}
+
/// 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
@@ -2529,40 +2711,24 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
if (RequireCompleteType(Arg->getSourceRange().getBegin(),
ProtoArgType,
- diag::err_call_incomplete_argument,
- Arg->getSourceRange()))
+ PDiag(diag::err_call_incomplete_argument)
+ << Arg->getSourceRange()))
return true;
// Pass the argument.
if (PerformCopyInitialization(Arg, ProtoArgType, "passing"))
return true;
} else {
- if (FDecl->getParamDecl(i)->hasUnparsedDefaultArg()) {
- Diag (Call->getSourceRange().getBegin(),
- diag::err_use_of_default_argument_to_function_declared_later) <<
- FDecl << cast<CXXRecordDecl>(FDecl->getDeclContext())->getDeclName();
- Diag(UnparsedDefaultArgLocs[FDecl->getParamDecl(i)],
- diag::note_default_argument_declared_here);
- } else {
- Expr *DefaultExpr = FDecl->getParamDecl(i)->getDefaultArg();
-
- // If the default expression creates temporaries, we need to
- // push them to the current stack of expression temporaries so they'll
- // be properly destroyed.
- if (CXXExprWithTemporaries *E
- = dyn_cast_or_null<CXXExprWithTemporaries>(DefaultExpr)) {
- assert(!E->shouldDestroyTemporaries() &&
- "Can't destroy temporaries in a default argument expr!");
- for (unsigned I = 0, N = E->getNumTemporaries(); I != N; ++I)
- ExprTemporaries.push_back(E->getTemporary(I));
- }
- }
-
- // We already type-checked the argument, so we know it works.
- Arg = new (Context) CXXDefaultArgExpr(FDecl->getParamDecl(i));
+ ParmVarDecl *Param = FDecl->getParamDecl(i);
+
+ OwningExprResult ArgExpr =
+ BuildCXXDefaultArgExpr(Call->getSourceRange().getBegin(),
+ FDecl, Param);
+ if (ArgExpr.isInvalid())
+ return true;
+
+ Arg = ArgExpr.takeAs<Expr>();
}
-
- QualType ArgType = Arg->getType();
Call->setArg(i, Arg);
}
@@ -2586,6 +2752,96 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
return Invalid;
}
+/// \brief "Deconstruct" the function argument of a call expression to find
+/// the underlying declaration (if any), the name of the called function,
+/// whether argument-dependent lookup is available, whether it has explicit
+/// template arguments, etc.
+void Sema::DeconstructCallFunction(Expr *FnExpr,
+ NamedDecl *&Function,
+ DeclarationName &Name,
+ NestedNameSpecifier *&Qualifier,
+ SourceRange &QualifierRange,
+ bool &ArgumentDependentLookup,
+ bool &HasExplicitTemplateArguments,
+ const TemplateArgument *&ExplicitTemplateArgs,
+ unsigned &NumExplicitTemplateArgs) {
+ // Set defaults for all of the output parameters.
+ Function = 0;
+ Name = DeclarationName();
+ Qualifier = 0;
+ QualifierRange = SourceRange();
+ ArgumentDependentLookup = getLangOptions().CPlusPlus;
+ HasExplicitTemplateArguments = false;
+
+ // If we're directly calling a function, get the appropriate declaration.
+ // Also, in C++, keep track of whether we should perform argument-dependent
+ // lookup and whether there were any explicitly-specified template arguments.
+ 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).
+ ArgumentDependentLookup = false;
+ FnExpr = PExpr->getSubExpr();
+ } else if (isa<UnaryOperator>(FnExpr) &&
+ cast<UnaryOperator>(FnExpr)->getOpcode()
+ == UnaryOperator::AddrOf) {
+ FnExpr = cast<UnaryOperator>(FnExpr)->getSubExpr();
+ } else if (QualifiedDeclRefExpr *QDRExpr
+ = dyn_cast<QualifiedDeclRefExpr>(FnExpr)) {
+ // Qualified names disable ADL (C++0x [basic.lookup.argdep]p1).
+ ArgumentDependentLookup = false;
+ Qualifier = QDRExpr->getQualifier();
+ QualifierRange = QDRExpr->getQualifierRange();
+ Function = dyn_cast<NamedDecl>(QDRExpr->getDecl());
+ break;
+ } else if (DeclRefExpr *DRExpr = dyn_cast<DeclRefExpr>(FnExpr)) {
+ Function = dyn_cast<NamedDecl>(DRExpr->getDecl());
+ break;
+ } else if (UnresolvedFunctionNameExpr *DepName
+ = dyn_cast<UnresolvedFunctionNameExpr>(FnExpr)) {
+ Name = DepName->getName();
+ break;
+ } else if (TemplateIdRefExpr *TemplateIdRef
+ = dyn_cast<TemplateIdRefExpr>(FnExpr)) {
+ Function = TemplateIdRef->getTemplateName().getAsTemplateDecl();
+ if (!Function)
+ Function = TemplateIdRef->getTemplateName().getAsOverloadedFunctionDecl();
+ HasExplicitTemplateArguments = true;
+ ExplicitTemplateArgs = TemplateIdRef->getTemplateArgs();
+ NumExplicitTemplateArgs = TemplateIdRef->getNumTemplateArgs();
+
+ // C++ [temp.arg.explicit]p6:
+ // [Note: For simple function names, argument dependent lookup (3.4.2)
+ // applies even when the function name is not visible within the
+ // scope of the call. This is because the call still has the syntactic
+ // form of a function call (3.4.1). But when a function template with
+ // explicit template arguments is used, the call does not have the
+ // correct syntactic form unless there is a function template with
+ // that name visible at the point of the call. If no such name is
+ // visible, the call is not syntactically well-formed and
+ // argument-dependent lookup does not apply. If some such name is
+ // visible, argument dependent lookup applies and additional function
+ // templates may be found in other namespaces.
+ //
+ // The summary of this paragraph is that, if we get to this point and the
+ // template-id was not a qualified name, then argument-dependent lookup
+ // is still possible.
+ if ((Qualifier = TemplateIdRef->getQualifier())) {
+ ArgumentDependentLookup = false;
+ QualifierRange = TemplateIdRef->getQualifierRange();
+ }
+ 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).
+ ArgumentDependentLookup = false;
+ break;
+ }
+ }
+}
+
/// 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.
@@ -2594,6 +2850,10 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
MultiExprArg args,
SourceLocation *CommaLocs, SourceLocation RParenLoc) {
unsigned NumArgs = args.size();
+
+ // Since this might be a postfix expression, get rid of ParenListExprs.
+ fn = MaybeConvertParenListExprToParenExpr(S, move(fn));
+
Expr *Fn = fn.takeAs<Expr>();
Expr **Args = reinterpret_cast<Expr**>(args.release());
assert(Fn && "no function call expression");
@@ -2602,6 +2862,25 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
DeclarationName UnqualifiedName;
if (getLangOptions().CPlusPlus) {
+ // If this is a pseudo-destructor expression, build the call immediately.
+ if (isa<CXXPseudoDestructorExpr>(Fn)) {
+ if (NumArgs > 0) {
+ // Pseudo-destructor calls should not have any arguments.
+ Diag(Fn->getLocStart(), diag::err_pseudo_dtor_call_with_args)
+ << CodeModificationHint::CreateRemoval(
+ SourceRange(Args[0]->getLocStart(),
+ Args[NumArgs-1]->getLocEnd()));
+
+ for (unsigned I = 0; I != NumArgs; ++I)
+ Args[I]->Destroy(Context);
+
+ NumArgs = 0;
+ }
+
+ return Owned(new (Context) CallExpr(Context, Fn, 0, 0, Context.VoidTy,
+ RParenLoc));
+ }
+
// 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
@@ -2632,70 +2911,42 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
return Owned(BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs,
CommaLocs, RParenLoc));
}
+
+ // Determine whether this is a call to a pointer-to-member function.
+ if (BinaryOperator *BO = dyn_cast<BinaryOperator>(Fn->IgnoreParens())) {
+ if (BO->getOpcode() == BinaryOperator::PtrMemD ||
+ BO->getOpcode() == BinaryOperator::PtrMemI) {
+ const FunctionProtoType *FPT = cast<FunctionProtoType>(BO->getType());
+ QualType ReturnTy = FPT->getResultType();
+
+ CXXMemberCallExpr *CE =
+ new (Context) CXXMemberCallExpr(Context, BO, Args, NumArgs,
+ ReturnTy.getNonReferenceType(),
+ RParenLoc);
+
+ ExprOwningPtr<CXXMemberCallExpr> TheCall(this, CE);
+
+ if (ConvertArgumentsForCall(&*TheCall, BO, 0, FPT, Args, NumArgs,
+ RParenLoc))
+ return ExprError();
+
+ return Owned(MaybeBindToTemporary(TheCall.release()).release());
+ }
+ }
}
// If we're directly calling a function, get the appropriate declaration.
- // Also, in C++, keep track of whether we should perform argument-dependent
+ // Also, in C++, keep track of whether we should perform argument-dependent
// lookup and whether there were any explicitly-specified template arguments.
- Expr *FnExpr = Fn;
bool ADL = true;
bool HasExplicitTemplateArgs = 0;
const TemplateArgument *ExplicitTemplateArgs = 0;
unsigned NumExplicitTemplateArgs = 0;
- 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 (DeclRefExpr *DRExpr = dyn_cast<DeclRefExpr>(FnExpr)) {
- // Qualified names disable ADL (C++0x [basic.lookup.argdep]p1).
- ADL &= !isa<QualifiedDeclRefExpr>(DRExpr);
- NDecl = dyn_cast<NamedDecl>(DRExpr->getDecl());
- break;
- } else if (UnresolvedFunctionNameExpr *DepName
- = dyn_cast<UnresolvedFunctionNameExpr>(FnExpr)) {
- UnqualifiedName = DepName->getName();
- break;
- } else if (TemplateIdRefExpr *TemplateIdRef
- = dyn_cast<TemplateIdRefExpr>(FnExpr)) {
- NDecl = TemplateIdRef->getTemplateName().getAsTemplateDecl();
- HasExplicitTemplateArgs = true;
- ExplicitTemplateArgs = TemplateIdRef->getTemplateArgs();
- NumExplicitTemplateArgs = TemplateIdRef->getNumTemplateArgs();
-
- // C++ [temp.arg.explicit]p6:
- // [Note: For simple function names, argument dependent lookup (3.4.2)
- // applies even when the function name is not visible within the
- // scope of the call. This is because the call still has the syntactic
- // form of a function call (3.4.1). But when a function template with
- // explicit template arguments is used, the call does not have the
- // correct syntactic form unless there is a function template with
- // that name visible at the point of the call. If no such name is
- // visible, the call is not syntactically well-formed and
- // argument-dependent lookup does not apply. If some such name is
- // visible, argument dependent lookup applies and additional function
- // templates may be found in other namespaces.
- //
- // The summary of this paragraph is that, if we get to this point and the
- // template-id was not a qualified name, then argument-dependent lookup
- // is still possible.
- if (TemplateIdRef->getQualifier())
- ADL = false;
- 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;
- }
- }
+ NestedNameSpecifier *Qualifier = 0;
+ SourceRange QualifierRange;
+ DeconstructCallFunction(Fn, NDecl, UnqualifiedName, Qualifier, QualifierRange,
+ ADL,HasExplicitTemplateArgs, ExplicitTemplateArgs,
+ NumExplicitTemplateArgs);
OverloadedFunctionDecl *Ovl = 0;
FunctionTemplateDecl *FunctionTemplate = 0;
@@ -2708,10 +2959,10 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
Ovl = dyn_cast<OverloadedFunctionDecl>(NDecl);
}
- if (Ovl || FunctionTemplate ||
+ if (Ovl || FunctionTemplate ||
(getLangOptions().CPlusPlus && (FDecl || UnqualifiedName))) {
// We don't perform ADL for implicit declarations of builtins.
- if (FDecl && FDecl->getBuiltinID(Context) && FDecl->isImplicit())
+ if (FDecl && FDecl->getBuiltinID() && FDecl->isImplicit())
ADL = false;
// We don't perform ADL in C.
@@ -2719,27 +2970,26 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
ADL = false;
if (Ovl || FunctionTemplate || ADL) {
- FDecl = ResolveOverloadedCallFn(Fn, NDecl, UnqualifiedName,
+ FDecl = ResolveOverloadedCallFn(Fn, NDecl, UnqualifiedName,
HasExplicitTemplateArgs,
ExplicitTemplateArgs,
NumExplicitTemplateArgs,
- LParenLoc, Args, NumArgs, CommaLocs,
+ 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<QualifiedDeclRefExpr>(FnExpr))
+ if (Qualifier)
NewFn = new (Context) QualifiedDeclRefExpr(FDecl, FDecl->getType(),
- QDRExpr->getLocation(),
+ Fn->getLocStart(),
false, false,
- QDRExpr->getQualifierRange(),
- QDRExpr->getQualifier());
+ QualifierRange,
+ Qualifier);
else
NewFn = new (Context) DeclRefExpr(FDecl, FDecl->getType(),
- Fn->getSourceRange().getBegin());
+ Fn->getLocStart());
Fn->Destroy(Context);
Fn = NewFn;
}
@@ -2759,25 +3009,23 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
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();
+ const PointerType *PT = Fn->getType()->getAs<PointerType>();
if (PT == 0)
return ExprError(Diag(LParenLoc, diag::err_typecheck_call_not_function)
<< Fn->getType() << Fn->getSourceRange());
- FuncT = PT->getPointeeType()->getAsFunctionType();
+ FuncT = PT->getPointeeType()->getAs<FunctionType>();
} else { // This is a block call.
- FuncT = Fn->getType()->getAsBlockPointerType()->getPointeeType()->
- getAsFunctionType();
+ FuncT = Fn->getType()->getAs<BlockPointerType>()->getPointeeType()->
+ getAs<FunctionType>();
}
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()))
+ if (CheckCallReturnType(FuncT->getResultType(),
+ Fn->getSourceRange().getBegin(), TheCall.get(),
+ FDecl))
return ExprError();
// We know the result type of the call, set it.
@@ -2796,7 +3044,7 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
const FunctionDecl *Def = 0;
if (FDecl->getBody(Def) && NumArgs != Def->param_size()) {
const FunctionProtoType *Proto =
- Def->getType()->getAsFunctionProtoType();
+ Def->getType()->getAs<FunctionProtoType>();
if (!Proto || !(Proto->isVariadic() && NumArgs >= Def->param_size())) {
Diag(RParenLoc, diag::warn_call_wrong_number_of_arguments)
<< (NumArgs > Def->param_size()) << FDecl << Fn->getSourceRange();
@@ -2810,8 +3058,8 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
DefaultArgumentPromotion(Arg);
if (RequireCompleteType(Arg->getSourceRange().getBegin(),
Arg->getType(),
- diag::err_call_incomplete_argument,
- Arg->getSourceRange()))
+ PDiag(diag::err_call_incomplete_argument)
+ << Arg->getSourceRange()))
return ExprError();
TheCall->setArg(i, Arg);
}
@@ -2825,20 +3073,28 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
// 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());
+ if (FDecl) {
+ if (CheckFunctionCall(FDecl, TheCall.get()))
+ return ExprError();
- return Owned(TheCall.take());
+ if (unsigned BuiltinID = FDecl->getBuiltinID())
+ return CheckBuiltinFunctionCall(BuiltinID, TheCall.take());
+ } else if (NDecl) {
+ if (CheckBlockCall(NDecl, TheCall.get()))
+ return ExprError();
+ }
+
+ return MaybeBindToTemporary(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: Preserve type source info.
+ QualType literalType = GetTypeFromParser(Ty);
// FIXME: put back this assert when initializers are worked out.
//assert((InitExpr != 0) && "ActOnCompoundLiteral(): missing expression");
Expr *literalExpr = static_cast<Expr*>(InitExpr.get());
@@ -2849,8 +3105,9 @@ Sema::ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty,
<< SourceRange(LParenLoc, literalExpr->getSourceRange().getEnd()));
} else if (!literalType->isDependentType() &&
RequireCompleteType(LParenLoc, literalType,
- diag::err_typecheck_decl_incomplete_type,
- SourceRange(LParenLoc, literalExpr->getSourceRange().getEnd())))
+ PDiag(diag::err_typecheck_decl_incomplete_type)
+ << SourceRange(LParenLoc,
+ literalExpr->getSourceRange().getEnd())))
return ExprError();
if (CheckInitializerTypes(literalExpr, literalType, LParenLoc,
@@ -2883,15 +3140,20 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg initlist,
}
/// CheckCastTypes - Check type constraints for casting between types.
-bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr) {
- UsualUnaryConversions(castExpr);
+bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr,
+ CastExpr::CastKind& Kind,
+ CXXMethodDecl *& ConversionDecl,
+ bool FunctionalStyle) {
+ if (getLangOptions().CPlusPlus)
+ return CXXCheckCStyleCast(TyR, castType, castExpr, Kind, FunctionalStyle,
+ ConversionDecl);
+
+ DefaultFunctionArrayConversion(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()) &&
@@ -2900,9 +3162,10 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr) {
// FIXME: Check that the cast destination type is complete.
Diag(TyR.getBegin(), diag::ext_typecheck_cast_nonscalar)
<< castType << castExpr->getSourceRange();
+ Kind = CastExpr::CK_NoOp;
} else if (castType->isUnionType()) {
// GCC cast to union extension
- RecordDecl *RD = castType->getAsRecordType()->getDecl();
+ RecordDecl *RD = castType->getAs<RecordType>()->getDecl();
RecordDecl::field_iterator Field, FieldEnd;
for (Field = RD->field_begin(), FieldEnd = RD->field_end();
Field != FieldEnd; ++Field) {
@@ -2916,6 +3179,7 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr) {
if (Field == FieldEnd)
return Diag(TyR.getBegin(), diag::err_typecheck_cast_to_union_no_type)
<< castExpr->getType() << castExpr->getSourceRange();
+ Kind = CastExpr::CK_ToUnion;
} else {
// Reject any other conversions to non-scalar types.
return Diag(TyR.getBegin(), diag::err_typecheck_cond_expect_scalar)
@@ -2974,7 +3238,7 @@ bool Sema::CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty) {
bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, QualType SrcTy) {
assert(DestTy->isExtVectorType() && "Not an extended vector type!");
-
+
// If SrcTy is a VectorType, the total size must match to explicitly cast to
// an ExtVectorType.
if (SrcTy->isVectorType()) {
@@ -2995,20 +3259,104 @@ bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, QualType SrcTy) {
}
Action::OwningExprResult
-Sema::ActOnCastExpr(SourceLocation LParenLoc, TypeTy *Ty,
+Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, TypeTy *Ty,
SourceLocation RParenLoc, ExprArg Op) {
+ CastExpr::CastKind Kind = CastExpr::CK_Unknown;
+
assert((Ty != 0) && (Op.get() != 0) &&
"ActOnCastExpr(): missing type or expr");
- Expr *castExpr = Op.takeAs<Expr>();
- QualType castType = QualType::getFromOpaquePtr(Ty);
+ Expr *castExpr = (Expr *)Op.get();
+ //FIXME: Preserve type source info.
+ QualType castType = GetTypeFromParser(Ty);
- if (CheckCastTypes(SourceRange(LParenLoc, RParenLoc), castType, castExpr))
+ // If the Expr being casted is a ParenListExpr, handle it specially.
+ if (isa<ParenListExpr>(castExpr))
+ return ActOnCastOfParenListExpr(S, LParenLoc, RParenLoc, move(Op),castType);
+ CXXMethodDecl *Method = 0;
+ if (CheckCastTypes(SourceRange(LParenLoc, RParenLoc), castType, castExpr,
+ Kind, Method))
return ExprError();
- return Owned(new (Context) CStyleCastExpr(castType, castExpr, castType,
+
+ if (Method) {
+ OwningExprResult CastArg = BuildCXXCastArgument(LParenLoc, castType, Kind,
+ Method, move(Op));
+
+ if (CastArg.isInvalid())
+ return ExprError();
+
+ castExpr = CastArg.takeAs<Expr>();
+ } else {
+ Op.release();
+ }
+
+ return Owned(new (Context) CStyleCastExpr(castType.getNonReferenceType(),
+ Kind, castExpr, castType,
LParenLoc, RParenLoc));
}
+/// This is not an AltiVec-style cast, so turn the ParenListExpr into a sequence
+/// of comma binary operators.
+Action::OwningExprResult
+Sema::MaybeConvertParenListExprToParenExpr(Scope *S, ExprArg EA) {
+ Expr *expr = EA.takeAs<Expr>();
+ ParenListExpr *E = dyn_cast<ParenListExpr>(expr);
+ if (!E)
+ return Owned(expr);
+
+ OwningExprResult Result(*this, E->getExpr(0));
+
+ for (unsigned i = 1, e = E->getNumExprs(); i != e && !Result.isInvalid(); ++i)
+ Result = ActOnBinOp(S, E->getExprLoc(), tok::comma, move(Result),
+ Owned(E->getExpr(i)));
+
+ return ActOnParenExpr(E->getLParenLoc(), E->getRParenLoc(), move(Result));
+}
+
+Action::OwningExprResult
+Sema::ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc,
+ SourceLocation RParenLoc, ExprArg Op,
+ QualType Ty) {
+ ParenListExpr *PE = (ParenListExpr *)Op.get();
+
+ // If this is an altivec initializer, '(' type ')' '(' init, ..., init ')'
+ // then handle it as such.
+ if (getLangOptions().AltiVec && Ty->isVectorType()) {
+ if (PE->getNumExprs() == 0) {
+ Diag(PE->getExprLoc(), diag::err_altivec_empty_initializer);
+ return ExprError();
+ }
+
+ llvm::SmallVector<Expr *, 8> initExprs;
+ for (unsigned i = 0, e = PE->getNumExprs(); i != e; ++i)
+ initExprs.push_back(PE->getExpr(i));
+
+ // FIXME: This means that pretty-printing the final AST will produce curly
+ // braces instead of the original commas.
+ Op.release();
+ InitListExpr *E = new (Context) InitListExpr(LParenLoc, &initExprs[0],
+ initExprs.size(), RParenLoc);
+ E->setType(Ty);
+ return ActOnCompoundLiteral(LParenLoc, Ty.getAsOpaquePtr(), RParenLoc,
+ Owned(E));
+ } else {
+ // This is not an AltiVec-style cast, so turn the ParenListExpr into a
+ // sequence of BinOp comma operators.
+ Op = MaybeConvertParenListExprToParenExpr(S, move(Op));
+ return ActOnCastExpr(S, LParenLoc, Ty.getAsOpaquePtr(), RParenLoc,move(Op));
+ }
+}
+
+Action::OwningExprResult Sema::ActOnParenListExpr(SourceLocation L,
+ SourceLocation R,
+ MultiExprArg Val) {
+ unsigned nexprs = Val.size();
+ Expr **exprs = reinterpret_cast<Expr**>(Val.release());
+ assert((exprs != 0) && "ActOnParenListExpr() missing expr list");
+ Expr *expr = new (Context) ParenListExpr(Context, L, exprs, nexprs, R);
+ return Owned(expr);
+}
+
/// 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
@@ -3033,6 +3381,8 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
}
// Now check the two expressions.
+ if (LHSTy->isVectorType() || RHSTy->isVectorType())
+ return CheckVectorOperands(QuestionLoc, LHS, RHS);
// If both operands have arithmetic type, do the usual arithmetic conversions
// to find a common type: C99 6.5.15p3,5.
@@ -3043,8 +3393,8 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// 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 (const RecordType *LHSRT = LHSTy->getAs<RecordType>()) { // C99 6.5.15p3
+ if (const RecordType *RHSRT = RHSTy->getAs<RecordType>())
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.
@@ -3067,24 +3417,46 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
}
// 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)) {
+ if ((LHSTy->isAnyPointerType() || LHSTy->isBlockPointerType()) &&
+ RHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
ImpCastExprToType(RHS, LHSTy); // promote the null to a pointer.
return LHSTy;
}
- if ((RHSTy->isPointerType() || RHSTy->isBlockPointerType() ||
- Context.isObjCObjectPointerType(RHSTy)) &&
- LHS->isNullPointerConstant(Context)) {
+ if ((RHSTy->isAnyPointerType() || RHSTy->isBlockPointerType()) &&
+ LHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
ImpCastExprToType(LHS, RHSTy); // promote the null to a pointer.
return RHSTy;
}
+ // Handle things like Class and struct objc_class*. Here we case the result
+ // to the pseudo-builtin, because that will be implicitly cast back to the
+ // redefinition type if an attempt is made to access its fields.
+ if (LHSTy->isObjCClassType() &&
+ (RHSTy.getDesugaredType() == Context.ObjCClassRedefinitionType)) {
+ ImpCastExprToType(RHS, LHSTy);
+ return LHSTy;
+ }
+ if (RHSTy->isObjCClassType() &&
+ (LHSTy.getDesugaredType() == Context.ObjCClassRedefinitionType)) {
+ ImpCastExprToType(LHS, RHSTy);
+ return RHSTy;
+ }
+ // And the same for struct objc_object* / id
+ if (LHSTy->isObjCIdType() &&
+ (RHSTy.getDesugaredType() == Context.ObjCIdRedefinitionType)) {
+ ImpCastExprToType(RHS, LHSTy);
+ return LHSTy;
+ }
+ if (RHSTy->isObjCIdType() &&
+ (LHSTy.getDesugaredType() == Context.ObjCIdRedefinitionType)) {
+ ImpCastExprToType(LHS, RHSTy);
+ return RHSTy;
+ }
// Handle block pointer types.
if (LHSTy->isBlockPointerType() || RHSTy->isBlockPointerType()) {
if (!LHSTy->isBlockPointerType() || !RHSTy->isBlockPointerType()) {
if (LHSTy->isVoidPointerType() || RHSTy->isVoidPointerType()) {
QualType destType = Context.getPointerType(Context.VoidTy);
- ImpCastExprToType(LHS, destType);
+ ImpCastExprToType(LHS, destType);
ImpCastExprToType(RHS, destType);
return destType;
}
@@ -3098,8 +3470,8 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
return LHSTy;
}
// The block pointer types aren't identical, continue checking.
- QualType lhptee = LHSTy->getAsBlockPointerType()->getPointeeType();
- QualType rhptee = RHSTy->getAsBlockPointerType()->getPointeeType();
+ QualType lhptee = LHSTy->getAs<BlockPointerType>()->getPointeeType();
+ QualType rhptee = RHSTy->getAs<BlockPointerType>()->getPointeeType();
if (!Context.typesAreCompatible(lhptee.getUnqualifiedType(),
rhptee.getUnqualifiedType())) {
@@ -3118,48 +3490,17 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
ImpCastExprToType(RHS, LHSTy);
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;
- }
- }
// Check constraints for Objective-C object pointers types.
- if (Context.isObjCObjectPointerType(LHSTy) &&
- Context.isObjCObjectPointerType(RHSTy)) {
-
+ if (LHSTy->isObjCObjectPointerType() && RHSTy->isObjCObjectPointerType()) {
+
if (Context.getCanonicalType(LHSTy) == Context.getCanonicalType(RHSTy)) {
// Two identical object pointer types are always compatible.
return LHSTy;
}
- // No need to check for block pointer types or qualified id types (they
- // were handled above).
- assert((LHSTy->isPointerType() && RHSTy->isPointerType()) &&
- "Sema::CheckConditionalOperands(): Unexpected type");
- QualType lhptee = LHSTy->getAsPointerType()->getPointeeType();
- QualType rhptee = RHSTy->getAsPointerType()->getPointeeType();
-
+ const ObjCObjectPointerType *LHSOPT = LHSTy->getAs<ObjCObjectPointerType>();
+ const ObjCObjectPointerType *RHSOPT = RHSTy->getAs<ObjCObjectPointerType>();
QualType compositeType = LHSTy;
-
+
// If both operands are interfaces and either operand can be
// assigned to the other, use that type as the composite
// type. This allows
@@ -3173,16 +3514,19 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// 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)) {
+ if (Context.canAssignObjCInterfaces(LHSOPT, RHSOPT)) {
+ compositeType = RHSOPT->isObjCBuiltinType() ? RHSTy : LHSTy;
+ } else if (Context.canAssignObjCInterfaces(RHSOPT, LHSOPT)) {
+ compositeType = LHSOPT->isObjCBuiltinType() ? LHSTy : RHSTy;
+ } else if ((LHSTy->isObjCQualifiedIdType() ||
+ RHSTy->isObjCQualifiedIdType()) &&
+ Context.ObjCQualifiedIdTypesAreCompatible(LHSTy, RHSTy, true)) {
+ // Need to handle "id<xx>" explicitly.
+ // 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.
+ compositeType = Context.getObjCIdType();
+ } else if (LHSTy->isObjCIdType() || RHSTy->isObjCIdType()) {
compositeType = Context.getObjCIdType();
} else {
Diag(QuestionLoc, diag::ext_typecheck_cond_incompatible_operands)
@@ -3198,23 +3542,46 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
ImpCastExprToType(RHS, compositeType);
return compositeType;
}
+ // Check Objective-C object pointer types and 'void *'
+ if (LHSTy->isVoidPointerType() && RHSTy->isObjCObjectPointerType()) {
+ QualType lhptee = LHSTy->getAs<PointerType>()->getPointeeType();
+ QualType rhptee = RHSTy->getAs<ObjCObjectPointerType>()->getPointeeType();
+ QualType destPointee
+ = Context.getQualifiedType(lhptee, rhptee.getQualifiers());
+ QualType destType = Context.getPointerType(destPointee);
+ ImpCastExprToType(LHS, destType); // add qualifiers if necessary
+ ImpCastExprToType(RHS, destType); // promote to void*
+ return destType;
+ }
+ if (LHSTy->isObjCObjectPointerType() && RHSTy->isVoidPointerType()) {
+ QualType lhptee = LHSTy->getAs<ObjCObjectPointerType>()->getPointeeType();
+ QualType rhptee = RHSTy->getAs<PointerType>()->getPointeeType();
+ QualType destPointee
+ = Context.getQualifiedType(rhptee, lhptee.getQualifiers());
+ QualType destType = Context.getPointerType(destPointee);
+ ImpCastExprToType(RHS, destType); // add qualifiers if necessary
+ ImpCastExprToType(LHS, destType); // promote to void*
+ return destType;
+ }
// Check constraints for C object pointers types (C99 6.5.15p3,6).
if (LHSTy->isPointerType() && RHSTy->isPointerType()) {
// get the "pointed to" types
- QualType lhptee = LHSTy->getAsPointerType()->getPointeeType();
- QualType rhptee = RHSTy->getAsPointerType()->getPointeeType();
+ QualType lhptee = LHSTy->getAs<PointerType>()->getPointeeType();
+ QualType rhptee = RHSTy->getAs<PointerType>()->getPointeeType();
// ignore qualifiers on void (C99 6.5.15p3, clause 6)
if (lhptee->isVoidType() && rhptee->isIncompleteOrObjectType()) {
// Figure out necessary qualifiers (C99 6.5.15p6)
- QualType destPointee=lhptee.getQualifiedType(rhptee.getCVRQualifiers());
+ QualType destPointee
+ = Context.getQualifiedType(lhptee, rhptee.getQualifiers());
QualType destType = Context.getPointerType(destPointee);
ImpCastExprToType(LHS, destType); // add qualifiers if necessary
ImpCastExprToType(RHS, destType); // promote to void*
return destType;
}
if (rhptee->isVoidType() && lhptee->isIncompleteOrObjectType()) {
- QualType destPointee=rhptee.getQualifiedType(lhptee.getCVRQualifiers());
+ QualType destPointee
+ = Context.getQualifiedType(rhptee, lhptee.getQualifiers());
QualType destType = Context.getPointerType(destPointee);
ImpCastExprToType(LHS, destType); // add qualifiers if necessary
ImpCastExprToType(RHS, destType); // promote to void*
@@ -3248,7 +3615,7 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
ImpCastExprToType(RHS, LHSTy);
return LHSTy;
}
-
+
// GCC compatibility: soften pointer/integer mismatch.
if (RHSTy->isPointerType() && LHSTy->isIntegerType()) {
Diag(QuestionLoc, diag::warn_typecheck_cond_pointer_integer_mismatch)
@@ -3292,12 +3659,11 @@ Action::OwningExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc,
Cond.release();
LHS.release();
RHS.release();
- return Owned(new (Context) ConditionalOperator(CondExpr,
+ return Owned(new (Context) ConditionalOperator(CondExpr, QuestionLoc,
isLHSNull ? 0 : LHSExpr,
- RHSExpr, result));
+ ColonLoc, 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.
@@ -3307,9 +3673,16 @@ Sema::AssignConvertType
Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) {
QualType lhptee, rhptee;
+ if ((lhsType->isObjCClassType() &&
+ (rhsType.getDesugaredType() == Context.ObjCClassRedefinitionType)) ||
+ (rhsType->isObjCClassType() &&
+ (lhsType.getDesugaredType() == Context.ObjCClassRedefinitionType))) {
+ return Compatible;
+ }
+
// get the "pointed to" type (ignoring qualifiers at the top level)
- lhptee = lhsType->getAsPointerType()->getPointeeType();
- rhptee = rhsType->getAsPointerType()->getPointeeType();
+ lhptee = lhsType->getAs<PointerType>()->getPointeeType();
+ rhptee = rhsType->getAs<PointerType>()->getPointeeType();
// make sure we operate on the canonical type
lhptee = Context.getCanonicalType(lhptee);
@@ -3371,7 +3744,7 @@ Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) {
return IncompatiblePointerSign;
}
// General pointer incompatibility takes priority over qualifiers.
- return IncompatiblePointer;
+ return IncompatiblePointer;
}
return ConvTy;
}
@@ -3386,8 +3759,8 @@ Sema::CheckBlockPointerTypesForAssignment(QualType lhsType,
QualType lhptee, rhptee;
// get the "pointed to" type (ignoring qualifiers at the top level)
- lhptee = lhsType->getAsBlockPointerType()->getPointeeType();
- rhptee = rhsType->getAsBlockPointerType()->getPointeeType();
+ lhptee = lhsType->getAs<BlockPointerType>()->getPointeeType();
+ rhptee = rhsType->getAs<BlockPointerType>()->getPointeeType();
// make sure we operate on the canonical type
lhptee = Context.getCanonicalType(lhptee);
@@ -3430,6 +3803,13 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
if (lhsType == rhsType)
return Compatible; // Common case: fast path an exact match.
+ if ((lhsType->isObjCClassType() &&
+ (rhsType.getDesugaredType() == Context.ObjCClassRedefinitionType)) ||
+ (rhsType->isObjCClassType() &&
+ (lhsType.getDesugaredType() == Context.ObjCClassRedefinitionType))) {
+ return Compatible;
+ }
+
// 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,
@@ -3437,23 +3817,11 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
// 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 (const ReferenceType *lhsTypeRef = lhsType->getAs<ReferenceType>()) {
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;
- }
-
// Allow scalar to ExtVector assignments, and assignments of an ExtVector type
// to the same ExtVector type.
if (lhsType->isExtVectorType()) {
@@ -3462,7 +3830,7 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
if (!rhsType->isVectorType() && rhsType->isArithmeticType())
return Compatible;
}
-
+
if (lhsType->isVectorType() || rhsType->isVectorType()) {
// 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;
@@ -3485,13 +3853,18 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
if (isa<PointerType>(rhsType))
return CheckPointerTypesForAssignment(lhsType, rhsType);
- if (rhsType->getAsBlockPointerType()) {
- if (lhsType->getAsPointerType()->getPointeeType()->isVoidType())
+ // In general, C pointers are not compatible with ObjC object pointers.
+ if (isa<ObjCObjectPointerType>(rhsType)) {
+ if (lhsType->isVoidPointerType()) // an exception to the rule.
+ return Compatible;
+ return IncompatiblePointer;
+ }
+ if (rhsType->getAs<BlockPointerType>()) {
+ if (lhsType->getAs<PointerType>()->getPointeeType()->isVoidType())
return Compatible;
// Treat block pointers as objects.
- if (getLangOptions().ObjC1 &&
- lhsType == Context.getCanonicalType(Context.getObjCIdType()))
+ if (getLangOptions().ObjC1 && lhsType->isObjCIdType())
return Compatible;
}
return Incompatible;
@@ -3502,20 +3875,47 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
return IntToBlockPointer;
// Treat block pointers as objects.
- if (getLangOptions().ObjC1 &&
- rhsType == Context.getCanonicalType(Context.getObjCIdType()))
+ if (getLangOptions().ObjC1 && rhsType->isObjCIdType())
return Compatible;
if (rhsType->isBlockPointerType())
return CheckBlockPointerTypesForAssignment(lhsType, rhsType);
- if (const PointerType *RHSPT = rhsType->getAsPointerType()) {
+ if (const PointerType *RHSPT = rhsType->getAs<PointerType>()) {
if (RHSPT->getPointeeType()->isVoidType())
return Compatible;
}
return Incompatible;
}
+ if (isa<ObjCObjectPointerType>(lhsType)) {
+ if (rhsType->isIntegerType())
+ return IntToPointer;
+
+ // In general, C pointers are not compatible with ObjC object pointers.
+ if (isa<PointerType>(rhsType)) {
+ if (rhsType->isVoidPointerType()) // an exception to the rule.
+ return Compatible;
+ return IncompatiblePointer;
+ }
+ if (rhsType->isObjCObjectPointerType()) {
+ if (lhsType->isObjCBuiltinType() || rhsType->isObjCBuiltinType())
+ return Compatible;
+ if (Context.typesAreCompatible(lhsType, rhsType))
+ return Compatible;
+ if (lhsType->isObjCQualifiedIdType() || rhsType->isObjCQualifiedIdType())
+ return IncompatibleObjCQualifiedId;
+ return IncompatiblePointer;
+ }
+ if (const PointerType *RHSPT = rhsType->getAs<PointerType>()) {
+ if (RHSPT->getPointeeType()->isVoidType())
+ return Compatible;
+ }
+ // Treat block pointers as objects.
+ if (rhsType->isBlockPointerType())
+ 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)
@@ -3528,7 +3928,26 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
return CheckPointerTypesForAssignment(lhsType, rhsType);
if (isa<BlockPointerType>(lhsType) &&
- rhsType->getAsPointerType()->getPointeeType()->isVoidType())
+ rhsType->getAs<PointerType>()->getPointeeType()->isVoidType())
+ return Compatible;
+ return Incompatible;
+ }
+ if (isa<ObjCObjectPointerType>(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;
+
+ // In general, C pointers are not compatible with ObjC object pointers.
+ if (isa<PointerType>(lhsType)) {
+ if (lhsType->isVoidPointerType()) // an exception to the rule.
+ return Compatible;
+ return IncompatiblePointer;
+ }
+ if (isa<BlockPointerType>(lhsType) &&
+ rhsType->getAs<PointerType>()->getPointeeType()->isVoidType())
return Compatible;
return Incompatible;
}
@@ -3542,7 +3961,7 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
/// \brief Constructs a transparent union from an expression that is
/// used to initialize the transparent union.
-static void ConstructTransparentUnion(ASTContext &C, Expr *&E,
+static void ConstructTransparentUnion(ASTContext &C, Expr *&E,
QualType UnionType, FieldDecl *Field) {
// Build an initializer list that designates the appropriate member
// of the transparent union.
@@ -3562,7 +3981,7 @@ 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
+ // 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>())
@@ -3580,13 +3999,14 @@ Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, Expr *&rExpr) {
// 1) void pointer
// 2) null pointer constant
if (FromType->isPointerType())
- if (FromType->getAsPointerType()->getPointeeType()->isVoidType()) {
+ if (FromType->getAs<PointerType>()->getPointeeType()->isVoidType()) {
ImpCastExprToType(rExpr, it->getType());
InitField = *it;
break;
}
-
- if (rExpr->isNullPointerConstant(Context)) {
+
+ if (rExpr->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNull)) {
ImpCastExprToType(rExpr, it->getType());
InitField = *it;
break;
@@ -3626,10 +4046,11 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) {
// C99 6.5.16.1p1: the left operand is a pointer and the right is
// a null pointer constant.
- if ((lhsType->isPointerType() ||
- lhsType->isObjCQualifiedIdType() ||
+ if ((lhsType->isPointerType() ||
+ lhsType->isObjCObjectPointerType() ||
lhsType->isBlockPointerType())
- && rExpr->isNullPointerConstant(Context)) {
+ && rExpr->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNull)) {
ImpCastExprToType(rExpr, lhsType);
return Compatible;
}
@@ -3681,8 +4102,8 @@ inline QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex,
// 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 (const VectorType *LV = lhsType->getAs<VectorType>()) {
+ if (const VectorType *RV = rhsType->getAs<VectorType>())
if (LV->getElementType() == RV->getElementType() &&
LV->getNumElements() == RV->getNumElements()) {
return lhsType->isExtVectorType() ? lhsType : rhsType;
@@ -3698,9 +4119,9 @@ inline QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex,
std::swap(rex, lex);
std::swap(rhsType, lhsType);
}
-
+
// Handle the case of an ext vector and scalar.
- if (const ExtVectorType *LV = lhsType->getAsExtVectorType()) {
+ if (const ExtVectorType *LV = lhsType->getAs<ExtVectorType>()) {
QualType EltTy = LV->getElementType();
if (EltTy->isIntegralType() && rhsType->isIntegralType()) {
if (Context.getIntegerTypeOrder(EltTy, rhsType) >= 0) {
@@ -3718,7 +4139,7 @@ inline QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex,
}
}
}
-
+
// Vectors of different size or scalar and non-ext-vector are errors.
Diag(Loc, diag::err_typecheck_vector_not_convertable)
<< lex->getType() << rex->getType()
@@ -3727,8 +4148,7 @@ inline QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex,
}
inline QualType Sema::CheckMultiplyDivideOperands(
- Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign)
-{
+ Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) {
if (lex->getType()->isVectorType() || rex->getType()->isVectorType())
return CheckVectorOperands(Loc, lex, rex);
@@ -3740,8 +4160,7 @@ inline QualType Sema::CheckMultiplyDivideOperands(
}
inline QualType Sema::CheckRemainderOperands(
- Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign)
-{
+ 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);
@@ -3756,8 +4175,7 @@ inline QualType Sema::CheckRemainderOperands(
}
inline QualType Sema::CheckAdditionOperands( // C99 6.5.6
- Expr *&lex, Expr *&rex, SourceLocation Loc, QualType* CompLHSTy)
-{
+ 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;
@@ -3775,12 +4193,14 @@ inline QualType Sema::CheckAdditionOperands( // C99 6.5.6
// Put any potential pointer into PExp
Expr* PExp = lex, *IExp = rex;
- if (IExp->getType()->isPointerType())
+ if (IExp->getType()->isAnyPointerType())
std::swap(PExp, IExp);
- if (const PointerType *PTy = PExp->getType()->getAsPointerType()) {
+ if (PExp->getType()->isAnyPointerType()) {
+
if (IExp->getType()->isIntegerType()) {
- QualType PointeeTy = PTy->getPointeeType();
+ QualType PointeeTy = PExp->getType()->getPointeeType();
+
// Check for arithmetic on pointers to incomplete types.
if (PointeeTy->isVoidType()) {
if (getLangOptions().CPlusPlus) {
@@ -3802,30 +4222,31 @@ inline QualType Sema::CheckAdditionOperands( // C99 6.5.6
// 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();
-
+ } else {
+ // Check if we require a complete type.
+ if (((PExp->getType()->isPointerType() &&
+ !PExp->getType()->isDependentType()) ||
+ PExp->getType()->isObjCObjectPointerType()) &&
+ RequireCompleteType(Loc, PointeeTy,
+ PDiag(diag::err_typecheck_arithmetic_incomplete_type)
+ << PExp->getSourceRange()
+ << 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;
+ QualType LHSTy = Context.isPromotableBitField(lex);
+ if (LHSTy.isNull()) {
+ LHSTy = lex->getType();
+ if (LHSTy->isPromotableIntegerType())
+ LHSTy = Context.getPromotedIntegerType(LHSTy);
}
-
*CompLHSTy = LHSTy;
}
return PExp->getType();
@@ -3856,8 +4277,8 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex,
}
// Either ptr - int or ptr - ptr.
- if (const PointerType *LHSPTy = lex->getType()->getAsPointerType()) {
- QualType lpointee = LHSPTy->getPointeeType();
+ if (lex->getType()->isAnyPointerType()) {
+ QualType lpointee = lex->getType()->getPointeeType();
// The LHS must be an completely-defined object type.
@@ -3882,11 +4303,10 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex,
// 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()))
+ RequireCompleteType(Loc, lpointee,
+ PDiag(diag::err_typecheck_sub_ptr_object)
+ << lex->getSourceRange()
+ << lex->getType()))
return QualType();
// Diagnose bad cases where we step over interface counts.
@@ -3895,7 +4315,7 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex,
<< lpointee << lex->getSourceRange();
return QualType();
}
-
+
// The result type of a pointer-int computation is the pointer type.
if (rex->getType()->isIntegerType()) {
if (ComplainAboutVoid)
@@ -3903,7 +4323,7 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex,
<< lex->getSourceRange() << rex->getSourceRange();
if (ComplainAboutFunc)
Diag(Loc, diag::ext_gnu_ptr_func_arith)
- << ComplainAboutFunc->getType()
+ << ComplainAboutFunc->getType()
<< ComplainAboutFunc->getSourceRange();
if (CompLHSTy) *CompLHSTy = lex->getType();
@@ -3911,7 +4331,7 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex,
}
// Handle pointer-pointer subtractions.
- if (const PointerType *RHSPTy = rex->getType()->getAsPointerType()) {
+ if (const PointerType *RHSPTy = rex->getType()->getAs<PointerType>()) {
QualType rpointee = RHSPTy->getPointeeType();
// RHS must be a completely-type object type.
@@ -3936,10 +4356,9 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex,
ComplainAboutFunc = rex;
} else if (!rpointee->isDependentType() &&
RequireCompleteType(Loc, rpointee,
- diag::err_typecheck_sub_ptr_object,
- rex->getSourceRange(),
- SourceRange(),
- rex->getType()))
+ PDiag(diag::err_typecheck_sub_ptr_object)
+ << rex->getSourceRange()
+ << rex->getType()))
return QualType();
if (getLangOptions().CPlusPlus) {
@@ -3967,7 +4386,7 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex,
<< lex->getSourceRange() << rex->getSourceRange();
if (ComplainAboutFunc)
Diag(Loc, diag::ext_gnu_ptr_func_arith)
- << ComplainAboutFunc->getType()
+ << ComplainAboutFunc->getType()
<< ComplainAboutFunc->getSourceRange();
if (CompLHSTy) *CompLHSTy = lex->getType();
@@ -3987,19 +4406,32 @@ QualType Sema::CheckShiftOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
// 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();
+ QualType LHSTy = Context.isPromotableBitField(lex);
+ if (LHSTy.isNull()) {
+ LHSTy = lex->getType();
+ if (LHSTy->isPromotableIntegerType())
+ LHSTy = Context.getPromotedIntegerType(LHSTy);
}
if (!isCompAssign)
ImpCastExprToType(lex, LHSTy);
UsualUnaryConversions(rex);
+ // Sanity-check shift operands
+ llvm::APSInt Right;
+ // Check right/shifter operand
+ if (!rex->isValueDependent() &&
+ rex->isIntegerConstantExpr(Right, Context)) {
+ if (Right.isNegative())
+ Diag(Loc, diag::warn_shift_negative) << rex->getSourceRange();
+ else {
+ llvm::APInt LeftBits(Right.getBitWidth(),
+ Context.getTypeSize(lex->getType()));
+ if (Right.uge(LeftBits))
+ Diag(Loc, diag::warn_shift_gt_typewidth) << rex->getSourceRange();
+ }
+ }
+
// "The type of the result is that of the promoted left operand."
return LHSTy;
}
@@ -4027,7 +4459,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
// 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
+ // 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();
@@ -4036,24 +4468,25 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
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)) {
+ !RHSStripped->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNull)) {
literalString = lex;
literalStringStripped = LHSStripped;
- }
- else if ((isa<StringLiteral>(RHSStripped) ||
- isa<ObjCEncodeExpr>(RHSStripped)) &&
- !LHSStripped->isNullPointerConstant(Context)) {
+ } else if ((isa<StringLiteral>(RHSStripped) ||
+ isa<ObjCEncodeExpr>(RHSStripped)) &&
+ !LHSStripped->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNull)) {
literalString = rex;
literalStringStripped = RHSStripped;
}
@@ -4098,41 +4531,31 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
return ResultTy;
}
- bool LHSIsNull = lex->isNullPointerConstant(Context);
- bool RHSIsNull = rex->isNullPointerConstant(Context);
+ bool LHSIsNull = lex->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNull);
+ bool RHSIsNull = rex->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNull);
// 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());
+ Context.getCanonicalType(lType->getAs<PointerType>()->getPointeeType());
QualType RCanPointeeTy =
- Context.getCanonicalType(rType->getAsPointerType()->getPointeeType());
-
- if (rType->isFunctionPointerType() || lType->isFunctionPointerType()) {
- if (isRelational) {
- Diag(Loc, diag::ext_typecheck_ordered_comparison_of_function_pointers)
- << lType << rType << lex->getSourceRange() << rex->getSourceRange();
- }
- }
- if (((!LHSIsNull || isRelational) && LCanPointeeTy->isVoidType()) !=
- ((!RHSIsNull || isRelational) && RCanPointeeTy->isVoidType())) {
- Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers)
- << lType << rType << lex->getSourceRange() << rex->getSourceRange();
- }
- // Simple check: if the pointee types are identical, we're done.
- if (LCanPointeeTy == RCanPointeeTy)
- return ResultTy;
+ Context.getCanonicalType(rType->getAs<PointerType>()->getPointeeType());
if (getLangOptions().CPlusPlus) {
+ if (LCanPointeeTy == RCanPointeeTy)
+ return ResultTy;
+
// C++ [expr.rel]p2:
// [...] Pointer conversions (4.10) and qualification
// conversions (4.4) are performed on pointer operands (or on
// a pointer operand and a null pointer constant) to bring
// them to their composite pointer type. [...]
//
- // C++ [expr.eq]p2 uses the same notion for (in)equality
+ // C++ [expr.eq]p1 uses the same notion for (in)equality
// comparisons of pointers.
QualType T = FindCompositePointerType(lex, rex);
if (T.isNull()) {
@@ -4145,36 +4568,82 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
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)) {
+ // C99 6.5.9p2 and C99 6.5.8p2
+ if (Context.typesAreCompatible(LCanPointeeTy.getUnqualifiedType(),
+ RCanPointeeTy.getUnqualifiedType())) {
+ // Valid unless a relational comparison of function pointers
+ if (isRelational && LCanPointeeTy->isFunctionType()) {
+ Diag(Loc, diag::ext_typecheck_ordered_comparison_of_function_pointers)
+ << lType << rType << lex->getSourceRange() << rex->getSourceRange();
+ }
+ } else if (!isRelational &&
+ (LCanPointeeTy->isVoidType() || RCanPointeeTy->isVoidType())) {
+ // Valid unless comparison between non-null pointer and function pointer
+ if ((LCanPointeeTy->isFunctionType() || RCanPointeeTy->isFunctionType())
+ && !LHSIsNull && !RHSIsNull) {
+ Diag(Loc, diag::ext_typecheck_comparison_of_fptr_to_void)
+ << lType << rType << lex->getSourceRange() << rex->getSourceRange();
+ }
+ } else {
+ // Invalid
Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers)
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
}
- ImpCastExprToType(rex, lType); // promote the pointer to pointer
+ if (LCanPointeeTy != RCanPointeeTy)
+ 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);
+ // Comparison of pointers with null pointer constants and equality
+ // comparisons of member pointers to null pointer constants.
+ if (RHSIsNull &&
+ (lType->isPointerType() ||
+ (!isRelational && lType->isMemberPointerType()))) {
+ ImpCastExprToType(rex, lType, CastExpr::CK_NullToMemberPointer);
+ return ResultTy;
+ }
+ if (LHSIsNull &&
+ (rType->isPointerType() ||
+ (!isRelational && rType->isMemberPointerType()))) {
+ ImpCastExprToType(lex, rType, CastExpr::CK_NullToMemberPointer);
return ResultTy;
}
- if (rType->isPointerType() && LHSIsNull) {
- ImpCastExprToType(lex, rType);
+
+ // Comparison of member pointers.
+ if (!isRelational &&
+ lType->isMemberPointerType() && rType->isMemberPointerType()) {
+ // C++ [expr.eq]p2:
+ // In addition, pointers to members can be compared, or a pointer to
+ // member and a null pointer constant. Pointer to member conversions
+ // (4.11) and qualification conversions (4.4) are performed to bring
+ // them to a common type. If one operand is a null pointer constant,
+ // the common type is the type of the other operand. Otherwise, the
+ // common type is a pointer to member type similar (4.4) to the type
+ // of one of the operands, with a cv-qualification signature (4.4)
+ // that is the union of the cv-qualification signatures of the operand
+ // types.
+ 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;
}
- // And comparison of nullptr_t with itself.
+
+ // 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();
+ QualType lpointee = lType->getAs<BlockPointerType>()->getPointeeType();
+ QualType rpointee = rType->getAs<BlockPointerType>()->getPointeeType();
if (!LHSIsNull && !RHSIsNull &&
!Context.typesAreCompatible(lpointee, rpointee)) {
@@ -4189,9 +4658,9 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
&& ((lType->isBlockPointerType() && rType->isPointerType())
|| (lType->isPointerType() && rType->isBlockPointerType()))) {
if (!LHSIsNull && !RHSIsNull) {
- if (!((rType->isPointerType() && rType->getAsPointerType()
+ if (!((rType->isPointerType() && rType->getAs<PointerType>()
->getPointeeType()->isVoidType())
- || (lType->isPointerType() && lType->getAsPointerType()
+ || (lType->isPointerType() && lType->getAs<PointerType>()
->getPointeeType()->isVoidType())))
Diag(Loc, diag::err_typecheck_comparison_of_distinct_blocks)
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
@@ -4200,10 +4669,10 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
return ResultTy;
}
- if ((lType->isObjCQualifiedIdType() || rType->isObjCQualifiedIdType())) {
+ if ((lType->isObjCObjectPointerType() || rType->isObjCObjectPointerType())) {
if (lType->isPointerType() || rType->isPointerType()) {
- const PointerType *LPT = lType->getAsPointerType();
- const PointerType *RPT = rType->getAsPointerType();
+ const PointerType *LPT = lType->getAs<PointerType>();
+ const PointerType *RPT = rType->getAs<PointerType>();
bool LPtrToVoid = LPT ?
Context.getCanonicalType(LPT->getPointeeType())->isVoidType() : false;
bool RPtrToVoid = RPT ?
@@ -4213,43 +4682,49 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
!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)) {
+ if (lType->isObjCObjectPointerType() && rType->isObjCObjectPointerType()) {
+ if (!Context.areComparableObjCPointerTypes(lType, rType))
+ Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers)
+ << lType << rType << lex->getSourceRange() << rex->getSourceRange();
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 (isRelational)
- Diag(Loc, diag::ext_typecheck_ordered_comparison_of_pointer_integer)
- << lType << rType << lex->getSourceRange() << rex->getSourceRange();
- else if (!RHSIsNull)
- Diag(Loc, diag::ext_typecheck_comparison_of_pointer_integer)
+ if (lType->isAnyPointerType() && rType->isIntegerType()) {
+ unsigned DiagID = 0;
+ if (RHSIsNull) {
+ if (isRelational)
+ DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_and_zero;
+ } else if (isRelational)
+ DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_integer;
+ else
+ DiagID = diag::ext_typecheck_comparison_of_pointer_integer;
+
+ if (DiagID) {
+ Diag(Loc, DiagID)
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
+ }
ImpCastExprToType(rex, lType); // promote the integer to pointer
return ResultTy;
}
- if (lType->isIntegerType() &&
- (rType->isPointerType() || rType->isObjCQualifiedIdType())) {
- if (isRelational)
- Diag(Loc, diag::ext_typecheck_ordered_comparison_of_pointer_integer)
- << lType << rType << lex->getSourceRange() << rex->getSourceRange();
- else if (!LHSIsNull)
- Diag(Loc, diag::ext_typecheck_comparison_of_pointer_integer)
+ if (lType->isIntegerType() && rType->isAnyPointerType()) {
+ unsigned DiagID = 0;
+ if (LHSIsNull) {
+ if (isRelational)
+ DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_and_zero;
+ } else if (isRelational)
+ DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_integer;
+ else
+ DiagID = diag::ext_typecheck_comparison_of_pointer_integer;
+
+ if (DiagID) {
+ Diag(Loc, DiagID)
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
+ }
ImpCastExprToType(lex, rType); // promote the integer to pointer
return ResultTy;
}
@@ -4299,21 +4774,13 @@ QualType Sema::CheckVectorCompareOperands(Expr *&lex, Expr *&rex,
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();
+ const VectorType *VTy = lType->getAs<VectorType>();
unsigned TypeSize = Context.getTypeSize(VTy->getElementType());
if (TypeSize == Context.getTypeSize(Context.IntTy))
return Context.getExtVectorType(Context.IntTy, VTy->getNumElements());
@@ -4326,8 +4793,7 @@ QualType Sema::CheckVectorCompareOperands(Expr *&lex, Expr *&rex,
}
inline QualType Sema::CheckBitwiseOperands(
- Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign)
-{
+ Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) {
if (lex->getType()->isVectorType() || rex->getType()->isVectorType())
return CheckVectorOperands(Loc, lex, rex);
@@ -4339,8 +4805,7 @@ inline QualType Sema::CheckBitwiseOperands(
}
inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
- Expr *&lex, Expr *&rex, SourceLocation Loc)
-{
+ Expr *&lex, Expr *&rex, SourceLocation Loc) {
UsualUnaryConversions(lex);
UsualUnaryConversions(rex);
@@ -4353,18 +4818,16 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
/// 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)
-{
+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;
+ if (const ObjCObjectPointerType *OPT =
+ BaseType->getAsObjCInterfacePointerType())
+ if (ObjCInterfaceDecl *IFace = OPT->getInterfaceDecl())
+ if (S.isPropertyReadonly(PDecl, IFace))
+ return true;
}
}
return false;
@@ -4374,7 +4837,7 @@ static bool IsReadonlyProperty(Expr *E, Sema &S)
/// 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,
+ Expr::isModifiableLvalueResult IsLV = E->isModifiableLvalue(S.Context,
&Loc);
if (IsLV == Expr::MLV_Valid && IsReadonlyProperty(E, S))
IsLV = Expr::MLV_ReadonlyProperty;
@@ -4403,8 +4866,8 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
case Expr::MLV_IncompleteType:
case Expr::MLV_IncompleteVoidType:
return S.RequireCompleteType(Loc, E->getType(),
- diag::err_typecheck_incomplete_type_not_modifiable_lvalue,
- E->getSourceRange());
+ PDiag(diag::err_typecheck_incomplete_type_not_modifiable_lvalue)
+ << E->getSourceRange());
case Expr::MLV_DuplicateVectorComponents:
Diag = diag::err_typecheck_duplicate_vector_components_not_mlvalue;
break;
@@ -4425,7 +4888,7 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
if (NeedType)
S.Diag(Loc, Diag) << E->getType() << E->getSourceRange() << Assign;
else
- S.Diag(Loc, Diag) << E->getSourceRange() << Assign;
+ S.Diag(Loc, Diag) << E->getSourceRange() << Assign;
return true;
}
@@ -4449,9 +4912,9 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, Expr *&RHS,
// Special case of NSObject attributes on c-style pointer types.
if (ConvTy == IncompatiblePointer &&
((Context.isObjCNSObjectType(LHSType) &&
- Context.isObjCObjectPointerType(RHSType)) ||
+ RHSType->isObjCObjectPointerType()) ||
(Context.isObjCNSObjectType(RHSType) &&
- Context.isObjCObjectPointerType(LHSType))))
+ LHSType->isObjCObjectPointerType())))
ConvTy = Compatible;
// If the RHS is a unary plus or minus, check to see if they = and + are
@@ -4525,9 +4988,11 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc,
Diag(OpLoc, diag::warn_increment_bool) << Op->getSourceRange();
} else if (ResType->isRealType()) {
// OK!
- } else if (const PointerType *PT = ResType->getAsPointerType()) {
+ } else if (ResType->isAnyPointerType()) {
+ QualType PointeeTy = ResType->getPointeeType();
+
// C99 6.5.2.4p2, 6.5.6p2
- if (PT->getPointeeType()->isVoidType()) {
+ if (PointeeTy->isVoidType()) {
if (getLangOptions().CPlusPlus) {
Diag(OpLoc, diag::err_typecheck_pointer_arith_void_type)
<< Op->getSourceRange();
@@ -4536,7 +5001,7 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc,
// Pointer to void is a GNU extension in C.
Diag(OpLoc, diag::ext_gnu_void_ptr) << Op->getSourceRange();
- } else if (PT->getPointeeType()->isFunctionType()) {
+ } else if (PointeeTy->isFunctionType()) {
if (getLangOptions().CPlusPlus) {
Diag(OpLoc, diag::err_typecheck_pointer_arith_function_type)
<< Op->getType() << Op->getSourceRange();
@@ -4545,11 +5010,17 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc,
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))
+ } else if (RequireCompleteType(OpLoc, PointeeTy,
+ PDiag(diag::err_typecheck_arithmetic_incomplete_type)
+ << Op->getSourceRange()
+ << ResType))
return QualType();
+ // Diagnose bad cases where we step over interface counts.
+ else if (PointeeTy->isObjCInterfaceType() && LangOpts.ObjCNonFragileABI) {
+ Diag(OpLoc, diag::err_arithmetic_nonfragile_interface)
+ << PointeeTy << Op->getSourceRange();
+ 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)
@@ -4672,6 +5143,15 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) {
Diag(OpLoc, diag::err_typecheck_address_of)
<< "vector element" << op->getSourceRange();
return QualType();
+ } else if (isa<ObjCPropertyRefExpr>(op)) {
+ // cannot take address of a property expression.
+ Diag(OpLoc, diag::err_typecheck_address_of)
+ << "property expression" << op->getSourceRange();
+ return QualType();
+ } else if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(op)) {
+ // FIXME: Can LHS ever be null here?
+ if (!CheckAddressOfOperand(CO->getTrueExpr(), OpLoc).isNull())
+ return CheckAddressOfOperand(CO->getFalseExpr(), OpLoc);
} 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.
@@ -4681,17 +5161,26 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) {
<< "register variable" << op->getSourceRange();
return QualType();
}
- } else if (isa<OverloadedFunctionDecl>(dcl)) {
+ } else if (isa<OverloadedFunctionDecl>(dcl) ||
+ isa<FunctionTemplateDecl>(dcl)) {
return Context.OverloadTy;
- } else if (isa<FieldDecl>(dcl)) {
+ } else if (FieldDecl *FD = dyn_cast<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())
+ if (Ctx && Ctx->isRecord()) {
+ if (FD->getType()->isReferenceType()) {
+ Diag(OpLoc,
+ diag::err_cannot_form_pointer_to_member_of_reference_type)
+ << FD->getDeclName() << FD->getType();
+ return QualType();
+ }
+
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.
@@ -4725,9 +5214,12 @@ QualType Sema::CheckIndirectionOperand(Expr *Op, SourceLocation OpLoc) {
// 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())
+ if (const PointerType *PT = Ty->getAs<PointerType>())
return PT->getPointeeType();
+ if (const ObjCObjectPointerType *OPT = Ty->getAs<ObjCObjectPointerType>())
+ return OPT->getPointeeType();
+
Diag(OpLoc, diag::err_typecheck_indirection_requires_pointer)
<< Ty << Op->getSourceRange();
return QualType();
@@ -4914,7 +5406,7 @@ Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
assert((rhs != 0) && "ActOnBinOp(): missing right expression");
if (getLangOptions().CPlusPlus &&
- (lhs->getType()->isOverloadableType() ||
+ (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
@@ -4926,7 +5418,7 @@ Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
LookupOverloadedOperatorName(OverOp, S, lhs->getType(), rhs->getType(),
Functions);
Expr *Args[2] = { lhs, rhs };
- DeclarationName OpName
+ DeclarationName OpName
= Context.DeclarationNames.getCXXOperatorName(OverOp);
ArgumentDependentLookup(OpName, Args, 2, Functions);
}
@@ -4941,7 +5433,7 @@ Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
}
Action::OwningExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
- unsigned OpcIn,
+ unsigned OpcIn,
ExprArg InputArg) {
UnaryOperator::Opcode Opc = static_cast<UnaryOperator::Opcode>(OpcIn);
@@ -4949,16 +5441,17 @@ Action::OwningExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
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:
+ case UnaryOperator::PostInc:
+ case UnaryOperator::PostDec:
resultType = CheckIncrementDecrementOperand(Input, OpLoc,
- Opc == UnaryOperator::PreInc);
+ Opc == UnaryOperator::PreInc ||
+ Opc == UnaryOperator::PostInc);
break;
case UnaryOperator::AddrOf:
resultType = CheckAddressOfOperand(Input, OpLoc);
@@ -5043,7 +5536,7 @@ Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
if (OverOp != OO_None) {
LookupOverloadedOperatorName(OverOp, S, Input->getType(), QualType(),
Functions);
- DeclarationName OpName
+ DeclarationName OpName
= Context.DeclarationNames.getCXXOperatorName(OverOp);
ArgumentDependentLookup(OpName, &Input, 1, Functions);
}
@@ -5116,7 +5609,8 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
SourceLocation RPLoc) {
// FIXME: This function leaks all expressions in the offset components on
// error.
- QualType ArgTy = QualType::getFromOpaquePtr(argty);
+ // FIXME: Preserve type source info.
+ QualType ArgTy = GetTypeFromParser(argty);
assert(!ArgTy.isNull() && "Missing type argument!");
bool Dependent = ArgTy->isDependentType();
@@ -5147,7 +5641,7 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
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) {
@@ -5180,7 +5674,7 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
continue;
}
- const RecordType *RC = Res->getType()->getAsRecordType();
+ const RecordType *RC = Res->getType()->getAs<RecordType>();
if (!RC) {
Res->Destroy(Context);
return ExprError(Diag(OC.LocEnd, diag::err_offsetof_record_type)
@@ -5197,15 +5691,16 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
DidWarnAboutNonPOD = true;
}
}
-
+
+ LookupResult R;
+ LookupQualifiedName(R, RD, OC.U.IdentInfo, LookupMemberName);
+
FieldDecl *MemberDecl
- = dyn_cast_or_null<FieldDecl>(LookupQualifiedName(RD, OC.U.IdentInfo,
- LookupMemberName)
- .getAsDecl());
+ = dyn_cast_or_null<FieldDecl>(R.getAsSingleDecl(Context));
// FIXME: Leaks Res
if (!MemberDecl)
- return ExprError(Diag(BuiltinLoc, diag::err_typecheck_no_member)
- << OC.U.IdentInfo << SourceRange(OC.LocStart, OC.LocEnd));
+ return ExprError(Diag(BuiltinLoc, diag::err_no_member)
+ << OC.U.IdentInfo << RD << SourceRange(OC.LocStart, OC.LocEnd));
// FIXME: C++: Verify that MemberDecl isn't a static field.
// FIXME: Verify that MemberDecl isn't a bitfield.
@@ -5229,8 +5724,9 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
Sema::OwningExprResult Sema::ActOnTypesCompatibleExpr(SourceLocation BuiltinLoc,
TypeTy *arg1,TypeTy *arg2,
SourceLocation RPLoc) {
- QualType argT1 = QualType::getFromOpaquePtr(arg1);
- QualType argT2 = QualType::getFromOpaquePtr(arg2);
+ // FIXME: Preserve type source info.
+ QualType argT1 = GetTypeFromParser(arg1);
+ QualType argT2 = GetTypeFromParser(arg2);
assert((!argT1.isNull() && !argT2.isNull()) && "Missing type argument(s)");
@@ -5255,8 +5751,10 @@ Sema::OwningExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc,
assert((CondExpr && LHSExpr && RHSExpr) && "Missing type argument(s)");
QualType resType;
+ bool ValueDependent = false;
if (CondExpr->isTypeDependent() || CondExpr->isValueDependent()) {
resType = Context.DependentTy;
+ ValueDependent = true;
} else {
// The conditional expression is required to be a constant expression.
llvm::APSInt condEval(32);
@@ -5268,11 +5766,15 @@ Sema::OwningExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc,
// If the condition is > zero, then the AST type is the same as the LSHExpr.
resType = condEval.getZExtValue() ? LHSExpr->getType() : RHSExpr->getType();
+ ValueDependent = condEval.getZExtValue() ? LHSExpr->isValueDependent()
+ : RHSExpr->isValueDependent();
}
cond.release(); expr1.release(); expr2.release();
return Owned(new (Context) ChooseExpr(BuiltinLoc, CondExpr, LHSExpr, RHSExpr,
- resType, RPLoc));
+ resType, RPLoc,
+ resType->isDependentType(),
+ ValueDependent));
}
//===----------------------------------------------------------------------===//
@@ -5291,6 +5793,7 @@ void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *BlockScope) {
BSI->ReturnType = QualType();
BSI->TheScope = BlockScope;
BSI->hasBlockDeclRefExprs = false;
+ BSI->hasPrototype = false;
BSI->SavedFunctionNeedsScopeChecking = CurFunctionNeedsScopeChecking;
CurFunctionNeedsScopeChecking = false;
@@ -5320,12 +5823,12 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
CurBlock->isVariadic = false;
// Check for a valid sentinel attribute on this block.
if (CurBlock->TheDecl->getAttr<SentinelAttr>()) {
- Diag(ParamInfo.getAttributes()->getLoc(),
+ Diag(ParamInfo.getAttributes()->getLoc(),
diag::warn_attribute_sentinel_not_variadic) << 1;
// FIXME: remove the attribute.
}
- QualType RetTy = T.getTypePtr()->getAsFunctionType()->getResultType();
-
+ QualType RetTy = T.getTypePtr()->getAs<FunctionType>()->getResultType();
+
// Do not allow returning a objc interface by-value.
if (RetTy->isObjCInterfaceType()) {
Diag(ParamInfo.getSourceRange().getBegin(),
@@ -5367,17 +5870,17 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
PushOnScopeChains(*AI, CurBlock->TheScope);
// Check for a valid sentinel attribute on this block.
- if (!CurBlock->isVariadic &&
+ if (!CurBlock->isVariadic &&
CurBlock->TheDecl->getAttr<SentinelAttr>()) {
- Diag(ParamInfo.getAttributes()->getLoc(),
+ 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();
-
+ QualType RetTy = T->getAs<FunctionType>()->getResultType();
+
// Do not allow returning a objc interface by-value.
if (RetTy->isObjCInterfaceType()) {
Diag(ParamInfo.getSourceRange().getBegin(),
@@ -5407,7 +5910,7 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
// 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);
@@ -5424,12 +5927,15 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
for (unsigned i = 0, e = BSI->Params.size(); i != e; ++i)
ArgTypes.push_back(BSI->Params[i]->getType());
+ bool NoReturn = BSI->TheDecl->getAttr<NoReturnAttr>();
QualType BlockTy;
if (!BSI->hasPrototype)
- BlockTy = Context.getFunctionType(RetTy, 0, 0, false, 0);
+ BlockTy = Context.getFunctionType(RetTy, 0, 0, false, 0, false, false, 0, 0,
+ NoReturn);
else
BlockTy = Context.getFunctionType(RetTy, ArgTypes.data(), ArgTypes.size(),
- BSI->isVariadic, 0);
+ BSI->isVariadic, 0, false, false, 0, 0,
+ NoReturn);
// FIXME: Check that return/parameter types are complete/non-abstract
DiagnoseUnusedParameters(BSI->Params.begin(), BSI->Params.end());
@@ -5439,8 +5945,9 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
if (CurFunctionNeedsScopeChecking)
DiagnoseInvalidJumps(static_cast<CompoundStmt*>(body.get()));
CurFunctionNeedsScopeChecking = BSI->SavedFunctionNeedsScopeChecking;
-
+
BSI->TheDecl->setBody(body.takeAs<CompoundStmt>());
+ CheckFallThroughForBlock(BlockTy, BSI->TheDecl->getBody());
return Owned(new (Context) BlockExpr(BSI->TheDecl, BlockTy,
BSI->hasBlockDeclRefExprs));
}
@@ -5448,10 +5955,10 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
Sema::OwningExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc,
ExprArg expr, TypeTy *type,
SourceLocation RPLoc) {
- QualType T = QualType::getFromOpaquePtr(type);
+ QualType T = GetTypeFromParser(type);
Expr *E = static_cast<Expr*>(expr.get());
Expr *OrigExpr = E;
-
+
InitBuiltinVaListType();
// Get the va_list type
@@ -5466,7 +5973,7 @@ Sema::OwningExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc,
} else {
// Otherwise, the va_list argument must be an l-value because
// it is modified by va_arg.
- if (!E->isTypeDependent() &&
+ if (!E->isTypeDependent() &&
CheckForModifiableLvalue(E, BuiltinLoc, *this))
return ExprError();
}
@@ -5600,17 +6107,17 @@ bool Sema::VerifyIntegerConstantExpression(const Expr *E, llvm::APSInt *Result){
return false;
}
-Sema::ExpressionEvaluationContext
-Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext) {
+Sema::ExpressionEvaluationContext
+Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext) {
// Introduce a new set of potentially referenced declarations to the stack.
if (NewContext == PotentiallyPotentiallyEvaluated)
PotentiallyReferencedDeclStack.push_back(PotentiallyReferencedDecls());
-
+
std::swap(ExprEvalContext, NewContext);
return NewContext;
}
-void
+void
Sema::PopExpressionEvaluationContext(ExpressionEvaluationContext OldContext,
ExpressionEvaluationContext NewContext) {
ExprEvalContext = NewContext;
@@ -5622,7 +6129,7 @@ Sema::PopExpressionEvaluationContext(ExpressionEvaluationContext OldContext,
PotentiallyReferencedDecls RemainingDecls;
RemainingDecls.swap(PotentiallyReferencedDeclStack.back());
PotentiallyReferencedDeclStack.pop_back();
-
+
for (PotentiallyReferencedDecls::iterator I = RemainingDecls.begin(),
IEnd = RemainingDecls.end();
I != IEnd; ++I)
@@ -5642,30 +6149,33 @@ Sema::PopExpressionEvaluationContext(ExpressionEvaluationContext OldContext,
/// \param D the declaration that has been referenced by the source code.
void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
assert(D && "No declaration?");
-
+
if (D->isUsed())
return;
-
- // Mark a parameter declaration "used", regardless of whether we're in a
- // template or not.
- if (isa<ParmVarDecl>(D))
+
+ // Mark a parameter or variable declaration "used", regardless of whether we're in a
+ // template or not. The reason for this is that unevaluated expressions
+ // (e.g. (void)sizeof()) constitute a use for warning purposes (-Wunused-variables and
+ // -Wunused-parameters)
+ if (isa<ParmVarDecl>(D) ||
+ (isa<VarDecl>(D) && D->getDeclContext()->isFunctionOrMethod()))
D->setUsed(true);
-
+
// Do not mark anything as "used" within a dependent context; wait for
// an instantiation.
if (CurContext->isDependentContext())
return;
-
+
switch (ExprEvalContext) {
case Unevaluated:
// We are in an expression that is not potentially evaluated; do nothing.
return;
-
+
case PotentiallyEvaluated:
// We are in a potentially-evaluated expression, so this declaration is
// "used"; handle this below.
break;
-
+
case PotentiallyPotentiallyEvaluated:
// We are in an expression that may be potentially evaluated; queue this
// declaration reference until we know whether the expression is
@@ -5673,23 +6183,22 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
PotentiallyReferencedDeclStack.back().push_back(std::make_pair(Loc, D));
return;
}
-
+
// Note that this declaration has been used.
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
unsigned TypeQuals;
if (Constructor->isImplicit() && Constructor->isDefaultConstructor()) {
if (!Constructor->isUsed())
DefineImplicitDefaultConstructor(Loc, Constructor);
- }
- else if (Constructor->isImplicit() &&
- Constructor->isCopyConstructor(Context, TypeQuals)) {
+ } else if (Constructor->isImplicit() &&
+ Constructor->isCopyConstructor(Context, TypeQuals)) {
if (!Constructor->isUsed())
DefineImplicitCopyConstructor(Loc, Constructor, TypeQuals);
}
} else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
if (Destructor->isImplicit() && !Destructor->isUsed())
DefineImplicitDestructor(Loc, Destructor);
-
+
} else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(D)) {
if (MethodDecl->isImplicit() && MethodDecl->isOverloadedOperator() &&
MethodDecl->getOverloadedOperator() == OO_Equal) {
@@ -5698,28 +6207,125 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
}
}
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
- // Implicit instantiation of function templates and member functions of
+ // Implicit instantiation of function templates and member functions of
// class templates.
- if (!Function->getBody()) {
- // FIXME: distinguish between implicit instantiations of function
- // templates and explicit specializations (the latter don't get
- // instantiated, naturally).
- if (Function->getInstantiatedFromMemberFunction() ||
- Function->getPrimaryTemplate())
+ if (!Function->getBody() &&
+ Function->getTemplateSpecializationKind()
+ == TSK_ImplicitInstantiation) {
+ bool AlreadyInstantiated = false;
+ if (FunctionTemplateSpecializationInfo *SpecInfo
+ = Function->getTemplateSpecializationInfo()) {
+ if (SpecInfo->getPointOfInstantiation().isInvalid())
+ SpecInfo->setPointOfInstantiation(Loc);
+ else
+ AlreadyInstantiated = true;
+ } else if (MemberSpecializationInfo *MSInfo
+ = Function->getMemberSpecializationInfo()) {
+ if (MSInfo->getPointOfInstantiation().isInvalid())
+ MSInfo->setPointOfInstantiation(Loc);
+ else
+ AlreadyInstantiated = true;
+ }
+
+ if (!AlreadyInstantiated)
PendingImplicitInstantiations.push_back(std::make_pair(Function, Loc));
}
-
// FIXME: keep track of references to static functions
Function->setUsed(true);
return;
}
-
+
if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
- (void)Var;
- // FIXME: implicit template instantiation
+ // Implicit instantiation of static data members of class templates.
+ if (Var->isStaticDataMember() &&
+ Var->getInstantiatedFromStaticDataMember()) {
+ MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo();
+ assert(MSInfo && "Missing member specialization information?");
+ if (MSInfo->getPointOfInstantiation().isInvalid() &&
+ MSInfo->getTemplateSpecializationKind()== TSK_ImplicitInstantiation) {
+ MSInfo->setPointOfInstantiation(Loc);
+ PendingImplicitInstantiations.push_back(std::make_pair(Var, Loc));
+ }
+ }
+
// FIXME: keep track of references to static data?
+
D->setUsed(true);
+ return;
+ }
+}
+
+bool Sema::CheckCallReturnType(QualType ReturnType, SourceLocation Loc,
+ CallExpr *CE, FunctionDecl *FD) {
+ if (ReturnType->isVoidType() || !ReturnType->isIncompleteType())
+ return false;
+
+ PartialDiagnostic Note =
+ FD ? PDiag(diag::note_function_with_incomplete_return_type_declared_here)
+ << FD->getDeclName() : PDiag();
+ SourceLocation NoteLoc = FD ? FD->getLocation() : SourceLocation();
+
+ if (RequireCompleteType(Loc, ReturnType,
+ FD ?
+ PDiag(diag::err_call_function_incomplete_return)
+ << CE->getSourceRange() << FD->getDeclName() :
+ PDiag(diag::err_call_incomplete_return)
+ << CE->getSourceRange(),
+ std::make_pair(NoteLoc, Note)))
+ return true;
+
+ return false;
+}
+
+// Diagnose the common s/=/==/ typo. Note that adding parentheses
+// will prevent this condition from triggering, which is what we want.
+void Sema::DiagnoseAssignmentAsCondition(Expr *E) {
+ SourceLocation Loc;
+
+ if (isa<BinaryOperator>(E)) {
+ BinaryOperator *Op = cast<BinaryOperator>(E);
+ if (Op->getOpcode() != BinaryOperator::Assign)
+ return;
+
+ Loc = Op->getOperatorLoc();
+ } else if (isa<CXXOperatorCallExpr>(E)) {
+ CXXOperatorCallExpr *Op = cast<CXXOperatorCallExpr>(E);
+ if (Op->getOperator() != OO_Equal)
+ return;
+
+ Loc = Op->getOperatorLoc();
+ } else {
+ // Not an assignment.
+ return;
}
+
+ SourceLocation Open = E->getSourceRange().getBegin();
+ SourceLocation Close = PP.getLocForEndOfToken(E->getSourceRange().getEnd());
+
+ Diag(Loc, diag::warn_condition_is_assignment)
+ << E->getSourceRange()
+ << CodeModificationHint::CreateInsertion(Open, "(")
+ << CodeModificationHint::CreateInsertion(Close, ")");
}
+bool Sema::CheckBooleanCondition(Expr *&E, SourceLocation Loc) {
+ DiagnoseAssignmentAsCondition(E);
+
+ if (!E->isTypeDependent()) {
+ DefaultFunctionArrayConversion(E);
+
+ QualType T = E->getType();
+
+ if (getLangOptions().CPlusPlus) {
+ if (CheckCXXBooleanCondition(E)) // C++ 6.4p4
+ return true;
+ } else if (!T->isScalarType()) { // C99 6.8.4.1p1
+ Diag(Loc, diag::err_typecheck_statement_requires_scalar)
+ << T << E->getSourceRange();
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 7afa594..5f111c8 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -11,13 +11,14 @@
//
//===----------------------------------------------------------------------===//
-#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/AST/CXXInheritance.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Parse/DeclSpec.h"
#include "llvm/ADT/STLExtras.h"
using namespace clang;
@@ -31,9 +32,10 @@ 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
+ //FIXME: Preserve type source info.
+ QualType ConvType = GetTypeFromParser(Ty);
+ CanQualType ConvTypeCanon = Context.getCanonicalType(ConvType);
+ DeclarationName ConvName
= Context.DeclarationNames.getCXXConversionFunctionName(ConvTypeCanon);
return ActOnDeclarationNameExpr(S, OperatorLoc, ConvName, HasTrailingLParen,
&SS, isAddressOfOperand);
@@ -59,12 +61,17 @@ Sema::ActOnCXXOperatorFunctionIdExpr(Scope *S, SourceLocation OperatorLoc,
Action::OwningExprResult
Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc,
bool isType, void *TyOrExpr, SourceLocation RParenLoc) {
- NamespaceDecl *StdNs = GetStdNamespace();
- if (!StdNs)
+ if (!StdNamespace)
return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid));
-
+
+ if (isType)
+ // FIXME: Preserve type source info.
+ TyOrExpr = GetTypeFromParser(TyOrExpr).getAsOpaquePtr();
+
IdentifierInfo *TypeInfoII = &PP.getIdentifierTable().get("type_info");
- Decl *TypeInfoDecl = LookupQualifiedName(StdNs, TypeInfoII, LookupTagName);
+ LookupResult R;
+ LookupQualifiedName(R, StdNamespace, TypeInfoII, LookupTagName);
+ Decl *TypeInfoDecl = R.getAsSingleDecl(Context);
RecordDecl *TypeInfoRecordDecl = dyn_cast_or_null<RecordDecl>(TypeInfoDecl);
if (!TypeInfoRecordDecl)
return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid));
@@ -73,29 +80,29 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc,
if (!isType) {
// C++0x [expr.typeid]p3:
- // When typeid is applied to an expression other than an lvalue of a
- // polymorphic class type [...] [the] expression is an unevaluated
+ // When typeid is applied to an expression other than an lvalue of a
+ // polymorphic class type [...] [the] expression is an unevaluated
// operand.
-
+
// FIXME: if the type of the expression is a class type, the class
// shall be completely defined.
bool isUnevaluatedOperand = true;
Expr *E = static_cast<Expr *>(TyOrExpr);
if (E && !E->isTypeDependent() && E->isLvalue(Context) == Expr::LV_Valid) {
QualType T = E->getType();
- if (const RecordType *RecordT = T->getAsRecordType()) {
+ if (const RecordType *RecordT = T->getAs<RecordType>()) {
CXXRecordDecl *RecordD = cast<CXXRecordDecl>(RecordT->getDecl());
if (RecordD->isPolymorphic())
isUnevaluatedOperand = false;
}
}
-
+
// If this is an unevaluated operand, clear out the set of declaration
// references we have been computing.
if (isUnevaluatedOperand)
PotentiallyReferencedDeclStack.back().clear();
}
-
+
return Owned(new (Context) CXXTypeidExpr(isType, TyOrExpr,
TypeInfoType.withConst(),
SourceRange(OpLoc, RParenLoc)));
@@ -136,15 +143,15 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) {
// 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()) {
+ if (const PointerType* Ptr = Ty->getAs<PointerType>()) {
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()))
+ PDiag(isPointer ? diag::err_throw_incomplete_ptr
+ : diag::err_throw_incomplete)
+ << E->getSourceRange()))
return true;
}
@@ -179,7 +186,8 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep,
SourceLocation *CommaLocs,
SourceLocation RParenLoc) {
assert(TypeRep && "Missing type!");
- QualType Ty = QualType::getFromOpaquePtr(TypeRep);
+ // FIXME: Preserve type source info.
+ QualType Ty = GetTypeFromParser(TypeRep);
unsigned NumExprs = exprs.size();
Expr **Exprs = (Expr**)exprs.get();
SourceLocation TyBeginLoc = TypeRange.getBegin();
@@ -188,14 +196,27 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep,
if (Ty->isDependentType() ||
CallExpr::hasAnyTypeDependentArguments(Exprs, NumExprs)) {
exprs.release();
-
- return Owned(CXXUnresolvedConstructExpr::Create(Context,
- TypeRange.getBegin(), Ty,
+
+ return Owned(CXXUnresolvedConstructExpr::Create(Context,
+ TypeRange.getBegin(), Ty,
LParenLoc,
Exprs, NumExprs,
RParenLoc));
}
+ if (Ty->isArrayType())
+ return ExprError(Diag(TyBeginLoc,
+ diag::err_value_init_for_array_type) << FullRange);
+ if (!Ty->isVoidType() &&
+ RequireCompleteType(TyBeginLoc, Ty,
+ PDiag(diag::err_invalid_incomplete_type_use)
+ << FullRange))
+ return ExprError();
+
+ if (RequireNonAbstractType(TyBeginLoc, Ty,
+ diag::err_allocation_of_abstract_type))
+ return ExprError();
+
// C++ [expr.type.conv]p1:
// If the expression list is a single expression, the type conversion
@@ -203,36 +224,54 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep,
// corresponding cast expression.
//
if (NumExprs == 1) {
- if (CheckCastTypes(TypeRange, Ty, Exprs[0]))
+ CastExpr::CastKind Kind = CastExpr::CK_Unknown;
+ CXXMethodDecl *Method = 0;
+ if (CheckCastTypes(TypeRange, Ty, Exprs[0], Kind, Method,
+ /*FunctionalStyle=*/true))
return ExprError();
+
exprs.release();
+ if (Method) {
+ OwningExprResult CastArg
+ = BuildCXXCastArgument(TypeRange.getBegin(), Ty.getNonReferenceType(),
+ Kind, Method, Owned(Exprs[0]));
+ if (CastArg.isInvalid())
+ return ExprError();
+
+ Exprs[0] = CastArg.takeAs<Expr>();
+ }
+
return Owned(new (Context) CXXFunctionalCastExpr(Ty.getNonReferenceType(),
- Ty, TyBeginLoc, Exprs[0],
- RParenLoc));
+ Ty, TyBeginLoc, Kind,
+ Exprs[0], RParenLoc));
}
- if (const RecordType *RT = Ty->getAsRecordType()) {
+ if (const RecordType *RT = Ty->getAs<RecordType>()) {
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()) {
+ if (NumExprs > 1 || !Record->hasTrivialConstructor() ||
+ !Record->hasTrivialDestructor()) {
+ ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
+
CXXConstructorDecl *Constructor
- = PerformInitializationByConstructor(Ty, Exprs, NumExprs,
+ = PerformInitializationByConstructor(Ty, move(exprs),
TypeRange.getBegin(),
SourceRange(TypeRange.getBegin(),
RParenLoc),
DeclarationName(),
- IK_Direct);
+ IK_Direct,
+ ConstructorArgs);
if (!Constructor)
return ExprError();
- exprs.release();
- Expr *E = new (Context) CXXTemporaryObjectExpr(Context, Constructor,
- Ty, TyBeginLoc, Exprs,
- NumExprs, RParenLoc);
- return MaybeBindToTemporary(E);
+ OwningExprResult Result =
+ BuildCXXTemporaryObjectExpr(Constructor, Ty, TyBeginLoc,
+ move_arg(ConstructorArgs), RParenLoc);
+ if (Result.isInvalid())
+ return ExprError();
+
+ return MaybeBindToTemporary(Result.takeAs<Expr>());
}
// Fall through to value-initialize an object of class type that
@@ -255,18 +294,6 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep,
// 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));
}
@@ -283,8 +310,7 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
SourceLocation PlacementRParen, bool ParenTypeId,
Declarator &D, SourceLocation ConstructorLParen,
MultiExprArg ConstructorArgs,
- SourceLocation ConstructorRParen)
-{
+ SourceLocation ConstructorRParen) {
Expr *ArraySize = 0;
unsigned Skip = 0;
// If the specified type is an array, unwrap it and save the expression.
@@ -301,29 +327,37 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
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();
+ if (D.getNumTypeObjects() > 0 &&
+ D.getTypeObject(0).Kind == DeclaratorChunk::Array) {
+ for (unsigned I = 1, N = D.getNumTypeObjects(); I < N; ++I) {
+ if (D.getTypeObject(I).Kind != DeclaratorChunk::Array)
+ break;
+
+ DeclaratorChunk::ArrayTypeInfo &Array = D.getTypeObject(I).Arr;
+ if (Expr *NumElts = (Expr *)Array.NumElts) {
+ if (!NumElts->isTypeDependent() && !NumElts->isValueDependent() &&
+ !NumElts->isIntegerConstantExpr(Context)) {
+ Diag(D.getTypeObject(I).Loc, diag::err_new_array_nonconst)
+ << NumElts->getSourceRange();
+ return ExprError();
+ }
+ }
}
- ElementType = Array->getElementType();
- ++i;
}
+
+ //FIXME: Store DeclaratorInfo in CXXNew expression.
+ DeclaratorInfo *DInfo = 0;
+ QualType AllocType = GetTypeForDeclarator(D, /*Scope=*/0, &DInfo, Skip);
+ if (D.isInvalidType())
+ return ExprError();
- return BuildCXXNew(StartLoc, UseGlobal,
+ return BuildCXXNew(StartLoc, UseGlobal,
PlacementLParen,
- move(PlacementArgs),
+ move(PlacementArgs),
PlacementRParen,
ParenTypeId,
- AllocType,
+ AllocType,
D.getSourceRange().getBegin(),
D.getSourceRange(),
Owned(ArraySize),
@@ -332,12 +366,12 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
ConstructorRParen);
}
-Sema::OwningExprResult
+Sema::OwningExprResult
Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
SourceLocation PlacementLParen,
MultiExprArg PlacementArgs,
SourceLocation PlacementRParen,
- bool ParenTypeId,
+ bool ParenTypeId,
QualType AllocType,
SourceLocation TypeLoc,
SourceRange TypeRange,
@@ -369,12 +403,15 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
llvm::APSInt Value;
if (ArraySize->isIntegerConstantExpr(Value, Context, 0, false)) {
if (Value < llvm::APSInt(
- llvm::APInt::getNullValue(Value.getBitWidth()), false))
+ llvm::APInt::getNullValue(Value.getBitWidth()),
+ Value.isUnsigned()))
return ExprError(Diag(ArraySize->getSourceRange().getBegin(),
diag::err_typecheck_negative_array_size)
<< ArraySize->getSourceRange());
}
}
+
+ ImpCastExprToType(ArraySize, Context.getSizeType());
}
FunctionDecl *OperatorNew = 0;
@@ -413,17 +450,24 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
unsigned NumConsArgs = ConstructorArgs.size();
if (AllocType->isDependentType()) {
// Skip all the checks.
- }
- else if ((RT = AllocType->getAsRecordType()) &&
- !AllocType->isAggregateType()) {
+ } else if ((RT = AllocType->getAs<RecordType>()) &&
+ !AllocType->isAggregateType()) {
+ ASTOwningVector<&ActionBase::DeleteExpr> ConvertedConstructorArgs(*this);
+
Constructor = PerformInitializationByConstructor(
- AllocType, ConsArgs, NumConsArgs,
+ AllocType, move(ConstructorArgs),
TypeLoc,
SourceRange(TypeLoc, ConstructorRParen),
RT->getDecl()->getDeclName(),
- NumConsArgs != 0 ? IK_Direct : IK_Default);
+ NumConsArgs != 0 ? IK_Direct : IK_Default,
+ ConvertedConstructorArgs);
if (!Constructor)
return ExprError();
+
+ // Take the converted constructor arguments and use them for the new
+ // expression.
+ NumConsArgs = ConvertedConstructorArgs.size();
+ ConsArgs = (Expr **)ConvertedConstructorArgs.take();
} else {
if (!Init) {
// FIXME: Check that no subpart is const.
@@ -454,15 +498,14 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
return Owned(new (Context) CXXNewExpr(UseGlobal, OperatorNew, PlaceArgs,
NumPlaceArgs, ParenTypeId, ArraySize, Constructor, Init,
ConsArgs, NumConsArgs, OperatorDelete, ResultType,
- StartLoc, Init ? ConstructorRParen : SourceLocation()));
+ 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)
-{
+ 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())
@@ -473,8 +516,8 @@ bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc,
<< AllocType << 1 << R;
else if (!AllocType->isDependentType() &&
RequireCompleteType(Loc, AllocType,
- diag::err_new_incomplete_type,
- R))
+ PDiag(diag::err_new_incomplete_type)
+ << R))
return true;
else if (RequireNonAbstractType(Loc, AllocType,
diag::err_allocation_of_abstract_type))
@@ -490,8 +533,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
bool IsArray, Expr **PlaceArgs,
unsigned NumPlaceArgs,
FunctionDecl *&OperatorNew,
- FunctionDecl *&OperatorDelete)
-{
+ 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
@@ -506,17 +548,18 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
// 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());
+ IntegerLiteral Size(llvm::APInt::getNullValue(
+ Context.Target.getPointerWidth(0)),
+ Context.getSizeType(),
+ SourceLocation());
+ AllocArgs[0] = &Size;
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());
+ CXXRecordDecl *Record
+ = cast<CXXRecordDecl>(AllocType->getAs<RecordType>()->getDecl());
// FIXME: We fail to find inherited overloads.
if (FindAllocationOverload(StartLoc, Range, NewName, &AllocArgs[0],
AllocArgs.size(), Record, /*AllowMissing=*/true,
@@ -537,10 +580,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
// 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;
}
@@ -549,24 +589,30 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
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(Name);
- if (Alloc == AllocEnd) {
+ bool AllowMissing, FunctionDecl *&Operator) {
+ LookupResult R;
+ LookupQualifiedName(R, Ctx, Name, LookupOrdinaryName);
+ if (R.empty()) {
if (AllowMissing)
return false;
return Diag(StartLoc, diag::err_ovl_no_viable_function_in_call)
<< Name << Range;
}
+ // FIXME: handle ambiguity
+
OverloadCandidateSet Candidates;
- for (; Alloc != AllocEnd; ++Alloc) {
+ for (LookupResult::iterator Alloc = R.begin(), AllocEnd = R.end();
+ 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))
+ if (FunctionDecl *Fn = dyn_cast<FunctionDecl>(*Alloc)) {
AddOverloadCandidate(Fn, Args, NumArgs, Candidates,
/*SuppressUserConversions=*/false);
+ continue;
+ }
+
+ // FIXME: Handle function templates
}
// Do the resolution.
@@ -578,7 +624,7 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
// 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) {
+ for (unsigned i = 0; i < NumArgs; ++i) {
// FIXME: Passing word to diagnostic.
if (PerformCopyInitialization(Args[i],
FnDecl->getParamDecl(i)->getType(),
@@ -623,16 +669,52 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
/// @endcode
/// Note that the placement and nothrow forms of new are *not* implicitly
/// declared. Their use requires including \<new\>.
-void Sema::DeclareGlobalNewDelete()
-{
+void Sema::DeclareGlobalNewDelete() {
if (GlobalNewDeleteDeclared)
return;
+
+ // C++ [basic.std.dynamic]p2:
+ // [...] The following allocation and deallocation functions (18.4) are
+ // implicitly declared in global scope in each translation unit of a
+ // program
+ //
+ // 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();
+ //
+ // These implicit declarations introduce only the function names operator
+ // new, operator new[], operator delete, operator delete[].
+ //
+ // Here, we need to refer to std::bad_alloc, so we will implicitly declare
+ // "std" or "bad_alloc" as necessary to form the exception specification.
+ // However, we do not make these implicit declarations visible to name
+ // lookup.
+ if (!StdNamespace) {
+ // The "std" namespace has not yet been defined, so build one implicitly.
+ StdNamespace = NamespaceDecl::Create(Context,
+ Context.getTranslationUnitDecl(),
+ SourceLocation(),
+ &PP.getIdentifierTable().get("std"));
+ StdNamespace->setImplicit(true);
+ }
+
+ if (!StdBadAlloc) {
+ // The "std::bad_alloc" class has not yet been declared, so build it
+ // implicitly.
+ StdBadAlloc = CXXRecordDecl::Create(Context, TagDecl::TK_class,
+ StdNamespace,
+ SourceLocation(),
+ &PP.getIdentifierTable().get("bad_alloc"),
+ SourceLocation(), 0);
+ StdBadAlloc->setImplicit(true);
+ }
+
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);
@@ -650,8 +732,7 @@ void Sema::DeclareGlobalNewDelete()
/// DeclareGlobalAllocationFunction - Declares a single implicit global
/// allocation function if it doesn't already exist.
void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
- QualType Return, QualType Argument)
-{
+ QualType Return, QualType Argument) {
DeclContext *GlobalCtx = Context.getTranslationUnitDecl();
// Check if this function is already declared.
@@ -667,14 +748,26 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
}
}
- QualType FnType = Context.getFunctionType(Return, &Argument, 1, false, 0);
+ QualType BadAllocType;
+ bool HasBadAllocExceptionSpec
+ = (Name.getCXXOverloadedOperator() == OO_New ||
+ Name.getCXXOverloadedOperator() == OO_Array_New);
+ if (HasBadAllocExceptionSpec) {
+ assert(StdBadAlloc && "Must have std::bad_alloc declared");
+ BadAllocType = Context.getTypeDeclType(StdBadAlloc);
+ }
+
+ QualType FnType = Context.getFunctionType(Return, &Argument, 1, false, 0,
+ true, false,
+ HasBadAllocExceptionSpec? 1 : 0,
+ &BadAllocType);
FunctionDecl *Alloc =
FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), Name,
- FnType, FunctionDecl::None, false, true,
- SourceLocation());
+ FnType, /*DInfo=*/0, FunctionDecl::None, false, true);
Alloc->setImplicit();
ParmVarDecl *Param = ParmVarDecl::Create(Context, Alloc, SourceLocation(),
- 0, Argument, VarDecl::None, 0);
+ 0, Argument, /*DInfo=*/0,
+ VarDecl::None, 0);
Alloc->setParams(Context, &Param, 1);
// FIXME: Also add this declaration to the IdentifierResolver, but
@@ -689,43 +782,131 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
/// @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."
+ bool ArrayForm, ExprArg Operand) {
+ // C++ [expr.delete]p1:
+ // 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.
+ FunctionDecl *OperatorDelete = 0;
+
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 (const RecordType *Record = Type->getAs<RecordType>()) {
+ llvm::SmallVector<CXXConversionDecl *, 4> ObjectPtrConversions;
+ CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl());
+ OverloadedFunctionDecl *Conversions =
+ RD->getVisibleConversionFunctions();
+
+ for (OverloadedFunctionDecl::function_iterator
+ Func = Conversions->function_begin(),
+ FuncEnd = Conversions->function_end();
+ Func != FuncEnd; ++Func) {
+ // Skip over templated conversion functions; they aren't considered.
+ if (isa<FunctionTemplateDecl>(*Func))
+ continue;
+
+ CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func);
+
+ QualType ConvType = Conv->getConversionType().getNonReferenceType();
+ if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>())
+ if (ConvPtrType->getPointeeType()->isObjectType())
+ ObjectPtrConversions.push_back(Conv);
+ }
+ if (ObjectPtrConversions.size() == 1) {
+ // We have a single conversion to a pointer-to-object type. Perform
+ // that conversion.
+ Operand.release();
+ if (!PerformImplicitConversion(Ex,
+ ObjectPtrConversions.front()->getConversionType(),
+ "converting")) {
+ Operand = Owned(Ex);
+ Type = Ex->getType();
+ }
+ }
+ else if (ObjectPtrConversions.size() > 1) {
+ Diag(StartLoc, diag::err_ambiguous_delete_operand)
+ << Type << Ex->getSourceRange();
+ for (unsigned i= 0; i < ObjectPtrConversions.size(); i++) {
+ CXXConversionDecl *Conv = ObjectPtrConversions[i];
+ Diag(Conv->getLocation(), diag::err_ovl_candidate);
+ }
+ return ExprError();
+ }
}
if (!Type->isPointerType())
return ExprError(Diag(StartLoc, diag::err_delete_operand)
<< Type << Ex->getSourceRange());
- QualType Pointee = Type->getAsPointerType()->getPointeeType();
+ QualType Pointee = Type->getAs<PointerType>()->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()))
+ RequireCompleteType(StartLoc, Pointee,
+ PDiag(diag::warn_delete_incomplete)
+ << Ex->getSourceRange()))
return ExprError();
- // FIXME: Look up the correct operator delete overload and pass a pointer
- // along.
+ // C++ [expr.delete]p2:
+ // [Note: a pointer to a const type can be the operand of a
+ // delete-expression; it is not necessary to cast away the constness
+ // (5.2.11) of the pointer expression before it is used as the operand
+ // of the delete-expression. ]
+ ImpCastExprToType(Ex, Context.getPointerType(Context.VoidTy),
+ CastExpr::CK_NoOp);
+
+ // Update the operand.
+ Operand.take();
+ Operand = ExprArg(*this, Ex);
+
+ DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName(
+ ArrayForm ? OO_Array_Delete : OO_Delete);
+
+ if (Pointee->isRecordType() && !UseGlobal) {
+ CXXRecordDecl *Record
+ = cast<CXXRecordDecl>(Pointee->getAs<RecordType>()->getDecl());
+
+ // Try to find operator delete/operator delete[] in class scope.
+ LookupResult Found;
+ LookupQualifiedName(Found, Record, DeleteName, LookupOrdinaryName);
+ // FIXME: Diagnose ambiguity properly
+ assert(!Found.isAmbiguous() && "Ambiguous delete/delete[] not handled");
+ for (LookupResult::iterator F = Found.begin(), FEnd = Found.end();
+ F != FEnd; ++F) {
+ if (CXXMethodDecl *Delete = dyn_cast<CXXMethodDecl>(*F))
+ if (Delete->isUsualDeallocationFunction()) {
+ OperatorDelete = Delete;
+ break;
+ }
+ }
+
+ if (!Record->hasTrivialDestructor())
+ if (const CXXDestructorDecl *Dtor = Record->getDestructor(Context))
+ MarkDeclarationReferenced(StartLoc,
+ const_cast<CXXDestructorDecl*>(Dtor));
+ }
+
+ if (!OperatorDelete) {
+ // Didn't find a member overload. Look for a global one.
+ DeclareGlobalNewDelete();
+ DeclContext *TUDecl = Context.getTranslationUnitDecl();
+ if (FindAllocationOverload(StartLoc, SourceRange(), DeleteName,
+ &Ex, 1, TUDecl, /*AllowMissing=*/false,
+ OperatorDelete))
+ return ExprError();
+ }
+
// FIXME: Check access and ambiguity of operator delete and destructor.
}
Operand.release();
return Owned(new (Context) CXXDeleteExpr(Context.VoidTy, UseGlobal, ArrayForm,
- 0, Ex, StartLoc));
+ OperatorDelete, Ex, StartLoc));
}
@@ -747,8 +928,11 @@ Sema::ActOnCXXConditionDeclarationExpr(Scope *S, SourceLocation StartLoc,
assert(D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef &&
"Parser allowed 'typedef' as storage class of condition decl.");
- QualType Ty = GetTypeForDeclarator(D, S);
-
+ // FIXME: Store DeclaratorInfo in the expression.
+ DeclaratorInfo *DInfo = 0;
+ TagDecl *OwnedTag = 0;
+ QualType Ty = GetTypeForDeclarator(D, S, &DInfo, /*Skip=*/0, &OwnedTag);
+
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.
@@ -757,18 +941,9 @@ Sema::ActOnCXXConditionDeclarationExpr(Scope *S, SourceLocation StartLoc,
} 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);
+ } else if (OwnedTag && OwnedTag->isDefinition()) {
+ // The type-specifier-seq shall not declare a new class or enumeration.
+ Diag(OwnedTag->getLocation(), diag::err_type_defined_in_condition);
}
DeclPtrTy Dcl = ActOnDeclarator(S, D);
@@ -801,7 +976,7 @@ bool Sema::CheckCXXBooleanCondition(Expr *&CondExpr) {
/// 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
+bool
Sema::IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType) {
// Look inside the implicit cast, if it exists.
if (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(From))
@@ -812,12 +987,12 @@ Sema::IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType) {
// 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()) {
+ if (const PointerType *ToPtrType = ToType->getAs<PointerType>())
+ if (const BuiltinType *ToPointeeType
+ = ToPtrType->getPointeeType()->getAs<BuiltinType>()) {
// This conversion is considered only when there is an
// explicit appropriate pointer target type (C++ 4.2p2).
- if (ToPtrType->getPointeeType().getCVRQualifiers() == 0 &&
+ if (!ToPtrType->getPointeeType().hasQualifiers() &&
((StrLit->isWide() && ToPointeeType->isWideCharType()) ||
(!StrLit->isWide() &&
(ToPointeeType->getKind() == BuiltinType::Char_U ||
@@ -839,16 +1014,31 @@ Sema::IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType) {
bool
Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
const char *Flavor, bool AllowExplicit,
- bool Elidable)
-{
+ bool Elidable) {
ImplicitConversionSequence ICS;
+ return PerformImplicitConversion(From, ToType, Flavor, AllowExplicit,
+ Elidable, ICS);
+}
+
+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);
+ ICS = TryImplicitConversion(From, ToType,
+ /*SuppressUserConversions=*/false,
+ AllowExplicit,
+ /*ForceRValue=*/true,
+ /*InOverloadResolution=*/false);
}
if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) {
- ICS = TryImplicitConversion(From, ToType, false, AllowExplicit);
+ ICS = TryImplicitConversion(From, ToType,
+ /*SuppressUserConversions=*/false,
+ AllowExplicit,
+ /*ForceRValue=*/false,
+ /*InOverloadResolution=*/false);
}
return PerformImplicitConversion(From, ToType, ICS, Flavor);
}
@@ -869,13 +1059,48 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
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::UserDefinedConversion: {
+
+ FunctionDecl *FD = ICS.UserDefined.ConversionFunction;
+ CastExpr::CastKind CastKind = CastExpr::CK_Unknown;
+ QualType BeforeToType;
+ if (const CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(FD)) {
+ CastKind = CastExpr::CK_UserDefinedConversion;
+
+ // If the user-defined conversion is specified by a conversion function,
+ // the initial standard conversion sequence converts the source type to
+ // the implicit object parameter of the conversion function.
+ BeforeToType = Context.getTagDeclType(Conv->getParent());
+ } else if (const CXXConstructorDecl *Ctor =
+ dyn_cast<CXXConstructorDecl>(FD)) {
+ CastKind = CastExpr::CK_ConstructorConversion;
+
+ // If the user-defined conversion is specified by a constructor, the
+ // initial standard conversion sequence converts the source type to the
+ // type required by the argument of the constructor
+ BeforeToType = Ctor->getParamDecl(0)->getType();
+ }
+ else
+ assert(0 && "Unknown conversion function kind!");
+
+ if (PerformImplicitConversion(From, BeforeToType,
+ ICS.UserDefined.Before, "converting"))
+ return true;
+
+ OwningExprResult CastArg
+ = BuildCXXCastArgument(From->getLocStart(),
+ ToType.getNonReferenceType(),
+ CastKind, cast<CXXMethodDecl>(FD),
+ Owned(From));
+
+ if (CastArg.isInvalid())
+ return true;
+
+ From = new (Context) ImplicitCastExpr(ToType.getNonReferenceType(),
+ CastKind, CastArg.takeAs<Expr>(),
+ ToType->isLValueReferenceType());
+ return false;
+ }
case ImplicitConversionSequence::EllipsisConversion:
assert(false && "Cannot perform an ellipsis conversion");
@@ -895,7 +1120,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
/// 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
+bool
Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
const StandardConversionSequence& SCS,
const char *Flavor) {
@@ -908,10 +1133,31 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
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);
+ if (SCS.Second == ICK_Derived_To_Base) {
+ ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
+ if (CompleteConstructorCall(cast<CXXConstructorDecl>(SCS.CopyConstructor),
+ MultiExprArg(*this, (void **)&From, 1),
+ /*FIXME:ConstructLoc*/SourceLocation(),
+ ConstructorArgs))
+ return true;
+ OwningExprResult FromResult =
+ BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(),
+ ToType, SCS.CopyConstructor,
+ move_arg(ConstructorArgs));
+ if (FromResult.isInvalid())
+ return true;
+ From = FromResult.takeAs<Expr>();
+ return false;
+ }
+ OwningExprResult FromResult =
+ BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(),
+ ToType, SCS.CopyConstructor,
+ MultiExprArg(*this, (void**)&From, 1));
+
+ if (FromResult.isInvalid())
+ return true;
+
+ From = FromResult.takeAs<Expr>();
return false;
}
@@ -924,7 +1170,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
case ICK_Array_To_Pointer:
FromType = Context.getArrayDecayedType(FromType);
- ImpCastExprToType(From, FromType);
+ ImpCastExprToType(From, FromType, CastExpr::CK_ArrayToPointerDecay);
break;
case ICK_Function_To_Pointer:
@@ -940,7 +1186,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
FromType = From->getType();
}
FromType = Context.getPointerType(FromType);
- ImpCastExprToType(From, FromType);
+ ImpCastExprToType(From, FromType, CastExpr::CK_FunctionToPointerDecay);
break;
default:
@@ -951,7 +1197,11 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
// Perform the second implicit conversion
switch (SCS.Second) {
case ICK_Identity:
- // Nothing to do.
+ // If both sides are functions (or pointers/references to them), there could
+ // be incompatible exception declarations.
+ if (CheckExceptionSpecCompatibility(From, ToType))
+ return true;
+ // Nothing else to do.
break;
case ICK_Integral_Promotion:
@@ -968,26 +1218,32 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
ImpCastExprToType(From, FromType);
break;
- case ICK_Pointer_Conversion:
+ case ICK_Pointer_Conversion: {
if (SCS.IncompatibleObjC) {
// Diagnose incompatible Objective-C conversions
- Diag(From->getSourceRange().getBegin(),
+ Diag(From->getSourceRange().getBegin(),
diag::ext_typecheck_convert_incompatible_pointer)
<< From->getType() << ToType << Flavor
<< From->getSourceRange();
}
- if (CheckPointerConversion(From, ToType))
+
+ CastExpr::CastKind Kind = CastExpr::CK_Unknown;
+ if (CheckPointerConversion(From, ToType, Kind))
return true;
- ImpCastExprToType(From, ToType);
+ ImpCastExprToType(From, ToType, Kind);
break;
-
- case ICK_Pointer_Member:
- if (CheckMemberPointerConversion(From, ToType))
+ }
+
+ case ICK_Pointer_Member: {
+ CastExpr::CastKind Kind = CastExpr::CK_Unknown;
+ if (CheckMemberPointerConversion(From, ToType, Kind))
return true;
- ImpCastExprToType(From, ToType);
+ if (CheckExceptionSpecCompatibility(From, ToType))
+ return true;
+ ImpCastExprToType(From, ToType, Kind);
break;
-
+ }
case ICK_Boolean_Conversion:
FromType = Context.BoolTy;
ImpCastExprToType(From, FromType);
@@ -1006,7 +1262,8 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
case ICK_Qualification:
// FIXME: Not sure about lvalue vs rvalue here in the presence of rvalue
// references.
- ImpCastExprToType(From, ToType.getNonReferenceType(),
+ ImpCastExprToType(From, ToType.getNonReferenceType(),
+ CastExpr::CK_Unknown,
ToType->isLValueReferenceType());
break;
@@ -1023,34 +1280,38 @@ Sema::OwningExprResult Sema::ActOnUnaryTypeTrait(UnaryTypeTrait OTT,
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.
+ QualType T = GetTypeFromParser(Ty);
+
+ // According to http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html
+ // all traits except __is_class, __is_enum and __is_union require a the type
+ // to be complete.
+ if (OTT != UTT_IsClass && OTT != UTT_IsEnum && OTT != UTT_IsUnion) {
+ if (RequireCompleteType(KWLoc, T,
+ diag::err_incomplete_type_used_in_type_trait_expr))
+ return ExprError();
+ }
// 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));
+ return Owned(new (Context) UnaryTypeTraitExpr(KWLoc, OTT, T,
+ RParen, Context.BoolTy));
}
QualType Sema::CheckPointerToMemberOperands(
- Expr *&lex, Expr *&rex, SourceLocation Loc, bool isIndirect)
-{
+ 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();
+ const MemberPointerType *MemPtr = RType->getAs<MemberPointerType>();
if (!MemPtr) {
Diag(Loc, diag::err_bad_memptr_rhs)
<< OpSpelling << RType << rex->getSourceRange();
return QualType();
- }
+ }
QualType Class(MemPtr->getClass(), 0);
@@ -1060,7 +1321,7 @@ QualType Sema::CheckPointerToMemberOperands(
// such a class]
QualType LType = lex->getType();
if (isIndirect) {
- if (const PointerType *Ptr = LType->getAsPointerType())
+ if (const PointerType *Ptr = LType->getAs<PointerType>())
LType = Ptr->getPointeeType().getNonReferenceType();
else {
Diag(Loc, diag::err_bad_memptr_lhs)
@@ -1071,8 +1332,8 @@ QualType Sema::CheckPointerToMemberOperands(
if (Context.getCanonicalType(Class).getUnqualifiedType() !=
Context.getCanonicalType(LType).getUnqualifiedType()) {
- BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false,
- /*DetectVirtual=*/false);
+ CXXBasePaths 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) ||
@@ -1096,10 +1357,7 @@ QualType Sema::CheckPointerToMemberOperands(
// argument.
// We probably need a "MemberFunctionClosureType" or something like that.
QualType Result = MemPtr->getPointeeType();
- if (LType.isConstQualified())
- Result.addConst();
- if (LType.isVolatileQualified())
- Result.addVolatile();
+ Result = Context.getCVRQualifiedType(Result, LType.getCVRQualifiers());
return Result;
}
@@ -1124,8 +1382,7 @@ static QualType TargetType(const ImplicitConversionSequence &ICS) {
/// conversion.
static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
SourceLocation QuestionLoc,
- ImplicitConversionSequence &ICS)
-{
+ 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
@@ -1137,7 +1394,11 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
// conversion the reference must bind directly to E1.
if (!Self.CheckReferenceInit(From,
Self.Context.getLValueReferenceType(To->getType()),
- &ICS))
+ To->getLocStart(),
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false,
+ /*ForceRValue=*/false,
+ &ICS))
{
assert((ICS.ConversionKind ==
ImplicitConversionSequence::StandardConversion ||
@@ -1157,8 +1418,8 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
// 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();
+ const RecordType *FRec = FTy->getAs<RecordType>();
+ const RecordType *TRec = TTy->getAs<RecordType>();
bool FDerivedFromT = FRec && TRec && Self.IsDerivedFrom(FTy, TTy);
if (FRec && TRec && (FRec == TRec ||
FDerivedFromT || Self.IsDerivedFrom(TTy, FTy))) {
@@ -1169,7 +1430,10 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
// 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);
+ ICS = Self.TryCopyInitialization(From, TTy,
+ /*SuppressUserConversions=*/false,
+ /*ForceRValue=*/false,
+ /*InOverloadResolution=*/false);
}
} else {
// -- Otherwise: E1 can be converted to match E2 if E1 can be
@@ -1178,12 +1442,16 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
// First find the decayed type.
if (TTy->isFunctionType())
TTy = Self.Context.getPointerType(TTy);
- else if(TTy->isArrayType())
+ 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);
+ ICS = Self.TryImplicitConversion(From, TTy,
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false,
+ /*ForceRValue=*/false,
+ /*InOverloadResolution=*/false);
}
return false;
}
@@ -1239,8 +1507,7 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS,
/// 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)
-{
+ const ImplicitConversionSequence &ICS) {
if (ICS.ConversionKind == ImplicitConversionSequence::StandardConversion &&
ICS.Standard.ReferenceBinding) {
assert(ICS.Standard.DirectBinding &&
@@ -1248,14 +1515,22 @@ static bool ConvertForConditional(Sema &Self, Expr *&E,
// FIXME: CheckReferenceInit should be able to reuse the ICS instead of
// redoing all the work.
return Self.CheckReferenceInit(E, Self.Context.getLValueReferenceType(
- TargetType(ICS)));
+ TargetType(ICS)),
+ /*FIXME:*/E->getLocStart(),
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false,
+ /*ForceRValue=*/false);
}
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)));
+ TargetType(ICS)),
+ /*FIXME:*/E->getLocStart(),
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false,
+ /*ForceRValue=*/false);
}
if (Self.PerformImplicitConversion(E, TargetType(ICS), ICS, "converting"))
return true;
@@ -1412,27 +1687,48 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// 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)) {
+ const MemberPointerType *LMemPtr = LTy->getAs<MemberPointerType>();
+ const MemberPointerType *RMemPtr = RTy->getAs<MemberPointerType>();
+ if (LMemPtr &&
+ RHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
ImpCastExprToType(RHS, LTy);
return LTy;
}
- if (RMemPtr && LHS->isNullPointerConstant(Context)) {
+ if (RMemPtr &&
+ LHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
ImpCastExprToType(LHS, RTy);
return RTy;
}
if (LMemPtr && RMemPtr) {
QualType LPointee = LMemPtr->getPointeeType();
QualType RPointee = RMemPtr->getPointeeType();
+
+ QualifierCollector LPQuals, RPQuals;
+ const Type *LPCan = LPQuals.strip(Context.getCanonicalType(LPointee));
+ const Type *RPCan = RPQuals.strip(Context.getCanonicalType(RPointee));
+
// 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
+ if (LPCan == RPCan) {
+
+ // Second, we take the greater of the two 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()){
+
+ Qualifiers MergedQuals = LPQuals + RPQuals;
+
+ bool CompatibleQuals = true;
+ if (MergedQuals.getCVRQualifiers() != LPQuals.getCVRQualifiers() &&
+ MergedQuals.getCVRQualifiers() != RPQuals.getCVRQualifiers())
+ CompatibleQuals = false;
+ else if (LPQuals.getAddressSpace() != RPQuals.getAddressSpace())
+ // FIXME:
+ // C99 6.5.15 as modified by TR 18037:
+ // If the second and third operands are pointers into different
+ // address spaces, the address spaces must overlap.
+ CompatibleQuals = false;
+ // FIXME: GC qualifiers?
+
+ if (CompatibleQuals) {
// Third, we check if either of the container classes is derived from
// the other.
QualType LContainer(LMemPtr->getClass(), 0);
@@ -1450,8 +1746,9 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// 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());
+ LPointee = Context.getQualifiedType(LPointee, MergedQuals);
+ QualType Common
+ = Context.getMemberPointerType(LPointee, MoreDerived.getTypePtr());
if (PerformImplicitConversion(LHS, Common, "converting"))
return QualType();
if (PerformImplicitConversion(RHS, Common, "converting"))
@@ -1470,30 +1767,37 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
/// \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.
+/// This finds the composite pointer type (or member 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();
+
+ if (!T1->isPointerType() && !T1->isMemberPointerType() &&
+ !T2->isPointerType() && !T2->isMemberPointerType())
+ return QualType();
+
+ // FIXME: Do we need to work on the canonical types?
// 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)) {
+ if (E1->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
ImpCastExprToType(E1, T2);
return T2;
}
- if (E2->isNullPointerConstant(Context)) {
+ if (E2->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
ImpCastExprToType(E2, T1);
return T1;
}
- // Now both have to be pointers.
- if(!T1->isPointerType() || !T2->isPointerType())
+
+ // Now both have to be pointers or member pointers.
+ if (!T1->isPointerType() && !T1->isMemberPointerType() &&
+ !T2->isPointerType() && !T2->isMemberPointerType())
return QualType();
// Otherwise, of one of the operands has type "pointer to cv1 void," then
@@ -1506,32 +1810,93 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) {
// 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.
+ // FIXME: extended qualifiers?
llvm::SmallVector<unsigned, 4> QualifierUnion;
+ llvm::SmallVector<std::pair<const Type *, const Type *>, 4> MemberOfClass;
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));
+ do {
+ const PointerType *Ptr1, *Ptr2;
+ if ((Ptr1 = Composite1->getAs<PointerType>()) &&
+ (Ptr2 = Composite2->getAs<PointerType>())) {
+ Composite1 = Ptr1->getPointeeType();
+ Composite2 = Ptr2->getPointeeType();
+ QualifierUnion.push_back(
+ Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers());
+ MemberOfClass.push_back(std::make_pair((const Type *)0, (const Type *)0));
+ continue;
+ }
+
+ const MemberPointerType *MemPtr1, *MemPtr2;
+ if ((MemPtr1 = Composite1->getAs<MemberPointerType>()) &&
+ (MemPtr2 = Composite2->getAs<MemberPointerType>())) {
+ Composite1 = MemPtr1->getPointeeType();
+ Composite2 = MemPtr2->getPointeeType();
+ QualifierUnion.push_back(
+ Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers());
+ MemberOfClass.push_back(std::make_pair(MemPtr1->getClass(),
+ MemPtr2->getClass()));
+ continue;
+ }
+
+ // FIXME: block pointer types?
+
+ // Cannot unwrap any more types.
+ break;
+ } while (true);
+
+ // Rewrap the composites as pointers or member pointers with the union CVRs.
+ llvm::SmallVector<std::pair<const Type *, const Type *>, 4>::iterator MOC
+ = MemberOfClass.begin();
+ for (llvm::SmallVector<unsigned, 4>::iterator
+ I = QualifierUnion.begin(),
+ E = QualifierUnion.end();
+ I != E; (void)++I, ++MOC) {
+ Qualifiers Quals = Qualifiers::fromCVRMask(*I);
+ if (MOC->first && MOC->second) {
+ // Rebuild member pointer type
+ Composite1 = Context.getMemberPointerType(
+ Context.getQualifiedType(Composite1, Quals),
+ MOC->first);
+ Composite2 = Context.getMemberPointerType(
+ Context.getQualifiedType(Composite2, Quals),
+ MOC->second);
+ } else {
+ // Rebuild pointer type
+ Composite1
+ = Context.getPointerType(Context.getQualifiedType(Composite1, Quals));
+ Composite2
+ = Context.getPointerType(Context.getQualifiedType(Composite2, Quals));
+ }
}
- ImplicitConversionSequence E1ToC1 = TryImplicitConversion(E1, Composite1);
- ImplicitConversionSequence E2ToC1 = TryImplicitConversion(E2, Composite1);
+ ImplicitConversionSequence E1ToC1 =
+ TryImplicitConversion(E1, Composite1,
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false,
+ /*ForceRValue=*/false,
+ /*InOverloadResolution=*/false);
+ ImplicitConversionSequence E2ToC1 =
+ TryImplicitConversion(E2, Composite1,
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false,
+ /*ForceRValue=*/false,
+ /*InOverloadResolution=*/false);
+
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);
+ E1ToC2 = TryImplicitConversion(E1, Composite2,
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false,
+ /*ForceRValue=*/false,
+ /*InOverloadResolution=*/false);
+ E2ToC2 = TryImplicitConversion(E2, Composite2,
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false,
+ /*ForceRValue=*/false,
+ /*InOverloadResolution=*/false);
}
bool ToC1Viable = E1ToC1.ConversionKind !=
@@ -1556,84 +1921,264 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) {
}
Sema::OwningExprResult Sema::MaybeBindToTemporary(Expr *E) {
- const RecordType *RT = E->getType()->getAsRecordType();
+ if (!Context.getLangOptions().CPlusPlus)
+ return Owned(E);
+
+ const RecordType *RT = E->getType()->getAs<RecordType>();
if (!RT)
return Owned(E);
-
+
CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
if (RD->hasTrivialDestructor())
return Owned(E);
-
- CXXTemporary *Temp = CXXTemporary::Create(Context,
+
+ if (CallExpr *CE = dyn_cast<CallExpr>(E)) {
+ QualType Ty = CE->getCallee()->getType();
+ if (const PointerType *PT = Ty->getAs<PointerType>())
+ Ty = PT->getPointeeType();
+
+ const FunctionType *FTy = Ty->getAs<FunctionType>();
+ if (FTy->getResultType()->isReferenceType())
+ return Owned(E);
+ }
+ CXXTemporary *Temp = CXXTemporary::Create(Context,
RD->getDestructor(Context));
ExprTemporaries.push_back(Temp);
- MarkDestructorReferenced(E->getExprLoc(), E->getType());
+ if (CXXDestructorDecl *Destructor =
+ const_cast<CXXDestructorDecl*>(RD->getDestructor(Context)))
+ MarkDeclarationReferenced(E->getExprLoc(), Destructor);
// 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;
-}
-
-Expr *Sema::MaybeCreateCXXExprWithTemporaries(Expr *SubExpr,
+Expr *Sema::MaybeCreateCXXExprWithTemporaries(Expr *SubExpr,
bool ShouldDestroyTemps) {
assert(SubExpr && "sub expression can't be null!");
-
+
if (ExprTemporaries.empty())
return SubExpr;
-
+
Expr *E = CXXExprWithTemporaries::Create(Context, SubExpr,
- &ExprTemporaries[0],
+ &ExprTemporaries[0],
ExprTemporaries.size(),
ShouldDestroyTemps);
ExprTemporaries.clear();
-
+
return E;
}
+Sema::OwningExprResult
+Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc,
+ tok::TokenKind OpKind, TypeTy *&ObjectType) {
+ // Since this might be a postfix expression, get rid of ParenListExprs.
+ Base = MaybeConvertParenListExprToParenExpr(S, move(Base));
+
+ Expr *BaseExpr = (Expr*)Base.get();
+ assert(BaseExpr && "no record expansion");
+
+ QualType BaseType = BaseExpr->getType();
+ if (BaseType->isDependentType()) {
+ // FIXME: member of the current instantiation
+ ObjectType = BaseType.getAsOpaquePtr();
+ return move(Base);
+ }
+
+ // C++ [over.match.oper]p8:
+ // [...] When operator->returns, the operator-> is applied to the value
+ // returned, with the original second operand.
+ if (OpKind == tok::arrow) {
+ // The set of types we've considered so far.
+ llvm::SmallPtrSet<CanQualType,8> CTypes;
+ llvm::SmallVector<SourceLocation, 8> Locations;
+ CTypes.insert(Context.getCanonicalType(BaseType));
+
+ while (BaseType->isRecordType()) {
+ Base = BuildOverloadedArrowExpr(S, move(Base), OpLoc);
+ BaseExpr = (Expr*)Base.get();
+ if (BaseExpr == NULL)
+ return ExprError();
+ if (CXXOperatorCallExpr *OpCall = dyn_cast<CXXOperatorCallExpr>(BaseExpr))
+ Locations.push_back(OpCall->getDirectCallee()->getLocation());
+ BaseType = BaseExpr->getType();
+ CanQualType CBaseType = Context.getCanonicalType(BaseType);
+ if (!CTypes.insert(CBaseType)) {
+ Diag(OpLoc, diag::err_operator_arrow_circular);
+ for (unsigned i = 0; i < Locations.size(); i++)
+ Diag(Locations[i], diag::note_declared_at);
+ return ExprError();
+ }
+ }
+ }
+
+ if (BaseType->isPointerType())
+ BaseType = BaseType->getPointeeType();
+
+ // We could end up with various non-record types here, such as extended
+ // vector types or Objective-C interfaces. Just return early and let
+ // ActOnMemberReferenceExpr do the work.
+ if (!BaseType->isRecordType()) {
+ // C++ [basic.lookup.classref]p2:
+ // [...] If the type of the object expression is of pointer to scalar
+ // type, the unqualified-id is looked up in the context of the complete
+ // postfix-expression.
+ ObjectType = 0;
+ return move(Base);
+ }
+
+ // C++ [basic.lookup.classref]p2:
+ // If the id-expression in a class member access (5.2.5) is an
+ // unqualified-id, and the type of the object expres- sion is of a class
+ // type C (or of pointer to a class type C), the unqualified-id is looked
+ // up in the scope of class C. [...]
+ ObjectType = BaseType.getAsOpaquePtr();
+ return move(Base);
+}
+
+Sema::OwningExprResult
+Sema::ActOnDestructorReferenceExpr(Scope *S, ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ SourceLocation ClassNameLoc,
+ IdentifierInfo *ClassName,
+ const CXXScopeSpec &SS,
+ bool HasTrailingLParen) {
+ if (SS.isInvalid())
+ return ExprError();
+
+ QualType BaseType;
+ if (isUnknownSpecialization(SS))
+ BaseType = Context.getTypenameType((NestedNameSpecifier *)SS.getScopeRep(),
+ ClassName);
+ else {
+ TypeTy *BaseTy = getTypeName(*ClassName, ClassNameLoc, S, &SS);
+ if (!BaseTy) {
+ Diag(ClassNameLoc, diag::err_ident_in_pseudo_dtor_not_a_type)
+ << ClassName;
+ return ExprError();
+ }
+
+ BaseType = GetTypeFromParser(BaseTy);
+ }
+
+ CanQualType CanBaseType = Context.getCanonicalType(BaseType);
+ DeclarationName DtorName =
+ Context.DeclarationNames.getCXXDestructorName(CanBaseType);
+
+ OwningExprResult Result
+ = BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, ClassNameLoc,
+ DtorName, DeclPtrTy(), &SS);
+ if (Result.isInvalid() || HasTrailingLParen)
+ return move(Result);
+
+ // The only way a reference to a destructor can be used is to
+ // immediately call them. Since the next token is not a '(', produce a
+ // diagnostic and build the call now.
+ Expr *E = (Expr *)Result.get();
+ SourceLocation ExpectedLParenLoc = PP.getLocForEndOfToken(E->getLocEnd());
+ Diag(E->getLocStart(), diag::err_dtor_expr_without_call)
+ << isa<CXXPseudoDestructorExpr>(E)
+ << CodeModificationHint::CreateInsertion(ExpectedLParenLoc, "()");
+
+ return ActOnCallExpr(0, move(Result), ExpectedLParenLoc,
+ MultiExprArg(*this, 0, 0), 0, ExpectedLParenLoc);
+}
+
+Sema::OwningExprResult
+Sema::ActOnOverloadedOperatorReferenceExpr(Scope *S, ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ SourceLocation ClassNameLoc,
+ OverloadedOperatorKind OverOpKind,
+ const CXXScopeSpec *SS) {
+ if (SS && SS->isInvalid())
+ return ExprError();
+
+ DeclarationName Name =
+ Context.DeclarationNames.getCXXOperatorName(OverOpKind);
+
+ return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, ClassNameLoc,
+ Name, DeclPtrTy(), SS);
+}
+
+Sema::OwningExprResult
+Sema::ActOnConversionOperatorReferenceExpr(Scope *S, ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ SourceLocation ClassNameLoc,
+ TypeTy *Ty,
+ const CXXScopeSpec *SS) {
+ if (SS && SS->isInvalid())
+ return ExprError();
+
+ //FIXME: Preserve type source info.
+ QualType ConvType = GetTypeFromParser(Ty);
+ CanQualType ConvTypeCanon = Context.getCanonicalType(ConvType);
+ DeclarationName ConvName =
+ Context.DeclarationNames.getCXXConversionFunctionName(ConvTypeCanon);
+
+ return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, ClassNameLoc,
+ ConvName, DeclPtrTy(), SS);
+}
+
+CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp,
+ CXXMethodDecl *Method) {
+ MemberExpr *ME =
+ new (Context) MemberExpr(Exp, /*IsArrow=*/false, Method,
+ SourceLocation(), Method->getType());
+ QualType ResultType;
+ if (const CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(Method))
+ ResultType = Conv->getConversionType().getNonReferenceType();
+ else
+ ResultType = Method->getResultType().getNonReferenceType();
+
+ CXXMemberCallExpr *CE =
+ new (Context) CXXMemberCallExpr(Context, ME, 0, 0,
+ ResultType,
+ SourceLocation());
+ return CE;
+}
+
+Sema::OwningExprResult Sema::BuildCXXCastArgument(SourceLocation CastLoc,
+ QualType Ty,
+ CastExpr::CastKind Kind,
+ CXXMethodDecl *Method,
+ ExprArg Arg) {
+ Expr *From = Arg.takeAs<Expr>();
+
+ switch (Kind) {
+ default: assert(0 && "Unhandled cast kind!");
+ case CastExpr::CK_ConstructorConversion: {
+ ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
+
+ if (CompleteConstructorCall(cast<CXXConstructorDecl>(Method),
+ MultiExprArg(*this, (void **)&From, 1),
+ CastLoc, ConstructorArgs))
+ return ExprError();
+
+ return BuildCXXConstructExpr(CastLoc, Ty, cast<CXXConstructorDecl>(Method),
+ move_arg(ConstructorArgs));
+ }
+
+ case CastExpr::CK_UserDefinedConversion: {
+ assert(!From->getType()->isPointerType() && "Arg can't have pointer type!");
+
+ // Cast to base if needed.
+ if (PerformObjectArgumentInitialization(From, Method))
+ return ExprError();
+
+ // Create an implicit call expr that calls it.
+ CXXMemberCallExpr *CE = BuildCXXMemberCallExpr(From, Method);
+ return Owned(CE);
+ }
+ }
+}
+
Sema::OwningExprResult Sema::ActOnFinishFullExpr(ExprArg Arg) {
Expr *FullExpr = Arg.takeAs<Expr>();
if (FullExpr)
- FullExpr = MaybeCreateCXXExprWithTemporaries(FullExpr,
+ FullExpr = MaybeCreateCXXExprWithTemporaries(FullExpr,
/*ShouldDestroyTemps=*/true);
+
return Owned(FullExpr);
}
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index 7bb6b44..d7e4e4a 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -20,7 +20,7 @@
using namespace clang;
-Sema::ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs,
+Sema::ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs,
ExprTy **strings,
unsigned NumStrings) {
StringLiteral **Strings = reinterpret_cast<StringLiteral**>(strings);
@@ -30,40 +30,40 @@ Sema::ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs,
// 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;
@@ -74,29 +74,29 @@ Sema::ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs,
// interface private (even though it appears in the header files).
QualType Ty = Context.getObjCConstantStringInterface();
if (!Ty.isNull()) {
- Ty = Context.getPointerType(Ty);
+ Ty = Context.getObjCObjectPointerType(Ty);
} else {
IdentifierInfo *NSIdent = &Context.Idents.get("NSString");
- NamedDecl *IF = LookupName(TUScope, NSIdent, LookupOrdinaryName);
+ NamedDecl *IF = LookupSingleName(TUScope, NSIdent, LookupOrdinaryName);
if (ObjCInterfaceDecl *StrIF = dyn_cast_or_null<ObjCInterfaceDecl>(IF)) {
Context.setObjCConstantStringInterface(StrIF);
Ty = Context.getObjCConstantStringInterface();
- Ty = Context.getPointerType(Ty);
+ Ty = Context.getObjCObjectPointerType(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]);
}
-Expr *Sema::BuildObjCEncodeExpression(SourceLocation AtLoc,
+Expr *Sema::BuildObjCEncodeExpression(SourceLocation AtLoc,
QualType EncodedType,
SourceLocation RParenLoc) {
QualType StrTy;
- if (EncodedType->isDependentType())
+ if (EncodedType->isDependentType())
StrTy = Context.DependentTy;
else {
std::string Str;
@@ -111,7 +111,7 @@ Expr *Sema::BuildObjCEncodeExpression(SourceLocation AtLoc,
StrTy = Context.getConstantArrayType(StrTy, llvm::APInt(32, Str.size()+1),
ArrayType::Normal, 0);
}
-
+
return new (Context) ObjCEncodeExpr(StrTy, EncodedType, AtLoc, RParenLoc);
}
@@ -120,7 +120,8 @@ Sema::ExprResult Sema::ParseObjCEncodeExpression(SourceLocation AtLoc,
SourceLocation LParenLoc,
TypeTy *ty,
SourceLocation RParenLoc) {
- QualType EncodedType = QualType::getFromOpaquePtr(ty);
+ // FIXME: Preserve type source info ?
+ QualType EncodedType = GetTypeFromParser(ty);
return BuildObjCEncodeExpression(AtLoc, EncodedType, RParenLoc);
}
@@ -130,8 +131,8 @@ Sema::ExprResult Sema::ParseObjCSelectorExpression(Selector Sel,
SourceLocation SelLoc,
SourceLocation LParenLoc,
SourceLocation RParenLoc) {
- ObjCMethodDecl *Method = LookupInstanceMethodInGlobalPool(Sel,
- SourceRange(LParenLoc, RParenLoc));
+ ObjCMethodDecl *Method = LookupInstanceMethodInGlobalPool(Sel,
+ SourceRange(LParenLoc, RParenLoc), false);
if (!Method)
Method = LookupFactoryMethodInGlobalPool(Sel,
SourceRange(LParenLoc, RParenLoc));
@@ -152,19 +153,19 @@ Sema::ExprResult Sema::ParseObjCProtocolExpression(IdentifierInfo *ProtocolId,
Diag(ProtoLoc, diag::err_undeclared_protocol) << ProtocolId;
return true;
}
-
+
QualType Ty = Context.getObjCProtoType();
if (Ty.isNull())
return true;
- Ty = Context.getPointerType(Ty);
+ Ty = Context.getObjCObjectPointerType(Ty);
return new (Context) ObjCProtocolExpr(Ty, PDecl, AtLoc, RParenLoc);
}
-bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs,
- Selector Sel, ObjCMethodDecl *Method,
+bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs,
+ Selector Sel, ObjCMethodDecl *Method,
bool isClassMessage,
SourceLocation lbrac, SourceLocation rbrac,
- QualType &ReturnType) {
+ QualType &ReturnType) {
if (!Method) {
// Apply default argument promotion as for (C99 6.5.2.2p6).
for (unsigned i = 0; i != NumArgs; i++)
@@ -177,9 +178,9 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs,
ReturnType = Context.getObjCIdType();
return false;
}
-
+
ReturnType = Method->getResultType();
-
+
unsigned NumNamedArgs = Sel.getNumArgs();
assert(NumArgs >= NumNamedArgs && "Too few arguments for selector!");
@@ -187,22 +188,22 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs,
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 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 =
+ AssignConvertType Result =
CheckSingleAssignmentConstraints(lhsType, argExpr);
if (Args[i] != argExpr) // The expression was converted.
Args[i] = argExpr; // Make sure we store the converted expression.
-
- IsError |=
+
+ IsError |=
DiagnoseAssignmentResult(Result, argExpr->getLocStart(), lhsType, rhsType,
argExpr, "sending");
}
@@ -214,7 +215,7 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs,
} else {
// Check for extra arguments to non-variadic methods.
if (NumArgs != NumNamedArgs) {
- Diag(Args[NumNamedArgs]->getLocStart(),
+ Diag(Args[NumNamedArgs]->getLocStart(),
diag::err_typecheck_call_too_many_args)
<< 2 /*method*/ << Method->getSourceRange()
<< SourceRange(Args[NumNamedArgs]->getLocStart(),
@@ -241,29 +242,24 @@ ObjCMethodDecl *Sema::LookupPrivateClassMethod(Selector Sel,
ObjCMethodDecl *Method = 0;
// lookup in class and all superclasses
while (ClassDecl && !Method) {
- if (ObjCImplementationDecl *ImpDecl
- = LookupObjCImplementation(ClassDecl->getIdentifier()))
+ if (ObjCImplementationDecl *ImpDecl = ClassDecl->getImplementation())
Method = ImpDecl->getClassMethod(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(Sel);
- }
- }
-
+ if (!Method)
+ Method = ClassDecl->getCategoryClassMethod(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(Sel);
- // Look through local category implementations associated
+ // Look through local category implementations associated
// with the root class.
- if (!Method)
+ if (!Method)
Method = LookupPrivateInstanceMethod(Sel, ClassDecl);
}
-
+
ClassDecl = ClassDecl->getSuperClass();
}
return Method;
@@ -274,17 +270,12 @@ ObjCMethodDecl *Sema::LookupPrivateInstanceMethod(Selector Sel,
ObjCMethodDecl *Method = 0;
while (ClassDecl && !Method) {
// If we have implementations in scope, check "private" methods.
- if (ObjCImplementationDecl *ImpDecl
- = LookupObjCImplementation(ClassDecl->getIdentifier()))
+ if (ObjCImplementationDecl *ImpDecl = ClassDecl->getImplementation())
Method = ImpDecl->getInstanceMethod(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(Sel);
- }
- }
+ if (!Method)
+ Method = ClassDecl->getCategoryInstanceMethod(Sel);
ClassDecl = ClassDecl->getSuperClass();
}
return Method;
@@ -295,11 +286,11 @@ Action::OwningExprResult Sema::ActOnClassPropertyRefExpr(
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(Sel);
@@ -307,8 +298,7 @@ Action::OwningExprResult Sema::ActOnClassPropertyRefExpr(
if (!Getter)
if (ObjCMethodDecl *CurMeth = getCurMethodDecl())
if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface())
- if (ObjCImplementationDecl *ImpDecl
- = LookupObjCImplementation(ClassDecl->getIdentifier()))
+ if (ObjCImplementationDecl *ImpDecl = ClassDecl->getImplementation())
Getter = ImpDecl->getClassMethod(Sel);
if (Getter) {
@@ -317,29 +307,24 @@ Action::OwningExprResult Sema::ActOnClassPropertyRefExpr(
if (DiagnoseUseOfDecl(Getter, propertyNameLoc))
return ExprError();
}
-
+
// Look for the matching setter, in case it is needed.
- Selector SetterSel =
- SelectorTable::constructSetterName(PP.getIdentifierTable(),
+ Selector SetterSel =
+ SelectorTable::constructSetterName(PP.getIdentifierTable(),
PP.getSelectorTable(), &propertyName);
-
+
ObjCMethodDecl *Setter = IFace->lookupClassMethod(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()))
+ if (ObjCImplementationDecl *ImpDecl = ClassDecl->getImplementation())
Setter = ImpDecl->getClassMethod(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(SetterSel);
- }
- }
+ if (!Setter)
+ Setter = IFace->getCategoryClassMethod(SetterSel);
if (Setter && DiagnoseUseOfDecl(Setter, propertyNameLoc))
return ExprError();
@@ -354,7 +339,8 @@ Action::OwningExprResult Sema::ActOnClassPropertyRefExpr(
E = Setter->param_end(); PI != E; ++PI)
PType = (*PI)->getType();
}
- return Owned(new (Context) ObjCKVCRefExpr(Getter, PType, Setter,
+ return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(
+ Getter, PType, Setter,
propertyNameLoc, IFace, receiverNameLoc));
}
return ExprError(Diag(propertyNameLoc, diag::err_property_not_found)
@@ -369,32 +355,31 @@ Sema::ExprResult Sema::ActOnClassMessage(
Scope *S,
IdentifierInfo *receiverName, Selector Sel,
SourceLocation lbrac, SourceLocation receiverLoc,
- SourceLocation selectorLoc, SourceLocation rbrac,
- ExprTy **Args, unsigned NumArgs)
-{
+ 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)
+ 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);
+ superTy = Context.getObjCObjectPointerType(superTy);
ExprResult ReceiverExpr = new (Context) ObjCSuperExpr(SourceLocation(),
superTy);
// We are really in an instance method, redirect.
- return ActOnInstanceMessage(ReceiverExpr.get(), Sel, lbrac,
+ return ActOnInstanceMessage(ReceiverExpr.get(), Sel, lbrac,
selectorLoc, rbrac, Args, NumArgs);
}
// We are sending a message to 'super' within a class method. Do nothing,
@@ -402,20 +387,21 @@ Sema::ExprResult Sema::ActOnClassMessage(
} 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);
+ NamedDecl *SuperDecl
+ = LookupSingleName(S, receiverName, LookupOrdinaryName);
ValueDecl *VD = dyn_cast_or_null<ValueDecl>(SuperDecl);
if (VD) {
- ExprResult ReceiverExpr = new (Context) DeclRefExpr(VD, VD->getType(),
+ ExprResult ReceiverExpr = new (Context) DeclRefExpr(VD, VD->getType(),
receiverLoc);
// We are really in an instance method, redirect.
- return ActOnInstanceMessage(ReceiverExpr.get(), Sel, lbrac,
+ 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;
@@ -427,10 +413,11 @@ Sema::ExprResult Sema::ActOnClassMessage(
//
// If necessary, the following lookup could move to getObjCInterfaceDecl().
if (!ClassDecl) {
- NamedDecl *IDecl = LookupName(TUScope, receiverName, LookupOrdinaryName);
+ NamedDecl *IDecl
+ = LookupSingleName(TUScope, receiverName, LookupOrdinaryName);
if (TypedefDecl *OCTD = dyn_cast_or_null<TypedefDecl>(IDecl)) {
const ObjCInterfaceType *OCIT;
- OCIT = OCTD->getUnderlyingType()->getAsObjCInterfaceType();
+ OCIT = OCTD->getUnderlyingType()->getAs<ObjCInterfaceType>();
if (!OCIT) {
Diag(receiverLoc, diag::err_invalid_receiver_to_message);
return true;
@@ -446,25 +433,25 @@ Sema::ExprResult Sema::ActOnClassMessage(
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)
+ Diag(Method->getLocation(), diag::note_method_sent_forward_class)
<< Method->getDeclName();
}
if (!Method)
Method = ClassDecl->lookupClassMethod(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,
+
+ 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.
@@ -483,19 +470,19 @@ Sema::ExprResult Sema::ActOnClassMessage(
// 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 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();
@@ -508,8 +495,8 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface())
if (ObjCInterfaceDecl *SuperDecl = ClassDecl->getSuperClass()) {
Method = SuperDecl->lookupInstanceMethod(Sel);
-
- if (!Method)
+
+ if (!Method)
// If we have implementations in scope, check "private" methods.
Method = LookupPrivateInstanceMethod(Sel, SuperDecl);
}
@@ -521,39 +508,42 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
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() ||
+ if (ReceiverCType->isObjCIdType() || 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,
+ 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())) {
+ if (ReceiverCType->isObjCClassType() ||
+ ReceiverCType->isObjCQualifiedClassType()) {
ObjCMethodDecl *Method = 0;
-
+
if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) {
if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) {
// First check the public methods in the class interface.
Method = ClassDecl->lookupClassMethod(Sel);
-
+
if (!Method)
Method = LookupPrivateClassMethod(Sel, ClassDecl);
+
+ // FIXME: if we still haven't found a method, we need to look in
+ // protocols (if we have qualifiers).
}
if (Method && DiagnoseUseOfDecl(Method, receiverLoc))
return true;
@@ -584,13 +574,13 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
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
+
+ // 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 (const ObjCObjectPointerType *QIdTy =
+ if (const ObjCObjectPointerType *QIdTy =
ReceiverCType->getAsObjCQualifiedIdType()) {
// Search protocols for instance methods.
for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(),
@@ -602,19 +592,19 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
if (PDecl && (Method = PDecl->lookupClassMethod(Sel)))
break;
}
- } else if (const ObjCInterfaceType *OCIType =
- ReceiverCType->getAsPointerToObjCInterfaceType()) {
+ } else if (const ObjCObjectPointerType *OCIType =
+ ReceiverCType->getAsObjCInterfacePointerType()) {
// We allow sending a message to a pointer to an interface (an object).
-
- ClassDecl = OCIType->getDecl();
+
+ ClassDecl = OCIType->getInterfaceDecl();
// 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(Sel);
-
+
if (!Method) {
// Search protocol qualifiers.
- for (ObjCQualifiedInterfaceType::qual_iterator QI = OCIType->qual_begin(),
+ for (ObjCObjectPointerType::qual_iterator QI = OCIType->qual_begin(),
E = OCIType->qual_end(); QI != E; ++QI) {
if ((Method = (*QI)->lookupInstanceMethod(Sel)))
break;
@@ -623,7 +613,7 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
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
@@ -631,9 +621,9 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
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 && !OCIType->getInterfaceDecl()->isForwardDecl())
+ Diag(lbrac, diag::warn_maynot_respond)
+ << OCIType->getInterfaceDecl()->getIdentifier()->getName() << Sel;
}
}
}
@@ -641,7 +631,7 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
return true;
} else if (!Context.getObjCIdType().isNull() &&
(ReceiverCType->isPointerType() ||
- (ReceiverCType->isIntegerType() &&
+ (ReceiverCType->isIntegerType() &&
ReceiverCType->isScalarType()))) {
// Implicitly convert integers and pointers to 'id' but emit a warning.
Diag(lbrac, diag::warn_bad_receiver_type)
@@ -653,7 +643,7 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
<< RExpr->getType() << RExpr->getSourceRange();
return true;
}
-
+
if (Method)
DiagnoseSentinelCalls(Method, receiverLoc, ArgExprs, NumArgs);
if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false,
@@ -664,217 +654,3 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
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 ObjCObjectPointerType *lhsQID = lhs->getAsObjCQualifiedIdType()) {
- const ObjCObjectPointerType *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 (ObjCObjectPointerType::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;
- }
- }
- }
-
- ObjCObjectPointerType::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 (ObjCObjectPointerType::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 (ObjCObjectPointerType::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 ObjCObjectPointerType *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()) {
- ObjCObjectPointerType::qual_iterator LHSProtoI = lhsQI->qual_begin();
- ObjCObjectPointerType::qual_iterator LHSProtoE = lhsQI->qual_end();
- for (; LHSProtoI != LHSProtoE; ++LHSProtoI) {
- bool match = false;
- ObjCProtocolDecl *lhsProto = *LHSProtoI;
- for (ObjCObjectPointerType::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 (ObjCObjectPointerType::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/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index ecfdfd7..27f0896 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -36,7 +36,7 @@ static Expr *IsStringInit(Expr *Init, QualType DeclType, ASTContext &Context) {
// 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;
@@ -58,26 +58,38 @@ static Expr *IsStringInit(Expr *Init, QualType DeclType, ASTContext &Context) {
if (Context.typesAreCompatible(Context.getWCharType(),
ElemTy.getUnqualifiedType()))
return Init;
-
+
return 0;
}
-static bool CheckSingleInitializer(Expr *&Init, QualType DeclType,
+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();
-
+ 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();
+ if (S.PerformImplicitConversion(Init, DeclType,
+ "initializing", DirectInit)) {
+ ImplicitConversionSequence ICS;
+ OverloadCandidateSet CandidateSet;
+ if (S.IsUserDefinedConversion(Init, DeclType, ICS.UserDefined,
+ CandidateSet,
+ true, false, false) != S.OR_Ambiguous)
+ return S.Diag(Init->getSourceRange().getBegin(),
+ diag::err_typecheck_convert_incompatible)
+ << DeclType << Init->getType() << "initializing"
+ << Init->getSourceRange();
+ S.Diag(Init->getSourceRange().getBegin(),
+ diag::err_typecheck_convert_ambiguous)
+ << DeclType << Init->getType() << Init->getSourceRange();
+ S.PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
+ return true;
+ }
return false;
}
-
+
Sema::AssignConvertType ConvTy =
S.CheckSingleAssignmentConstraints(DeclType, Init);
return S.DiagnoseAssignmentResult(ConvTy, Init->getLocStart(), DeclType,
@@ -89,21 +101,22 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, Sema &S) {
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
+ // 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);
+ DeclT = S.Context.getConstantArrayWithoutExprType(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.
@@ -111,7 +124,7 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, Sema &S) {
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";
@@ -122,23 +135,26 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, Sema &S) {
bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType,
SourceLocation InitLoc,
DeclarationName InitEntity, bool DirectInit) {
- if (DeclType->isDependentType() ||
+ 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);
-
+ return CheckReferenceInit(Init, DeclType, InitLoc,
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/DirectInit,
+ /*ForceRValue=*/false);
+
// 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
@@ -146,41 +162,52 @@ bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType,
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());
-
+ const CXXRecordDecl *RD =
+ cast<CXXRecordDecl>(DeclType->getAs<RecordType>()->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);
+
+ ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
+
+ CXXConstructorDecl *Constructor
+ = PerformInitializationByConstructor(DeclType,
+ MultiExprArg(*this,
+ (void **)&Init, 1),
+ InitLoc, Init->getSourceRange(),
+ InitEntity,
+ DirectInit? IK_Direct : IK_Copy,
+ ConstructorArgs);
if (!Constructor)
return true;
-
- Init = CXXConstructExpr::Create(Context, DeclType, Constructor, false,
- &Init, 1);
+
+ OwningExprResult InitResult =
+ BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(),
+ DeclType, Constructor,
+ move_arg(ConstructorArgs));
+ if (InitResult.isInvalid())
+ return true;
+
+ Init = InitResult.takeAs<Expr>();
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
@@ -197,7 +224,7 @@ bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType,
// 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)
@@ -206,15 +233,15 @@ bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType,
<< 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;
@@ -257,8 +284,8 @@ class InitListChecker {
bool hadError;
std::map<InitListExpr *, InitListExpr *> SyntacticToSemantic;
InitListExpr *FullyStructuredList;
-
- void CheckImplicitInitList(InitListExpr *ParentIList, QualType T,
+
+ void CheckImplicitInitList(InitListExpr *ParentIList, QualType T,
unsigned &Index, InitListExpr *StructuredList,
unsigned &StructuredIndex,
bool TopLevelObject = false);
@@ -266,41 +293,41 @@ class InitListChecker {
unsigned &Index, InitListExpr *StructuredList,
unsigned &StructuredIndex,
bool TopLevelObject = false);
- void CheckListElementTypes(InitListExpr *IList, QualType &DeclType,
- bool SubobjectIsDesignatorContext,
+ void CheckListElementTypes(InitListExpr *IList, QualType &DeclType,
+ bool SubobjectIsDesignatorContext,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex,
bool TopLevelObject = false);
- void CheckSubElementType(InitListExpr *IList, QualType ElemType,
+ void CheckSubElementType(InitListExpr *IList, QualType ElemType,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex);
- void CheckScalarType(InitListExpr *IList, QualType DeclType,
+ void CheckScalarType(InitListExpr *IList, QualType DeclType,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex);
- void CheckReferenceType(InitListExpr *IList, QualType DeclType,
+ 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,
+ 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,
+ void CheckArrayType(InitListExpr *IList, QualType &DeclType,
+ llvm::APSInt elementIndex,
bool SubobjectIsDesignatorContext, unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex);
- bool CheckDesignatedInitializer(InitListExpr *IList, DesignatedInitExpr *DIE,
+ bool CheckDesignatedInitializer(InitListExpr *IList, DesignatedInitExpr *DIE,
unsigned DesigIdx,
- QualType &CurrentObjectType,
+ QualType &CurrentObjectType,
RecordDecl::field_iterator *NextField,
llvm::APSInt *NextElementIndex,
unsigned &Index,
@@ -334,15 +361,15 @@ public:
/// with expressions that perform value-initialization of the
/// appropriate type.
void InitListChecker::FillInValueInitializations(InitListExpr *ILE) {
- assert((ILE->getType() != SemaRef.Context.VoidTy) &&
+ 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()) {
+
+ if (const RecordType *RType = ILE->getType()->getAs<RecordType>()) {
unsigned Init = 0, NumInits = ILE->getNumInits();
- for (RecordDecl::field_iterator
+ for (RecordDecl::field_iterator
Field = RType->getDecl()->field_begin(),
FieldEnd = RType->getDecl()->field_end();
Field != FieldEnd; ++Field) {
@@ -354,11 +381,11 @@ void InitListChecker::FillInValueInitializations(InitListExpr *ILE) {
// C++ [dcl.init.aggr]p9:
// If an incomplete or empty initializer-list leaves a
// member of reference type uninitialized, the program is
- // ill-formed.
+ // ill-formed.
SemaRef.Diag(Loc, diag::err_init_reference_member_uninitialized)
<< Field->getType()
<< ILE->getSyntacticForm()->getSourceRange();
- SemaRef.Diag(Field->getLocation(),
+ SemaRef.Diag(Field->getLocation(),
diag::note_uninit_reference_member);
hadError = true;
return;
@@ -371,9 +398,9 @@ void InitListChecker::FillInValueInitializations(InitListExpr *ILE) {
// we make that call explicit in the representation (even when it means
// extending the initializer list)?
if (Init < NumInits && !hadError)
- ILE->setInit(Init,
+ ILE->setInit(Init,
new (SemaRef.Context) ImplicitValueInitExpr(Field->getType()));
- } else if (InitListExpr *InnerILE
+ } else if (InitListExpr *InnerILE
= dyn_cast<InitListExpr>(ILE->getInit(Init)))
FillInValueInitializations(InnerILE);
++Init;
@@ -384,22 +411,22 @@ void InitListChecker::FillInValueInitializations(InitListExpr *ILE) {
}
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()) {
+ } else if (const VectorType *VType = ILE->getType()->getAs<VectorType>()) {
ElementType = VType->getElementType();
NumElements = VType->getNumElements();
- } else
+ } else
ElementType = ILE->getType();
-
+
for (unsigned Init = 0; Init != NumElements; ++Init) {
if (Init >= NumInits || !ILE->getInit(Init)) {
if (SemaRef.CheckValueInitialization(ElementType, Loc)) {
@@ -411,10 +438,10 @@ void InitListChecker::FillInValueInitializations(InitListExpr *ILE) {
// we make that call explicit in the representation (even when it means
// extending the initializer list)?
if (Init < NumInits && !hadError)
- ILE->setInit(Init,
+ ILE->setInit(Init,
new (SemaRef.Context) ImplicitValueInitExpr(ElementType));
- }
- else if (InitListExpr *InnerILE =dyn_cast<InitListExpr>(ILE->getInit(Init)))
+ } else if (InitListExpr *InnerILE
+ = dyn_cast<InitListExpr>(ILE->getInit(Init)))
FillInValueInitializations(InnerILE);
}
}
@@ -426,7 +453,7 @@ InitListChecker::InitListChecker(Sema &S, InitListExpr *IL, QualType &T)
unsigned newIndex = 0;
unsigned newStructuredIndex = 0;
- FullyStructuredList
+ FullyStructuredList
= getStructuredSubobjectInit(IL, newIndex, T, 0, 0, IL->getSourceRange());
CheckExplicitInitList(IL, T, newIndex, FullyStructuredList, newStructuredIndex,
/*TopLevelObject=*/true);
@@ -446,9 +473,9 @@ int InitListChecker::numArrayElements(QualType DeclType) {
}
int InitListChecker::numStructUnionElements(QualType DeclType) {
- RecordDecl *structDecl = DeclType->getAsRecordType()->getDecl();
+ RecordDecl *structDecl = DeclType->getAs<RecordType>()->getDecl();
int InitializableMembers = 0;
- for (RecordDecl::field_iterator
+ for (RecordDecl::field_iterator
Field = structDecl->field_begin(),
FieldEnd = structDecl->field_end();
Field != FieldEnd; ++Field) {
@@ -460,19 +487,19 @@ int InitListChecker::numStructUnionElements(QualType DeclType) {
return InitializableMembers - structDecl->hasFlexibleArrayMember();
}
-void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList,
+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();
+ maxElements = T->getAs<VectorType>()->getNumElements();
else
assert(0 && "CheckImplicitInitList(): Illegal type");
@@ -486,8 +513,8 @@ void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList,
// Build a structured initializer list corresponding to this subobject.
InitListExpr *StructuredSubobjectInitList
- = getStructuredSubobjectInit(ParentIList, Index, T, StructuredList,
- StructuredIndex,
+ = getStructuredSubobjectInit(ParentIList, Index, T, StructuredList,
+ StructuredIndex,
SourceRange(ParentIList->getInit(Index)->getSourceRange().getBegin(),
ParentIList->getSourceRange().getEnd()));
unsigned StructuredSubobjectInitIndex = 0;
@@ -495,7 +522,7 @@ void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList,
// Check the element types and build the structural subobject.
unsigned StartIndex = Index;
CheckListElementTypes(ParentIList, T, false, Index,
- StructuredSubobjectInitList,
+ StructuredSubobjectInitList,
StructuredSubobjectInitIndex,
TopLevelObject);
unsigned EndIndex = (Index == StartIndex? StartIndex : Index - 1);
@@ -504,7 +531,7 @@ void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList,
// 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
+ SourceLocation EndLoc
= ParentIList->getInit(EndIndex)->getSourceRange().getEnd();
StructuredSubobjectInitList->setRBraceLoc(EndLoc);
}
@@ -518,7 +545,7 @@ void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T,
assert(IList->isExplicit() && "Illegal Implicit InitListExpr");
SyntacticToSemantic[IList] = StructuredList;
StructuredList->setSyntacticForm(IList);
- CheckListElementTypes(IList, T, true, Index, StructuredList,
+ CheckListElementTypes(IList, T, true, Index, StructuredList,
StructuredIndex, TopLevelObject);
IList->setType(T);
StructuredList->setType(T);
@@ -541,7 +568,7 @@ void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T,
// Don't complain for incomplete types, since we'll get an error
// elsewhere
QualType CurrentObjectType = StructuredList->getType();
- int initKind =
+ int initKind =
CurrentObjectType->isArrayType()? 0 :
CurrentObjectType->isVectorType()? 1 :
CurrentObjectType->isScalarType()? 2 :
@@ -553,6 +580,10 @@ void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T,
DK = diag::err_excess_initializers;
hadError = true;
}
+ if (SemaRef.getLangOptions().OpenCL && initKind == 1) {
+ DK = diag::err_excess_initializers;
+ hadError = true;
+ }
SemaRef.Diag(IList->getInit(Index)->getLocStart(), DK)
<< initKind << IList->getInit(Index)->getSourceRange();
@@ -567,7 +598,7 @@ void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T,
}
void InitListChecker::CheckListElementTypes(InitListExpr *IList,
- QualType &DeclType,
+ QualType &DeclType,
bool SubobjectIsDesignatorContext,
unsigned &Index,
InitListExpr *StructuredList,
@@ -579,8 +610,8 @@ void InitListChecker::CheckListElementTypes(InitListExpr *IList,
CheckVectorType(IList, DeclType, Index, StructuredList, StructuredIndex);
} else if (DeclType->isAggregateType()) {
if (DeclType->isRecordType()) {
- RecordDecl *RD = DeclType->getAsRecordType()->getDecl();
- CheckStructUnionTypes(IList, DeclType, RD->field_begin(),
+ RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl();
+ CheckStructUnionTypes(IList, DeclType, RD->field_begin(),
SubobjectIsDesignatorContext, Index,
StructuredList, StructuredIndex,
TopLevelObject);
@@ -590,8 +621,7 @@ void InitListChecker::CheckListElementTypes(InitListExpr *IList,
false);
CheckArrayType(IList, DeclType, Zero, SubobjectIsDesignatorContext, Index,
StructuredList, StructuredIndex);
- }
- else
+ } else
assert(0 && "Aggregate that isn't a structure or array?!");
} else if (DeclType->isVoidType() || DeclType->isFunctionType()) {
// This type is invalid, issue a diagnostic.
@@ -615,13 +645,13 @@ void InitListChecker::CheckListElementTypes(InitListExpr *IList,
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?).
+ // additional handling is needed here for C++ (and possibly others?).
assert(0 && "Unsupported initializer type");
}
}
void InitListChecker::CheckSubElementType(InitListExpr *IList,
- QualType ElemType,
+ QualType ElemType,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
@@ -629,11 +659,11 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList,
if (InitListExpr *SubInitList = dyn_cast<InitListExpr>(expr)) {
unsigned newIndex = 0;
unsigned newStructuredIndex = 0;
- InitListExpr *newStructuredList
+ InitListExpr *newStructuredList
= getStructuredSubobjectInit(IList, Index, ElemType,
StructuredList, StructuredIndex,
SubInitList->getSourceRange());
- CheckExplicitInitList(SubInitList, ElemType, newIndex,
+ CheckExplicitInitList(SubInitList, ElemType, newIndex,
newStructuredList, newStructuredIndex);
++StructuredIndex;
++Index;
@@ -652,10 +682,14 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList,
// 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);
+ ImplicitConversionSequence ICS
+ = SemaRef.TryCopyInitialization(expr, ElemType,
+ /*SuppressUserConversions=*/false,
+ /*ForceRValue=*/false,
+ /*InOverloadResolution=*/false);
+
if (ICS.ConversionKind != ImplicitConversionSequence::BadConversion) {
- if (SemaRef.PerformImplicitConversion(expr, ElemType, ICS,
+ if (SemaRef.PerformImplicitConversion(expr, ElemType, ICS,
"initializing"))
hadError = true;
UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
@@ -665,7 +699,7 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList,
// Fall through for subaggregate initialization
} else {
- // C99 6.7.8p13:
+ // C99 6.7.8p13:
//
// The initializer for a structure or union object that has
// automatic storage duration shall be either an initializer
@@ -684,13 +718,13 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList,
}
// 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,
+ CheckImplicitInitList(IList, ElemType, Index, StructuredList,
StructuredIndex);
++StructuredIndex;
} else {
@@ -719,7 +753,7 @@ void InitListChecker::CheckScalarType(InitListExpr *IList, QualType DeclType,
++StructuredIndex;
return;
} else if (isa<DesignatedInitExpr>(expr)) {
- SemaRef.Diag(expr->getSourceRange().getBegin(),
+ SemaRef.Diag(expr->getSourceRange().getBegin(),
diag::err_designator_for_scalar_init)
<< DeclType << expr->getSourceRange();
hadError = true;
@@ -763,10 +797,14 @@ void InitListChecker::CheckReferenceType(InitListExpr *IList, QualType DeclType,
++Index;
++StructuredIndex;
return;
- }
+ }
Expr *savExpr = expr; // Might be promoted by CheckSingleInitializer.
- if (SemaRef.CheckReferenceInit(expr, DeclType))
+ if (SemaRef.CheckReferenceInit(expr, DeclType,
+ /*FIXME:*/expr->getLocStart(),
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false,
+ /*ForceRValue=*/false))
hadError = true;
else if (savExpr != expr) {
// The type was promoted, update initializer list.
@@ -782,7 +820,7 @@ void InitListChecker::CheckReferenceType(InitListExpr *IList, QualType DeclType,
// 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(),
+ SemaRef.Diag(IList->getLocStart(),
diag::err_init_reference_member_uninitialized)
<< DeclType
<< IList->getSourceRange();
@@ -793,28 +831,59 @@ void InitListChecker::CheckReferenceType(InitListExpr *IList, QualType DeclType,
}
}
-void InitListChecker::CheckVectorType(InitListExpr *IList, QualType DeclType,
+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();
+ const VectorType *VT = DeclType->getAs<VectorType>();
+ unsigned maxElements = VT->getNumElements();
+ unsigned numEltsInit = 0;
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);
+
+ if (!SemaRef.getLangOptions().OpenCL) {
+ for (unsigned i = 0; i < maxElements; ++i, ++numEltsInit) {
+ // Don't attempt to go past the end of the init list
+ if (Index >= IList->getNumInits())
+ break;
+ CheckSubElementType(IList, elementType, Index,
+ StructuredList, StructuredIndex);
+ }
+ } else {
+ // OpenCL initializers allows vectors to be constructed from vectors.
+ for (unsigned i = 0; i < maxElements; ++i) {
+ // Don't attempt to go past the end of the init list
+ if (Index >= IList->getNumInits())
+ break;
+ QualType IType = IList->getInit(Index)->getType();
+ if (!IType->isVectorType()) {
+ CheckSubElementType(IList, elementType, Index,
+ StructuredList, StructuredIndex);
+ ++numEltsInit;
+ } else {
+ const VectorType *IVT = IType->getAs<VectorType>();
+ unsigned numIElts = IVT->getNumElements();
+ QualType VecType = SemaRef.Context.getExtVectorType(elementType,
+ numIElts);
+ CheckSubElementType(IList, VecType, Index,
+ StructuredList, StructuredIndex);
+ numEltsInit += numIElts;
+ }
+ }
}
+
+ // OpenCL & AltiVec require all elements to be initialized.
+ if (numEltsInit != maxElements)
+ if (SemaRef.getLangOptions().OpenCL || SemaRef.getLangOptions().AltiVec)
+ SemaRef.Diag(IList->getSourceRange().getBegin(),
+ diag::err_vector_incorrect_num_initializers)
+ << (numEltsInit < maxElements) << maxElements << numEltsInit;
}
}
-void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType,
+void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType,
llvm::APSInt elementIndex,
- bool SubobjectIsDesignatorContext,
+ bool SubobjectIsDesignatorContext,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
@@ -873,7 +942,7 @@ void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType,
// Handle this designated initializer. elementIndex will be
// updated to be the next array element we'll initialize.
- if (CheckDesignatedInitializer(IList, DIE, 0,
+ if (CheckDesignatedInitializer(IList, DIE, 0,
DeclType, 0, &elementIndex, Index,
StructuredList, StructuredIndex, true,
false)) {
@@ -921,31 +990,31 @@ void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType,
diag::ext_typecheck_zero_array_size);
}
- DeclType = SemaRef.Context.getConstantArrayType(elementType, maxElements,
+ DeclType = SemaRef.Context.getConstantArrayType(elementType, maxElements,
ArrayType::Normal, 0);
}
}
-void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
- QualType DeclType,
+void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
+ QualType DeclType,
RecordDecl::field_iterator Field,
- bool SubobjectIsDesignatorContext,
+ bool SubobjectIsDesignatorContext,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex,
bool TopLevelObject) {
- RecordDecl* structDecl = DeclType->getAsRecordType()->getDecl();
-
+ RecordDecl* structDecl = DeclType->getAs<RecordType>()->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();
+ RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl();
for (RecordDecl::field_iterator FieldEnd = RD->field_end();
Field != FieldEnd; ++Field) {
if (Field->getDeclName()) {
@@ -960,7 +1029,7 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
// 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 *RD = DeclType->getAs<RecordType>()->getDecl();
RecordDecl::field_iterator FieldEnd = RD->field_end();
bool InitializedSomething = false;
while (Index < IList->getNumInits()) {
@@ -975,7 +1044,7 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
// Handle this designated initializer. Field will be updated to
// the next field that we'll be initializing.
- if (CheckDesignatedInitializer(IList, DIE, 0,
+ if (CheckDesignatedInitializer(IList, DIE, 0,
DeclType, &Field, 0, Index,
StructuredList, StructuredIndex,
true, TopLevelObject))
@@ -1016,15 +1085,15 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
++Field;
}
- if (Field == FieldEnd || !Field->getType()->isIncompleteArrayType() ||
+ if (Field == FieldEnd || !Field->getType()->isIncompleteArrayType() ||
Index >= IList->getNumInits())
return;
// Handle GNU flexible array initializers.
- if (!TopLevelObject &&
+ if (!TopLevelObject &&
(!isa<InitListExpr>(IList->getInit(Index)) ||
cast<InitListExpr>(IList->getInit(Index))->getNumInits() > 0)) {
- SemaRef.Diag(IList->getInit(Index)->getSourceRange().getBegin(),
+ 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)
@@ -1033,7 +1102,7 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
++Index;
return;
} else {
- SemaRef.Diag(IList->getInit(Index)->getSourceRange().getBegin(),
+ 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)
@@ -1055,8 +1124,8 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
/// Field/FieldIndex will be updated to point to the (new)
/// currently-designated field.
static void ExpandAnonymousFieldDesignator(Sema &SemaRef,
- DesignatedInitExpr *DIE,
- unsigned DesigIdx,
+ DesignatedInitExpr *DIE,
+ unsigned DesigIdx,
FieldDecl *Field,
RecordDecl::field_iterator &FieldIter,
unsigned &FieldIndex) {
@@ -1066,14 +1135,14 @@ static void ExpandAnonymousFieldDesignator(Sema &SemaRef,
// 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,
+ Replacements.push_back(Designator((IdentifierInfo *)0,
DIE->getDesignator(DesigIdx)->getDotLoc(),
DIE->getDesignator(DesigIdx)->getFieldLoc()));
else
@@ -1085,9 +1154,9 @@ static void ExpandAnonymousFieldDesignator(Sema &SemaRef,
// 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],
+ DIE->ExpandDesignator(DesigIdx, &Replacements[0],
&Replacements[0] + Replacements.size());
-
+
// Update FieldIter/FieldIndex;
RecordDecl *Record = cast<RecordDecl>(Path.back()->getDeclContext());
FieldIter = Record->field_begin();
@@ -1112,7 +1181,7 @@ static void ExpandAnonymousFieldDesignator(Sema &SemaRef,
/// 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
+/// 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
@@ -1141,9 +1210,9 @@ static void ExpandAnonymousFieldDesignator(Sema &SemaRef,
/// actually be initialized.
///
/// @returns true if there was an error, false otherwise.
-bool
+bool
InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
- DesignatedInitExpr *DIE,
+ DesignatedInitExpr *DIE,
unsigned DesigIdx,
QualType &CurrentObjectType,
RecordDecl::field_iterator *NextField,
@@ -1176,14 +1245,14 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
}
bool IsFirstDesignator = (DesigIdx == 0);
- assert((IsFirstDesignator || StructuredList) &&
+ 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,
+ : getStructuredSubobjectInit(IList, Index, CurrentObjectType,
StructuredList, StructuredIndex,
SourceRange(D->getStartLocation(),
DIE->getSourceRange().getEnd()));
@@ -1198,8 +1267,8 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
//
// 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();
+ // name of a member of that type.
+ const RecordType *RT = CurrentObjectType->getAs<RecordType>();
if (!RT) {
SourceLocation Loc = D->getDotLoc();
if (Loc.isInvalid())
@@ -1216,7 +1285,7 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
FieldDecl *KnownField = D->getField();
IdentifierInfo *FieldName = D->getFieldName();
unsigned FieldIndex = 0;
- RecordDecl::field_iterator
+ RecordDecl::field_iterator
Field = RT->getDecl()->field_begin(),
FieldEnd = RT->getDecl()->field_end();
for (; Field != FieldEnd; ++Field) {
@@ -1234,7 +1303,7 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
// 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.
+ // struct/union.
DeclContext::lookup_result Lookup = RT->getDecl()->lookup(FieldName);
if (Lookup.first == Lookup.second) {
// Name lookup didn't find anything.
@@ -1247,7 +1316,7 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
->isAnonymousStructOrUnion()) {
// Handle an field designator that refers to a member of an
// anonymous struct or union.
- ExpandAnonymousFieldDesignator(SemaRef, DIE, DesigIdx,
+ ExpandAnonymousFieldDesignator(SemaRef, DIE, DesigIdx,
cast<FieldDecl>(*Lookup.first),
Field, FieldIndex);
D = DIE->getDesignator(DesigIdx);
@@ -1255,7 +1324,7 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
// Name lookup found something, but it wasn't a field.
SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_nonfield)
<< FieldName;
- SemaRef.Diag((*Lookup.first)->getLocation(),
+ SemaRef.Diag((*Lookup.first)->getLocation(),
diag::note_field_designator_found);
++Index;
return true;
@@ -1277,7 +1346,7 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
// 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())
@@ -1289,11 +1358,11 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
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
+ DesignatedInitExpr::Designator *NextD
= DIE->getDesignator(DesigIdx + 1);
- SemaRef.Diag(NextD->getStartLocation(),
+ SemaRef.Diag(NextD->getStartLocation(),
diag::err_designator_into_flexible_array_member)
- << SourceRange(NextD->getStartLocation(),
+ << SourceRange(NextD->getStartLocation(),
DIE->getSourceRange().getEnd());
SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member)
<< *Field;
@@ -1311,9 +1380,9 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
}
// Handle GNU flexible array initializers.
- if (!Invalid && !TopLevelObject &&
+ if (!Invalid && !TopLevelObject &&
cast<InitListExpr>(DIE->getInit())->getNumInits() > 0) {
- SemaRef.Diag(DIE->getSourceRange().getBegin(),
+ SemaRef.Diag(DIE->getSourceRange().getBegin(),
diag::err_flexible_array_init_nonempty)
<< DIE->getSourceRange().getBegin();
SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member)
@@ -1331,7 +1400,7 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
unsigned newStructuredIndex = FieldIndex;
unsigned OldIndex = Index;
IList->setInit(Index, DIE->getInit());
- CheckSubElementType(IList, Field->getType(), Index,
+ CheckSubElementType(IList, Field->getType(), Index,
StructuredList, newStructuredIndex);
IList->setInit(OldIndex, DIE);
if (hadError && !prevHadError) {
@@ -1412,10 +1481,10 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
} else {
assert(D->isArrayRangeDesignator() && "Need array-range designator");
-
- DesignatedStartIndex =
+
+ DesignatedStartIndex =
DIE->getArrayRangeStart(*D)->EvaluateAsInt(SemaRef.Context);
- DesignatedEndIndex =
+ DesignatedEndIndex =
DIE->getArrayRangeEnd(*D)->EvaluateAsInt(SemaRef.Context);
IndexExpr = DIE->getArrayRangeEnd(*D);
@@ -1447,11 +1516,11 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
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,
+ StructuredList->resizeInits(SemaRef.Context,
DesignatedEndIndex.getZExtValue() + 1);
// Repeatedly perform subobject initializations in the range
@@ -1483,7 +1552,7 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
StructuredIndex = ElementIndex;
return false;
}
-
+
if (!FinishSubobjectInit)
return false;
@@ -1491,7 +1560,7 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
bool prevHadError = hadError;
CheckArrayType(IList, CurrentObjectType, DesignatedStartIndex, false, Index,
StructuredList, ElementIndex);
- return hadError && !prevHadError;
+ return hadError && !prevHadError;
}
// Get the structured initializer list for a subobject of type
@@ -1507,7 +1576,7 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
ExistingInit = SyntacticToSemantic[IList];
else if (StructuredIndex < StructuredList->getNumInits())
ExistingInit = StructuredList->getInit(StructuredIndex);
-
+
if (InitListExpr *Result = dyn_cast_or_null<InitListExpr>(ExistingInit))
return Result;
@@ -1516,24 +1585,24 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
// 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(),
+ SemaRef.Diag(InitRange.getBegin(),
diag::warn_subobject_initializer_overrides)
<< InitRange;
- SemaRef.Diag(ExistingInit->getSourceRange().getBegin(),
+ 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,
+ InitListExpr *Result
+ = new (SemaRef.Context) InitListExpr(InitRange.getBegin(), 0, 0,
InitRange.getEnd());
Result->setType(CurrentObjectType);
@@ -1548,7 +1617,7 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
NumInits = SubList->getNumInits();
}
- if (const ArrayType *AType
+ if (const ArrayType *AType
= SemaRef.Context.getAsArrayType(CurrentObjectType)) {
if (const ConstantArrayType *CAType = dyn_cast<ConstantArrayType>(AType)) {
NumElements = CAType->getSize().getZExtValue();
@@ -1557,14 +1626,14 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
if (NumInits && NumElements > NumInits)
NumElements = 0;
}
- } else if (const VectorType *VType = CurrentObjectType->getAsVectorType())
+ } else if (const VectorType *VType = CurrentObjectType->getAs<VectorType>())
NumElements = VType->getNumElements();
- else if (const RecordType *RType = CurrentObjectType->getAsRecordType()) {
+ else if (const RecordType *RType = CurrentObjectType->getAs<RecordType>()) {
RecordDecl *RDecl = RType->getDecl();
if (RDecl->isUnion())
NumElements = 1;
else
- NumElements = std::distance(RDecl->field_begin(),
+ NumElements = std::distance(RDecl->field_begin(),
RDecl->field_end());
}
@@ -1596,15 +1665,15 @@ void InitListChecker::UpdateStructuredListElement(InitListExpr *StructuredList,
if (Expr *PrevInit = StructuredList->updateInit(StructuredIndex, expr)) {
// This initializer overwrites a previous initializer. Warn.
- SemaRef.Diag(expr->getSourceRange().getBegin(),
+ SemaRef.Diag(expr->getSourceRange().getBegin(),
diag::warn_initializer_overrides)
<< expr->getSourceRange();
- SemaRef.Diag(PrevInit->getSourceRange().getBegin(),
+ SemaRef.Diag(PrevInit->getSourceRange().getBegin(),
diag::note_previous_initializer)
<< /*FIXME:has side effects=*/0
<< PrevInit->getSourceRange();
}
-
+
++StructuredIndex;
}
@@ -1615,7 +1684,7 @@ void InitListChecker::UpdateStructuredListElement(InitListExpr *StructuredList,
/// 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
+static bool
CheckArrayDesignatorExpr(Sema &S, Expr *Index, llvm::APSInt &Value) {
SourceLocation Loc = Index->getSourceRange().getBegin();
@@ -1646,7 +1715,7 @@ Sema::OwningExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
const Designator &D = Desig.getDesignator(Idx);
switch (D.getKind()) {
case Designator::FieldDesignator:
- Designators.push_back(ASTDesignator(D.getField(), D.getDotLoc(),
+ Designators.push_back(ASTDesignator(D.getField(), D.getDotLoc(),
D.getFieldLoc()));
break;
@@ -1659,7 +1728,7 @@ Sema::OwningExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
Invalid = true;
else {
Designators.push_back(ASTDesignator(InitExpressions.size(),
- D.getLBracketLoc(),
+ D.getLBracketLoc(),
D.getRBracketLoc()));
InitExpressions.push_back(Index);
}
@@ -1691,12 +1760,12 @@ Sema::OwningExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
if (!StartDependent && !EndDependent && EndValue < StartValue) {
Diag(D.getEllipsisLoc(), diag::err_array_designator_empty_range)
- << StartValue.toString(10) << EndValue.toString(10)
+ << StartValue.toString(10) << EndValue.toString(10)
<< StartIndex->getSourceRange() << EndIndex->getSourceRange();
Invalid = true;
} else {
Designators.push_back(ASTDesignator(InitExpressions.size(),
- D.getLBracketLoc(),
+ D.getLBracketLoc(),
D.getEllipsisLoc(),
D.getRBracketLoc()));
InitExpressions.push_back(StartIndex);
@@ -1741,7 +1810,7 @@ bool Sema::CheckInitList(InitListExpr *&InitList, QualType &DeclType) {
/// 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.
+/// initializer is provided for that object.
///
/// \returns true if there was an error, false otherwise.
bool Sema::CheckValueInitialization(QualType Type, SourceLocation Loc) {
@@ -1753,19 +1822,34 @@ bool Sema::CheckValueInitialization(QualType Type, SourceLocation Loc) {
if (const ArrayType *AT = Context.getAsArrayType(Type))
return CheckValueInitialization(AT->getElementType(), Loc);
- if (const RecordType *RT = Type->getAsRecordType()) {
+ if (const RecordType *RT = Type->getAs<RecordType>()) {
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 (ClassDecl->hasUserDeclaredConstructor()) {
+ ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
+
+ CXXConstructorDecl *Constructor
+ = PerformInitializationByConstructor(Type,
+ MultiExprArg(*this, 0, 0),
+ Loc, SourceRange(Loc),
+ DeclarationName(),
+ IK_Direct,
+ ConstructorArgs);
+ if (!Constructor)
+ return true;
+
+ OwningExprResult Init
+ = BuildCXXConstructExpr(Loc, Type, Constructor,
+ move_arg(ConstructorArgs));
+ if (Init.isInvalid())
+ return true;
+
+ // FIXME: Actually perform the value-initialization!
+ return false;
+ }
}
}
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 6f2fc5e..dd877c1 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -12,18 +12,20 @@
//
//===----------------------------------------------------------------------===//
#include "Sema.h"
-#include "SemaInherit.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/CXXInheritance.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/ExprCXX.h"
#include "clang/Parse/DeclSpec.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/LangOptions.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/Support/ErrorHandling.h"
#include <set>
#include <vector>
#include <iterator>
@@ -34,7 +36,6 @@ 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.
@@ -59,7 +60,7 @@ struct UsingDirAncestorCompare {
/// 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,
+void AddNamespaceUsingDirectives(ASTContext &Context,
DeclContext *NS,
UsingDirectivesTy &UDirs,
NamespaceSet &Visited) {
@@ -76,7 +77,7 @@ void AddNamespaceUsingDirectives(ASTContext &Context,
/// AddScopeUsingDirectives - Adds all UsingDirectiveDecl's found in Scope S,
/// including all found in the namespaces they nominate.
-static void AddScopeUsingDirectives(ASTContext &Context, Scope *S,
+static void AddScopeUsingDirectives(ASTContext &Context, Scope *S,
UsingDirectivesTy &UDirs) {
NamespaceSet VisitedNS;
@@ -99,189 +100,17 @@ static void AddScopeUsingDirectives(ASTContext &Context, Scope *S,
NamespaceDecl *Nominated = UD->getNominatedNamespace();
if (!VisitedNS.count(Nominated)) {
VisitedNS.insert(Nominated);
- AddNamespaceUsingDirectives(Context, Nominated, UDirs,
+ 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 ((*I)->isFunctionOrFunctionTemplate()) {
- // 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 && (*Last)->isFunctionOrFunctionTemplate();
- ++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());
- NamedDecl *ND = (*I)->getUnderlyingDecl();
- if (isa<FunctionDecl>(ND))
- Ovl->addOverload(cast<FunctionDecl>(ND));
- else
- Ovl->addOverload(cast<FunctionTemplateDecl>(ND));
- }
-
- NamedDecl *ND = (*Last)->getUnderlyingDecl();
- if (isa<FunctionDecl>(ND))
- Ovl->addOverload(cast<FunctionDecl>(ND));
- else
- Ovl->addOverload(cast<FunctionTemplateDecl>(ND));
- }
-
- // 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()->getUnderlyingDecl();
-
- if (TagDecl *TD = dyn_cast<TagDecl>(ND)) {
- TagFound = Context.getCanonicalDecl(TD);
- TagNames += FoundDecls.insert(TagFound)? 1 : 0;
- } else if (ND->isFunctionOrFunctionTemplate())
- 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,
+inline unsigned
+getIdentifierNamespacesFromLookupNameKind(Sema::LookupNameKind NameKind,
bool CPlusPlus) {
unsigned IDNS = 0;
switch (NameKind) {
@@ -300,7 +129,7 @@ getIdentifierNamespacesFromLookupNameKind(Sema::LookupNameKind NameKind,
case Sema::LookupMemberName:
IDNS = Decl::IDNS_Member;
if (CPlusPlus)
- IDNS |= Decl::IDNS_Tag | Decl::IDNS_Ordinary;
+ IDNS |= Decl::IDNS_Tag | Decl::IDNS_Ordinary;
break;
case Sema::LookupNestedNameSpecifierName:
@@ -323,97 +152,81 @@ getIdentifierNamespacesFromLookupNameKind(Sema::LookupNameKind NameKind,
return IDNS;
}
-Sema::LookupResult
-Sema::LookupResult::CreateLookupResult(ASTContext &Context, NamedDecl *D) {
- if (D)
- D = D->getUnderlyingDecl();
-
- 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;
+// Necessary because CXXBasePaths is not complete in Sema.h
+void Sema::LookupResult::deletePaths(CXXBasePaths *Paths) {
+ delete Paths;
}
-/// @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 && (*F)->isFunctionOrFunctionTemplate()) {
- IdentifierResolver::iterator Next = F;
- ++Next;
- if (Next != L && (*Next)->isFunctionOrFunctionTemplate()) {
- Result.StoredKind = OverloadedDeclFromIdResolver;
- Result.First = F.getAsOpaqueValue();
- Result.Last = L.getAsOpaqueValue();
- return Result;
- }
- }
-
- NamedDecl *D = *F;
- if (D)
- D = D->getUnderlyingDecl();
-
- 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 && (*F)->isFunctionOrFunctionTemplate()) {
- DeclContext::lookup_iterator Next = F;
- ++Next;
- if (Next != L && (*Next)->isFunctionOrFunctionTemplate()) {
- Result.StoredKind = OverloadedDeclFromDeclContext;
- Result.First = reinterpret_cast<uintptr_t>(F);
- Result.Last = reinterpret_cast<uintptr_t>(L);
- return Result;
- }
- }
+void Sema::LookupResult::resolveKind() {
+ unsigned N = Decls.size();
- NamedDecl *D = *F;
- if (D)
- D = D->getUnderlyingDecl();
-
- Result.StoredKind = SingleDecl;
- Result.First = reinterpret_cast<uintptr_t>(D);
- Result.Last = 0;
- return Result;
-}
+ // Fast case: no possible ambiguity.
+ if (N <= 1) return;
-/// @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;
+ // Don't do any extra resolution if we've already resolved as ambiguous.
+ if (Kind == Ambiguous) return;
- case OverloadedDeclSingleDecl:
- case OverloadedDeclFromIdResolver:
- case OverloadedDeclFromDeclContext:
- return FoundOverloaded;
+ llvm::SmallPtrSet<NamedDecl*, 16> Unique;
- case AmbiguousLookupStoresBasePaths:
- return Last? AmbiguousBaseSubobjectTypes : AmbiguousBaseSubobjects;
+ bool Ambiguous = false;
+ bool HasTag = false, HasFunction = false, HasNonFunction = false;
- case AmbiguousLookupStoresDecls:
- return AmbiguousReference;
+ unsigned UniqueTagIndex = 0;
+
+ unsigned I = 0;
+ while (I < N) {
+ NamedDecl *D = Decls[I];
+ assert(D == D->getUnderlyingDecl());
+
+ NamedDecl *CanonD = cast<NamedDecl>(D->getCanonicalDecl());
+ if (!Unique.insert(CanonD)) {
+ // If it's not unique, pull something off the back (and
+ // continue at this index).
+ Decls[I] = Decls[--N];
+ } else if (isa<UnresolvedUsingDecl>(D)) {
+ // FIXME: proper support for UnresolvedUsingDecls.
+ Decls[I] = Decls[--N];
+ } else {
+ // Otherwise, do some decl type analysis and then continue.
+ if (isa<TagDecl>(D)) {
+ if (HasTag)
+ Ambiguous = true;
+ UniqueTagIndex = I;
+ HasTag = true;
+ } else if (D->isFunctionOrFunctionTemplate()) {
+ HasFunction = true;
+ } else {
+ if (HasNonFunction)
+ Ambiguous = true;
+ HasNonFunction = true;
+ }
+ I++;
+ }
}
- // We can't ever get here.
- return NotFound;
+ // C++ [basic.scope.hiding]p2:
+ // A class name or enumeration name can be hidden by the name of
+ // an object, function, or enumerator declared in the same
+ // scope. If a class or enumeration name and an object, function,
+ // or enumerator are declared in the same scope (in any order)
+ // with the same name, the class or enumeration name is hidden
+ // wherever the object, function, or enumerator name is visible.
+ // But it's still an error if there are distinct tag types found,
+ // even if they're not visible. (ref?)
+ if (HasTag && !Ambiguous && (HasFunction || HasNonFunction))
+ Decls[UniqueTagIndex] = Decls[--N];
+
+ Decls.set_size(N);
+
+ if (HasFunction && HasNonFunction)
+ Ambiguous = true;
+
+ if (Ambiguous)
+ setAmbiguous(LookupResult::AmbiguousReference);
+ else if (N > 1)
+ Kind = LookupResult::FoundOverloaded;
+ else
+ Kind = LookupResult::Found;
}
/// @brief Converts the result of name lookup into a single (possible
@@ -423,197 +236,99 @@ Sema::LookupResult::LookupKind Sema::LookupResult::getKind() const {
/// (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.
+/// 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;
+NamedDecl *Sema::LookupResult::getAsSingleDecl(ASTContext &C) const {
+ size_t size = Decls.size();
+ if (size == 0) return 0;
+ if (size == 1) return *begin();
+
+ if (isAmbiguous()) return 0;
+
+ iterator I = begin(), E = end();
+
+ OverloadedFunctionDecl *Ovl
+ = OverloadedFunctionDecl::Create(C, (*I)->getDeclContext(),
+ (*I)->getDeclName());
+ for (; I != E; ++I) {
+ NamedDecl *ND = *I;
+ assert(ND->getUnderlyingDecl() == ND
+ && "decls in lookup result should have redirections stripped");
+ assert(ND->isFunctionOrFunctionTemplate());
+ if (isa<FunctionDecl>(ND))
+ Ovl->addOverload(cast<FunctionDecl>(ND));
+ else
+ Ovl->addOverload(cast<FunctionTemplateDecl>(ND));
+ // FIXME: UnresolvedUsingDecls.
}
-
- return 0;
+
+ return Ovl;
}
-/// @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;
+void Sema::LookupResult::addDeclsFromBasePaths(const CXXBasePaths &P) {
+ CXXBasePaths::paths_iterator I, E;
+ DeclContext::lookup_iterator DI, DE;
+ for (I = P.begin(), E = P.end(); I != E; ++I)
+ for (llvm::tie(DI,DE) = I->Decls; DI != DE; ++DI)
+ addDecl(*DI);
}
-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;
+void Sema::LookupResult::setAmbiguousBaseSubobjects(CXXBasePaths &P) {
+ Paths = new CXXBasePaths;
+ Paths->swap(P);
+ addDeclsFromBasePaths(*Paths);
+ resolveKind();
+ setAmbiguous(AmbiguousBaseSubobjects);
}
-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;
+void Sema::LookupResult::setAmbiguousBaseSubobjectTypes(CXXBasePaths &P) {
+ Paths = new CXXBasePaths;
+ Paths->swap(P);
+ addDeclsFromBasePaths(*Paths);
+ resolveKind();
+ setAmbiguous(AmbiguousBaseSubobjectTypes);
}
-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));
+void Sema::LookupResult::print(llvm::raw_ostream &Out) {
+ Out << Decls.size() << " result(s)";
+ if (isAmbiguous()) Out << ", ambiguous";
+ if (Paths) Out << ", base paths present";
+
+ for (iterator I = begin(), E = end(); I != E; ++I) {
+ Out << "\n";
+ (*I)->print(Out, 2);
}
-
- // 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));
- }
+// Adds all qualifying matches for a name within a decl context to the
+// given lookup result. Returns true if any matches were found.
+static bool LookupDirect(Sema::LookupResult &R, DeclContext *DC,
+ DeclarationName Name,
+ Sema::LookupNameKind NameKind,
+ unsigned IDNS) {
+ bool Found = false;
- // Required to suppress GCC warning.
- return iterator();
-}
+ DeclContext::lookup_iterator I, E;
+ for (llvm::tie(I, E) = DC->lookup(Name); I != E; ++I)
+ if (Sema::isAcceptableLookupResult(*I, NameKind, IDNS))
+ R.addDecl(*I), Found = true;
-void Sema::LookupResult::Destroy() {
- if (BasePaths *Paths = getBasePaths())
- delete Paths;
- else if (getKind() == AmbiguousReference)
- delete[] reinterpret_cast<NamedDecl **>(First);
+ return Found;
}
-static void
-CppNamespaceLookup(ASTContext &Context, DeclContext *NS,
+static bool
+CppNamespaceLookup(Sema::LookupResult &R, ASTContext &Context, DeclContext *NS,
DeclarationName Name, Sema::LookupNameKind NameKind,
- unsigned IDNS, LookupResultsTy &Results,
- UsingDirectivesTy *UDirs = 0) {
+ unsigned IDNS, 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(Name); I != E; ++I)
- if (Sema::isAcceptableLookupResult(*I, NameKind, IDNS)) {
- Results.push_back(Sema::LookupResult::CreateLookupResult(Context, I, E));
- break;
- }
+ bool Found = LookupDirect(R, NS, Name, NameKind, IDNS);
if (UDirs) {
// For each UsingDirectiveDecl, which common ancestor is equal
@@ -622,11 +337,15 @@ CppNamespaceLookup(ASTContext &Context, DeclContext *NS,
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);
+ if (LookupDirect(R, (*UI)->getNominatedNamespace(), Name, NameKind, IDNS))
+ Found = true;
}
+
+ R.resolveKind();
+
+ return Found;
}
static bool isNamespaceOrTranslationUnitScope(Scope *S) {
@@ -635,16 +354,31 @@ static bool isNamespaceOrTranslationUnitScope(Scope *S) {
return false;
}
-std::pair<bool, Sema::LookupResult>
-Sema::CppLookupName(Scope *S, DeclarationName Name,
+// Find the next outer declaration context corresponding to this scope.
+static DeclContext *findOuterContext(Scope *S) {
+ for (S = S->getParent(); S; S = S->getParent())
+ if (S->getEntity())
+ return static_cast<DeclContext *>(S->getEntity())->getPrimaryContext();
+
+ return 0;
+}
+
+bool
+Sema::CppLookupName(LookupResult &R, Scope *S, DeclarationName Name,
LookupNameKind NameKind, bool RedeclarationOnly) {
assert(getLangOptions().CPlusPlus &&
"Can perform only C++ lookup");
- unsigned IDNS
+ unsigned IDNS
= getIdentifierNamespacesFromLookupNameKind(NameKind, /*CPlusPlus*/ true);
+
+ // If we're testing for redeclarations, also look in the friend namespaces.
+ if (RedeclarationOnly) {
+ if (IDNS & Decl::IDNS_Tag) IDNS |= Decl::IDNS_TagFriend;
+ if (IDNS & Decl::IDNS_Ordinary) IDNS |= Decl::IDNS_OrdinaryFriend;
+ }
+
Scope *Initial = S;
- DeclContext *OutOfLineCtx = 0;
- IdentifierResolver::iterator
+ IdentifierResolver::iterator
I = IdResolver.begin(Name),
IEnd = IdResolver.end();
@@ -653,8 +387,8 @@ Sema::CppLookupName(Scope *S, DeclarationName Name,
// ...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”.
+ // [Note: in this context, "contains" means "contains directly or
+ // indirectly".
//
// For example:
// namespace A { int i; }
@@ -668,47 +402,33 @@ Sema::CppLookupName(Scope *S, DeclarationName Name,
//
for (; S && !isNamespaceOrTranslationUnitScope(S); S = S->getParent()) {
// Check whether the IdResolver has anything in this scope.
+ bool Found = false;
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);
+ Found = true;
+ R.addDecl(*I);
}
}
+ if (Found) {
+ R.resolveKind();
+ return true;
+ }
+
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)
- 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)
- return std::make_pair(true, R);
- }
+ DeclContext *OuterCtx = findOuterContext(S);
+ for (; Ctx && Ctx->getPrimaryContext() != OuterCtx;
+ Ctx = Ctx->getLookupParent()) {
+ if (Ctx->isFunctionOrMethod())
+ continue;
+
+ // Perform qualified name lookup into this context.
+ // FIXME: In some cases, we know that every name that could be found by
+ // this qualified name lookup will also be on the identifier chain. For
+ // 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 (LookupQualifiedName(R, Ctx, Name, NameKind, RedeclarationOnly))
+ return true;
}
}
}
@@ -731,71 +451,41 @@ Sema::CppLookupName(Scope *S, DeclarationName Name,
// 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());
+ if (Ctx->isTransparentContext())
+ continue;
+
assert(Ctx && Ctx->isFileContext() &&
"We should have been looking only at file context here already.");
// Check whether the IdResolver has anything in this scope.
+ bool Found = false;
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;
+ Found = true;
+ R.addDecl(*I);
}
}
- LookedInCtx = true;
// Look into context considering using-directives.
- CppNamespaceLookup(Context, Ctx, Name, NameKind, IDNS,
- LookupResults, &UDirs);
+ if (CppNamespaceLookup(R, Context, Ctx, Name, NameKind, IDNS, &UDirs))
+ Found = true;
- if ((Result = MergeLookupResults(Context, LookupResults)) ||
- (RedeclarationOnly && !Ctx->isTransparentContext()))
- return std::make_pair(true, Result);
- }
+ if (Found) {
+ R.resolveKind();
+ return true;
+ }
- 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());
+ if (RedeclarationOnly && !Ctx->isTransparentContext())
+ return false;
}
- return std::make_pair(false, LookupResult());
+
+ return !R.empty();
}
/// @brief Perform unqualified name lookup starting from a given
@@ -823,17 +513,16 @@ Sema::CppLookupName(Scope *S, DeclarationName Name,
/// @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
+/// 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);
+bool Sema::LookupName(LookupResult &R, Scope *S, DeclarationName Name,
+ LookupNameKind NameKind, bool RedeclarationOnly,
+ bool AllowBuiltinCreation, SourceLocation Loc) {
+ if (!Name) return false;
if (!getLangOptions().CPlusPlus) {
// Unqualified name lookup in C/Objective-C is purely lexical, so
@@ -861,7 +550,7 @@ Sema::LookupName(Scope *S, DeclarationName Name, LookupNameKind NameKind,
case Sema::LookupRedeclarationWithLinkage:
// Find the nearest non-transparent declaration scope.
while (!(S->getFlags() & Scope::DeclScope) ||
- (S->getEntity() &&
+ (S->getEntity() &&
static_cast<DeclContext *>(S->getEntity())
->isTransparentContext()))
S = S->getParent();
@@ -875,7 +564,7 @@ Sema::LookupName(Scope *S, DeclarationName Name, LookupNameKind NameKind,
case Sema::LookupObjCImplementationName:
IDNS = Decl::IDNS_ObjCImplementation;
break;
-
+
case Sema::LookupObjCCategoryImplName:
IDNS = Decl::IDNS_ObjCCategoryImpl;
break;
@@ -888,7 +577,7 @@ Sema::LookupName(Scope *S, DeclarationName Name, LookupNameKind NameKind,
bool LeftStartingScope = false;
for (IdentifierResolver::iterator I = IdResolver.begin(Name),
- IEnd = IdResolver.end();
+ IEnd = IdResolver.end();
I != IEnd; ++I)
if ((*I)->isInIdentifierNamespace(IDNS)) {
if (NameKind == LookupRedeclarationWithLinkage) {
@@ -903,6 +592,8 @@ Sema::LookupName(Scope *S, DeclarationName Name, LookupNameKind NameKind,
continue;
}
+ R.addDecl(*I);
+
if ((*I)->getAttr<OverloadableAttr>()) {
// If this declaration has the "overloadable" attribute, we
// might have a set of overloaded functions.
@@ -918,26 +609,24 @@ Sema::LookupName(Scope *S, DeclarationName Name, LookupNameKind NameKind,
for (++LastI; LastI != IEnd; ++LastI) {
if (!S->isDeclScope(DeclPtrTy::make(*LastI)))
break;
+ R.addDecl(*LastI);
}
-
- return LookupResult::CreateLookupResult(Context, I, LastI);
}
- // We have a single lookup result.
- return LookupResult::CreateLookupResult(Context, *I);
+ R.resolveKind();
+
+ return true;
}
} else {
// Perform C++ unqualified name lookup.
- std::pair<bool, LookupResult> MaybeResult =
- CppLookupName(S, Name, NameKind, RedeclarationOnly);
- if (MaybeResult.first)
- return MaybeResult.second;
+ if (CppLookupName(R, S, Name, NameKind, RedeclarationOnly))
+ return true;
}
// 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 ||
+ if (NameKind == LookupOrdinaryName ||
NameKind == LookupRedeclarationWithLinkage) {
IdentifierInfo *II = Name.getAsIdentifierInfo();
if (II && AllowBuiltinCreation) {
@@ -945,17 +634,132 @@ Sema::LookupName(Scope *S, DeclarationName Name, LookupNameKind NameKind,
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 &&
+ if (getLangOptions().CPlusPlus &&
Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
- return LookupResult::CreateLookupResult(Context, 0);
+ return false;
+
+ NamedDecl *D = LazilyCreateBuiltin((IdentifierInfo *)II, BuiltinID,
+ S, RedeclarationOnly, Loc);
+ if (D) R.addDecl(D);
+ return (D != NULL);
+ }
+ }
+ }
+ return false;
+}
+
+/// @brief Perform qualified name lookup in the namespaces nominated by
+/// using directives by the given context.
+///
+/// C++98 [namespace.qual]p2:
+/// Given X::m (where X is a user-declared namespace), or given ::m
+/// (where X is the global namespace), let S be the set of all
+/// declarations of m in X and in the transitive closure of all
+/// namespaces nominated by using-directives in X and its used
+/// namespaces, except that using-directives are ignored in any
+/// namespace, including X, directly containing one or more
+/// declarations of m. No namespace is searched more than once in
+/// the lookup of a name. If S is the empty set, the program is
+/// ill-formed. Otherwise, if S has exactly one member, or if the
+/// context of the reference is a using-declaration
+/// (namespace.udecl), S is the required set of declarations of
+/// m. Otherwise if the use of m is not one that allows a unique
+/// declaration to be chosen from S, the program is ill-formed.
+/// C++98 [namespace.qual]p5:
+/// During the lookup of a qualified namespace member name, if the
+/// lookup finds more than one declaration of the member, and if one
+/// declaration introduces a class name or enumeration name and the
+/// other declarations either introduce the same object, the same
+/// enumerator or a set of functions, the non-type name hides the
+/// class or enumeration name if and only if the declarations are
+/// from the same namespace; otherwise (the declarations are from
+/// different namespaces), the program is ill-formed.
+static bool LookupQualifiedNameInUsingDirectives(Sema::LookupResult &R,
+ DeclContext *StartDC,
+ DeclarationName Name,
+ Sema::LookupNameKind NameKind,
+ unsigned IDNS) {
+ assert(StartDC->isFileContext() && "start context is not a file context");
+
+ DeclContext::udir_iterator I = StartDC->using_directives_begin();
+ DeclContext::udir_iterator E = StartDC->using_directives_end();
+
+ if (I == E) return false;
+
+ // We have at least added all these contexts to the queue.
+ llvm::DenseSet<DeclContext*> Visited;
+ Visited.insert(StartDC);
+
+ // We have not yet looked into these namespaces, much less added
+ // their "using-children" to the queue.
+ llvm::SmallVector<NamespaceDecl*, 8> Queue;
+
+ // We have already looked into the initial namespace; seed the queue
+ // with its using-children.
+ for (; I != E; ++I) {
+ NamespaceDecl *ND = (*I)->getNominatedNamespace();
+ if (Visited.insert(ND).second)
+ Queue.push_back(ND);
+ }
+
+ // The easiest way to implement the restriction in [namespace.qual]p5
+ // is to check whether any of the individual results found a tag
+ // and, if so, to declare an ambiguity if the final result is not
+ // a tag.
+ bool FoundTag = false;
+ bool FoundNonTag = false;
+
+ Sema::LookupResult LocalR;
+
+ bool Found = false;
+ while (!Queue.empty()) {
+ NamespaceDecl *ND = Queue.back();
+ Queue.pop_back();
+
+ // We go through some convolutions here to avoid copying results
+ // between LookupResults.
+ bool UseLocal = !R.empty();
+ Sema::LookupResult &DirectR = UseLocal ? LocalR : R;
+ bool FoundDirect = LookupDirect(DirectR, ND, Name, NameKind, IDNS);
+
+ if (FoundDirect) {
+ // First do any local hiding.
+ DirectR.resolveKind();
+
+ // If the local result is a tag, remember that.
+ if (DirectR.isSingleTagDecl())
+ FoundTag = true;
+ else
+ FoundNonTag = true;
- return LookupResult::CreateLookupResult(Context,
- LazilyCreateBuiltin((IdentifierInfo *)II, BuiltinID,
- S, RedeclarationOnly, Loc));
+ // Append the local results to the total results if necessary.
+ if (UseLocal) {
+ R.addAllDecls(LocalR);
+ LocalR.clear();
}
}
+
+ // If we find names in this namespace, ignore its using directives.
+ if (FoundDirect) {
+ Found = true;
+ continue;
+ }
+
+ for (llvm::tie(I,E) = ND->getUsingDirectives(); I != E; ++I) {
+ NamespaceDecl *Nom = (*I)->getNominatedNamespace();
+ if (Visited.insert(Nom).second)
+ Queue.push_back(Nom);
+ }
}
- return LookupResult::CreateLookupResult(Context, 0);
+
+ if (Found) {
+ if (FoundTag && FoundNonTag)
+ R.setAmbiguousQualifiedTagHiding();
+ else
+ R.resolveKind();
+ }
+
+ return Found;
}
/// @brief Perform qualified name lookup into a given context.
@@ -988,40 +792,91 @@ Sema::LookupName(Scope *S, DeclarationName Name, LookupNameKind NameKind,
/// @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) {
+bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
+ DeclarationName Name, LookupNameKind NameKind,
+ bool RedeclarationOnly) {
assert(LookupCtx && "Sema::LookupQualifiedName requires a lookup context");
-
- if (!Name) return LookupResult::CreateLookupResult(Context, 0);
+
+ if (!Name)
+ return false;
// 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,
+ = getIdentifierNamespacesFromLookupNameKind(NameKind,
getLangOptions().CPlusPlus);
if (NameKind == LookupOrdinaryName)
IDNS |= Decl::IDNS_Member;
+ // Make sure that the declaration context is complete.
+ assert((!isa<TagDecl>(LookupCtx) ||
+ LookupCtx->isDependentContext() ||
+ cast<TagDecl>(LookupCtx)->isDefinition() ||
+ Context.getTypeDeclType(cast<TagDecl>(LookupCtx))->getAs<TagType>()
+ ->isBeingDefined()) &&
+ "Declaration context must already be complete!");
+
// Perform qualified name lookup into the LookupCtx.
- DeclContext::lookup_iterator I, E;
- for (llvm::tie(I, E) = LookupCtx->lookup(Name); I != E; ++I)
- if (isAcceptableLookupResult(*I, NameKind, IDNS))
- return LookupResult::CreateLookupResult(Context, I, E);
+ if (LookupDirect(R, LookupCtx, Name, NameKind, IDNS)) {
+ R.resolveKind();
+ return true;
+ }
+
+ // Don't descend into implied contexts for redeclarations.
+ // C++98 [namespace.qual]p6:
+ // In a declaration for a namespace member in which the
+ // declarator-id is a qualified-id, given that the qualified-id
+ // for the namespace member has the form
+ // nested-name-specifier unqualified-id
+ // the unqualified-id shall name a member of the namespace
+ // designated by the nested-name-specifier.
+ // See also [class.mfct]p5 and [class.static.data]p2.
+ if (RedeclarationOnly)
+ return false;
- // If this isn't a C++ class or we aren't allowed to look into base
+ // If this is a namespace, look it up in
+ if (LookupCtx->isFileContext())
+ return LookupQualifiedNameInUsingDirectives(R, LookupCtx, Name, NameKind,
+ IDNS);
+
+ // If this isn't a C++ class, we aren't allowed to look into base
// classes, we're done.
- if (RedeclarationOnly || !isa<CXXRecordDecl>(LookupCtx))
- return LookupResult::CreateLookupResult(Context, 0);
+ if (!isa<CXXRecordDecl>(LookupCtx))
+ return false;
// Perform lookup into our base classes.
- BasePaths Paths;
- Paths.setOrigin(Context.getTypeDeclType(cast<RecordDecl>(LookupCtx)));
+ CXXRecordDecl *LookupRec = cast<CXXRecordDecl>(LookupCtx);
+ CXXBasePaths Paths;
+ Paths.setOrigin(LookupRec);
// Look for this member in our base classes
- if (!LookupInBases(cast<CXXRecordDecl>(LookupCtx),
- MemberLookupCriteria(Name, NameKind, IDNS), Paths))
- return LookupResult::CreateLookupResult(Context, 0);
+ CXXRecordDecl::BaseMatchesCallback *BaseCallback = 0;
+ switch (NameKind) {
+ case LookupOrdinaryName:
+ case LookupMemberName:
+ case LookupRedeclarationWithLinkage:
+ BaseCallback = &CXXRecordDecl::FindOrdinaryMember;
+ break;
+
+ case LookupTagName:
+ BaseCallback = &CXXRecordDecl::FindTagMember;
+ break;
+
+ case LookupOperatorName:
+ case LookupNamespaceName:
+ case LookupObjCProtocolName:
+ case LookupObjCImplementationName:
+ case LookupObjCCategoryImplName:
+ // These lookups will never find a member in a C++ class (or base class).
+ return false;
+
+ case LookupNestedNameSpecifierName:
+ BaseCallback = &CXXRecordDecl::FindNestedNameSpecifierMember;
+ break;
+ }
+
+ if (!LookupRec->lookupInBases(BaseCallback, Name.getAsOpaquePtr(), Paths))
+ return false;
// C++ [class.member.lookup]p2:
// [...] If the resulting set of declarations are not all from
@@ -1032,29 +887,28 @@ Sema::LookupQualifiedName(DeclContext *LookupCtx, DeclarationName Name,
// FIXME: support using declarations!
QualType SubobjectType;
int SubobjectNumber = 0;
- for (BasePaths::paths_iterator Path = Paths.begin(), PathEnd = Paths.end();
+ for (CXXBasePaths::paths_iterator Path = Paths.begin(), PathEnd = Paths.end();
Path != PathEnd; ++Path) {
- const BasePathElement &PathElement = Path->back();
+ const CXXBasePathElement &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.
+ // This is the first subobject we've looked at. Record its type.
SubobjectType = Context.getCanonicalType(PathElement.Base->getType());
SubobjectNumber = PathElement.SubobjectNumber;
- } else if (SubobjectType
+ } 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);
+ R.setAmbiguousBaseSubobjectTypes(Paths);
+ return 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.
+ // has more than one base class subobject of type T.
Decl *FirstDecl = *Path->Decls.first;
if (isa<VarDecl>(FirstDecl) ||
isa<TypeDecl>(FirstDecl) ||
@@ -1083,21 +937,18 @@ Sema::LookupQualifiedName(DeclContext *LookupCtx, DeclarationName Name,
// 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);
+ R.setAmbiguousBaseSubobjects(Paths);
+ return true;
}
}
// Lookup in a base class succeeded; return these results.
- // If we found a function declaration, return an overload set.
- if ((*Paths.front().Decls.first)->isFunctionOrFunctionTemplate())
- 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);
+ DeclContext::lookup_iterator I, E;
+ for (llvm::tie(I,E) = Paths.front().Decls; I != E; ++I)
+ R.addDecl(*I);
+ R.resolveKind();
+ return true;
}
/// @brief Performs name lookup for a name that was parsed in the
@@ -1111,59 +962,50 @@ Sema::LookupQualifiedName(DeclContext *LookupCtx, DeclarationName Name,
///
/// @param S The scope from which unqualified name lookup will
/// begin.
-///
-/// @param SS An optional C++ scope-specified, e.g., "::N::M".
+///
+/// @param SS An optional C++ scope-specifier, 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
+/// 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
+/// @param EnteringContext Indicates whether we are going to enter the
+/// context of the scope-specifier SS (if present).
+///
+/// @returns True if any decls were found (but possibly ambiguous)
+bool Sema::LookupParsedName(LookupResult &R, Scope *S, const CXXScopeSpec *SS,
+ DeclarationName Name, LookupNameKind NameKind,
+ bool RedeclarationOnly, bool AllowBuiltinCreation,
+ SourceLocation Loc,
+ bool EnteringContext) {
+ if (SS && SS->isInvalid()) {
+ // When 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(Name); I != E; ++I)
- if (isAcceptableLookupResult(*I, NameKind, IDNS))
- return LookupResult::CreateLookupResult(Context, I, E);
- }
+ return false;
+ }
- if (RequireCompleteDeclContext(*SS))
- return LookupResult::CreateLookupResult(Context, 0);
+ if (SS && SS->isSet()) {
+ if (DeclContext *DC = computeDeclContext(*SS, EnteringContext)) {
+ // We have resolved the scope specifier to a particular declaration
+ // contex, and will perform name lookup in that context.
+ if (!DC->isDependentContext() && RequireCompleteDeclContext(*SS))
+ return false;
- return LookupQualifiedName(computeDeclContext(*SS),
- Name, NameKind, RedeclarationOnly);
+ return LookupQualifiedName(R, DC, Name, NameKind, RedeclarationOnly);
+ }
+
+ // We could not resolve the scope specified to a specific declaration
+ // context, which means that SS refers to an unknown specialization.
+ // Name lookup can't find anything in this case.
+ return false;
}
- LookupResult result(LookupName(S, Name, NameKind, RedeclarationOnly,
- AllowBuiltinCreation, Loc));
-
- return(result);
+ // Perform unqualified name lookup starting in the given scope.
+ return LookupName(R, S, Name, NameKind, RedeclarationOnly,
+ AllowBuiltinCreation, Loc);
}
@@ -1171,7 +1013,7 @@ Sema::LookupParsedName(Scope *S, const CXXScopeSpec *SS,
/// from name lookup.
///
/// @param Result The ambiguous name lookup result.
-///
+///
/// @param Name The name of the entity that name lookup was
/// searching for.
///
@@ -1184,79 +1026,164 @@ Sema::LookupParsedName(Scope *S, const CXXScopeSpec *SS,
///
/// @returns true
bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result, DeclarationName Name,
- SourceLocation NameLoc,
+ 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");
+ switch (Result.getAmbiguityKind()) {
+ case LookupResult::AmbiguousBaseSubobjects: {
+ CXXBasePaths *Paths = Result.getBasePaths();
+ 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);
+
+ return true;
+ }
+ case LookupResult::AmbiguousBaseSubobjectTypes: {
Diag(NameLoc, diag::err_ambiguous_member_multiple_subobject_types)
<< Name << LookupRange;
-
+
+ CXXBasePaths *Paths = Result.getBasePaths();
std::set<Decl *> DeclsPrinted;
- for (BasePaths::paths_iterator Path = Paths->begin(), PathEnd = Paths->end();
+ for (CXXBasePaths::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);
+ case LookupResult::AmbiguousTagHiding: {
+ Diag(NameLoc, diag::err_ambiguous_tag_hiding) << Name << LookupRange;
- for (; DI != DEnd; ++DI)
- Diag((*DI)->getLocation(), diag::note_ambiguous_candidate) << *DI;
+ llvm::SmallPtrSet<NamedDecl*,8> TagDecls;
+
+ LookupResult::iterator DI, DE = Result.end();
+ for (DI = Result.begin(); DI != DE; ++DI)
+ if (TagDecl *TD = dyn_cast<TagDecl>(*DI)) {
+ TagDecls.insert(TD);
+ Diag(TD->getLocation(), diag::note_hidden_tag);
+ }
+
+ for (DI = Result.begin(); DI != DE; ++DI)
+ if (!isa<TagDecl>(*DI))
+ Diag((*DI)->getLocation(), diag::note_hiding_object);
+
+ // For recovery purposes, go ahead and implement the hiding.
+ Result.hideDecls(TagDecls);
- Result.Destroy();
return true;
}
- assert(false && "Unhandled form of name lookup ambiguity");
+ case LookupResult::AmbiguousReference: {
+ Diag(NameLoc, diag::err_ambiguous_reference) << Name << LookupRange;
+
+ LookupResult::iterator DI = Result.begin(), DE = Result.end();
+ for (; DI != DE; ++DI)
+ Diag((*DI)->getLocation(), diag::note_ambiguous_candidate) << *DI;
+
+ return true;
+ }
+ }
- // We can't reach here.
+ llvm::llvm_unreachable("unknown ambiguity kind");
return true;
}
+static void
+addAssociatedClassesAndNamespaces(QualType T,
+ ASTContext &Context,
+ Sema::AssociatedNamespaceSet &AssociatedNamespaces,
+ Sema::AssociatedClassSet &AssociatedClasses);
+
+static void CollectNamespace(Sema::AssociatedNamespaceSet &Namespaces,
+ DeclContext *Ctx) {
+ if (Ctx->isFileContext())
+ Namespaces.insert(Ctx);
+}
+
+// \brief Add the associated classes and namespaces for argument-dependent
+// lookup that involves a template argument (C++ [basic.lookup.koenig]p2).
+static void
+addAssociatedClassesAndNamespaces(const TemplateArgument &Arg,
+ ASTContext &Context,
+ Sema::AssociatedNamespaceSet &AssociatedNamespaces,
+ Sema::AssociatedClassSet &AssociatedClasses) {
+ // C++ [basic.lookup.koenig]p2, last bullet:
+ // -- [...] ;
+ switch (Arg.getKind()) {
+ case TemplateArgument::Null:
+ break;
+
+ case TemplateArgument::Type:
+ // [...] the namespaces and classes associated with the types of the
+ // template arguments provided for template type parameters (excluding
+ // template template parameters)
+ addAssociatedClassesAndNamespaces(Arg.getAsType(), Context,
+ AssociatedNamespaces,
+ AssociatedClasses);
+ break;
+
+ case TemplateArgument::Declaration:
+ // [...] the namespaces in which any template template arguments are
+ // defined; and the classes in which any member templates used as
+ // template template arguments are defined.
+ if (ClassTemplateDecl *ClassTemplate
+ = dyn_cast<ClassTemplateDecl>(Arg.getAsDecl())) {
+ DeclContext *Ctx = ClassTemplate->getDeclContext();
+ if (CXXRecordDecl *EnclosingClass = dyn_cast<CXXRecordDecl>(Ctx))
+ AssociatedClasses.insert(EnclosingClass);
+ // Add the associated namespace for this class.
+ while (Ctx->isRecord())
+ Ctx = Ctx->getParent();
+ CollectNamespace(AssociatedNamespaces, Ctx);
+ }
+ break;
+
+ case TemplateArgument::Integral:
+ case TemplateArgument::Expression:
+ // [Note: non-type template arguments do not contribute to the set of
+ // associated namespaces. ]
+ break;
+
+ case TemplateArgument::Pack:
+ for (TemplateArgument::pack_iterator P = Arg.pack_begin(),
+ PEnd = Arg.pack_end();
+ P != PEnd; ++P)
+ addAssociatedClassesAndNamespaces(*P, Context,
+ AssociatedNamespaces,
+ AssociatedClasses);
+ break;
+ }
+}
+
// \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,
+// 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,
- bool &GlobalScope) {
+ 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.
+ // which its associated classes are defined.
// Add the class of which it is a member, if any.
DeclContext *Ctx = Class->getDeclContext();
@@ -1265,17 +1192,38 @@ addAssociatedClassesAndNamespaces(CXXRecordDecl *Class,
// Add the associated namespace for this class.
while (Ctx->isRecord())
Ctx = Ctx->getParent();
- if (NamespaceDecl *EnclosingNamespace = dyn_cast<NamespaceDecl>(Ctx))
- AssociatedNamespaces.insert(EnclosingNamespace);
- else if (Ctx->isTranslationUnit())
- GlobalScope = true;
-
+ CollectNamespace(AssociatedNamespaces, Ctx);
+
// 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
+ // -- If T is a template-id, its associated namespaces and classes are
+ // the namespace in which the template is defined; for member
+ // templates, the member template’s class; the namespaces and classes
+ // associated with the types of the template arguments provided for
+ // template type parameters (excluding template template parameters); the
+ // namespaces in which any template template arguments are defined; and
+ // the classes in which any member templates used as template template
+ // arguments are defined. [Note: non-type template arguments do not
+ // contribute to the set of associated namespaces. ]
+ if (ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(Class)) {
+ DeclContext *Ctx = Spec->getSpecializedTemplate()->getDeclContext();
+ if (CXXRecordDecl *EnclosingClass = dyn_cast<CXXRecordDecl>(Ctx))
+ AssociatedClasses.insert(EnclosingClass);
+ // Add the associated namespace for this class.
+ while (Ctx->isRecord())
+ Ctx = Ctx->getParent();
+ CollectNamespace(AssociatedNamespaces, Ctx);
+
+ const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
+ for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
+ addAssociatedClassesAndNamespaces(TemplateArgs[I], Context,
+ AssociatedNamespaces,
+ AssociatedClasses);
+ }
// Add direct and indirect base classes along with their associated
// namespaces.
@@ -1290,17 +1238,14 @@ addAssociatedClassesAndNamespaces(CXXRecordDecl *Class,
for (CXXRecordDecl::base_class_iterator Base = Class->bases_begin(),
BaseEnd = Class->bases_end();
Base != BaseEnd; ++Base) {
- const RecordType *BaseType = Base->getType()->getAsRecordType();
+ const RecordType *BaseType = Base->getType()->getAs<RecordType>();
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);
- else if (BaseCtx->isTranslationUnit())
- GlobalScope = true;
+ CollectNamespace(AssociatedNamespaces, BaseCtx);
// Make sure we visit the bases of this base class.
if (BaseDecl->bases_begin() != BaseDecl->bases_end())
@@ -1312,13 +1257,12 @@ addAssociatedClassesAndNamespaces(CXXRecordDecl *Class,
// \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,
+// (C++ [basic.lookup.koenig]p2).
+static void
+addAssociatedClassesAndNamespaces(QualType T,
ASTContext &Context,
Sema::AssociatedNamespaceSet &AssociatedNamespaces,
- Sema::AssociatedClassSet &AssociatedClasses,
- bool &GlobalScope) {
+ Sema::AssociatedClassSet &AssociatedClasses) {
// C++ [basic.lookup.koenig]p2:
//
// For each argument type T in the function call, there is a set
@@ -1332,44 +1276,43 @@ addAssociatedClassesAndNamespaces(QualType T,
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.
+ // 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())
+ if (const PointerType *Ptr = T->getAs<PointerType>())
T = Ptr->getPointeeType();
else if (const ArrayType *Ptr = Context.getAsArrayType(T))
T = Ptr->getElementType();
- else
+ else
break;
}
// -- If T is a fundamental type, its associated sets of
// namespaces and classes are both empty.
- if (T->getAsBuiltinType())
+ if (T->getAs<BuiltinType>())
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
+ // which its associated classes are defined.
+ if (const RecordType *ClassType = T->getAs<RecordType>())
+ if (CXXRecordDecl *ClassDecl
= dyn_cast<CXXRecordDecl>(ClassType->getDecl())) {
- addAssociatedClassesAndNamespaces(ClassDecl, Context,
- AssociatedNamespaces,
- AssociatedClasses,
- GlobalScope);
+ 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()) {
+ // it has no associated class.
+ if (const EnumType *EnumT = T->getAs<EnumType>()) {
EnumDecl *Enum = EnumT->getDecl();
DeclContext *Ctx = Enum->getDeclContext();
@@ -1379,10 +1322,7 @@ addAssociatedClassesAndNamespaces(QualType T,
// Add the associated namespace for this class.
while (Ctx->isRecord())
Ctx = Ctx->getParent();
- if (NamespaceDecl *EnclosingNamespace = dyn_cast<NamespaceDecl>(Ctx))
- AssociatedNamespaces.insert(EnclosingNamespace);
- else if (Ctx->isTranslationUnit())
- GlobalScope = true;
+ CollectNamespace(AssociatedNamespaces, Ctx);
return;
}
@@ -1390,50 +1330,48 @@ addAssociatedClassesAndNamespaces(QualType T,
// -- 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()) {
+ if (const FunctionType *FnType = T->getAs<FunctionType>()) {
// Return type
- addAssociatedClassesAndNamespaces(FunctionType->getResultType(),
+ addAssociatedClassesAndNamespaces(FnType->getResultType(),
Context,
- AssociatedNamespaces, AssociatedClasses,
- GlobalScope);
+ AssociatedNamespaces, AssociatedClasses);
- const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FunctionType);
+ const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FnType);
if (!Proto)
return;
// Argument types
for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(),
- ArgEnd = Proto->arg_type_end();
+ ArgEnd = Proto->arg_type_end();
Arg != ArgEnd; ++Arg)
addAssociatedClassesAndNamespaces(*Arg, Context,
- AssociatedNamespaces, AssociatedClasses,
- GlobalScope);
-
+ 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.
+ // 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()) {
+ // X.
+ if (const MemberPointerType *MemberPtr = T->getAs<MemberPointerType>()) {
// Handle the type that the pointer to member points to.
addAssociatedClassesAndNamespaces(MemberPtr->getPointeeType(),
Context,
- AssociatedNamespaces, AssociatedClasses,
- GlobalScope);
+ AssociatedNamespaces,
+ AssociatedClasses);
// Handle the class type into which this points.
- if (const RecordType *Class = MemberPtr->getClass()->getAsRecordType())
+ if (const RecordType *Class = MemberPtr->getClass()->getAs<RecordType>())
addAssociatedClassesAndNamespaces(cast<CXXRecordDecl>(Class->getDecl()),
Context,
- AssociatedNamespaces, AssociatedClasses,
- GlobalScope);
+ AssociatedNamespaces,
+ AssociatedClasses);
return;
}
@@ -1447,13 +1385,12 @@ addAssociatedClassesAndNamespaces(QualType T,
/// arguments.
///
/// This routine computes the sets of associated classes and associated
-/// namespaces searched by argument-dependent lookup
+/// namespaces searched by argument-dependent lookup
/// (C++ [basic.lookup.argdep]) for a given set of arguments.
-void
+void
Sema::FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs,
AssociatedNamespaceSet &AssociatedNamespaces,
- AssociatedClassSet &AssociatedClasses,
- bool &GlobalScope) {
+ AssociatedClassSet &AssociatedClasses) {
AssociatedNamespaces.clear();
AssociatedClasses.clear();
@@ -1463,14 +1400,14 @@ Sema::FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs,
// 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).
+ // argument).
for (unsigned ArgIdx = 0; ArgIdx != NumArgs; ++ArgIdx) {
Expr *Arg = Args[ArgIdx];
if (Arg->getType() != Context.OverloadTy) {
addAssociatedClassesAndNamespaces(Arg->getType(), Context,
- AssociatedNamespaces, AssociatedClasses,
- GlobalScope);
+ AssociatedNamespaces,
+ AssociatedClasses);
continue;
}
@@ -1482,16 +1419,23 @@ Sema::FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs,
// classes and namespaces associated with its (non-dependent)
// parameter types and return type.
DeclRefExpr *DRE = 0;
+ TemplateIdRefExpr *TIRE = 0;
+ Arg = Arg->IgnoreParens();
if (UnaryOperator *unaryOp = dyn_cast<UnaryOperator>(Arg)) {
- if (unaryOp->getOpcode() == UnaryOperator::AddrOf)
+ if (unaryOp->getOpcode() == UnaryOperator::AddrOf) {
DRE = dyn_cast<DeclRefExpr>(unaryOp->getSubExpr());
- } else
+ TIRE = dyn_cast<TemplateIdRefExpr>(unaryOp->getSubExpr());
+ }
+ } else {
DRE = dyn_cast<DeclRefExpr>(Arg);
- if (!DRE)
- continue;
+ TIRE = dyn_cast<TemplateIdRefExpr>(Arg);
+ }
- OverloadedFunctionDecl *Ovl
- = dyn_cast<OverloadedFunctionDecl>(DRE->getDecl());
+ OverloadedFunctionDecl *Ovl = 0;
+ if (DRE)
+ Ovl = dyn_cast<OverloadedFunctionDecl>(DRE->getDecl());
+ else if (TIRE)
+ Ovl = TIRE->getTemplateName().getAsOverloadedFunctionDecl();
if (!Ovl)
continue;
@@ -1506,16 +1450,13 @@ Sema::FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs,
// 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);
- else if (Ctx->isTranslationUnit())
- GlobalScope = true;
+ CollectNamespace(AssociatedNamespaces, Ctx);
// Add the classes and namespaces associated with the parameter
// types and return type of this function.
addAssociatedClassesAndNamespaces(FDecl->getType(), Context,
- AssociatedNamespaces, AssociatedClasses,
- GlobalScope);
+ AssociatedNamespaces,
+ AssociatedClasses);
}
}
}
@@ -1525,7 +1466,7 @@ Sema::FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs,
/// 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
+static bool
IsAcceptableNonMemberOperatorCandidate(FunctionDecl *Fn,
QualType T1, QualType T2,
ASTContext &Context) {
@@ -1535,7 +1476,7 @@ IsAcceptableNonMemberOperatorCandidate(FunctionDecl *Fn,
if (T1->isRecordType() || (!T2.isNull() && T2->isRecordType()))
return true;
- const FunctionProtoType *Proto = Fn->getType()->getAsFunctionProtoType();
+ const FunctionProtoType *Proto = Fn->getType()->getAs<FunctionProtoType>();
if (Proto->getNumArgs() < 1)
return false;
@@ -1561,26 +1502,19 @@ IsAcceptableNonMemberOperatorCandidate(FunctionDecl *Fn,
/// \brief Find the protocol with the given name, if any.
ObjCProtocolDecl *Sema::LookupProtocol(IdentifierInfo *II) {
- Decl *D = LookupName(TUScope, II, LookupObjCProtocolName).getAsDecl();
+ Decl *D = LookupSingleName(TUScope, II, LookupObjCProtocolName);
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();
+ Decl *D = LookupSingleName(TUScope, II, LookupObjCCategoryImplName);
return cast_or_null<ObjCCategoryImplDecl>(D);
}
void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
- QualType T1, QualType T2,
+ QualType T1, QualType T2,
FunctionSet &Functions) {
// C++ [over.match.oper]p3:
// -- The set of non-member candidates is the result of the
@@ -1589,17 +1523,18 @@ void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
// 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
+ // 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”,
+ // 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);
-
+ LookupResult Operators;
+ LookupName(Operators, S, OpName, LookupOperatorName);
+
assert(!Operators.isAmbiguous() && "Operator lookup cannot be ambiguous");
- if (!Operators)
+ if (Operators.empty())
return;
for (LookupResult::iterator Op = Operators.begin(), OpEnd = Operators.end();
@@ -1607,10 +1542,10 @@ void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*Op)) {
if (IsAcceptableNonMemberOperatorCandidate(FD, T1, T2, Context))
Functions.insert(FD); // FIXME: canonical FD
- } else if (FunctionTemplateDecl *FunTmpl
+ } else if (FunctionTemplateDecl *FunTmpl
= dyn_cast<FunctionTemplateDecl>(*Op)) {
// FIXME: friend operators?
- // FIXME: do we need to check IsAcceptableNonMemberOperatorCandidate,
+ // FIXME: do we need to check IsAcceptableNonMemberOperatorCandidate,
// later?
if (!FunTmpl->getDeclContext()->isRecord())
Functions.insert(FunTmpl);
@@ -1618,6 +1553,14 @@ void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
}
}
+static void CollectFunctionDecl(Sema::FunctionSet &Functions,
+ Decl *D) {
+ if (FunctionDecl *Func = dyn_cast<FunctionDecl>(D))
+ Functions.insert(Func);
+ else if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D))
+ Functions.insert(FunTmpl);
+}
+
void Sema::ArgumentDependentLookup(DeclarationName Name,
Expr **Args, unsigned NumArgs,
FunctionSet &Functions) {
@@ -1625,10 +1568,9 @@ void Sema::ArgumentDependentLookup(DeclarationName Name,
// arguments we have.
AssociatedNamespaceSet AssociatedNamespaces;
AssociatedClassSet AssociatedClasses;
- bool GlobalScope = false;
- FindAssociatedClassesAndNamespaces(Args, NumArgs,
- AssociatedNamespaces, AssociatedClasses,
- GlobalScope);
+ FindAssociatedClassesAndNamespaces(Args, NumArgs,
+ AssociatedNamespaces,
+ AssociatedClasses);
// C++ [basic.lookup.argdep]p3:
// Let X be the lookup set produced by unqualified lookup (3.4.1)
@@ -1642,8 +1584,8 @@ void Sema::ArgumentDependentLookup(DeclarationName Name,
// 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) {
+ 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:
@@ -1651,28 +1593,22 @@ void Sema::ArgumentDependentLookup(DeclarationName Name,
// -- Any using-directives in the associated namespace are
// ignored.
//
- // -- FIXME: Any namespace-scope friend functions declared in
+ // -- 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(Name); I != E; ++I) {
- if (FunctionDecl *Func = dyn_cast<FunctionDecl>(*I))
- Functions.insert(Func);
- else if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(*I))
- Functions.insert(FunTmpl);
- }
- }
-
- if (GlobalScope) {
- DeclContext::lookup_iterator I, E;
- for (llvm::tie(I, E)
- = Context.getTranslationUnitDecl()->lookup(Name);
- I != E; ++I) {
- if (FunctionDecl *Func = dyn_cast<FunctionDecl>(*I))
- Functions.insert(Func);
- else if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(*I))
- Functions.insert(FunTmpl);
+ Decl *D = *I;
+ // If the only declaration here is an ordinary friend, consider
+ // it only if it was declared in an associated classes.
+ if (D->getIdentifierNamespace() == Decl::IDNS_OrdinaryFriend) {
+ DeclContext *LexDC = D->getLexicalDeclContext();
+ if (!AssociatedClasses.count(cast<CXXRecordDecl>(LexDC)))
+ continue;
+ }
+
+ CollectFunctionDecl(Functions, D);
}
}
}
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 03ac2d9..99e7b08 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -12,23 +12,25 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
-#include "SemaInherit.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/TypeOrdering.h"
+#include "clang/Basic/PartialDiagnostic.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Compiler.h"
#include <algorithm>
+#include <cstdio>
namespace clang {
/// GetConversionCategory - Retrieve the implicit conversion
/// category corresponding to the given implicit conversion kind.
-ImplicitConversionCategory
+ImplicitConversionCategory
GetConversionCategory(ImplicitConversionKind Kind) {
static const ImplicitConversionCategory
Category[(int)ICK_Num_Conversion_Kinds] = {
@@ -136,10 +138,9 @@ ImplicitConversionRank StandardConversionSequence::getRank() const {
/// 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
+/// used as part of the ranking of standard conversion sequences
/// (C++ 13.3.3.2p4).
-bool StandardConversionSequence::isPointerConversionToBool() const
-{
+bool StandardConversionSequence::isPointerConversionToBool() const {
QualType FromType = QualType::getFromOpaquePtr(FromTypePtr);
QualType ToType = QualType::getFromOpaquePtr(ToTypePtr);
@@ -159,10 +160,9 @@ bool StandardConversionSequence::isPointerConversionToBool() const
/// 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
+bool
StandardConversionSequence::
-isPointerConversionToVoidPointer(ASTContext& Context) const
-{
+isPointerConversionToVoidPointer(ASTContext& Context) const {
QualType FromType = QualType::getFromOpaquePtr(FromTypePtr);
QualType ToType = QualType::getFromOpaquePtr(ToTypePtr);
@@ -173,7 +173,7 @@ isPointerConversionToVoidPointer(ASTContext& Context) const
FromType = Context.getArrayDecayedType(FromType);
if (Second == ICK_Pointer_Conversion)
- if (const PointerType* ToPtrType = ToType->getAsPointerType())
+ if (const PointerType* ToPtrType = ToType->getAs<PointerType>())
return ToPtrType->getPointeeType()->isVoidType();
return false;
@@ -260,7 +260,7 @@ void ImplicitConversionSequence::DebugPrint() const {
// 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.
+// FunctionDecl that New cannot be overloaded with.
//
// Example: Given the following input:
//
@@ -269,7 +269,7 @@ void ImplicitConversionSequence::DebugPrint() const {
// int f(int, int); // #3
//
// When we process #1, there is no previous declaration of "f",
-// so IsOverload will not be used.
+// 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
@@ -283,9 +283,8 @@ void ImplicitConversionSequence::DebugPrint() const {
// 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)
-{
+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?
@@ -304,8 +303,8 @@ Sema::IsOverload(FunctionDecl *New, Decl* OldD,
return IsOverload(New, Old->getTemplatedDecl(), MatchedDecl);
else if (FunctionDecl* Old = dyn_cast<FunctionDecl>(OldD)) {
FunctionTemplateDecl *OldTemplate = Old->getDescribedFunctionTemplate();
- FunctionTemplateDecl *NewTemplate = New->getDescribedFunctionTemplate();
-
+ FunctionTemplateDecl *NewTemplate = New->getDescribedFunctionTemplate();
+
// C++ [temp.fct]p2:
// A function template can be overloaded with other function templates
// and with normal (non-template) functions.
@@ -340,21 +339,21 @@ Sema::IsOverload(FunctionDecl *New, Decl* OldD,
return true;
// C++ [temp.over.link]p4:
- // The signature of a function template consists of its function
+ // The signature of a function template consists of its function
// signature, its return type and its template parameter list. The names
// of the template parameters are significant only for establishing the
- // relationship between the template parameters and the rest of the
+ // relationship between the template parameters and the rest of the
// signature.
//
// We check the return type and template parameter lists for function
// templates first; the remaining checks follow.
if (NewTemplate &&
- (!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
- OldTemplate->getTemplateParameters(),
+ (!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
+ OldTemplate->getTemplateParameters(),
false, false, SourceLocation()) ||
OldType->getResultType() != NewType->getResultType()))
return true;
-
+
// If the function is a class member, its signature includes the
// cv-qualifiers (if any) on the function itself.
//
@@ -365,7 +364,7 @@ Sema::IsOverload(FunctionDecl *New, Decl* OldD,
// can be overloaded.
CXXMethodDecl* OldMethod = dyn_cast<CXXMethodDecl>(Old);
CXXMethodDecl* NewMethod = dyn_cast<CXXMethodDecl>(New);
- if (OldMethod && NewMethod &&
+ if (OldMethod && NewMethod &&
!OldMethod->isStatic() && !NewMethod->isStatic() &&
OldMethod->getTypeQualifiers() != NewMethod->getTypeQualifiers())
return true;
@@ -405,18 +404,25 @@ Sema::IsOverload(FunctionDecl *New, Decl* OldD,
/// permitted.
/// If @p ForceRValue, then overloading is performed as if From was an rvalue,
/// no matter its actual lvalueness.
+/// If @p UserCast, the implicit conversion is being done for a user-specified
+/// cast.
ImplicitConversionSequence
Sema::TryImplicitConversion(Expr* From, QualType ToType,
bool SuppressUserConversions,
- bool AllowExplicit, bool ForceRValue)
-{
+ bool AllowExplicit, bool ForceRValue,
+ bool InOverloadResolution,
+ bool UserCast) {
ImplicitConversionSequence ICS;
- if (IsStandardConversion(From, ToType, ICS.Standard))
+ OverloadCandidateSet Conversions;
+ OverloadingResult UserDefResult = OR_Success;
+ if (IsStandardConversion(From, ToType, InOverloadResolution, ICS.Standard))
ICS.ConversionKind = ImplicitConversionSequence::StandardConversion;
else if (getLangOptions().CPlusPlus &&
- IsUserDefinedConversion(From, ToType, ICS.UserDefined,
+ (UserDefResult = IsUserDefinedConversion(From, ToType,
+ ICS.UserDefined,
+ Conversions,
!SuppressUserConversions, AllowExplicit,
- ForceRValue)) {
+ ForceRValue, UserCast)) == OR_Success) {
ICS.ConversionKind = ImplicitConversionSequence::UserDefinedConversion;
// C++ [over.ics.user]p4:
// A conversion of an expression of class type to the same class
@@ -425,9 +431,9 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType,
// 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
+ if (CXXConstructorDecl *Constructor
= dyn_cast<CXXConstructorDecl>(ICS.UserDefined.ConversionFunction)) {
- QualType FromCanon
+ QualType FromCanon
= Context.getCanonicalType(From->getType().getUnqualifiedType());
QualType ToCanon = Context.getCanonicalType(ToType).getUnqualifiedType();
if (FromCanon == ToCanon || IsDerivedFrom(FromCanon, ToCanon)) {
@@ -453,8 +459,15 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType,
if (SuppressUserConversions &&
ICS.ConversionKind == ImplicitConversionSequence::UserDefinedConversion)
ICS.ConversionKind = ImplicitConversionSequence::BadConversion;
- } else
+ } else {
ICS.ConversionKind = ImplicitConversionSequence::BadConversion;
+ if (UserDefResult == OR_Ambiguous) {
+ for (OverloadCandidateSet::iterator Cand = Conversions.begin();
+ Cand != Conversions.end(); ++Cand)
+ if (Cand->Viable)
+ ICS.ConversionFunctionSet.push_back(Cand->Function);
+ }
+ }
return ICS;
}
@@ -467,10 +480,10 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType,
/// 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)
-{
+bool
+Sema::IsStandardConversion(Expr* From, QualType ToType,
+ bool InOverloadResolution,
+ StandardConversionSequence &SCS) {
QualType FromType = From->getType();
// Standard conversions (C++ [conv])
@@ -481,23 +494,23 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
SCS.CopyConstructor = 0;
// There are no standard conversions for class types in C++, so
- // abort early. When overloading in C, however, we do permit
+ // 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,
+ // 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):
+ // 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 &&
+ if (argIsLvalue == Expr::LV_Valid &&
!FromType->isFunctionType() && !FromType->isArrayType() &&
Context.getCanonicalType(FromType) != Context.OverloadTy) {
SCS.First = ICK_Lvalue_To_Rvalue;
@@ -509,9 +522,8 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
// FIXME: Doesn't see through to qualifiers behind a typedef!
FromType = FromType.getUnqualifiedType();
- }
- // Array-to-pointer conversion (C++ 4.2)
- else if (FromType->isArrayType()) {
+ } else if (FromType->isArrayType()) {
+ // Array-to-pointer conversion (C++ 4.2)
SCS.First = ICK_Array_To_Pointer;
// An lvalue or rvalue of type "array of N T" or "array of unknown
@@ -532,19 +544,17 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
SCS.ToTypePtr = ToType.getAsOpaquePtr();
return true;
}
- }
- // Function-to-pointer conversion (C++ 4.3).
- else if (FromType->isFunctionType() && argIsLvalue == Expr::LV_Valid) {
+ } else if (FromType->isFunctionType() && argIsLvalue == Expr::LV_Valid) {
+ // Function-to-pointer conversion (C++ 4.3).
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
+ } else if (FunctionDecl *Fn
= ResolveAddressOfOverloadedFunction(From, ToType, false)) {
+ // Address of overloaded function (C++ [over.over]).
SCS.First = ICK_Function_To_Pointer;
// We were able to resolve the address of the overloaded function,
@@ -566,9 +576,8 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
Context.getTypeDeclType(M->getParent()).getTypePtr());
} else
FromType = Context.getPointerType(FromType);
- }
- // We don't require any conversions for the first step.
- else {
+ } else {
+ // We don't require any conversions for the first step.
SCS.First = ICK_Identity;
}
@@ -583,79 +592,68 @@ Sema::IsStandardConversion(Expr* From, QualType 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)) {
+ } else if (IsIntegralPromotion(From, FromType, ToType)) {
+ // Integral promotion (C++ 4.5).
SCS.Second = ICK_Integral_Promotion;
FromType = ToType.getUnqualifiedType();
- }
- // Floating point promotion (C++ 4.6).
- else if (IsFloatingPointPromotion(FromType, ToType)) {
+ } else if (IsFloatingPointPromotion(FromType, ToType)) {
+ // Floating point promotion (C++ 4.6).
SCS.Second = ICK_Floating_Promotion;
FromType = ToType.getUnqualifiedType();
- }
- // Complex promotion (Clang extension)
- else if (IsComplexPromotion(FromType, ToType)) {
+ } else if (IsComplexPromotion(FromType, ToType)) {
+ // Complex promotion (Clang extension)
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()) &&
+ } else if ((FromType->isIntegralType() || FromType->isEnumeralType()) &&
(ToType->isIntegralType() && !ToType->isEnumeralType())) {
+ // Integral conversions (C++ 4.7).
+ // FIXME: isIntegralType shouldn't be true for enums in C++.
SCS.Second = ICK_Integral_Conversion;
FromType = ToType.getUnqualifiedType();
- }
- // Floating point conversions (C++ 4.8).
- else if (FromType->isFloatingType() && ToType->isFloatingType()) {
+ } else if (FromType->isFloatingType() && ToType->isFloatingType()) {
+ // Floating point conversions (C++ 4.8).
SCS.Second = ICK_Floating_Conversion;
FromType = ToType.getUnqualifiedType();
- }
- // Complex conversions (C99 6.3.1.6)
- else if (FromType->isComplexType() && ToType->isComplexType()) {
+ } else if (FromType->isComplexType() && ToType->isComplexType()) {
+ // Complex conversions (C99 6.3.1.6)
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())) {
+ } else if ((FromType->isFloatingType() &&
+ ToType->isIntegralType() && (!ToType->isBooleanType() &&
+ !ToType->isEnumeralType())) ||
+ ((FromType->isIntegralType() || FromType->isEnumeralType()) &&
+ ToType->isFloatingType())) {
+ // Floating-integral conversions (C++ 4.9).
+ // FIXME: isIntegralType shouldn't be true for enums in C++.
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())) {
+ } else if ((FromType->isComplexType() && ToType->isArithmeticType()) ||
+ (ToType->isComplexType() && FromType->isArithmeticType())) {
+ // Complex-real conversions (C99 6.3.1.7)
SCS.Second = ICK_Complex_Real;
FromType = ToType.getUnqualifiedType();
- }
- // Pointer conversions (C++ 4.10).
- else if (IsPointerConversion(From, FromType, ToType, FromType,
- IncompatibleObjC)) {
+ } else if (IsPointerConversion(From, FromType, ToType, InOverloadResolution,
+ FromType, IncompatibleObjC)) {
+ // Pointer conversions (C++ 4.10).
SCS.Second = ICK_Pointer_Conversion;
SCS.IncompatibleObjC = IncompatibleObjC;
- }
- // Pointer to member conversions (4.11).
- else if (IsMemberPointerConversion(From, FromType, ToType, FromType)) {
+ } else if (IsMemberPointerConversion(From, FromType, ToType,
+ InOverloadResolution, FromType)) {
+ // Pointer to member conversions (4.11).
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())) {
+ } else if (ToType->isBooleanType() &&
+ (FromType->isArithmeticType() ||
+ FromType->isEnumeralType() ||
+ FromType->isPointerType() ||
+ FromType->isBlockPointerType() ||
+ FromType->isMemberPointerType() ||
+ FromType->isNullPtrType())) {
+ // Boolean conversions (C++ 4.12).
SCS.Second = ICK_Boolean_Conversion;
FromType = Context.BoolTy;
- }
- // Compatible conversions (Clang extension for C function overloading)
- else if (!getLangOptions().CPlusPlus &&
- Context.typesAreCompatible(ToType, FromType)) {
+ } else if (!getLangOptions().CPlusPlus &&
+ Context.typesAreCompatible(ToType, FromType)) {
+ // Compatible conversions (Clang extension for C function overloading)
SCS.Second = ICK_Compatible_Conversion;
} else {
// No second conversion required.
@@ -674,12 +672,12 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
// No conversion required
SCS.Third = ICK_Identity;
- // C++ [over.best.ics]p6:
+ // 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);
+ CanonTo = Context.getCanonicalType(ToType);
if (CanonFrom.getUnqualifiedType() == CanonTo.getUnqualifiedType() &&
CanonFrom.getCVRQualifiers() != CanonTo.getCVRQualifiers()) {
FromType = ToType;
@@ -700,9 +698,8 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
/// 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();
+bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) {
+ const BuiltinType *To = ToType->getAs<BuiltinType>();
// All integers are built-in.
if (!To) {
return false;
@@ -718,7 +715,7 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType)
(FromType->isSignedIntegerType() ||
// We can promote any unsigned integer type whose size is
// less than int to an int.
- (!FromType->isSignedIntegerType() &&
+ (!FromType->isSignedIntegerType() &&
Context.getTypeSize(FromType) < Context.getTypeSize(ToType)))) {
return To->getKind() == BuiltinType::Int;
}
@@ -736,7 +733,7 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType)
// unsigned.
bool FromIsSigned;
uint64_t FromSize = Context.getTypeSize(FromType);
- if (const EnumType *FromEnumType = FromType->getAsEnumType()) {
+ if (const EnumType *FromEnumType = FromType->getAs<EnumType>()) {
QualType UnderlyingType = FromEnumType->getDecl()->getIntegerType();
FromIsSigned = UnderlyingType->isSignedIntegerType();
} else {
@@ -746,15 +743,15 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType)
// The types we'll try to promote to, in the appropriate
// order. Try each of these types.
- QualType PromoteTypes[6] = {
- Context.IntTy, Context.UnsignedIntTy,
+ 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 &&
+ (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
@@ -782,23 +779,23 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType)
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) {
@@ -811,12 +808,11 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType)
/// 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)
-{
+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 (const BuiltinType *FromBuiltin = FromType->getAs<BuiltinType>())
+ if (const BuiltinType *ToBuiltin = ToType->getAs<BuiltinType>()) {
if (FromBuiltin->getKind() == BuiltinType::Float &&
ToBuiltin->getKind() == BuiltinType::Double)
return true;
@@ -840,11 +836,11 @@ bool Sema::IsFloatingPointPromotion(QualType FromType, QualType ToType)
/// 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();
+ const ComplexType *FromComplex = FromType->getAs<ComplexType>();
if (!FromComplex)
return false;
- const ComplexType *ToComplex = ToType->getAsComplexType();
+ const ComplexType *ToComplex = ToType->getAs<ComplexType>();
if (!ToComplex)
return false;
@@ -859,18 +855,18 @@ bool Sema::IsComplexPromotion(QualType FromType, QualType ToType) {
/// 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,
+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) {
+ Qualifiers Quals = CanonFromPointee.getQualifiers();
+
+ // Exact qualifier match -> return the pointer type we're converting to.
+ if (CanonToPointee.getQualifiers() == Quals) {
// ToType is exactly what we need. Return it.
- if (ToType.getTypePtr())
+ if (!ToType.isNull())
return ToType;
// Build a pointer to ToPointee. It has the right qualifiers
@@ -879,7 +875,22 @@ BuildSimilarlyQualifiedPointerType(const PointerType *FromPtr,
}
// Just build a canonical type that has the right qualifiers.
- return Context.getPointerType(CanonToPointee.getQualifiedType(Quals));
+ return Context.getPointerType(
+ Context.getQualifiedType(CanonToPointee.getUnqualifiedType(), Quals));
+}
+
+static bool isNullPointerConstantForConversion(Expr *Expr,
+ bool InOverloadResolution,
+ ASTContext &Context) {
+ // Handle value-dependent integral null pointer constants correctly.
+ // http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#903
+ if (Expr->isValueDependent() && !Expr->isTypeDependent() &&
+ Expr->getType()->isIntegralType())
+ return !InOverloadResolution;
+
+ return Expr->isNullPointerConstant(Context,
+ InOverloadResolution? Expr::NPC_ValueDependentIsNotNull
+ : Expr::NPC_ValueDependentIsNull);
}
/// IsPointerConversion - Determines whether the conversion of the
@@ -899,52 +910,54 @@ BuildSimilarlyQualifiedPointerType(const PointerType *FromPtr,
/// 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,
+ bool InOverloadResolution,
QualType& ConvertedType,
- bool &IncompatibleObjC)
-{
+ 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)) {
+ // Conversion from a null pointer constant to any Objective-C pointer type.
+ if (ToType->isObjCObjectPointerType() &&
+ isNullPointerConstantForConversion(From, InOverloadResolution, Context)) {
ConvertedType = ToType;
return true;
}
// Blocks: Block pointers can be converted to void*.
if (FromType->isBlockPointerType() && ToType->isPointerType() &&
- ToType->getAsPointerType()->getPointeeType()->isVoidType()) {
+ ToType->getAs<PointerType>()->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)) {
+ if (ToType->isBlockPointerType() &&
+ isNullPointerConstantForConversion(From, InOverloadResolution, 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)) {
+ if (ToType->isNullPtrType() &&
+ isNullPointerConstantForConversion(From, InOverloadResolution, Context)) {
ConvertedType = ToType;
return true;
}
- const PointerType* ToTypePtr = ToType->getAsPointerType();
+ const PointerType* ToTypePtr = ToType->getAs<PointerType>();
if (!ToTypePtr)
return false;
// A null pointer constant can be converted to a pointer type (C++ 4.10p1).
- if (From->isNullPointerConstant(Context)) {
+ if (isNullPointerConstantForConversion(From, InOverloadResolution, Context)) {
ConvertedType = ToType;
return true;
}
// Beyond this point, both types need to be pointers.
- const PointerType *FromTypePtr = FromType->getAsPointerType();
+ const PointerType *FromTypePtr = FromType->getAs<PointerType>();
if (!FromTypePtr)
return false;
@@ -955,7 +968,7 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
// can be converted to an rvalue of type "pointer to cv void" (C++
// 4.10p2).
if (FromPointeeType->isObjectType() && ToPointeeType->isVoidType()) {
- ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
+ ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
ToPointeeType,
ToType, Context);
return true;
@@ -963,16 +976,16 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
// When we're overloading in C, we allow a special kind of pointer
// conversion for compatible-but-not-identical pointee types.
- if (!getLangOptions().CPlusPlus &&
+ if (!getLangOptions().CPlusPlus &&
Context.typesAreCompatible(FromPointeeType, ToPointeeType)) {
- ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
+ ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
ToPointeeType,
- ToType, Context);
+ 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
@@ -987,7 +1000,7 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
if (getLangOptions().CPlusPlus &&
FromPointeeType->isRecordType() && ToPointeeType->isRecordType() &&
IsDerivedFrom(FromPointeeType, ToPointeeType)) {
- ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
+ ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
ToPointeeType,
ToType, Context);
return true;
@@ -999,83 +1012,65 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
/// 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,
+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;
- }
+ // First, we handle all conversions on ObjC object pointer types.
+ const ObjCObjectPointerType* ToObjCPtr = ToType->getAs<ObjCObjectPointerType>();
+ const ObjCObjectPointerType *FromObjCPtr =
+ FromType->getAs<ObjCObjectPointerType>();
+
+ if (ToObjCPtr && FromObjCPtr) {
+ // Objective C++: We're able to convert between "id" or "Class" and a
+ // pointer to any interface (in both directions).
+ if (ToObjCPtr->isObjCBuiltinType() && FromObjCPtr->isObjCBuiltinType()) {
+ ConvertedType = ToType;
+ return true;
+ }
+ // Conversions with Objective-C's id<...>.
+ if ((FromObjCPtr->isObjCQualifiedIdType() ||
+ ToObjCPtr->isObjCQualifiedIdType()) &&
+ Context.ObjCQualifiedIdTypesAreCompatible(ToType, FromType,
+ /*compare=*/false)) {
+ ConvertedType = ToType;
+ return true;
+ }
+ // Objective C++: We're able to convert from a pointer to an
+ // interface to a pointer to a different interface.
+ if (Context.canAssignObjCInterfaces(ToObjCPtr, FromObjCPtr)) {
+ ConvertedType = ToType;
+ return true;
+ }
- // Beyond this point, both types need to be pointers or block pointers.
+ if (Context.canAssignObjCInterfaces(FromObjCPtr, ToObjCPtr)) {
+ // 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 = FromType;
+ return true;
+ }
+ }
+ // Beyond this point, both types need to be C pointers or block pointers.
QualType ToPointeeType;
- const PointerType* ToTypePtr = ToType->getAsPointerType();
- if (ToTypePtr)
- ToPointeeType = ToTypePtr->getPointeeType();
- else if (const BlockPointerType *ToBlockPtr = ToType->getAsBlockPointerType())
+ if (const PointerType *ToCPtr = ToType->getAs<PointerType>())
+ ToPointeeType = ToCPtr->getPointeeType();
+ else if (const BlockPointerType *ToBlockPtr = ToType->getAs<BlockPointerType>())
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())
+ if (const PointerType *FromCPtr = FromType->getAs<PointerType>())
+ FromPointeeType = FromCPtr->getPointeeType();
+ else if (const BlockPointerType *FromBlockPtr = FromType->getAs<BlockPointerType>())
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() &&
@@ -1086,15 +1081,14 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
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 *FromFunctionType
+ = FromPointeeType->getAs<FunctionProtoType>();
const FunctionProtoType *ToFunctionType
- = ToPointeeType->getAsFunctionProtoType();
+ = ToPointeeType->getAs<FunctionProtoType>();
if (FromFunctionType && ToFunctionType) {
// If the function types are exactly the same, this isn't an
// Objective-C pointer conversion.
@@ -1122,7 +1116,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
// Function types are too different. Abort.
return false;
}
-
+
// Check argument types.
for (unsigned ArgIdx = 0, NumArgs = FromFunctionType->getNumArgs();
ArgIdx != NumArgs; ++ArgIdx) {
@@ -1155,37 +1149,43 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
/// 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
+/// ambiguous 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) {
+bool Sema::CheckPointerConversion(Expr *From, QualType ToType,
+ CastExpr::CastKind &Kind) {
QualType FromType = From->getType();
- if (const PointerType *FromPtrType = FromType->getAsPointerType())
- if (const PointerType *ToPtrType = ToType->getAsPointerType()) {
+ if (const PointerType *FromPtrType = FromType->getAs<PointerType>())
+ if (const PointerType *ToPtrType = ToType->getAs<PointerType>()) {
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());
+ if (CheckDerivedToBaseConversion(FromPointeeType, ToPointeeType,
+ From->getExprLoc(),
+ From->getSourceRange()))
+ return true;
+
+ // The conversion was successful.
+ Kind = CastExpr::CK_DerivedToBase;
}
}
+ if (const ObjCObjectPointerType *FromPtrType =
+ FromType->getAs<ObjCObjectPointerType>())
+ if (const ObjCObjectPointerType *ToPtrType =
+ ToType->getAs<ObjCObjectPointerType>()) {
+ // Objective-C++ conversions are always okay.
+ // FIXME: We should have a different class of conversions for the
+ // Objective-C++ implicit conversions.
+ if (FromPtrType->isObjCBuiltinType() || ToPtrType->isObjCBuiltinType())
+ return false;
+ }
return false;
}
@@ -1195,20 +1195,23 @@ bool Sema::CheckPointerConversion(Expr *From, QualType ToType) {
/// 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();
+ QualType ToType,
+ bool InOverloadResolution,
+ QualType &ConvertedType) {
+ const MemberPointerType *ToTypePtr = ToType->getAs<MemberPointerType>();
if (!ToTypePtr)
return false;
// A null pointer constant can be converted to a member pointer (C++ 4.11p1)
- if (From->isNullPointerConstant(Context)) {
+ if (From->isNullPointerConstant(Context,
+ InOverloadResolution? Expr::NPC_ValueDependentIsNotNull
+ : Expr::NPC_ValueDependentIsNull)) {
ConvertedType = ToType;
return true;
}
// Otherwise, both types have to be member pointers.
- const MemberPointerType *FromTypePtr = FromType->getAsMemberPointerType();
+ const MemberPointerType *FromTypePtr = FromType->getAs<MemberPointerType>();
if (!FromTypePtr)
return false;
@@ -1233,13 +1236,20 @@ bool Sema::IsMemberPointerConversion(Expr *From, QualType FromType,
/// 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) {
+bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType,
+ CastExpr::CastKind &Kind) {
QualType FromType = From->getType();
- const MemberPointerType *FromPtrType = FromType->getAsMemberPointerType();
- if (!FromPtrType)
+ const MemberPointerType *FromPtrType = FromType->getAs<MemberPointerType>();
+ if (!FromPtrType) {
+ // This must be a null pointer to member pointer conversion
+ assert(From->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNull) &&
+ "Expr must be null pointer constant!");
+ Kind = CastExpr::CK_NullToMemberPointer;
return false;
+ }
- const MemberPointerType *ToPtrType = ToType->getAsMemberPointerType();
+ const MemberPointerType *ToPtrType = ToType->getAs<MemberPointerType>();
assert(ToPtrType && "No member pointer cast has a target type "
"that is not a member pointer.");
@@ -1250,8 +1260,8 @@ bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType) {
assert(FromClass->isRecordType() && "Pointer into non-class.");
assert(ToClass->isRecordType() && "Pointer into non-class.");
- BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false,
- /*DetectVirtual=*/true);
+ CXXBasePaths 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.");
@@ -1279,15 +1289,16 @@ bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType) {
return true;
}
+ // Must be a base to derived member conversion.
+ Kind = CastExpr::CK_BaseToDerivedMemberPointer;
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)
-{
+bool
+Sema::IsQualificationConversion(QualType FromType, QualType ToType) {
FromType = Context.getCanonicalType(FromType);
ToType = Context.getCanonicalType(ToType);
@@ -1314,16 +1325,16 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType)
// 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
= PreviousToQualsIncludeConst && ToType.isConstQualified();
}
@@ -1336,6 +1347,18 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType)
FromType.getUnqualifiedType() == ToType.getUnqualifiedType();
}
+/// \brief Given a function template or function, extract the function template
+/// declaration (if any) and the underlying function declaration.
+template<typename T>
+static void GetFunctionAndTemplate(AnyFunctionDecl Orig, T *&Function,
+ FunctionTemplateDecl *&FunctionTemplate) {
+ FunctionTemplate = dyn_cast<FunctionTemplateDecl>(Orig);
+ if (FunctionTemplate)
+ Function = cast<T>(FunctionTemplate->getTemplatedDecl());
+ else
+ Function = cast<T>(Orig);
+}
+
/// 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
@@ -1353,14 +1376,17 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType)
///
/// \param ForceRValue true if the expression should be treated as an rvalue
/// for overload resolution.
-bool Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
+/// \param UserCast true if looking for user defined conversion for a static
+/// cast.
+Sema::OverloadingResult Sema::IsUserDefinedConversion(
+ Expr *From, QualType ToType,
UserDefinedConversionSequence& User,
+ OverloadCandidateSet& CandidateSet,
bool AllowConversionFunctions,
- bool AllowExplicit, bool ForceRValue)
-{
- OverloadCandidateSet CandidateSet;
- if (const RecordType *ToRecordType = ToType->getAsRecordType()) {
- if (CXXRecordDecl *ToRecordDecl
+ bool AllowExplicit, bool ForceRValue,
+ bool UserCast) {
+ if (const RecordType *ToRecordType = ToType->getAs<RecordType>()) {
+ if (CXXRecordDecl *ToRecordDecl
= dyn_cast<CXXRecordDecl>(ToRecordType->getDecl())) {
// C++ [over.match.ctor]p1:
// When objects of class type are direct-initialized (8.5), or
@@ -1370,37 +1396,72 @@ bool Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
// 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
+ DeclarationName ConstructorName
= Context.DeclarationNames.getCXXConstructorName(
Context.getCanonicalType(ToType).getUnqualifiedType());
DeclContext::lookup_iterator Con, ConEnd;
- for (llvm::tie(Con, ConEnd)
+ for (llvm::tie(Con, ConEnd)
= ToRecordDecl->lookup(ConstructorName);
Con != ConEnd; ++Con) {
- CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con);
- if (Constructor->isConvertingConstructor())
- AddOverloadCandidate(Constructor, &From, 1, CandidateSet,
- /*SuppressUserConversions=*/true, ForceRValue);
+ // Find the constructor (which may be a template).
+ CXXConstructorDecl *Constructor = 0;
+ FunctionTemplateDecl *ConstructorTmpl
+ = dyn_cast<FunctionTemplateDecl>(*Con);
+ if (ConstructorTmpl)
+ Constructor
+ = cast<CXXConstructorDecl>(ConstructorTmpl->getTemplatedDecl());
+ else
+ Constructor = cast<CXXConstructorDecl>(*Con);
+
+ if (!Constructor->isInvalidDecl() &&
+ Constructor->isConvertingConstructor(AllowExplicit)) {
+ if (ConstructorTmpl)
+ AddTemplateOverloadCandidate(ConstructorTmpl, false, 0, 0, &From,
+ 1, CandidateSet,
+ /*SuppressUserConversions=*/!UserCast,
+ ForceRValue);
+ else
+ // Allow one user-defined conversion when user specifies a
+ // From->ToType conversion via an static cast (c-style, etc).
+ AddOverloadCandidate(Constructor, &From, 1, CandidateSet,
+ /*SuppressUserConversions=*/!UserCast,
+ 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())) {
+ } else if (RequireCompleteType(From->getLocStart(), From->getType(),
+ PDiag(0)
+ << From->getSourceRange())) {
+ // No conversion functions from incomplete types.
+ } else if (const RecordType *FromRecordType
+ = From->getType()->getAs<RecordType>()) {
+ 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
+ OverloadedFunctionDecl *Conversions
+ = FromRecordDecl->getVisibleConversionFunctions();
+ 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);
+ CXXConversionDecl *Conv;
+ FunctionTemplateDecl *ConvTemplate;
+ GetFunctionAndTemplate(*Func, Conv, ConvTemplate);
+ if (ConvTemplate)
+ Conv = dyn_cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
+ else
+ Conv = dyn_cast<CXXConversionDecl>(*Func);
+
+ if (AllowExplicit || !Conv->isExplicit()) {
+ if (ConvTemplate)
+ AddTemplateConversionCandidate(ConvTemplate, From, ToType,
+ CandidateSet);
+ else
+ AddConversionCandidate(Conv, From, ToType, CandidateSet);
+ }
}
}
}
@@ -1409,7 +1470,7 @@ bool Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
switch (BestViableFunction(CandidateSet, From->getLocStart(), Best)) {
case OR_Success:
// Record the standard conversion we used and the conversion function.
- if (CXXConstructorDecl *Constructor
+ if (CXXConstructorDecl *Constructor
= dyn_cast<CXXConstructorDecl>(Best->Function)) {
// C++ [over.ics.user]p1:
// If the user-defined conversion is specified by a
@@ -1422,10 +1483,10 @@ bool Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
User.Before = Best->Conversions[0].Standard;
User.ConversionFunction = Constructor;
User.After.setAsIdentityConversion();
- User.After.FromTypePtr
- = ThisType->getAsPointerType()->getPointeeType().getAsOpaquePtr();
+ User.After.FromTypePtr
+ = ThisType->getAs<PointerType>()->getPointeeType().getAsOpaquePtr();
User.After.ToTypePtr = ToType.getAsOpaquePtr();
- return true;
+ return OR_Success;
} else if (CXXConversionDecl *Conversion
= dyn_cast<CXXConversionDecl>(Best->Function)) {
// C++ [over.ics.user]p1:
@@ -1436,8 +1497,8 @@ bool Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
// implicit object parameter of the conversion function.
User.Before = Best->Conversions[0].Standard;
User.ConversionFunction = Conversion;
-
- // C++ [over.ics.user]p2:
+
+ // 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
@@ -1447,30 +1508,45 @@ bool Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
// user-defined conversion sequence (see 13.3.3 and
// 13.3.3.1).
User.After = Best->FinalConversion;
- return true;
+ return OR_Success;
} else {
assert(false && "Not a constructor or conversion function?");
- return false;
+ return OR_No_Viable_Function;
}
-
+
case OR_No_Viable_Function:
+ return OR_No_Viable_Function;
case OR_Deleted:
// No conversion here! We're done.
- return false;
+ return OR_Deleted;
case OR_Ambiguous:
- // FIXME: See C++ [over.best.ics]p10 for the handling of
- // ambiguous conversion sequences.
- return false;
+ return OR_Ambiguous;
}
- return false;
+ return OR_No_Viable_Function;
+}
+
+bool
+Sema::DiagnoseAmbiguousUserDefinedConversion(Expr *From, QualType ToType) {
+ ImplicitConversionSequence ICS;
+ OverloadCandidateSet CandidateSet;
+ OverloadingResult OvResult =
+ IsUserDefinedConversion(From, ToType, ICS.UserDefined,
+ CandidateSet, true, false, false);
+ if (OvResult != OR_Ambiguous)
+ return false;
+ Diag(From->getSourceRange().getBegin(),
+ diag::err_typecheck_ambiguous_condition)
+ << From->getType() << ToType << From->getSourceRange();
+ PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
+ return true;
}
/// 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
+ImplicitConversionSequence::CompareKind
Sema::CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1,
const ImplicitConversionSequence& ICS2)
{
@@ -1482,7 +1558,7 @@ Sema::CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1,
// -- 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)
@@ -1493,7 +1569,7 @@ Sema::CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1,
// following rules apply: (C++ 13.3.3.2p3):
if (ICS1.ConversionKind == ImplicitConversionSequence::StandardConversion)
return CompareStandardConversionSequences(ICS1.Standard, ICS2.Standard);
- else if (ICS1.ConversionKind ==
+ else if (ICS1.ConversionKind ==
ImplicitConversionSequence::UserDefinedConversion) {
// User-defined conversion sequence U1 is a better conversion
// sequence than another user-defined conversion sequence U2 if
@@ -1501,7 +1577,7 @@ Sema::CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1,
// 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 ==
+ if (ICS1.UserDefined.ConversionFunction ==
ICS2.UserDefined.ConversionFunction)
return CompareStandardConversionSequences(ICS1.UserDefined.After,
ICS2.UserDefined.After);
@@ -1513,7 +1589,7 @@ Sema::CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1,
/// 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
+ImplicitConversionSequence::CompareKind
Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1,
const StandardConversionSequence& SCS2)
{
@@ -1530,13 +1606,13 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1,
;
else if ((SCS1.Second == ICK_Identity && SCS1.Third == SCS2.Third) ||
(SCS1.Third == ICK_Identity && SCS1.Second == SCS2.Second) ||
- (SCS1.Second == ICK_Identity &&
+ (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.Second == ICK_Identity &&
SCS2.Third == ICK_Identity))
// SCS2 is a proper subsequence of SCS1.
return ImplicitConversionSequence::Worse;
@@ -1553,7 +1629,7 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1,
// (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.
@@ -1568,9 +1644,9 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1,
// 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
+ bool SCS1ConvertsToVoid
= SCS1.isPointerConversionToVoidPointer(Context);
- bool SCS2ConvertsToVoid
+ bool SCS2ConvertsToVoid
= SCS2.isPointerConversionToVoidPointer(Context);
if (SCS1ConvertsToVoid != SCS2ConvertsToVoid) {
// Exactly one of the conversion sequences is a conversion to
@@ -1597,10 +1673,10 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1,
if (SCS2.First == ICK_Array_To_Pointer)
FromType2 = Context.getArrayDecayedType(FromType2);
- QualType FromPointee1
- = FromType1->getAsPointerType()->getPointeeType().getUnqualifiedType();
+ QualType FromPointee1
+ = FromType1->getAs<PointerType>()->getPointeeType().getUnqualifiedType();
QualType FromPointee2
- = FromType2->getAsPointerType()->getPointeeType().getUnqualifiedType();
+ = FromType2->getAs<PointerType>()->getPointeeType().getUnqualifiedType();
if (IsDerivedFrom(FromPointee2, FromPointee1))
return ImplicitConversionSequence::Better;
@@ -1609,8 +1685,8 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1,
// 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();
+ const ObjCInterfaceType* FromIface1 = FromPointee1->getAs<ObjCInterfaceType>();
+ const ObjCInterfaceType* FromIface2 = FromPointee2->getAs<ObjCInterfaceType>();
if (FromIface1 && FromIface1) {
if (Context.canAssignObjCInterfaces(FromIface2, FromIface1))
return ImplicitConversionSequence::Better;
@@ -1621,7 +1697,7 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1,
// Compare based on qualification conversions (C++ 13.3.3.2p3,
// bullet 3).
- if (ImplicitConversionSequence::CompareKind QualCK
+ if (ImplicitConversionSequence::CompareKind QualCK
= CompareQualificationConversions(SCS1, SCS2))
return QualCK;
@@ -1661,11 +1737,10 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1,
/// 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
+/// qualification conversions (C++ 13.3.3.2p3 bullet 3).
+ImplicitConversionSequence::CompareKind
Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1,
- const StandardConversionSequence& SCS2)
-{
+ 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
@@ -1688,7 +1763,7 @@ Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1,
if (T1.getUnqualifiedType() == T2.getUnqualifiedType())
return ImplicitConversionSequence::Indistinguishable;
- ImplicitConversionSequence::CompareKind Result
+ ImplicitConversionSequence::CompareKind Result
= ImplicitConversionSequence::Indistinguishable;
while (UnwrapSimilarPointerTypes(T1, T2)) {
// Within each iteration of the loop, we check the qualifiers to
@@ -1709,7 +1784,7 @@ Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1,
// 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.
@@ -1717,7 +1792,7 @@ Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1,
// Neither has qualifiers that are a subset of the other's
// qualifiers.
return ImplicitConversionSequence::Indistinguishable;
-
+
Result = ImplicitConversionSequence::Worse;
} else {
// Qualifiers are disjoint.
@@ -1784,24 +1859,24 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
// interfaces.
// Compare based on pointer conversions.
- if (SCS1.Second == ICK_Pointer_Conversion &&
+ 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 FromPointee1
+ = FromType1->getAs<PointerType>()->getPointeeType().getUnqualifiedType();
+ QualType ToPointee1
+ = ToType1->getAs<PointerType>()->getPointeeType().getUnqualifiedType();
QualType FromPointee2
- = FromType2->getAsPointerType()->getPointeeType().getUnqualifiedType();
+ = FromType2->getAs<PointerType>()->getPointeeType().getUnqualifiedType();
QualType ToPointee2
- = ToType2->getAsPointerType()->getPointeeType().getUnqualifiedType();
+ = ToType2->getAs<PointerType>()->getPointeeType().getUnqualifiedType();
- const ObjCInterfaceType* FromIface1 = FromPointee1->getAsObjCInterfaceType();
- const ObjCInterfaceType* FromIface2 = FromPointee2->getAsObjCInterfaceType();
- const ObjCInterfaceType* ToIface1 = ToPointee1->getAsObjCInterfaceType();
- const ObjCInterfaceType* ToIface2 = ToPointee2->getAsObjCInterfaceType();
+ const ObjCInterfaceType* FromIface1 = FromPointee1->getAs<ObjCInterfaceType>();
+ const ObjCInterfaceType* FromIface2 = FromPointee2->getAs<ObjCInterfaceType>();
+ const ObjCInterfaceType* ToIface1 = ToPointee1->getAs<ObjCInterfaceType>();
+ const ObjCInterfaceType* ToIface2 = ToPointee2->getAs<ObjCInterfaceType>();
// -- conversion of C* to B* is better than conversion of C* to A*,
if (FromPointee1 == FromPointee2 && ToPointee1 != ToPointee2) {
@@ -1824,7 +1899,7 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
return ImplicitConversionSequence::Better;
else if (IsDerivedFrom(FromPointee1, FromPointee2))
return ImplicitConversionSequence::Worse;
-
+
if (FromIface1 && FromIface2) {
if (Context.canAssignObjCInterfaces(FromIface1, FromIface2))
return ImplicitConversionSequence::Better;
@@ -1898,17 +1973,25 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
/// 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) {
+ImplicitConversionSequence
+Sema::TryCopyInitialization(Expr *From, QualType ToType,
+ bool SuppressUserConversions, bool ForceRValue,
+ bool InOverloadResolution) {
if (ToType->isReferenceType()) {
ImplicitConversionSequence ICS;
- CheckReferenceInit(From, ToType, &ICS, SuppressUserConversions,
- /*AllowExplicit=*/false, ForceRValue);
+ CheckReferenceInit(From, ToType,
+ /*FIXME:*/From->getLocStart(),
+ SuppressUserConversions,
+ /*AllowExplicit=*/false,
+ ForceRValue,
+ &ICS);
return ICS;
} else {
- return TryImplicitConversion(From, ToType, SuppressUserConversions,
- ForceRValue);
+ return TryImplicitConversion(From, ToType,
+ SuppressUserConversions,
+ /*AllowExplicit=*/false,
+ ForceRValue,
+ InOverloadResolution);
}
}
@@ -1917,32 +2000,37 @@ Sema::TryCopyInitialization(Expr *From, QualType ToType,
/// 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,
+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);
+ return CheckReferenceInit(From, ToType,
+ /*FIXME:*/From->getLocStart(),
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false,
+ /*ForceRValue=*/false);
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();
+ if (!DiagnoseAmbiguousUserDefinedConversion(From, ToType))
+ return Diag(From->getSourceRange().getBegin(),
+ diag::err_typecheck_convert_incompatible)
+ << ToType << From->getType() << Flavor << From->getSourceRange();
+ return true;
}
/// TryObjectArgumentInitialization - Try to initialize the object
@@ -1951,8 +2039,8 @@ bool Sema::PerformCopyInitialization(Expr *&From, QualType ToType,
ImplicitConversionSequence
Sema::TryObjectArgumentInitialization(Expr *From, CXXMethodDecl *Method) {
QualType ClassType = Context.getTypeDeclType(Method->getParent());
- unsigned MethodQuals = Method->getTypeQualifiers();
- QualType ImplicitParamType = ClassType.getQualifiedType(MethodQuals);
+ QualType ImplicitParamType
+ = Context.getCVRQualifiedType(ClassType, Method->getTypeQualifiers());
// Set up the conversion sequence as a "bad" conversion, to allow us
// to exit early.
@@ -1962,7 +2050,7 @@ Sema::TryObjectArgumentInitialization(Expr *From, CXXMethodDecl *Method) {
// We need to have an object of class type.
QualType FromType = From->getType();
- if (const PointerType *PT = FromType->getAsPointerType())
+ if (const PointerType *PT = FromType->getAs<PointerType>())
FromType = PT->getPointeeType();
assert(FromType->isRecordType());
@@ -1971,7 +2059,7 @@ Sema::TryObjectArgumentInitialization(Expr *From, CXXMethodDecl *Method) {
// 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
+ // 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.
@@ -2009,10 +2097,10 @@ Sema::TryObjectArgumentInitialization(Expr *From, CXXMethodDecl *Method) {
bool
Sema::PerformObjectArgumentInitialization(Expr *&From, CXXMethodDecl *Method) {
QualType FromRecordType, DestType;
- QualType ImplicitParamRecordType =
- Method->getThisType(Context)->getAsPointerType()->getPointeeType();
-
- if (const PointerType *PT = From->getType()->getAsPointerType()) {
+ QualType ImplicitParamRecordType =
+ Method->getThisType(Context)->getAs<PointerType>()->getPointeeType();
+
+ if (const PointerType *PT = From->getType()->getAs<PointerType>()) {
FromRecordType = PT->getPointeeType();
DestType = Method->getThisType(Context);
} else {
@@ -2020,13 +2108,13 @@ Sema::PerformObjectArgumentInitialization(Expr *&From, CXXMethodDecl *Method) {
DestType = ImplicitParamRecordType;
}
- ImplicitConversionSequence ICS
+ 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,
@@ -2034,14 +2122,20 @@ Sema::PerformObjectArgumentInitialization(Expr *&From, CXXMethodDecl *Method) {
From->getSourceRange()))
return true;
- ImpCastExprToType(From, DestType, /*isLvalue=*/true);
+ ImpCastExprToType(From, DestType, CastExpr::CK_DerivedToBase,
+ /*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);
+ return TryImplicitConversion(From, Context.BoolTy,
+ // FIXME: Are these flags correct?
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/true,
+ /*ForceRValue=*/false,
+ /*InOverloadResolution=*/false);
}
/// PerformContextuallyConvertToBool - Perform a contextual conversion
@@ -2050,10 +2144,12 @@ 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();
+
+ if (!DiagnoseAmbiguousUserDefinedConversion(From, Context.BoolTy))
+ return Diag(From->getSourceRange().getBegin(),
+ diag::err_typecheck_bool_condition)
+ << From->getType() << From->getSourceRange();
+ return true;
}
/// AddOverloadCandidate - Adds the given function to the set of
@@ -2063,21 +2159,25 @@ bool Sema::PerformContextuallyConvertToBool(Expr *&From) {
/// 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,
+///
+/// \para PartialOverloading true if we are performing "partial" overloading
+/// based on an incomplete set of function arguments. This feature is used by
+/// code completion.
+void
+Sema::AddOverloadCandidate(FunctionDecl *Function,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions,
- bool ForceRValue)
-{
- const FunctionProtoType* Proto
- = dyn_cast<FunctionProtoType>(Function->getType()->getAsFunctionType());
+ bool ForceRValue,
+ bool PartialOverloading) {
+ const FunctionProtoType* Proto
+ = dyn_cast<FunctionProtoType>(Function->getType()->getAs<FunctionType>());
assert(Proto && "Functions without a prototype cannot be overloaded");
- assert(!isa<CXXConversionDecl>(Function) &&
+ assert(!isa<CXXConversionDecl>(Function) &&
"Use AddConversionCandidate for conversion functions");
- assert(!Function->getDescribedFunctionTemplate() &&
+ assert(!Function->getDescribedFunctionTemplate() &&
"Use AddTemplateOverloadCandidate for function templates");
-
+
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Function)) {
if (!isa<CXXConstructorDecl>(Method)) {
// If we get here, it's because we're calling a member function
@@ -2086,7 +2186,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
// 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,
+ AddMethodCandidate(Method, 0, Args, NumArgs, CandidateSet,
SuppressUserConversions, ForceRValue);
return;
}
@@ -2094,7 +2194,9 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
// argument doesn't participate in overload resolution.
}
-
+ if (!CandidateSet.isNewCandidate(Function))
+ return;
+
// Add this candidate
CandidateSet.push_back(OverloadCandidate());
OverloadCandidate& Candidate = CandidateSet.back();
@@ -2108,7 +2210,8 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
// (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()) {
+ if ((NumArgs + (PartialOverloading && NumArgs)) > NumArgsInProto &&
+ !Proto->isVariadic()) {
Candidate.Viable = false;
return;
}
@@ -2119,7 +2222,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
// parameter list is truncated on the right, so that there are
// exactly m parameters.
unsigned MinRequiredArgs = Function->getMinRequiredArguments();
- if (NumArgs < MinRequiredArgs) {
+ if (NumArgs < MinRequiredArgs && !PartialOverloading) {
// Not enough arguments.
Candidate.Viable = false;
return;
@@ -2135,19 +2238,38 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
// (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
+ Candidate.Conversions[ArgIdx]
+ = TryCopyInitialization(Args[ArgIdx], ParamType,
+ SuppressUserConversions, ForceRValue,
+ /*InOverloadResolution=*/true);
+ if (Candidate.Conversions[ArgIdx].ConversionKind
== ImplicitConversionSequence::BadConversion) {
- Candidate.Viable = false;
- break;
+ // 13.3.3.1-p10 If several different sequences of conversions exist that
+ // each convert the argument to the parameter type, the implicit conversion
+ // sequence associated with the parameter is defined to be the unique conversion
+ // sequence designated the ambiguous conversion sequence. For the purpose of
+ // ranking implicit conversion sequences as described in 13.3.3.2, the ambiguous
+ // conversion sequence is treated as a user-defined sequence that is
+ // indistinguishable from any other user-defined conversion sequence
+ if (!Candidate.Conversions[ArgIdx].ConversionFunctionSet.empty()) {
+ Candidate.Conversions[ArgIdx].ConversionKind =
+ ImplicitConversionSequence::UserDefinedConversion;
+ // Set the conversion function to one of them. As due to ambiguity,
+ // they carry the same weight and is needed for overload resolution
+ // later.
+ Candidate.Conversions[ArgIdx].UserDefined.ConversionFunction =
+ Candidate.Conversions[ArgIdx].ConversionFunctionSet[0];
+ }
+ else {
+ 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
+ Candidate.Conversions[ArgIdx].ConversionKind
= ImplicitConversionSequence::EllipsisConversion;
}
}
@@ -2159,17 +2281,32 @@ void Sema::AddFunctionCandidates(const FunctionSet &Functions,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions) {
- for (FunctionSet::const_iterator F = Functions.begin(),
+ for (FunctionSet::const_iterator F = Functions.begin(),
FEnd = Functions.end();
F != FEnd; ++F) {
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*F))
- AddOverloadCandidate(FD, Args, NumArgs, CandidateSet,
- SuppressUserConversions);
- else
- AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*F),
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*F)) {
+ if (isa<CXXMethodDecl>(FD) && !cast<CXXMethodDecl>(FD)->isStatic())
+ AddMethodCandidate(cast<CXXMethodDecl>(FD),
+ Args[0], Args + 1, NumArgs - 1,
+ CandidateSet, SuppressUserConversions);
+ else
+ AddOverloadCandidate(FD, Args, NumArgs, CandidateSet,
+ SuppressUserConversions);
+ } else {
+ FunctionTemplateDecl *FunTmpl = cast<FunctionTemplateDecl>(*F);
+ if (isa<CXXMethodDecl>(FunTmpl->getTemplatedDecl()) &&
+ !cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl())->isStatic())
+ AddMethodTemplateCandidate(FunTmpl,
/*FIXME: explicit args */false, 0, 0,
- Args, NumArgs, CandidateSet,
+ Args[0], Args + 1, NumArgs - 1,
+ CandidateSet,
SuppressUserConversions);
+ else
+ AddTemplateOverloadCandidate(FunTmpl,
+ /*FIXME: explicit args */false, 0, 0,
+ Args, NumArgs, CandidateSet,
+ SuppressUserConversions);
+ }
}
}
@@ -2182,20 +2319,22 @@ void Sema::AddFunctionCandidates(const FunctionSet &Functions,
/// 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
+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());
+ bool SuppressUserConversions, bool ForceRValue) {
+ const FunctionProtoType* Proto
+ = dyn_cast<FunctionProtoType>(Method->getType()->getAs<FunctionType>());
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");
+ if (!CandidateSet.isNewCandidate(Method))
+ return;
+
// Add this candidate
CandidateSet.push_back(OverloadCandidate());
OverloadCandidate& Candidate = CandidateSet.back();
@@ -2235,7 +2374,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, Expr *Object,
// Determine the implicit conversion sequence for the object
// parameter.
Candidate.Conversions[0] = TryObjectArgumentInitialization(Object, Method);
- if (Candidate.Conversions[0].ConversionKind
+ if (Candidate.Conversions[0].ConversionKind
== ImplicitConversionSequence::BadConversion) {
Candidate.Viable = false;
return;
@@ -2251,10 +2390,11 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, Expr *Object,
// (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
+ Candidate.Conversions[ArgIdx + 1]
+ = TryCopyInitialization(Args[ArgIdx], ParamType,
+ SuppressUserConversions, ForceRValue,
+ /*InOverloadResolution=*/true);
+ if (Candidate.Conversions[ArgIdx + 1].ConversionKind
== ImplicitConversionSequence::BadConversion) {
Candidate.Viable = false;
break;
@@ -2263,16 +2403,61 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, Expr *Object,
// (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
+ Candidate.Conversions[ArgIdx + 1].ConversionKind
= ImplicitConversionSequence::EllipsisConversion;
}
}
}
-/// \brief Add a C++ function template as a candidate in the candidate set,
-/// using template argument deduction to produce an appropriate function
-/// template specialization.
-void
+/// \brief Add a C++ member function template as a candidate to the candidate
+/// set, using template argument deduction to produce an appropriate member
+/// function template specialization.
+void
+Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
+ bool HasExplicitTemplateArgs,
+ const TemplateArgument *ExplicitTemplateArgs,
+ unsigned NumExplicitTemplateArgs,
+ Expr *Object, Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet& CandidateSet,
+ bool SuppressUserConversions,
+ bool ForceRValue) {
+ if (!CandidateSet.isNewCandidate(MethodTmpl))
+ return;
+
+ // C++ [over.match.funcs]p7:
+ // In each case where a candidate is a function template, candidate
+ // function template specializations are generated using template argument
+ // deduction (14.8.3, 14.8.2). Those candidates are then handled as
+ // candidate functions in the usual way.113) A given name can refer to one
+ // or more function templates and also to a set of overloaded non-template
+ // functions. In such a case, the candidate functions generated from each
+ // function template are combined with the set of non-template candidate
+ // functions.
+ TemplateDeductionInfo Info(Context);
+ FunctionDecl *Specialization = 0;
+ if (TemplateDeductionResult Result
+ = DeduceTemplateArguments(MethodTmpl, HasExplicitTemplateArgs,
+ ExplicitTemplateArgs, NumExplicitTemplateArgs,
+ Args, NumArgs, Specialization, Info)) {
+ // FIXME: Record what happened with template argument deduction, so
+ // that we can give the user a beautiful diagnostic.
+ (void)Result;
+ return;
+ }
+
+ // Add the function template specialization produced by template argument
+ // deduction as a candidate.
+ assert(Specialization && "Missing member function template specialization?");
+ assert(isa<CXXMethodDecl>(Specialization) &&
+ "Specialization is not a member function?");
+ AddMethodCandidate(cast<CXXMethodDecl>(Specialization), Object, Args, NumArgs,
+ CandidateSet, SuppressUserConversions, ForceRValue);
+}
+
+/// \brief Add a C++ function template specialization as a candidate
+/// in the candidate set, using template argument deduction to produce
+/// an appropriate function template specialization.
+void
Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
bool HasExplicitTemplateArgs,
const TemplateArgument *ExplicitTemplateArgs,
@@ -2281,10 +2466,13 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions,
bool ForceRValue) {
+ if (!CandidateSet.isNewCandidate(FunctionTemplate))
+ return;
+
// C++ [over.match.funcs]p7:
- // In each case where a candidate is a function template, candidate
+ // In each case where a candidate is a function template, candidate
// function template specializations are generated using template argument
- // deduction (14.8.3, 14.8.2). Those candidates are then handled as
+ // deduction (14.8.3, 14.8.2). Those candidates are then handled as
// candidate functions in the usual way.113) A given name can refer to one
// or more function templates and also to a set of overloaded non-template
// functions. In such a case, the candidate functions generated from each
@@ -2301,24 +2489,30 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
(void)Result;
return;
}
-
+
// Add the function template specialization produced by template argument
// deduction as a candidate.
assert(Specialization && "Missing function template specialization?");
AddOverloadCandidate(Specialization, Args, NumArgs, CandidateSet,
SuppressUserConversions, ForceRValue);
}
-
+
/// AddConversionCandidate - Add a C++ conversion function as a
-/// candidate in the candidate set (C++ [over.match.conv],
+/// 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
+/// 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) {
+ assert(!Conversion->getDescribedFunctionTemplate() &&
+ "Conversion function templates use AddTemplateConversionCandidate");
+
+ if (!CandidateSet.isNewCandidate(Conversion))
+ return;
+
// Add this candidate
CandidateSet.push_back(OverloadCandidate());
OverloadCandidate& Candidate = CandidateSet.back();
@@ -2326,7 +2520,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
Candidate.FinalConversion.setAsIdentityConversion();
- Candidate.FinalConversion.FromTypePtr
+ Candidate.FinalConversion.FromTypePtr
= Conversion->getConversionType().getAsOpaquePtr();
Candidate.FinalConversion.ToTypePtr = ToType.getAsOpaquePtr();
@@ -2335,8 +2529,12 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
Candidate.Viable = true;
Candidate.Conversions.resize(1);
Candidate.Conversions[0] = TryObjectArgumentInitialization(From, Conversion);
-
- if (Candidate.Conversions[0].ConversionKind
+ // Conversion functions to a different type in the base class is visible in
+ // the derived class. So, a derived to base conversion should not participate
+ // in overload resolution.
+ if (Candidate.Conversions[0].Standard.Second == ICK_Derived_To_Base)
+ Candidate.Conversions[0].Standard.Second = ICK_Identity;
+ if (Candidate.Conversions[0].ConversionKind
== ImplicitConversionSequence::BadConversion) {
Candidate.Viable = false;
return;
@@ -2350,18 +2548,24 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
// 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(),
+ DeclRefExpr ConversionRef(Conversion, Conversion->getType(),
SourceLocation());
ImplicitCastExpr ConversionFn(Context.getPointerType(Conversion->getType()),
+ CastExpr::CK_Unknown,
&ConversionRef, false);
-
- // Note that it is safe to allocate CallExpr on the stack here because
+
+ // 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,
+ CallExpr Call(Context, &ConversionFn, 0, 0,
Conversion->getConversionType().getNonReferenceType(),
SourceLocation());
- ImplicitConversionSequence ICS = TryCopyInitialization(&Call, ToType, true);
+ ImplicitConversionSequence ICS =
+ TryCopyInitialization(&Call, ToType,
+ /*SuppressUserConversions=*/true,
+ /*ForceRValue=*/false,
+ /*InOverloadResolution=*/false);
+
switch (ICS.ConversionKind) {
case ImplicitConversionSequence::StandardConversion:
Candidate.FinalConversion = ICS.Standard;
@@ -2372,11 +2576,43 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
break;
default:
- assert(false &&
+ assert(false &&
"Can only end up with a standard conversion sequence or failure");
}
}
+/// \brief Adds a conversion function template specialization
+/// candidate to the overload set, using template argument deduction
+/// to deduce the template arguments of the conversion function
+/// template from the type that we are converting to (C++
+/// [temp.deduct.conv]).
+void
+Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
+ Expr *From, QualType ToType,
+ OverloadCandidateSet &CandidateSet) {
+ assert(isa<CXXConversionDecl>(FunctionTemplate->getTemplatedDecl()) &&
+ "Only conversion function templates permitted here");
+
+ if (!CandidateSet.isNewCandidate(FunctionTemplate))
+ return;
+
+ TemplateDeductionInfo Info(Context);
+ CXXConversionDecl *Specialization = 0;
+ if (TemplateDeductionResult Result
+ = DeduceTemplateArguments(FunctionTemplate, ToType,
+ Specialization, Info)) {
+ // FIXME: Record what happened with template argument deduction, so
+ // that we can give the user a beautiful diagnostic.
+ (void)Result;
+ return;
+ }
+
+ // Add the conversion function template specialization produced by
+ // template argument deduction as a candidate.
+ assert(Specialization && "Missing function template specialization?");
+ AddConversionCandidate(Specialization, From, ToType, CandidateSet);
+}
+
/// 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
@@ -2386,6 +2622,9 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
const FunctionProtoType *Proto,
Expr *Object, Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet) {
+ if (!CandidateSet.isNewCandidate(Conversion))
+ return;
+
CandidateSet.push_back(OverloadCandidate());
OverloadCandidate& Candidate = CandidateSet.back();
Candidate.Function = 0;
@@ -2397,7 +2636,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
// Determine the implicit conversion sequence for the implicit
// object parameter.
- ImplicitConversionSequence ObjectInit
+ ImplicitConversionSequence ObjectInit
= TryObjectArgumentInitialization(Object, Conversion);
if (ObjectInit.ConversionKind == ImplicitConversionSequence::BadConversion) {
Candidate.Viable = false;
@@ -2407,15 +2646,15 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
// 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
+ 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.After
= Candidate.Conversions[0].UserDefined.Before;
Candidate.Conversions[0].UserDefined.After.setAsIdentityConversion();
- // Find the
+ // Find the
unsigned NumArgsInProto = Proto->getNumArgs();
// (C++ 13.3.2p2): A candidate function having fewer than m
@@ -2443,10 +2682,12 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
// (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
+ Candidate.Conversions[ArgIdx + 1]
+ = TryCopyInitialization(Args[ArgIdx], ParamType,
+ /*SuppressUserConversions=*/false,
+ /*ForceRValue=*/false,
+ /*InOverloadResolution=*/false);
+ if (Candidate.Conversions[ArgIdx + 1].ConversionKind
== ImplicitConversionSequence::BadConversion) {
Candidate.Viable = false;
break;
@@ -2455,7 +2696,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
// (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
+ Candidate.Conversions[ArgIdx + 1].ConversionKind
= ImplicitConversionSequence::EllipsisConversion;
}
}
@@ -2469,7 +2710,6 @@ void Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
SourceRange OpRange) {
-
FunctionSet Functions;
QualType T1 = Args[0]->getType();
@@ -2518,14 +2758,32 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op,
// 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(OpName);
- Oper != OperEnd; ++Oper)
- AddMethodCandidate(cast<CXXMethodDecl>(*Oper), Args[0],
- Args+1, NumArgs - 1, CandidateSet,
- /*SuppressUserConversions=*/false);
+ if (const RecordType *T1Rec = T1->getAs<RecordType>()) {
+ // Complete the type if it can be completed. Otherwise, we're done.
+ if (RequireCompleteType(OpLoc, T1, PDiag()))
+ return;
+
+ LookupResult Operators;
+ LookupQualifiedName(Operators, T1Rec->getDecl(), OpName,
+ LookupOrdinaryName, false);
+ for (LookupResult::iterator Oper = Operators.begin(),
+ OperEnd = Operators.end();
+ Oper != OperEnd;
+ ++Oper) {
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*Oper)) {
+ AddMethodCandidate(Method, Args[0], Args+1, NumArgs - 1, CandidateSet,
+ /*SuppressUserConversions=*/false);
+ continue;
+ }
+
+ assert(isa<FunctionTemplateDecl>(*Oper) &&
+ isa<CXXMethodDecl>(cast<FunctionTemplateDecl>(*Oper)
+ ->getTemplatedDecl()) &&
+ "Expected a member function template");
+ AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(*Oper), false, 0, 0,
+ Args[0], Args+1, NumArgs - 1, CandidateSet,
+ /*SuppressUserConversions=*/false);
+ }
}
}
@@ -2537,7 +2795,7 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op,
/// 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,
+void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool IsAssignmentOperator,
@@ -2563,22 +2821,24 @@ void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
// -- 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.
+ // 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 &&
+ 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);
+ Candidate.Conversions[ArgIdx]
+ = TryCopyInitialization(Args[ArgIdx], ParamTys[ArgIdx],
+ ArgIdx == 0 && IsAssignmentOperator,
+ /*ForceRValue=*/false,
+ /*InOverloadResolution=*/false);
}
- if (Candidate.Conversions[ArgIdx].ConversionKind
+ if (Candidate.Conversions[ArgIdx].ConversionKind
== ImplicitConversionSequence::BadConversion) {
Candidate.Viable = false;
break;
@@ -2606,6 +2866,10 @@ class BuiltinCandidateTypeSet {
/// used in the built-in candidates.
TypeSet EnumerationTypes;
+ /// Sema - The semantic analysis instance where we are building the
+ /// candidate type set.
+ Sema &SemaRef;
+
/// Context - The AST context in which we will build the type sets.
ASTContext &Context;
@@ -2616,7 +2880,8 @@ public:
/// iterator - Iterates through the types that are part of the set.
typedef TypeSet::iterator iterator;
- BuiltinCandidateTypeSet(ASTContext &Context) : Context(Context) { }
+ BuiltinCandidateTypeSet(Sema &SemaRef)
+ : SemaRef(SemaRef), Context(SemaRef.Context) { }
void AddTypesConvertedFrom(QualType Ty, bool AllowUserConversions,
bool AllowExplicitConversions);
@@ -2647,27 +2912,27 @@ public:
/// restrict *", and "int const volatile restrict *" to the set of
/// pointer types. Returns true if the add of @p Ty itself succeeded,
/// false otherwise.
+///
+/// FIXME: what to do about extended qualifiers?
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()));
+ const PointerType *PointerTy = Ty->getAs<PointerType>();
+ assert(PointerTy && "type was not a pointer type!");
+
+ QualType PointeeTy = PointerTy->getPointeeType();
+ unsigned BaseCVR = PointeeTy.getCVRQualifiers();
+
+ // Iterate through all strict supersets of BaseCVR.
+ for (unsigned CVR = BaseCVR+1; CVR <= Qualifiers::CVRMask; ++CVR) {
+ if ((CVR | BaseCVR) != CVR) continue;
+
+ QualType QPointeeTy = Context.getCVRQualifiedType(PointeeTy, CVR);
+ PointerTypes.insert(Context.getPointerType(QPointeeTy));
}
return true;
@@ -2680,6 +2945,8 @@ BuiltinCandidateTypeSet::AddPointerWithMoreQualifiedTypeVariants(QualType Ty) {
/// restrict *", and "int const volatile restrict *" to the set of
/// pointer types. Returns true if the add of @p Ty itself succeeded,
/// false otherwise.
+///
+/// FIXME: what to do about extended qualifiers?
bool
BuiltinCandidateTypeSet::AddMemberPointerWithMoreQualifiedTypeVariants(
QualType Ty) {
@@ -2687,20 +2954,20 @@ BuiltinCandidateTypeSet::AddMemberPointerWithMoreQualifiedTypeVariants(
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));
+ const MemberPointerType *PointerTy = Ty->getAs<MemberPointerType>();
+ assert(PointerTy && "type was not a member pointer type!");
+
+ QualType PointeeTy = PointerTy->getPointeeType();
+ const Type *ClassTy = PointerTy->getClass();
+
+ // Iterate through all strict supersets of the pointee type's CVR
+ // qualifiers.
+ unsigned BaseCVR = PointeeTy.getCVRQualifiers();
+ for (unsigned CVR = BaseCVR+1; CVR <= Qualifiers::CVRMask; ++CVR) {
+ if ((CVR | BaseCVR) != CVR) continue;
+
+ QualType QPointeeTy = Context.getCVRQualifiedType(PointeeTy, CVR);
+ MemberPointerTypes.insert(Context.getMemberPointerType(QPointeeTy, ClassTy));
}
return true;
@@ -2714,7 +2981,7 @@ BuiltinCandidateTypeSet::AddMemberPointerWithMoreQualifiedTypeVariants(
/// functions of a class type, and AllowExplicitConversions if we
/// should also include the explicit conversion functions of a class
/// type.
-void
+void
BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
bool AllowUserConversions,
bool AllowExplicitConversions) {
@@ -2723,13 +2990,13 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType 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())
+ if (const ReferenceType *RefTy = Ty->getAs<ReferenceType>())
Ty = RefTy->getPointeeType();
// We don't care about qualifiers on the type.
Ty = Ty.getUnqualifiedType();
- if (const PointerType *PointerTy = Ty->getAsPointerType()) {
+ if (const PointerType *PointerTy = Ty->getAs<PointerType>()) {
QualType PointeeTy = PointerTy->getPointeeType();
// Insert our type, and its more-qualified variants, into the set
@@ -2739,20 +3006,22 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
// Add 'cv void*' to our set of types.
if (!Ty->isVoidType()) {
- QualType QualVoid
- = Context.VoidTy.getQualifiedType(PointeeTy.getCVRQualifiers());
+ QualType QualVoid
+ = Context.getCVRQualifiedType(Context.VoidTy,
+ 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()) {
+ if (const RecordType *PointeeRec = PointeeTy->getAs<RecordType>()) {
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());
+ BaseTy = Context.getCVRQualifiedType(BaseTy.getUnqualifiedType(),
+ PointeeTy.getCVRQualifiers());
// Add the pointer type, recursively, so that we get all of
// the indirect base classes, too.
@@ -2766,15 +3035,27 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
} else if (Ty->isEnumeralType()) {
EnumerationTypes.insert(Ty);
} else if (AllowUserConversions) {
- if (const RecordType *TyRec = Ty->getAsRecordType()) {
+ if (const RecordType *TyRec = Ty->getAs<RecordType>()) {
+ if (SemaRef.RequireCompleteType(SourceLocation(), Ty, 0)) {
+ // No conversion functions in incomplete types.
+ return;
+ }
+
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(TyRec->getDecl());
- // FIXME: Visit conversion functions in the base classes, too.
- OverloadedFunctionDecl *Conversions
- = ClassDecl->getConversionFunctions();
- for (OverloadedFunctionDecl::function_iterator Func
+ OverloadedFunctionDecl *Conversions
+ = ClassDecl->getVisibleConversionFunctions();
+ for (OverloadedFunctionDecl::function_iterator Func
= Conversions->function_begin();
Func != Conversions->function_end(); ++Func) {
- CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func);
+ CXXConversionDecl *Conv;
+ FunctionTemplateDecl *ConvTemplate;
+ GetFunctionAndTemplate(*Func, Conv, ConvTemplate);
+
+ // Skip conversion function templates; they don't tell us anything
+ // about which builtin types we can convert to.
+ if (ConvTemplate)
+ continue;
+
if (AllowExplicitConversions || !Conv->isExplicit())
AddTypesConvertedFrom(Conv->getConversionType(), false, false);
}
@@ -2782,13 +3063,39 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
}
}
+/// \brief Helper function for AddBuiltinOperatorCandidates() that adds
+/// the volatile- and non-volatile-qualified assignment operators for the
+/// given type to the candidate set.
+static void AddBuiltinAssignmentOperatorCandidates(Sema &S,
+ QualType T,
+ Expr **Args,
+ unsigned NumArgs,
+ OverloadCandidateSet &CandidateSet) {
+ QualType ParamTypes[2];
+
+ // T& operator=(T&, T)
+ ParamTypes[0] = S.Context.getLValueReferenceType(T);
+ ParamTypes[1] = T;
+ S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
+ /*IsAssignmentOperator=*/true);
+
+ if (!S.Context.getCanonicalType(T).isVolatileQualified()) {
+ // volatile T& operator=(volatile T&, T)
+ ParamTypes[0]
+ = S.Context.getLValueReferenceType(S.Context.getVolatileType(T));
+ ParamTypes[1] = T;
+ S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
+ /*IsAssignmentOperator=*/true);
+ }
+}
+
/// 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,
+Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet) {
// The set of "promoted arithmetic types", which are the arithmetic
@@ -2798,13 +3105,14 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
// FIXME: What about complex?
const unsigned FirstIntegralType = 0;
const unsigned LastIntegralType = 13;
- const unsigned FirstPromotedIntegralType = 7,
+ 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,
+// FIXME: Context.Char16Ty, Context.Char32Ty,
Context.SignedCharTy, Context.ShortTy,
Context.UnsignedCharTy, Context.UnsignedShortTy,
Context.IntTy, Context.LongTy, Context.LongLongTy,
@@ -2815,7 +3123,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
// 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);
+ BuiltinCandidateTypeSet CandidateTypes(*this);
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 ||
@@ -2838,7 +3146,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
break;
case OO_Star: // '*' is either unary or binary
- if (NumArgs == 1)
+ if (NumArgs == 1)
goto UnaryStar;
else
goto BinaryStar;
@@ -2883,10 +3191,10 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
//
// VQ T& operator--(VQ T&);
// T operator--(VQ T&, int);
- for (unsigned Arith = (Op == OO_PlusPlus? 0 : 1);
+ for (unsigned Arith = (Op == OO_PlusPlus? 0 : 1);
Arith < NumArithmeticTypes; ++Arith) {
QualType ArithTy = ArithmeticTypes[Arith];
- QualType ParamTypes[2]
+ QualType ParamTypes[2]
= { Context.getLValueReferenceType(ArithTy), Context.IntTy };
// Non-volatile version.
@@ -2896,7 +3204,8 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
AddBuiltinCandidate(ArithTy, ParamTypes, Args, 2, CandidateSet);
// Volatile version
- ParamTypes[0] = Context.getLValueReferenceType(ArithTy.withVolatile());
+ ParamTypes[0]
+ = Context.getLValueReferenceType(Context.getVolatileType(ArithTy));
if (NumArgs == 1)
AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet);
else
@@ -2916,13 +3225,13 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
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())
+ if (!(*Ptr)->getAs<PointerType>()->getPointeeType()->isObjectType())
continue;
- QualType ParamTypes[2] = {
- Context.getLValueReferenceType(*Ptr), Context.IntTy
+ QualType ParamTypes[2] = {
+ Context.getLValueReferenceType(*Ptr), Context.IntTy
};
-
+
// Without volatile
if (NumArgs == 1)
AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet);
@@ -2931,7 +3240,8 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
if (!Context.getCanonicalType(*Ptr).isVolatileQualified()) {
// With volatile
- ParamTypes[0] = Context.getLValueReferenceType((*Ptr).withVolatile());
+ ParamTypes[0]
+ = Context.getLValueReferenceType(Context.getVolatileType(*Ptr));
if (NumArgs == 1)
AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet);
else
@@ -2954,8 +3264,8 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin();
Ptr != CandidateTypes.pointer_end(); ++Ptr) {
QualType ParamTy = *Ptr;
- QualType PointeeTy = ParamTy->getAsPointerType()->getPointeeType();
- AddBuiltinCandidate(Context.getLValueReferenceType(PointeeTy),
+ QualType PointeeTy = ParamTy->getAs<PointerType>()->getPointeeType();
+ AddBuiltinCandidate(Context.getLValueReferenceType(PointeeTy),
&ParamTy, Args, 1, CandidateSet);
}
break;
@@ -2971,7 +3281,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
QualType ParamTy = *Ptr;
AddBuiltinCandidate(ParamTy, &ParamTy, Args, 1, CandidateSet);
}
-
+
// Fall through
UnaryMinus:
@@ -2981,7 +3291,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
//
// T operator+(T);
// T operator-(T);
- for (unsigned Arith = FirstPromotedArithmeticType;
+ for (unsigned Arith = FirstPromotedArithmeticType;
Arith < LastPromotedArithmeticType; ++Arith) {
QualType ArithTy = ArithmeticTypes[Arith];
AddBuiltinCandidate(ArithTy, &ArithTy, Args, 1, CandidateSet);
@@ -2994,7 +3304,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
// operator functions of the form
//
// T operator~(T);
- for (unsigned Int = FirstPromotedIntegralType;
+ for (unsigned Int = FirstPromotedIntegralType;
Int < LastPromotedIntegralType; ++Int) {
QualType IntTy = ArithmeticTypes[Int];
AddBuiltinCandidate(IntTy, &IntTy, Args, 1, CandidateSet);
@@ -3017,17 +3327,34 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
// operator '->', the built-in candidates set is empty.
break;
+ case OO_EqualEqual:
+ case OO_ExclaimEqual:
+ // C++ [over.match.oper]p16:
+ // For every pointer to member type T, there exist candidate operator
+ // functions of the form
+ //
+ // bool operator==(T,T);
+ // bool operator!=(T,T);
+ for (BuiltinCandidateTypeSet::iterator
+ MemPtr = CandidateTypes.member_pointer_begin(),
+ MemPtrEnd = CandidateTypes.member_pointer_end();
+ MemPtr != MemPtrEnd;
+ ++MemPtr) {
+ QualType ParamTypes[2] = { *MemPtr, *MemPtr };
+ AddBuiltinCandidate(Context.BoolTy, ParamTypes, Args, 2, CandidateSet);
+ }
+
+ // Fall through
+
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);
@@ -3039,7 +3366,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
QualType ParamTypes[2] = { *Ptr, *Ptr };
AddBuiltinCandidate(Context.BoolTy, ParamTypes, Args, 2, CandidateSet);
}
- for (BuiltinCandidateTypeSet::iterator Enum
+ for (BuiltinCandidateTypeSet::iterator Enum
= CandidateTypes.enumeration_begin();
Enum != CandidateTypes.enumeration_end(); ++Enum) {
QualType ParamTypes[2] = { *Enum, *Enum };
@@ -3058,7 +3385,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
//
// 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);
@@ -3071,7 +3398,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
// exist candidate operator functions of the form
//
// ptrdiff_t operator-(T, T);
- for (BuiltinCandidateTypeSet::iterator Ptr
+ for (BuiltinCandidateTypeSet::iterator Ptr
= CandidateTypes.pointer_begin();
Ptr != CandidateTypes.pointer_end(); ++Ptr) {
QualType ParamTypes[2] = { *Ptr, Context.getPointerDiffType() };
@@ -3126,14 +3453,15 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
// 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;
+ for (unsigned Left = FirstPromotedArithmeticType;
Left < LastPromotedArithmeticType; ++Left) {
- for (unsigned Right = FirstPromotedArithmeticType;
+ for (unsigned Right = FirstPromotedArithmeticType;
Right < LastPromotedArithmeticType; ++Right) {
QualType LandR[2] = { ArithmeticTypes[Left], ArithmeticTypes[Right] };
- QualType Result
- = isComparison? Context.BoolTy
- : UsualArithmeticConversionsType(LandR[0], LandR[1]);
+ QualType Result
+ = isComparison
+ ? Context.BoolTy
+ : Context.UsualArithmeticConversionsType(LandR[0], LandR[1]);
AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet);
}
}
@@ -3159,14 +3487,14 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
//
// where LR is the result of the usual arithmetic conversions
// between types L and R.
- for (unsigned Left = FirstPromotedIntegralType;
+ for (unsigned Left = FirstPromotedIntegralType;
Left < LastPromotedIntegralType; ++Left) {
- for (unsigned Right = FirstPromotedIntegralType;
+ 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]);
+ : Context.UsualArithmeticConversionsType(LandR[0], LandR[1]);
AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet);
}
}
@@ -3176,30 +3504,23 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
// 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
+ // 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.
+ for (BuiltinCandidateTypeSet::iterator
+ Enum = CandidateTypes.enumeration_begin(),
+ EnumEnd = CandidateTypes.enumeration_end();
+ Enum != EnumEnd; ++Enum)
+ AddBuiltinAssignmentOperatorCandidates(*this, *Enum, Args, 2,
+ CandidateSet);
+ for (BuiltinCandidateTypeSet::iterator
+ MemPtr = CandidateTypes.member_pointer_begin(),
+ MemPtrEnd = CandidateTypes.member_pointer_end();
+ MemPtr != MemPtrEnd; ++MemPtr)
+ AddBuiltinAssignmentOperatorCandidates(*this, *MemPtr, Args, 2,
+ CandidateSet);
+ // Fall through.
case OO_PlusEqual:
case OO_MinusEqual:
@@ -3231,7 +3552,8 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
if (!Context.getCanonicalType(*Ptr).isVolatileQualified()) {
// volatile version
- ParamTypes[0] = Context.getLValueReferenceType((*Ptr).withVolatile());
+ ParamTypes[0]
+ = Context.getLValueReferenceType(Context.getVolatileType(*Ptr));
AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
/*IsAssigmentOperator=*/Op == OO_Equal);
}
@@ -3253,7 +3575,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
// VQ L& operator+=(VQ L&, R);
// VQ L& operator-=(VQ L&, R);
for (unsigned Left = 0; Left < NumArithmeticTypes; ++Left) {
- for (unsigned Right = FirstPromotedArithmeticType;
+ for (unsigned Right = FirstPromotedArithmeticType;
Right < LastPromotedArithmeticType; ++Right) {
QualType ParamTypes[2];
ParamTypes[1] = ArithmeticTypes[Right];
@@ -3264,7 +3586,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
/*IsAssigmentOperator=*/Op == OO_Equal);
// Add this built-in operator as a candidate (VQ is 'volatile').
- ParamTypes[0] = ArithmeticTypes[Left].withVolatile();
+ ParamTypes[0] = Context.getVolatileType(ArithmeticTypes[Left]);
ParamTypes[0] = Context.getLValueReferenceType(ParamTypes[0]);
AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
/*IsAssigmentOperator=*/Op == OO_Equal);
@@ -3291,7 +3613,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
// VQ L& operator^=(VQ L&, R);
// VQ L& operator|=(VQ L&, R);
for (unsigned Left = FirstIntegralType; Left < LastIntegralType; ++Left) {
- for (unsigned Right = FirstPromotedIntegralType;
+ for (unsigned Right = FirstPromotedIntegralType;
Right < LastPromotedIntegralType; ++Right) {
QualType ParamTypes[2];
ParamTypes[1] = ArithmeticTypes[Right];
@@ -3302,7 +3624,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
// Add this built-in operator as a candidate (VQ is 'volatile').
ParamTypes[0] = ArithmeticTypes[Left];
- ParamTypes[0].addVolatile();
+ ParamTypes[0] = Context.getVolatileType(ParamTypes[0]);
ParamTypes[0] = Context.getLValueReferenceType(ParamTypes[0]);
AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet);
}
@@ -3314,7 +3636,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
//
// There also exist candidate operator functions of the form
//
- // bool operator!(bool);
+ // bool operator!(bool);
// bool operator&&(bool, bool); [BELOW]
// bool operator||(bool, bool); [BELOW]
QualType ParamTy = Context.BoolTy;
@@ -3345,7 +3667,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
//
// 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]
@@ -3354,7 +3676,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin();
Ptr != CandidateTypes.pointer_end(); ++Ptr) {
QualType ParamTypes[2] = { *Ptr, Context.getPointerDiffType() };
- QualType PointeeType = (*Ptr)->getAsPointerType()->getPointeeType();
+ QualType PointeeType = (*Ptr)->getAs<PointerType>()->getPointeeType();
QualType ResultTy = Context.getLValueReferenceType(PointeeType);
// T& operator[](T*, ptrdiff_t)
@@ -3368,7 +3690,43 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
break;
case OO_ArrowStar:
- // FIXME: No support for pointer-to-members yet.
+ // C++ [over.built]p11:
+ // For every quintuple (C1, C2, T, CV1, CV2), where C2 is a class type,
+ // C1 is the same type as C2 or is a derived class of C2, T is an object
+ // type or a function type, and CV1 and CV2 are cv-qualifier-seqs,
+ // there exist candidate operator functions of the form
+ // CV12 T& operator->*(CV1 C1*, CV2 T C2::*);
+ // where CV12 is the union of CV1 and CV2.
+ {
+ for (BuiltinCandidateTypeSet::iterator Ptr =
+ CandidateTypes.pointer_begin();
+ Ptr != CandidateTypes.pointer_end(); ++Ptr) {
+ QualType C1Ty = (*Ptr);
+ QualType C1;
+ QualifierCollector Q1;
+ if (const PointerType *PointerTy = C1Ty->getAs<PointerType>()) {
+ C1 = QualType(Q1.strip(PointerTy->getPointeeType()), 0);
+ if (!isa<RecordType>(C1))
+ continue;
+ }
+ for (BuiltinCandidateTypeSet::iterator
+ MemPtr = CandidateTypes.member_pointer_begin(),
+ MemPtrEnd = CandidateTypes.member_pointer_end();
+ MemPtr != MemPtrEnd; ++MemPtr) {
+ const MemberPointerType *mptr = cast<MemberPointerType>(*MemPtr);
+ QualType C2 = QualType(mptr->getClass(), 0);
+ C2 = C2.getUnqualifiedType();
+ if (C1 != C2 && !IsDerivedFrom(C1, C2))
+ break;
+ QualType ParamTypes[2] = { *Ptr, *MemPtr };
+ // build CV12 T&
+ QualType T = mptr->getPointeeType();
+ T = Q1.apply(T);
+ QualType ResultTy = Context.getLValueReferenceType(T);
+ AddBuiltinCandidate(ResultTy, ParamTypes, Args, 2, CandidateSet);
+ }
+ }
+ }
break;
case OO_Conditional:
@@ -3404,12 +3762,18 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
/// 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
+void
Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
Expr **Args, unsigned NumArgs,
- OverloadCandidateSet& CandidateSet) {
+ bool HasExplicitTemplateArgs,
+ const TemplateArgument *ExplicitTemplateArgs,
+ unsigned NumExplicitTemplateArgs,
+ OverloadCandidateSet& CandidateSet,
+ bool PartialOverloading) {
FunctionSet Functions;
+ // FIXME: Should we be trafficking in canonical function decls throughout?
+
// 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.
@@ -3422,6 +3786,7 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
Functions.insert(FunTmpl);
}
+ // FIXME: Pass in the explicit template arguments?
ArgumentDependentLookup(Name, Args, NumArgs, Functions);
// Erase all of the candidates we already knew about.
@@ -3440,21 +3805,26 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
for (FunctionSet::iterator Func = Functions.begin(),
FuncEnd = Functions.end();
Func != FuncEnd; ++Func) {
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*Func))
- AddOverloadCandidate(FD, Args, NumArgs, CandidateSet);
- else
- AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*Func),
- /*FIXME: explicit args */false, 0, 0,
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*Func)) {
+ if (HasExplicitTemplateArgs)
+ continue;
+
+ AddOverloadCandidate(FD, Args, NumArgs, CandidateSet,
+ false, false, PartialOverloading);
+ } else
+ AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*Func),
+ HasExplicitTemplateArgs,
+ ExplicitTemplateArgs,
+ NumExplicitTemplateArgs,
Args, NumArgs, CandidateSet);
}
}
/// isBetterOverloadCandidate - Determines whether the first overload
/// candidate is a better candidate than the second (C++ 13.3.3p1).
-bool
+bool
Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1,
- const OverloadCandidate& Cand2)
-{
+ const OverloadCandidate& Cand2) {
// Define viable functions to be better candidates than non-viable
// functions.
if (!Cand2.Viable)
@@ -3472,10 +3842,10 @@ Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1,
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...
+ // C++ [over.match.best]p1:
+ // 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;
@@ -3497,22 +3867,38 @@ Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1,
}
}
+ // -- for some argument j, ICSj(F1) is a better conversion sequence than
+ // ICSj(F2), or, if not that,
if (HasBetterConversion)
return true;
- // FIXME: Several other bullets in (C++ 13.3.3p1) need to be
- // implemented, but they require template support.
+ // - F1 is a non-template function and F2 is a function template
+ // specialization, or, if not that,
+ if (Cand1.Function && !Cand1.Function->getPrimaryTemplate() &&
+ Cand2.Function && Cand2.Function->getPrimaryTemplate())
+ return true;
+
+ // -- F1 and F2 are function template specializations, and the function
+ // template for F1 is more specialized than the template for F2
+ // according to the partial ordering rules described in 14.5.5.2, or,
+ // if not that,
+ if (Cand1.Function && Cand1.Function->getPrimaryTemplate() &&
+ Cand2.Function && Cand2.Function->getPrimaryTemplate())
+ if (FunctionTemplateDecl *BetterTemplate
+ = getMoreSpecializedTemplate(Cand1.Function->getPrimaryTemplate(),
+ Cand2.Function->getPrimaryTemplate(),
+ isa<CXXConversionDecl>(Cand1.Function)? TPOC_Conversion
+ : TPOC_Call))
+ return BetterTemplate == Cand1.Function->getPrimaryTemplate();
- // 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) &&
+ if (Cand1.Function && Cand2.Function &&
+ isa<CXXConversionDecl>(Cand1.Function) &&
isa<CXXConversionDecl>(Cand2.Function)) {
switch (CompareStandardConversionSequences(Cand1.FinalConversion,
Cand2.FinalConversion)) {
@@ -3533,7 +3919,7 @@ Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1,
return false;
}
-/// \brief Computes the best viable function (C++ 13.3.3)
+/// \brief Computes the best viable function (C++ 13.3.3)
/// within an overload candidate set.
///
/// \param CandidateSet the set of candidate functions.
@@ -3541,15 +3927,14 @@ Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1,
/// \param Loc the location of the function name (or operator symbol) for
/// which overload resolution occurs.
///
-/// \param Best f overload resolution was successful or found a deleted
+/// \param Best f overload resolution was successful or found a deleted
/// function, Best points to the candidate function found.
///
/// \returns The result of overload resolution.
-Sema::OverloadingResult
+Sema::OverloadingResult
Sema::BestViableFunction(OverloadCandidateSet& CandidateSet,
SourceLocation Loc,
- OverloadCandidateSet::iterator& Best)
-{
+ OverloadCandidateSet::iterator& Best) {
// Find the best viable function.
Best = CandidateSet.end();
for (OverloadCandidateSet::iterator Cand = CandidateSet.begin();
@@ -3568,24 +3953,24 @@ Sema::BestViableFunction(OverloadCandidateSet& CandidateSet,
// function. If not, we have an ambiguity.
for (OverloadCandidateSet::iterator Cand = CandidateSet.begin();
Cand != CandidateSet.end(); ++Cand) {
- if (Cand->Viable &&
+ 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->isDeleted() ||
Best->Function->getAttr<UnavailableAttr>()))
return OR_Deleted;
// C++ [basic.def.odr]p2:
// An overloaded function is used if it is selected by overload resolution
- // when referred to from a potentially-evaluated expression. [Note: this
- // covers calls to named functions (5.2.2), operator overloading
+ // when referred to from a potentially-evaluated expression. [Note: this
+ // covers calls to named functions (5.2.2), operator overloading
// (clause 13), user-defined conversions (12.3.2), allocation function for
// placement new (5.3.4), as well as non-default initialization (8.5).
if (Best->Function)
@@ -3596,12 +3981,14 @@ Sema::BestViableFunction(OverloadCandidateSet& CandidateSet,
/// 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
+void
Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet,
- bool OnlyViable)
-{
+ bool OnlyViable,
+ const char *Opc,
+ SourceLocation OpLoc) {
OverloadCandidateSet::iterator Cand = CandidateSet.begin(),
LastCand = CandidateSet.end();
+ bool Reported = false;
for (; Cand != LastCand; ++Cand) {
if (Cand->Viable || !OnlyViable) {
if (Cand->Function) {
@@ -3610,10 +3997,36 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet,
// Deleted or "unavailable" function.
Diag(Cand->Function->getLocation(), diag::err_ovl_candidate_deleted)
<< Cand->Function->isDeleted();
+ } else if (FunctionTemplateDecl *FunTmpl
+ = Cand->Function->getPrimaryTemplate()) {
+ // Function template specialization
+ // FIXME: Give a better reason!
+ Diag(Cand->Function->getLocation(), diag::err_ovl_template_candidate)
+ << getTemplateArgumentBindingsText(FunTmpl->getTemplateParameters(),
+ *Cand->Function->getTemplateSpecializationArgs());
} else {
// Normal function
- // FIXME: Give a better reason!
- Diag(Cand->Function->getLocation(), diag::err_ovl_candidate);
+ bool errReported = false;
+ if (!Cand->Viable && Cand->Conversions.size() > 0) {
+ for (int i = Cand->Conversions.size()-1; i >= 0; i--) {
+ const ImplicitConversionSequence &Conversion =
+ Cand->Conversions[i];
+ if ((Conversion.ConversionKind !=
+ ImplicitConversionSequence::BadConversion) ||
+ Conversion.ConversionFunctionSet.size() == 0)
+ continue;
+ Diag(Cand->Function->getLocation(),
+ diag::err_ovl_candidate_not_viable) << (i+1);
+ errReported = true;
+ for (int j = Conversion.ConversionFunctionSet.size()-1;
+ j >= 0; j--) {
+ FunctionDecl *Func = Conversion.ConversionFunctionSet[j];
+ Diag(Func->getLocation(), diag::err_ovl_candidate);
+ }
+ }
+ }
+ if (!errReported)
+ Diag(Cand->Function->getLocation(), diag::err_ovl_candidate);
}
} else if (Cand->IsSurrogate) {
// Desugar the type of the surrogate down to a function type,
@@ -3624,20 +4037,20 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet,
bool isRValueReference = false;
bool isPointer = false;
if (const LValueReferenceType *FnTypeRef =
- FnType->getAsLValueReferenceType()) {
+ FnType->getAs<LValueReferenceType>()) {
FnType = FnTypeRef->getPointeeType();
isLValueReference = true;
} else if (const RValueReferenceType *FnTypeRef =
- FnType->getAsRValueReferenceType()) {
+ FnType->getAs<RValueReferenceType>()) {
FnType = FnTypeRef->getPointeeType();
isRValueReference = true;
}
- if (const PointerType *FnTypePtr = FnType->getAsPointerType()) {
+ if (const PointerType *FnTypePtr = FnType->getAs<PointerType>()) {
FnType = FnTypePtr->getPointeeType();
isPointer = true;
}
// Desugar down to a function type.
- FnType = QualType(FnType->getAsFunctionType(), 0);
+ FnType = QualType(FnType->getAs<FunctionType>(), 0);
// Reconstruct the pointer/reference as appropriate.
if (isPointer) FnType = Context.getPointerType(FnType);
if (isRValueReference) FnType = Context.getRValueReferenceType(FnType);
@@ -3645,17 +4058,42 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet,
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;
+ } else if (OnlyViable) {
+ assert(Cand->Conversions.size() <= 2 &&
+ "builtin-binary-operator-not-binary");
+ if (Cand->Conversions.size() == 1)
+ Diag(OpLoc, diag::err_ovl_builtin_unary_candidate)
+ << Opc << Cand->BuiltinTypes.ParamTypes[0];
+ else
+ Diag(OpLoc, diag::err_ovl_builtin_binary_candidate)
+ << Opc << Cand->BuiltinTypes.ParamTypes[0]
+ << Cand->BuiltinTypes.ParamTypes[1];
+ }
+ else if (!Cand->Viable && !Reported) {
+ // Non-viability might be due to ambiguous user-defined conversions,
+ // needed for built-in operators. Report them as well, but only once
+ // as we have typically many built-in candidates.
+ unsigned NoOperands = Cand->Conversions.size();
+ for (unsigned ArgIdx = 0; ArgIdx < NoOperands; ++ArgIdx) {
+ const ImplicitConversionSequence &ICS = Cand->Conversions[ArgIdx];
+ if (ICS.ConversionKind != ImplicitConversionSequence::BadConversion ||
+ ICS.ConversionFunctionSet.empty())
+ continue;
+ if (CXXConversionDecl *Func = dyn_cast<CXXConversionDecl>(
+ Cand->Conversions[ArgIdx].ConversionFunctionSet[0])) {
+ QualType FromTy =
+ QualType(
+ static_cast<Type*>(ICS.UserDefined.Before.FromTypePtr),0);
+ Diag(OpLoc,diag::note_ambiguous_type_conversion)
+ << FromTy << Func->getConversionType();
+ }
+ for (unsigned j = 0; j < ICS.ConversionFunctionSet.size(); j++) {
+ FunctionDecl *Func =
+ Cand->Conversions[ArgIdx].ConversionFunctionSet[j];
+ Diag(Func->getLocation(),diag::err_ovl_candidate);
+ }
+ }
+ Reported = true;
}
}
}
@@ -3669,7 +4107,7 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet,
/// @code
/// int f(double);
/// int f(int);
-///
+///
/// int (*pfd)(double) = f; // selects f(double)
/// @endcode
///
@@ -3681,23 +4119,24 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
bool Complain) {
QualType FunctionType = ToType;
bool IsMember = false;
- if (const PointerType *ToTypePtr = ToType->getAsPointerType())
+ if (const PointerType *ToTypePtr = ToType->getAs<PointerType>())
FunctionType = ToTypePtr->getPointeeType();
- else if (const ReferenceType *ToTypeRef = ToType->getAsReferenceType())
+ else if (const ReferenceType *ToTypeRef = ToType->getAs<ReferenceType>())
FunctionType = ToTypeRef->getPointeeType();
else if (const MemberPointerType *MemTypePtr =
- ToType->getAsMemberPointerType()) {
+ ToType->getAs<MemberPointerType>()) {
FunctionType = MemTypePtr->getPointeeType();
IsMember = true;
}
// We only look at pointers or references to functions.
- if (!FunctionType->isFunctionType())
+ FunctionType = Context.getCanonicalType(FunctionType).getUnqualifiedType();
+ 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). ]
@@ -3712,27 +4151,76 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
}
// Try to dig out the overloaded function.
- if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(OvlExpr))
+ FunctionTemplateDecl *FunctionTemplate = 0;
+ if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(OvlExpr)) {
Ovl = dyn_cast<OverloadedFunctionDecl>(DR->getDecl());
+ FunctionTemplate = dyn_cast<FunctionTemplateDecl>(DR->getDecl());
+ } else if (MemberExpr *ME = dyn_cast<MemberExpr>(OvlExpr)) {
+ Ovl = dyn_cast<OverloadedFunctionDecl>(ME->getMemberDecl());
+ FunctionTemplate = dyn_cast<FunctionTemplateDecl>(ME->getMemberDecl());
+ // FIXME: Explicit template arguments
+ }
+ // FIXME: TemplateIdRefExpr?
- // If there's no overloaded function declaration, we're done.
- if (!Ovl)
+ // If there's no overloaded function declaration or function template,
+ // we're done.
+ if (!Ovl && !FunctionTemplate)
return 0;
-
+
+ OverloadIterator Fun;
+ if (Ovl)
+ Fun = Ovl;
+ else
+ Fun = FunctionTemplate;
+
// 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) {
+ llvm::SmallPtrSet<FunctionDecl *, 4> Matches;
+ bool FoundNonTemplateFunction = false;
+ for (OverloadIterator FunEnd; Fun != FunEnd; ++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 (FunctionTemplateDecl *FunctionTemplate
+ = dyn_cast<FunctionTemplateDecl>(*Fun)) {
+ if (CXXMethodDecl *Method
+ = dyn_cast<CXXMethodDecl>(FunctionTemplate->getTemplatedDecl())) {
+ // Skip non-static function templates when converting to pointer, and
+ // static when converting to member pointer.
+ if (Method->isStatic() == IsMember)
+ continue;
+ } else if (IsMember)
+ continue;
+
+ // C++ [over.over]p2:
+ // If the name is a function template, template argument deduction is
+ // done (14.8.2.2), and if the argument deduction succeeds, the
+ // resulting template argument list is used to generate a single
+ // function template specialization, which is added to the set of
+ // overloaded functions considered.
+ // FIXME: We don't really want to build the specialization here, do we?
+ FunctionDecl *Specialization = 0;
+ TemplateDeductionInfo Info(Context);
+ if (TemplateDeductionResult Result
+ = DeduceTemplateArguments(FunctionTemplate, /*FIXME*/false,
+ /*FIXME:*/0, /*FIXME:*/0,
+ FunctionType, Specialization, Info)) {
+ // FIXME: make a note of the failed deduction for diagnostics.
+ (void)Result;
+ } else {
+ // FIXME: If the match isn't exact, shouldn't we just drop this as
+ // a candidate? Find a testcase before changing the code.
+ assert(FunctionType
+ == Context.getCanonicalType(Specialization->getType()));
+ Matches.insert(
+ cast<FunctionDecl>(Specialization->getCanonicalDecl()));
+ }
+ }
+
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*Fun)) {
// Skip non-static functions when converting to pointer, and static
// when converting to member pointer.
@@ -3742,38 +4230,106 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
continue;
if (FunctionDecl *FunDecl = dyn_cast<FunctionDecl>(*Fun)) {
- if (FunctionType == Context.getCanonicalType(FunDecl->getType()))
- return FunDecl;
- } else {
- unsigned DiagID
- = PP.getDiagnostics().getCustomDiagID(Diagnostic::Warning,
- "Clang does not yet support templated conversion functions");
- Diag(From->getLocStart(), DiagID);
+ if (FunctionType == Context.getCanonicalType(FunDecl->getType())) {
+ Matches.insert(cast<FunctionDecl>(Fun->getCanonicalDecl()));
+ FoundNonTemplateFunction = true;
+ }
}
}
+ // If there were 0 or 1 matches, we're done.
+ if (Matches.empty())
+ return 0;
+ else if (Matches.size() == 1)
+ return *Matches.begin();
+
+ // C++ [over.over]p4:
+ // If more than one function is selected, [...]
+ typedef llvm::SmallPtrSet<FunctionDecl *, 4>::iterator MatchIter;
+ if (!FoundNonTemplateFunction) {
+ // [...] and any given function template specialization F1 is
+ // eliminated if the set contains a second function template
+ // specialization whose function template is more specialized
+ // than the function template of F1 according to the partial
+ // ordering rules of 14.5.5.2.
+
+ // The algorithm specified above is quadratic. We instead use a
+ // two-pass algorithm (similar to the one used to identify the
+ // best viable function in an overload set) that identifies the
+ // best function template (if it exists).
+ llvm::SmallVector<FunctionDecl *, 8> TemplateMatches(Matches.begin(),
+ Matches.end());
+ return getMostSpecialized(TemplateMatches.data(), TemplateMatches.size(),
+ TPOC_Other, From->getLocStart(),
+ PDiag(),
+ PDiag(diag::err_addr_ovl_ambiguous)
+ << TemplateMatches[0]->getDeclName(),
+ PDiag(diag::err_ovl_template_candidate));
+ }
+
+ // [...] any function template specializations in the set are
+ // eliminated if the set also contains a non-template function, [...]
+ llvm::SmallVector<FunctionDecl *, 4> RemainingMatches;
+ for (MatchIter M = Matches.begin(), MEnd = Matches.end(); M != MEnd; ++M)
+ if ((*M)->getPrimaryTemplate() == 0)
+ RemainingMatches.push_back(*M);
+
+ // [...] After such eliminations, if any, there shall remain exactly one
+ // selected function.
+ if (RemainingMatches.size() == 1)
+ return RemainingMatches.front();
+
+ // FIXME: We should probably return the same thing that BestViableFunction
+ // returns (even if we issue the diagnostics here).
+ Diag(From->getLocStart(), diag::err_addr_ovl_ambiguous)
+ << RemainingMatches[0]->getDeclName();
+ for (unsigned I = 0, N = RemainingMatches.size(); I != N; ++I)
+ Diag(RemainingMatches[I]->getLocation(), diag::err_ovl_candidate);
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,
- bool HasExplicitTemplateArgs,
+/// \brief Add a single candidate to the overload set.
+static void AddOverloadedCallCandidate(Sema &S,
+ AnyFunctionDecl Callee,
+ bool &ArgumentDependentLookup,
+ bool HasExplicitTemplateArgs,
const TemplateArgument *ExplicitTemplateArgs,
- unsigned NumExplicitTemplateArgs,
- SourceLocation LParenLoc,
- Expr **Args, unsigned NumArgs,
- SourceLocation *CommaLocs,
- SourceLocation RParenLoc,
- bool &ArgumentDependentLookup) {
- OverloadCandidateSet CandidateSet;
-
+ unsigned NumExplicitTemplateArgs,
+ Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet &CandidateSet,
+ bool PartialOverloading) {
+ if (FunctionDecl *Func = dyn_cast<FunctionDecl>(Callee)) {
+ assert(!HasExplicitTemplateArgs && "Explicit template arguments?");
+ S.AddOverloadCandidate(Func, Args, NumArgs, CandidateSet, false, false,
+ PartialOverloading);
+
+ if (Func->getDeclContext()->isRecord() ||
+ Func->getDeclContext()->isFunctionOrMethod())
+ ArgumentDependentLookup = false;
+ return;
+ }
+
+ FunctionTemplateDecl *FuncTemplate = cast<FunctionTemplateDecl>(Callee);
+ S.AddTemplateOverloadCandidate(FuncTemplate, HasExplicitTemplateArgs,
+ ExplicitTemplateArgs,
+ NumExplicitTemplateArgs,
+ Args, NumArgs, CandidateSet);
+
+ if (FuncTemplate->getDeclContext()->isRecord())
+ ArgumentDependentLookup = false;
+}
+
+/// \brief Add the overload candidates named by callee and/or found by argument
+/// dependent lookup to the given overload set.
+void Sema::AddOverloadedCallCandidates(NamedDecl *Callee,
+ DeclarationName &UnqualifiedName,
+ bool &ArgumentDependentLookup,
+ bool HasExplicitTemplateArgs,
+ const TemplateArgument *ExplicitTemplateArgs,
+ unsigned NumExplicitTemplateArgs,
+ Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet &CandidateSet,
+ bool PartialOverloading) {
// 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:
@@ -3783,66 +4339,75 @@ FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee,
// 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 declaration of a class member, or
//
// -- a block-scope function declaration that is not a
- // using-declaration, or
- //
+ // using-declaration (FIXME: check for 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)) {
+ // then Y is empty.
+ if (!Callee) {
+ // Nothing to do.
+ } else if (OverloadedFunctionDecl *Ovl
+ = dyn_cast<OverloadedFunctionDecl>(Callee)) {
for (OverloadedFunctionDecl::function_iterator Func = Ovl->function_begin(),
FuncEnd = Ovl->function_end();
- Func != FuncEnd; ++Func) {
- DeclContext *Ctx = 0;
- if (FunctionDecl *FunDecl = dyn_cast<FunctionDecl>(*Func)) {
- if (HasExplicitTemplateArgs)
- continue;
-
- AddOverloadCandidate(FunDecl, Args, NumArgs, CandidateSet);
- Ctx = FunDecl->getDeclContext();
- } else {
- FunctionTemplateDecl *FunTmpl = cast<FunctionTemplateDecl>(*Func);
- AddTemplateOverloadCandidate(FunTmpl, HasExplicitTemplateArgs,
- ExplicitTemplateArgs,
- NumExplicitTemplateArgs,
- Args, NumArgs, CandidateSet);
- Ctx = FunTmpl->getDeclContext();
- }
-
-
- if (Ctx->isRecord() || Ctx->isFunctionOrMethod())
- ArgumentDependentLookup = false;
- }
- } else if (FunctionDecl *Func = dyn_cast_or_null<FunctionDecl>(Callee)) {
- assert(!HasExplicitTemplateArgs && "Explicit template arguments?");
- AddOverloadCandidate(Func, Args, NumArgs, CandidateSet);
-
- if (Func->getDeclContext()->isRecord() ||
- Func->getDeclContext()->isFunctionOrMethod())
- ArgumentDependentLookup = false;
- } else if (FunctionTemplateDecl *FuncTemplate
- = dyn_cast_or_null<FunctionTemplateDecl>(Callee)) {
- AddTemplateOverloadCandidate(FuncTemplate, HasExplicitTemplateArgs,
- ExplicitTemplateArgs,
- NumExplicitTemplateArgs,
- Args, NumArgs, CandidateSet);
-
- if (FuncTemplate->getDeclContext()->isRecord())
- ArgumentDependentLookup = false;
- }
-
+ Func != FuncEnd; ++Func)
+ AddOverloadedCallCandidate(*this, *Func, ArgumentDependentLookup,
+ HasExplicitTemplateArgs,
+ ExplicitTemplateArgs, NumExplicitTemplateArgs,
+ Args, NumArgs, CandidateSet,
+ PartialOverloading);
+ } else if (isa<FunctionDecl>(Callee) || isa<FunctionTemplateDecl>(Callee))
+ AddOverloadedCallCandidate(*this,
+ AnyFunctionDecl::getFromNamedDecl(Callee),
+ ArgumentDependentLookup,
+ HasExplicitTemplateArgs,
+ ExplicitTemplateArgs, NumExplicitTemplateArgs,
+ Args, NumArgs, CandidateSet,
+ PartialOverloading);
+ // FIXME: assert isa<FunctionDecl> || isa<FunctionTemplateDecl> rather than
+ // checking dynamically.
+
if (Callee)
UnqualifiedName = Callee->getDeclName();
-
- // FIXME: Pass explicit template arguments through for ADL
+
if (ArgumentDependentLookup)
AddArgumentDependentLookupCandidates(UnqualifiedName, Args, NumArgs,
- CandidateSet);
+ HasExplicitTemplateArgs,
+ ExplicitTemplateArgs,
+ NumExplicitTemplateArgs,
+ CandidateSet,
+ PartialOverloading);
+}
+
+/// 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,
+ bool HasExplicitTemplateArgs,
+ const TemplateArgument *ExplicitTemplateArgs,
+ unsigned NumExplicitTemplateArgs,
+ 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.
+ AddOverloadedCallCandidates(Callee, UnqualifiedName, ArgumentDependentLookup,
+ HasExplicitTemplateArgs, ExplicitTemplateArgs,
+ NumExplicitTemplateArgs, Args, NumArgs,
+ CandidateSet);
OverloadCandidateSet::iterator Best;
switch (BestViableFunction(CandidateSet, Fn->getLocStart(), Best)) {
case OR_Success:
@@ -3897,7 +4462,7 @@ FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee,
Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc,
unsigned OpcIn,
FunctionSet &Functions,
- ExprArg input) {
+ ExprArg input) {
UnaryOperator::Opcode Opc = static_cast<UnaryOperator::Opcode>(OpcIn);
Expr *Input = (Expr *)input.get();
@@ -3907,28 +4472,28 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc,
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,
+ Args[1] = new (Context) IntegerLiteral(Zero, Context.IntTy,
SourceLocation());
NumArgs = 2;
}
if (Input->isTypeDependent()) {
- OverloadedFunctionDecl *Overloads
+ OverloadedFunctionDecl *Overloads
= OverloadedFunctionDecl::Create(Context, CurContext, OpName);
- for (FunctionSet::iterator Func = Functions.begin(),
+ 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,
@@ -3954,11 +4519,11 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc,
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))
@@ -3972,19 +4537,24 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc,
}
// Determine the result type
- QualType ResultTy
- = FnDecl->getType()->getAsFunctionType()->getResultType();
- ResultTy = ResultTy.getNonReferenceType();
-
+ QualType ResultTy = FnDecl->getResultType().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));
+
+ ExprOwningPtr<CallExpr> TheCall(this,
+ new (Context) CXXOperatorCallExpr(Context, Op, FnExpr,
+ &Input, 1, ResultTy, OpLoc));
+
+ if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall.get(),
+ FnDecl))
+ return ExprError();
+
+ return MaybeBindToTemporary(TheCall.release());
} else {
// We matched a built-in operator. Convert the arguments, then
// break out so that we will build the appropriate built-in
@@ -4006,7 +4576,8 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc,
Diag(OpLoc, diag::err_ovl_ambiguous_oper)
<< UnaryOperator::getOpcodeStr(Opc)
<< Input->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true,
+ UnaryOperator::getOpcodeStr(Opc), OpLoc);
return ExprError();
case OR_Deleted:
@@ -4042,12 +4613,13 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc,
///
/// \param LHS Left-hand argument.
/// \param RHS Right-hand argument.
-Sema::OwningExprResult
+Sema::OwningExprResult
Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
- unsigned OpcIn,
+ unsigned OpcIn,
FunctionSet &Functions,
Expr *LHS, Expr *RHS) {
Expr *Args[2] = { LHS, RHS };
+ LHS=RHS=0; //Please use only Args instead of LHS/RHS couple
BinaryOperator::Opcode Opc = static_cast<BinaryOperator::Opcode>(OpcIn);
OverloadedOperatorKind Op = BinaryOperator::getOverloadedOperator(Opc);
@@ -4055,24 +4627,24 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// If either side is type-dependent, create an appropriate dependent
// expression.
- if (LHS->isTypeDependent() || RHS->isTypeDependent()) {
+ if (Args[0]->isTypeDependent() || Args[1]->isTypeDependent()) {
// .* cannot be overloaded.
if (Opc == BinaryOperator::PtrMemD)
- return Owned(new (Context) BinaryOperator(LHS, RHS, Opc,
+ return Owned(new (Context) BinaryOperator(Args[0], Args[1], Opc,
Context.DependentTy, OpLoc));
- OverloadedFunctionDecl *Overloads
+ OverloadedFunctionDecl *Overloads
= OverloadedFunctionDecl::Create(Context, CurContext, OpName);
- for (FunctionSet::iterator Func = Functions.begin(),
+ 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,
+ Args, 2,
Context.DependentTy,
OpLoc));
}
@@ -4080,14 +4652,14 @@ Sema::CreateOverloadedBinOp(SourceLocation 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);
+ return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
// 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);
+ !Args[0]->getType()->isOverloadableType())
+ return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
// Build an empty overload set.
OverloadCandidateSet CandidateSet;
@@ -4114,39 +4686,46 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// Convert the arguments.
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
- if (PerformObjectArgumentInitialization(LHS, Method) ||
- PerformCopyInitialization(RHS, FnDecl->getParamDecl(0)->getType(),
+ if (PerformObjectArgumentInitialization(Args[0], Method) ||
+ PerformCopyInitialization(Args[1], FnDecl->getParamDecl(0)->getType(),
"passing"))
return ExprError();
} else {
// Convert the arguments.
- if (PerformCopyInitialization(LHS, FnDecl->getParamDecl(0)->getType(),
+ if (PerformCopyInitialization(Args[0], FnDecl->getParamDecl(0)->getType(),
"passing") ||
- PerformCopyInitialization(RHS, FnDecl->getParamDecl(1)->getType(),
+ PerformCopyInitialization(Args[1], FnDecl->getParamDecl(1)->getType(),
"passing"))
return ExprError();
}
// Determine the result type
QualType ResultTy
- = FnDecl->getType()->getAsFunctionType()->getResultType();
+ = FnDecl->getType()->getAs<FunctionType>()->getResultType();
ResultTy = ResultTy.getNonReferenceType();
// Build the actual expression node.
Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(),
- SourceLocation());
+ OpLoc);
UsualUnaryConversions(FnExpr);
- return Owned(new (Context) CXXOperatorCallExpr(Context, Op, FnExpr,
- Args, 2, ResultTy,
- OpLoc));
+ ExprOwningPtr<CXXOperatorCallExpr>
+ TheCall(this, new (Context) CXXOperatorCallExpr(Context, Op, FnExpr,
+ Args, 2, ResultTy,
+ OpLoc));
+
+ if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall.get(),
+ FnDecl))
+ return ExprError();
+
+ return MaybeBindToTemporary(TheCall.release());
} 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],
+ if (PerformImplicitConversion(Args[0], Best->BuiltinTypes.ParamTypes[0],
Best->Conversions[0], "passing") ||
- PerformImplicitConversion(RHS, Best->BuiltinTypes.ParamTypes[1],
+ PerformImplicitConversion(Args[1], Best->BuiltinTypes.ParamTypes[1],
Best->Conversions[1], "passing"))
return ExprError();
@@ -4154,40 +4733,55 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
}
}
- case OR_No_Viable_Function:
+ case OR_No_Viable_Function: {
+ // C++ [over.match.oper]p9:
+ // If the operator is the operator , [...] and there are no
+ // viable functions, then the operator is assumed to be the
+ // built-in operator and interpreted according to clause 5.
+ if (Opc == BinaryOperator::Comma)
+ break;
+
// 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) {
+ OwningExprResult Result = ExprError();
+ if (Args[0]->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();
+ << Args[0]->getSourceRange() << Args[1]->getSourceRange();
+ } else {
+ // No viable function; try to create a built-in operation, which will
+ // produce an error. Then, show the non-viable candidates.
+ Result = CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
}
- // No viable function; fall through to handling this as a
- // built-in operator, which will produce an error message for us.
- break;
+ assert(Result.isInvalid() &&
+ "C++ binary operator overloading is missing candidates!");
+ if (Result.isInvalid())
+ PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false,
+ BinaryOperator::getOpcodeStr(Opc), OpLoc);
+ return move(Result);
+ }
case OR_Ambiguous:
Diag(OpLoc, diag::err_ovl_ambiguous_oper)
<< BinaryOperator::getOpcodeStr(Opc)
- << LHS->getSourceRange() << RHS->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ << Args[0]->getSourceRange() << Args[1]->getSourceRange();
+ PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true,
+ BinaryOperator::getOpcodeStr(Opc), OpLoc);
return ExprError();
case OR_Deleted:
Diag(OpLoc, diag::err_ovl_deleted_oper)
<< Best->Function->isDeleted()
<< BinaryOperator::getOpcodeStr(Opc)
- << LHS->getSourceRange() << RHS->getSourceRange();
+ << Args[0]->getSourceRange() << Args[1]->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);
+ // We matched a built-in operator; build it.
+ return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
}
/// BuildCallToMemberFunction - Build a call to a member
@@ -4198,8 +4792,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
/// expression refers to a member function or an overloaded member
/// function.
Sema::ExprResult
-Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
- SourceLocation LParenLoc, Expr **Args,
+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
@@ -4215,17 +4809,25 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
Expr *ObjectArg = MemExpr->getBase();
CXXMethodDecl *Method = 0;
- if (OverloadedFunctionDecl *Ovl
- = dyn_cast<OverloadedFunctionDecl>(MemExpr->getMemberDecl())) {
+ if (isa<OverloadedFunctionDecl>(MemExpr->getMemberDecl()) ||
+ isa<FunctionTemplateDecl>(MemExpr->getMemberDecl())) {
// Add overload candidates
OverloadCandidateSet CandidateSet;
- for (OverloadedFunctionDecl::function_iterator Func = Ovl->function_begin(),
- FuncEnd = Ovl->function_end();
+ DeclarationName DeclName = MemExpr->getMemberDecl()->getDeclName();
+
+ for (OverloadIterator Func(MemExpr->getMemberDecl()), FuncEnd;
Func != FuncEnd; ++Func) {
- assert(isa<CXXMethodDecl>(*Func) && "Function is not a method");
- Method = cast<CXXMethodDecl>(*Func);
- AddMethodCandidate(Method, ObjectArg, Args, NumArgs, CandidateSet,
- /*SuppressUserConversions=*/false);
+ if ((Method = dyn_cast<CXXMethodDecl>(*Func)))
+ AddMethodCandidate(Method, ObjectArg, Args, NumArgs, CandidateSet,
+ /*SuppressUserConversions=*/false);
+ else
+ AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(*Func),
+ MemExpr->hasExplicitTemplateArgumentList(),
+ MemExpr->getTemplateArgs(),
+ MemExpr->getNumTemplateArgs(),
+ ObjectArg, Args, NumArgs,
+ CandidateSet,
+ /*SuppressUsedConversions=*/false);
}
OverloadCandidateSet::iterator Best;
@@ -4235,26 +4837,26 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
break;
case OR_No_Viable_Function:
- Diag(MemExpr->getSourceRange().getBegin(),
+ Diag(MemExpr->getSourceRange().getBegin(),
diag::err_ovl_no_viable_member_function_in_call)
- << Ovl->getDeclName() << MemExprE->getSourceRange();
+ << DeclName << MemExprE->getSourceRange();
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
// FIXME: Leaking incoming expressions!
return true;
case OR_Ambiguous:
- Diag(MemExpr->getSourceRange().getBegin(),
+ Diag(MemExpr->getSourceRange().getBegin(),
diag::err_ovl_ambiguous_member_call)
- << Ovl->getDeclName() << MemExprE->getSourceRange();
+ << DeclName << MemExprE->getSourceRange();
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
// FIXME: Leaking incoming expressions!
return true;
case OR_Deleted:
- Diag(MemExpr->getSourceRange().getBegin(),
+ Diag(MemExpr->getSourceRange().getBegin(),
diag::err_ovl_deleted_member_call)
<< Best->Function->isDeleted()
- << Ovl->getDeclName() << MemExprE->getSourceRange();
+ << DeclName << MemExprE->getSourceRange();
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
// FIXME: Leaking incoming expressions!
return true;
@@ -4266,43 +4868,51 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
}
assert(Method && "Member call to something that isn't a method?");
- ExprOwningPtr<CXXMemberCallExpr>
+ ExprOwningPtr<CXXMemberCallExpr>
TheCall(this, new (Context) CXXMemberCallExpr(Context, MemExpr, Args,
- NumArgs,
+ NumArgs,
Method->getResultType().getNonReferenceType(),
RParenLoc));
+ // Check for a valid return type.
+ if (CheckCallReturnType(Method->getResultType(), MemExpr->getMemberLoc(),
+ TheCall.get(), Method))
+ return true;
+
// Convert the object argument (for a non-static member function call).
- if (!Method->isStatic() &&
+ 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,
+ if (ConvertArgumentsForCall(&*TheCall, MemExpr, Method, Proto, Args, NumArgs,
RParenLoc))
return true;
- return CheckFunctionCall(Method, TheCall.take()).release();
+ if (CheckFunctionCall(Method, TheCall.get()))
+ return true;
+
+ return MaybeBindToTemporary(TheCall.release()).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,
+Sema::ExprResult
+Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
SourceLocation LParenLoc,
Expr **Args, unsigned NumArgs,
- SourceLocation *CommaLocs,
+ SourceLocation *CommaLocs,
SourceLocation RParenLoc) {
assert(Object->getType()->isRecordType() && "Requires object type argument");
- const RecordType *Record = Object->getType()->getAsRecordType();
-
+ const RecordType *Record = Object->getType()->getAs<RecordType>();
+
// 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
+ // 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
@@ -4312,7 +4922,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
DeclContext::lookup_const_iterator Oper, OperEnd;
for (llvm::tie(Oper, OperEnd) = Record->getDecl()->lookup(OpName);
Oper != OperEnd; ++Oper)
- AddMethodCandidate(cast<CXXMethodDecl>(*Oper), Object, Args, NumArgs,
+ AddMethodCandidate(cast<CXXMethodDecl>(*Oper), Object, Args, NumArgs,
CandidateSet, /*SuppressUserConversions=*/false);
// C++ [over.call.object]p2:
@@ -4332,24 +4942,33 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
// 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 (!RequireCompleteType(SourceLocation(), Object->getType(), 0)) {
+ // 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;
+ FunctionTemplateDecl *ConvTemplate;
+ GetFunctionAndTemplate(*Func, Conv, ConvTemplate);
+
+ // Skip over templated conversion functions; they aren't
+ // surrogates.
+ if (ConvTemplate)
+ continue;
+
+ // Strip the reference type (if any) and then the pointer type (if
+ // any) to get down to what might be a function type.
+ QualType ConvType = Conv->getConversionType().getNonReferenceType();
+ if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>())
+ ConvType = ConvPtrType->getPointeeType();
- if (const FunctionProtoType *Proto = ConvType->getAsFunctionProtoType())
- AddSurrogateCandidate(Conv, Proto, Object, Args, NumArgs, CandidateSet);
+ if (const FunctionProtoType *Proto = ConvType->getAs<FunctionProtoType>())
+ AddSurrogateCandidate(Conv, Proto, Object, Args, NumArgs, CandidateSet);
+ }
}
// Perform overload resolution.
@@ -4361,7 +4980,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
break;
case OR_No_Viable_Function:
- Diag(Object->getSourceRange().getBegin(),
+ Diag(Object->getSourceRange().getBegin(),
diag::err_ovl_no_viable_object_call)
<< Object->getType() << Object->getSourceRange();
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
@@ -4381,7 +5000,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
<< Object->getType() << Object->getSourceRange();
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
break;
- }
+ }
if (Best == CandidateSet.end()) {
// We had an error; delete all of the subexpressions and return
@@ -4395,18 +5014,20 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
if (Best->Function == 0) {
// Since there is no function declaration, this is one of the
// surrogate candidates. Dig out the conversion function.
- CXXConversionDecl *Conv
+ 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,
+
+ // Create an implicit member expr to refer to the conversion operator.
+ // and then call it.
+ CXXMemberCallExpr *CE =
+ BuildCXXMemberCallExpr(Object, Conv);
+
+ return ActOnCallExpr(S, ExprArg(*this, CE), LParenLoc,
MultiExprArg(*this, (ExprTy**)Args, NumArgs),
CommaLocs, RParenLoc).release();
}
@@ -4415,7 +5036,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
// 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();
+ const FunctionProtoType *Proto = Method->getType()->getAs<FunctionProtoType>();
unsigned NumArgsInProto = Proto->getNumArgs();
unsigned NumArgsToCheck = NumArgs;
@@ -4433,20 +5054,24 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
MethodArgs[0] = Object;
for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx)
MethodArgs[ArgIdx + 1] = Args[ArgIdx];
-
- Expr *NewFn = new (Context) DeclRefExpr(Method, Method->getType(),
+
+ 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,
+ ExprOwningPtr<CXXOperatorCallExpr>
+ TheCall(this, new (Context) CXXOperatorCallExpr(Context, OO_Call, NewFn,
MethodArgs, NumArgs + 1,
ResultTy, RParenLoc));
delete [] MethodArgs;
+ if (CheckCallReturnType(Method->getResultType(), LParenLoc, TheCall.get(),
+ Method))
+ return true;
+
// We may have default arguments. If so, we need to allocate more
// slots in the call for them.
if (NumArgs < NumArgsInProto)
@@ -4466,12 +5091,12 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
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));
+ Arg = CXXDefaultArgExpr::Create(Context, Method->getParamDecl(i));
}
TheCall->setArg(i + 1, Arg);
@@ -4489,37 +5114,38 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
if (IsError) return true;
- return CheckFunctionCall(Method, TheCall.take()).release();
+ if (CheckFunctionCall(Method, TheCall.get()))
+ return true;
+
+ return MaybeBindToTemporary(TheCall.release()).release();
}
/// BuildOverloadedArrowExpr - Build a call to an overloaded @c operator->
-/// (if one exists), where @c Base is an expression of class type and
+/// (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) {
+Sema::OwningExprResult
+Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) {
+ Expr *Base = static_cast<Expr *>(BaseIn.get());
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(OpName); Oper != OperEnd; ++Oper)
+ const RecordType *BaseRecord = Base->getType()->getAs<RecordType>();
+
+ LookupResult R;
+ LookupQualifiedName(R, BaseRecord->getDecl(), OpName, LookupOrdinaryName);
+
+ for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end();
+ 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, OpLoc, Best)) {
@@ -4530,44 +5156,49 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
case OR_No_Viable_Function:
if (CandidateSet.empty())
Diag(OpLoc, diag::err_typecheck_member_reference_arrow)
- << BasePtr->getType() << BasePtr->getSourceRange();
+ << Base->getType() << Base->getSourceRange();
else
Diag(OpLoc, diag::err_ovl_no_viable_oper)
- << "operator->" << BasePtr->getSourceRange();
+ << "operator->" << Base->getSourceRange();
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
- return true;
+ return ExprError();
case OR_Ambiguous:
Diag(OpLoc, diag::err_ovl_ambiguous_oper)
- << "operator->" << BasePtr->getSourceRange();
+ << "->" << Base->getSourceRange();
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
- return true;
+ return ExprError();
case OR_Deleted:
Diag(OpLoc, diag::err_ovl_deleted_oper)
<< Best->Function->isDeleted()
- << "operator->" << BasePtr->getSourceRange();
+ << "->" << Base->getSourceRange();
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
- return true;
+ return ExprError();
}
// Convert the object parameter.
CXXMethodDecl *Method = cast<CXXMethodDecl>(Best->Function);
if (PerformObjectArgumentInitialization(Base, Method))
- return true;
+ return ExprError();
// No concerns about early exits now.
- BasePtr.take();
+ BaseIn.release();
// 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();
+
+ QualType ResultTy = Method->getResultType().getNonReferenceType();
+ ExprOwningPtr<CXXOperatorCallExpr>
+ TheCall(this, new (Context) CXXOperatorCallExpr(Context, OO_Arrow, FnExpr,
+ &Base, 1, ResultTy, OpLoc));
+
+ if (CheckCallReturnType(Method->getResultType(), OpLoc, TheCall.get(),
+ Method))
+ return ExprError();
+ return move(TheCall);
}
/// FixOverloadedFunctionReference - E is an expression that refers to
@@ -4580,14 +5211,13 @@ void Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) {
FixOverloadedFunctionReference(PE->getSubExpr(), Fn);
E->setType(PE->getSubExpr()->getType());
} else if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(E)) {
- assert(UnOp->getOpcode() == UnaryOperator::AddrOf &&
+ 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
+ } 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
@@ -4596,7 +5226,7 @@ void Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) {
DRE->setType(Fn->getType());
QualType ClassType
= Context.getTypeDeclType(cast<RecordDecl>(Method->getDeclContext()));
- E->setType(Context.getMemberPointerType(Fn->getType(),
+ E->setType(Context.getMemberPointerType(Fn->getType(),
ClassType.getTypePtr()));
return;
}
@@ -4604,8 +5234,9 @@ void Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) {
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");
+ assert((isa<OverloadedFunctionDecl>(DR->getDecl()) ||
+ isa<FunctionTemplateDecl>(DR->getDecl())) &&
+ "Expected overloaded function or function template");
DR->setDecl(Fn);
E->setType(Fn->getType());
} else if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(E)) {
diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h
index 9de3806..898393a 100644
--- a/lib/Sema/SemaOverload.h
+++ b/lib/Sema/SemaOverload.h
@@ -59,7 +59,7 @@ namespace clang {
ICC_Conversion ///< Conversion
};
- ImplicitConversionCategory
+ ImplicitConversionCategory
GetConversionCategory(ImplicitConversionKind Kind);
/// ImplicitConversionRank - The rank of an implicit conversion
@@ -98,7 +98,7 @@ namespace clang {
ImplicitConversionKind Third : 8;
/// Deprecated - Whether this the deprecated conversion of a
- /// string literal to a pointer to non-const character data
+ /// string literal to a pointer to non-const character data
/// (C++ 4.2p2).
bool Deprecated : 1;
@@ -106,11 +106,11 @@ namespace clang {
/// that we should warn about (if we actually use it).
bool IncompatibleObjC : 1;
- /// ReferenceBinding - True when this is a reference binding
+ /// 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
+ /// DirectBinding - True when this is a reference binding that is a
/// direct binding (C++ [dcl.init.ref]).
bool DirectBinding : 1;
@@ -134,7 +134,7 @@ namespace clang {
/// conversions.
CXXConstructorDecl *CopyConstructor;
- void setAsIdentityConversion();
+ void setAsIdentityConversion();
ImplicitConversionRank getRank() const;
bool isPointerConversionToBool() const;
bool isPointerConversionToVoidPointer(ASTContext& Context) const;
@@ -159,7 +159,7 @@ namespace clang {
/// 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;
@@ -168,7 +168,7 @@ namespace clang {
};
/// ImplicitConversionSequence - Represents an implicit conversion
- /// sequence, which may be a standard conversion sequence
+ /// 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 {
@@ -195,7 +195,11 @@ namespace clang {
/// details of the user-defined conversion sequence.
UserDefinedConversionSequence UserDefined;
};
-
+
+ /// When ConversionKind == BadConversion due to multiple conversion
+ /// functions, this will list those functions.
+ llvm::SmallVector<FunctionDecl*, 4> ConversionFunctionSet;
+
// The result of a comparison between implicit conversion
// sequences. Use Sema::CompareImplicitConversionSequences to
// actually perform the comparison.
@@ -211,8 +215,8 @@ namespace clang {
/// 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
+ /// 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;
@@ -222,7 +226,7 @@ namespace clang {
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;
@@ -257,7 +261,16 @@ namespace clang {
/// OverloadCandidateSet - A set of overload candidates, used in C++
/// overload resolution (C++ 13.3).
- typedef llvm::SmallVector<OverloadCandidate, 16> OverloadCandidateSet;
+ class OverloadCandidateSet : public llvm::SmallVector<OverloadCandidate, 16> {
+ llvm::SmallPtrSet<Decl *, 16> Functions;
+
+ public:
+ /// \brief Determine when this overload candidate will be new to the
+ /// overload set.
+ bool isNewCandidate(Decl *F) {
+ return Functions.insert(F->getCanonicalDecl());
+ }
+ };
} // end namespace clang
#endif // LLVM_CLANG_SEMA_OVERLOAD_H
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 63191e0..e8cd6b0 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -15,16 +15,26 @@
#include "clang/AST/APValue.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
-#include "clang/AST/Expr.h"
+#include "clang/AST/ExprObjC.h"
#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtCXX.h"
#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
using namespace clang;
Sema::OwningStmtResult Sema::ActOnExprStmt(FullExprArg expr) {
Expr *E = expr->takeAs<Expr>();
assert(E && "ActOnExprStmt(): missing expression");
-
+ if (E->getType()->isObjCInterfaceType()) {
+ if (LangOpts.ObjCNonFragileABI)
+ Diag(E->getLocEnd(), diag::err_indirection_requires_nonfragile_object)
+ << E->getType();
+ else
+ Diag(E->getLocEnd(), diag::err_direct_interface_unsupported)
+ << E->getType();
+ return StmtError();
+ }
// 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.
@@ -42,13 +52,57 @@ 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));
}
+void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
+ const Expr *E = dyn_cast_or_null<Expr>(S);
+ if (!E)
+ return;
+
+ // Ignore expressions that have void type.
+ if (E->getType()->isVoidType())
+ return;
+
+ SourceLocation Loc;
+ SourceRange R1, R2;
+ if (!E->isUnusedResultAWarning(Loc, R1, R2))
+ return;
+
+ // Okay, we have an unused result. Depending on what the base expression is,
+ // we might want to make a more specific diagnostic. Check for one of these
+ // cases now.
+ unsigned DiagID = diag::warn_unused_expr;
+ E = E->IgnoreParens();
+ if (isa<ObjCImplicitSetterGetterRefExpr>(E))
+ DiagID = diag::warn_unused_property_expr;
+
+ if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
+ // If the callee has attribute pure, const, or warn_unused_result, warn with
+ // a more specific message to make it clear what is happening.
+ if (const FunctionDecl *FD = CE->getDirectCallee()) {
+ if (FD->getAttr<WarnUnusedResultAttr>()) {
+ Diag(Loc, diag::warn_unused_call) << R1 << R2 << "warn_unused_result";
+ return;
+ }
+ if (FD->getAttr<PureAttr>()) {
+ Diag(Loc, diag::warn_unused_call) << R1 << R2 << "pure";
+ return;
+ }
+ if (FD->getAttr<ConstAttr>()) {
+ Diag(Loc, diag::warn_unused_call) << R1 << R2 << "const";
+ return;
+ }
+ }
+ }
+
+ Diag(Loc, DiagID) << R1 << R2;
+}
+
Action::OwningStmtResult
Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R,
MultiStmtArg elts, bool isStmtExpr) {
@@ -66,7 +120,7 @@ Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R,
// 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);
@@ -74,20 +128,11 @@ Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R,
}
// 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))
+ // Ignore statements that are last in a statement expression.
+ if (isStmtExpr && i == NumElts - 1)
continue;
- Diag(Loc, diag::warn_unused_expr) << R1 << R2;
+ DiagnoseUnusedExprResult(Elts[i]);
}
return Owned(new (Context) CompoundStmt(Context, Elts, NumElts, L, R));
@@ -100,9 +145,9 @@ Sema::ActOnCaseStmt(SourceLocation CaseLoc, ExprArg lhsval,
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.
+ // However, GCC allows any evaluatable integer expression.
Expr *LHSVal = static_cast<Expr*>(lhsval.get());
- if (!LHSVal->isTypeDependent() && !LHSVal->isValueDependent() &&
+ if (!LHSVal->isTypeDependent() && !LHSVal->isValueDependent() &&
VerifyIntegerConstantExpression(LHSVal))
return StmtError();
@@ -137,7 +182,7 @@ void Sema::ActOnCaseStmtBody(StmtTy *caseStmt, StmtArg subStmt) {
}
Action::OwningStmtResult
-Sema::ActOnDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc,
+Sema::ActOnDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc,
StmtArg subStmt, Scope *CurScope) {
Stmt *SubStmt = subStmt.takeAs<Stmt>();
@@ -184,40 +229,33 @@ 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.
+ if (CheckBooleanCondition(condExpr, IfLoc)) {
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());
+ return StmtError();
}
Stmt *thenStmt = ThenVal.takeAs<Stmt>();
+ DiagnoseUnusedExprResult(thenStmt);
// 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 (!ElseVal.get()) {
if (NullStmt* stmt = dyn_cast<NullStmt>(thenStmt))
Diag(stmt->getSemiLoc(), diag::warn_empty_if_body);
}
+ Stmt *elseStmt = ElseVal.takeAs<Stmt>();
+ DiagnoseUnusedExprResult(elseStmt);
+
CondResult.release();
return Owned(new (Context) IfStmt(IfLoc, condExpr, thenStmt,
- ElseLoc, ElseVal.takeAs<Stmt>()));
+ ElseLoc, elseStmt));
}
Action::OwningStmtResult
@@ -234,9 +272,9 @@ Sema::ActOnStartOfSwitchStmt(ExprArg cond) {
// 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()) {
@@ -260,19 +298,19 @@ Sema::ActOnStartOfSwitchStmt(ExprArg cond) {
/// the specified diagnostic.
void Sema::ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &Val,
unsigned NewWidth, bool NewSign,
- SourceLocation Loc,
+ 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.
@@ -283,7 +321,7 @@ void Sema::ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &Val,
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);
@@ -293,7 +331,7 @@ void Sema::ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &Val,
// 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);
}
@@ -339,12 +377,12 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
assert(SS == (SwitchStmt*)Switch.get() && "switch stack missing push/pop!");
SS->setBody(BodyStmt, SwitchLoc);
- getSwitchStack().pop_back();
+ getSwitchStack().pop_back();
Expr *CondExpr = SS->getCond();
QualType CondType = CondExpr->getType();
- if (!CondExpr->isTypeDependent() &&
+ if (!CondExpr->isTypeDependent() &&
!CondType->isIntegerType()) { // C99 6.8.4.2p1
Diag(SwitchLoc, diag::err_typecheck_statement_requires_integer)
<< CondType << CondExpr->getSourceRange();
@@ -353,29 +391,29 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
// Get the bitwidth of the switched-on value before promotions. We must
// convert the integer case values to this width before comparison.
- bool HasDependentValue
+ bool HasDependentValue
= CondExpr->isTypeDependent() || CondExpr->isValueDependent();
- unsigned CondWidth
+ 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);
@@ -388,10 +426,10 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
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();
@@ -400,9 +438,9 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
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(),
@@ -412,16 +450,16 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
// 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() ||
+ if (CS->getRHS()->isTypeDependent() ||
CS->getRHS()->isValueDependent()) {
HasDependentValue = true;
break;
}
CaseRanges.push_back(std::make_pair(LoVal, CS));
- } else
+ } else
CaseVals.push_back(std::make_pair(LoVal, CS));
}
}
@@ -436,7 +474,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
// 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(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.
@@ -444,31 +482,31 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
}
}
}
-
+
// 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)
@@ -480,7 +518,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
}
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.
@@ -488,12 +526,12 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
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(),
@@ -503,26 +541,26 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
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(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.
@@ -547,23 +585,16 @@ Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond, StmtArg Body) {
Expr *condExpr = CondArg.takeAs<Expr>();
assert(condExpr && "ActOnWhileStmt(): missing expression");
- if (!condExpr->isTypeDependent()) {
- DefaultFunctionArrayConversion(condExpr);
+ if (CheckBooleanCondition(condExpr, WhileLoc)) {
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());
+ return StmtError();
}
+ Stmt *bodyStmt = Body.takeAs<Stmt>();
+ DiagnoseUnusedExprResult(bodyStmt);
+
CondArg.release();
- return Owned(new (Context) WhileStmt(condExpr, Body.takeAs<Stmt>(),
- WhileLoc));
+ return Owned(new (Context) WhileStmt(condExpr, bodyStmt, WhileLoc));
}
Action::OwningStmtResult
@@ -573,22 +604,16 @@ Sema::ActOnDoStmt(SourceLocation DoLoc, StmtArg Body,
Expr *condExpr = Cond.takeAs<Expr>();
assert(condExpr && "ActOnDoStmt(): missing expression");
- if (!condExpr->isTypeDependent()) {
- DefaultFunctionArrayConversion(condExpr);
+ if (CheckBooleanCondition(condExpr, DoLoc)) {
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());
+ return StmtError();
}
+ Stmt *bodyStmt = Body.takeAs<Stmt>();
+ DiagnoseUnusedExprResult(bodyStmt);
+
Cond.release();
- return Owned(new (Context) DoStmt(Body.takeAs<Stmt>(), condExpr, DoLoc,
+ return Owned(new (Context) DoStmt(bodyStmt, condExpr, DoLoc,
WhileLoc, CondRParen));
}
@@ -597,7 +622,7 @@ 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 *Second = second.takeAs<Expr>();
Expr *Third = static_cast<Expr*>(third.get());
Stmt *Body = static_cast<Stmt*>(body.get());
@@ -617,20 +642,16 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
}
}
}
- 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());
+ if (Second && CheckBooleanCondition(Second, ForLoc)) {
+ second = Second;
+ return StmtError();
}
+
+ DiagnoseUnusedExprResult(First);
+ DiagnoseUnusedExprResult(Third);
+ DiagnoseUnusedExprResult(Body);
+
first.release();
- second.release();
third.release();
body.release();
return Owned(new (Context) ForStmt(First, Second, Third, Body, ForLoc,
@@ -667,16 +688,17 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc,
diag::err_selector_element_not_lvalue)
<< First->getSourceRange());
- FirstType = static_cast<Expr*>(First)->getType();
+ FirstType = static_cast<Expr*>(First)->getType();
}
- if (!Context.isObjCObjectPointerType(FirstType))
+ if (!FirstType->isObjCObjectPointerType() &&
+ !FirstType->isBlockPointerType())
Diag(ForLoc, diag::err_selector_element_type)
<< FirstType << First->getSourceRange();
}
if (Second) {
DefaultFunctionArrayConversion(Second);
QualType SecondType = Second->getType();
- if (!Context.isObjCObjectPointerType(SecondType))
+ if (!SecondType->isObjCObjectPointerType())
Diag(ForLoc, diag::err_collection_expr_type)
<< SecondType << Second->getSourceRange();
}
@@ -791,8 +813,8 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// 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
+ // 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.
@@ -834,8 +856,8 @@ static bool IsReturnCopyElidable(ASTContext &Ctx, QualType RetType,
}
Action::OwningStmtResult
-Sema::ActOnReturnStmt(SourceLocation ReturnLoc, FullExprArg rex) {
- Expr *RetValExp = rex->takeAs<Expr>();
+Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) {
+ Expr *RetValExp = rex.takeAs<Expr>();
if (CurBlock)
return ActOnBlockReturnStmt(ReturnLoc, RetValExp);
@@ -849,9 +871,10 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, FullExprArg rex) {
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)
+ if (RetValExp && !RetValExp->isTypeDependent()) {
+ // 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;
@@ -864,6 +887,8 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, FullExprArg rex) {
<< CurDecl->getDeclName() << isa<ObjCMethodDecl>(CurDecl)
<< RetValExp->getSourceRange();
}
+
+ RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp, true);
}
return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp));
}
@@ -883,8 +908,8 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, FullExprArg rex) {
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
+ // 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
@@ -912,6 +937,8 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, FullExprArg rex) {
if (RetValExp) CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
}
+ if (RetValExp)
+ RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp, true);
return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp));
}
@@ -964,7 +991,7 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
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)
@@ -976,7 +1003,7 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
<< Literal->getSourceRange());
- TargetInfo::ConstraintInfo Info(Literal->getStrData(),
+ TargetInfo::ConstraintInfo Info(Literal->getStrData(),
Literal->getByteLength(),
Names[i]);
if (!Context.Target.validateOutputConstraint(Info))
@@ -991,7 +1018,7 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
diag::err_asm_invalid_lvalue_in_output)
<< OutputExpr->getSourceRange());
}
-
+
OutputConstraintInfos.push_back(Info);
}
@@ -1003,7 +1030,7 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
<< Literal->getSourceRange());
- TargetInfo::ConstraintInfo Info(Literal->getStrData(),
+ TargetInfo::ConstraintInfo Info(Literal->getStrData(),
Literal->getByteLength(),
Names[i]);
if (!Context.Target.validateInputConstraint(OutputConstraintInfos.data(),
@@ -1028,13 +1055,13 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
if (InputExpr->getType()->isVoidType()) {
return StmtError(Diag(InputExpr->getLocStart(),
diag::err_asm_invalid_type_in_input)
- << InputExpr->getType() << Info.getConstraintStr()
+ << InputExpr->getType() << Info.getConstraintStr()
<< InputExpr->getSourceRange());
}
}
-
+
DefaultFunctionArrayConversion(Exprs[i]);
-
+
InputConstraintInfos.push_back(Info);
}
@@ -1045,13 +1072,13 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
<< Literal->getSourceRange());
- llvm::SmallString<16> Clobber(Literal->getStrData(),
- Literal->getStrData() +
- Literal->getByteLength());
+ std::string 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());
+ diag::err_asm_unknown_register_name) << Clobber);
}
constraints.release();
@@ -1072,16 +1099,16 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
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];
@@ -1089,11 +1116,11 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
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*.
@@ -1101,7 +1128,7 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
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.
@@ -1109,7 +1136,7 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
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) {
@@ -1128,7 +1155,7 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
}
}
}
-
+
// 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.
@@ -1136,7 +1163,7 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
OutputConstraintInfos[TiedTo].allowsRegister())
continue;
}
-
+
Diag(InputExpr->getLocStart(),
diag::err_asm_tying_incompatible_types)
<< InTy << OutTy << OutputExpr->getSourceRange()
@@ -1144,7 +1171,7 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
DeleteStmt(NS);
return StmtError();
}
-
+
return Owned(NS);
}
@@ -1154,18 +1181,18 @@ Sema::ActOnObjCAtCatchStmt(SourceLocation AtLoc,
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(),
+
+ if (!PVD->getType()->isObjCObjectPointerType())
+ return StmtError(Diag(PVD->getLocation(),
diag::err_catch_param_not_objc_type));
if (PVD->getType()->isObjCQualifiedIdType())
- return StmtError(Diag(PVD->getLocation(),
+ return StmtError(Diag(PVD->getLocation(),
diag::err_illegal_qualifiers_on_catch_parm));
}
@@ -1203,8 +1230,8 @@ Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, ExprArg expr,Scope *CurScope) {
} 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 (!ThrowType->isObjCObjectPointerType()) {
+ const PointerType *PT = ThrowType->getAs<PointerType>();
if (!PT || !PT->getPointeeType()->isVoidType())
return StmtError(Diag(AtLoc, diag::error_objc_throw_expects_object)
<< ThrowExpr->getType() << ThrowExpr->getSourceRange());
@@ -1220,14 +1247,14 @@ Sema::ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, ExprArg SynchExpr,
// 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 (!SyncExpr->getType()->isObjCObjectPointerType()) {
+ const PointerType *PT = SyncExpr->getType()->getAs<PointerType>();
if (!PT || !PT->getPointeeType()->isVoidType())
return StmtError(Diag(AtLoc, diag::error_objc_synchronized_expects_object)
<< SyncExpr->getType() << SyncExpr->getSourceRange());
}
-
- return Owned(new (Context) ObjCAtSynchronizedStmt(AtLoc,
+
+ return Owned(new (Context) ObjCAtSynchronizedStmt(AtLoc,
SynchExpr.takeAs<Stmt>(),
SynchBody.takeAs<Stmt>()));
}
@@ -1243,6 +1270,35 @@ Sema::ActOnCXXCatchBlock(SourceLocation CatchLoc, DeclPtrTy ExDecl,
HandlerBlock.takeAs<Stmt>()));
}
+class TypeWithHandler {
+ QualType t;
+ CXXCatchStmt *stmt;
+public:
+ TypeWithHandler(const QualType &type, CXXCatchStmt *statement)
+ : t(type), stmt(statement) {}
+
+ // An arbitrary order is fine as long as it places identical
+ // types next to each other.
+ bool operator<(const TypeWithHandler &y) const {
+ if (t.getAsOpaquePtr() < y.t.getAsOpaquePtr())
+ return true;
+ if (t.getAsOpaquePtr() > y.t.getAsOpaquePtr())
+ return false;
+ else
+ return getTypeSpecStartLoc() < y.getTypeSpecStartLoc();
+ }
+
+ bool operator==(const TypeWithHandler& other) const {
+ return t == other.t;
+ }
+
+ QualType getQualType() const { return t; }
+ CXXCatchStmt *getCatchStmt() const { return stmt; }
+ SourceLocation getTypeSpecStartLoc() const {
+ return stmt->getExceptionDecl()->getTypeSpecStartLoc();
+ }
+};
+
/// ActOnCXXTryBlock - Takes a try compound-statement and a number of
/// handlers and creates a try statement from them.
Action::OwningStmtResult
@@ -1253,13 +1309,44 @@ Sema::ActOnCXXTryBlock(SourceLocation TryLoc, StmtArg TryBlock,
"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) {
+ llvm::SmallVector<TypeWithHandler, 8> TypesWithHandlers;
+
+ for (unsigned i = 0; i < NumHandlers; ++i) {
CXXCatchStmt *Handler = llvm::cast<CXXCatchStmt>(Handlers[i]);
- if (!Handler->getExceptionDecl())
- return StmtError(Diag(Handler->getLocStart(), diag::err_early_catch_all));
+ if (!Handler->getExceptionDecl()) {
+ if (i < NumHandlers - 1)
+ return StmtError(Diag(Handler->getLocStart(),
+ diag::err_early_catch_all));
+
+ continue;
+ }
+
+ const QualType CaughtType = Handler->getCaughtType();
+ const QualType CanonicalCaughtType = Context.getCanonicalType(CaughtType);
+ TypesWithHandlers.push_back(TypeWithHandler(CanonicalCaughtType, Handler));
}
- // FIXME: We should detect handlers for the same type as an earlier one.
- // This one is rather easy.
+
+ // Detect handlers for the same type as an earlier one.
+ if (NumHandlers > 1) {
+ llvm::array_pod_sort(TypesWithHandlers.begin(), TypesWithHandlers.end());
+
+ TypeWithHandler prev = TypesWithHandlers[0];
+ for (unsigned i = 1; i < TypesWithHandlers.size(); ++i) {
+ TypeWithHandler curr = TypesWithHandlers[i];
+
+ if (curr == prev) {
+ Diag(curr.getTypeSpecStartLoc(),
+ diag::warn_exception_caught_by_earlier_handler)
+ << curr.getCatchStmt()->getCaughtType().getAsString();
+ Diag(prev.getTypeSpecStartLoc(),
+ diag::note_previous_exception_handler)
+ << prev.getCatchStmt()->getCaughtType().getAsString();
+ }
+
+ prev = curr;
+ }
+ }
+
// 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.
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 568d68c..d56b4e1 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -1,104 +1,239 @@
//===------- 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 "TreeTransform.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"
-
+#include "clang/Basic/PartialDiagnostic.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/ADT/StringExtras.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;
- }
- }
+/// \brief Determine whether the declaration found is acceptable as the name
+/// of a template and, if so, return that template declaration. Otherwise,
+/// returns NULL.
+static NamedDecl *isAcceptableTemplateName(ASTContext &Context, NamedDecl *D) {
+ if (!D)
+ return 0;
+
+ if (isa<TemplateDecl>(D))
+ return D;
+
+ if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) {
+ // 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>(Record->getDeclContext());
+ if (Record->getDescribedClassTemplate())
+ return Record->getDescribedClassTemplate();
+
+ if (ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(Record))
+ return Spec->getSpecializedTemplate();
}
- // FIXME: What follows is a slightly less gross hack than what used to
- // follow.
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(IIDecl)) {
- if (FD->getDescribedFunctionTemplate()) {
- TemplateResult = TemplateTy::make(FD);
- return TNK_Function_template;
+ return 0;
+ }
+
+ OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(D);
+ if (!Ovl)
+ return 0;
+
+ for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
+ FEnd = Ovl->function_end();
+ F != FEnd; ++F) {
+ if (FunctionTemplateDecl *FuncTmpl = dyn_cast<FunctionTemplateDecl>(*F)) {
+ // We've found a function template. Determine whether there are
+ // any other function templates we need to bundle together in an
+ // OverloadedFunctionDecl
+ for (++F; F != FEnd; ++F) {
+ if (isa<FunctionTemplateDecl>(*F))
+ break;
}
- } else if (OverloadedFunctionDecl *Ovl
- = dyn_cast<OverloadedFunctionDecl>(IIDecl)) {
- for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
- FEnd = Ovl->function_end();
- F != FEnd; ++F) {
- if (isa<FunctionTemplateDecl>(*F)) {
- TemplateResult = TemplateTy::make(Ovl);
- return TNK_Function_template;
+
+ if (F != FEnd) {
+ // Build an overloaded function decl containing only the
+ // function templates in Ovl.
+ OverloadedFunctionDecl *OvlTemplate
+ = OverloadedFunctionDecl::Create(Context,
+ Ovl->getDeclContext(),
+ Ovl->getDeclName());
+ OvlTemplate->addOverload(FuncTmpl);
+ OvlTemplate->addOverload(*F);
+ for (++F; F != FEnd; ++F) {
+ if (isa<FunctionTemplateDecl>(*F))
+ OvlTemplate->addOverload(*F);
}
+
+ return OvlTemplate;
}
+
+ return FuncTmpl;
}
+ }
+
+ return 0;
+}
- 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));
+TemplateNameKind Sema::isTemplateName(Scope *S,
+ const IdentifierInfo &II,
+ SourceLocation IdLoc,
+ const CXXScopeSpec *SS,
+ TypeTy *ObjectTypePtr,
+ bool EnteringContext,
+ TemplateTy &TemplateResult) {
+ // Determine where to perform name lookup
+ DeclContext *LookupCtx = 0;
+ bool isDependent = false;
+ if (ObjectTypePtr) {
+ // This nested-name-specifier occurs in a member access expression, e.g.,
+ // x->B::f, and we are looking into the type of the object.
+ assert((!SS || !SS->isSet()) &&
+ "ObjectType and scope specifier cannot coexist");
+ QualType ObjectType = QualType::getFromOpaquePtr(ObjectTypePtr);
+ LookupCtx = computeDeclContext(ObjectType);
+ isDependent = ObjectType->isDependentType();
+ } else if (SS && SS->isSet()) {
+ // This nested-name-specifier occurs after another nested-name-specifier,
+ // so long into the context associated with the prior nested-name-specifier.
+
+ LookupCtx = computeDeclContext(*SS, EnteringContext);
+ isDependent = isDependentScopeSpecifier(*SS);
+ }
+
+ LookupResult Found;
+ bool ObjectTypeSearchedInScope = false;
+ if (LookupCtx) {
+ // Perform "qualified" name lookup into the declaration context we
+ // computed, which is either the type of the base of a member access
+ // expression or the declaration context associated with a prior
+ // nested-name-specifier.
+
+ // The declaration context must be complete.
+ if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(*SS))
+ return TNK_Non_template;
+
+ LookupQualifiedName(Found, LookupCtx, &II, LookupOrdinaryName);
+
+ if (ObjectTypePtr && Found.getKind() == LookupResult::NotFound) {
+ // C++ [basic.lookup.classref]p1:
+ // In a class member access expression (5.2.5), if the . or -> token is
+ // immediately followed by an identifier followed by a <, the
+ // identifier must be looked up to determine whether the < is the
+ // beginning of a template argument list (14.2) or a less-than operator.
+ // The identifier is first looked up in the class of the object
+ // expression. If the identifier is not found, it is then looked up in
+ // the context of the entire postfix-expression and shall name a class
+ // or function template.
+ //
+ // FIXME: When we're instantiating a template, do we actually have to
+ // look in the scope of the template? Seems fishy...
+ LookupName(Found, S, &II, LookupOrdinaryName);
+ ObjectTypeSearchedInScope = true;
}
+ } else if (isDependent) {
+ // We cannot look into a dependent object type or
+ return TNK_Non_template;
+ } else {
+ // Perform unqualified name lookup in the current scope.
+ LookupName(Found, S, &II, LookupOrdinaryName);
}
- return TNK;
+
+ // FIXME: Cope with ambiguous name-lookup results.
+ assert(!Found.isAmbiguous() &&
+ "Cannot handle template name-lookup ambiguities");
+
+ NamedDecl *Template
+ = isAcceptableTemplateName(Context, Found.getAsSingleDecl(Context));
+ if (!Template)
+ return TNK_Non_template;
+
+ if (ObjectTypePtr && !ObjectTypeSearchedInScope) {
+ // C++ [basic.lookup.classref]p1:
+ // [...] If the lookup in the class of the object expression finds a
+ // template, the name is also looked up in the context of the entire
+ // postfix-expression and [...]
+ //
+ LookupResult FoundOuter;
+ LookupName(FoundOuter, S, &II, LookupOrdinaryName);
+ // FIXME: Handle ambiguities in this lookup better
+ NamedDecl *OuterTemplate
+ = isAcceptableTemplateName(Context, FoundOuter.getAsSingleDecl(Context));
+
+ if (!OuterTemplate) {
+ // - if the name is not found, the name found in the class of the
+ // object expression is used, otherwise
+ } else if (!isa<ClassTemplateDecl>(OuterTemplate)) {
+ // - if the name is found in the context of the entire
+ // postfix-expression and does not name a class template, the name
+ // found in the class of the object expression is used, otherwise
+ } else {
+ // - if the name found is a class template, it must refer to the same
+ // entity as the one found in the class of the object expression,
+ // otherwise the program is ill-formed.
+ if (OuterTemplate->getCanonicalDecl() != Template->getCanonicalDecl()) {
+ Diag(IdLoc, diag::err_nested_name_member_ref_lookup_ambiguous)
+ << &II;
+ Diag(Template->getLocation(), diag::note_ambig_member_ref_object_type)
+ << QualType::getFromOpaquePtr(ObjectTypePtr);
+ Diag(OuterTemplate->getLocation(), diag::note_ambig_member_ref_scope);
+
+ // Recover by taking the template that we found in the object
+ // expression's type.
+ }
+ }
+ }
+
+ if (SS && SS->isSet() && !SS->isInvalid()) {
+ NestedNameSpecifier *Qualifier
+ = static_cast<NestedNameSpecifier *>(SS->getScopeRep());
+ if (OverloadedFunctionDecl *Ovl
+ = dyn_cast<OverloadedFunctionDecl>(Template))
+ TemplateResult
+ = TemplateTy::make(Context.getQualifiedTemplateName(Qualifier, false,
+ Ovl));
+ else
+ TemplateResult
+ = TemplateTy::make(Context.getQualifiedTemplateName(Qualifier, false,
+ cast<TemplateDecl>(Template)));
+ } else if (OverloadedFunctionDecl *Ovl
+ = dyn_cast<OverloadedFunctionDecl>(Template)) {
+ TemplateResult = TemplateTy::make(TemplateName(Ovl));
+ } else {
+ TemplateResult = TemplateTy::make(
+ TemplateName(cast<TemplateDecl>(Template)));
+ }
+
+ if (isa<ClassTemplateDecl>(Template) ||
+ isa<TemplateTemplateParmDecl>(Template))
+ return TNK_Type_template;
+
+ assert((isa<FunctionTemplateDecl>(Template) ||
+ isa<OverloadedFunctionDecl>(Template)) &&
+ "Unhandled template kind in Sema::isTemplateName");
+ return TNK_Function_template;
}
/// DiagnoseTemplateParameterShadow - Produce a diagnostic complaining
@@ -115,7 +250,7 @@ bool Sema::DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl) {
// C++ [temp.local]p4:
// A template-parameter shall not be redeclared within its
// scope (including nested scopes).
- Diag(Loc, diag::err_template_param_shadow)
+ Diag(Loc, diag::err_template_param_shadow)
<< cast<NamedDecl>(PrevDecl)->getDeclName();
Diag(PrevDecl->getLocation(), diag::note_template_param_here);
return true;
@@ -125,7 +260,7 @@ bool Sema::DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl) {
/// 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>())) {
+ if (TemplateDecl *Temp = dyn_cast_or_null<TemplateDecl>(D.getAs<Decl>())) {
D = DeclPtrTy::make(Temp->getTemplatedDecl());
return Temp;
}
@@ -138,24 +273,24 @@ TemplateDecl *Sema::AdjustDeclIfTemplate(DeclPtrTy &D) {
/// (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).
+/// 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, bool Ellipsis,
+Sema::DeclPtrTy Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis,
SourceLocation EllipsisLoc,
SourceLocation KeyLoc,
IdentifierInfo *ParamName,
SourceLocation ParamNameLoc,
unsigned Depth, unsigned Position) {
- assert(S->isTemplateParamScope() &&
- "Template type parameter not in template parameter scope!");
+ assert(S->isTemplateParamScope() &&
+ "Template type parameter not in template parameter scope!");
bool Invalid = false;
if (ParamName) {
- NamedDecl *PrevDecl = LookupName(S, ParamName, LookupTagName);
+ NamedDecl *PrevDecl = LookupSingleName(S, ParamName, LookupTagName);
if (PrevDecl && PrevDecl->isTemplateParameter())
Invalid = Invalid || DiagnoseTemplateParameterShadow(ParamNameLoc,
- PrevDecl);
+ PrevDecl);
}
SourceLocation Loc = ParamNameLoc;
@@ -163,8 +298,8 @@ Sema::DeclPtrTy Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis,
Loc = KeyLoc;
TemplateTypeParmDecl *Param
- = TemplateTypeParmDecl::Create(Context, CurContext, Loc,
- Depth, Position, ParamName, Typename,
+ = TemplateTypeParmDecl::Create(Context, CurContext, Loc,
+ Depth, Position, ParamName, Typename,
Ellipsis);
if (Invalid)
Param->setInvalidDecl();
@@ -179,27 +314,28 @@ Sema::DeclPtrTy Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis,
}
/// ActOnTypeParameterDefault - Adds a default argument (the type
-/// Default) to the given template type parameter (TypeParam).
-void Sema::ActOnTypeParameterDefault(DeclPtrTy TypeParam,
+/// Default) to the given template type parameter (TypeParam).
+void Sema::ActOnTypeParameterDefault(DeclPtrTy TypeParam,
SourceLocation EqualLoc,
- SourceLocation DefaultLoc,
+ SourceLocation DefaultLoc,
TypeTy *DefaultT) {
- TemplateTypeParmDecl *Parm
+ TemplateTypeParmDecl *Parm
= cast<TemplateTypeParmDecl>(TypeParam.getAs<Decl>());
- QualType Default = QualType::getFromOpaquePtr(DefaultT);
+ // FIXME: Preserve type source info.
+ QualType Default = GetTypeFromParser(DefaultT);
// C++0x [temp.param]p9:
// A default template-argument may be specified for any kind of
- // template-parameter that is not a template parameter pack.
+ // template-parameter that is not a template parameter pack.
if (Parm->isParameterPack()) {
Diag(DefaultLoc, diag::err_template_param_pack_default_arg);
return;
}
-
+
// 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();
@@ -214,7 +350,7 @@ void Sema::ActOnTypeParameterDefault(DeclPtrTy TypeParam,
///
/// \returns the (possibly-promoted) parameter type if valid;
/// otherwise, produces a diagnostic and returns a NULL type.
-QualType
+QualType
Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) {
// C++ [temp.param]p4:
//
@@ -223,11 +359,11 @@ Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) {
//
// -- 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,
+ // -- pointer to object or pointer to function,
+ (T->isPointerType() &&
+ (T->getAs<PointerType>()->getPointeeType()->isObjectType() ||
+ T->getAs<PointerType>()->getPointeeType()->isFunctionType())) ||
+ // -- reference to object or reference to function,
T->isReferenceType() ||
// -- pointer to member.
T->isMemberPointerType() ||
@@ -258,9 +394,10 @@ Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) {
/// 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 Depth,
unsigned Position) {
- QualType T = GetTypeForDeclarator(D, S);
+ DeclaratorInfo *DInfo = 0;
+ QualType T = GetTypeForDeclarator(D, S, &DInfo);
assert(S->isTemplateParamScope() &&
"Non-type template parameter not in template parameter scope!");
@@ -268,7 +405,7 @@ Sema::DeclPtrTy Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
IdentifierInfo *ParamName = D.getIdentifier();
if (ParamName) {
- NamedDecl *PrevDecl = LookupName(S, ParamName, LookupTagName);
+ NamedDecl *PrevDecl = LookupSingleName(S, ParamName, LookupTagName);
if (PrevDecl && PrevDecl->isTemplateParameter())
Invalid = Invalid || DiagnoseTemplateParameterShadow(D.getIdentifierLoc(),
PrevDecl);
@@ -282,7 +419,7 @@ Sema::DeclPtrTy Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
NonTypeTemplateParmDecl *Param
= NonTypeTemplateParmDecl::Create(Context, CurContext, D.getIdentifierLoc(),
- Depth, Position, ParamName, T);
+ Depth, Position, ParamName, T, DInfo);
if (Invalid)
Param->setInvalidDecl();
@@ -299,14 +436,14 @@ Sema::DeclPtrTy Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
void Sema::ActOnNonTypeTemplateParameterDefault(DeclPtrTy TemplateParamD,
SourceLocation EqualLoc,
ExprArg DefaultE) {
- NonTypeTemplateParmDecl *TemplateParm
+ 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.
TemplateArgument Converted;
if (CheckTemplateArgument(TemplateParm, TemplateParm->getType(), Default,
@@ -328,8 +465,7 @@ Sema::DeclPtrTy Sema::ActOnTemplateTemplateParameter(Scope* S,
IdentifierInfo *Name,
SourceLocation NameLoc,
unsigned Depth,
- unsigned Position)
-{
+ unsigned Position) {
assert(S->isTemplateParamScope() &&
"Template template parameter not in template parameter scope!");
@@ -363,12 +499,12 @@ Sema::DeclPtrTy Sema::ActOnTemplateTemplateParameter(Scope* S,
void Sema::ActOnTemplateTemplateParameterDefault(DeclPtrTy TemplateParamD,
SourceLocation EqualLoc,
ExprArg DefaultE) {
- TemplateTemplateParmDecl *TemplateParm
+ 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
+ DeclRefExpr *Default
= cast<DeclRefExpr>(static_cast<Expr *>(DefaultE.get()));
// C++ [temp.param]p14:
@@ -377,12 +513,12 @@ void Sema::ActOnTemplateTemplateParameterDefault(DeclPtrTy TemplateParamD,
// Check the well-formedness of the template argument.
if (!isa<TemplateDecl>(Default->getDecl())) {
- Diag(Default->getSourceRange().getBegin(),
+ Diag(Default->getSourceRange().getBegin(),
diag::err_template_arg_must_be_template)
<< Default->getSourceRange();
TemplateParm->setInvalidDecl();
return;
- }
+ }
if (CheckTemplateArgument(TemplateParm, Default)) {
TemplateParm->setInvalidDecl();
return;
@@ -397,7 +533,7 @@ void Sema::ActOnTemplateTemplateParameterDefault(DeclPtrTy TemplateParamD,
Sema::TemplateParamsTy *
Sema::ActOnTemplateParameterList(unsigned Depth,
SourceLocation ExportLoc,
- SourceLocation TemplateLoc,
+ SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
DeclPtrTy *Params, unsigned NumParams,
SourceLocation RAngleLoc) {
@@ -405,31 +541,28 @@ Sema::ActOnTemplateParameterList(unsigned Depth,
Diag(ExportLoc, diag::note_template_export_unsupported);
return TemplateParameterList::Create(Context, TemplateLoc, LAngleLoc,
- (Decl**)Params, NumParams, RAngleLoc);
+ (NamedDecl**)Params, NumParams,
+ RAngleLoc);
}
Sema::DeclResult
-Sema::ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK,
+Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
SourceLocation KWLoc, const CXXScopeSpec &SS,
IdentifierInfo *Name, SourceLocation NameLoc,
AttributeList *Attr,
- MultiTemplateParamsArg TemplateParameterLists,
+ TemplateParameterList *TemplateParams,
AccessSpecifier AS) {
- assert(TemplateParameterLists.size() > 0 && "No template parameter lists?");
- assert(TK != TK_Reference && "Can only declare or define class templates");
+ assert(TemplateParams && TemplateParams->size() > 0 &&
+ "No template parameters");
+ assert(TUK != TUK_Reference && "Can only declare or define class templates");
bool Invalid = false;
// Check that we can declare a template here.
- if (CheckTemplateDeclScope(S, TemplateParameterLists))
+ if (CheckTemplateDeclScope(S, TemplateParams))
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;
- }
+ TagDecl::TagKind Kind = TagDecl::getTagKindForTypeSpec(TagSpec);
+ assert(Kind != TagDecl::TK_enum && "can't build template of enumerated type");
// There is no such thing as an unnamed class template.
if (!Name) {
@@ -438,31 +571,73 @@ Sema::ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK,
}
// Find any previous declaration with this name.
- LookupResult Previous = LookupParsedName(S, &SS, Name, LookupOrdinaryName,
- true);
+ DeclContext *SemanticContext;
+ LookupResult Previous;
+ if (SS.isNotEmpty() && !SS.isInvalid()) {
+ if (RequireCompleteDeclContext(SS))
+ return true;
+
+ SemanticContext = computeDeclContext(SS, true);
+ if (!SemanticContext) {
+ // FIXME: Produce a reasonable diagnostic here
+ return true;
+ }
+
+ LookupQualifiedName(Previous, SemanticContext, Name, LookupOrdinaryName,
+ true);
+ } else {
+ SemanticContext = CurContext;
+ LookupName(Previous, S, Name, LookupOrdinaryName, true);
+ }
+
assert(!Previous.isAmbiguous() && "Ambiguity in class template redecl?");
NamedDecl *PrevDecl = 0;
if (Previous.begin() != Previous.end())
PrevDecl = *Previous.begin();
- if (PrevDecl && !isDeclInScope(PrevDecl, CurContext, S))
+ if (PrevDecl && TUK == TUK_Friend) {
+ // C++ [namespace.memdef]p3:
+ // [...] When looking for a prior declaration of a class or a function
+ // declared as a friend, and when the name of the friend class or
+ // function is neither a qualified name nor a template-id, scopes outside
+ // the innermost enclosing namespace scope are not considered.
+ DeclContext *OutermostContext = CurContext;
+ while (!OutermostContext->isFileContext())
+ OutermostContext = OutermostContext->getLookupParent();
+
+ if (OutermostContext->Equals(PrevDecl->getDeclContext()) ||
+ OutermostContext->Encloses(PrevDecl->getDeclContext())) {
+ SemanticContext = PrevDecl->getDeclContext();
+ } else {
+ // Declarations in outer scopes don't matter. However, the outermost
+ // context we computed is the semntic context for our new
+ // declaration.
+ PrevDecl = 0;
+ SemanticContext = OutermostContext;
+ }
+ } else if (PrevDecl && !isDeclInScope(PrevDecl, SemanticContext, S))
PrevDecl = 0;
-
- 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
+ ClassTemplateDecl *PrevClassTemplate
= dyn_cast_or_null<ClassTemplateDecl>(PrevDecl);
+
+ // We may have found the injected-class-name of a class template,
+ // class template partial specialization, or class template specialization.
+ // In these cases, grab the template that is being defined or specialized.
+ if (!PrevClassTemplate && PrevDecl && isa<CXXRecordDecl>(PrevDecl) &&
+ cast<CXXRecordDecl>(PrevDecl)->isInjectedClassName()) {
+ PrevDecl = cast<CXXRecordDecl>(PrevDecl->getDeclContext());
+ PrevClassTemplate
+ = cast<CXXRecordDecl>(PrevDecl)->getDescribedClassTemplate();
+ if (!PrevClassTemplate && isa<ClassTemplateSpecializationDecl>(PrevDecl)) {
+ PrevClassTemplate
+ = cast<ClassTemplateSpecializationDecl>(PrevDecl)
+ ->getSpecializedTemplate();
+ }
+ }
+
if (PrevClassTemplate) {
// Ensure that the template parameter lists are compatible.
if (!TemplateParameterListsAreEqual(TemplateParams,
@@ -477,16 +652,16 @@ Sema::ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK,
// template declaration (7.1.5.3).
RecordDecl *PrevRecordDecl = PrevClassTemplate->getTemplatedDecl();
if (!isAcceptableTagRedeclaration(PrevRecordDecl, Kind, KWLoc, *Name)) {
- Diag(KWLoc, diag::err_use_with_wrong_tag)
+ Diag(KWLoc, diag::err_use_with_wrong_tag)
<< Name
- << CodeModificationHint::CreateReplacement(KWLoc,
+ << 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 (TUK == TUK_Definition) {
if (TagDecl *Def = PrevRecordDecl->getDefinition(Context)) {
Diag(NameLoc, diag::err_redefinition) << Name;
Diag(Def->getLocation(), diag::note_previous_definition);
@@ -517,13 +692,13 @@ Sema::ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK,
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?
+ CXXRecordDecl *NewClass =
+ CXXRecordDecl::Create(Context, Kind, SemanticContext, NameLoc, Name, KWLoc,
+ PrevClassTemplate?
PrevClassTemplate->getTemplatedDecl() : 0,
/*DelayTypeCreation=*/true);
@@ -534,27 +709,60 @@ Sema::ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK,
NewClass->setDescribedClassTemplate(NewTemplate);
// Build the type for the class template declaration now.
- QualType T =
- Context.getTypeDeclType(NewClass,
- PrevClassTemplate?
- PrevClassTemplate->getTemplatedDecl() : 0);
+ 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);
+ // If we are providing an explicit specialization of a member that is a
+ // class template, make a note of that.
+ if (PrevClassTemplate &&
+ PrevClassTemplate->getInstantiatedFromMemberTemplate())
+ PrevClassTemplate->setMemberSpecialization();
+ // Set the access specifier.
+ if (!Invalid && TUK != TUK_Friend)
+ SetMemberAccessSpecifier(NewTemplate, PrevClassTemplate, AS);
+
// Set the lexical context of these templates
NewClass->setLexicalDeclContext(CurContext);
NewTemplate->setLexicalDeclContext(CurContext);
- if (TK == TK_Definition)
+ if (TUK == TUK_Definition)
NewClass->startDefinition();
if (Attr)
ProcessDeclAttributeList(S, NewClass, Attr);
- PushOnScopeChains(NewTemplate, S);
+ if (TUK != TUK_Friend)
+ PushOnScopeChains(NewTemplate, S);
+ else {
+ if (PrevClassTemplate && PrevClassTemplate->getAccess() != AS_none) {
+ NewTemplate->setAccess(PrevClassTemplate->getAccess());
+ NewClass->setAccess(PrevClassTemplate->getAccess());
+ }
+
+ NewTemplate->setObjectOfFriendDecl(/* PreviouslyDeclared = */
+ PrevClassTemplate != NULL);
+
+ // Friend templates are visible in fairly strange ways.
+ if (!CurContext->isDependentContext()) {
+ DeclContext *DC = SemanticContext->getLookupContext();
+ DC->makeDeclVisibleInContext(NewTemplate, /* Recoverable = */ false);
+ if (Scope *EnclosingScope = getScopeForDeclContext(S, DC))
+ PushOnScopeChains(NewTemplate, EnclosingScope,
+ /* AddToContext = */ false);
+ }
+
+ FriendDecl *Friend = FriendDecl::Create(Context, CurContext,
+ NewClass->getLocation(),
+ NewTemplate,
+ /*FIXME:*/NewClass->getLocation());
+ Friend->setAccess(AS_public);
+ CurContext->addDecl(Friend);
+ }
if (Invalid) {
NewTemplate->setInvalidDecl();
@@ -585,7 +793,7 @@ Sema::ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK,
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
@@ -618,7 +826,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
// If a template parameter of a class template is a template parameter pack,
// it must be the last template parameter.
if (SawParameterPack) {
- Diag(ParameterPackLoc,
+ Diag(ParameterPackLoc,
diag::err_template_param_pack_must_be_last_template_parameter);
Invalid = true;
}
@@ -626,15 +834,15 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
// Merge default arguments for template type parameters.
if (TemplateTypeParmDecl *NewTypeParm
= dyn_cast<TemplateTypeParmDecl>(*NewParam)) {
- TemplateTypeParmDecl *OldTypeParm
+ TemplateTypeParmDecl *OldTypeParm
= OldParams? cast<TemplateTypeParmDecl>(*OldParam) : 0;
-
+
if (NewTypeParm->isParameterPack()) {
assert(!NewTypeParm->hasDefaultArgument() &&
"Parameter packs can't have a default argument!");
SawParameterPack = true;
ParameterPackLoc = NewTypeParm->getLocation();
- } else if (OldTypeParm && OldTypeParm->hasDefaultArgument() &&
+ } else if (OldTypeParm && OldTypeParm->hasDefaultArgument() &&
NewTypeParm->hasDefaultArgument()) {
OldDefaultLoc = OldTypeParm->getDefaultArgumentLoc();
NewDefaultLoc = NewTypeParm->getDefaultArgumentLoc();
@@ -654,13 +862,12 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
PreviousDefaultArgLoc = NewTypeParm->getDefaultArgumentLoc();
} else if (SawDefaultArgument)
MissingDefaultArg = true;
- }
- // Merge default arguments for non-type template parameters
- else if (NonTypeTemplateParmDecl *NewNonTypeParm
+ } else if (NonTypeTemplateParmDecl *NewNonTypeParm
= dyn_cast<NonTypeTemplateParmDecl>(*NewParam)) {
+ // Merge default arguments for non-type template parameters
NonTypeTemplateParmDecl *OldNonTypeParm
= OldParams? cast<NonTypeTemplateParmDecl>(*OldParam) : 0;
- if (OldNonTypeParm && OldNonTypeParm->hasDefaultArgument() &&
+ if (OldNonTypeParm && OldNonTypeParm->hasDefaultArgument() &&
NewNonTypeParm->hasDefaultArgument()) {
OldDefaultLoc = OldNonTypeParm->getDefaultArgumentLoc();
NewDefaultLoc = NewNonTypeParm->getDefaultArgumentLoc();
@@ -681,15 +888,14 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
SawDefaultArgument = true;
PreviousDefaultArgLoc = NewNonTypeParm->getDefaultArgumentLoc();
} else if (SawDefaultArgument)
- MissingDefaultArg = true;
- }
+ MissingDefaultArg = true;
+ } else {
// Merge default arguments for template template parameters
- else {
TemplateTemplateParmDecl *NewTemplateParm
= cast<TemplateTemplateParmDecl>(*NewParam);
TemplateTemplateParmDecl *OldTemplateParm
= OldParams? cast<TemplateTemplateParmDecl>(*OldParam) : 0;
- if (OldTemplateParm && OldTemplateParm->hasDefaultArgument() &&
+ if (OldTemplateParm && OldTemplateParm->hasDefaultArgument() &&
NewTemplateParm->hasDefaultArgument()) {
OldDefaultLoc = OldTemplateParm->getDefaultArgumentLoc();
NewDefaultLoc = NewTemplateParm->getDefaultArgumentLoc();
@@ -709,7 +915,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
SawDefaultArgument = true;
PreviousDefaultArgLoc = NewTemplateParm->getDefaultArgumentLoc();
} else if (SawDefaultArgument)
- MissingDefaultArg = true;
+ MissingDefaultArg = true;
}
if (RedundantDefaultArg) {
@@ -724,7 +930,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
// If a template-parameter has a default template-argument,
// all subsequent template-parameters shall have a default
// template-argument supplied.
- Diag((*NewParam)->getLocation(),
+ Diag((*NewParam)->getLocation(),
diag::err_template_param_default_arg_missing);
Diag(PreviousDefaultArgLoc, diag::note_template_param_prev_default_arg);
Invalid = true;
@@ -739,11 +945,157 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
return Invalid;
}
+/// \brief Match the given template parameter lists to the given scope
+/// specifier, returning the template parameter list that applies to the
+/// name.
+///
+/// \param DeclStartLoc the start of the declaration that has a scope
+/// specifier or a template parameter list.
+///
+/// \param SS the scope specifier that will be matched to the given template
+/// parameter lists. This scope specifier precedes a qualified name that is
+/// being declared.
+///
+/// \param ParamLists the template parameter lists, from the outermost to the
+/// innermost template parameter lists.
+///
+/// \param NumParamLists the number of template parameter lists in ParamLists.
+///
+/// \param IsExplicitSpecialization will be set true if the entity being
+/// declared is an explicit specialization, false otherwise.
+///
+/// \returns the template parameter list, if any, that corresponds to the
+/// name that is preceded by the scope specifier @p SS. This template
+/// parameter list may be have template parameters (if we're declaring a
+/// template) or may have no template parameters (if we're declaring a
+/// template specialization), or may be NULL (if we were's declaring isn't
+/// itself a template).
+TemplateParameterList *
+Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
+ const CXXScopeSpec &SS,
+ TemplateParameterList **ParamLists,
+ unsigned NumParamLists,
+ bool &IsExplicitSpecialization) {
+ IsExplicitSpecialization = false;
+
+ // Find the template-ids that occur within the nested-name-specifier. These
+ // template-ids will match up with the template parameter lists.
+ llvm::SmallVector<const TemplateSpecializationType *, 4>
+ TemplateIdsInSpecifier;
+ for (NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep();
+ NNS; NNS = NNS->getPrefix()) {
+ if (const TemplateSpecializationType *SpecType
+ = dyn_cast_or_null<TemplateSpecializationType>(NNS->getAsType())) {
+ TemplateDecl *Template = SpecType->getTemplateName().getAsTemplateDecl();
+ if (!Template)
+ continue; // FIXME: should this be an error? probably...
+
+ if (const RecordType *Record = SpecType->getAs<RecordType>()) {
+ ClassTemplateSpecializationDecl *SpecDecl
+ = cast<ClassTemplateSpecializationDecl>(Record->getDecl());
+ // If the nested name specifier refers to an explicit specialization,
+ // we don't need a template<> header.
+ // FIXME: revisit this approach once we cope with specializations
+ // properly.
+ if (SpecDecl->getSpecializationKind() == TSK_ExplicitSpecialization)
+ continue;
+ }
+
+ TemplateIdsInSpecifier.push_back(SpecType);
+ }
+ }
+
+ // Reverse the list of template-ids in the scope specifier, so that we can
+ // more easily match up the template-ids and the template parameter lists.
+ std::reverse(TemplateIdsInSpecifier.begin(), TemplateIdsInSpecifier.end());
+
+ SourceLocation FirstTemplateLoc = DeclStartLoc;
+ if (NumParamLists)
+ FirstTemplateLoc = ParamLists[0]->getTemplateLoc();
+
+ // Match the template-ids found in the specifier to the template parameter
+ // lists.
+ unsigned Idx = 0;
+ for (unsigned NumTemplateIds = TemplateIdsInSpecifier.size();
+ Idx != NumTemplateIds; ++Idx) {
+ QualType TemplateId = QualType(TemplateIdsInSpecifier[Idx], 0);
+ bool DependentTemplateId = TemplateId->isDependentType();
+ if (Idx >= NumParamLists) {
+ // We have a template-id without a corresponding template parameter
+ // list.
+ if (DependentTemplateId) {
+ // FIXME: the location information here isn't great.
+ Diag(SS.getRange().getBegin(),
+ diag::err_template_spec_needs_template_parameters)
+ << TemplateId
+ << SS.getRange();
+ } else {
+ Diag(SS.getRange().getBegin(), diag::err_template_spec_needs_header)
+ << SS.getRange()
+ << CodeModificationHint::CreateInsertion(FirstTemplateLoc,
+ "template<> ");
+ IsExplicitSpecialization = true;
+ }
+ return 0;
+ }
+
+ // Check the template parameter list against its corresponding template-id.
+ if (DependentTemplateId) {
+ TemplateDecl *Template
+ = TemplateIdsInSpecifier[Idx]->getTemplateName().getAsTemplateDecl();
+
+ if (ClassTemplateDecl *ClassTemplate
+ = dyn_cast<ClassTemplateDecl>(Template)) {
+ TemplateParameterList *ExpectedTemplateParams = 0;
+ // Is this template-id naming the primary template?
+ if (Context.hasSameType(TemplateId,
+ ClassTemplate->getInjectedClassNameType(Context)))
+ ExpectedTemplateParams = ClassTemplate->getTemplateParameters();
+ // ... or a partial specialization?
+ else if (ClassTemplatePartialSpecializationDecl *PartialSpec
+ = ClassTemplate->findPartialSpecialization(TemplateId))
+ ExpectedTemplateParams = PartialSpec->getTemplateParameters();
+
+ if (ExpectedTemplateParams)
+ TemplateParameterListsAreEqual(ParamLists[Idx],
+ ExpectedTemplateParams,
+ true);
+ }
+ } else if (ParamLists[Idx]->size() > 0)
+ Diag(ParamLists[Idx]->getTemplateLoc(),
+ diag::err_template_param_list_matches_nontemplate)
+ << TemplateId
+ << ParamLists[Idx]->getSourceRange();
+ else
+ IsExplicitSpecialization = true;
+ }
+
+ // If there were at least as many template-ids as there were template
+ // parameter lists, then there are no template parameter lists remaining for
+ // the declaration itself.
+ if (Idx >= NumParamLists)
+ return 0;
+
+ // If there were too many template parameter lists, complain about that now.
+ if (Idx != NumParamLists - 1) {
+ while (Idx < NumParamLists - 1) {
+ Diag(ParamLists[Idx]->getTemplateLoc(),
+ diag::err_template_spec_extra_headers)
+ << SourceRange(ParamLists[Idx]->getTemplateLoc(),
+ ParamLists[Idx]->getRAngleLoc());
+ ++Idx;
+ }
+ }
+
+ // Return the last template parameter list, which corresponds to the
+ // entity being declared.
+ return ParamLists[NumParamLists - 1];
+}
+
/// \brief Translates template arguments as provided by the parser
/// into template arguments used by semantic analysis.
-static void
-translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn,
- SourceLocation *TemplateArgLocs,
+void Sema::translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn,
+ SourceLocation *TemplateArgLocs,
llvm::SmallVector<TemplateArgument, 16> &TemplateArgs) {
TemplateArgs.reserve(TemplateArgsIn.size());
@@ -752,72 +1104,12 @@ translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn,
for (unsigned Arg = 0, Last = TemplateArgsIn.size(); Arg != Last; ++Arg) {
TemplateArgs.push_back(
ArgIsType[Arg]? TemplateArgument(TemplateArgLocs[Arg],
- QualType::getFromOpaquePtr(Args[Arg]))
+ //FIXME: Preserve type source info.
+ Sema::GetTypeFromParser(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::Null:
- assert(false && "Should never see a NULL template argument here");
- break;
-
- 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()));
- break;
-
- case TemplateArgument::Type: {
- QualType CanonType
- = Context.getCanonicalType(TemplateArgs[Idx].getAsType());
- Canonical.push_back(TemplateArgument(SourceLocation(), CanonType));
- break;
- }
-
- case TemplateArgument::Pack:
- assert(0 && "FIXME: Implement!");
- break;
- }
- }
-}
-
QualType Sema::CheckTemplateIdType(TemplateName Name,
SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
@@ -828,34 +1120,20 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
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);
+ NumTemplateArgs);
}
// Check that the template argument list is well-formed for this
// template.
TemplateArgumentListBuilder Converted(Template->getTemplateParameters(),
NumTemplateArgs);
- if (CheckTemplateArgumentList(Template, TemplateLoc, LAngleLoc,
+ if (CheckTemplateArgumentList(Template, TemplateLoc, LAngleLoc,
TemplateArgs, NumTemplateArgs, RAngleLoc,
false, Converted))
return QualType();
- assert((Converted.structuredSize() ==
+ assert((Converted.structuredSize() ==
Template->getTemplateParameters()->size()) &&
"Converted template argument list is too short!");
@@ -872,17 +1150,24 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
//
// template<typename T, typename U = T> struct A;
TemplateName CanonName = Context.getCanonicalTemplateName(Name);
- CanonType = Context.getTemplateSpecializationType(CanonName,
+ CanonType = Context.getTemplateSpecializationType(CanonName,
Converted.getFlatArguments(),
Converted.flatSize());
- } else if (ClassTemplateDecl *ClassTemplate
+
+ // FIXME: CanonType is not actually the canonical type, and unfortunately
+ // it is a TemplateTypeSpecializationType that we will never use again.
+ // In the future, we need to teach getTemplateSpecializationType to only
+ // build the canonical type and return that to us.
+ CanonType = Context.getCanonicalType(CanonType);
+ } 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,
+ ClassTemplateSpecializationDecl::Profile(ID,
Converted.getFlatArguments(),
- Converted.flatSize());
+ Converted.flatSize(),
+ Context);
void *InsertPos = 0;
ClassTemplateSpecializationDecl *Decl
= ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos);
@@ -890,9 +1175,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
// 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,
+ Decl = ClassTemplateSpecializationDecl::Create(Context,
ClassTemplate->getDeclContext(),
- TemplateLoc,
+ ClassTemplate->getLocation(),
ClassTemplate,
Converted, 0);
ClassTemplate->getSpecializations().InsertNode(Decl, InsertPos);
@@ -901,17 +1186,18 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
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.
+ //FIXME: Preserve type source info.
return Context.getTemplateSpecializationType(Name, TemplateArgs,
NumTemplateArgs, CanonType);
}
Action::TypeResult
Sema::ActOnTemplateIdType(TemplateTy TemplateD, SourceLocation TemplateLoc,
- SourceLocation LAngleLoc,
+ SourceLocation LAngleLoc,
ASTTemplateArgsPtr TemplateArgsIn,
SourceLocation *TemplateArgLocs,
SourceLocation RAngleLoc) {
@@ -933,6 +1219,38 @@ Sema::ActOnTemplateIdType(TemplateTy TemplateD, SourceLocation TemplateLoc,
return Result.getAsOpaquePtr();
}
+Sema::TypeResult Sema::ActOnTagTemplateIdType(TypeResult TypeResult,
+ TagUseKind TUK,
+ DeclSpec::TST TagSpec,
+ SourceLocation TagLoc) {
+ if (TypeResult.isInvalid())
+ return Sema::TypeResult();
+
+ QualType Type = QualType::getFromOpaquePtr(TypeResult.get());
+
+ // Verify the tag specifier.
+ TagDecl::TagKind TagKind = TagDecl::getTagKindForTypeSpec(TagSpec);
+
+ if (const RecordType *RT = Type->getAs<RecordType>()) {
+ RecordDecl *D = RT->getDecl();
+
+ IdentifierInfo *Id = D->getIdentifier();
+ assert(Id && "templated class must have an identifier");
+
+ if (!isAcceptableTagRedeclaration(D, TagKind, TagLoc, *Id)) {
+ Diag(TagLoc, diag::err_use_with_wrong_tag)
+ << Type
+ << CodeModificationHint::CreateReplacement(SourceRange(TagLoc),
+ D->getKindName());
+ Diag(D->getLocation(), diag::note_previous_use);
+ }
+ }
+
+ QualType ElabType = Context.getElaboratedType(Type, TagKind);
+
+ return ElabType.getAsOpaquePtr();
+}
+
Sema::OwningExprResult Sema::BuildTemplateIdExpr(TemplateName Template,
SourceLocation TemplateNameLoc,
SourceLocation LAngleLoc,
@@ -941,14 +1259,14 @@ Sema::OwningExprResult Sema::BuildTemplateIdExpr(TemplateName Template,
SourceLocation RAngleLoc) {
// FIXME: Can we do any checking at this point? I guess we could check the
// template arguments that we have against the template name, if the template
- // name refers to a single template. That's not a terribly common case,
+ // name refers to a single template. That's not a terribly common case,
// though.
- return Owned(TemplateIdRefExpr::Create(Context,
+ return Owned(TemplateIdRefExpr::Create(Context,
/*FIXME: New type?*/Context.OverloadTy,
/*FIXME: Necessary?*/0,
/*FIXME: Necessary?*/SourceRange(),
Template, TemplateNameLoc, LAngleLoc,
- TemplateArgs,
+ TemplateArgs,
NumTemplateArgs, RAngleLoc));
}
@@ -959,16 +1277,52 @@ Sema::OwningExprResult Sema::ActOnTemplateIdExpr(TemplateTy TemplateD,
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);
-
+ TemplateArgsIn.release();
+
return BuildTemplateIdExpr(Template, TemplateNameLoc, LAngleLoc,
TemplateArgs.data(), TemplateArgs.size(),
RAngleLoc);
}
+Sema::OwningExprResult
+Sema::ActOnMemberTemplateIdReferenceExpr(Scope *S, ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ const CXXScopeSpec &SS,
+ TemplateTy TemplateD,
+ SourceLocation TemplateNameLoc,
+ SourceLocation LAngleLoc,
+ ASTTemplateArgsPtr TemplateArgsIn,
+ SourceLocation *TemplateArgLocs,
+ SourceLocation RAngleLoc) {
+ TemplateName Template = TemplateD.getAsVal<TemplateName>();
+
+ // FIXME: We're going to end up looking up the template based on its name,
+ // twice!
+ DeclarationName Name;
+ if (TemplateDecl *ActualTemplate = Template.getAsTemplateDecl())
+ Name = ActualTemplate->getDeclName();
+ else if (OverloadedFunctionDecl *Ovl = Template.getAsOverloadedFunctionDecl())
+ Name = Ovl->getDeclName();
+ else
+ Name = Template.getAsDependentTemplateName()->getName();
+
+ // Translate the parser's template argument list in our AST format.
+ llvm::SmallVector<TemplateArgument, 16> TemplateArgs;
+ translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs);
+ TemplateArgsIn.release();
+
+ // Do we have the save the actual template name? We might need it...
+ return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, TemplateNameLoc,
+ Name, true, LAngleLoc,
+ TemplateArgs.data(), TemplateArgs.size(),
+ RAngleLoc, DeclPtrTy(), &SS);
+}
+
/// \brief Form a dependent template name.
///
/// This action forms a dependent template name given the template
@@ -976,20 +1330,15 @@ Sema::OwningExprResult Sema::ActOnTemplateIdExpr(TemplateTy TemplateD,
/// 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::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()) {
+ const CXXScopeSpec &SS,
+ TypeTy *ObjectType) {
+ if ((ObjectType &&
+ computeDeclContext(QualType::getFromOpaquePtr(ObjectType))) ||
+ (SS.isSet() && computeDeclContext(SS, false))) {
// 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
@@ -1007,7 +1356,8 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
// "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);
+ TemplateNameKind TNK = isTemplateName(0, Name, NameLoc, &SS, ObjectType,
+ false, Template);
if (TNK == TNK_Non_template) {
Diag(NameLoc, diag::err_template_kw_refers_to_non_template)
<< &Name;
@@ -1017,10 +1367,12 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
return Template;
}
+ NestedNameSpecifier *Qualifier
+ = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
return TemplateTy::make(Context.getDependentTemplateName(Qualifier, &Name));
}
-bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
+bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
const TemplateArgument &Arg,
TemplateArgumentListBuilder &Converted) {
// Check template type parameter.
@@ -1033,13 +1385,13 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
// is not a type.
Diag(Arg.getLocation(), diag::err_template_arg_must_be_type);
Diag(Param->getLocation(), diag::note_template_param_here);
-
+
return true;
- }
+ }
if (CheckTemplateArgument(Param, Arg.getAsType(), Arg.getLocation()))
return true;
-
+
// Add the converted template type argument.
Converted.Append(
TemplateArgument(Arg.getLocation(),
@@ -1062,9 +1414,9 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
unsigned NumArgs = NumTemplateArgs;
bool Invalid = false;
- bool HasParameterPack =
+ bool HasParameterPack =
NumParams > 0 && Params->getParam(NumParams - 1)->isTemplateParameterPack();
-
+
if ((NumArgs > NumParams && !HasParameterPack) ||
(NumArgs < Params->getMinRequiredArguments() &&
!PartialTemplateArgs)) {
@@ -1084,8 +1436,8 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
<< Params->getSourceRange();
Invalid = true;
}
-
- // C++ [temp.arg]p1:
+
+ // 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
@@ -1096,7 +1448,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
Param != ParamEnd; ++Param, ++ArgIdx) {
if (ArgIdx > NumArgs && PartialTemplateArgs)
break;
-
+
// Decode the template argument
TemplateArgument Arg;
if (ArgIdx >= NumArgs) {
@@ -1109,7 +1461,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
Converted.EndPack();
break;
}
-
+
if (!TTP->hasDefaultArgument())
break;
@@ -1118,49 +1470,51 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
// If the argument type is dependent, instantiate it now based
// on the previously-computed template arguments.
if (ArgType->isDependentType()) {
- InstantiatingTemplate Inst(*this, TemplateLoc,
+ InstantiatingTemplate Inst(*this, TemplateLoc,
Template, Converted.getFlatArguments(),
Converted.flatSize(),
SourceRange(TemplateLoc, RAngleLoc));
TemplateArgumentList TemplateArgs(Context, Converted,
/*TakeArgs=*/false);
- ArgType = InstantiateType(ArgType, TemplateArgs,
- TTP->getDefaultArgumentLoc(),
- TTP->getDeclName());
+ ArgType = SubstType(ArgType,
+ MultiLevelTemplateArgumentList(TemplateArgs),
+ TTP->getDefaultArgumentLoc(),
+ TTP->getDeclName());
}
if (ArgType.isNull())
return true;
Arg = TemplateArgument(TTP->getLocation(), ArgType);
- } else if (NonTypeTemplateParmDecl *NTTP
+ } else if (NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
if (!NTTP->hasDefaultArgument())
break;
- InstantiatingTemplate Inst(*this, TemplateLoc,
+ InstantiatingTemplate Inst(*this, TemplateLoc,
Template, Converted.getFlatArguments(),
Converted.flatSize(),
SourceRange(TemplateLoc, RAngleLoc));
-
+
TemplateArgumentList TemplateArgs(Context, Converted,
/*TakeArgs=*/false);
- Sema::OwningExprResult E = InstantiateExpr(NTTP->getDefaultArgument(),
- TemplateArgs);
+ Sema::OwningExprResult E
+ = SubstExpr(NTTP->getDefaultArgument(),
+ MultiLevelTemplateArgumentList(TemplateArgs));
if (E.isInvalid())
return true;
-
+
Arg = TemplateArgument(E.takeAs<Expr>());
} else {
- TemplateTemplateParmDecl *TempParm
- = cast<TemplateTemplateParmDecl>(*Param);
+ TemplateTemplateParmDecl *TempParm
+ = cast<TemplateTemplateParmDecl>(*Param);
if (!TempParm->hasDefaultArgument())
break;
- // FIXME: Instantiate default argument
+ // FIXME: Subst default argument
Arg = TemplateArgument(TempParm->getDefaultArgument());
}
} else {
@@ -1177,35 +1531,36 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
if (CheckTemplateTypeArgument(TTP, TemplateArgs[ArgIdx], Converted))
Invalid = true;
}
-
+
Converted.EndPack();
} else {
if (CheckTemplateTypeArgument(TTP, Arg, Converted))
Invalid = true;
}
- } else if (NonTypeTemplateParmDecl *NTTP
+ } 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.
+ // Do substitution on 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,
+ // Do substitution on the type of the non-type template parameter.
+ InstantiatingTemplate Inst(*this, TemplateLoc,
Template, Converted.getFlatArguments(),
Converted.flatSize(),
SourceRange(TemplateLoc, RAngleLoc));
TemplateArgumentList TemplateArgs(Context, Converted,
/*TakeArgs=*/false);
- NTTPType = InstantiateType(NTTPType, TemplateArgs,
- NTTP->getLocation(),
- NTTP->getDeclName());
+ NTTPType = SubstType(NTTPType,
+ MultiLevelTemplateArgumentList(TemplateArgs),
+ NTTP->getLocation(),
+ NTTP->getDeclName());
// If that worked, check the non-type template parameter type
// for validity.
if (!NTTPType.isNull())
- NTTPType = CheckNonTypeTemplateParameterType(NTTPType,
+ NTTPType = CheckNonTypeTemplateParameterType(NTTPType,
NTTP->getLocation());
if (NTTPType.isNull()) {
Invalid = true;
@@ -1217,7 +1572,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
case TemplateArgument::Null:
assert(false && "Should never see a NULL template argument here");
break;
-
+
case TemplateArgument::Expression: {
Expr *E = Arg.getAsExpr();
TemplateArgument Result;
@@ -1238,7 +1593,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
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
@@ -1254,37 +1609,37 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
Diag((*Param)->getLocation(), diag::note_template_param_here);
Invalid = true;
break;
-
+
case TemplateArgument::Pack:
assert(0 && "FIXME: Implement!");
break;
}
- } else {
+ } else {
// Check template template parameters.
- TemplateTemplateParmDecl *TempParm
+ TemplateTemplateParmDecl *TempParm
= cast<TemplateTemplateParmDecl>(*Param);
-
+
switch (Arg.getKind()) {
case TemplateArgument::Null:
assert(false && "Should never see a NULL template argument here");
break;
-
+
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());
+ Decl *D
+ = cast<DeclRefExpr>(ArgExpr)->getDecl()->getCanonicalDecl();
Converted.Append(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.
@@ -1298,11 +1653,11 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
// it to the list of converted arguments.
Converted.Append(Arg);
break;
-
+
case TemplateArgument::Integral:
assert(false && "Integral argument with template template parameter");
break;
-
+
case TemplateArgument::Pack:
assert(0 && "FIXME: Implement!");
break;
@@ -1318,7 +1673,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
///
/// 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,
+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
@@ -1327,14 +1682,14 @@ bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param,
//
// FIXME: Perform the recursive and no-linkage type checks.
const TagType *Tag = 0;
- if (const EnumType *EnumT = Arg->getAsEnumType())
+ if (const EnumType *EnumT = Arg->getAs<EnumType>())
Tag = EnumT;
- else if (const RecordType *RecordT = Arg->getAsRecordType())
+ else if (const RecordType *RecordT = Arg->getAs<RecordType>())
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() &&
+ 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);
@@ -1359,7 +1714,7 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
return false;
// C++ [temp.arg.nontype]p1:
- //
+ //
// A template-argument for a non-type, non-template
// template-parameter shall be one of: [...]
//
@@ -1370,11 +1725,11 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
// 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(Arg->getSourceRange().getBegin(),
diag::err_template_arg_extra_parens)
<< Arg->getSourceRange();
Invalid = true;
@@ -1390,7 +1745,7 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
DRE = dyn_cast<DeclRefExpr>(Arg);
if (!DRE || !isa<ValueDecl>(DRE->getDecl()))
- return Diag(Arg->getSourceRange().getBegin(),
+ return Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_not_object_or_func_form)
<< Arg->getSourceRange();
@@ -1402,14 +1757,14 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
// Cannot refer to non-static member functions
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(DRE->getDecl()))
if (!Method->isStatic())
- return Diag(Arg->getSourceRange().getBegin(),
+ 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(Arg->getSourceRange().getBegin(),
diag::err_template_arg_function_not_extern)
<< Func << Arg->getSourceRange();
Diag(Func->getLocation(), diag::note_template_arg_internal_object)
@@ -1424,7 +1779,7 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
if (!Var->hasGlobalStorage()) {
- Diag(Arg->getSourceRange().getBegin(),
+ Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_object_not_extern)
<< Var << Arg->getSourceRange();
Diag(Var->getLocation(), diag::note_template_arg_internal_object)
@@ -1436,19 +1791,19 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
Entity = Var;
return Invalid;
}
-
+
// We found something else, but we don't know specifically what it is.
- Diag(Arg->getSourceRange().getBegin(),
+ Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_not_object_or_func)
<< Arg->getSourceRange();
- Diag(DRE->getDecl()->getLocation(),
+ 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
+bool
Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) {
bool Invalid = false;
@@ -1461,7 +1816,7 @@ Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) {
return false;
// C++ [temp.arg.nontype]p1:
- //
+ //
// A template-argument for a non-type, non-template
// template-parameter shall be one of: [...]
//
@@ -1471,7 +1826,7 @@ Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) {
// Ignore (and complain about) any excess parentheses.
while (ParenExpr *Parens = dyn_cast<ParenExpr>(Arg)) {
if (!Invalid) {
- Diag(Arg->getSourceRange().getBegin(),
+ Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_extra_parens)
<< Arg->getSourceRange();
Invalid = true;
@@ -1501,10 +1856,10 @@ Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) {
}
// We found something else, but we don't know specifically what it is.
- Diag(Arg->getSourceRange().getBegin(),
+ Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_not_pointer_to_member_form)
<< Arg->getSourceRange();
- Diag(DRE->getDecl()->getLocation(),
+ Diag(DRE->getDecl()->getLocation(),
diag::note_template_arg_refers_here);
return true;
}
@@ -1519,7 +1874,7 @@ Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) {
///
/// If no error was detected, Converted receives the converted template argument.
bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
- QualType InstantiatedParamType, Expr *&Arg,
+ QualType InstantiatedParamType, Expr *&Arg,
TemplateArgument &Converted) {
SourceLocation StartLoc = Arg->getSourceRange().getBegin();
@@ -1555,7 +1910,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
SourceLocation NonConstantLoc;
llvm::APSInt Value;
if (!ArgType->isIntegralType() && !ArgType->isEnumeralType()) {
- Diag(Arg->getSourceRange().getBegin(),
+ Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_not_integral_or_enumeral)
<< ArgType << Arg->getSourceRange();
Diag(Param->getLocation(), diag::note_template_param_here);
@@ -1584,7 +1939,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
ImpCastExprToType(Arg, ParamType);
} else {
// We can't perform this conversion.
- Diag(Arg->getSourceRange().getBegin(),
+ Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_not_convertible)
<< Arg->getType() << InstantiatedParamType << Arg->getSourceRange();
Diag(Param->getLocation(), diag::note_template_param_here);
@@ -1592,7 +1947,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
}
QualType IntegerType = Context.getCanonicalType(ParamType);
- if (const EnumType *Enum = IntegerType->getAsEnumType())
+ if (const EnumType *Enum = IntegerType->getAs<EnumType>())
IntegerType = Context.getCanonicalType(Enum->getDecl()->getIntegerType());
if (!Arg->isValueDependent()) {
@@ -1610,7 +1965,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// Check that we don't overflow the template parameter type.
unsigned AllowedBits = Context.getTypeSize(IntegerType);
if (Value.getActiveBits() > AllowedBits) {
- Diag(Arg->getSourceRange().getBegin(),
+ Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_too_large)
<< Value.toString(10) << Param->getType()
<< Arg->getSourceRange();
@@ -1634,7 +1989,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
}
Converted = TemplateArgument(StartLoc, Value,
- ParamType->isEnumeralType() ? ParamType
+ ParamType->isEnumeralType() ? ParamType
: IntegerType);
return false;
}
@@ -1648,13 +2003,13 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// 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()) ||
+ ParamType->getAs<PointerType>()->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()) ||
+ ParamType->getAs<ReferenceType>()->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
@@ -1662,9 +2017,9 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// the set (13.4).
// Again, C++0x allows a std::nullptr_t value.
(ParamType->isMemberPointerType() &&
- ParamType->getAsMemberPointerType()->getPointeeType()
+ ParamType->getAs<MemberPointerType>()->getPointeeType()
->isFunctionType())) {
- if (Context.hasSameUnqualifiedType(ArgType,
+ if (Context.hasSameUnqualifiedType(ArgType,
ParamType.getNonReferenceType())) {
// We don't have to do anything: the types already match.
} else if (ArgType->isNullPtrType() && (ParamType->isPointerType() ||
@@ -1674,7 +2029,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
} else if (ArgType->isFunctionType() && ParamType->isPointerType()) {
ArgType = Context.getPointerType(ArgType);
ImpCastExprToType(Arg, ArgType);
- } else if (FunctionDecl *Fn
+ } else if (FunctionDecl *Fn
= ResolveAddressOfOverloadedFunction(Arg, ParamType, true)) {
if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin()))
return true;
@@ -1687,31 +2042,33 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
}
}
- if (!Context.hasSameUnqualifiedType(ArgType,
+ if (!Context.hasSameUnqualifiedType(ArgType,
ParamType.getNonReferenceType())) {
// We can't perform this conversion.
- Diag(Arg->getSourceRange().getBegin(),
+ 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;
- Member = cast_or_null<NamedDecl>(Context.getCanonicalDecl(Member));
+ if (Member)
+ Member = cast<NamedDecl>(Member->getCanonicalDecl());
Converted = TemplateArgument(StartLoc, Member);
return false;
}
-
+
NamedDecl *Entity = 0;
if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
return true;
- Entity = cast_or_null<NamedDecl>(Context.getCanonicalDecl(Entity));
+ if (Entity)
+ Entity = cast<NamedDecl>(Entity->getCanonicalDecl());
Converted = TemplateArgument(StartLoc, Entity);
return false;
}
@@ -1721,7 +2078,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// 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() &&
+ assert(ParamType->getAs<PointerType>()->getPointeeType()->isObjectType() &&
"Only object pointers allowed here");
if (ArgType->isNullPtrType()) {
@@ -1736,26 +2093,27 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
ArgType = ParamType;
ImpCastExprToType(Arg, ParamType);
}
-
+
if (!Context.hasSameUnqualifiedType(ArgType, ParamType)) {
// We can't perform this conversion.
- Diag(Arg->getSourceRange().getBegin(),
+ 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;
- Entity = cast_or_null<NamedDecl>(Context.getCanonicalDecl(Entity));
+ if (Entity)
+ Entity = cast<NamedDecl>(Entity->getCanonicalDecl());
Converted = TemplateArgument(StartLoc, Entity);
return false;
}
-
- if (const ReferenceType *ParamRefType = ParamType->getAsReferenceType()) {
+
+ if (const ReferenceType *ParamRefType = ParamType->getAs<ReferenceType>()) {
// -- 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
@@ -1766,7 +2124,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
"Only object references allowed here");
if (!Context.hasSameUnqualifiedType(ParamRefType->getPointeeType(), ArgType)) {
- Diag(Arg->getSourceRange().getBegin(),
+ Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_no_ref_bind)
<< InstantiatedParamType << Arg->getType()
<< Arg->getSourceRange();
@@ -1774,10 +2132,10 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return true;
}
- unsigned ParamQuals
+ 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)
@@ -1786,12 +2144,12 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
Diag(Param->getLocation(), diag::note_template_param_here);
return true;
}
-
+
NamedDecl *Entity = 0;
if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
return true;
- Entity = cast<NamedDecl>(Context.getCanonicalDecl(Entity));
+ Entity = cast<NamedDecl>(Entity->getCanonicalDecl());
Converted = TemplateArgument(StartLoc, Entity);
return false;
}
@@ -1809,18 +2167,19 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
ImpCastExprToType(Arg, ParamType);
} else {
// We can't perform this conversion.
- Diag(Arg->getSourceRange().getBegin(),
+ 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;
+ return true;
}
NamedDecl *Member = 0;
if (CheckTemplateArgumentPointerToMember(Arg, Member))
return true;
-
- Member = cast_or_null<NamedDecl>(Context.getCanonicalDecl(Member));
+
+ if (Member)
+ Member = cast<NamedDecl>(Member->getCanonicalDecl());
Converted = TemplateArgument(StartLoc, Member);
return false;
}
@@ -1846,9 +2205,9 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param,
// Note that we also allow template template parameters here, which
// will happen when we are dealing with, e.g., class template
// partial specializations.
- if (!isa<ClassTemplateDecl>(Template) &&
+ if (!isa<ClassTemplateDecl>(Template) &&
!isa<TemplateTemplateParmDecl>(Template)) {
- assert(isa<FunctionTemplateDecl>(Template) &&
+ assert(isa<FunctionTemplateDecl>(Template) &&
"Only function templates are possible here");
Diag(Arg->getLocStart(), diag::err_template_arg_not_class_template);
Diag(Template->getLocation(), diag::note_template_arg_refers_here_func)
@@ -1864,7 +2223,7 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param,
/// \brief Determine whether the given template parameter lists are
/// equivalent.
///
-/// \param New The new template parameter list, typically written in the
+/// \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
@@ -1886,7 +2245,7 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param,
///
/// \returns True if the template parameter lists are equal, false
/// otherwise.
-bool
+bool
Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
TemplateParameterList *Old,
bool Complain,
@@ -1898,7 +2257,7 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
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
@@ -1939,15 +2298,15 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
// 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
+ QualType OldParmType
= Context.getTypeDeclType(cast<TemplateTypeParmDecl>(*OldParm));
- QualType NewParmType
+ QualType NewParmType
= Context.getTypeDeclType(cast<TemplateTypeParmDecl>(*NewParm));
- assert(Context.getCanonicalType(OldParmType) ==
- Context.getCanonicalType(NewParmType) &&
+ assert(Context.getCanonicalType(OldParmType) ==
+ Context.getCanonicalType(NewParmType) &&
"type parameter mismatch?");
#endif
- } else if (NonTypeTemplateParmDecl *OldNTTP
+ } else if (NonTypeTemplateParmDecl *OldNTTP
= dyn_cast<NonTypeTemplateParmDecl>(*OldParm)) {
// The types of non-type template parameters must agree.
NonTypeTemplateParmDecl *NewNTTP
@@ -1957,14 +2316,14 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
if (Complain) {
unsigned NextDiag = diag::err_template_nontype_parm_different_type;
if (TemplateArgLoc.isValid()) {
- Diag(TemplateArgLoc,
+ 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(OldNTTP->getLocation(),
diag::note_template_nontype_parm_prev_declaration)
<< OldNTTP->getType();
}
@@ -1974,9 +2333,9 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
// The template parameter lists of template template
// parameters must agree.
// FIXME: Could we perform a faster "type" comparison here?
- assert(isa<TemplateTemplateParmDecl>(*OldParm) &&
+ assert(isa<TemplateTemplateParmDecl>(*OldParm) &&
"Only template template parameters handled here");
- TemplateTemplateParmDecl *OldTTP
+ TemplateTemplateParmDecl *OldTTP
= cast<TemplateTemplateParmDecl>(*OldParm);
TemplateTemplateParmDecl *NewTTP
= cast<TemplateTemplateParmDecl>(*NewParm);
@@ -1996,56 +2355,105 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
///
/// 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");
-
+bool
+Sema::CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams) {
// 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;
+ if (Ctx && isa<LinkageSpecDecl>(Ctx) &&
+ cast<LinkageSpecDecl>(Ctx)->getLanguage() != LinkageSpecDecl::lang_cxx)
+ return Diag(TemplateParams->getTemplateLoc(), diag::err_template_linkage)
+ << TemplateParams->getSourceRange();
+ while (Ctx && isa<LinkageSpecDecl>(Ctx))
Ctx = Ctx->getParent();
- }
if (Ctx && (Ctx->isFileContext() || Ctx->isRecord()))
return false;
- return Diag(TemplateLoc, diag::err_template_outside_namespace_or_class_scope)
- << TemplateRange;
+ return Diag(TemplateParams->getTemplateLoc(),
+ diag::err_template_outside_namespace_or_class_scope)
+ << TemplateParams->getSourceRange();
+}
+
+/// \brief Determine what kind of template specialization the given declaration
+/// is.
+static TemplateSpecializationKind getTemplateSpecializationKind(NamedDecl *D) {
+ if (!D)
+ return TSK_Undeclared;
+
+ if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D))
+ return Record->getTemplateSpecializationKind();
+ if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D))
+ return Function->getTemplateSpecializationKind();
+ if (VarDecl *Var = dyn_cast<VarDecl>(D))
+ return Var->getTemplateSpecializationKind();
+
+ return TSK_Undeclared;
}
-/// \brief Check whether a class template specialization or explicit
-/// instantiation in the current context is well-formed.
+/// \brief Check whether a specialization or explicit instantiation is
+/// well-formed in the current context.
///
-/// 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 PartialSpecialization,
- bool ExplicitInstantiation) {
+/// This routine determines whether a template specialization or
+/// explicit instantiation can be declared in the current context
+/// (C++ [temp.expl.spec]p2, C++0x [temp.explicit]p2).
+///
+/// \param S the semantic analysis object for which this check is being
+/// performed.
+///
+/// \param Specialized the entity being specialized or instantiated, which
+/// may be a kind of template (class template, function template, etc.) or
+/// a member of a class template (member function, static data member,
+/// member class).
+///
+/// \param PrevDecl the previous declaration of this entity, if any.
+///
+/// \param Loc the location of the explicit specialization or instantiation of
+/// this entity.
+///
+/// \param IsPartialSpecialization whether this is a partial specialization of
+/// a class template.
+///
+/// \param TSK the kind of specialization or implicit instantiation being
+/// performed.
+///
+/// \returns true if there was an error that we cannot recover from, false
+/// otherwise.
+static bool CheckTemplateSpecializationScope(Sema &S,
+ NamedDecl *Specialized,
+ NamedDecl *PrevDecl,
+ SourceLocation Loc,
+ bool IsPartialSpecialization,
+ TemplateSpecializationKind TSK) {
+ // Keep these "kind" numbers in sync with the %select statements in the
+ // various diagnostics emitted by this routine.
+ int EntityKind = 0;
+ bool isTemplateSpecialization = false;
+ if (isa<ClassTemplateDecl>(Specialized)) {
+ EntityKind = IsPartialSpecialization? 1 : 0;
+ isTemplateSpecialization = true;
+ } else if (isa<FunctionTemplateDecl>(Specialized)) {
+ EntityKind = 2;
+ isTemplateSpecialization = true;
+ } else if (isa<CXXMethodDecl>(Specialized))
+ EntityKind = 3;
+ else if (isa<VarDecl>(Specialized))
+ EntityKind = 4;
+ else if (isa<RecordDecl>(Specialized))
+ EntityKind = 5;
+ else {
+ S.Diag(Loc, diag::err_template_spec_unknown_kind) << TSK;
+ S.Diag(Specialized->getLocation(), diag::note_specialized_entity) << TSK;
+ return true;
+ }
+
// 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
@@ -2059,66 +2467,79 @@ Sema::CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate,
// the explicit specialization was declared, or in a namespace
// that encloses the one in which the explicit specialization was
// declared.
- if (CurContext->getLookupContext()->isFunctionOrMethod()) {
- int Kind = ExplicitInstantiation? 2 : PartialSpecialization? 1 : 0;
- Diag(TemplateNameLoc, diag::err_template_spec_decl_function_scope)
- << Kind << ClassTemplate;
+ if (S.CurContext->getLookupContext()->isFunctionOrMethod()) {
+ S.Diag(Loc, diag::err_template_spec_decl_function_scope)
+ << TSK << Specialized;
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)
- << PartialSpecialization
- << ClassTemplate << ScopeSpecifierRange;
- else if (isa<NamespaceDecl>(TemplateContext))
- Diag(TemplateNameLoc, diag::err_template_spec_decl_out_of_scope)
- << PartialSpecialization << ClassTemplate
- << cast<NamedDecl>(TemplateContext) << ScopeSpecifierRange;
-
- Diag(ClassTemplate->getLocation(), diag::note_template_decl_here);
- }
-
- return false;
+ if (S.CurContext->isRecord() && !IsPartialSpecialization) {
+ S.Diag(Loc, diag::err_template_spec_decl_class_scope)
+ << TSK << Specialized;
+ return true;
}
-
- // 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;
- int Kind = ExplicitInstantiation? 2 : PartialSpecialization? 1 : 0;
- if (isa<TranslationUnitDecl>(TemplateContext)) {
- if (!ExplicitInstantiation || getLangOptions().CPlusPlus0x)
- Diag(TemplateNameLoc, diag::err_template_spec_redecl_global_scope)
- << Kind << ClassTemplate << ScopeSpecifierRange;
- else
- SuppressedDiag = true;
- } else if (isa<NamespaceDecl>(TemplateContext)) {
- if (!ExplicitInstantiation || getLangOptions().CPlusPlus0x)
- Diag(TemplateNameLoc, diag::err_template_spec_redecl_out_of_scope)
- << Kind << ClassTemplate
- << cast<NamedDecl>(TemplateContext) << ScopeSpecifierRange;
- else
- SuppressedDiag = true;
+
+ // C++ [temp.class.spec]p6:
+ // A class template partial specialization may be declared or redeclared
+ // in any namespace scope in which its definition may be defined (14.5.1
+ // and 14.5.2).
+ bool ComplainedAboutScope = false;
+ DeclContext *SpecializedContext
+ = Specialized->getDeclContext()->getEnclosingNamespaceContext();
+ DeclContext *DC = S.CurContext->getEnclosingNamespaceContext();
+ if (TSK == TSK_ExplicitSpecialization) {
+ if ((!PrevDecl ||
+ getTemplateSpecializationKind(PrevDecl) == TSK_Undeclared ||
+ getTemplateSpecializationKind(PrevDecl) == TSK_ImplicitInstantiation)){
+ // There is no prior declaration of this entity, so this
+ // specialization must be in the same context as the template
+ // itself.
+ if (!DC->Equals(SpecializedContext)) {
+ if (isa<TranslationUnitDecl>(SpecializedContext))
+ S.Diag(Loc, diag::err_template_spec_decl_out_of_scope_global)
+ << EntityKind << Specialized;
+ else if (isa<NamespaceDecl>(SpecializedContext))
+ S.Diag(Loc, diag::err_template_spec_decl_out_of_scope)
+ << EntityKind << Specialized
+ << cast<NamedDecl>(SpecializedContext);
+
+ S.Diag(Specialized->getLocation(), diag::note_specialized_entity)
+ << TSK;
+ ComplainedAboutScope = true;
+ }
}
-
- if (!SuppressedDiag)
- Diag(ClassTemplate->getLocation(), diag::note_template_decl_here);
}
-
+
+ // Make sure that this redeclaration (or definition) occurs in an enclosing
+ // namespace. We perform this check for explicit specializations and, in
+ // C++0x, for explicit instantiations as well (per DR275).
+ // FIXME: -Wc++0x should make these warnings.
+ // Note that HandleDeclarator() performs this check for explicit
+ // specializations of function templates, static data members, and member
+ // functions, so we skip the check here for those kinds of entities.
+ // FIXME: HandleDeclarator's diagnostics aren't quite as good, though.
+ // Should we refactor that check, so that it occurs later?
+ if (!ComplainedAboutScope && !DC->Encloses(SpecializedContext) &&
+ ((TSK == TSK_ExplicitSpecialization &&
+ !(isa<FunctionTemplateDecl>(Specialized) || isa<VarDecl>(Specialized) ||
+ isa<FunctionDecl>(Specialized))) ||
+ S.getLangOptions().CPlusPlus0x)) {
+ if (isa<TranslationUnitDecl>(SpecializedContext))
+ S.Diag(Loc, diag::err_template_spec_redecl_global_scope)
+ << EntityKind << Specialized;
+ else if (isa<NamespaceDecl>(SpecializedContext))
+ S.Diag(Loc, diag::err_template_spec_redecl_out_of_scope)
+ << EntityKind << Specialized
+ << cast<NamedDecl>(SpecializedContext);
+
+ S.Diag(Specialized->getLocation(), diag::note_specialized_entity) << TSK;
+ }
+
+ // FIXME: check for specialization-after-instantiation errors and such.
+
return false;
}
-
+
/// \brief Check the non-type template arguments of a class template
/// partial specialization according to C++ [temp.class.spec]p9.
///
@@ -2142,16 +2563,16 @@ bool Sema::CheckClassTemplatePartialSpecializationArgs(
// FIXME: the interface to this function will have to change to
// accommodate variadic templates.
MirrorsPrimaryTemplate = true;
-
+
const TemplateArgument *ArgList = TemplateArgs.getFlatArguments();
-
+
for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) {
// Determine whether the template argument list of the partial
// specialization is identical to the implicit argument list of
// the primary template. The caller may need to diagnostic this as
// an error per C++ [temp.class.spec]p9b3.
if (MirrorsPrimaryTemplate) {
- if (TemplateTypeParmDecl *TTP
+ if (TemplateTypeParmDecl *TTP
= dyn_cast<TemplateTypeParmDecl>(TemplateParams->getParam(I))) {
if (Context.getCanonicalType(Context.getTypeDeclType(TTP)) !=
Context.getCanonicalType(ArgList[I].getAsType()))
@@ -2161,11 +2582,11 @@ bool Sema::CheckClassTemplatePartialSpecializationArgs(
TemplateParams->getParam(I))) {
// FIXME: We should settle on either Declaration storage or
// Expression storage for template template parameters.
- TemplateTemplateParmDecl *ArgDecl
+ TemplateTemplateParmDecl *ArgDecl
= dyn_cast_or_null<TemplateTemplateParmDecl>(
ArgList[I].getAsDecl());
if (!ArgDecl)
- if (DeclRefExpr *DRE
+ if (DeclRefExpr *DRE
= dyn_cast_or_null<DeclRefExpr>(ArgList[I].getAsExpr()))
ArgDecl = dyn_cast<TemplateTemplateParmDecl>(DRE->getDecl());
@@ -2176,7 +2597,7 @@ bool Sema::CheckClassTemplatePartialSpecializationArgs(
}
}
- NonTypeTemplateParmDecl *Param
+ NonTypeTemplateParmDecl *Param
= dyn_cast<NonTypeTemplateParmDecl>(TemplateParams->getParam(I));
if (!Param) {
continue;
@@ -2197,9 +2618,9 @@ bool Sema::CheckClassTemplatePartialSpecializationArgs(
// specialized non-type arguments, so skip any non-specialized
// arguments.
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ArgExpr))
- if (NonTypeTemplateParmDecl *NTTP
+ if (NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(DRE->getDecl())) {
- if (MirrorsPrimaryTemplate &&
+ if (MirrorsPrimaryTemplate &&
(Param->getIndex() != NTTP->getIndex() ||
Param->getDepth() != NTTP->getDepth()))
MirrorsPrimaryTemplate = false;
@@ -2215,7 +2636,7 @@ bool Sema::CheckClassTemplatePartialSpecializationArgs(
// specialization except when the argument expression is a
// simple identifier.
if (ArgExpr->isTypeDependent() || ArgExpr->isValueDependent()) {
- Diag(ArgExpr->getLocStart(),
+ Diag(ArgExpr->getLocStart(),
diag::err_dependent_non_type_arg_in_partial_spec)
<< ArgExpr->getSourceRange();
return true;
@@ -2225,7 +2646,7 @@ bool Sema::CheckClassTemplatePartialSpecializationArgs(
// specialized non-type argument shall not be dependent on a
// parameter of the specialization.
if (Param->getType()->isDependentType()) {
- Diag(ArgExpr->getLocStart(),
+ Diag(ArgExpr->getLocStart(),
diag::err_dependent_typed_non_type_arg_in_partial_spec)
<< Param->getType()
<< ArgExpr->getSourceRange();
@@ -2240,8 +2661,9 @@ bool Sema::CheckClassTemplatePartialSpecializationArgs(
}
Sema::DeclResult
-Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
- SourceLocation KWLoc,
+Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
+ TagUseKind TUK,
+ SourceLocation KWLoc,
const CXXScopeSpec &SS,
TemplateTy TemplateD,
SourceLocation TemplateNameLoc,
@@ -2251,65 +2673,72 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
SourceLocation RAngleLoc,
AttributeList *Attr,
MultiTemplateParamsArg TemplateParameterLists) {
+ assert(TUK != TUK_Reference && "References are not specializations");
+
// Find the class template we're specializing
TemplateName Name = TemplateD.getAsVal<TemplateName>();
- ClassTemplateDecl *ClassTemplate
+ ClassTemplateDecl *ClassTemplate
= cast<ClassTemplateDecl>(Name.getAsTemplateDecl());
+ bool isExplicitSpecialization = false;
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;
- }
-
- if (TemplateParams->size() > 0) {
- isPartialSpecialization = true;
-
- // C++ [temp.class.spec]p10:
- // The template parameter list of a specialization shall not
- // contain default template argument values.
- for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) {
- Decl *Param = TemplateParams->getParam(I);
- if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
- if (TTP->hasDefaultArgument()) {
- Diag(TTP->getDefaultArgumentLoc(),
- diag::err_default_arg_in_partial_spec);
- TTP->setDefaultArgument(QualType(), SourceLocation(), false);
- }
- } else if (NonTypeTemplateParmDecl *NTTP
- = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
- if (Expr *DefArg = NTTP->getDefaultArgument()) {
- Diag(NTTP->getDefaultArgumentLoc(),
- diag::err_default_arg_in_partial_spec)
- << DefArg->getSourceRange();
- NTTP->setDefaultArgument(0);
- DefArg->Destroy(Context);
- }
- } else {
- TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(Param);
- if (Expr *DefArg = TTP->getDefaultArgument()) {
- Diag(TTP->getDefaultArgumentLoc(),
- diag::err_default_arg_in_partial_spec)
- << DefArg->getSourceRange();
- TTP->setDefaultArgument(0);
- DefArg->Destroy(Context);
- }
+ // FIXME: We probably shouldn't complain about these headers for
+ // friend declarations.
+ TemplateParameterList *TemplateParams
+ = MatchTemplateParametersToScopeSpecifier(TemplateNameLoc, SS,
+ (TemplateParameterList**)TemplateParameterLists.get(),
+ TemplateParameterLists.size(),
+ isExplicitSpecialization);
+ if (TemplateParams && TemplateParams->size() > 0) {
+ isPartialSpecialization = true;
+
+ // C++ [temp.class.spec]p10:
+ // The template parameter list of a specialization shall not
+ // contain default template argument values.
+ for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) {
+ Decl *Param = TemplateParams->getParam(I);
+ if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
+ if (TTP->hasDefaultArgument()) {
+ Diag(TTP->getDefaultArgumentLoc(),
+ diag::err_default_arg_in_partial_spec);
+ TTP->setDefaultArgument(QualType(), SourceLocation(), false);
+ }
+ } else if (NonTypeTemplateParmDecl *NTTP
+ = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
+ if (Expr *DefArg = NTTP->getDefaultArgument()) {
+ Diag(NTTP->getDefaultArgumentLoc(),
+ diag::err_default_arg_in_partial_spec)
+ << DefArg->getSourceRange();
+ NTTP->setDefaultArgument(0);
+ DefArg->Destroy(Context);
+ }
+ } else {
+ TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(Param);
+ if (Expr *DefArg = TTP->getDefaultArgument()) {
+ Diag(TTP->getDefaultArgumentLoc(),
+ diag::err_default_arg_in_partial_spec)
+ << DefArg->getSourceRange();
+ TTP->setDefaultArgument(0);
+ DefArg->Destroy(Context);
}
}
}
+ } else if (TemplateParams) {
+ if (TUK == TUK_Friend)
+ Diag(KWLoc, diag::err_template_spec_friend)
+ << CodeModificationHint::CreateRemoval(
+ SourceRange(TemplateParams->getTemplateLoc(),
+ TemplateParams->getRAngleLoc()))
+ << SourceRange(LAngleLoc, RAngleLoc);
+ else
+ isExplicitSpecialization = true;
+ } else if (TUK != TUK_Friend) {
+ Diag(KWLoc, diag::err_template_spec_needs_header)
+ << CodeModificationHint::CreateInsertion(KWLoc, "template<> ");
+ isExplicitSpecialization = true;
}
// Check that the specialization uses the same tag kind as the
@@ -2322,13 +2751,13 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
case DeclSpec::TST_class: Kind = TagDecl::TK_class; break;
}
if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(),
- Kind, KWLoc,
+ Kind, KWLoc,
*ClassTemplate->getIdentifier())) {
- Diag(KWLoc, diag::err_use_with_wrong_tag)
+ Diag(KWLoc, diag::err_use_with_wrong_tag)
<< ClassTemplate
- << CodeModificationHint::CreateReplacement(KWLoc,
+ << CodeModificationHint::CreateReplacement(KWLoc,
ClassTemplate->getTemplatedDecl()->getKindName());
- Diag(ClassTemplate->getTemplatedDecl()->getLocation(),
+ Diag(ClassTemplate->getTemplatedDecl()->getLocation(),
diag::note_previous_use);
Kind = ClassTemplate->getTemplatedDecl()->getTagKind();
}
@@ -2341,15 +2770,15 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
// template.
TemplateArgumentListBuilder Converted(ClassTemplate->getTemplateParameters(),
TemplateArgs.size());
- if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, LAngleLoc,
+ if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, LAngleLoc,
TemplateArgs.data(), TemplateArgs.size(),
RAngleLoc, false, Converted))
return true;
- assert((Converted.structuredSize() ==
+ assert((Converted.structuredSize() ==
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;
@@ -2363,35 +2792,38 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
if (MirrorsPrimaryTemplate) {
// C++ [temp.class.spec]p9b3:
//
- // -- The argument list of the specialization shall not be identical
- // to the implicit argument list of the primary template.
+ // -- The argument list of the specialization shall not be identical
+ // to the implicit argument list of the primary template.
Diag(TemplateNameLoc, diag::err_partial_spec_args_match_primary_template)
- << (TK == TK_Definition)
- << CodeModificationHint::CreateRemoval(SourceRange(LAngleLoc,
+ << (TUK == TUK_Definition)
+ << CodeModificationHint::CreateRemoval(SourceRange(LAngleLoc,
RAngleLoc));
- return ActOnClassTemplate(S, TagSpec, TK, KWLoc, SS,
+ return CheckClassTemplate(S, TagSpec, TUK, KWLoc, SS,
ClassTemplate->getIdentifier(),
TemplateNameLoc,
Attr,
- move(TemplateParameterLists),
+ TemplateParams,
AS_none);
}
+ // FIXME: Diagnose friend partial specializations
+
// FIXME: Template parameter list matters, too
- ClassTemplatePartialSpecializationDecl::Profile(ID,
+ ClassTemplatePartialSpecializationDecl::Profile(ID,
Converted.getFlatArguments(),
- Converted.flatSize());
- }
- else
+ Converted.flatSize(),
+ Context);
+ } else
ClassTemplateSpecializationDecl::Profile(ID,
Converted.getFlatArguments(),
- Converted.flatSize());
+ Converted.flatSize(),
+ Context);
void *InsertPos = 0;
ClassTemplateSpecializationDecl *PrevDecl = 0;
if (isPartialSpecialization)
PrevDecl
- = ClassTemplate->getPartialSpecializations().FindNodeOrInsertPos(ID,
+ = ClassTemplate->getPartialSpecializations().FindNodeOrInsertPos(ID,
InsertPos);
else
PrevDecl
@@ -2401,29 +2833,41 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
// Check whether we can declare a class template specialization in
// the current scope.
- if (CheckClassTemplateSpecializationScope(ClassTemplate, PrevDecl,
- TemplateNameLoc,
- SS.getRange(),
- isPartialSpecialization,
- /*ExplicitInstantiation=*/false))
+ if (TUK != TUK_Friend &&
+ CheckTemplateSpecializationScope(*this, ClassTemplate, PrevDecl,
+ TemplateNameLoc, isPartialSpecialization,
+ TSK_ExplicitSpecialization))
return true;
-
- if (PrevDecl && PrevDecl->getSpecializationKind() == TSK_Undeclared) {
+
+ // The canonical type
+ QualType CanonType;
+ if (PrevDecl &&
+ (PrevDecl->getSpecializationKind() == TSK_Undeclared ||
+ TUK == TUK_Friend)) {
// Since the only prior class template specialization with these
- // arguments was referenced but not declared, reuse that
+ // arguments was referenced but not declared, or we're only
+ // referencing this specialization as a friend, reuse that
// declaration node as our own, updating its source location to
// reflect our new declaration.
Specialization = PrevDecl;
Specialization->setLocation(TemplateNameLoc);
PrevDecl = 0;
+ CanonType = Context.getTypeDeclType(Specialization);
} else if (isPartialSpecialization) {
+ // Build the canonical type that describes the converted template
+ // arguments of the class template partial specialization.
+ CanonType = Context.getTemplateSpecializationType(
+ TemplateName(ClassTemplate),
+ Converted.getFlatArguments(),
+ Converted.flatSize());
+
// Create a new class template partial specialization declaration node.
- TemplateParameterList *TemplateParams
+ TemplateParameterList *TemplateParams
= static_cast<TemplateParameterList*>(*TemplateParameterLists.get());
ClassTemplatePartialSpecializationDecl *PrevPartial
= cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl);
- ClassTemplatePartialSpecializationDecl *Partial
- = ClassTemplatePartialSpecializationDecl::Create(Context,
+ ClassTemplatePartialSpecializationDecl *Partial
+ = ClassTemplatePartialSpecializationDecl::Create(Context,
ClassTemplate->getDeclContext(),
TemplateNameLoc,
TemplateParams,
@@ -2445,7 +2889,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
// will never be used.
llvm::SmallVector<bool, 8> DeducibleParams;
DeducibleParams.resize(TemplateParams->size());
- MarkDeducedTemplateParameters(Partial->getTemplateArgs(), DeducibleParams);
+ MarkUsedTemplateParameters(Partial->getTemplateArgs(), true,
+ DeducibleParams);
unsigned NumNonDeducible = 0;
for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I)
if (!DeducibleParams[I])
@@ -2459,25 +2904,24 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
if (!DeducibleParams[I]) {
NamedDecl *Param = cast<NamedDecl>(TemplateParams->getParam(I));
if (Param->getDeclName())
- Diag(Param->getLocation(),
+ Diag(Param->getLocation(),
diag::note_partial_spec_unused_parameter)
<< Param->getDeclName();
else
- Diag(Param->getLocation(),
+ Diag(Param->getLocation(),
diag::note_partial_spec_unused_parameter)
<< std::string("<anonymous>");
}
}
}
-
} else {
// Create a new class template specialization declaration node for
- // this explicit specialization.
+ // this explicit specialization or friend declaration.
Specialization
- = ClassTemplateSpecializationDecl::Create(Context,
+ = ClassTemplateSpecializationDecl::Create(Context,
ClassTemplate->getDeclContext(),
TemplateNameLoc,
- ClassTemplate,
+ ClassTemplate,
Converted,
PrevDecl);
@@ -2485,21 +2929,40 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
ClassTemplate->getSpecializations().RemoveNode(PrevDecl);
ClassTemplate->getSpecializations().GetOrInsertNode(Specialization);
} else {
- ClassTemplate->getSpecializations().InsertNode(Specialization,
+ ClassTemplate->getSpecializations().InsertNode(Specialization,
InsertPos);
}
+
+ CanonType = Context.getTypeDeclType(Specialization);
}
- // Note that this is an explicit specialization.
- Specialization->setSpecializationKind(TSK_ExplicitSpecialization);
+ // C++ [temp.expl.spec]p6:
+ // If a template, a member template or the member of a class template is
+ // explicitly specialized then that specialization shall be declared
+ // before the first use of that specialization that would cause an implicit
+ // instantiation to take place, in every translation unit in which such a
+ // use occurs; no diagnostic is required.
+ if (PrevDecl && PrevDecl->getPointOfInstantiation().isValid()) {
+ SourceRange Range(TemplateNameLoc, RAngleLoc);
+ Diag(TemplateNameLoc, diag::err_specialization_after_instantiation)
+ << Context.getTypeDeclType(Specialization) << Range;
+
+ Diag(PrevDecl->getPointOfInstantiation(),
+ diag::note_instantiation_required_here)
+ << (PrevDecl->getTemplateSpecializationKind()
+ != TSK_ImplicitInstantiation);
+ return true;
+ }
+
+ // If this is not a friend, note that this is an explicit specialization.
+ if (TUK != TUK_Friend)
+ Specialization->setSpecializationKind(TSK_ExplicitSpecialization);
// Check that this isn't a redefinition of this specialization.
- if (TK == TK_Definition) {
+ if (TUK == TUK_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)
+ Diag(TemplateNameLoc, diag::err_redefinition)
<< Context.getTypeDeclType(Specialization) << Range;
Diag(Def->getLocation(), diag::note_previous_definition);
Specialization->setInvalidDecl();
@@ -2514,12 +2977,13 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
// 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,
+ QualType WrittenTy
+ = Context.getTemplateSpecializationType(Name,
TemplateArgs.data(),
TemplateArgs.size(),
- Context.getTypeDeclType(Specialization));
- Specialization->setTypeAsWritten(WrittenTy);
+ CanonType);
+ if (TUK != TUK_Friend)
+ Specialization->setTypeAsWritten(WrittenTy);
TemplateArgsIn.release();
// C++ [temp.expl.spec]p9:
@@ -2531,56 +2995,343 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
// 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)
+ if (TUK == TUK_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(Specialization);
+ if (TUK == TUK_Friend) {
+ FriendDecl *Friend = FriendDecl::Create(Context, CurContext,
+ TemplateNameLoc,
+ WrittenTy.getTypePtr(),
+ /*FIXME:*/KWLoc);
+ Friend->setAccess(AS_public);
+ CurContext->addDecl(Friend);
+ } else {
+ // 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(Specialization);
+ }
return DeclPtrTy::make(Specialization);
}
-Sema::DeclPtrTy
-Sema::ActOnTemplateDeclarator(Scope *S,
+Sema::DeclPtrTy
+Sema::ActOnTemplateDeclarator(Scope *S,
MultiTemplateParamsArg TemplateParameterLists,
Declarator &D) {
return HandleDeclarator(S, D, move(TemplateParameterLists), false);
}
-Sema::DeclPtrTy
-Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
+Sema::DeclPtrTy
+Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
MultiTemplateParamsArg TemplateParameterLists,
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.
+ // FIXME: Diagnose arguments without names in C.
}
-
+
Scope *ParentScope = FnBodyScope->getParent();
-
- DeclPtrTy DP = HandleDeclarator(ParentScope, D,
+
+ DeclPtrTy DP = HandleDeclarator(ParentScope, D,
move(TemplateParameterLists),
/*IsFunctionDefinition=*/true);
- FunctionTemplateDecl *FunctionTemplate
- = cast_or_null<FunctionTemplateDecl>(DP.getAs<Decl>());
- if (FunctionTemplate)
- return ActOnStartOfFunctionDef(FnBodyScope,
+ if (FunctionTemplateDecl *FunctionTemplate
+ = dyn_cast_or_null<FunctionTemplateDecl>(DP.getAs<Decl>()))
+ return ActOnStartOfFunctionDef(FnBodyScope,
DeclPtrTy::make(FunctionTemplate->getTemplatedDecl()));
-
+ if (FunctionDecl *Function = dyn_cast_or_null<FunctionDecl>(DP.getAs<Decl>()))
+ return ActOnStartOfFunctionDef(FnBodyScope, DeclPtrTy::make(Function));
return DeclPtrTy();
}
+/// \brief Perform semantic analysis for the given function template
+/// specialization.
+///
+/// This routine performs all of the semantic analysis required for an
+/// explicit function template specialization. On successful completion,
+/// the function declaration \p FD will become a function template
+/// specialization.
+///
+/// \param FD the function declaration, which will be updated to become a
+/// function template specialization.
+///
+/// \param HasExplicitTemplateArgs whether any template arguments were
+/// explicitly provided.
+///
+/// \param LAngleLoc the location of the left angle bracket ('<'), if
+/// template arguments were explicitly provided.
+///
+/// \param ExplicitTemplateArgs the explicitly-provided template arguments,
+/// if any.
+///
+/// \param NumExplicitTemplateArgs the number of explicitly-provided template
+/// arguments. This number may be zero even when HasExplicitTemplateArgs is
+/// true as in, e.g., \c void sort<>(char*, char*);
+///
+/// \param RAngleLoc the location of the right angle bracket ('>'), if
+/// template arguments were explicitly provided.
+///
+/// \param PrevDecl the set of declarations that
+bool
+Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
+ bool HasExplicitTemplateArgs,
+ SourceLocation LAngleLoc,
+ const TemplateArgument *ExplicitTemplateArgs,
+ unsigned NumExplicitTemplateArgs,
+ SourceLocation RAngleLoc,
+ NamedDecl *&PrevDecl) {
+ // The set of function template specializations that could match this
+ // explicit function template specialization.
+ typedef llvm::SmallVector<FunctionDecl *, 8> CandidateSet;
+ CandidateSet Candidates;
+
+ DeclContext *FDLookupContext = FD->getDeclContext()->getLookupContext();
+ for (OverloadIterator Ovl(PrevDecl), OvlEnd; Ovl != OvlEnd; ++Ovl) {
+ if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(*Ovl)) {
+ // Only consider templates found within the same semantic lookup scope as
+ // FD.
+ if (!FDLookupContext->Equals(Ovl->getDeclContext()->getLookupContext()))
+ continue;
+
+ // C++ [temp.expl.spec]p11:
+ // A trailing template-argument can be left unspecified in the
+ // template-id naming an explicit function template specialization
+ // provided it can be deduced from the function argument type.
+ // Perform template argument deduction to determine whether we may be
+ // specializing this template.
+ // FIXME: It is somewhat wasteful to build
+ TemplateDeductionInfo Info(Context);
+ FunctionDecl *Specialization = 0;
+ if (TemplateDeductionResult TDK
+ = DeduceTemplateArguments(FunTmpl, HasExplicitTemplateArgs,
+ ExplicitTemplateArgs,
+ NumExplicitTemplateArgs,
+ FD->getType(),
+ Specialization,
+ Info)) {
+ // FIXME: Template argument deduction failed; record why it failed, so
+ // that we can provide nifty diagnostics.
+ (void)TDK;
+ continue;
+ }
+
+ // Record this candidate.
+ Candidates.push_back(Specialization);
+ }
+ }
+
+ // Find the most specialized function template.
+ FunctionDecl *Specialization = getMostSpecialized(Candidates.data(),
+ Candidates.size(),
+ TPOC_Other,
+ FD->getLocation(),
+ PartialDiagnostic(diag::err_function_template_spec_no_match)
+ << FD->getDeclName(),
+ PartialDiagnostic(diag::err_function_template_spec_ambiguous)
+ << FD->getDeclName() << HasExplicitTemplateArgs,
+ PartialDiagnostic(diag::note_function_template_spec_matched));
+ if (!Specialization)
+ return true;
+
+ // FIXME: Check if the prior specialization has a point of instantiation.
+ // If so, we have run afoul of .
+
+ // Check the scope of this explicit specialization.
+ if (CheckTemplateSpecializationScope(*this,
+ Specialization->getPrimaryTemplate(),
+ Specialization, FD->getLocation(),
+ false, TSK_ExplicitSpecialization))
+ return true;
+
+ // C++ [temp.expl.spec]p6:
+ // If a template, a member template or the member of a class template is
+ // explicitly specialized then that spe- cialization shall be declared
+ // before the first use of that specialization that would cause an implicit
+ // instantiation to take place, in every translation unit in which such a
+ // use occurs; no diagnostic is required.
+ FunctionTemplateSpecializationInfo *SpecInfo
+ = Specialization->getTemplateSpecializationInfo();
+ assert(SpecInfo && "Function template specialization info missing?");
+ if (SpecInfo->getPointOfInstantiation().isValid()) {
+ Diag(FD->getLocation(), diag::err_specialization_after_instantiation)
+ << FD;
+ Diag(SpecInfo->getPointOfInstantiation(),
+ diag::note_instantiation_required_here)
+ << (Specialization->getTemplateSpecializationKind()
+ != TSK_ImplicitInstantiation);
+ return true;
+ }
+
+ // Mark the prior declaration as an explicit specialization, so that later
+ // clients know that this is an explicit specialization.
+ SpecInfo->setTemplateSpecializationKind(TSK_ExplicitSpecialization);
+
+ // Turn the given function declaration into a function template
+ // specialization, with the template arguments from the previous
+ // specialization.
+ FD->setFunctionTemplateSpecialization(Context,
+ Specialization->getPrimaryTemplate(),
+ new (Context) TemplateArgumentList(
+ *Specialization->getTemplateSpecializationArgs()),
+ /*InsertPos=*/0,
+ TSK_ExplicitSpecialization);
+
+ // The "previous declaration" for this function template specialization is
+ // the prior function template specialization.
+ PrevDecl = Specialization;
+ return false;
+}
+
+/// \brief Perform semantic analysis for the given non-template member
+/// specialization.
+///
+/// This routine performs all of the semantic analysis required for an
+/// explicit member function specialization. On successful completion,
+/// the function declaration \p FD will become a member function
+/// specialization.
+///
+/// \param Member the member declaration, which will be updated to become a
+/// specialization.
+///
+/// \param PrevDecl the set of declarations, one of which may be specialized
+/// by this function specialization.
+bool
+Sema::CheckMemberSpecialization(NamedDecl *Member, NamedDecl *&PrevDecl) {
+ assert(!isa<TemplateDecl>(Member) && "Only for non-template members");
+
+ // Try to find the member we are instantiating.
+ NamedDecl *Instantiation = 0;
+ NamedDecl *InstantiatedFrom = 0;
+ MemberSpecializationInfo *MSInfo = 0;
+
+ if (!PrevDecl) {
+ // Nowhere to look anyway.
+ } else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Member)) {
+ for (OverloadIterator Ovl(PrevDecl), OvlEnd; Ovl != OvlEnd; ++Ovl) {
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*Ovl)) {
+ if (Context.hasSameType(Function->getType(), Method->getType())) {
+ Instantiation = Method;
+ InstantiatedFrom = Method->getInstantiatedFromMemberFunction();
+ MSInfo = Method->getMemberSpecializationInfo();
+ break;
+ }
+ }
+ }
+ } else if (isa<VarDecl>(Member)) {
+ if (VarDecl *PrevVar = dyn_cast<VarDecl>(PrevDecl))
+ if (PrevVar->isStaticDataMember()) {
+ Instantiation = PrevDecl;
+ InstantiatedFrom = PrevVar->getInstantiatedFromStaticDataMember();
+ MSInfo = PrevVar->getMemberSpecializationInfo();
+ }
+ } else if (isa<RecordDecl>(Member)) {
+ if (CXXRecordDecl *PrevRecord = dyn_cast<CXXRecordDecl>(PrevDecl)) {
+ Instantiation = PrevDecl;
+ InstantiatedFrom = PrevRecord->getInstantiatedFromMemberClass();
+ MSInfo = PrevRecord->getMemberSpecializationInfo();
+ }
+ }
+
+ if (!Instantiation) {
+ // There is no previous declaration that matches. Since member
+ // specializations are always out-of-line, the caller will complain about
+ // this mismatch later.
+ return false;
+ }
+
+ // Make sure that this is a specialization of a member.
+ if (!InstantiatedFrom) {
+ Diag(Member->getLocation(), diag::err_spec_member_not_instantiated)
+ << Member;
+ Diag(Instantiation->getLocation(), diag::note_specialized_decl);
+ return true;
+ }
+
+ // C++ [temp.expl.spec]p6:
+ // If a template, a member template or the member of a class template is
+ // explicitly specialized then that spe- cialization shall be declared
+ // before the first use of that specialization that would cause an implicit
+ // instantiation to take place, in every translation unit in which such a
+ // use occurs; no diagnostic is required.
+ assert(MSInfo && "Member specialization info missing?");
+ if (MSInfo->getPointOfInstantiation().isValid()) {
+ Diag(Member->getLocation(), diag::err_specialization_after_instantiation)
+ << Member;
+ Diag(MSInfo->getPointOfInstantiation(),
+ diag::note_instantiation_required_here)
+ << (MSInfo->getTemplateSpecializationKind() != TSK_ImplicitInstantiation);
+ return true;
+ }
+
+ // Check the scope of this explicit specialization.
+ if (CheckTemplateSpecializationScope(*this,
+ InstantiatedFrom,
+ Instantiation, Member->getLocation(),
+ false, TSK_ExplicitSpecialization))
+ return true;
+
+ // Note that this is an explicit instantiation of a member.
+ // the original declaration to note that it is an explicit specialization
+ // (if it was previously an implicit instantiation). This latter step
+ // makes bookkeeping easier.
+ if (isa<FunctionDecl>(Member)) {
+ FunctionDecl *InstantiationFunction = cast<FunctionDecl>(Instantiation);
+ if (InstantiationFunction->getTemplateSpecializationKind() ==
+ TSK_ImplicitInstantiation) {
+ InstantiationFunction->setTemplateSpecializationKind(
+ TSK_ExplicitSpecialization);
+ InstantiationFunction->setLocation(Member->getLocation());
+ }
+
+ cast<FunctionDecl>(Member)->setInstantiationOfMemberFunction(
+ cast<CXXMethodDecl>(InstantiatedFrom),
+ TSK_ExplicitSpecialization);
+ } else if (isa<VarDecl>(Member)) {
+ VarDecl *InstantiationVar = cast<VarDecl>(Instantiation);
+ if (InstantiationVar->getTemplateSpecializationKind() ==
+ TSK_ImplicitInstantiation) {
+ InstantiationVar->setTemplateSpecializationKind(
+ TSK_ExplicitSpecialization);
+ InstantiationVar->setLocation(Member->getLocation());
+ }
+
+ Context.setInstantiatedFromStaticDataMember(cast<VarDecl>(Member),
+ cast<VarDecl>(InstantiatedFrom),
+ TSK_ExplicitSpecialization);
+ } else {
+ assert(isa<CXXRecordDecl>(Member) && "Only member classes remain");
+ CXXRecordDecl *InstantiationClass = cast<CXXRecordDecl>(Instantiation);
+ if (InstantiationClass->getTemplateSpecializationKind() ==
+ TSK_ImplicitInstantiation) {
+ InstantiationClass->setTemplateSpecializationKind(
+ TSK_ExplicitSpecialization);
+ InstantiationClass->setLocation(Member->getLocation());
+ }
+
+ cast<CXXRecordDecl>(Member)->setInstantiationOfMemberClass(
+ cast<CXXRecordDecl>(InstantiatedFrom),
+ TSK_ExplicitSpecialization);
+ }
+
+ // Save the caller the trouble of having to figure out which declaration
+ // this specialization matches.
+ PrevDecl = Instantiation;
+ return false;
+}
+
// Explicit instantiation of a class template specialization
+// FIXME: Implement extern template semantics
Sema::DeclResult
-Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
- unsigned TagSpec,
+Sema::ActOnExplicitInstantiation(Scope *S,
+ SourceLocation ExternLoc,
+ SourceLocation TemplateLoc,
+ unsigned TagSpec,
SourceLocation KWLoc,
const CXXScopeSpec &SS,
TemplateTy TemplateD,
@@ -2592,7 +3343,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
AttributeList *Attr) {
// Find the class template we're specializing
TemplateName Name = TemplateD.getAsVal<TemplateName>();
- ClassTemplateDecl *ClassTemplate
+ ClassTemplateDecl *ClassTemplate
= cast<ClassTemplateDecl>(Name.getAsTemplateDecl());
// Check that the specialization uses the same tag kind as the
@@ -2605,29 +3356,21 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
case DeclSpec::TST_class: Kind = TagDecl::TK_class; break;
}
if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(),
- Kind, KWLoc,
+ Kind, KWLoc,
*ClassTemplate->getIdentifier())) {
- Diag(KWLoc, diag::err_use_with_wrong_tag)
+ Diag(KWLoc, diag::err_use_with_wrong_tag)
<< ClassTemplate
- << CodeModificationHint::CreateReplacement(KWLoc,
+ << CodeModificationHint::CreateReplacement(KWLoc,
ClassTemplate->getTemplatedDecl()->getKindName());
- Diag(ClassTemplate->getTemplatedDecl()->getLocation(),
+ 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(),
- /*PartialSpecialization=*/false,
- /*ExplicitInstantiation=*/true))
- return true;
-
+ TemplateSpecializationKind TSK
+ = ExternLoc.isInvalid()? TSK_ExplicitInstantiationDefinition
+ : TSK_ExplicitInstantiationDeclaration;
+
// Translate the parser's template argument list in our AST format.
llvm::SmallVector<TemplateArgument, 16> TemplateArgs;
translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs);
@@ -2636,35 +3379,47 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
// template.
TemplateArgumentListBuilder Converted(ClassTemplate->getTemplateParameters(),
TemplateArgs.size());
- if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, LAngleLoc,
+ if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, LAngleLoc,
TemplateArgs.data(), TemplateArgs.size(),
RAngleLoc, false, Converted))
return true;
- assert((Converted.structuredSize() ==
+ assert((Converted.structuredSize() ==
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,
+ ClassTemplateSpecializationDecl::Profile(ID,
Converted.getFlatArguments(),
- Converted.flatSize());
+ Converted.flatSize(),
+ Context);
void *InsertPos = 0;
ClassTemplateSpecializationDecl *PrevDecl
= ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos);
+ // C++0x [temp.explicit]p2:
+ // [...] An explicit instantiation shall appear in an enclosing
+ // namespace of its template. [...]
+ //
+ // This is C++ DR 275.
+ if (CheckTemplateSpecializationScope(*this, ClassTemplate, PrevDecl,
+ TemplateNameLoc, false,
+ TSK))
+ return true;
+
ClassTemplateSpecializationDecl *Specialization = 0;
bool SpecializationRequiresInstantiation = true;
if (PrevDecl) {
- if (PrevDecl->getSpecializationKind() == TSK_ExplicitInstantiation) {
+ if (PrevDecl->getSpecializationKind()
+ == TSK_ExplicitInstantiationDefinition) {
// 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(PrevDecl->getLocation(),
diag::note_previous_explicit_instantiation);
return DeclPtrTy::make(PrevDecl);
}
@@ -2676,10 +3431,10 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
// an explicit specialization for that template, the explicit
// instantiation has no effect.
if (!getLangOptions().CPlusPlus0x) {
- Diag(TemplateNameLoc,
+ Diag(TemplateNameLoc,
diag::ext_explicit_instantiation_after_specialization)
<< Context.getTypeDeclType(PrevDecl);
- Diag(PrevDecl->getLocation(),
+ Diag(PrevDecl->getLocation(),
diag::note_previous_template_specialization);
}
@@ -2689,14 +3444,14 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
// accurate reproduction of the source code; we don't actually
// use it for anything, since it is semantically irrelevant.
Specialization
- = ClassTemplateSpecializationDecl::Create(Context,
+ = ClassTemplateSpecializationDecl::Create(Context,
ClassTemplate->getDeclContext(),
TemplateNameLoc,
ClassTemplate,
Converted, 0);
Specialization->setLexicalDeclContext(CurContext);
CurContext->addDecl(Specialization);
- return DeclPtrTy::make(Specialization);
+ return DeclPtrTy::make(PrevDecl);
}
// If we have already (implicitly) instantiated this
@@ -2704,25 +3459,37 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
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 {
+ if (PrevDecl->getSpecializationKind() == TSK_ImplicitInstantiation ||
+ 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;
+ }
+ }
+
+ if (!Specialization) {
// Create a new class template specialization declaration node for
// this explicit specialization.
Specialization
- = ClassTemplateSpecializationDecl::Create(Context,
+ = ClassTemplateSpecializationDecl::Create(Context,
ClassTemplate->getDeclContext(),
TemplateNameLoc,
ClassTemplate,
- Converted, 0);
+ Converted, PrevDecl);
- ClassTemplate->getSpecializations().InsertNode(Specialization,
- InsertPos);
+ if (PrevDecl) {
+ // Remove the previous declaration from the folding set, since we want
+ // to introduce a new declaration.
+ ClassTemplate->getSpecializations().RemoveNode(PrevDecl);
+ ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos);
+ }
+
+ // Insert the new specialization.
+ ClassTemplate->getSpecializations().InsertNode(Specialization, InsertPos);
}
// Build the fully-sugared type for this explicit instantiation as
@@ -2732,8 +3499,8 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
// 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,
+ QualType WrittenTy
+ = Context.getTemplateSpecializationType(Name,
TemplateArgs.data(),
TemplateArgs.size(),
Context.getTypeDeclType(Specialization));
@@ -2746,6 +3513,8 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
Specialization->setLexicalDeclContext(CurContext);
CurContext->addDecl(Specialization);
+ Specialization->setPointOfInstantiation(TemplateNameLoc);
+
// 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
@@ -2754,17 +3523,20 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
// This check comes when we actually try to perform the
// instantiation.
if (SpecializationRequiresInstantiation)
- InstantiateClassTemplateSpecialization(Specialization, true);
+ InstantiateClassTemplateSpecialization(Specialization, TSK);
else // Instantiate the members of this class template specialization.
- InstantiateClassTemplateSpecializationMembers(TemplateLoc, Specialization);
+ InstantiateClassTemplateSpecializationMembers(TemplateLoc, Specialization,
+ TSK);
return DeclPtrTy::make(Specialization);
}
// Explicit instantiation of a member class of a class template.
Sema::DeclResult
-Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
- unsigned TagSpec,
+Sema::ActOnExplicitInstantiation(Scope *S,
+ SourceLocation ExternLoc,
+ SourceLocation TemplateLoc,
+ unsigned TagSpec,
SourceLocation KWLoc,
const CXXScopeSpec &SS,
IdentifierInfo *Name,
@@ -2772,8 +3544,13 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
AttributeList *Attr) {
bool Owned = false;
- DeclPtrTy TagD = ActOnTag(S, TagSpec, Action::TK_Reference,
- KWLoc, SS, Name, NameLoc, Attr, AS_none, Owned);
+ bool IsDependent = false;
+ DeclPtrTy TagD = ActOnTag(S, TagSpec, Action::TUK_Reference,
+ KWLoc, SS, Name, NameLoc, Attr, AS_none,
+ MultiTemplateParamsArg(*this, 0, 0),
+ Owned, IsDependent);
+ assert(!IsDependent && "explicit instantiation of dependent name not yet handled");
+
if (!TagD)
return true;
@@ -2804,7 +3581,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
if (getLangOptions().CPlusPlus0x) {
// FIXME: In C++98, we would like to turn these errors into warnings,
// dependent on a -Wc++0x flag.
- DeclContext *PatternContext
+ DeclContext *PatternContext
= Pattern->getDeclContext()->getEnclosingNamespaceContext();
if (!CurContext->Encloses(PatternContext)) {
Diag(TemplateLoc, diag::err_explicit_instantiation_out_of_scope)
@@ -2813,17 +3590,21 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
}
}
+ TemplateSpecializationKind TSK
+ = ExternLoc.isInvalid()? TSK_ExplicitInstantiationDefinition
+ : TSK_ExplicitInstantiationDeclaration;
+
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,
+ if (Pattern && InstantiateClass(TemplateLoc, Record, Pattern,
getTemplateInstantiationArgs(Record),
- /*ExplicitInstantiation=*/true))
+ TSK))
return true;
- } else // Instantiate all of the members of class.
- InstantiateClassMembers(TemplateLoc, Record,
- getTemplateInstantiationArgs(Record));
+ } else // Instantiate all of the members of the class.
+ InstantiateClassMembers(TemplateLoc, Record,
+ getTemplateInstantiationArgs(Record), TSK);
// FIXME: We don't have any representation for explicit instantiations of
// member classes. Such a representation is not needed for compilation, but it
@@ -2832,10 +3613,221 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
return TagD;
}
+Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
+ SourceLocation ExternLoc,
+ SourceLocation TemplateLoc,
+ Declarator &D) {
+ // Explicit instantiations always require a name.
+ DeclarationName Name = GetNameForDeclarator(D);
+ if (!Name) {
+ if (!D.isInvalidType())
+ Diag(D.getDeclSpec().getSourceRange().getBegin(),
+ diag::err_explicit_instantiation_requires_name)
+ << D.getDeclSpec().getSourceRange()
+ << D.getSourceRange();
+
+ return true;
+ }
+
+ // 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();
+
+ // Determine the type of the declaration.
+ QualType R = GetTypeForDeclarator(D, S, 0);
+ if (R.isNull())
+ return true;
+
+ if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) {
+ // Cannot explicitly instantiate a typedef.
+ Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_of_typedef)
+ << Name;
+ return true;
+ }
+
+ // Determine what kind of explicit instantiation we have.
+ TemplateSpecializationKind TSK
+ = ExternLoc.isInvalid()? TSK_ExplicitInstantiationDefinition
+ : TSK_ExplicitInstantiationDeclaration;
+
+ LookupResult Previous;
+ LookupParsedName(Previous, S, &D.getCXXScopeSpec(),
+ Name, LookupOrdinaryName);
+
+ if (!R->isFunctionType()) {
+ // C++ [temp.explicit]p1:
+ // A [...] static data member of a class template can be explicitly
+ // instantiated from the member definition associated with its class
+ // template.
+ if (Previous.isAmbiguous()) {
+ return DiagnoseAmbiguousLookup(Previous, Name, D.getIdentifierLoc(),
+ D.getSourceRange());
+ }
+
+ VarDecl *Prev = dyn_cast_or_null<VarDecl>(
+ Previous.getAsSingleDecl(Context));
+ if (!Prev || !Prev->isStaticDataMember()) {
+ // We expect to see a data data member here.
+ Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_not_known)
+ << Name;
+ for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end();
+ P != PEnd; ++P)
+ Diag((*P)->getLocation(), diag::note_explicit_instantiation_here);
+ return true;
+ }
+
+ if (!Prev->getInstantiatedFromStaticDataMember()) {
+ // FIXME: Check for explicit specialization?
+ Diag(D.getIdentifierLoc(),
+ diag::err_explicit_instantiation_data_member_not_instantiated)
+ << Prev;
+ Diag(Prev->getLocation(), diag::note_explicit_instantiation_here);
+ // FIXME: Can we provide a note showing where this was declared?
+ return true;
+ }
+
+ // Instantiate static data member.
+ // FIXME: Check for prior specializations and such.
+ Prev->setTemplateSpecializationKind(TSK);
+ if (TSK == TSK_ExplicitInstantiationDefinition)
+ InstantiateStaticDataMemberDefinition(D.getIdentifierLoc(), Prev, false);
+
+ // FIXME: Create an ExplicitInstantiation node?
+ return DeclPtrTy();
+ }
+
+ // If the declarator is a template-id, translate the parser's template
+ // argument list into our AST format.
+ bool HasExplicitTemplateArgs = false;
+ llvm::SmallVector<TemplateArgument, 16> TemplateArgs;
+ if (D.getKind() == Declarator::DK_TemplateId) {
+ TemplateIdAnnotation *TemplateId = D.getTemplateId();
+ ASTTemplateArgsPtr TemplateArgsPtr(*this,
+ TemplateId->getTemplateArgs(),
+ TemplateId->getTemplateArgIsType(),
+ TemplateId->NumArgs);
+ translateTemplateArguments(TemplateArgsPtr,
+ TemplateId->getTemplateArgLocations(),
+ TemplateArgs);
+ HasExplicitTemplateArgs = true;
+ TemplateArgsPtr.release();
+ }
+
+ // C++ [temp.explicit]p1:
+ // A [...] function [...] can be explicitly instantiated from its template.
+ // A member function [...] of a class template can be explicitly
+ // instantiated from the member definition associated with its class
+ // template.
+ llvm::SmallVector<FunctionDecl *, 8> Matches;
+ for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end();
+ P != PEnd; ++P) {
+ NamedDecl *Prev = *P;
+ if (!HasExplicitTemplateArgs) {
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Prev)) {
+ if (Context.hasSameUnqualifiedType(Method->getType(), R)) {
+ Matches.clear();
+ Matches.push_back(Method);
+ break;
+ }
+ }
+ }
+
+ FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(Prev);
+ if (!FunTmpl)
+ continue;
+
+ TemplateDeductionInfo Info(Context);
+ FunctionDecl *Specialization = 0;
+ if (TemplateDeductionResult TDK
+ = DeduceTemplateArguments(FunTmpl, HasExplicitTemplateArgs,
+ TemplateArgs.data(), TemplateArgs.size(),
+ R, Specialization, Info)) {
+ // FIXME: Keep track of almost-matches?
+ (void)TDK;
+ continue;
+ }
+
+ Matches.push_back(Specialization);
+ }
+
+ // Find the most specialized function template specialization.
+ FunctionDecl *Specialization
+ = getMostSpecialized(Matches.data(), Matches.size(), TPOC_Other,
+ D.getIdentifierLoc(),
+ PartialDiagnostic(diag::err_explicit_instantiation_not_known) << Name,
+ PartialDiagnostic(diag::err_explicit_instantiation_ambiguous) << Name,
+ PartialDiagnostic(diag::note_explicit_instantiation_candidate));
+
+ if (!Specialization)
+ return true;
+
+ switch (Specialization->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ Diag(D.getIdentifierLoc(),
+ diag::err_explicit_instantiation_member_function_not_instantiated)
+ << Specialization
+ << (Specialization->getTemplateSpecializationKind() ==
+ TSK_ExplicitSpecialization);
+ Diag(Specialization->getLocation(), diag::note_explicit_instantiation_here);
+ return true;
+
+ case TSK_ExplicitSpecialization:
+ // C++ [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.
+ break;
+
+ case TSK_ExplicitInstantiationDefinition:
+ // FIXME: Check that we aren't trying to perform an explicit instantiation
+ // declaration now.
+ // Fall through
+
+ case TSK_ImplicitInstantiation:
+ case TSK_ExplicitInstantiationDeclaration:
+ // Instantiate the function, if this is an explicit instantiation
+ // definition.
+ if (TSK == TSK_ExplicitInstantiationDefinition)
+ InstantiateFunctionDefinition(D.getIdentifierLoc(), Specialization,
+ false);
+
+ Specialization->setTemplateSpecializationKind(TSK);
+ break;
+ }
+
+ // FIXME: Create some kind of ExplicitInstantiationDecl here.
+ return DeclPtrTy();
+}
+
+Sema::TypeResult
+Sema::ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
+ const CXXScopeSpec &SS, IdentifierInfo *Name,
+ SourceLocation TagLoc, SourceLocation NameLoc) {
+ // This has to hold, because SS is expected to be defined.
+ assert(Name && "Expected a name in a dependent tag");
+
+ NestedNameSpecifier *NNS
+ = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+ if (!NNS)
+ return true;
+
+ QualType T = CheckTypenameType(NNS, *Name, SourceRange(TagLoc, NameLoc));
+ if (T.isNull())
+ return true;
+
+ TagDecl::TagKind TagKind = TagDecl::getTagKindForTypeSpec(TagSpec);
+ QualType ElabType = Context.getElaboratedType(T, TagKind);
+
+ return ElabType.getAsOpaquePtr();
+}
+
Sema::TypeResult
Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
const IdentifierInfo &II, SourceLocation IdLoc) {
- NestedNameSpecifier *NNS
+ NestedNameSpecifier *NNS
= static_cast<NestedNameSpecifier *>(SS.getScopeRep());
if (!NNS)
return true;
@@ -2849,17 +3841,23 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
Sema::TypeResult
Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
SourceLocation TemplateLoc, TypeTy *Ty) {
- QualType T = QualType::getFromOpaquePtr(Ty);
- NestedNameSpecifier *NNS
+ QualType T = GetTypeFromParser(Ty);
+ NestedNameSpecifier *NNS
= static_cast<NestedNameSpecifier *>(SS.getScopeRep());
- const TemplateSpecializationType *TemplateId
- = T->getAsTemplateSpecializationType();
+ const TemplateSpecializationType *TemplateId
+ = T->getAs<TemplateSpecializationType>();
assert(TemplateId && "Expected a template specialization type");
- if (NNS->isDependent())
- return Context.getTypenameType(NNS, TemplateId).getAsOpaquePtr();
+ if (computeDeclContext(SS, false)) {
+ // If we can compute a declaration context, then the "typename"
+ // keyword was superfluous. Just build a QualifiedNameType to keep
+ // track of the nested-name-specifier.
- return Context.getQualifiedNameType(NNS, T).getAsOpaquePtr();
+ // FIXME: Note that the QualifiedNameType had the "typename" keyword!
+ return Context.getQualifiedNameType(NNS, T).getAsOpaquePtr();
+ }
+
+ return Context.getTypenameType(NNS, TemplateId).getAsOpaquePtr();
}
/// \brief Build the type that describes a C++ typename specifier,
@@ -2875,6 +3873,12 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II,
// instantiation, then build a typename type.
if (!CurrentInstantiation)
return Context.getTypenameType(NNS, &II);
+
+ // The nested-name-specifier refers to the current instantiation, so the
+ // "typename" keyword itself is superfluous. In C++03, the program is
+ // actually ill-formed. However, DR 382 (in C++0x CD1) allows such
+ // extraneous "typename" keywords, and we retroactively apply this DR to
+ // C++03 code.
}
DeclContext *Ctx = 0;
@@ -2893,20 +3897,17 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II,
assert(Ctx && "No declaration context?");
DeclarationName Name(&II);
- LookupResult Result = LookupQualifiedName(Ctx, Name, LookupOrdinaryName,
- false);
+ LookupResult Result;
+ LookupQualifiedName(Result, 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;
+ DiagID = diag::err_typename_nested_not_found;
break;
case LookupResult::Found:
- if (TypeDecl *Type = dyn_cast<TypeDecl>(Result.getAsDecl())) {
+ if (TypeDecl *Type = dyn_cast<TypeDecl>(Result.getFoundDecl())) {
// We found a type. Build a QualifiedNameType, since the
// typename-specifier was just sugar. FIXME: Tell
// QualifiedNameType that it has a "typename" prefix.
@@ -2914,7 +3915,7 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II,
}
DiagID = diag::err_typename_nested_not_type;
- Referenced = Result.getAsDecl();
+ Referenced = Result.getFoundDecl();
break;
case LookupResult::FoundOverloaded:
@@ -2922,21 +3923,207 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II,
Referenced = *Result.begin();
break;
- case LookupResult::AmbiguousBaseSubobjectTypes:
- case LookupResult::AmbiguousBaseSubobjects:
- case LookupResult::AmbiguousReference:
+ case LookupResult::Ambiguous:
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;
+ Diag(Range.getEnd(), DiagID) << Range << Name << Ctx;
if (Referenced)
Diag(Referenced->getLocation(), diag::note_typename_refers_here)
<< Name;
return QualType();
}
+
+namespace {
+ // See Sema::RebuildTypeInCurrentInstantiation
+ class VISIBILITY_HIDDEN CurrentInstantiationRebuilder
+ : public TreeTransform<CurrentInstantiationRebuilder> {
+ SourceLocation Loc;
+ DeclarationName Entity;
+
+ public:
+ CurrentInstantiationRebuilder(Sema &SemaRef,
+ SourceLocation Loc,
+ DeclarationName Entity)
+ : TreeTransform<CurrentInstantiationRebuilder>(SemaRef),
+ Loc(Loc), Entity(Entity) { }
+
+ /// \brief Determine whether the given type \p T has already been
+ /// transformed.
+ ///
+ /// For the purposes of type reconstruction, a type has already been
+ /// transformed if it is NULL or if it is not dependent.
+ bool AlreadyTransformed(QualType T) {
+ return T.isNull() || !T->isDependentType();
+ }
+
+ /// \brief Returns the location of the entity whose type is being
+ /// rebuilt.
+ SourceLocation getBaseLocation() { return Loc; }
+
+ /// \brief Returns the name of the entity whose type is being rebuilt.
+ DeclarationName getBaseEntity() { return Entity; }
+
+ /// \brief Transforms an expression by returning the expression itself
+ /// (an identity function).
+ ///
+ /// FIXME: This is completely unsafe; we will need to actually clone the
+ /// expressions.
+ Sema::OwningExprResult TransformExpr(Expr *E) {
+ return getSema().Owned(E);
+ }
+
+ /// \brief Transforms a typename type by determining whether the type now
+ /// refers to a member of the current instantiation, and then
+ /// type-checking and building a QualifiedNameType (when possible).
+ QualType TransformTypenameType(const TypenameType *T);
+ };
+}
+
+QualType
+CurrentInstantiationRebuilder::TransformTypenameType(const TypenameType *T) {
+ NestedNameSpecifier *NNS
+ = TransformNestedNameSpecifier(T->getQualifier(),
+ /*FIXME:*/SourceRange(getBaseLocation()));
+ if (!NNS)
+ return QualType();
+
+ // If the nested-name-specifier did not change, and we cannot compute the
+ // context corresponding to the nested-name-specifier, then this
+ // typename type will not change; exit early.
+ CXXScopeSpec SS;
+ SS.setRange(SourceRange(getBaseLocation()));
+ SS.setScopeRep(NNS);
+ if (NNS == T->getQualifier() && getSema().computeDeclContext(SS) == 0)
+ return QualType(T, 0);
+
+ // Rebuild the typename type, which will probably turn into a
+ // QualifiedNameType.
+ if (const TemplateSpecializationType *TemplateId = T->getTemplateId()) {
+ QualType NewTemplateId
+ = TransformType(QualType(TemplateId, 0));
+ if (NewTemplateId.isNull())
+ return QualType();
+
+ if (NNS == T->getQualifier() &&
+ NewTemplateId == QualType(TemplateId, 0))
+ return QualType(T, 0);
+
+ return getDerived().RebuildTypenameType(NNS, NewTemplateId);
+ }
+
+ return getDerived().RebuildTypenameType(NNS, T->getIdentifier());
+}
+
+/// \brief Rebuilds a type within the context of the current instantiation.
+///
+/// The type \p T is part of the type of an out-of-line member definition of
+/// a class template (or class template partial specialization) that was parsed
+/// and constructed before we entered the scope of the class template (or
+/// partial specialization thereof). This routine will rebuild that type now
+/// that we have entered the declarator's scope, which may produce different
+/// canonical types, e.g.,
+///
+/// \code
+/// template<typename T>
+/// struct X {
+/// typedef T* pointer;
+/// pointer data();
+/// };
+///
+/// template<typename T>
+/// typename X<T>::pointer X<T>::data() { ... }
+/// \endcode
+///
+/// Here, the type "typename X<T>::pointer" will be created as a TypenameType,
+/// since we do not know that we can look into X<T> when we parsed the type.
+/// This function will rebuild the type, performing the lookup of "pointer"
+/// in X<T> and returning a QualifiedNameType whose canonical type is the same
+/// as the canonical type of T*, allowing the return types of the out-of-line
+/// definition and the declaration to match.
+QualType Sema::RebuildTypeInCurrentInstantiation(QualType T, SourceLocation Loc,
+ DeclarationName Name) {
+ if (T.isNull() || !T->isDependentType())
+ return T;
+
+ CurrentInstantiationRebuilder Rebuilder(*this, Loc, Name);
+ return Rebuilder.TransformType(T);
+}
+
+/// \brief Produces a formatted string that describes the binding of
+/// template parameters to template arguments.
+std::string
+Sema::getTemplateArgumentBindingsText(const TemplateParameterList *Params,
+ const TemplateArgumentList &Args) {
+ std::string Result;
+
+ if (!Params || Params->size() == 0)
+ return Result;
+
+ for (unsigned I = 0, N = Params->size(); I != N; ++I) {
+ if (I == 0)
+ Result += "[with ";
+ else
+ Result += ", ";
+
+ if (const IdentifierInfo *Id = Params->getParam(I)->getIdentifier()) {
+ Result += Id->getName();
+ } else {
+ Result += '$';
+ Result += llvm::utostr(I);
+ }
+
+ Result += " = ";
+
+ switch (Args[I].getKind()) {
+ case TemplateArgument::Null:
+ Result += "<no value>";
+ break;
+
+ case TemplateArgument::Type: {
+ std::string TypeStr;
+ Args[I].getAsType().getAsStringInternal(TypeStr,
+ Context.PrintingPolicy);
+ Result += TypeStr;
+ break;
+ }
+
+ case TemplateArgument::Declaration: {
+ bool Unnamed = true;
+ if (NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Args[I].getAsDecl())) {
+ if (ND->getDeclName()) {
+ Unnamed = false;
+ Result += ND->getNameAsString();
+ }
+ }
+
+ if (Unnamed) {
+ Result += "<anonymous>";
+ }
+ break;
+ }
+
+ case TemplateArgument::Integral: {
+ Result += Args[I].getAsIntegral()->toString(10);
+ break;
+ }
+
+ case TemplateArgument::Expression: {
+ assert(false && "No expressions in deduced template arguments!");
+ Result += "<expression>";
+ break;
+ }
+
+ case TemplateArgument::Pack:
+ // FIXME: Format template argument packs
+ Result += "<template argument pack>";
+ break;
+ }
+ }
+
+ Result += ']';
+ return Result;
+}
diff --git a/lib/Sema/SemaTemplate.h b/lib/Sema/SemaTemplate.h
new file mode 100644
index 0000000..2bfb25a
--- /dev/null
+++ b/lib/Sema/SemaTemplate.h
@@ -0,0 +1,104 @@
+//===------- SemaTemplate.h - 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 provides types used in the semantic analysis of C++ templates.
+//
+//===----------------------------------------------------------------------===/
+#ifndef LLVM_CLANG_SEMA_TEMPLATE_H
+#define LLVM_CLANG_SEMA_TEMPLATE_H
+
+#include "clang/AST/DeclTemplate.h"
+#include "llvm/ADT/SmallVector.h"
+#include <cassert>
+
+namespace clang {
+ /// \brief Data structure that captures multiple levels of template argument
+ /// lists for use in template instantiation.
+ ///
+ /// Multiple levels of template arguments occur when instantiating the
+ /// definitions of member templates. For example:
+ ///
+ /// \code
+ /// template<typename T>
+ /// struct X {
+ /// template<T Value>
+ /// struct Y {
+ /// void f();
+ /// };
+ /// };
+ /// \endcode
+ ///
+ /// When instantiating X<int>::Y<17>::f, the multi-level template argument
+ /// list will contain a template argument list (int) at depth 0 and a
+ /// template argument list (17) at depth 1.
+ struct MultiLevelTemplateArgumentList {
+ /// \brief The template argument lists, stored from the innermost template
+ /// argument list (first) to the outermost template argument list (last).
+ llvm::SmallVector<const TemplateArgumentList *, 4> TemplateArgumentLists;
+
+ public:
+ /// \brief Construct an empty set of template argument lists.
+ MultiLevelTemplateArgumentList() { }
+
+ /// \brief Construct a single-level template argument list.
+ explicit
+ MultiLevelTemplateArgumentList(const TemplateArgumentList &TemplateArgs) {
+ TemplateArgumentLists.push_back(&TemplateArgs);
+ }
+
+ /// \brief Determine the number of levels in this template argument
+ /// list.
+ unsigned getNumLevels() const { return TemplateArgumentLists.size(); }
+
+ /// \brief Retrieve the template argument at a given depth and index.
+ const TemplateArgument &operator()(unsigned Depth, unsigned Index) const {
+ assert(Depth < TemplateArgumentLists.size());
+ assert(Index < TemplateArgumentLists[getNumLevels() - Depth - 1]->size());
+ return TemplateArgumentLists[getNumLevels() - Depth - 1]->get(Index);
+ }
+
+ /// \brief Determine whether there is a non-NULL template argument at the
+ /// given depth and index.
+ ///
+ /// There must exist a template argument list at the given depth.
+ bool hasTemplateArgument(unsigned Depth, unsigned Index) const {
+ assert(Depth < TemplateArgumentLists.size());
+
+ if (Index >= TemplateArgumentLists[getNumLevels() - Depth - 1]->size())
+ return false;
+
+ return !(*this)(Depth, Index).isNull();
+ }
+
+ /// \brief Add a new outermost level to the multi-level template argument
+ /// list.
+ void addOuterTemplateArguments(const TemplateArgumentList *TemplateArgs) {
+ TemplateArgumentLists.push_back(TemplateArgs);
+ }
+
+ /// \brief Retrieve the innermost template argument list.
+ const TemplateArgumentList &getInnermost() const {
+ return *TemplateArgumentLists.front();
+ }
+ };
+
+ /// \brief The context in which partial ordering of function templates occurs.
+ enum TemplatePartialOrderingContext {
+ /// \brief Partial ordering of function templates for a function call.
+ TPOC_Call,
+ /// \brief Partial ordering of function templates for a call to a
+ /// conversion function.
+ TPOC_Conversion,
+ /// \brief Partial ordering of function templates in other contexts, e.g.,
+ /// taking the address of a function template or matching a function
+ /// template specialization to a function template.
+ TPOC_Other
+ };
+}
+
+#endif // LLVM_CLANG_SEMA_TEMPLATE_H
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 5a0578f..b981389 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -18,6 +18,7 @@
#include "clang/AST/ExprCXX.h"
#include "clang/Parse/DeclSpec.h"
#include "llvm/Support/Compiler.h"
+#include <algorithm>
namespace clang {
/// \brief Various flags that control template argument deduction.
@@ -38,14 +39,18 @@ namespace clang {
/// \brief Within template argument deduction from a function call,
/// we are matching in a case where we can perform template argument
/// deduction from a template-id of a derived class of the argument type.
- TDF_DerivedClass = 0x04
+ TDF_DerivedClass = 0x04,
+ /// \brief Allow non-dependent types to differ, e.g., when performing
+ /// template argument deduction from a function call where conversions
+ /// may apply.
+ TDF_SkipNonDependent = 0x08
};
}
using namespace clang;
static Sema::TemplateDeductionResult
-DeduceTemplateArguments(ASTContext &Context,
+DeduceTemplateArguments(ASTContext &Context,
TemplateParameterList *TemplateParams,
const TemplateArgument &Param,
const TemplateArgument &Arg,
@@ -58,27 +63,27 @@ DeduceTemplateArguments(ASTContext &Context,
static NonTypeTemplateParmDecl *getDeducedParameterFromExpr(Expr *E) {
if (ImplicitCastExpr *IC = dyn_cast<ImplicitCastExpr>(E))
E = IC->getSubExpr();
-
+
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
return dyn_cast<NonTypeTemplateParmDecl>(DRE->getDecl());
-
+
return 0;
}
-/// \brief Deduce the value of the given non-type template parameter
+/// \brief Deduce the value of the given non-type template parameter
/// from the given constant.
static Sema::TemplateDeductionResult
-DeduceNonTypeTemplateArgument(ASTContext &Context,
- NonTypeTemplateParmDecl *NTTP,
+DeduceNonTypeTemplateArgument(ASTContext &Context,
+ NonTypeTemplateParmDecl *NTTP,
llvm::APSInt Value,
Sema::TemplateDeductionInfo &Info,
llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
- assert(NTTP->getDepth() == 0 &&
+ assert(NTTP->getDepth() == 0 &&
"Cannot deduce non-type template argument with depth > 0");
-
+
if (Deduced[NTTP->getIndex()].isNull()) {
QualType T = NTTP->getType();
-
+
// FIXME: Make sure we didn't overflow our data type!
unsigned AllowedBits = Context.getTypeSize(T);
if (Value.getBitWidth() != AllowedBits)
@@ -88,10 +93,10 @@ DeduceNonTypeTemplateArgument(ASTContext &Context,
Deduced[NTTP->getIndex()] = TemplateArgument(SourceLocation(), Value, T);
return Sema::TDK_Success;
}
-
+
assert(Deduced[NTTP->getIndex()].getKind() == TemplateArgument::Integral);
-
- // If the template argument was previously deduced to a negative value,
+
+ // If the template argument was previously deduced to a negative value,
// then our deduction fails.
const llvm::APSInt *PrevValuePtr = Deduced[NTTP->getIndex()].getAsIntegral();
if (PrevValuePtr->isNegative()) {
@@ -117,36 +122,47 @@ DeduceNonTypeTemplateArgument(ASTContext &Context,
return Sema::TDK_Success;
}
-/// \brief Deduce the value of the given non-type template parameter
+/// \brief Deduce the value of the given non-type template parameter
/// from the given type- or value-dependent expression.
///
/// \returns true if deduction succeeded, false otherwise.
static Sema::TemplateDeductionResult
-DeduceNonTypeTemplateArgument(ASTContext &Context,
+DeduceNonTypeTemplateArgument(ASTContext &Context,
NonTypeTemplateParmDecl *NTTP,
Expr *Value,
Sema::TemplateDeductionInfo &Info,
llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
- assert(NTTP->getDepth() == 0 &&
+ assert(NTTP->getDepth() == 0 &&
"Cannot deduce non-type template argument with depth > 0");
assert((Value->isTypeDependent() || Value->isValueDependent()) &&
"Expression template argument must be type- or value-dependent.");
-
+
if (Deduced[NTTP->getIndex()].isNull()) {
// FIXME: Clone the Value?
Deduced[NTTP->getIndex()] = TemplateArgument(Value);
return Sema::TDK_Success;
}
-
+
if (Deduced[NTTP->getIndex()].getKind() == TemplateArgument::Integral) {
- // Okay, we deduced a constant in one case and a dependent expression
- // in another case. FIXME: Later, we will check that instantiating the
+ // Okay, we deduced a constant in one case and a dependent expression
+ // in another case. FIXME: Later, we will check that instantiating the
// dependent expression gives us the constant value.
return Sema::TDK_Success;
}
-
- // FIXME: Compare the expressions for equality!
+
+ if (Deduced[NTTP->getIndex()].getKind() == TemplateArgument::Expression) {
+ // Compare the expressions for equality
+ llvm::FoldingSetNodeID ID1, ID2;
+ Deduced[NTTP->getIndex()].getAsExpr()->Profile(ID1, Context, true);
+ Value->Profile(ID2, Context, true);
+ if (ID1 == ID2)
+ return Sema::TDK_Success;
+
+ // FIXME: Fill in argument mismatch information
+ return Sema::TDK_NonDeducedMismatch;
+ }
+
return Sema::TDK_Success;
}
@@ -164,14 +180,14 @@ DeduceTemplateArguments(ASTContext &Context,
TemplateDecl *ParamDecl = Param.getAsTemplateDecl();
TemplateDecl *ArgDecl = Arg.getAsTemplateDecl();
-
+
if (!ParamDecl || !ArgDecl) {
// FIXME: fill in Info.Param/Info.FirstArg
return Sema::TDK_Inconsistent;
}
- ParamDecl = cast<TemplateDecl>(Context.getCanonicalDecl(ParamDecl));
- ArgDecl = cast<TemplateDecl>(Context.getCanonicalDecl(ArgDecl));
+ ParamDecl = cast<TemplateDecl>(ParamDecl->getCanonicalDecl());
+ ArgDecl = cast<TemplateDecl>(ArgDecl->getCanonicalDecl());
if (ParamDecl != ArgDecl) {
// FIXME: fill in Info.Param/Info.FirstArg
return Sema::TDK_Inconsistent;
@@ -180,6 +196,161 @@ DeduceTemplateArguments(ASTContext &Context,
return Sema::TDK_Success;
}
+/// \brief Deduce the template arguments by comparing the template parameter
+/// type (which is a template-id) with the template argument type.
+///
+/// \param Context the AST context in which this deduction occurs.
+///
+/// \param TemplateParams the template parameters that we are deducing
+///
+/// \param Param the parameter type
+///
+/// \param Arg the argument type
+///
+/// \param Info information about the template argument deduction itself
+///
+/// \param Deduced the deduced template arguments
+///
+/// \returns the result of template argument deduction so far. Note that a
+/// "success" result means that template argument deduction has not yet failed,
+/// but it may still fail, later, for other reasons.
+static Sema::TemplateDeductionResult
+DeduceTemplateArguments(ASTContext &Context,
+ TemplateParameterList *TemplateParams,
+ const TemplateSpecializationType *Param,
+ QualType Arg,
+ Sema::TemplateDeductionInfo &Info,
+ llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+ assert(Arg->isCanonical() && "Argument type must be canonical");
+
+ // Check whether the template argument is a dependent template-id.
+ // FIXME: This is untested code; it can be tested when we implement
+ // partial ordering of class template partial specializations.
+ if (const TemplateSpecializationType *SpecArg
+ = dyn_cast<TemplateSpecializationType>(Arg)) {
+ // Perform template argument deduction for the template name.
+ if (Sema::TemplateDeductionResult Result
+ = DeduceTemplateArguments(Context,
+ Param->getTemplateName(),
+ SpecArg->getTemplateName(),
+ Info, Deduced))
+ return Result;
+
+ unsigned NumArgs = Param->getNumArgs();
+
+ // FIXME: When one of the template-names refers to a
+ // declaration with default template arguments, do we need to
+ // fill in those default template arguments here? Most likely,
+ // the answer is "yes", but I don't see any references. This
+ // issue may be resolved elsewhere, because we may want to
+ // instantiate default template arguments when we actually write
+ // the template-id.
+ if (SpecArg->getNumArgs() != NumArgs)
+ return Sema::TDK_NonDeducedMismatch;
+
+ // Perform template argument deduction on each template
+ // argument.
+ for (unsigned I = 0; I != NumArgs; ++I)
+ if (Sema::TemplateDeductionResult Result
+ = DeduceTemplateArguments(Context, TemplateParams,
+ Param->getArg(I),
+ SpecArg->getArg(I),
+ Info, Deduced))
+ return Result;
+
+ return Sema::TDK_Success;
+ }
+
+ // If the argument type is a class template specialization, we
+ // perform template argument deduction using its template
+ // arguments.
+ const RecordType *RecordArg = dyn_cast<RecordType>(Arg);
+ if (!RecordArg)
+ return Sema::TDK_NonDeducedMismatch;
+
+ ClassTemplateSpecializationDecl *SpecArg
+ = dyn_cast<ClassTemplateSpecializationDecl>(RecordArg->getDecl());
+ if (!SpecArg)
+ return Sema::TDK_NonDeducedMismatch;
+
+ // Perform template argument deduction for the template name.
+ if (Sema::TemplateDeductionResult Result
+ = DeduceTemplateArguments(Context,
+ Param->getTemplateName(),
+ TemplateName(SpecArg->getSpecializedTemplate()),
+ Info, Deduced))
+ return Result;
+
+ // FIXME: Can the # of arguments in the parameter and the argument
+ // differ due to default arguments?
+ unsigned NumArgs = Param->getNumArgs();
+ const TemplateArgumentList &ArgArgs = SpecArg->getTemplateArgs();
+ if (NumArgs != ArgArgs.size())
+ return Sema::TDK_NonDeducedMismatch;
+
+ for (unsigned I = 0; I != NumArgs; ++I)
+ if (Sema::TemplateDeductionResult Result
+ = DeduceTemplateArguments(Context, TemplateParams,
+ Param->getArg(I),
+ ArgArgs.get(I),
+ Info, Deduced))
+ return Result;
+
+ return Sema::TDK_Success;
+}
+
+/// \brief Returns a completely-unqualified array type, capturing the
+/// qualifiers in Quals.
+///
+/// \param Context the AST context in which the array type was built.
+///
+/// \param T a canonical type that may be an array type.
+///
+/// \param Quals will receive the full set of qualifiers that were
+/// applied to the element type of the array.
+///
+/// \returns if \p T is an array type, the completely unqualified array type
+/// that corresponds to T. Otherwise, returns T.
+static QualType getUnqualifiedArrayType(ASTContext &Context, QualType T,
+ Qualifiers &Quals) {
+ assert(T->isCanonical() && "Only operates on canonical types");
+ if (!isa<ArrayType>(T)) {
+ Quals = T.getQualifiers();
+ return T.getUnqualifiedType();
+ }
+
+ assert(!T.hasQualifiers() && "canonical array type has qualifiers!");
+
+ if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(T)) {
+ QualType Elt = getUnqualifiedArrayType(Context, CAT->getElementType(),
+ Quals);
+ if (Elt == CAT->getElementType())
+ return T;
+
+ return Context.getConstantArrayType(Elt, CAT->getSize(),
+ CAT->getSizeModifier(), 0);
+ }
+
+ if (const IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(T)) {
+ QualType Elt = getUnqualifiedArrayType(Context, IAT->getElementType(),
+ Quals);
+ if (Elt == IAT->getElementType())
+ return T;
+
+ return Context.getIncompleteArrayType(Elt, IAT->getSizeModifier(), 0);
+ }
+
+ const DependentSizedArrayType *DSAT = cast<DependentSizedArrayType>(T);
+ QualType Elt = getUnqualifiedArrayType(Context, DSAT->getElementType(),
+ Quals);
+ if (Elt == DSAT->getElementType())
+ return T;
+
+ return Context.getDependentSizedArrayType(Elt, DSAT->getSizeExpr()->Retain(),
+ DSAT->getSizeModifier(), 0,
+ SourceRange());
+}
+
/// \brief Deduce the template arguments by comparing the parameter type and
/// the argument type (C++ [temp.deduct.type]).
///
@@ -196,13 +367,13 @@ DeduceTemplateArguments(ASTContext &Context,
/// \param Deduced the deduced template arguments
///
/// \param TDF bitwise OR of the TemplateDeductionFlags bits that describe
-/// how template argument deduction is performed.
+/// how template argument deduction is performed.
///
/// \returns the result of template argument deduction so far. Note that a
/// "success" result means that template argument deduction has not yet failed,
/// but it may still fail, later, for other reasons.
static Sema::TemplateDeductionResult
-DeduceTemplateArguments(ASTContext &Context,
+DeduceTemplateArguments(ASTContext &Context,
TemplateParameterList *TemplateParams,
QualType ParamIn, QualType ArgIn,
Sema::TemplateDeductionInfo &Info,
@@ -215,28 +386,47 @@ DeduceTemplateArguments(ASTContext &Context,
// C++0x [temp.deduct.call]p4 bullet 1:
// - If the original P is a reference type, the deduced A (i.e., the type
- // referred to by the reference) can be more cv-qualified than the
+ // referred to by the reference) can be more cv-qualified than the
// transformed A.
if (TDF & TDF_ParamWithReferenceType) {
- unsigned ExtraQualsOnParam
- = Param.getCVRQualifiers() & ~Arg.getCVRQualifiers();
- Param.setCVRQualifiers(Param.getCVRQualifiers() & ~ExtraQualsOnParam);
+ Qualifiers Quals = Param.getQualifiers();
+ Quals.setCVRQualifiers(Quals.getCVRQualifiers() & Arg.getCVRQualifiers());
+ Param = Context.getQualifiedType(Param.getUnqualifiedType(), Quals);
}
-
+
// If the parameter type is not dependent, there is nothing to deduce.
- if (!Param->isDependentType())
+ if (!Param->isDependentType()) {
+ if (!(TDF & TDF_SkipNonDependent) && Param != Arg) {
+
+ return Sema::TDK_NonDeducedMismatch;
+ }
+
return Sema::TDK_Success;
+ }
// C++ [temp.deduct.type]p9:
- // A template type argument T, a template template argument TT or a
- // template non-type argument i can be deduced if P and A have one of
+ // A template type argument T, a template template argument TT or a
+ // template non-type argument i can be deduced if P and A have one of
// the following forms:
//
// T
// cv-list T
- if (const TemplateTypeParmType *TemplateTypeParm
- = Param->getAsTemplateTypeParmType()) {
+ if (const TemplateTypeParmType *TemplateTypeParm
+ = Param->getAs<TemplateTypeParmType>()) {
unsigned Index = TemplateTypeParm->getIndex();
+ bool RecanonicalizeArg = false;
+
+ // If the argument type is an array type, move the qualifiers up to the
+ // top level, so they can be matched with the qualifiers on the parameter.
+ // FIXME: address spaces, ObjC GC qualifiers
+ if (isa<ArrayType>(Arg)) {
+ Qualifiers Quals;
+ Arg = getUnqualifiedArrayType(Context, Arg, Quals);
+ if (Quals) {
+ Arg = Context.getQualifiedType(Arg, Quals);
+ RecanonicalizeArg = true;
+ }
+ }
// The argument type can not be less qualified than the parameter
// type.
@@ -248,21 +438,23 @@ DeduceTemplateArguments(ASTContext &Context,
}
assert(TemplateTypeParm->getDepth() == 0 && "Can't deduce with depth > 0");
-
- unsigned Quals = Arg.getCVRQualifiers() & ~Param.getCVRQualifiers();
- QualType DeducedType = Arg.getQualifiedType(Quals);
+
+ QualType DeducedType = Arg;
+ DeducedType.removeCVRQualifiers(Param.getCVRQualifiers());
+ if (RecanonicalizeArg)
+ DeducedType = Context.getCanonicalType(DeducedType);
if (Deduced[Index].isNull())
Deduced[Index] = TemplateArgument(SourceLocation(), DeducedType);
else {
- // C++ [temp.deduct.type]p2:
+ // C++ [temp.deduct.type]p2:
// [...] If type deduction cannot be done for any P/A pair, or if for
- // any pair the deduction leads to more than one possible set of
- // deduced values, or if different pairs yield different deduced
- // values, or if any template argument remains neither deduced nor
+ // any pair the deduction leads to more than one possible set of
+ // deduced values, or if different pairs yield different deduced
+ // values, or if any template argument remains neither deduced nor
// explicitly specified, template argument deduction fails.
if (Deduced[Index].getAsType() != DeducedType) {
- Info.Param
+ Info.Param
= cast<TemplateTypeParmDecl>(TemplateParams->getParam(Index));
Info.FirstArg = Deduced[Index];
Info.SecondArg = TemplateArgument(SourceLocation(), Arg);
@@ -283,7 +475,7 @@ DeduceTemplateArguments(ASTContext &Context,
return Sema::TDK_NonDeducedMismatch;
} else {
if (Param.getCVRQualifiers() != Arg.getCVRQualifiers())
- return Sema::TDK_NonDeducedMismatch;
+ return Sema::TDK_NonDeducedMismatch;
}
}
@@ -291,26 +483,26 @@ DeduceTemplateArguments(ASTContext &Context,
// No deduction possible for these types
case Type::Builtin:
return Sema::TDK_NonDeducedMismatch;
-
+
// T *
case Type::Pointer: {
- const PointerType *PointerArg = Arg->getAsPointerType();
+ const PointerType *PointerArg = Arg->getAs<PointerType>();
if (!PointerArg)
return Sema::TDK_NonDeducedMismatch;
-
+
unsigned SubTDF = TDF & (TDF_IgnoreQualifiers | TDF_DerivedClass);
return DeduceTemplateArguments(Context, TemplateParams,
cast<PointerType>(Param)->getPointeeType(),
PointerArg->getPointeeType(),
Info, Deduced, SubTDF);
}
-
+
// T &
case Type::LValueReference: {
- const LValueReferenceType *ReferenceArg = Arg->getAsLValueReferenceType();
+ const LValueReferenceType *ReferenceArg = Arg->getAs<LValueReferenceType>();
if (!ReferenceArg)
return Sema::TDK_NonDeducedMismatch;
-
+
return DeduceTemplateArguments(Context, TemplateParams,
cast<LValueReferenceType>(Param)->getPointeeType(),
ReferenceArg->getPointeeType(),
@@ -319,23 +511,23 @@ DeduceTemplateArguments(ASTContext &Context,
// T && [C++0x]
case Type::RValueReference: {
- const RValueReferenceType *ReferenceArg = Arg->getAsRValueReferenceType();
+ const RValueReferenceType *ReferenceArg = Arg->getAs<RValueReferenceType>();
if (!ReferenceArg)
return Sema::TDK_NonDeducedMismatch;
-
+
return DeduceTemplateArguments(Context, TemplateParams,
cast<RValueReferenceType>(Param)->getPointeeType(),
ReferenceArg->getPointeeType(),
Info, Deduced, 0);
}
-
+
// T [] (implied, but not stated explicitly)
case Type::IncompleteArray: {
- const IncompleteArrayType *IncompleteArrayArg =
+ const IncompleteArrayType *IncompleteArrayArg =
Context.getAsIncompleteArrayType(Arg);
if (!IncompleteArrayArg)
return Sema::TDK_NonDeducedMismatch;
-
+
return DeduceTemplateArguments(Context, TemplateParams,
Context.getAsIncompleteArrayType(Param)->getElementType(),
IncompleteArrayArg->getElementType(),
@@ -344,16 +536,16 @@ DeduceTemplateArguments(ASTContext &Context,
// T [integer-constant]
case Type::ConstantArray: {
- const ConstantArrayType *ConstantArrayArg =
+ const ConstantArrayType *ConstantArrayArg =
Context.getAsConstantArrayType(Arg);
if (!ConstantArrayArg)
return Sema::TDK_NonDeducedMismatch;
-
- const ConstantArrayType *ConstantArrayParm =
+
+ const ConstantArrayType *ConstantArrayParm =
Context.getAsConstantArrayType(Param);
if (ConstantArrayArg->getSize() != ConstantArrayParm->getSize())
return Sema::TDK_NonDeducedMismatch;
-
+
return DeduceTemplateArguments(Context, TemplateParams,
ConstantArrayParm->getElementType(),
ConstantArrayArg->getElementType(),
@@ -365,7 +557,7 @@ DeduceTemplateArguments(ASTContext &Context,
const ArrayType *ArrayArg = dyn_cast<ArrayType>(Arg);
if (!ArrayArg)
return Sema::TDK_NonDeducedMismatch;
-
+
// Check the element type of the arrays
const DependentSizedArrayType *DependentArrayParm
= cast<DependentSizedArrayType>(Param);
@@ -375,18 +567,18 @@ DeduceTemplateArguments(ASTContext &Context,
ArrayArg->getElementType(),
Info, Deduced, 0))
return Result;
-
+
// Determine the array bound is something we can deduce.
- NonTypeTemplateParmDecl *NTTP
+ NonTypeTemplateParmDecl *NTTP
= getDeducedParameterFromExpr(DependentArrayParm->getSizeExpr());
if (!NTTP)
return Sema::TDK_Success;
-
- // We can perform template argument deduction for the given non-type
+
+ // We can perform template argument deduction for the given non-type
// template parameter.
- assert(NTTP->getDepth() == 0 &&
+ assert(NTTP->getDepth() == 0 &&
"Cannot deduce non-type template argument at depth > 0");
- if (const ConstantArrayType *ConstantArrayArg
+ if (const ConstantArrayType *ConstantArrayArg
= dyn_cast<ConstantArrayType>(ArrayArg)) {
llvm::APSInt Size(ConstantArrayArg->getSize());
return DeduceNonTypeTemplateArgument(Context, NTTP, Size,
@@ -397,30 +589,30 @@ DeduceTemplateArguments(ASTContext &Context,
return DeduceNonTypeTemplateArgument(Context, NTTP,
DependentArrayArg->getSizeExpr(),
Info, Deduced);
-
+
// Incomplete type does not match a dependently-sized array type
return Sema::TDK_NonDeducedMismatch;
}
-
- // type(*)(T)
- // T(*)()
- // T(*)(T)
+
+ // type(*)(T)
+ // T(*)()
+ // T(*)(T)
case Type::FunctionProto: {
- const FunctionProtoType *FunctionProtoArg =
+ const FunctionProtoType *FunctionProtoArg =
dyn_cast<FunctionProtoType>(Arg);
if (!FunctionProtoArg)
return Sema::TDK_NonDeducedMismatch;
-
- const FunctionProtoType *FunctionProtoParam =
+
+ const FunctionProtoType *FunctionProtoParam =
cast<FunctionProtoType>(Param);
- if (FunctionProtoParam->getTypeQuals() !=
+ if (FunctionProtoParam->getTypeQuals() !=
FunctionProtoArg->getTypeQuals())
return Sema::TDK_NonDeducedMismatch;
-
+
if (FunctionProtoParam->getNumArgs() != FunctionProtoArg->getNumArgs())
return Sema::TDK_NonDeducedMismatch;
-
+
if (FunctionProtoParam->isVariadic() != FunctionProtoArg->isVariadic())
return Sema::TDK_NonDeducedMismatch;
@@ -431,7 +623,7 @@ DeduceTemplateArguments(ASTContext &Context,
FunctionProtoArg->getResultType(),
Info, Deduced, 0))
return Result;
-
+
for (unsigned I = 0, N = FunctionProtoParam->getNumArgs(); I != N; ++I) {
// Check argument types.
if (Sema::TemplateDeductionResult Result
@@ -441,10 +633,10 @@ DeduceTemplateArguments(ASTContext &Context,
Info, Deduced, 0))
return Result;
}
-
+
return Sema::TDK_Success;
}
-
+
// template-name<T> (where template-name refers to a class template)
// template-name<i>
// TT<T> (TODO)
@@ -454,83 +646,69 @@ DeduceTemplateArguments(ASTContext &Context,
const TemplateSpecializationType *SpecParam
= cast<TemplateSpecializationType>(Param);
- // Check whether the template argument is a dependent template-id.
- // FIXME: This is untested code; it can be tested when we implement
- // partial ordering of class template partial specializations.
- if (const TemplateSpecializationType *SpecArg
- = dyn_cast<TemplateSpecializationType>(Arg)) {
- // Perform template argument deduction for the template name.
- if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(Context,
- SpecParam->getTemplateName(),
- SpecArg->getTemplateName(),
- Info, Deduced))
- return Result;
-
- unsigned NumArgs = SpecParam->getNumArgs();
-
- // FIXME: When one of the template-names refers to a
- // declaration with default template arguments, do we need to
- // fill in those default template arguments here? Most likely,
- // the answer is "yes", but I don't see any references. This
- // issue may be resolved elsewhere, because we may want to
- // instantiate default template arguments when
- if (SpecArg->getNumArgs() != NumArgs)
- return Sema::TDK_NonDeducedMismatch;
-
- // Perform template argument deduction on each template
- // argument.
- for (unsigned I = 0; I != NumArgs; ++I)
- if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(Context, TemplateParams,
- SpecParam->getArg(I),
- SpecArg->getArg(I),
- Info, Deduced))
- return Result;
-
- return Sema::TDK_Success;
- }
-
- // If the argument type is a class template specialization, we
- // perform template argument deduction using its template
- // arguments.
- const RecordType *RecordArg = dyn_cast<RecordType>(Arg);
- if (!RecordArg)
- return Sema::TDK_NonDeducedMismatch;
-
- // FIXME: Check TDF_DerivedClass here. When this flag is set, we need
- // to troll through the base classes of the argument and try matching
- // all of them. Failure to match does not mean that there is a problem,
- // of course.
-
- ClassTemplateSpecializationDecl *SpecArg
- = dyn_cast<ClassTemplateSpecializationDecl>(RecordArg->getDecl());
- if (!SpecArg)
- return Sema::TDK_NonDeducedMismatch;
-
- // Perform template argument deduction for the template name.
- if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(Context,
- SpecParam->getTemplateName(),
- TemplateName(SpecArg->getSpecializedTemplate()),
- Info, Deduced))
- return Result;
+ // Try to deduce template arguments from the template-id.
+ Sema::TemplateDeductionResult Result
+ = DeduceTemplateArguments(Context, TemplateParams, SpecParam, Arg,
+ Info, Deduced);
+
+ if (Result && (TDF & TDF_DerivedClass)) {
+ // C++ [temp.deduct.call]p3b3:
+ // If P is a class, and P has the form template-id, then A can be a
+ // derived class of the deduced A. Likewise, if P is a pointer to a
+ // class of the form template-id, A can be a pointer to a derived
+ // class pointed to by the deduced A.
+ //
+ // More importantly:
+ // These alternatives are considered only if type deduction would
+ // otherwise fail.
+ if (const RecordType *RecordT = dyn_cast<RecordType>(Arg)) {
+ // Use data recursion to crawl through the list of base classes.
+ // Visited contains the set of nodes we have already visited, while
+ // ToVisit is our stack of records that we still need to visit.
+ llvm::SmallPtrSet<const RecordType *, 8> Visited;
+ llvm::SmallVector<const RecordType *, 8> ToVisit;
+ ToVisit.push_back(RecordT);
+ bool Successful = false;
+ while (!ToVisit.empty()) {
+ // Retrieve the next class in the inheritance hierarchy.
+ const RecordType *NextT = ToVisit.back();
+ ToVisit.pop_back();
+
+ // If we have already seen this type, skip it.
+ if (!Visited.insert(NextT))
+ continue;
+
+ // If this is a base class, try to perform template argument
+ // deduction from it.
+ if (NextT != RecordT) {
+ Sema::TemplateDeductionResult BaseResult
+ = DeduceTemplateArguments(Context, TemplateParams, SpecParam,
+ QualType(NextT, 0), Info, Deduced);
+
+ // If template argument deduction for this base was successful,
+ // note that we had some success.
+ if (BaseResult == Sema::TDK_Success)
+ Successful = true;
+ }
+
+ // Visit base classes
+ CXXRecordDecl *Next = cast<CXXRecordDecl>(NextT->getDecl());
+ for (CXXRecordDecl::base_class_iterator Base = Next->bases_begin(),
+ BaseEnd = Next->bases_end();
+ Base != BaseEnd; ++Base) {
+ assert(Base->getType()->isRecordType() &&
+ "Base class that isn't a record?");
+ ToVisit.push_back(Base->getType()->getAs<RecordType>());
+ }
+ }
+
+ if (Successful)
+ return Sema::TDK_Success;
+ }
- // FIXME: Can the # of arguments in the parameter and the argument differ?
- unsigned NumArgs = SpecParam->getNumArgs();
- const TemplateArgumentList &ArgArgs = SpecArg->getTemplateArgs();
- if (NumArgs != ArgArgs.size())
- return Sema::TDK_NonDeducedMismatch;
+ }
- for (unsigned I = 0; I != NumArgs; ++I)
- if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(Context, TemplateParams,
- SpecParam->getArg(I),
- ArgArgs.get(I),
- Info, Deduced))
- return Result;
-
- return Sema::TDK_Success;
+ return Result;
}
// T type::*
@@ -564,16 +742,16 @@ DeduceTemplateArguments(ASTContext &Context,
// (clang extension)
//
- // type(^)(T)
- // T(^)()
- // T(^)(T)
+ // type(^)(T)
+ // T(^)()
+ // T(^)(T)
case Type::BlockPointer: {
const BlockPointerType *BlockPtrParam = cast<BlockPointerType>(Param);
const BlockPointerType *BlockPtrArg = dyn_cast<BlockPointerType>(Arg);
-
+
if (!BlockPtrArg)
return Sema::TDK_NonDeducedMismatch;
-
+
return DeduceTemplateArguments(Context, TemplateParams,
BlockPtrParam->getPointeeType(),
BlockPtrArg->getPointeeType(), Info,
@@ -595,7 +773,7 @@ DeduceTemplateArguments(ASTContext &Context,
}
static Sema::TemplateDeductionResult
-DeduceTemplateArguments(ASTContext &Context,
+DeduceTemplateArguments(ASTContext &Context,
TemplateParameterList *TemplateParams,
const TemplateArgument &Param,
const TemplateArgument &Arg,
@@ -605,8 +783,8 @@ DeduceTemplateArguments(ASTContext &Context,
case TemplateArgument::Null:
assert(false && "Null template argument in parameter list");
break;
-
- case TemplateArgument::Type:
+
+ case TemplateArgument::Type:
assert(Arg.getKind() == TemplateArgument::Type && "Type/value mismatch");
return DeduceTemplateArguments(Context, TemplateParams, Param.getAsType(),
Arg.getAsType(), Info, Deduced, 0);
@@ -617,7 +795,7 @@ DeduceTemplateArguments(ASTContext &Context,
Info.FirstArg = Param;
Info.SecondArg = Arg;
return Sema::TDK_NonDeducedMismatch;
-
+
case TemplateArgument::Integral:
if (Arg.getKind() == TemplateArgument::Integral) {
// FIXME: Zero extension + sign checking here?
@@ -639,25 +817,25 @@ DeduceTemplateArguments(ASTContext &Context,
Info.FirstArg = Param;
Info.SecondArg = Arg;
return Sema::TDK_NonDeducedMismatch;
-
+
case TemplateArgument::Expression: {
- if (NonTypeTemplateParmDecl *NTTP
+ if (NonTypeTemplateParmDecl *NTTP
= getDeducedParameterFromExpr(Param.getAsExpr())) {
if (Arg.getKind() == TemplateArgument::Integral)
// FIXME: Sign problems here
- return DeduceNonTypeTemplateArgument(Context, NTTP,
- *Arg.getAsIntegral(),
+ return DeduceNonTypeTemplateArgument(Context, NTTP,
+ *Arg.getAsIntegral(),
Info, Deduced);
if (Arg.getKind() == TemplateArgument::Expression)
return DeduceNonTypeTemplateArgument(Context, NTTP, Arg.getAsExpr(),
Info, Deduced);
-
+
assert(false && "Type/value mismatch");
Info.FirstArg = Param;
Info.SecondArg = Arg;
return Sema::TDK_NonDeducedMismatch;
}
-
+
// Can't deduce anything, but that's okay.
return Sema::TDK_Success;
}
@@ -665,11 +843,11 @@ DeduceTemplateArguments(ASTContext &Context,
assert(0 && "FIXME: Implement!");
break;
}
-
+
return Sema::TDK_Success;
}
-static Sema::TemplateDeductionResult
+static Sema::TemplateDeductionResult
DeduceTemplateArguments(ASTContext &Context,
TemplateParameterList *TemplateParams,
const TemplateArgumentList &ParamList,
@@ -680,7 +858,7 @@ DeduceTemplateArguments(ASTContext &Context,
for (unsigned I = 0, N = ParamList.size(); I != N; ++I) {
if (Sema::TemplateDeductionResult Result
= DeduceTemplateArguments(Context, TemplateParams,
- ParamList[I], ArgList[I],
+ ParamList[I], ArgList[I],
Info, Deduced))
return Result;
}
@@ -688,41 +866,41 @@ DeduceTemplateArguments(ASTContext &Context,
}
/// \brief Determine whether two template arguments are the same.
-static bool isSameTemplateArg(ASTContext &Context,
+static bool isSameTemplateArg(ASTContext &Context,
const TemplateArgument &X,
const TemplateArgument &Y) {
if (X.getKind() != Y.getKind())
return false;
-
+
switch (X.getKind()) {
case TemplateArgument::Null:
assert(false && "Comparing NULL template argument");
break;
-
+
case TemplateArgument::Type:
return Context.getCanonicalType(X.getAsType()) ==
Context.getCanonicalType(Y.getAsType());
-
+
case TemplateArgument::Declaration:
- return Context.getCanonicalDecl(X.getAsDecl()) ==
- Context.getCanonicalDecl(Y.getAsDecl());
-
+ return X.getAsDecl()->getCanonicalDecl() ==
+ Y.getAsDecl()->getCanonicalDecl();
+
case TemplateArgument::Integral:
return *X.getAsIntegral() == *Y.getAsIntegral();
-
+
case TemplateArgument::Expression:
// FIXME: We assume that all expressions are distinct, but we should
// really check their canonical forms.
return false;
-
+
case TemplateArgument::Pack:
if (X.pack_size() != Y.pack_size())
return false;
-
- for (TemplateArgument::pack_iterator XP = X.pack_begin(),
- XPEnd = X.pack_end(),
+
+ for (TemplateArgument::pack_iterator XP = X.pack_begin(),
+ XPEnd = X.pack_end(),
YP = Y.pack_begin();
- XP != XPEnd; ++XP, ++YP)
+ XP != XPEnd; ++XP, ++YP)
if (!isSameTemplateArg(Context, *XP, *YP))
return false;
@@ -739,7 +917,7 @@ static TemplateParameter makeTemplateParameter(Decl *D) {
return TemplateParameter(TTP);
else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D))
return TemplateParameter(NTTP);
-
+
return TemplateParameter(cast<TemplateTemplateParmDecl>(D));
}
@@ -759,9 +937,9 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
llvm::SmallVector<TemplateArgument, 4> Deduced;
Deduced.resize(Partial->getTemplateParameters()->size());
if (TemplateDeductionResult Result
- = ::DeduceTemplateArguments(Context,
+ = ::DeduceTemplateArguments(Context,
Partial->getTemplateParameters(),
- Partial->getTemplateArgs(),
+ Partial->getTemplateArgs(),
TemplateArgs, Info, Deduced))
return Result;
@@ -777,11 +955,12 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
Deduced.size());
for (unsigned I = 0, N = Deduced.size(); I != N; ++I) {
if (Deduced[I].isNull()) {
- Decl *Param
- = const_cast<Decl *>(Partial->getTemplateParameters()->getParam(I));
+ Decl *Param
+ = const_cast<NamedDecl *>(
+ Partial->getTemplateParameters()->getParam(I));
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
Info.Param = TTP;
- else if (NonTypeTemplateParmDecl *NTTP
+ else if (NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(Param))
Info.Param = NTTP;
else
@@ -793,7 +972,7 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
}
// Form the template argument list from the deduced template arguments.
- TemplateArgumentList *DeducedArgumentList
+ TemplateArgumentList *DeducedArgumentList
= new (Context) TemplateArgumentList(Context, Builder, /*TakeArgs=*/true);
Info.reset(DeducedArgumentList);
@@ -801,44 +980,45 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
// arguments of the class template partial specialization, and
// verify that the instantiated template arguments are both valid
// and are equivalent to the template arguments originally provided
- // to the class template.
+ // to the class template.
ClassTemplateDecl *ClassTemplate = Partial->getSpecializedTemplate();
const TemplateArgumentList &PartialTemplateArgs = Partial->getTemplateArgs();
for (unsigned I = 0, N = PartialTemplateArgs.flat_size(); I != N; ++I) {
- Decl *Param = const_cast<Decl *>(
+ Decl *Param = const_cast<NamedDecl *>(
ClassTemplate->getTemplateParameters()->getParam(I));
- TemplateArgument InstArg = Instantiate(PartialTemplateArgs[I],
- *DeducedArgumentList);
+ TemplateArgument InstArg
+ = Subst(PartialTemplateArgs[I],
+ MultiLevelTemplateArgumentList(*DeducedArgumentList));
if (InstArg.isNull()) {
Info.Param = makeTemplateParameter(Param);
Info.FirstArg = PartialTemplateArgs[I];
- return TDK_SubstitutionFailure;
+ return TDK_SubstitutionFailure;
}
-
+
if (InstArg.getKind() == TemplateArgument::Expression) {
- // When the argument is an expression, check the expression result
+ // When the argument is an expression, check the expression result
// against the actual template parameter to get down to the canonical
// template argument.
Expr *InstExpr = InstArg.getAsExpr();
- if (NonTypeTemplateParmDecl *NTTP
+ if (NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(Param)) {
if (CheckTemplateArgument(NTTP, NTTP->getType(), InstExpr, InstArg)) {
Info.Param = makeTemplateParameter(Param);
Info.FirstArg = PartialTemplateArgs[I];
- return TDK_SubstitutionFailure;
+ return TDK_SubstitutionFailure;
}
- } else if (TemplateTemplateParmDecl *TTP
+ } else if (TemplateTemplateParmDecl *TTP
= dyn_cast<TemplateTemplateParmDecl>(Param)) {
// FIXME: template template arguments should really resolve to decls
DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(InstExpr);
if (!DRE || CheckTemplateArgument(TTP, DRE)) {
Info.Param = makeTemplateParameter(Param);
Info.FirstArg = PartialTemplateArgs[I];
- return TDK_SubstitutionFailure;
+ return TDK_SubstitutionFailure;
}
}
}
-
+
if (!isSameTemplateArg(Context, TemplateArgs[I], InstArg)) {
Info.Param = makeTemplateParameter(Param);
Info.FirstArg = TemplateArgs[I];
@@ -855,27 +1035,244 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
/// \brief Determine whether the given type T is a simple-template-id type.
static bool isSimpleTemplateIdType(QualType T) {
- if (const TemplateSpecializationType *Spec
- = T->getAsTemplateSpecializationType())
+ if (const TemplateSpecializationType *Spec
+ = T->getAs<TemplateSpecializationType>())
return Spec->getTemplateName().getAsTemplateDecl() != 0;
-
+
return false;
}
-
+
+/// \brief Substitute the explicitly-provided template arguments into the
+/// given function template according to C++ [temp.arg.explicit].
+///
+/// \param FunctionTemplate the function template into which the explicit
+/// template arguments will be substituted.
+///
+/// \param ExplicitTemplateArguments the explicitly-specified template
+/// arguments.
+///
+/// \param NumExplicitTemplateArguments the number of explicitly-specified
+/// template arguments in @p ExplicitTemplateArguments. This value may be zero.
+///
+/// \param Deduced the deduced template arguments, which will be populated
+/// with the converted and checked explicit template arguments.
+///
+/// \param ParamTypes will be populated with the instantiated function
+/// parameters.
+///
+/// \param FunctionType if non-NULL, the result type of the function template
+/// will also be instantiated and the pointed-to value will be updated with
+/// the instantiated function type.
+///
+/// \param Info if substitution fails for any reason, this object will be
+/// populated with more information about the failure.
+///
+/// \returns TDK_Success if substitution was successful, or some failure
+/// condition.
+Sema::TemplateDeductionResult
+Sema::SubstituteExplicitTemplateArguments(
+ FunctionTemplateDecl *FunctionTemplate,
+ const TemplateArgument *ExplicitTemplateArgs,
+ unsigned NumExplicitTemplateArgs,
+ llvm::SmallVectorImpl<TemplateArgument> &Deduced,
+ llvm::SmallVectorImpl<QualType> &ParamTypes,
+ QualType *FunctionType,
+ TemplateDeductionInfo &Info) {
+ FunctionDecl *Function = FunctionTemplate->getTemplatedDecl();
+ TemplateParameterList *TemplateParams
+ = FunctionTemplate->getTemplateParameters();
+
+ if (NumExplicitTemplateArgs == 0) {
+ // No arguments to substitute; just copy over the parameter types and
+ // fill in the function type.
+ for (FunctionDecl::param_iterator P = Function->param_begin(),
+ PEnd = Function->param_end();
+ P != PEnd;
+ ++P)
+ ParamTypes.push_back((*P)->getType());
+
+ if (FunctionType)
+ *FunctionType = Function->getType();
+ return TDK_Success;
+ }
+
+ // Substitution of the explicit template arguments into a function template
+ /// is a SFINAE context. Trap any errors that might occur.
+ SFINAETrap Trap(*this);
+
+ // C++ [temp.arg.explicit]p3:
+ // Template arguments that are present shall be specified in the
+ // declaration order of their corresponding template-parameters. The
+ // template argument list shall not specify more template-arguments than
+ // there are corresponding template-parameters.
+ TemplateArgumentListBuilder Builder(TemplateParams,
+ NumExplicitTemplateArgs);
+
+ // Enter a new template instantiation context where we check the
+ // explicitly-specified template arguments against this function template,
+ // and then substitute them into the function parameter types.
+ InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(),
+ FunctionTemplate, Deduced.data(), Deduced.size(),
+ ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution);
+ if (Inst)
+ return TDK_InstantiationDepth;
+
+ if (CheckTemplateArgumentList(FunctionTemplate,
+ SourceLocation(), SourceLocation(),
+ ExplicitTemplateArgs,
+ NumExplicitTemplateArgs,
+ SourceLocation(),
+ true,
+ Builder) || Trap.hasErrorOccurred())
+ return TDK_InvalidExplicitArguments;
+
+ // Form the template argument list from the explicitly-specified
+ // template arguments.
+ TemplateArgumentList *ExplicitArgumentList
+ = new (Context) TemplateArgumentList(Context, Builder, /*TakeArgs=*/true);
+ Info.reset(ExplicitArgumentList);
+
+ // Instantiate the types of each of the function parameters given the
+ // explicitly-specified template arguments.
+ for (FunctionDecl::param_iterator P = Function->param_begin(),
+ PEnd = Function->param_end();
+ P != PEnd;
+ ++P) {
+ QualType ParamType
+ = SubstType((*P)->getType(),
+ MultiLevelTemplateArgumentList(*ExplicitArgumentList),
+ (*P)->getLocation(), (*P)->getDeclName());
+ if (ParamType.isNull() || Trap.hasErrorOccurred())
+ return TDK_SubstitutionFailure;
+
+ ParamTypes.push_back(ParamType);
+ }
+
+ // If the caller wants a full function type back, instantiate the return
+ // type and form that function type.
+ if (FunctionType) {
+ // FIXME: exception-specifications?
+ const FunctionProtoType *Proto
+ = Function->getType()->getAs<FunctionProtoType>();
+ assert(Proto && "Function template does not have a prototype?");
+
+ QualType ResultType
+ = SubstType(Proto->getResultType(),
+ MultiLevelTemplateArgumentList(*ExplicitArgumentList),
+ Function->getTypeSpecStartLoc(),
+ Function->getDeclName());
+ if (ResultType.isNull() || Trap.hasErrorOccurred())
+ return TDK_SubstitutionFailure;
+
+ *FunctionType = BuildFunctionType(ResultType,
+ ParamTypes.data(), ParamTypes.size(),
+ Proto->isVariadic(),
+ Proto->getTypeQuals(),
+ Function->getLocation(),
+ Function->getDeclName());
+ if (FunctionType->isNull() || Trap.hasErrorOccurred())
+ return TDK_SubstitutionFailure;
+ }
+
+ // C++ [temp.arg.explicit]p2:
+ // Trailing template arguments that can be deduced (14.8.2) may be
+ // omitted from the list of explicit template-arguments. If all of the
+ // template arguments can be deduced, they may all be omitted; in this
+ // case, the empty template argument list <> itself may also be omitted.
+ //
+ // Take all of the explicitly-specified arguments and put them into the
+ // set of deduced template arguments.
+ Deduced.reserve(TemplateParams->size());
+ for (unsigned I = 0, N = ExplicitArgumentList->size(); I != N; ++I)
+ Deduced.push_back(ExplicitArgumentList->get(I));
+
+ return TDK_Success;
+}
+
+/// \brief Finish template argument deduction for a function template,
+/// checking the deduced template arguments for completeness and forming
+/// the function template specialization.
+Sema::TemplateDeductionResult
+Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
+ llvm::SmallVectorImpl<TemplateArgument> &Deduced,
+ FunctionDecl *&Specialization,
+ TemplateDeductionInfo &Info) {
+ TemplateParameterList *TemplateParams
+ = FunctionTemplate->getTemplateParameters();
+
+ // C++ [temp.deduct.type]p2:
+ // [...] or if any template argument remains neither deduced nor
+ // explicitly specified, template argument deduction fails.
+ TemplateArgumentListBuilder Builder(TemplateParams, Deduced.size());
+ for (unsigned I = 0, N = Deduced.size(); I != N; ++I) {
+ if (Deduced[I].isNull()) {
+ Info.Param = makeTemplateParameter(
+ const_cast<NamedDecl *>(TemplateParams->getParam(I)));
+ return TDK_Incomplete;
+ }
+
+ Builder.Append(Deduced[I]);
+ }
+
+ // Form the template argument list from the deduced template arguments.
+ TemplateArgumentList *DeducedArgumentList
+ = new (Context) TemplateArgumentList(Context, Builder, /*TakeArgs=*/true);
+ Info.reset(DeducedArgumentList);
+
+ // Template argument deduction for function templates in a SFINAE context.
+ // Trap any errors that might occur.
+ SFINAETrap Trap(*this);
+
+ // Enter a new template instantiation context while we instantiate the
+ // actual function declaration.
+ InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(),
+ FunctionTemplate, Deduced.data(), Deduced.size(),
+ ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution);
+ if (Inst)
+ return TDK_InstantiationDepth;
+
+ // Substitute the deduced template arguments into the function template
+ // declaration to produce the function template specialization.
+ Specialization = cast_or_null<FunctionDecl>(
+ SubstDecl(FunctionTemplate->getTemplatedDecl(),
+ FunctionTemplate->getDeclContext(),
+ MultiLevelTemplateArgumentList(*DeducedArgumentList)));
+ if (!Specialization)
+ return TDK_SubstitutionFailure;
+
+ assert(Specialization->getPrimaryTemplate()->getCanonicalDecl() ==
+ FunctionTemplate->getCanonicalDecl());
+
+ // If the template argument list is owned by the function template
+ // specialization, release it.
+ if (Specialization->getTemplateSpecializationArgs() == DeducedArgumentList)
+ Info.take();
+
+ // There may have been an error that did not prevent us from constructing a
+ // declaration. Mark the declaration invalid and return with a substitution
+ // failure.
+ if (Trap.hasErrorOccurred()) {
+ Specialization->setInvalidDecl(true);
+ return TDK_SubstitutionFailure;
+ }
+
+ return TDK_Success;
+}
+
/// \brief Perform template argument deduction from a function call
/// (C++ [temp.deduct.call]).
///
/// \param FunctionTemplate the function template for which we are performing
/// template argument deduction.
///
-/// \param HasExplicitTemplateArgs whether any template arguments were
+/// \param HasExplicitTemplateArgs whether any template arguments were
/// explicitly specified.
///
/// \param ExplicitTemplateArguments when @p HasExplicitTemplateArgs is true,
/// the explicitly-specified template arguments.
///
/// \param NumExplicitTemplateArguments when @p HasExplicitTemplateArgs is true,
-/// the number of explicitly-specified template arguments in
+/// the number of explicitly-specified template arguments in
/// @p ExplicitTemplateArguments. This value may be zero.
///
/// \param Args the function call arguments
@@ -883,7 +1280,7 @@ static bool isSimpleTemplateIdType(QualType T) {
/// \param NumArgs the number of arguments in Args
///
/// \param Specialization if template argument deduction was successful,
-/// this will be set to the function template specialization produced by
+/// this will be set to the function template specialization produced by
/// template argument deduction.
///
/// \param Info the argument will be updated to provide additional information
@@ -908,17 +1305,13 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
if (NumArgs < Function->getMinRequiredArguments())
return TDK_TooFewArguments;
else if (NumArgs > Function->getNumParams()) {
- const FunctionProtoType *Proto
- = Function->getType()->getAsFunctionProtoType();
+ const FunctionProtoType *Proto
+ = Function->getType()->getAs<FunctionProtoType>();
if (!Proto->isVariadic())
return TDK_TooManyArguments;
-
+
CheckArgs = Function->getNumParams();
}
-
- // Template argument deduction for function templates in a SFINAE context.
- // Trap any errors that might occur.
- SFINAETrap Trap(*this);
// The types of the parameters from which we will perform template argument
// deduction.
@@ -927,89 +1320,40 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
llvm::SmallVector<TemplateArgument, 4> Deduced;
llvm::SmallVector<QualType, 4> ParamTypes;
if (NumExplicitTemplateArgs) {
- // C++ [temp.arg.explicit]p3:
- // Template arguments that are present shall be specified in the
- // declaration order of their corresponding template-parameters. The
- // template argument list shall not specify more template-arguments than
- // there are corresponding template-parameters.
- TemplateArgumentListBuilder Builder(TemplateParams,
- NumExplicitTemplateArgs);
-
- // Enter a new template instantiation context where we check the
- // explicitly-specified template arguments against this function template,
- // and then substitute them into the function parameter types.
- InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(),
- FunctionTemplate, Deduced.data(), Deduced.size(),
- ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution);
- if (Inst)
- return TDK_InstantiationDepth;
-
- if (CheckTemplateArgumentList(FunctionTemplate,
- SourceLocation(), SourceLocation(),
- ExplicitTemplateArgs,
- NumExplicitTemplateArgs,
- SourceLocation(),
- true,
- Builder) || Trap.hasErrorOccurred())
- return TDK_InvalidExplicitArguments;
-
- // Form the template argument list from the explicitly-specified
- // template arguments.
- TemplateArgumentList *ExplicitArgumentList
- = new (Context) TemplateArgumentList(Context, Builder, /*TakeArgs=*/true);
- Info.reset(ExplicitArgumentList);
-
- // Instantiate the types of each of the function parameters given the
- // explicitly-specified template arguments.
- for (FunctionDecl::param_iterator P = Function->param_begin(),
- PEnd = Function->param_end();
- P != PEnd;
- ++P) {
- QualType ParamType = InstantiateType((*P)->getType(),
- *ExplicitArgumentList,
- (*P)->getLocation(),
- (*P)->getDeclName());
- if (ParamType.isNull() || Trap.hasErrorOccurred())
- return TDK_SubstitutionFailure;
-
- ParamTypes.push_back(ParamType);
- }
-
- // C++ [temp.arg.explicit]p2:
- // Trailing template arguments that can be deduced (14.8.2) may be
- // omitted from the list of explicit template- arguments. If all of the
- // template arguments can be deduced, they may all be omitted; in this
- // case, the empty template argument list <> itself may also be omitted.
- //
- // Take all of the explicitly-specified arguments and put them into the
- // set of deduced template arguments.
- Deduced.reserve(TemplateParams->size());
- for (unsigned I = 0, N = ExplicitArgumentList->size(); I != N; ++I)
- Deduced.push_back(ExplicitArgumentList->get(I));
+ TemplateDeductionResult Result =
+ SubstituteExplicitTemplateArguments(FunctionTemplate,
+ ExplicitTemplateArgs,
+ NumExplicitTemplateArgs,
+ Deduced,
+ ParamTypes,
+ 0,
+ Info);
+ if (Result)
+ return Result;
} else {
// Just fill in the parameter types from the function declaration.
for (unsigned I = 0; I != CheckArgs; ++I)
ParamTypes.push_back(Function->getParamDecl(I)->getType());
}
-
+
// Deduce template arguments from the function parameters.
- Deduced.resize(TemplateParams->size());
+ Deduced.resize(TemplateParams->size());
for (unsigned I = 0; I != CheckArgs; ++I) {
QualType ParamType = ParamTypes[I];
QualType ArgType = Args[I]->getType();
-
+
// C++ [temp.deduct.call]p2:
// If P is not a reference type:
QualType CanonParamType = Context.getCanonicalType(ParamType);
bool ParamWasReference = isa<ReferenceType>(CanonParamType);
if (!ParamWasReference) {
- // - If A is an array type, the pointer type produced by the
- // array-to-pointer standard conversion (4.2) is used in place of
+ // - If A is an array type, the pointer type produced by the
+ // array-to-pointer standard conversion (4.2) is used in place of
// A for type deduction; otherwise,
if (ArgType->isArrayType())
ArgType = Context.getArrayDecayedType(ArgType);
- // - If A is a function type, the pointer type produced by the
- // function-to-pointer standard conversion (4.3) is used in place
+ // - If A is a function type, the pointer type produced by the
+ // function-to-pointer standard conversion (4.3) is used in place
// of A for type deduction; otherwise,
else if (ArgType->isFunctionType())
ArgType = Context.getPointerType(ArgType);
@@ -1021,252 +1365,884 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
ArgType = CanonArgType.getUnqualifiedType();
}
}
-
+
// C++0x [temp.deduct.call]p3:
// If P is a cv-qualified type, the top level cv-qualifiers of P’s type
- // are ignored for type deduction.
+ // are ignored for type deduction.
if (CanonParamType.getCVRQualifiers())
ParamType = CanonParamType.getUnqualifiedType();
- if (const ReferenceType *ParamRefType = ParamType->getAsReferenceType()) {
- // [...] If P is a reference type, the type referred to by P is used
- // for type deduction.
+ if (const ReferenceType *ParamRefType = ParamType->getAs<ReferenceType>()) {
+ // [...] If P is a reference type, the type referred to by P is used
+ // for type deduction.
ParamType = ParamRefType->getPointeeType();
-
- // [...] If P is of the form T&&, where T is a template parameter, and
- // the argument is an lvalue, the type A& is used in place of A for
+
+ // [...] If P is of the form T&&, where T is a template parameter, and
+ // the argument is an lvalue, the type A& is used in place of A for
// type deduction.
if (isa<RValueReferenceType>(ParamRefType) &&
- ParamRefType->getAsTemplateTypeParmType() &&
+ ParamRefType->getAs<TemplateTypeParmType>() &&
Args[I]->isLvalue(Context) == Expr::LV_Valid)
ArgType = Context.getLValueReferenceType(ArgType);
}
-
+
// C++0x [temp.deduct.call]p4:
// In general, the deduction process attempts to find template argument
// values that will make the deduced A identical to A (after the type A
// is transformed as described above). [...]
- unsigned TDF = 0;
-
+ unsigned TDF = TDF_SkipNonDependent;
+
// - If the original P is a reference type, the deduced A (i.e., the
// type referred to by the reference) can be more cv-qualified than
// the transformed A.
if (ParamWasReference)
TDF |= TDF_ParamWithReferenceType;
- // - The transformed A can be another pointer or pointer to member
- // type that can be converted to the deduced A via a qualification
+ // - The transformed A can be another pointer or pointer to member
+ // type that can be converted to the deduced A via a qualification
// conversion (4.4).
if (ArgType->isPointerType() || ArgType->isMemberPointerType())
TDF |= TDF_IgnoreQualifiers;
- // - If P is a class and P has the form simple-template-id, then the
+ // - If P is a class and P has the form simple-template-id, then the
// transformed A can be a derived class of the deduced A. Likewise,
// if P is a pointer to a class of the form simple-template-id, the
// transformed A can be a pointer to a derived class pointed to by
// the deduced A.
if (isSimpleTemplateIdType(ParamType) ||
- (isa<PointerType>(ParamType) &&
+ (isa<PointerType>(ParamType) &&
isSimpleTemplateIdType(
- ParamType->getAsPointerType()->getPointeeType())))
+ ParamType->getAs<PointerType>()->getPointeeType())))
TDF |= TDF_DerivedClass;
-
+
if (TemplateDeductionResult Result
= ::DeduceTemplateArguments(Context, TemplateParams,
ParamType, ArgType, Info, Deduced,
TDF))
return Result;
+
+ // FIXME: C++0x [temp.deduct.call] paragraphs 6-9 deal with function
+ // pointer parameters.
+
+ // FIXME: we need to check that the deduced A is the same as A,
+ // modulo the various allowed differences.
+ }
+
+ return FinishTemplateArgumentDeduction(FunctionTemplate, Deduced,
+ Specialization, Info);
+}
+
+/// \brief Deduce template arguments when taking the address of a function
+/// template (C++ [temp.deduct.funcaddr]) or matching a
+///
+/// \param FunctionTemplate the function template for which we are performing
+/// template argument deduction.
+///
+/// \param HasExplicitTemplateArgs whether any template arguments were
+/// explicitly specified.
+///
+/// \param ExplicitTemplateArguments when @p HasExplicitTemplateArgs is true,
+/// the explicitly-specified template arguments.
+///
+/// \param NumExplicitTemplateArguments when @p HasExplicitTemplateArgs is true,
+/// the number of explicitly-specified template arguments in
+/// @p ExplicitTemplateArguments. This value may be zero.
+///
+/// \param ArgFunctionType the function type that will be used as the
+/// "argument" type (A) when performing template argument deduction from the
+/// function template's function type.
+///
+/// \param Specialization if template argument deduction was successful,
+/// this will be set to the function template specialization produced by
+/// template argument deduction.
+///
+/// \param Info the argument will be updated to provide additional information
+/// about template argument deduction.
+///
+/// \returns the result of template argument deduction.
+Sema::TemplateDeductionResult
+Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
+ bool HasExplicitTemplateArgs,
+ const TemplateArgument *ExplicitTemplateArgs,
+ unsigned NumExplicitTemplateArgs,
+ QualType ArgFunctionType,
+ FunctionDecl *&Specialization,
+ TemplateDeductionInfo &Info) {
+ FunctionDecl *Function = FunctionTemplate->getTemplatedDecl();
+ TemplateParameterList *TemplateParams
+ = FunctionTemplate->getTemplateParameters();
+ QualType FunctionType = Function->getType();
+
+ // Substitute any explicit template arguments.
+ llvm::SmallVector<TemplateArgument, 4> Deduced;
+ llvm::SmallVector<QualType, 4> ParamTypes;
+ if (HasExplicitTemplateArgs) {
+ if (TemplateDeductionResult Result
+ = SubstituteExplicitTemplateArguments(FunctionTemplate,
+ ExplicitTemplateArgs,
+ NumExplicitTemplateArgs,
+ Deduced, ParamTypes,
+ &FunctionType, Info))
+ return Result;
+ }
+
+ // Template argument deduction for function templates in a SFINAE context.
+ // Trap any errors that might occur.
+ SFINAETrap Trap(*this);
+
+ // Deduce template arguments from the function type.
+ Deduced.resize(TemplateParams->size());
+ if (TemplateDeductionResult Result
+ = ::DeduceTemplateArguments(Context, TemplateParams,
+ FunctionType, ArgFunctionType, Info,
+ Deduced, 0))
+ return Result;
+
+ return FinishTemplateArgumentDeduction(FunctionTemplate, Deduced,
+ Specialization, Info);
+}
+
+/// \brief Deduce template arguments for a templated conversion
+/// function (C++ [temp.deduct.conv]) and, if successful, produce a
+/// conversion function template specialization.
+Sema::TemplateDeductionResult
+Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
+ QualType ToType,
+ CXXConversionDecl *&Specialization,
+ TemplateDeductionInfo &Info) {
+ CXXConversionDecl *Conv
+ = cast<CXXConversionDecl>(FunctionTemplate->getTemplatedDecl());
+ QualType FromType = Conv->getConversionType();
+
+ // Canonicalize the types for deduction.
+ QualType P = Context.getCanonicalType(FromType);
+ QualType A = Context.getCanonicalType(ToType);
+
+ // C++0x [temp.deduct.conv]p3:
+ // If P is a reference type, the type referred to by P is used for
+ // type deduction.
+ if (const ReferenceType *PRef = P->getAs<ReferenceType>())
+ P = PRef->getPointeeType();
+
+ // C++0x [temp.deduct.conv]p3:
+ // If A is a reference type, the type referred to by A is used
+ // for type deduction.
+ if (const ReferenceType *ARef = A->getAs<ReferenceType>())
+ A = ARef->getPointeeType();
+ // C++ [temp.deduct.conv]p2:
+ //
+ // If A is not a reference type:
+ else {
+ assert(!A->isReferenceType() && "Reference types were handled above");
+
+ // - If P is an array type, the pointer type produced by the
+ // array-to-pointer standard conversion (4.2) is used in place
+ // of P for type deduction; otherwise,
+ if (P->isArrayType())
+ P = Context.getArrayDecayedType(P);
+ // - If P is a function type, the pointer type produced by the
+ // function-to-pointer standard conversion (4.3) is used in
+ // place of P for type deduction; otherwise,
+ else if (P->isFunctionType())
+ P = Context.getPointerType(P);
+ // - If P is a cv-qualified type, the top level cv-qualifiers of
+ // P’s type are ignored for type deduction.
+ else
+ P = P.getUnqualifiedType();
+
+ // C++0x [temp.deduct.conv]p3:
+ // If A is a cv-qualified type, the top level cv-qualifiers of A’s
+ // type are ignored for type deduction.
+ A = A.getUnqualifiedType();
+ }
+
+ // Template argument deduction for function templates in a SFINAE context.
+ // Trap any errors that might occur.
+ SFINAETrap Trap(*this);
+
+ // C++ [temp.deduct.conv]p1:
+ // Template argument deduction is done by comparing the return
+ // type of the template conversion function (call it P) with the
+ // type that is required as the result of the conversion (call it
+ // A) as described in 14.8.2.4.
+ TemplateParameterList *TemplateParams
+ = FunctionTemplate->getTemplateParameters();
+ llvm::SmallVector<TemplateArgument, 4> Deduced;
+ Deduced.resize(TemplateParams->size());
+
+ // C++0x [temp.deduct.conv]p4:
+ // In general, the deduction process attempts to find template
+ // argument values that will make the deduced A identical to
+ // A. However, there are two cases that allow a difference:
+ unsigned TDF = 0;
+ // - If the original A is a reference type, A can be more
+ // cv-qualified than the deduced A (i.e., the type referred to
+ // by the reference)
+ if (ToType->isReferenceType())
+ TDF |= TDF_ParamWithReferenceType;
+ // - The deduced A can be another pointer or pointer to member
+ // type that can be converted to A via a qualification
+ // conversion.
+ //
+ // (C++0x [temp.deduct.conv]p6 clarifies that this only happens when
+ // both P and A are pointers or member pointers. In this case, we
+ // just ignore cv-qualifiers completely).
+ if ((P->isPointerType() && A->isPointerType()) ||
+ (P->isMemberPointerType() && P->isMemberPointerType()))
+ TDF |= TDF_IgnoreQualifiers;
+ if (TemplateDeductionResult Result
+ = ::DeduceTemplateArguments(Context, TemplateParams,
+ P, A, Info, Deduced, TDF))
+ return Result;
+
+ // FIXME: we need to check that the deduced A is the same as A,
+ // modulo the various allowed differences.
+
+ // Finish template argument deduction.
+ FunctionDecl *Spec = 0;
+ TemplateDeductionResult Result
+ = FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, Spec, Info);
+ Specialization = cast_or_null<CXXConversionDecl>(Spec);
+ return Result;
+}
+
+/// \brief Stores the result of comparing the qualifiers of two types.
+enum DeductionQualifierComparison {
+ NeitherMoreQualified = 0,
+ ParamMoreQualified,
+ ArgMoreQualified
+};
+
+/// \brief Deduce the template arguments during partial ordering by comparing
+/// the parameter type and the argument type (C++0x [temp.deduct.partial]).
+///
+/// \param Context the AST context in which this deduction occurs.
+///
+/// \param TemplateParams the template parameters that we are deducing
+///
+/// \param ParamIn the parameter type
+///
+/// \param ArgIn the argument type
+///
+/// \param Info information about the template argument deduction itself
+///
+/// \param Deduced the deduced template arguments
+///
+/// \returns the result of template argument deduction so far. Note that a
+/// "success" result means that template argument deduction has not yet failed,
+/// but it may still fail, later, for other reasons.
+static Sema::TemplateDeductionResult
+DeduceTemplateArgumentsDuringPartialOrdering(ASTContext &Context,
+ TemplateParameterList *TemplateParams,
+ QualType ParamIn, QualType ArgIn,
+ Sema::TemplateDeductionInfo &Info,
+ llvm::SmallVectorImpl<TemplateArgument> &Deduced,
+ llvm::SmallVectorImpl<DeductionQualifierComparison> *QualifierComparisons) {
+ CanQualType Param = Context.getCanonicalType(ParamIn);
+ CanQualType Arg = Context.getCanonicalType(ArgIn);
+
+ // C++0x [temp.deduct.partial]p5:
+ // Before the partial ordering is done, certain transformations are
+ // performed on the types used for partial ordering:
+ // - If P is a reference type, P is replaced by the type referred to.
+ CanQual<ReferenceType> ParamRef = Param->getAs<ReferenceType>();
+ if (ParamRef)
+ Param = ParamRef->getPointeeType();
+
+ // - If A is a reference type, A is replaced by the type referred to.
+ CanQual<ReferenceType> ArgRef = Arg->getAs<ReferenceType>();
+ if (ArgRef)
+ Arg = ArgRef->getPointeeType();
+
+ if (QualifierComparisons && ParamRef && ArgRef) {
+ // C++0x [temp.deduct.partial]p6:
+ // If both P and A were reference types (before being replaced with the
+ // type referred to above), determine which of the two types (if any) is
+ // more cv-qualified than the other; otherwise the types are considered to
+ // be equally cv-qualified for partial ordering purposes. The result of this
+ // determination will be used below.
+ //
+ // We save this information for later, using it only when deduction
+ // succeeds in both directions.
+ DeductionQualifierComparison QualifierResult = NeitherMoreQualified;
+ if (Param.isMoreQualifiedThan(Arg))
+ QualifierResult = ParamMoreQualified;
+ else if (Arg.isMoreQualifiedThan(Param))
+ QualifierResult = ArgMoreQualified;
+ QualifierComparisons->push_back(QualifierResult);
+ }
+
+ // C++0x [temp.deduct.partial]p7:
+ // Remove any top-level cv-qualifiers:
+ // - If P is a cv-qualified type, P is replaced by the cv-unqualified
+ // version of P.
+ Param = Param.getUnqualifiedType();
+ // - If A is a cv-qualified type, A is replaced by the cv-unqualified
+ // version of A.
+ Arg = Arg.getUnqualifiedType();
+
+ // C++0x [temp.deduct.partial]p8:
+ // Using the resulting types P and A the deduction is then done as
+ // described in 14.9.2.5. If deduction succeeds for a given type, the type
+ // from the argument template is considered to be at least as specialized
+ // as the type from the parameter template.
+ return DeduceTemplateArguments(Context, TemplateParams, Param, Arg, Info,
+ Deduced, TDF_None);
+}
+
+static void
+MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
+ bool OnlyDeduced,
+ llvm::SmallVectorImpl<bool> &Deduced);
+
+/// \brief Determine whether the function template \p FT1 is at least as
+/// specialized as \p FT2.
+static bool isAtLeastAsSpecializedAs(Sema &S,
+ FunctionTemplateDecl *FT1,
+ FunctionTemplateDecl *FT2,
+ TemplatePartialOrderingContext TPOC,
+ llvm::SmallVectorImpl<DeductionQualifierComparison> *QualifierComparisons) {
+ FunctionDecl *FD1 = FT1->getTemplatedDecl();
+ FunctionDecl *FD2 = FT2->getTemplatedDecl();
+ const FunctionProtoType *Proto1 = FD1->getType()->getAs<FunctionProtoType>();
+ const FunctionProtoType *Proto2 = FD2->getType()->getAs<FunctionProtoType>();
+
+ assert(Proto1 && Proto2 && "Function templates must have prototypes");
+ TemplateParameterList *TemplateParams = FT2->getTemplateParameters();
+ llvm::SmallVector<TemplateArgument, 4> Deduced;
+ Deduced.resize(TemplateParams->size());
+
+ // C++0x [temp.deduct.partial]p3:
+ // The types used to determine the ordering depend on the context in which
+ // the partial ordering is done:
+ Sema::TemplateDeductionInfo Info(S.Context);
+ switch (TPOC) {
+ case TPOC_Call: {
+ // - In the context of a function call, the function parameter types are
+ // used.
+ unsigned NumParams = std::min(Proto1->getNumArgs(), Proto2->getNumArgs());
+ for (unsigned I = 0; I != NumParams; ++I)
+ if (DeduceTemplateArgumentsDuringPartialOrdering(S.Context,
+ TemplateParams,
+ Proto2->getArgType(I),
+ Proto1->getArgType(I),
+ Info,
+ Deduced,
+ QualifierComparisons))
+ return false;
+
+ break;
+ }
+
+ case TPOC_Conversion:
+ // - In the context of a call to a conversion operator, the return types
+ // of the conversion function templates are used.
+ if (DeduceTemplateArgumentsDuringPartialOrdering(S.Context,
+ TemplateParams,
+ Proto2->getResultType(),
+ Proto1->getResultType(),
+ Info,
+ Deduced,
+ QualifierComparisons))
+ return false;
+ break;
- // FIXME: C++ [temp.deduct.call] paragraphs 6-9 deal with function
- // pointer parameters.
+ case TPOC_Other:
+ // - In other contexts (14.6.6.2) the function template’s function type
+ // is used.
+ if (DeduceTemplateArgumentsDuringPartialOrdering(S.Context,
+ TemplateParams,
+ FD2->getType(),
+ FD1->getType(),
+ Info,
+ Deduced,
+ QualifierComparisons))
+ return false;
+ break;
}
- // C++ [temp.deduct.type]p2:
- // [...] or if any template argument remains neither deduced nor
- // explicitly specified, template argument deduction fails.
- TemplateArgumentListBuilder Builder(TemplateParams, Deduced.size());
- for (unsigned I = 0, N = Deduced.size(); I != N; ++I) {
- if (Deduced[I].isNull()) {
- Decl *Param
- = const_cast<Decl *>(TemplateParams->getParam(I));
- if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
- Info.Param = TTP;
- else if (NonTypeTemplateParmDecl *NTTP
- = dyn_cast<NonTypeTemplateParmDecl>(Param))
- Info.Param = NTTP;
- else
- Info.Param = cast<TemplateTemplateParmDecl>(Param);
- return TDK_Incomplete;
- }
+ // C++0x [temp.deduct.partial]p11:
+ // In most cases, all template parameters must have values in order for
+ // deduction to succeed, but for partial ordering purposes a template
+ // parameter may remain without a value provided it is not used in the
+ // types being used for partial ordering. [ Note: a template parameter used
+ // in a non-deduced context is considered used. -end note]
+ unsigned ArgIdx = 0, NumArgs = Deduced.size();
+ for (; ArgIdx != NumArgs; ++ArgIdx)
+ if (Deduced[ArgIdx].isNull())
+ break;
+
+ if (ArgIdx == NumArgs) {
+ // All template arguments were deduced. FT1 is at least as specialized
+ // as FT2.
+ return true;
+ }
+
+ // Figure out which template parameters were used.
+ llvm::SmallVector<bool, 4> UsedParameters;
+ UsedParameters.resize(TemplateParams->size());
+ switch (TPOC) {
+ case TPOC_Call: {
+ unsigned NumParams = std::min(Proto1->getNumArgs(), Proto2->getNumArgs());
+ for (unsigned I = 0; I != NumParams; ++I)
+ ::MarkUsedTemplateParameters(S, Proto2->getArgType(I), false,
+ UsedParameters);
+ break;
+ }
- Builder.Append(Deduced[I]);
+ case TPOC_Conversion:
+ ::MarkUsedTemplateParameters(S, Proto2->getResultType(), false,
+ UsedParameters);
+ break;
+
+ case TPOC_Other:
+ ::MarkUsedTemplateParameters(S, FD2->getType(), false, UsedParameters);
+ break;
}
- // Form the template argument list from the deduced template arguments.
- TemplateArgumentList *DeducedArgumentList
- = new (Context) TemplateArgumentList(Context, Builder, /*TakeArgs=*/true);
- Info.reset(DeducedArgumentList);
+ for (; ArgIdx != NumArgs; ++ArgIdx)
+ // If this argument had no value deduced but was used in one of the types
+ // used for partial ordering, then deduction fails.
+ if (Deduced[ArgIdx].isNull() && UsedParameters[ArgIdx])
+ return false;
- // Enter a new template instantiation context while we instantiate the
- // actual function declaration.
- InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(),
- FunctionTemplate, Deduced.data(), Deduced.size(),
- ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution);
- if (Inst)
- return TDK_InstantiationDepth;
-
- // Substitute the deduced template arguments into the function template
- // declaration to produce the function template specialization.
- Specialization = cast_or_null<FunctionDecl>(
- InstantiateDecl(FunctionTemplate->getTemplatedDecl(),
- FunctionTemplate->getDeclContext(),
- *DeducedArgumentList));
- if (!Specialization)
- return TDK_SubstitutionFailure;
+ return true;
+}
+
+
+/// \brief Returns the more specialized function template according
+/// to the rules of function template partial ordering (C++ [temp.func.order]).
+///
+/// \param FT1 the first function template
+///
+/// \param FT2 the second function template
+///
+/// \param TPOC the context in which we are performing partial ordering of
+/// function templates.
+///
+/// \returns the more specialized function template. If neither
+/// template is more specialized, returns NULL.
+FunctionTemplateDecl *
+Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
+ FunctionTemplateDecl *FT2,
+ TemplatePartialOrderingContext TPOC) {
+ llvm::SmallVector<DeductionQualifierComparison, 4> QualifierComparisons;
+ bool Better1 = isAtLeastAsSpecializedAs(*this, FT1, FT2, TPOC, 0);
+ bool Better2 = isAtLeastAsSpecializedAs(*this, FT2, FT1, TPOC,
+ &QualifierComparisons);
- // If the template argument list is owned by the function template
- // specialization, release it.
- if (Specialization->getTemplateSpecializationArgs() == DeducedArgumentList)
- Info.take();
+ if (Better1 != Better2) // We have a clear winner
+ return Better1? FT1 : FT2;
+
+ if (!Better1 && !Better2) // Neither is better than the other
+ return 0;
+
+
+ // C++0x [temp.deduct.partial]p10:
+ // If for each type being considered a given template is at least as
+ // specialized for all types and more specialized for some set of types and
+ // the other template is not more specialized for any types or is not at
+ // least as specialized for any types, then the given template is more
+ // specialized than the other template. Otherwise, neither template is more
+ // specialized than the other.
+ Better1 = false;
+ Better2 = false;
+ for (unsigned I = 0, N = QualifierComparisons.size(); I != N; ++I) {
+ // C++0x [temp.deduct.partial]p9:
+ // If, for a given type, deduction succeeds in both directions (i.e., the
+ // types are identical after the transformations above) and if the type
+ // from the argument template is more cv-qualified than the type from the
+ // parameter template (as described above) that type is considered to be
+ // more specialized than the other. If neither type is more cv-qualified
+ // than the other then neither type is more specialized than the other.
+ switch (QualifierComparisons[I]) {
+ case NeitherMoreQualified:
+ break;
+
+ case ParamMoreQualified:
+ Better1 = true;
+ if (Better2)
+ return 0;
+ break;
+
+ case ArgMoreQualified:
+ Better2 = true;
+ if (Better1)
+ return 0;
+ break;
+ }
+ }
+
+ assert(!(Better1 && Better2) && "Should have broken out in the loop above");
+ if (Better1)
+ return FT1;
+ else if (Better2)
+ return FT2;
+ else
+ return 0;
+}
- // There may have been an error that did not prevent us from constructing a
- // declaration. Mark the declaration invalid and return with a substitution
- // failure.
- if (Trap.hasErrorOccurred()) {
- Specialization->setInvalidDecl(true);
- return TDK_SubstitutionFailure;
+/// \brief Determine if the two templates are equivalent.
+static bool isSameTemplate(TemplateDecl *T1, TemplateDecl *T2) {
+ if (T1 == T2)
+ return true;
+
+ if (!T1 || !T2)
+ return false;
+
+ return T1->getCanonicalDecl() == T2->getCanonicalDecl();
+}
+
+/// \brief Retrieve the most specialized of the given function template
+/// specializations.
+///
+/// \param Specializations the set of function template specializations that
+/// we will be comparing.
+///
+/// \param NumSpecializations the number of function template specializations in
+/// \p Specializations
+///
+/// \param TPOC the partial ordering context to use to compare the function
+/// template specializations.
+///
+/// \param Loc the location where the ambiguity or no-specializations
+/// diagnostic should occur.
+///
+/// \param NoneDiag partial diagnostic used to diagnose cases where there are
+/// no matching candidates.
+///
+/// \param AmbigDiag partial diagnostic used to diagnose an ambiguity, if one
+/// occurs.
+///
+/// \param CandidateDiag partial diagnostic used for each function template
+/// specialization that is a candidate in the ambiguous ordering. One parameter
+/// in this diagnostic should be unbound, which will correspond to the string
+/// describing the template arguments for the function template specialization.
+///
+/// \param Index if non-NULL and the result of this function is non-nULL,
+/// receives the index corresponding to the resulting function template
+/// specialization.
+///
+/// \returns the most specialized function template specialization, if
+/// found. Otherwise, returns NULL.
+///
+/// \todo FIXME: Consider passing in the "also-ran" candidates that failed
+/// template argument deduction.
+FunctionDecl *Sema::getMostSpecialized(FunctionDecl **Specializations,
+ unsigned NumSpecializations,
+ TemplatePartialOrderingContext TPOC,
+ SourceLocation Loc,
+ const PartialDiagnostic &NoneDiag,
+ const PartialDiagnostic &AmbigDiag,
+ const PartialDiagnostic &CandidateDiag,
+ unsigned *Index) {
+ if (NumSpecializations == 0) {
+ Diag(Loc, NoneDiag);
+ return 0;
}
- return TDK_Success;
+ if (NumSpecializations == 1) {
+ if (Index)
+ *Index = 0;
+
+ return Specializations[0];
+ }
+
+
+ // Find the function template that is better than all of the templates it
+ // has been compared to.
+ unsigned Best = 0;
+ FunctionTemplateDecl *BestTemplate
+ = Specializations[Best]->getPrimaryTemplate();
+ assert(BestTemplate && "Not a function template specialization?");
+ for (unsigned I = 1; I != NumSpecializations; ++I) {
+ FunctionTemplateDecl *Challenger = Specializations[I]->getPrimaryTemplate();
+ assert(Challenger && "Not a function template specialization?");
+ if (isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger,
+ TPOC),
+ Challenger)) {
+ Best = I;
+ BestTemplate = Challenger;
+ }
+ }
+
+ // Make sure that the "best" function template is more specialized than all
+ // of the others.
+ bool Ambiguous = false;
+ for (unsigned I = 0; I != NumSpecializations; ++I) {
+ FunctionTemplateDecl *Challenger = Specializations[I]->getPrimaryTemplate();
+ if (I != Best &&
+ !isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger,
+ TPOC),
+ BestTemplate)) {
+ Ambiguous = true;
+ break;
+ }
+ }
+
+ if (!Ambiguous) {
+ // We found an answer. Return it.
+ if (Index)
+ *Index = Best;
+ return Specializations[Best];
+ }
+
+ // Diagnose the ambiguity.
+ Diag(Loc, AmbigDiag);
+
+ // FIXME: Can we order the candidates in some sane way?
+ for (unsigned I = 0; I != NumSpecializations; ++I)
+ Diag(Specializations[I]->getLocation(), CandidateDiag)
+ << getTemplateArgumentBindingsText(
+ Specializations[I]->getPrimaryTemplate()->getTemplateParameters(),
+ *Specializations[I]->getTemplateSpecializationArgs());
+
+ return 0;
+}
+
+/// \brief Returns the more specialized class template partial specialization
+/// according to the rules of partial ordering of class template partial
+/// specializations (C++ [temp.class.order]).
+///
+/// \param PS1 the first class template partial specialization
+///
+/// \param PS2 the second class template partial specialization
+///
+/// \returns the more specialized class template partial specialization. If
+/// neither partial specialization is more specialized, returns NULL.
+ClassTemplatePartialSpecializationDecl *
+Sema::getMoreSpecializedPartialSpecialization(
+ ClassTemplatePartialSpecializationDecl *PS1,
+ ClassTemplatePartialSpecializationDecl *PS2) {
+ // C++ [temp.class.order]p1:
+ // For two class template partial specializations, the first is at least as
+ // specialized as the second if, given the following rewrite to two
+ // function templates, the first function template is at least as
+ // specialized as the second according to the ordering rules for function
+ // templates (14.6.6.2):
+ // - the first function template has the same template parameters as the
+ // first partial specialization and has a single function parameter
+ // whose type is a class template specialization with the template
+ // arguments of the first partial specialization, and
+ // - the second function template has the same template parameters as the
+ // second partial specialization and has a single function parameter
+ // whose type is a class template specialization with the template
+ // arguments of the second partial specialization.
+ //
+ // Rather than synthesize function templates, we merely perform the
+ // equivalent partial ordering by performing deduction directly on the
+ // template arguments of the class template partial specializations. This
+ // computation is slightly simpler than the general problem of function
+ // template partial ordering, because class template partial specializations
+ // are more constrained. We know that every template parameter is deduc
+ llvm::SmallVector<TemplateArgument, 4> Deduced;
+ Sema::TemplateDeductionInfo Info(Context);
+
+ // Determine whether PS1 is at least as specialized as PS2
+ Deduced.resize(PS2->getTemplateParameters()->size());
+ bool Better1 = !DeduceTemplateArgumentsDuringPartialOrdering(Context,
+ PS2->getTemplateParameters(),
+ Context.getTypeDeclType(PS2),
+ Context.getTypeDeclType(PS1),
+ Info,
+ Deduced,
+ 0);
+
+ // Determine whether PS2 is at least as specialized as PS1
+ Deduced.resize(PS1->getTemplateParameters()->size());
+ bool Better2 = !DeduceTemplateArgumentsDuringPartialOrdering(Context,
+ PS1->getTemplateParameters(),
+ Context.getTypeDeclType(PS1),
+ Context.getTypeDeclType(PS2),
+ Info,
+ Deduced,
+ 0);
+
+ if (Better1 == Better2)
+ return 0;
+
+ return Better1? PS1 : PS2;
}
-static void
-MarkDeducedTemplateParameters(Sema &SemaRef,
- const TemplateArgument &TemplateArg,
- llvm::SmallVectorImpl<bool> &Deduced);
+static void
+MarkUsedTemplateParameters(Sema &SemaRef,
+ const TemplateArgument &TemplateArg,
+ bool OnlyDeduced,
+ llvm::SmallVectorImpl<bool> &Used);
-/// \brief Mark the template arguments that are deduced by the given
+/// \brief Mark the template parameters that are used by the given
/// expression.
-static void
-MarkDeducedTemplateParameters(const Expr *E,
- llvm::SmallVectorImpl<bool> &Deduced) {
+static void
+MarkUsedTemplateParameters(Sema &SemaRef,
+ const Expr *E,
+ bool OnlyDeduced,
+ llvm::SmallVectorImpl<bool> &Used) {
+ // FIXME: if !OnlyDeduced, we have to walk the whole subexpression to
+ // find other occurrences of template parameters.
const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E);
if (!E)
return;
- const NonTypeTemplateParmDecl *NTTP
+ const NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(DRE->getDecl());
if (!NTTP)
return;
- Deduced[NTTP->getIndex()] = true;
+ Used[NTTP->getIndex()] = true;
+}
+
+/// \brief Mark the template parameters that are used by the given
+/// nested name specifier.
+static void
+MarkUsedTemplateParameters(Sema &SemaRef,
+ NestedNameSpecifier *NNS,
+ bool OnlyDeduced,
+ llvm::SmallVectorImpl<bool> &Used) {
+ if (!NNS)
+ return;
+
+ MarkUsedTemplateParameters(SemaRef, NNS->getPrefix(), OnlyDeduced, Used);
+ MarkUsedTemplateParameters(SemaRef, QualType(NNS->getAsType(), 0),
+ OnlyDeduced, Used);
+}
+
+/// \brief Mark the template parameters that are used by the given
+/// template name.
+static void
+MarkUsedTemplateParameters(Sema &SemaRef,
+ TemplateName Name,
+ bool OnlyDeduced,
+ llvm::SmallVectorImpl<bool> &Used) {
+ if (TemplateDecl *Template = Name.getAsTemplateDecl()) {
+ if (TemplateTemplateParmDecl *TTP
+ = dyn_cast<TemplateTemplateParmDecl>(Template))
+ Used[TTP->getIndex()] = true;
+ return;
+ }
+
+ if (DependentTemplateName *DTN = Name.getAsDependentTemplateName())
+ MarkUsedTemplateParameters(SemaRef, DTN->getQualifier(), OnlyDeduced, Used);
}
-/// \brief Mark the template parameters that are deduced by the given
+/// \brief Mark the template parameters that are used by the given
/// type.
-static void
-MarkDeducedTemplateParameters(Sema &SemaRef, QualType T,
- llvm::SmallVectorImpl<bool> &Deduced) {
+static void
+MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
+ bool OnlyDeduced,
+ llvm::SmallVectorImpl<bool> &Used) {
+ if (T.isNull())
+ return;
+
// Non-dependent types have nothing deducible
if (!T->isDependentType())
return;
T = SemaRef.Context.getCanonicalType(T);
switch (T->getTypeClass()) {
- case Type::ExtQual:
- MarkDeducedTemplateParameters(SemaRef,
- QualType(cast<ExtQualType>(T)->getBaseType(), 0),
- Deduced);
- break;
-
case Type::Pointer:
- MarkDeducedTemplateParameters(SemaRef,
- cast<PointerType>(T)->getPointeeType(),
- Deduced);
+ MarkUsedTemplateParameters(SemaRef,
+ cast<PointerType>(T)->getPointeeType(),
+ OnlyDeduced,
+ Used);
break;
case Type::BlockPointer:
- MarkDeducedTemplateParameters(SemaRef,
- cast<BlockPointerType>(T)->getPointeeType(),
- Deduced);
+ MarkUsedTemplateParameters(SemaRef,
+ cast<BlockPointerType>(T)->getPointeeType(),
+ OnlyDeduced,
+ Used);
break;
case Type::LValueReference:
case Type::RValueReference:
- MarkDeducedTemplateParameters(SemaRef,
- cast<ReferenceType>(T)->getPointeeType(),
- Deduced);
+ MarkUsedTemplateParameters(SemaRef,
+ cast<ReferenceType>(T)->getPointeeType(),
+ OnlyDeduced,
+ Used);
break;
case Type::MemberPointer: {
const MemberPointerType *MemPtr = cast<MemberPointerType>(T.getTypePtr());
- MarkDeducedTemplateParameters(SemaRef, MemPtr->getPointeeType(), Deduced);
- MarkDeducedTemplateParameters(SemaRef, QualType(MemPtr->getClass(), 0),
- Deduced);
+ MarkUsedTemplateParameters(SemaRef, MemPtr->getPointeeType(), OnlyDeduced,
+ Used);
+ MarkUsedTemplateParameters(SemaRef, QualType(MemPtr->getClass(), 0),
+ OnlyDeduced, Used);
break;
}
case Type::DependentSizedArray:
- MarkDeducedTemplateParameters(cast<DependentSizedArrayType>(T)->getSizeExpr(),
- Deduced);
+ MarkUsedTemplateParameters(SemaRef,
+ cast<DependentSizedArrayType>(T)->getSizeExpr(),
+ OnlyDeduced, Used);
// Fall through to check the element type
case Type::ConstantArray:
case Type::IncompleteArray:
- MarkDeducedTemplateParameters(SemaRef,
- cast<ArrayType>(T)->getElementType(),
- Deduced);
+ MarkUsedTemplateParameters(SemaRef,
+ cast<ArrayType>(T)->getElementType(),
+ OnlyDeduced, Used);
break;
case Type::Vector:
case Type::ExtVector:
- MarkDeducedTemplateParameters(SemaRef,
- cast<VectorType>(T)->getElementType(),
- Deduced);
+ MarkUsedTemplateParameters(SemaRef,
+ cast<VectorType>(T)->getElementType(),
+ OnlyDeduced, Used);
break;
case Type::DependentSizedExtVector: {
const DependentSizedExtVectorType *VecType
= cast<DependentSizedExtVectorType>(T);
- MarkDeducedTemplateParameters(SemaRef, VecType->getElementType(), Deduced);
- MarkDeducedTemplateParameters(VecType->getSizeExpr(), Deduced);
+ MarkUsedTemplateParameters(SemaRef, VecType->getElementType(), OnlyDeduced,
+ Used);
+ MarkUsedTemplateParameters(SemaRef, VecType->getSizeExpr(), OnlyDeduced,
+ Used);
break;
}
case Type::FunctionProto: {
const FunctionProtoType *Proto = cast<FunctionProtoType>(T);
- MarkDeducedTemplateParameters(SemaRef, Proto->getResultType(), Deduced);
+ MarkUsedTemplateParameters(SemaRef, Proto->getResultType(), OnlyDeduced,
+ Used);
for (unsigned I = 0, N = Proto->getNumArgs(); I != N; ++I)
- MarkDeducedTemplateParameters(SemaRef, Proto->getArgType(I), Deduced);
+ MarkUsedTemplateParameters(SemaRef, Proto->getArgType(I), OnlyDeduced,
+ Used);
break;
}
case Type::TemplateTypeParm:
- Deduced[cast<TemplateTypeParmType>(T)->getIndex()] = true;
+ Used[cast<TemplateTypeParmType>(T)->getIndex()] = true;
break;
case Type::TemplateSpecialization: {
- const TemplateSpecializationType *Spec
+ const TemplateSpecializationType *Spec
= cast<TemplateSpecializationType>(T);
- if (TemplateDecl *Template = Spec->getTemplateName().getAsTemplateDecl())
- if (TemplateTemplateParmDecl *TTP
- = dyn_cast<TemplateTemplateParmDecl>(Template))
- Deduced[TTP->getIndex()] = true;
-
- for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I)
- MarkDeducedTemplateParameters(SemaRef, Spec->getArg(I), Deduced);
-
+ MarkUsedTemplateParameters(SemaRef, Spec->getTemplateName(), OnlyDeduced,
+ Used);
+ for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I)
+ MarkUsedTemplateParameters(SemaRef, Spec->getArg(I), OnlyDeduced, Used);
break;
}
- // None of these types have any deducible parts.
+ case Type::Complex:
+ if (!OnlyDeduced)
+ MarkUsedTemplateParameters(SemaRef,
+ cast<ComplexType>(T)->getElementType(),
+ OnlyDeduced, Used);
+ break;
+
+ case Type::Typename:
+ if (!OnlyDeduced)
+ MarkUsedTemplateParameters(SemaRef,
+ cast<TypenameType>(T)->getQualifier(),
+ OnlyDeduced, Used);
+ break;
+
+ // None of these types have any template parameters in them.
case Type::Builtin:
case Type::FixedWidthInt:
- case Type::Complex:
case Type::VariableArray:
case Type::FunctionNoProto:
case Type::Record:
case Type::Enum:
- case Type::Typename:
case Type::ObjCInterface:
- case Type::ObjCQualifiedInterface:
case Type::ObjCObjectPointer:
#define TYPE(Class, Base)
#define ABSTRACT_TYPE(Class, Base)
@@ -1277,32 +2253,39 @@ MarkDeducedTemplateParameters(Sema &SemaRef, QualType T,
}
}
-/// \brief Mark the template parameters that are deduced by this
+/// \brief Mark the template parameters that are used by this
/// template argument.
-static void
-MarkDeducedTemplateParameters(Sema &SemaRef,
- const TemplateArgument &TemplateArg,
- llvm::SmallVectorImpl<bool> &Deduced) {
+static void
+MarkUsedTemplateParameters(Sema &SemaRef,
+ const TemplateArgument &TemplateArg,
+ bool OnlyDeduced,
+ llvm::SmallVectorImpl<bool> &Used) {
switch (TemplateArg.getKind()) {
case TemplateArgument::Null:
case TemplateArgument::Integral:
break;
-
+
case TemplateArgument::Type:
- MarkDeducedTemplateParameters(SemaRef, TemplateArg.getAsType(), Deduced);
+ MarkUsedTemplateParameters(SemaRef, TemplateArg.getAsType(), OnlyDeduced,
+ Used);
break;
case TemplateArgument::Declaration:
- if (TemplateTemplateParmDecl *TTP
+ if (TemplateTemplateParmDecl *TTP
= dyn_cast<TemplateTemplateParmDecl>(TemplateArg.getAsDecl()))
- Deduced[TTP->getIndex()] = true;
+ Used[TTP->getIndex()] = true;
break;
case TemplateArgument::Expression:
- MarkDeducedTemplateParameters(TemplateArg.getAsExpr(), Deduced);
+ MarkUsedTemplateParameters(SemaRef, TemplateArg.getAsExpr(), OnlyDeduced,
+ Used);
break;
+
case TemplateArgument::Pack:
- assert(0 && "FIXME: Implement!");
+ for (TemplateArgument::pack_iterator P = TemplateArg.pack_begin(),
+ PEnd = TemplateArg.pack_end();
+ P != PEnd; ++P)
+ MarkUsedTemplateParameters(SemaRef, *P, OnlyDeduced, Used);
break;
}
}
@@ -1316,9 +2299,25 @@ MarkDeducedTemplateParameters(Sema &SemaRef,
/// \param Deduced a bit vector whose elements will be set to \c true
/// to indicate when the corresponding template parameter will be
/// deduced.
-void
-Sema::MarkDeducedTemplateParameters(const TemplateArgumentList &TemplateArgs,
- llvm::SmallVectorImpl<bool> &Deduced) {
+void
+Sema::MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs,
+ bool OnlyDeduced,
+ llvm::SmallVectorImpl<bool> &Used) {
for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
- ::MarkDeducedTemplateParameters(*this, TemplateArgs[I], Deduced);
+ ::MarkUsedTemplateParameters(*this, TemplateArgs[I], OnlyDeduced, Used);
+}
+
+/// \brief Marks all of the template parameters that will be deduced by a
+/// call to the given function template.
+void Sema::MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate,
+ llvm::SmallVectorImpl<bool> &Deduced) {
+ TemplateParameterList *TemplateParams
+ = FunctionTemplate->getTemplateParameters();
+ Deduced.clear();
+ Deduced.resize(TemplateParams->size());
+
+ FunctionDecl *Function = FunctionTemplate->getTemplatedDecl();
+ for (unsigned I = 0, N = Function->getNumParams(); I != N; ++I)
+ ::MarkUsedTemplateParameters(*this, Function->getParamDecl(I)->getType(),
+ true, Deduced);
}
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 6c2dc77..65260c8 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===/
#include "Sema.h"
+#include "TreeTransform.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
@@ -25,32 +26,65 @@ using namespace clang;
// Template Instantiation Support
//===----------------------------------------------------------------------===/
-/// \brief Retrieve the template argument list that should be used to
-/// instantiate the given declaration.
-const TemplateArgumentList &
+/// \brief Retrieve the template argument list(s) that should be used to
+/// instantiate the definition of the given declaration.
+MultiLevelTemplateArgumentList
Sema::getTemplateInstantiationArgs(NamedDecl *D) {
- // Template arguments for a class template specialization.
- if (ClassTemplateSpecializationDecl *Spec
- = dyn_cast<ClassTemplateSpecializationDecl>(D))
- return Spec->getTemplateArgs();
-
- // Template arguments for a function template specialization.
- if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D))
- if (const TemplateArgumentList *TemplateArgs
- = Function->getTemplateSpecializationArgs())
- return *TemplateArgs;
+ // Accumulate the set of template argument lists in this structure.
+ MultiLevelTemplateArgumentList Result;
+
+ DeclContext *Ctx = dyn_cast<DeclContext>(D);
+ if (!Ctx)
+ Ctx = D->getDeclContext();
+
+ while (!Ctx->isFileContext()) {
+ // Add template arguments from a class template instantiation.
+ if (ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(Ctx)) {
+ // We're done when we hit an explicit specialization.
+ if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization)
+ break;
+
+ Result.addOuterTemplateArguments(&Spec->getTemplateInstantiationArgs());
- // Template arguments for a member of a class template specialization.
- DeclContext *EnclosingTemplateCtx = D->getDeclContext();
- while (!isa<ClassTemplateSpecializationDecl>(EnclosingTemplateCtx)) {
- assert(!EnclosingTemplateCtx->isFileContext() &&
- "Tried to get the instantiation arguments of a non-template");
- EnclosingTemplateCtx = EnclosingTemplateCtx->getParent();
+ // If this class template specialization was instantiated from a
+ // specialized member that is a class template, we're done.
+ assert(Spec->getSpecializedTemplate() && "No class template?");
+ if (Spec->getSpecializedTemplate()->isMemberSpecialization())
+ break;
+ }
+ // Add template arguments from a function template specialization.
+ else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Ctx)) {
+ if (Function->getTemplateSpecializationKind()
+ == TSK_ExplicitSpecialization)
+ break;
+
+ if (const TemplateArgumentList *TemplateArgs
+ = Function->getTemplateSpecializationArgs()) {
+ // Add the template arguments for this specialization.
+ Result.addOuterTemplateArguments(TemplateArgs);
+
+ // If this function was instantiated from a specialized member that is
+ // a function template, we're done.
+ assert(Function->getPrimaryTemplate() && "No function template?");
+ if (Function->getPrimaryTemplate()->isMemberSpecialization())
+ break;
+ }
+
+ // If this is a friend declaration and it declares an entity at
+ // namespace scope, take arguments from its lexical parent
+ // instead of its semantic parent.
+ if (Function->getFriendObjectKind() &&
+ Function->getDeclContext()->isFileContext()) {
+ Ctx = Function->getLexicalDeclContext();
+ continue;
+ }
+ }
+
+ Ctx = Ctx->getParent();
}
- ClassTemplateSpecializationDecl *EnclosingTemplate
- = cast<ClassTemplateSpecializationDecl>(EnclosingTemplateCtx);
- return EnclosingTemplate->getTemplateArgs();
+ return Result;
}
Sema::InstantiatingTemplate::
@@ -74,7 +108,7 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
}
}
-Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
+Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
SourceLocation PointOfInstantiation,
TemplateDecl *Template,
const TemplateArgument *TemplateArgs,
@@ -86,7 +120,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
InstantiationRange);
if (!Invalid) {
ActiveTemplateInstantiation Inst;
- Inst.Kind
+ Inst.Kind
= ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation;
Inst.PointOfInstantiation = PointOfInstantiation;
Inst.Entity = reinterpret_cast<uintptr_t>(Template);
@@ -98,7 +132,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
}
}
-Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
+Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
SourceLocation PointOfInstantiation,
FunctionTemplateDecl *FunctionTemplate,
const TemplateArgument *TemplateArgs,
@@ -106,7 +140,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
ActiveTemplateInstantiation::InstantiationKind Kind,
SourceRange InstantiationRange)
: SemaRef(SemaRef) {
-
+
Invalid = CheckInstantiationDepth(PointOfInstantiation,
InstantiationRange);
if (!Invalid) {
@@ -122,7 +156,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
}
}
-Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
+Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
SourceLocation PointOfInstantiation,
ClassTemplatePartialSpecializationDecl *PartialSpec,
const TemplateArgument *TemplateArgs,
@@ -134,7 +168,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
InstantiationRange);
if (!Invalid) {
ActiveTemplateInstantiation Inst;
- Inst.Kind
+ Inst.Kind
= ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution;
Inst.PointOfInstantiation = PointOfInstantiation;
Inst.Entity = reinterpret_cast<uintptr_t>(PartialSpec);
@@ -146,6 +180,30 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
}
}
+Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
+ SourceLocation PointOfInstantation,
+ ParmVarDecl *Param,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ SourceRange InstantiationRange)
+ : SemaRef(SemaRef) {
+
+ Invalid = CheckInstantiationDepth(PointOfInstantation, InstantiationRange);
+
+ if (!Invalid) {
+ ActiveTemplateInstantiation Inst;
+ Inst.Kind
+ = ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation;
+ Inst.PointOfInstantiation = PointOfInstantation;
+ Inst.Entity = reinterpret_cast<uintptr_t>(Param);
+ 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();
@@ -156,11 +214,11 @@ void Sema::InstantiatingTemplate::Clear() {
bool Sema::InstantiatingTemplate::CheckInstantiationDepth(
SourceLocation PointOfInstantiation,
SourceRange InstantiationRange) {
- if (SemaRef.ActiveTemplateInstantiations.size()
+ if (SemaRef.ActiveTemplateInstantiations.size()
<= SemaRef.getLangOptions().InstantiationDepth)
return false;
- SemaRef.Diag(PointOfInstantiation,
+ SemaRef.Diag(PointOfInstantiation,
diag::err_template_recursion_depth_exceeded)
<< SemaRef.getLangOptions().InstantiationDepth
<< InstantiationRange;
@@ -185,21 +243,25 @@ void Sema::PrintInstantiationStack() {
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),
+ Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
DiagID)
<< Context.getTypeDeclType(Record)
<< Active->InstantiationRange;
- } else {
- FunctionDecl *Function = cast<FunctionDecl>(D);
+ } else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
unsigned DiagID;
if (Function->getPrimaryTemplate())
DiagID = diag::note_function_template_spec_here;
else
DiagID = diag::note_template_member_function_here;
- Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
+ Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
DiagID)
<< Function
<< Active->InstantiationRange;
+ } else {
+ Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
+ diag::note_template_static_data_member_def_here)
+ << cast<VarDecl>(D)
+ << Active->InstantiationRange;
}
break;
}
@@ -208,7 +270,7 @@ void Sema::PrintInstantiationStack() {
TemplateDecl *Template = cast<TemplateDecl>((Decl *)Active->Entity);
std::string TemplateArgsStr
= TemplateSpecializationType::PrintTemplateArgumentList(
- Active->TemplateArgs,
+ Active->TemplateArgs,
Active->NumTemplateArgs,
Context.PrintingPolicy);
Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
@@ -219,14 +281,14 @@ void Sema::PrintInstantiationStack() {
}
case ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution: {
- FunctionTemplateDecl *FnTmpl
+ FunctionTemplateDecl *FnTmpl
= cast<FunctionTemplateDecl>((Decl *)Active->Entity);
Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
diag::note_explicit_template_arg_substitution_here)
<< FnTmpl << Active->InstantiationRange;
break;
}
-
+
case ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution:
if (ClassTemplatePartialSpecializationDecl *PartialSpec
= dyn_cast<ClassTemplatePartialSpecializationDecl>(
@@ -244,6 +306,22 @@ void Sema::PrintInstantiationStack() {
}
break;
+ case ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation: {
+ ParmVarDecl *Param = cast<ParmVarDecl>((Decl *)Active->Entity);
+ FunctionDecl *FD = cast<FunctionDecl>(Param->getDeclContext());
+
+ std::string TemplateArgsStr
+ = TemplateSpecializationType::PrintTemplateArgumentList(
+ Active->TemplateArgs,
+ Active->NumTemplateArgs,
+ Context.PrintingPolicy);
+ Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
+ diag::note_default_function_arg_instantiation_here)
+ << (FD->getNameAsString() + TemplateArgsStr)
+ << Active->InstantiationRange;
+ break;
+ }
+
}
}
}
@@ -258,14 +336,16 @@ bool Sema::isSFINAEContext() const {
switch(Active->Kind) {
case ActiveTemplateInstantiation::TemplateInstantiation:
+ case ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation:
+
// This is a template instantiation, so there is no SFINAE.
return false;
-
+
case ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation:
// A default template argument instantiation may or may not be a
// SFINAE context; look further up the stack.
break;
-
+
case ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution:
case ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution:
// We're either substitution explicitly-specified template arguments
@@ -281,482 +361,274 @@ bool Sema::isSFINAEContext() const {
// Template Instantiation for Types
//===----------------------------------------------------------------------===/
namespace {
- class VISIBILITY_HIDDEN TemplateTypeInstantiator {
- Sema &SemaRef;
- const TemplateArgumentList &TemplateArgs;
+ class VISIBILITY_HIDDEN TemplateInstantiator
+ : public TreeTransform<TemplateInstantiator> {
+ const MultiLevelTemplateArgumentList &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) const;
-#define ABSTRACT_TYPE(Class, Base)
-#include "clang/AST/TypeNodes.def"
- };
-}
-
-QualType
-TemplateTypeInstantiator::InstantiateExtQualType(const ExtQualType *T) const {
- // FIXME: Implement this
- assert(false && "Cannot instantiate ExtQualType yet");
- return QualType();
-}
-
-QualType
-TemplateTypeInstantiator::InstantiateBuiltinType(const BuiltinType *T) const {
- assert(false && "Builtin types are not dependent and cannot be instantiated");
- return QualType(T, 0);
-}
-
-QualType
-TemplateTypeInstantiator::
-InstantiateFixedWidthIntType(const FixedWidthIntType *T) const {
- // FIXME: Implement this
- assert(false && "Cannot instantiate FixedWidthIntType yet");
- return QualType();
-}
-
-QualType
-TemplateTypeInstantiator::InstantiateComplexType(const ComplexType *T) const {
- // FIXME: Implement this
- assert(false && "Cannot instantiate ComplexType yet");
- return QualType();
-}
-
-QualType
-TemplateTypeInstantiator::InstantiatePointerType(const PointerType *T) const {
- QualType PointeeType = Instantiate(T->getPointeeType());
- if (PointeeType.isNull())
- return QualType();
-
- return SemaRef.BuildPointerType(PointeeType, 0, Loc, Entity);
-}
+ typedef TreeTransform<TemplateInstantiator> inherited;
+
+ TemplateInstantiator(Sema &SemaRef,
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ SourceLocation Loc,
+ DeclarationName Entity)
+ : inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc),
+ Entity(Entity) { }
+
+ /// \brief Determine whether the given type \p T has already been
+ /// transformed.
+ ///
+ /// For the purposes of template instantiation, a type has already been
+ /// transformed if it is NULL or if it is not dependent.
+ bool AlreadyTransformed(QualType T) {
+ return T.isNull() || !T->isDependentType();
+ }
-QualType
-TemplateTypeInstantiator::InstantiateBlockPointerType(
- const BlockPointerType *T) const {
- QualType PointeeType = Instantiate(T->getPointeeType());
- if (PointeeType.isNull())
- return QualType();
-
- return SemaRef.BuildBlockPointerType(PointeeType, 0, Loc, Entity);
-}
+ /// \brief Returns the location of the entity being instantiated, if known.
+ SourceLocation getBaseLocation() { return Loc; }
-QualType
-TemplateTypeInstantiator::InstantiateLValueReferenceType(
- const LValueReferenceType *T) const {
- QualType ReferentType = Instantiate(T->getPointeeType());
- if (ReferentType.isNull())
- return QualType();
+ /// \brief Returns the name of the entity being instantiated, if any.
+ DeclarationName getBaseEntity() { return Entity; }
- return SemaRef.BuildReferenceType(ReferentType, true, 0, Loc, Entity);
-}
+ /// \brief Transform the given declaration by instantiating a reference to
+ /// this declaration.
+ Decl *TransformDecl(Decl *D);
-QualType
-TemplateTypeInstantiator::InstantiateRValueReferenceType(
- const RValueReferenceType *T) const {
- QualType ReferentType = Instantiate(T->getPointeeType());
- if (ReferentType.isNull())
- return QualType();
+ /// \brief Transform the definition of the given declaration by
+ /// instantiating it.
+ Decl *TransformDefinition(Decl *D);
- return SemaRef.BuildReferenceType(ReferentType, false, 0, Loc, Entity);
-}
+ /// \brief Rebuild the exception declaration and register the declaration
+ /// as an instantiated local.
+ VarDecl *RebuildExceptionDecl(VarDecl *ExceptionDecl, QualType T,
+ DeclaratorInfo *Declarator,
+ IdentifierInfo *Name,
+ SourceLocation Loc, SourceRange TypeRange);
-QualType
-TemplateTypeInstantiator::
-InstantiateMemberPointerType(const MemberPointerType *T) const {
- QualType PointeeType = Instantiate(T->getPointeeType());
- if (PointeeType.isNull())
- return QualType();
+ /// \brief Check for tag mismatches when instantiating an
+ /// elaborated type.
+ QualType RebuildElaboratedType(QualType T, ElaboratedType::TagKind Tag);
- QualType ClassType = Instantiate(QualType(T->getClass(), 0));
- if (ClassType.isNull())
- return QualType();
+ Sema::OwningExprResult TransformPredefinedExpr(PredefinedExpr *E);
+ Sema::OwningExprResult TransformDeclRefExpr(DeclRefExpr *E);
- return SemaRef.BuildMemberPointerType(PointeeType, ClassType, 0, Loc,
- Entity);
-}
-
-QualType
-TemplateTypeInstantiator::
-InstantiateConstantArrayType(const ConstantArrayType *T) 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
+ /// \brief Transforms a template type parameter type by performing
+ /// substitution of the corresponding template type argument.
+ QualType TransformTemplateTypeParmType(const TemplateTypeParmType *T);
};
- 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) const {
- QualType ElementType = Instantiate(T->getElementType());
- if (ElementType.isNull())
- return ElementType;
-
- return SemaRef.BuildArrayType(ElementType, T->getSizeModifier(),
- 0, T->getIndexTypeQualifier(),
- Loc, Entity);
-}
+Decl *TemplateInstantiator::TransformDecl(Decl *D) {
+ if (!D)
+ return 0;
-QualType
-TemplateTypeInstantiator::
-InstantiateVariableArrayType(const VariableArrayType *T) const {
- // FIXME: Implement this
- assert(false && "Cannot instantiate VariableArrayType yet");
- return QualType();
-}
+ if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(D)) {
+ if (TTP->getDepth() < TemplateArgs.getNumLevels()) {
+ assert(TemplateArgs(TTP->getDepth(), TTP->getPosition()).getAsDecl() &&
+ "Wrong kind of template template argument");
+ return cast<TemplateDecl>(TemplateArgs(TTP->getDepth(),
+ TTP->getPosition()).getAsDecl());
+ }
-QualType
-TemplateTypeInstantiator::
-InstantiateDependentSizedArrayType(const DependentSizedArrayType *T) 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
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
- 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);
-}
+ // If the corresponding template argument is NULL or non-existent, it's
+ // because we are performing instantiation from explicitly-specified
+ // template arguments in a function template, but there were some
+ // arguments left unspecified.
+ if (!TemplateArgs.hasTemplateArgument(TTP->getDepth(),
+ TTP->getPosition()))
+ return D;
-QualType
-TemplateTypeInstantiator::
-InstantiateDependentSizedExtVectorType(
- const DependentSizedExtVectorType *T) const {
-
- // Instantiate the element type if needed.
- QualType ElementType = T->getElementType();
- if (ElementType->isDependentType()) {
- ElementType = Instantiate(ElementType);
- if (ElementType.isNull())
- return QualType();
+ // FIXME: Implement depth reduction of template template parameters
+ assert(false &&
+ "Reducing depth of template template parameters is not yet implemented");
}
- // The expression in a dependent-sized extended vector type is not
- // potentially evaluated.
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
-
- // Instantiate the size expression.
- const Expr *SizeExpr = T->getSizeExpr();
- Sema::OwningExprResult InstantiatedArraySize =
- SemaRef.InstantiateExpr(const_cast<Expr *>(SizeExpr), TemplateArgs);
- if (InstantiatedArraySize.isInvalid())
- return QualType();
-
- return SemaRef.BuildExtVectorType(ElementType,
- SemaRef.Owned(
- InstantiatedArraySize.takeAs<Expr>()),
- T->getAttributeLoc());
+ return SemaRef.FindInstantiatedDecl(cast<NamedDecl>(D), TemplateArgs);
}
-QualType
-TemplateTypeInstantiator::InstantiateVectorType(const VectorType *T) const {
- // FIXME: Implement this
- assert(false && "Cannot instantiate VectorType yet");
- return QualType();
-}
-
-QualType
-TemplateTypeInstantiator::InstantiateExtVectorType(
- const ExtVectorType *T) const {
- // FIXME: Implement this
- assert(false && "Cannot instantiate ExtVectorType yet");
- return QualType();
-}
-
-QualType
-TemplateTypeInstantiator::
-InstantiateFunctionProtoType(const FunctionProtoType *T) 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.data(),
- ParamTypes.size(),
- T->isVariadic(), T->getTypeQuals(),
- Loc, Entity);
-}
+Decl *TemplateInstantiator::TransformDefinition(Decl *D) {
+ Decl *Inst = getSema().SubstDecl(D, getSema().CurContext, TemplateArgs);
+ if (!Inst)
+ return 0;
-QualType
-TemplateTypeInstantiator::
-InstantiateFunctionNoProtoType(const FunctionNoProtoType *T) const {
- assert(false && "Functions without prototypes cannot be dependent.");
- return QualType();
+ getSema().CurrentInstantiationScope->InstantiatedLocal(D, Inst);
+ return Inst;
}
-QualType
-TemplateTypeInstantiator::InstantiateTypedefType(const TypedefType *T) const {
- TypedefDecl *Typedef
- = cast_or_null<TypedefDecl>(
- SemaRef.InstantiateCurrentDeclRef(T->getDecl()));
- if (!Typedef)
- return QualType();
-
- return SemaRef.Context.getTypeDeclType(Typedef);
+VarDecl *
+TemplateInstantiator::RebuildExceptionDecl(VarDecl *ExceptionDecl,
+ QualType T,
+ DeclaratorInfo *Declarator,
+ IdentifierInfo *Name,
+ SourceLocation Loc,
+ SourceRange TypeRange) {
+ VarDecl *Var = inherited::RebuildExceptionDecl(ExceptionDecl, T, Declarator,
+ Name, Loc, TypeRange);
+ if (Var && !Var->isInvalidDecl())
+ getSema().CurrentInstantiationScope->InstantiatedLocal(ExceptionDecl, Var);
+ return Var;
}
-QualType
-TemplateTypeInstantiator::InstantiateTypeOfExprType(
- const TypeOfExprType *T) const {
- // The expression in a typeof is not potentially evaluated.
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
-
- Sema::OwningExprResult E
- = SemaRef.InstantiateExpr(T->getUnderlyingExpr(), TemplateArgs);
- if (E.isInvalid())
- return QualType();
+QualType
+TemplateInstantiator::RebuildElaboratedType(QualType T,
+ ElaboratedType::TagKind Tag) {
+ if (const TagType *TT = T->getAs<TagType>()) {
+ TagDecl* TD = TT->getDecl();
+
+ // FIXME: this location is very wrong; we really need typelocs.
+ SourceLocation TagLocation = TD->getTagKeywordLoc();
+
+ // FIXME: type might be anonymous.
+ IdentifierInfo *Id = TD->getIdentifier();
+
+ // TODO: should we even warn on struct/class mismatches for this? Seems
+ // like it's likely to produce a lot of spurious errors.
+ if (!SemaRef.isAcceptableTagRedeclaration(TD, Tag, TagLocation, *Id)) {
+ SemaRef.Diag(TagLocation, diag::err_use_with_wrong_tag)
+ << Id
+ << CodeModificationHint::CreateReplacement(SourceRange(TagLocation),
+ TD->getKindName());
+ SemaRef.Diag(TD->getLocation(), diag::note_previous_use);
+ }
+ }
- return SemaRef.BuildTypeofExprType(E.takeAs<Expr>());
+ return TreeTransform<TemplateInstantiator>::RebuildElaboratedType(T, Tag);
}
-QualType
-TemplateTypeInstantiator::InstantiateTypeOfType(const TypeOfType *T) const {
- QualType Underlying = Instantiate(T->getUnderlyingType());
- if (Underlying.isNull())
- return QualType();
+Sema::OwningExprResult
+TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E) {
+ if (!E->isTypeDependent())
+ return SemaRef.Owned(E->Retain());
- return SemaRef.Context.getTypeOfType(Underlying);
-}
+ FunctionDecl *currentDecl = getSema().getCurFunctionDecl();
+ assert(currentDecl && "Must have current function declaration when "
+ "instantiating.");
-QualType
-TemplateTypeInstantiator::InstantiateDecltypeType(const DecltypeType *T) const {
- // C++0x [dcl.type.simple]p4:
- // The operand of the decltype specifier is an unevaluated operand.
- EnterExpressionEvaluationContext Unevaluated(SemaRef,
- Action::Unevaluated);
-
- Sema::OwningExprResult E
- = SemaRef.InstantiateExpr(T->getUnderlyingExpr(), TemplateArgs);
+ PredefinedExpr::IdentType IT = E->getIdentType();
- if (E.isInvalid())
- return QualType();
-
- return SemaRef.BuildDecltypeType(E.takeAs<Expr>());
-}
+ unsigned Length =
+ PredefinedExpr::ComputeName(getSema().Context, IT, currentDecl).length();
-QualType
-TemplateTypeInstantiator::InstantiateRecordType(const RecordType *T) const {
- RecordDecl *Record
- = cast_or_null<RecordDecl>(SemaRef.InstantiateCurrentDeclRef(T->getDecl()));
- if (!Record)
- return QualType();
-
- return SemaRef.Context.getTypeDeclType(Record);
+ llvm::APInt LengthI(32, Length + 1);
+ QualType ResTy = getSema().Context.CharTy.withConst();
+ ResTy = getSema().Context.getConstantArrayType(ResTy, LengthI,
+ ArrayType::Normal, 0);
+ PredefinedExpr *PE =
+ new (getSema().Context) PredefinedExpr(E->getLocation(), ResTy, IT);
+ return getSema().Owned(PE);
}
-QualType
-TemplateTypeInstantiator::InstantiateEnumType(const EnumType *T) const {
- EnumDecl *Enum
- = cast_or_null<EnumDecl>(SemaRef.InstantiateCurrentDeclRef(T->getDecl()));
- if (!Enum)
- return QualType();
-
- return SemaRef.Context.getTypeDeclType(Enum);
-}
+Sema::OwningExprResult
+TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) {
+ // FIXME: Clean this up a bit
+ NamedDecl *D = E->getDecl();
+ if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) {
+ if (NTTP->getDepth() >= TemplateArgs.getNumLevels()) {
+ assert(false && "Cannot reduce non-type template parameter depth yet");
+ return getSema().ExprError();
+ }
-QualType
-TemplateTypeInstantiator::
-InstantiateTemplateTypeParmType(const TemplateTypeParmType *T) const {
- if (T->getDepth() == 0) {
- // Replace the template type parameter with its corresponding
- // template argument.
-
- // If the corresponding template argument is NULL or doesn't exist, it's
- // because we are performing instantiation from explicitly-specified
- // template arguments in a function template class, but there were some
+ // If the corresponding template argument is NULL or non-existent, it's
+ // because we are performing instantiation from explicitly-specified
+ // template arguments in a function template, but there were some
// arguments left unspecified.
- if (T->getIndex() >= TemplateArgs.size() ||
- TemplateArgs[T->getIndex()].isNull())
- return QualType(T, 0); // Would be nice to keep the original type here
-
- assert(TemplateArgs[T->getIndex()].getKind() == TemplateArgument::Type &&
- "Template argument kind mismatch");
- return TemplateArgs[T->getIndex()].getAsType();
- }
+ if (!TemplateArgs.hasTemplateArgument(NTTP->getDepth(),
+ NTTP->getPosition()))
+ return SemaRef.Owned(E->Retain());
- // 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->isParameterPack(),
- T->getName());
-}
+ const TemplateArgument &Arg = TemplateArgs(NTTP->getDepth(),
+ NTTP->getPosition());
-QualType
-TemplateTypeInstantiator::
-InstantiateTemplateSpecializationType(
- const TemplateSpecializationType *T) const {
- llvm::SmallVector<TemplateArgument, 4> InstantiatedTemplateArgs;
- InstantiatedTemplateArgs.reserve(T->getNumArgs());
- for (TemplateSpecializationType::iterator Arg = T->begin(), ArgEnd = T->end();
- Arg != ArgEnd; ++Arg) {
- TemplateArgument InstArg = SemaRef.Instantiate(*Arg, TemplateArgs);
- if (InstArg.isNull())
- return QualType();
-
- InstantiatedTemplateArgs.push_back(InstArg);
- }
+ // The template argument itself might be an expression, in which
+ // case we just return that expression.
+ if (Arg.getKind() == TemplateArgument::Expression)
+ return SemaRef.Owned(Arg.getAsExpr()->Retain());
- // FIXME: We're missing the locations of the template name, '<', and '>'.
+ if (Arg.getKind() == TemplateArgument::Declaration) {
+ ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl());
- TemplateName Name = SemaRef.InstantiateTemplateName(T->getTemplateName(),
- Loc,
- TemplateArgs);
+ VD = cast_or_null<ValueDecl>(
+ getSema().FindInstantiatedDecl(VD, TemplateArgs));
+ if (!VD)
+ return SemaRef.ExprError();
- return SemaRef.CheckTemplateIdType(Name, Loc, SourceLocation(),
- InstantiatedTemplateArgs.data(),
- InstantiatedTemplateArgs.size(),
- SourceLocation());
-}
-
-QualType
-TemplateTypeInstantiator::
-InstantiateQualifiedNameType(const QualifiedNameType *T) 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());
-}
+ return SemaRef.BuildDeclRefExpr(VD, VD->getType(), E->getLocation(),
+ /*FIXME:*/false, /*FIXME:*/false);
+ }
-QualType
-TemplateTypeInstantiator::
-InstantiateTypenameType(const TypenameType *T) 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);
+ assert(Arg.getKind() == TemplateArgument::Integral);
+ 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()));
+ if (T->isBooleanType())
+ return SemaRef.Owned(new (SemaRef.Context) CXXBoolLiteralExpr(
+ Arg.getAsIntegral()->getBoolValue(),
+ T,
+ E->getSourceRange().getBegin()));
+
+ assert(Arg.getAsIntegral()->getBitWidth() == SemaRef.Context.getIntWidth(T));
+ return SemaRef.Owned(new (SemaRef.Context) IntegerLiteral(
+ *Arg.getAsIntegral(),
+ T,
+ E->getSourceRange().getBegin()));
}
- NestedNameSpecifier *NNS
- = SemaRef.InstantiateNestedNameSpecifier(T->getQualifier(),
- SourceRange(Loc),
- TemplateArgs);
- if (!NNS)
- return QualType();
+ NamedDecl *InstD = SemaRef.FindInstantiatedDecl(D, TemplateArgs);
+ if (!InstD)
+ return SemaRef.ExprError();
- return SemaRef.CheckTypenameType(NNS, *T->getIdentifier(), SourceRange(Loc));
-}
+ // If we instantiated an UnresolvedUsingDecl and got back an UsingDecl,
+ // we need to get the underlying decl.
+ // FIXME: Is this correct? Maybe FindInstantiatedDecl should do this?
+ InstD = InstD->getUnderlyingDecl();
-QualType
-TemplateTypeInstantiator::
-InstantiateObjCObjectPointerType(const ObjCObjectPointerType *T) const {
- assert(false && "Objective-C types cannot be dependent");
- return QualType();
+ // FIXME: nested-name-specifier for QualifiedDeclRefExpr
+ return SemaRef.BuildDeclarationNameExpr(E->getLocation(), InstD,
+ /*FIXME:*/false,
+ /*FIXME:*/0,
+ /*FIXME:*/false);
}
QualType
-TemplateTypeInstantiator::
-InstantiateObjCInterfaceType(const ObjCInterfaceType *T) const {
- assert(false && "Objective-C types cannot be dependent");
- return QualType();
-}
+TemplateInstantiator::TransformTemplateTypeParmType(
+ const TemplateTypeParmType *T) {
+ if (T->getDepth() < TemplateArgs.getNumLevels()) {
+ // Replace the template type parameter with its corresponding
+ // template argument.
-QualType
-TemplateTypeInstantiator::
-InstantiateObjCQualifiedInterfaceType(
- const ObjCQualifiedInterfaceType *T) const {
- assert(false && "Objective-C types cannot be dependent");
- return QualType();
-}
+ // If the corresponding template argument is NULL or doesn't exist, it's
+ // because we are performing instantiation from explicitly-specified
+ // template arguments in a function template class, but there were some
+ // arguments left unspecified.
+ if (!TemplateArgs.hasTemplateArgument(T->getDepth(), T->getIndex()))
+ return QualType(T, 0);
-/// \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;
+ assert(TemplateArgs(T->getDepth(), T->getIndex()).getKind()
+ == TemplateArgument::Type &&
+ "Template argument kind mismatch");
- QualType Result;
- switch (T->getTypeClass()) {
-#define TYPE(Class, Base) \
- case Type::Class: \
- Result = Instantiate##Class##Type(cast<Class##Type>(T.getTypePtr())); \
- break;
-#define ABSTRACT_TYPE(Class, Base)
-#include "clang/AST/TypeNodes.def"
+ return TemplateArgs(T->getDepth(), T->getIndex()).getAsType();
}
- // 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.
- //
- // The same rule applies to function types.
- if (!Result.isNull() && T.getCVRQualifiers() &&
- !Result->isFunctionType() && !Result->isReferenceType())
- Result = Result.getWithAdditionalQualifiers(T.getCVRQualifiers());
- return Result;
+ // 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 getSema().Context.getTemplateTypeParmType(
+ T->getDepth() - TemplateArgs.getNumLevels(),
+ T->getIndex(),
+ T->isParameterPack(),
+ T->getName());
}
-/// \brief Instantiate the type T with a given set of template arguments.
+/// \brief Perform substitution on 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.
@@ -782,9 +654,9 @@ QualType TemplateTypeInstantiator::Instantiate(QualType T) const {
///
/// \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) {
+QualType Sema::SubstType(QualType T,
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ SourceLocation Loc, DeclarationName Entity) {
assert(!ActiveTemplateInstantiations.empty() &&
"Cannot perform an instantiation without some context on the "
"instantiation stack");
@@ -793,35 +665,34 @@ QualType Sema::InstantiateType(QualType T,
if (!T->isDependentType())
return T;
- TemplateTypeInstantiator Instantiator(*this, TemplateArgs, Loc, Entity);
- return Instantiator(T);
+ TemplateInstantiator Instantiator(*this, TemplateArgs, Loc, Entity);
+ return Instantiator.TransformType(T);
}
-/// \brief Instantiate the base class specifiers of the given class
-/// template specialization.
+/// \brief Perform substitution on 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
+Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation,
+ CXXRecordDecl *Pattern,
+ const MultiLevelTemplateArgumentList &TemplateArgs) {
bool Invalid = false;
llvm::SmallVector<CXXBaseSpecifier*, 4> InstantiatedBases;
- for (ClassTemplateSpecializationDecl::base_class_iterator
+ 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));
+ InstantiatedBases.push_back(new (Context) CXXBaseSpecifier(*Base));
continue;
}
- QualType BaseType = InstantiateType(Base->getType(),
- TemplateArgs,
- Base->getSourceRange().getBegin(),
- DeclarationName());
+ QualType BaseType = SubstType(Base->getType(),
+ TemplateArgs,
+ Base->getSourceRange().getBegin(),
+ DeclarationName());
if (BaseType.isNull()) {
Invalid = true;
continue;
@@ -864,25 +735,33 @@ Sema::InstantiateBaseSpecifiers(CXXRecordDecl *Instantiation,
/// \param TemplateArgs The template arguments to be substituted into
/// the pattern.
///
+/// \param TSK the kind of implicit or explicit instantiation to perform.
+///
+/// \param Complain whether to complain if the class cannot be instantiated due
+/// to the lack of a definition.
+///
/// \returns true if an error occurred, false otherwise.
bool
Sema::InstantiateClass(SourceLocation PointOfInstantiation,
CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern,
- const TemplateArgumentList &TemplateArgs,
- bool ExplicitInstantiation) {
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ TemplateSpecializationKind TSK,
+ bool Complain) {
bool Invalid = false;
-
- CXXRecordDecl *PatternDef
+
+ CXXRecordDecl *PatternDef
= cast_or_null<CXXRecordDecl>(Pattern->getDefinition(Context));
if (!PatternDef) {
- if (Pattern == Instantiation->getInstantiatedFromMemberClass()) {
+ if (!Complain) {
+ // Say nothing
+ } else 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
+ << (TSK != TSK_ImplicitInstantiation)
<< Context.getTypeDeclType(Instantiation);
Diag(Pattern->getLocation(), diag::note_template_decl_here);
}
@@ -902,20 +781,22 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
// Start the definition of this instantiation.
Instantiation->startDefinition();
- // Instantiate the base class specifiers.
- if (InstantiateBaseSpecifiers(Instantiation, Pattern, TemplateArgs))
+ // Do substitution on the base class specifiers.
+ if (SubstBaseSpecifiers(Instantiation, Pattern, TemplateArgs))
Invalid = true;
llvm::SmallVector<DeclPtrTy, 4> Fields;
for (RecordDecl::decl_iterator Member = Pattern->decls_begin(),
- MemberEnd = Pattern->decls_end();
+ MemberEnd = Pattern->decls_end();
Member != MemberEnd; ++Member) {
- Decl *NewMember = InstantiateDecl(*Member, Instantiation, TemplateArgs);
+ Decl *NewMember = SubstDecl(*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 if (UsingDecl *UD = dyn_cast<UsingDecl>(NewMember))
+ Instantiation->addDecl(UD);
} else {
// FIXME: Eventually, a NULL return will mean that one of the
// instantiations was a semantic disaster, and we'll want to set Invalid =
@@ -938,32 +819,52 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
Consumer.HandleTagDeclDefinition(Instantiation);
// If this is an explicit instantiation, instantiate our members, too.
- if (!Invalid && ExplicitInstantiation) {
+ if (!Invalid && TSK != TSK_ImplicitInstantiation) {
Inst.Clear();
- InstantiateClassMembers(PointOfInstantiation, Instantiation, TemplateArgs);
+ InstantiateClassMembers(PointOfInstantiation, Instantiation, TemplateArgs,
+ TSK);
}
return Invalid;
}
-bool
+bool
Sema::InstantiateClassTemplateSpecialization(
ClassTemplateSpecializationDecl *ClassTemplateSpec,
- bool ExplicitInstantiation) {
+ TemplateSpecializationKind TSK,
+ bool Complain) {
// 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)
+ ClassTemplateSpec->getCanonicalDecl());
+
+ // Check whether we have already instantiated or specialized this class
+ // template specialization.
+ if (ClassTemplateSpec->getSpecializationKind() != TSK_Undeclared) {
+ if (ClassTemplateSpec->getSpecializationKind() ==
+ TSK_ExplicitInstantiationDeclaration &&
+ TSK == TSK_ExplicitInstantiationDefinition) {
+ // An explicit instantiation definition follows an explicit instantiation
+ // declaration (C++0x [temp.explicit]p10); go ahead and perform the
+ // explicit instantiation.
+ ClassTemplateSpec->setSpecializationKind(TSK);
+ InstantiateClassTemplateSpecializationMembers(
+ /*FIXME?*/ClassTemplateSpec->getPointOfInstantiation(),
+ ClassTemplateSpec,
+ TSK);
+ return false;
+ }
+
+ // We can only instantiate something that hasn't already been
+ // instantiated or specialized. Fail without any diagnostics: our
+ // caller will provide an error message.
return true;
+ }
+ if (ClassTemplateSpec->isInvalidDecl())
+ return true;
+
ClassTemplateDecl *Template = ClassTemplateSpec->getSpecializedTemplate();
- CXXRecordDecl *Pattern = Template->getTemplatedDecl();
- const TemplateArgumentList *TemplateArgs
- = &ClassTemplateSpec->getTemplateArgs();
+ CXXRecordDecl *Pattern = 0;
// C++ [temp.class.spec.match]p1:
// When a class template is used in a context that requires an
@@ -976,14 +877,14 @@ Sema::InstantiateClassTemplateSpecialization(
typedef std::pair<ClassTemplatePartialSpecializationDecl *,
TemplateArgumentList *> MatchResult;
llvm::SmallVector<MatchResult, 4> Matched;
- for (llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator
+ for (llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator
Partial = Template->getPartialSpecializations().begin(),
PartialEnd = Template->getPartialSpecializations().end();
Partial != PartialEnd;
++Partial) {
TemplateDeductionInfo Info(Context);
if (TemplateDeductionResult Result
- = DeduceTemplateArguments(&*Partial,
+ = DeduceTemplateArguments(&*Partial,
ClassTemplateSpec->getTemplateArgs(),
Info)) {
// FIXME: Store the failed-deduction information for use in
@@ -998,7 +899,7 @@ Sema::InstantiateClassTemplateSpecialization(
// -- If exactly one matching specialization is found, the
// instantiation is generated from that specialization.
Pattern = Matched[0].first;
- TemplateArgs = Matched[0].second;
+ ClassTemplateSpec->setInstantiationOf(Matched[0].first, Matched[0].second);
} else if (Matched.size() > 1) {
// -- If more than one matching specialization is found, the
// partial order rules (14.5.4.2) are used to determine
@@ -1007,61 +908,137 @@ Sema::InstantiateClassTemplateSpecialization(
// specialized than all of the other matching
// specializations, then the use of the class template is
// ambiguous and the program is ill-formed.
- // FIXME: Implement partial ordering of class template partial
- // specializations.
- Diag(ClassTemplateSpec->getLocation(),
- diag::unsup_template_partial_spec_ordering);
+ llvm::SmallVector<MatchResult, 4>::iterator Best = Matched.begin();
+ for (llvm::SmallVector<MatchResult, 4>::iterator P = Best + 1,
+ PEnd = Matched.end();
+ P != PEnd; ++P) {
+ if (getMoreSpecializedPartialSpecialization(P->first, Best->first)
+ == P->first)
+ Best = P;
+ }
+
+ // Determine if the best partial specialization is more specialized than
+ // the others.
+ bool Ambiguous = false;
+ for (llvm::SmallVector<MatchResult, 4>::iterator P = Matched.begin(),
+ PEnd = Matched.end();
+ P != PEnd; ++P) {
+ if (P != Best &&
+ getMoreSpecializedPartialSpecialization(P->first, Best->first)
+ != Best->first) {
+ Ambiguous = true;
+ break;
+ }
+ }
+
+ if (Ambiguous) {
+ // Partial ordering did not produce a clear winner. Complain.
+ ClassTemplateSpec->setInvalidDecl();
+ Diag(ClassTemplateSpec->getPointOfInstantiation(),
+ diag::err_partial_spec_ordering_ambiguous)
+ << ClassTemplateSpec;
+
+ // Print the matching partial specializations.
+ for (llvm::SmallVector<MatchResult, 4>::iterator P = Matched.begin(),
+ PEnd = Matched.end();
+ P != PEnd; ++P)
+ Diag(P->first->getLocation(), diag::note_partial_spec_match)
+ << getTemplateArgumentBindingsText(P->first->getTemplateParameters(),
+ *P->second);
+
+ return true;
+ }
+
+ // Instantiate using the best class template partial specialization.
+ Pattern = Best->first;
+ ClassTemplateSpec->setInstantiationOf(Best->first, Best->second);
} else {
// -- If no matches are found, the instantiation is generated
// from the primary template.
-
- // Since we initialized the pattern and template arguments from
- // the primary template, there is nothing more we need to do here.
+ ClassTemplateDecl *OrigTemplate = Template;
+ while (OrigTemplate->getInstantiatedFromMemberTemplate()) {
+ // If we've found an explicit specialization of this class template,
+ // stop here and use that as the pattern.
+ if (OrigTemplate->isMemberSpecialization())
+ break;
+
+ OrigTemplate = OrigTemplate->getInstantiatedFromMemberTemplate();
+ }
+
+ Pattern = OrigTemplate->getTemplatedDecl();
}
- // Note that this is an instantiation.
- ClassTemplateSpec->setSpecializationKind(
- ExplicitInstantiation? TSK_ExplicitInstantiation
- : TSK_ImplicitInstantiation);
+ // Note that this is an instantiation.
+ ClassTemplateSpec->setSpecializationKind(TSK);
+
+ bool Result = InstantiateClass(ClassTemplateSpec->getPointOfInstantiation(),
+ ClassTemplateSpec, Pattern,
+ getTemplateInstantiationArgs(ClassTemplateSpec),
+ TSK,
+ Complain);
- bool Result = InstantiateClass(ClassTemplateSpec->getLocation(),
- ClassTemplateSpec, Pattern, *TemplateArgs,
- ExplicitInstantiation);
-
for (unsigned I = 0, N = Matched.size(); I != N; ++I) {
// FIXME: Implement TemplateArgumentList::Destroy!
// if (Matched[I].first != Pattern)
// Matched[I].second->Destroy(Context);
}
-
+
return Result;
}
-/// \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.
+/// \brief Instantiates 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) {
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ TemplateSpecializationKind TSK) {
for (DeclContext::decl_iterator D = Instantiation->decls_begin(),
DEnd = Instantiation->decls_end();
D != DEnd; ++D) {
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(*D)) {
- if (!Function->getBody())
+ if (Function->getInstantiatedFromMemberFunction()) {
+ // If this member was explicitly specialized, do nothing.
+ if (Function->getTemplateSpecializationKind() ==
+ TSK_ExplicitSpecialization)
+ continue;
+
+ Function->setTemplateSpecializationKind(TSK);
+ }
+
+ if (!Function->getBody() && TSK == TSK_ExplicitInstantiationDefinition)
InstantiateFunctionDefinition(PointOfInstantiation, Function);
} else if (VarDecl *Var = dyn_cast<VarDecl>(*D)) {
- const VarDecl *Def = 0;
- if (!Var->getDefinition(Def))
- InstantiateVariableDefinition(Var);
+ if (Var->isStaticDataMember()) {
+ // If this member was explicitly specialized, do nothing.
+ if (Var->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+ continue;
+
+ Var->setTemplateSpecializationKind(TSK);
+
+ if (TSK == TSK_ExplicitInstantiationDefinition)
+ InstantiateStaticDataMemberDefinition(PointOfInstantiation, Var);
+ }
} else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(*D)) {
- if (!Record->isInjectedClassName() && !Record->getDefinition(Context)) {
- assert(Record->getInstantiatedFromMemberClass() &&
- "Missing instantiated-from-template information");
+ if (Record->isInjectedClassName())
+ continue;
+
+ assert(Record->getInstantiatedFromMemberClass() &&
+ "Missing instantiated-from-template information");
+
+ // If this member was explicitly specialized, do nothing.
+ if (Record->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+ continue;
+
+ if (!Record->getDefinition(Context))
InstantiateClass(PointOfInstantiation, Record,
Record->getInstantiatedFromMemberClass(),
- TemplateArgs, true);
- }
+ TemplateArgs,
+ TSK);
+
+ InstantiateClassMembers(PointOfInstantiation, Record, TemplateArgs,
+ TSK);
}
}
}
@@ -1069,9 +1046,11 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
/// \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(
+void
+Sema::InstantiateClassTemplateSpecializationMembers(
SourceLocation PointOfInstantiation,
- ClassTemplateSpecializationDecl *ClassTemplateSpec) {
+ ClassTemplateSpecializationDecl *ClassTemplateSpec,
+ TemplateSpecializationKind TSK) {
// C++0x [temp.explicit]p7:
// An explicit instantiation that names a class template
// specialization is an explicit instantion of the same kind
@@ -1081,172 +1060,53 @@ void Sema::InstantiateClassTemplateSpecializationMembers(
// containing the explicit instantiation, except as described
// below.
InstantiateClassMembers(PointOfInstantiation, ClassTemplateSpec,
- ClassTemplateSpec->getTemplateArgs());
+ getTemplateInstantiationArgs(ClassTemplateSpec),
+ TSK);
}
-/// \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;
- }
+Sema::OwningStmtResult
+Sema::SubstStmt(Stmt *S, const MultiLevelTemplateArgumentList &TemplateArgs) {
+ if (!S)
+ return Owned(S);
- 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;
- }
+ TemplateInstantiator Instantiator(*this, TemplateArgs,
+ SourceLocation(),
+ DeclarationName());
+ return Instantiator.TransformStmt(S);
+}
- 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->isDependentType() || 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());
- }
+Sema::OwningExprResult
+Sema::SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs) {
+ if (!E)
+ return Owned(E);
- Diag(Range.getBegin(), diag::err_nested_name_spec_non_tag) << T;
- return 0;
- }
- }
+ TemplateInstantiator Instantiator(*this, TemplateArgs,
+ SourceLocation(),
+ DeclarationName());
+ return Instantiator.TransformExpr(E);
+}
- // Required to silence a GCC warning
- return 0;
+/// \brief Do template substitution on a nested-name-specifier.
+NestedNameSpecifier *
+Sema::SubstNestedNameSpecifier(NestedNameSpecifier *NNS,
+ SourceRange Range,
+ const MultiLevelTemplateArgumentList &TemplateArgs) {
+ TemplateInstantiator Instantiator(*this, TemplateArgs, Range.getBegin(),
+ DeclarationName());
+ return Instantiator.TransformNestedNameSpecifier(NNS, Range);
}
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;
+Sema::SubstTemplateName(TemplateName Name, SourceLocation Loc,
+ const MultiLevelTemplateArgumentList &TemplateArgs) {
+ TemplateInstantiator Instantiator(*this, TemplateArgs, Loc,
+ DeclarationName());
+ return Instantiator.TransformTemplateName(Name);
}
-TemplateArgument Sema::Instantiate(TemplateArgument Arg,
- const TemplateArgumentList &TemplateArgs) {
- switch (Arg.getKind()) {
- case TemplateArgument::Null:
- assert(false && "Should never have a NULL template argument");
- break;
-
- case TemplateArgument::Type: {
- QualType T = InstantiateType(Arg.getAsType(), TemplateArgs,
- Arg.getLocation(), DeclarationName());
- if (T.isNull())
- return TemplateArgument();
-
- return TemplateArgument(Arg.getLocation(), T);
- }
-
- case TemplateArgument::Declaration:
- // FIXME: Template instantiation for template template parameters.
- return Arg;
-
- case TemplateArgument::Integral:
- return Arg;
-
- case TemplateArgument::Expression: {
- // Template argument expressions are not potentially evaluated.
- EnterExpressionEvaluationContext Unevaluated(*this, Action::Unevaluated);
-
- Sema::OwningExprResult E = InstantiateExpr(Arg.getAsExpr(), TemplateArgs);
- if (E.isInvalid())
- return TemplateArgument();
- return TemplateArgument(E.takeAs<Expr>());
- }
-
- case TemplateArgument::Pack:
- assert(0 && "FIXME: Implement!");
- break;
- }
-
- assert(false && "Unhandled template argument kind");
- return TemplateArgument();
+TemplateArgument Sema::Subst(TemplateArgument Arg,
+ const MultiLevelTemplateArgumentList &TemplateArgs) {
+ TemplateInstantiator Instantiator(*this, TemplateArgs, SourceLocation(),
+ DeclarationName());
+ return Instantiator.TransformTemplateArgument(Arg);
}
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index f597199..33fa288 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -15,24 +15,26 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/Expr.h"
+#include "clang/Basic/PrettyStackTrace.h"
+#include "clang/Lex/Preprocessor.h"
#include "llvm/Support/Compiler.h"
using namespace clang;
namespace {
- class VISIBILITY_HIDDEN TemplateDeclInstantiator
+ class VISIBILITY_HIDDEN TemplateDeclInstantiator
: public DeclVisitor<TemplateDeclInstantiator, Decl *> {
Sema &SemaRef;
DeclContext *Owner;
- const TemplateArgumentList &TemplateArgs;
-
+ const MultiLevelTemplateArgumentList &TemplateArgs;
+
public:
typedef Sema::OwningExprResult OwningExprResult;
TemplateDeclInstantiator(Sema &SemaRef, DeclContext *Owner,
- const TemplateArgumentList &TemplateArgs)
+ const MultiLevelTemplateArgumentList &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.
@@ -44,26 +46,42 @@ namespace {
Decl *VisitStaticAssertDecl(StaticAssertDecl *D);
Decl *VisitEnumDecl(EnumDecl *D);
Decl *VisitEnumConstantDecl(EnumConstantDecl *D);
- Decl *VisitFunctionDecl(FunctionDecl *D);
+ Decl *VisitFriendDecl(FriendDecl *D);
+ Decl *VisitFunctionDecl(FunctionDecl *D,
+ TemplateParameterList *TemplateParams = 0);
Decl *VisitCXXRecordDecl(CXXRecordDecl *D);
- Decl *VisitCXXMethodDecl(CXXMethodDecl *D);
+ Decl *VisitCXXMethodDecl(CXXMethodDecl *D,
+ TemplateParameterList *TemplateParams = 0);
Decl *VisitCXXConstructorDecl(CXXConstructorDecl *D);
Decl *VisitCXXDestructorDecl(CXXDestructorDecl *D);
Decl *VisitCXXConversionDecl(CXXConversionDecl *D);
ParmVarDecl *VisitParmVarDecl(ParmVarDecl *D);
Decl *VisitOriginalParmVarDecl(OriginalParmVarDecl *D);
+ Decl *VisitClassTemplateDecl(ClassTemplateDecl *D);
+ Decl *VisitClassTemplatePartialSpecializationDecl(
+ ClassTemplatePartialSpecializationDecl *D);
+ Decl *VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
+ Decl *VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D);
+ Decl *VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D);
// Base case. FIXME: Remove once we can instantiate everything.
- Decl *VisitDecl(Decl *) {
+ Decl *VisitDecl(Decl *) {
assert(false && "Template instantiation of unknown declaration kind!");
return 0;
}
+ const LangOptions &getLangOptions() {
+ return SemaRef.getLangOptions();
+ }
+
// Helper functions for instantiating methods.
- QualType InstantiateFunctionType(FunctionDecl *D,
+ QualType SubstFunctionType(FunctionDecl *D,
llvm::SmallVectorImpl<ParmVarDecl *> &Params);
bool InitFunctionInstantiation(FunctionDecl *New, FunctionDecl *Tmpl);
bool InitMethodInstantiation(CXXMethodDecl *New, CXXMethodDecl *Tmpl);
+
+ TemplateParameterList *
+ SubstTemplateParams(TemplateParameterList *List);
};
}
@@ -83,14 +101,14 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) {
bool Invalid = false;
QualType T = D->getUnderlyingType();
if (T->isDependentType()) {
- T = SemaRef.InstantiateType(T, TemplateArgs,
- D->getLocation(), D->getDeclName());
+ T = SemaRef.SubstType(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(),
@@ -99,44 +117,86 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) {
Typedef->setInvalidDecl();
Owner->addDecl(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());
+ // Do substitution on the type of the declaration
+ QualType T = SemaRef.SubstType(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());
+ T, D->getDeclaratorInfo(),
+ D->getStorageClass());
Var->setThreadSpecified(D->isThreadSpecified());
Var->setCXXDirectInitializer(D->hasCXXDirectInitializer());
Var->setDeclaredInCondition(D->isDeclaredInCondition());
-
+
+ // If we are instantiating a static data member defined
+ // out-of-line, the instantiation will have the same lexical
+ // context (which will be a namespace scope) as the template.
+ if (D->isOutOfLine())
+ Var->setLexicalDeclContext(D->getLexicalDeclContext());
+
// 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(Var);
+ if (D->isOutOfLine()) {
+ D->getLexicalDeclContext()->addDecl(Var);
+ Owner->makeDeclVisibleInContext(Var);
+ } else {
+ Owner->addDecl(Var);
+ }
+
+ // Link instantiations of static data members back to the template from
+ // which they were instantiated.
+ if (Var->isStaticDataMember())
+ SemaRef.Context.setInstantiatedFromStaticDataMember(Var, D,
+ TSK_ImplicitInstantiation);
+
if (D->getInit()) {
- OwningExprResult Init
- = SemaRef.InstantiateExpr(D->getInit(), TemplateArgs);
+ OwningExprResult Init
+ = SemaRef.SubstExpr(D->getInit(), TemplateArgs);
if (Init.isInvalid())
Var->setInvalidDecl();
- else
+ else if (ParenListExpr *PLE = dyn_cast<ParenListExpr>((Expr *)Init.get())) {
+ // FIXME: We're faking all of the comma locations, which is suboptimal.
+ // Do we even need these comma locations?
+ llvm::SmallVector<SourceLocation, 4> FakeCommaLocs;
+ if (PLE->getNumExprs() > 0) {
+ FakeCommaLocs.reserve(PLE->getNumExprs() - 1);
+ for (unsigned I = 0, N = PLE->getNumExprs() - 1; I != N; ++I) {
+ Expr *E = PLE->getExpr(I)->Retain();
+ FakeCommaLocs.push_back(
+ SemaRef.PP.getLocForEndOfToken(E->getLocEnd()));
+ }
+ PLE->getExpr(PLE->getNumExprs() - 1)->Retain();
+ }
+
+ // Add the direct initializer to the declaration.
+ SemaRef.AddCXXDirectInitializerToDecl(Sema::DeclPtrTy::make(Var),
+ PLE->getLParenLoc(),
+ Sema::MultiExprArg(SemaRef,
+ (void**)PLE->getExprs(),
+ PLE->getNumExprs()),
+ FakeCommaLocs.data(),
+ PLE->getRParenLoc());
+
+ // When Init is destroyed, it will destroy the instantiated ParenListExpr;
+ // we've explicitly retained all of its subexpressions already.
+ } else
SemaRef.AddInitializerToDecl(Sema::DeclPtrTy::make(Var), move(Init),
D->hasCXXDirectInitializer());
- } else {
- // FIXME: Call ActOnUninitializedDecl? (Not always)
- }
+ } else if (!Var->isStaticDataMember() || Var->isOutOfLine())
+ SemaRef.ActOnUninitializedDecl(Sema::DeclPtrTy::make(Var), false);
return Var;
}
@@ -145,8 +205,8 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
bool Invalid = false;
QualType T = D->getType();
if (T->isDependentType()) {
- T = SemaRef.InstantiateType(T, TemplateArgs,
- D->getLocation(), D->getDeclName());
+ T = SemaRef.SubstType(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
@@ -167,9 +227,9 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
else if (BitWidth) {
// The bit-width expression is not potentially evaluated.
EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
-
+
OwningExprResult InstantiatedBitWidth
- = SemaRef.InstantiateExpr(BitWidth, TemplateArgs);
+ = SemaRef.SubstExpr(BitWidth, TemplateArgs);
if (InstantiatedBitWidth.isInvalid()) {
Invalid = true;
BitWidth = 0;
@@ -178,44 +238,90 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
}
FieldDecl *Field = SemaRef.CheckFieldDecl(D->getDeclName(), T,
- cast<RecordDecl>(Owner),
+ D->getDeclaratorInfo(),
+ cast<RecordDecl>(Owner),
D->getLocation(),
D->isMutable(),
BitWidth,
+ D->getTypeSpecStartLoc(),
D->getAccess(),
0);
- if (Field) {
- if (Invalid)
- Field->setInvalidDecl();
-
- Owner->addDecl(Field);
+ if (!Field)
+ return 0;
+
+ if (Invalid)
+ Field->setInvalidDecl();
+
+ if (!Field->getDeclName()) {
+ // Keep track of where this decl came from.
+ SemaRef.Context.setInstantiatedFromUnnamedFieldDecl(Field, D);
}
+ Field->setImplicit(D->isImplicit());
+ Owner->addDecl(Field);
+
return Field;
}
+Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
+ FriendDecl::FriendUnion FU;
+
+ // Handle friend type expressions by simply substituting template
+ // parameters into the pattern type.
+ if (Type *Ty = D->getFriendType()) {
+ QualType T = SemaRef.SubstType(QualType(Ty,0), TemplateArgs,
+ D->getLocation(), DeclarationName());
+ if (T.isNull()) return 0;
+
+ assert(getLangOptions().CPlusPlus0x || T->isRecordType());
+ FU = T.getTypePtr();
+
+ // Handle everything else by appropriate substitution.
+ } else {
+ NamedDecl *ND = D->getFriendDecl();
+ assert(ND && "friend decl must be a decl or a type!");
+
+ // FIXME: We have a problem here, because the nested call to Visit(ND)
+ // will inject the thing that the friend references into the current
+ // owner, which is wrong.
+ Decl *NewND = Visit(ND);
+ if (!NewND) return 0;
+
+ FU = cast<NamedDecl>(NewND);
+ }
+
+ FriendDecl *FD =
+ FriendDecl::Create(SemaRef.Context, Owner, D->getLocation(), FU,
+ D->getFriendLoc());
+ FD->setAccess(AS_public);
+ Owner->addDecl(FD);
+ return FD;
+}
+
Decl *TemplateDeclInstantiator::VisitStaticAssertDecl(StaticAssertDecl *D) {
Expr *AssertExpr = D->getAssertExpr();
-
+
// The expression in a static assertion is not potentially evaluated.
EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
-
+
OwningExprResult InstantiatedAssertExpr
- = SemaRef.InstantiateExpr(AssertExpr, TemplateArgs);
+ = SemaRef.SubstExpr(AssertExpr, TemplateArgs);
if (InstantiatedAssertExpr.isInvalid())
return 0;
- OwningExprResult Message = SemaRef.Clone(D->getMessage());
- Decl *StaticAssert
- = SemaRef.ActOnStaticAssertDeclaration(D->getLocation(),
+ OwningExprResult Message(SemaRef, D->getMessage());
+ D->getMessage()->Retain();
+ 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,
+ EnumDecl *Enum = EnumDecl::Create(SemaRef.Context, Owner,
D->getLocation(), D->getIdentifier(),
+ D->getTagKeywordLoc(),
/*PrevDecl=*/0);
Enum->setInstantiationOfMemberEnum(D);
Enum->setAccess(D->getAccess());
@@ -232,10 +338,10 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
OwningExprResult Value = SemaRef.Owned((Expr *)0);
if (Expr *UninstValue = EC->getInitExpr()) {
// The enumerator's value expression is not potentially evaluated.
- EnterExpressionEvaluationContext Unevaluated(SemaRef,
+ EnterExpressionEvaluationContext Unevaluated(SemaRef,
Action::Unevaluated);
-
- Value = SemaRef.InstantiateExpr(UninstValue, TemplateArgs);
+
+ Value = SemaRef.SubstExpr(UninstValue, TemplateArgs);
}
// Drop the initial value and continue.
@@ -245,7 +351,7 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
isInvalid = true;
}
- EnumConstantDecl *EnumConst
+ EnumConstantDecl *EnumConst
= SemaRef.CheckEnumConstant(Enum, LastEnumConst,
EC->getLocation(), EC->getIdentifier(),
move(Value));
@@ -262,11 +368,13 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
LastEnumConst = EnumConst;
}
}
-
+
// FIXME: Fixup LBraceLoc and RBraceLoc
+ // FIXME: Empty Scope and AttributeList (required to handle attribute packed).
SemaRef.ActOnEnumBody(Enum->getLocation(), SourceLocation(), SourceLocation(),
Sema::DeclPtrTy::make(Enum),
- &Enumerators[0], Enumerators.size());
+ &Enumerators[0], Enumerators.size(),
+ 0, 0);
return Enum;
}
@@ -276,100 +384,337 @@ Decl *TemplateDeclInstantiator::VisitEnumConstantDecl(EnumConstantDecl *D) {
return 0;
}
+Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
+ TemplateParameterList *TempParams = D->getTemplateParameters();
+ TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
+ if (!InstParams)
+ return NULL;
+
+ CXXRecordDecl *Pattern = D->getTemplatedDecl();
+ CXXRecordDecl *RecordInst
+ = CXXRecordDecl::Create(SemaRef.Context, Pattern->getTagKind(), Owner,
+ Pattern->getLocation(), Pattern->getIdentifier(),
+ Pattern->getTagKeywordLoc(), /*PrevDecl=*/ NULL,
+ /*DelayTypeCreation=*/true);
+
+ ClassTemplateDecl *Inst
+ = ClassTemplateDecl::Create(SemaRef.Context, Owner, D->getLocation(),
+ D->getIdentifier(), InstParams, RecordInst, 0);
+ RecordInst->setDescribedClassTemplate(Inst);
+ Inst->setAccess(D->getAccess());
+ Inst->setInstantiatedFromMemberTemplate(D);
+
+ // Trigger creation of the type for the instantiation.
+ SemaRef.Context.getTypeDeclType(RecordInst);
+
+ Owner->addDecl(Inst);
+ return Inst;
+}
+
+Decl *
+TemplateDeclInstantiator::VisitClassTemplatePartialSpecializationDecl(
+ ClassTemplatePartialSpecializationDecl *D) {
+ assert(false &&"Partial specializations of member templates are unsupported");
+ return 0;
+}
+
+Decl *
+TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
+ // FIXME: Dig out the out-of-line definition of this function template?
+
+ TemplateParameterList *TempParams = D->getTemplateParameters();
+ TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
+ if (!InstParams)
+ return NULL;
+
+ FunctionDecl *Instantiated = 0;
+ if (CXXMethodDecl *DMethod = dyn_cast<CXXMethodDecl>(D->getTemplatedDecl()))
+ Instantiated = cast_or_null<FunctionDecl>(VisitCXXMethodDecl(DMethod,
+ InstParams));
+ else
+ Instantiated = cast_or_null<FunctionDecl>(VisitFunctionDecl(
+ D->getTemplatedDecl(),
+ InstParams));
+
+ if (!Instantiated)
+ return 0;
+
+ // Link the instantiated function template declaration to the function
+ // template from which it was instantiated.
+ FunctionTemplateDecl *InstTemplate
+ = Instantiated->getDescribedFunctionTemplate();
+ InstTemplate->setAccess(D->getAccess());
+ assert(InstTemplate &&
+ "VisitFunctionDecl/CXXMethodDecl didn't create a template!");
+ if (!InstTemplate->getInstantiatedFromMemberTemplate())
+ InstTemplate->setInstantiatedFromMemberTemplate(D);
+
+ // Add non-friends into the owner.
+ if (!InstTemplate->getFriendObjectKind())
+ Owner->addDecl(InstTemplate);
+ return InstTemplate;
+}
+
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);
+ = CXXRecordDecl::Create(SemaRef.Context, D->getTagKind(), Owner,
+ D->getLocation(), D->getIdentifier(),
+ D->getTagKeywordLoc(), PrevDecl);
Record->setImplicit(D->isImplicit());
- Record->setAccess(D->getAccess());
+ // FIXME: Check against AS_none is an ugly hack to work around the issue that
+ // the tag decls introduced by friend class declarations don't have an access
+ // specifier. Remove once this area of the code gets sorted out.
+ if (D->getAccess() != AS_none)
+ Record->setAccess(D->getAccess());
if (!D->isInjectedClassName())
- Record->setInstantiationOfMemberClass(D);
+ Record->setInstantiationOfMemberClass(D, TSK_ImplicitInstantiation);
+
+ // If the original function was part of a friend declaration,
+ // inherit its namespace state.
+ if (Decl::FriendObjectKind FOK = D->getFriendObjectKind())
+ Record->setObjectOfFriendDecl(FOK == Decl::FOK_Declared);
+
+ Record->setAnonymousStructOrUnion(D->isAnonymousStructOrUnion());
Owner->addDecl(Record);
return Record;
}
-Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) {
+/// Normal class members are of more specific types and therefore
+/// don't make it here. This function serves two purposes:
+/// 1) instantiating function templates
+/// 2) substituting friend declarations
+/// FIXME: preserve function definitions in case #2
+ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
+ TemplateParameterList *TemplateParams) {
// Check whether there is already a function template specialization for
// this declaration.
FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate();
void *InsertPos = 0;
- if (FunctionTemplate) {
+ if (FunctionTemplate && !TemplateParams) {
llvm::FoldingSetNodeID ID;
- FunctionTemplateSpecializationInfo::Profile(ID,
- TemplateArgs.getFlatArgumentList(),
- TemplateArgs.flat_size());
-
- FunctionTemplateSpecializationInfo *Info
- = FunctionTemplate->getSpecializations().FindNodeOrInsertPos(ID,
+ FunctionTemplateSpecializationInfo::Profile(ID,
+ TemplateArgs.getInnermost().getFlatArgumentList(),
+ TemplateArgs.getInnermost().flat_size(),
+ SemaRef.Context);
+
+ FunctionTemplateSpecializationInfo *Info
+ = FunctionTemplate->getSpecializations().FindNodeOrInsertPos(ID,
InsertPos);
-
+
// If we already have a function template specialization, return it.
if (Info)
return Info->Function;
}
-
+
Sema::LocalInstantiationScope Scope(SemaRef);
-
+
llvm::SmallVector<ParmVarDecl *, 4> Params;
- QualType T = InstantiateFunctionType(D, Params);
+ QualType T = SubstFunctionType(D, Params);
if (T.isNull())
return 0;
-
+
// Build the instantiated method declaration.
- FunctionDecl *Function
- = FunctionDecl::Create(SemaRef.Context, Owner, D->getLocation(),
- D->getDeclName(), T, D->getStorageClass(),
- D->isInline(), D->hasWrittenPrototype(),
- D->getTypeSpecStartLoc());
-
- // FIXME: friend functions
-
+ DeclContext *DC = SemaRef.FindInstantiatedContext(D->getDeclContext(),
+ TemplateArgs);
+ FunctionDecl *Function =
+ FunctionDecl::Create(SemaRef.Context, DC, D->getLocation(),
+ D->getDeclName(), T, D->getDeclaratorInfo(),
+ D->getStorageClass(),
+ D->isInline(), D->hasWrittenPrototype());
+ Function->setLexicalDeclContext(Owner);
+
// Attach the parameters
for (unsigned P = 0; P < Params.size(); ++P)
Params[P]->setOwningFunction(Function);
Function->setParams(SemaRef.Context, Params.data(), Params.size());
-
+
+ if (TemplateParams) {
+ // Our resulting instantiation is actually a function template, since we
+ // are substituting only the outer template parameters. For example, given
+ //
+ // template<typename T>
+ // struct X {
+ // template<typename U> friend void f(T, U);
+ // };
+ //
+ // X<int> x;
+ //
+ // We are instantiating the friend function template "f" within X<int>,
+ // which means substituting int for T, but leaving "f" as a friend function
+ // template.
+ // Build the function template itself.
+ FunctionTemplate = FunctionTemplateDecl::Create(SemaRef.Context, Owner,
+ Function->getLocation(),
+ Function->getDeclName(),
+ TemplateParams, Function);
+ Function->setDescribedFunctionTemplate(FunctionTemplate);
+ FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext());
+ }
+
if (InitFunctionInstantiation(Function, D))
Function->setInvalidDecl();
-
+
bool Redeclaration = false;
bool OverloadableAttrRequired = false;
+
NamedDecl *PrevDecl = 0;
- SemaRef.CheckFunctionDeclaration(Function, PrevDecl, Redeclaration,
+ if (TemplateParams || !FunctionTemplate) {
+ // Look only into the namespace where the friend would be declared to
+ // find a previous declaration. This is the innermost enclosing namespace,
+ // as described in ActOnFriendFunctionDecl.
+ Sema::LookupResult R;
+ SemaRef.LookupQualifiedName(R, DC, Function->getDeclName(),
+ Sema::LookupOrdinaryName, true);
+
+ PrevDecl = R.getAsSingleDecl(SemaRef.Context);
+
+ // 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;
+ }
+
+ SemaRef.CheckFunctionDeclaration(Function, PrevDecl, false, Redeclaration,
/*FIXME:*/OverloadableAttrRequired);
- if (FunctionTemplate) {
+ // If the original function was part of a friend declaration,
+ // inherit its namespace state and add it to the owner.
+ NamedDecl *FromFriendD
+ = TemplateParams? cast<NamedDecl>(D->getDescribedFunctionTemplate()) : D;
+ if (FromFriendD->getFriendObjectKind()) {
+ NamedDecl *ToFriendD = 0;
+ if (TemplateParams) {
+ ToFriendD = cast<NamedDecl>(FunctionTemplate);
+ PrevDecl = FunctionTemplate->getPreviousDeclaration();
+ } else {
+ ToFriendD = Function;
+ PrevDecl = Function->getPreviousDeclaration();
+ }
+ ToFriendD->setObjectOfFriendDecl(PrevDecl != NULL);
+ if (!Owner->isDependentContext() && !PrevDecl)
+ DC->makeDeclVisibleInContext(ToFriendD, /* Recoverable = */ false);
+
+ if (!TemplateParams)
+ Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
+ }
+
+ if (FunctionTemplate && !TemplateParams) {
// Record this function template specialization.
Function->setFunctionTemplateSpecialization(SemaRef.Context,
FunctionTemplate,
- &TemplateArgs,
+ &TemplateArgs.getInnermost(),
InsertPos);
- }
+ }
return Function;
}
-Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
- // FIXME: Look for existing, explicit specializations.
+Decl *
+TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
+ TemplateParameterList *TemplateParams) {
+ FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate();
+ void *InsertPos = 0;
+ if (FunctionTemplate && !TemplateParams) {
+ // We are creating a function template specialization from a function
+ // template. Check whether there is already a function template
+ // specialization for this particular set of template arguments.
+ llvm::FoldingSetNodeID ID;
+ FunctionTemplateSpecializationInfo::Profile(ID,
+ TemplateArgs.getInnermost().getFlatArgumentList(),
+ TemplateArgs.getInnermost().flat_size(),
+ SemaRef.Context);
+
+ FunctionTemplateSpecializationInfo *Info
+ = FunctionTemplate->getSpecializations().FindNodeOrInsertPos(ID,
+ InsertPos);
+
+ // If we already have a function template specialization, return it.
+ if (Info)
+ return Info->Function;
+ }
+
Sema::LocalInstantiationScope Scope(SemaRef);
llvm::SmallVector<ParmVarDecl *, 4> Params;
- QualType T = InstantiateFunctionType(D, Params);
+ QualType T = SubstFunctionType(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);
+ CXXMethodDecl *Method = 0;
+
+ DeclarationName Name = D->getDeclName();
+ if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
+ QualType ClassTy = SemaRef.Context.getTypeDeclType(Record);
+ Name = SemaRef.Context.DeclarationNames.getCXXConstructorName(
+ SemaRef.Context.getCanonicalType(ClassTy));
+ Method = CXXConstructorDecl::Create(SemaRef.Context, Record,
+ Constructor->getLocation(),
+ Name, T,
+ Constructor->getDeclaratorInfo(),
+ Constructor->isExplicit(),
+ Constructor->isInline(), false);
+ } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
+ QualType ClassTy = SemaRef.Context.getTypeDeclType(Record);
+ Name = SemaRef.Context.DeclarationNames.getCXXDestructorName(
+ SemaRef.Context.getCanonicalType(ClassTy));
+ Method = CXXDestructorDecl::Create(SemaRef.Context, Record,
+ Destructor->getLocation(), Name,
+ T, Destructor->isInline(), false);
+ } else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) {
+ CanQualType ConvTy
+ = SemaRef.Context.getCanonicalType(
+ T->getAs<FunctionType>()->getResultType());
+ Name = SemaRef.Context.DeclarationNames.getCXXConversionFunctionName(
+ ConvTy);
+ Method = CXXConversionDecl::Create(SemaRef.Context, Record,
+ Conversion->getLocation(), Name,
+ T, Conversion->getDeclaratorInfo(),
+ Conversion->isInline(),
+ Conversion->isExplicit());
+ } else {
+ Method = CXXMethodDecl::Create(SemaRef.Context, Record, D->getLocation(),
+ D->getDeclName(), T, D->getDeclaratorInfo(),
+ D->isStatic(), D->isInline());
+ }
+
+ if (TemplateParams) {
+ // Our resulting instantiation is actually a function template, since we
+ // are substituting only the outer template parameters. For example, given
+ //
+ // template<typename T>
+ // struct X {
+ // template<typename U> void f(T, U);
+ // };
+ //
+ // X<int> x;
+ //
+ // We are instantiating the member template "f" within X<int>, which means
+ // substituting int for T, but leaving "f" as a member function template.
+ // Build the function template itself.
+ FunctionTemplate = FunctionTemplateDecl::Create(SemaRef.Context, Record,
+ Method->getLocation(),
+ Method->getDeclName(),
+ TemplateParams, Method);
+ if (D->isOutOfLine())
+ FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext());
+ Method->setDescribedFunctionTemplate(FunctionTemplate);
+ } else if (!FunctionTemplate)
+ Method->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
+
+ // If we are instantiating a member function defined
+ // out-of-line, the instantiation will have the same lexical
+ // context (which will be a namespace scope) as the template.
+ if (D->isOutOfLine())
+ Method->setLexicalDeclContext(D->getLexicalDeclContext());
// Attach the parameters
for (unsigned P = 0; P < Params.size(); ++P)
@@ -379,167 +724,78 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
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;
+ NamedDecl *PrevDecl = 0;
+
+ if (!FunctionTemplate || TemplateParams) {
+ Sema::LookupResult R;
+ SemaRef.LookupQualifiedName(R, Owner, Name, Sema::LookupOrdinaryName, true);
+ PrevDecl = R.getAsSingleDecl(SemaRef.Context);
+
+ // 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;
+ }
+
+ if (FunctionTemplate && !TemplateParams)
+ // Record this function template specialization.
+ Method->setFunctionTemplateSpecialization(SemaRef.Context,
+ FunctionTemplate,
+ &TemplateArgs.getInnermost(),
+ InsertPos);
+
bool Redeclaration = false;
bool OverloadableAttrRequired = false;
- SemaRef.CheckFunctionDeclaration(Method, PrevDecl, Redeclaration,
+ SemaRef.CheckFunctionDeclaration(Method, PrevDecl, false, Redeclaration,
/*FIXME:*/OverloadableAttrRequired);
- if (!Method->isInvalidDecl() || !PrevDecl)
+ if (!FunctionTemplate && (!Method->isInvalidDecl() || !PrevDecl) &&
+ !Method->getFriendObjectKind())
Owner->addDecl(Method);
+
return Method;
}
Decl *TemplateDeclInstantiator::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
- // FIXME: Look for existing, explicit specializations.
- 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(Constructor);
- return Constructor;
+ return VisitCXXMethodDecl(D);
}
Decl *TemplateDeclInstantiator::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
- // FIXME: Look for existing, explicit specializations.
- 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(Destructor);
- return Destructor;
+ return VisitCXXMethodDecl(D);
}
Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) {
- // FIXME: Look for existing, explicit specializations.
- 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(Conversion);
- return Conversion;
+ return VisitCXXMethodDecl(D);
}
ParmVarDecl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) {
- QualType OrigT = SemaRef.InstantiateType(D->getOriginalType(), TemplateArgs,
+ QualType OrigT = SemaRef.SubstType(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);
+ D->getIdentifier(), T, D->getDeclaratorInfo(),
+ D->getStorageClass(), 0);
else
- Param = OriginalParmVarDecl::Create(SemaRef.Context, Owner,
+ Param = OriginalParmVarDecl::Create(SemaRef.Context, Owner,
D->getLocation(), D->getIdentifier(),
- T, OrigT, D->getStorageClass(), 0);
-
+ T, D->getDeclaratorInfo(), OrigT,
+ D->getStorageClass(), 0);
+
+ // Mark the default argument as being uninstantiated.
+ if (D->hasUninstantiatedDefaultArg())
+ Param->setUninstantiatedDefaultArg(D->getUninstantiatedDefaultArg());
+ else if (Expr *Arg = D->getDefaultArg())
+ Param->setUninstantiatedDefaultArg(Arg);
+
// 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.
@@ -556,41 +812,130 @@ TemplateDeclInstantiator::VisitOriginalParmVarDecl(OriginalParmVarDecl *D) {
return VisitParmVarDecl(D);
}
-Decl *Sema::InstantiateDecl(Decl *D, DeclContext *Owner,
- const TemplateArgumentList &TemplateArgs) {
+Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl(
+ TemplateTypeParmDecl *D) {
+ // TODO: don't always clone when decls are refcounted.
+ const Type* T = D->getTypeForDecl();
+ assert(T->isTemplateTypeParmType());
+ const TemplateTypeParmType *TTPT = T->getAs<TemplateTypeParmType>();
+
+ TemplateTypeParmDecl *Inst =
+ TemplateTypeParmDecl::Create(SemaRef.Context, Owner, D->getLocation(),
+ TTPT->getDepth(), TTPT->getIndex(),
+ TTPT->getName(),
+ D->wasDeclaredWithTypename(),
+ D->isParameterPack());
+
+ if (D->hasDefaultArgument()) {
+ QualType DefaultPattern = D->getDefaultArgument();
+ QualType DefaultInst
+ = SemaRef.SubstType(DefaultPattern, TemplateArgs,
+ D->getDefaultArgumentLoc(),
+ D->getDeclName());
+
+ Inst->setDefaultArgument(DefaultInst,
+ D->getDefaultArgumentLoc(),
+ D->defaultArgumentWasInherited() /* preserve? */);
+ }
+
+ return Inst;
+}
+
+Decl *
+TemplateDeclInstantiator::VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D) {
+ NestedNameSpecifier *NNS =
+ SemaRef.SubstNestedNameSpecifier(D->getTargetNestedNameSpecifier(),
+ D->getTargetNestedNameRange(),
+ TemplateArgs);
+ if (!NNS)
+ return 0;
+
+ CXXScopeSpec SS;
+ SS.setRange(D->getTargetNestedNameRange());
+ SS.setScopeRep(NNS);
+
+ NamedDecl *UD =
+ SemaRef.BuildUsingDeclaration(D->getLocation(), SS,
+ D->getTargetNameLocation(),
+ D->getTargetName(), 0, D->isTypeName());
+ if (UD)
+ SemaRef.Context.setInstantiatedFromUnresolvedUsingDecl(cast<UsingDecl>(UD),
+ D);
+ return UD;
+}
+
+Decl *Sema::SubstDecl(Decl *D, DeclContext *Owner,
+ const MultiLevelTemplateArgumentList &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.
+/// \brief Instantiates a nested template parameter list in the current
+/// instantiation context.
///
-/// \param D The function that we will be instantiated
+/// \param L The parameter list to instantiate
+///
+/// \returns NULL if there was an error
+TemplateParameterList *
+TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) {
+ // Get errors for all the parameters before bailing out.
+ bool Invalid = false;
+
+ unsigned N = L->size();
+ typedef llvm::SmallVector<NamedDecl *, 8> ParamVector;
+ ParamVector Params;
+ Params.reserve(N);
+ for (TemplateParameterList::iterator PI = L->begin(), PE = L->end();
+ PI != PE; ++PI) {
+ NamedDecl *D = cast_or_null<NamedDecl>(Visit(*PI));
+ Params.push_back(D);
+ Invalid = Invalid || !D;
+ }
+
+ // Clean up if we had an error.
+ if (Invalid) {
+ for (ParamVector::iterator PI = Params.begin(), PE = Params.end();
+ PI != PE; ++PI)
+ if (*PI)
+ (*PI)->Destroy(SemaRef.Context);
+ return NULL;
+ }
+
+ TemplateParameterList *InstL
+ = TemplateParameterList::Create(SemaRef.Context, L->getTemplateLoc(),
+ L->getLAngleLoc(), &Params.front(), N,
+ L->getRAngleLoc());
+ return InstL;
+}
+
+/// \brief Does substitution on the type of the given function, including
+/// all of the function parameters.
+///
+/// \param D The function whose type will be the basis of the substitution
///
/// \param Params the instantiated parameter declarations
-/// \returns the instantiated function's type if successfull, a NULL
+/// \returns the instantiated function's type if successful, a NULL
/// type if there was an error.
-QualType
-TemplateDeclInstantiator::InstantiateFunctionType(FunctionDecl *D,
+QualType
+TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
llvm::SmallVectorImpl<ParmVarDecl *> &Params) {
bool InvalidDecl = false;
- // Instantiate the function parameters
+ // Substitute all of the function's formal parameter types.
TemplateDeclInstantiator ParamInstantiator(SemaRef, 0, TemplateArgs);
llvm::SmallVector<QualType, 4> ParamTys;
- for (FunctionDecl::param_iterator P = D->param_begin(),
+ 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))
+ } else if (SemaRef.RequireNonAbstractType(PInst->getLocation(),
+ PInst->getType(),
+ diag::err_abstract_type_in_decl,
+ Sema::AbstractParamType))
PInst->setInvalidDecl();
Params.push_back(PInst);
@@ -598,7 +943,7 @@ TemplateDeclInstantiator::InstantiateFunctionType(FunctionDecl *D,
if (PInst->isInvalidDecl())
InvalidDecl = true;
- } else
+ } else
InvalidDecl = true;
}
@@ -606,11 +951,11 @@ TemplateDeclInstantiator::InstantiateFunctionType(FunctionDecl *D,
if (InvalidDecl)
return QualType();
- const FunctionProtoType *Proto = D->getType()->getAsFunctionProtoType();
+ const FunctionProtoType *Proto = D->getType()->getAs<FunctionProtoType>();
assert(Proto && "Missing prototype?");
- QualType ResultType
- = SemaRef.InstantiateType(Proto->getResultType(), TemplateArgs,
- D->getLocation(), D->getDeclName());
+ QualType ResultType
+ = SemaRef.SubstType(Proto->getResultType(), TemplateArgs,
+ D->getLocation(), D->getDeclName());
if (ResultType.isNull())
return QualType();
@@ -619,21 +964,21 @@ TemplateDeclInstantiator::InstantiateFunctionType(FunctionDecl *D,
D->getLocation(), D->getDeclName());
}
-/// \brief Initializes the common fields of an instantiation function
+/// \brief Initializes the common fields of an instantiation function
/// declaration (New) from the corresponding fields of its template (Tmpl).
///
/// \returns true if there was an error
-bool
-TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
+bool
+TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
FunctionDecl *Tmpl) {
if (Tmpl->isDeleted())
New->setDeleted();
-
+
// If we are performing substituting explicitly-specified template arguments
// or deduced template arguments into a function template and we reach this
// point, we are now past the point where SFINAE applies and have committed
- // to keeping the new function template specialization. We therefore
- // convert the active template instantiation for the function template
+ // to keeping the new function template specialization. We therefore
+ // convert the active template instantiation for the function template
// into a template instantiation for this specific function template
// specialization, which is not a SFINAE context, so that we diagnose any
// further errors in the declaration itself.
@@ -641,15 +986,16 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
ActiveInstType &ActiveInst = SemaRef.ActiveTemplateInstantiations.back();
if (ActiveInst.Kind == ActiveInstType::ExplicitTemplateArgumentSubstitution ||
ActiveInst.Kind == ActiveInstType::DeducedTemplateArgumentSubstitution) {
- if (FunctionTemplateDecl *FunTmpl
+ if (FunctionTemplateDecl *FunTmpl
= dyn_cast<FunctionTemplateDecl>((Decl *)ActiveInst.Entity)) {
- assert(FunTmpl->getTemplatedDecl() == Tmpl &&
+ assert(FunTmpl->getTemplatedDecl() == Tmpl &&
"Deduction from the wrong function template?");
+ (void) FunTmpl;
ActiveInst.Kind = ActiveInstType::TemplateInstantiation;
ActiveInst.Entity = reinterpret_cast<uintptr_t>(New);
}
}
-
+
return false;
}
@@ -658,18 +1004,19 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
/// (Tmpl).
///
/// \returns true if there was an error
-bool
-TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New,
+bool
+TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New,
CXXMethodDecl *Tmpl) {
if (InitFunctionInstantiation(New, Tmpl))
return true;
-
+
CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner);
New->setAccess(Tmpl->getAccess());
if (Tmpl->isVirtualAsWritten()) {
New->setVirtualAsWritten(true);
Record->setAggregate(false);
Record->setPOD(false);
+ Record->setEmpty(false);
Record->setPolymorphic(true);
}
if (Tmpl->isPure()) {
@@ -702,12 +1049,25 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
return;
assert(!Function->getBody() && "Already instantiated!");
+
+ // Never instantiate an explicit specialization.
+ if (Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+ return;
// Find the function body that we'll be substituting.
const FunctionDecl *PatternDecl = 0;
- if (FunctionTemplateDecl *Primary = Function->getPrimaryTemplate())
+ if (FunctionTemplateDecl *Primary = Function->getPrimaryTemplate()) {
+ while (Primary->getInstantiatedFromMemberTemplate()) {
+ // If we have hit a point where the user provided a specialization of
+ // this template, we're done looking.
+ if (Primary->isMemberSpecialization())
+ break;
+
+ Primary = Primary->getInstantiatedFromMemberTemplate();
+ }
+
PatternDecl = Primary->getTemplatedDecl();
- else
+ } else
PatternDecl = Function->getInstantiatedFromMemberFunction();
Stmt *Pattern = 0;
if (PatternDecl)
@@ -716,6 +1076,15 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
if (!Pattern)
return;
+ // C++0x [temp.explicit]p9:
+ // Except for inline functions, other explicit instantiation declarations
+ // have the effect of suppressing the implicit instantiation of the entity
+ // to which they refer.
+ if (Function->getTemplateSpecializationKind()
+ == TSK_ExplicitInstantiationDeclaration &&
+ PatternDecl->isOutOfLine() && !PatternDecl->isInline())
+ return;
+
InstantiatingTemplate Inst(*this, PointOfInstantiation, Function);
if (Inst)
return;
@@ -726,13 +1095,13 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
std::deque<PendingImplicitInstantiation> SavedPendingImplicitInstantiations;
if (Recursive)
PendingImplicitInstantiations.swap(SavedPendingImplicitInstantiations);
-
+
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)
@@ -744,23 +1113,35 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
DeclContext *PreviousContext = CurContext;
CurContext = Function;
+ MultiLevelTemplateArgumentList TemplateArgs =
+ getTemplateInstantiationArgs(Function);
+
+ // If this is a constructor, instantiate the member initializers.
+ if (const CXXConstructorDecl *Ctor =
+ dyn_cast<CXXConstructorDecl>(PatternDecl)) {
+ InstantiateMemInitializers(cast<CXXConstructorDecl>(Function), Ctor,
+ TemplateArgs);
+ }
+
// Instantiate the function body.
- OwningStmtResult Body
- = InstantiateStmt(Pattern, getTemplateInstantiationArgs(Function));
+ OwningStmtResult Body = SubstStmt(Pattern, TemplateArgs);
- ActOnFinishFunctionBody(DeclPtrTy::make(Function), move(Body),
+ if (Body.isInvalid())
+ Function->setInvalidDecl();
+
+ ActOnFinishFunctionBody(DeclPtrTy::make(Function), move(Body),
/*IsInstantiation=*/true);
CurContext = PreviousContext;
DeclGroupRef DG(Function);
Consumer.HandleTopLevelDecl(DG);
-
+
if (Recursive) {
// Instantiate any pending implicit instantiations found during the
- // instantiation of this template.
+ // instantiation of this template.
PerformPendingImplicitInstantiations();
-
+
// Restore the set of pending implicit instantiations.
PendingImplicitInstantiations.swap(SavedPendingImplicitInstantiations);
}
@@ -769,35 +1150,296 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
/// \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!
+/// \param PointOfInstantiation the point at which the instantiation was
+/// required. Note that this is not precisely a "point of instantiation"
+/// for the function, but it's close.
+///
+/// \param Var the already-instantiated declaration of a static member
+/// variable of a class template specialization.
+///
+/// \param Recursive if true, recursively instantiates any functions that
+/// are required by this instantiation.
+void Sema::InstantiateStaticDataMemberDefinition(
+ SourceLocation PointOfInstantiation,
+ VarDecl *Var,
+ bool Recursive) {
+ if (Var->isInvalidDecl())
+ return;
+
+ // Find the out-of-line definition of this static data member.
+ VarDecl *Def = Var->getInstantiatedFromStaticDataMember();
+ bool FoundOutOfLineDef = false;
+ assert(Def && "This data member was not instantiated from a template?");
+ assert(Def->isStaticDataMember() && "Not a static data member?");
+ for (VarDecl::redecl_iterator RD = Def->redecls_begin(),
+ RDEnd = Def->redecls_end();
+ RD != RDEnd; ++RD) {
+ if (RD->getLexicalDeclContext()->isFileContext()) {
+ Def = *RD;
+ FoundOutOfLineDef = true;
+ }
+ }
+
+ if (!FoundOutOfLineDef) {
+ // We did not find an out-of-line definition of this static data member,
+ // so we won't perform any instantiation. Rather, we rely on the user to
+ // instantiate this definition (or provide a specialization for it) in
+ // another translation unit.
+ return;
+ }
+
+ // Never instantiate an explicit specialization.
+ if (Def->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+ return;
+
+ // C++0x [temp.explicit]p9:
+ // Except for inline functions, other explicit instantiation declarations
+ // have the effect of suppressing the implicit instantiation of the entity
+ // to which they refer.
+ if (Def->getTemplateSpecializationKind()
+ == TSK_ExplicitInstantiationDeclaration)
+ return;
+
+ InstantiatingTemplate Inst(*this, PointOfInstantiation, Var);
+ if (Inst)
+ return;
+
+ // If we're performing recursive template instantiation, create our own
+ // queue of pending implicit instantiations that we will instantiate later,
+ // while we're still within our own instantiation context.
+ std::deque<PendingImplicitInstantiation> SavedPendingImplicitInstantiations;
+ if (Recursive)
+ PendingImplicitInstantiations.swap(SavedPendingImplicitInstantiations);
+
+ // Enter the scope of this instantiation. We don't use
+ // PushDeclContext because we don't have a scope.
+ DeclContext *PreviousContext = CurContext;
+ CurContext = Var->getDeclContext();
+
+ Var = cast_or_null<VarDecl>(SubstDecl(Def, Var->getDeclContext(),
+ getTemplateInstantiationArgs(Var)));
+
+ CurContext = PreviousContext;
+
+ if (Var) {
+ DeclGroupRef DG(Var);
+ Consumer.HandleTopLevelDecl(DG);
+ }
+
+ if (Recursive) {
+ // Instantiate any pending implicit instantiations found during the
+ // instantiation of this template.
+ PerformPendingImplicitInstantiations();
+
+ // Restore the set of pending implicit instantiations.
+ PendingImplicitInstantiations.swap(SavedPendingImplicitInstantiations);
+ }
+}
+
+void
+Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
+ const CXXConstructorDecl *Tmpl,
+ const MultiLevelTemplateArgumentList &TemplateArgs) {
+
+ llvm::SmallVector<MemInitTy*, 4> NewInits;
+
+ // Instantiate all the initializers.
+ for (CXXConstructorDecl::init_const_iterator Inits = Tmpl->init_begin(),
+ InitsEnd = Tmpl->init_end();
+ Inits != InitsEnd; ++Inits) {
+ CXXBaseOrMemberInitializer *Init = *Inits;
+
+ ASTOwningVector<&ActionBase::DeleteExpr> NewArgs(*this);
+
+ // Instantiate all the arguments.
+ for (ExprIterator Args = Init->arg_begin(), ArgsEnd = Init->arg_end();
+ Args != ArgsEnd; ++Args) {
+ OwningExprResult NewArg = SubstExpr(*Args, TemplateArgs);
+
+ if (NewArg.isInvalid())
+ New->setInvalidDecl();
+ else
+ NewArgs.push_back(NewArg.takeAs<Expr>());
+ }
+
+ MemInitResult NewInit;
+
+ if (Init->isBaseInitializer()) {
+ QualType BaseType(Init->getBaseClass(), 0);
+ BaseType = SubstType(BaseType, TemplateArgs, Init->getSourceLocation(),
+ New->getDeclName());
+
+ NewInit = BuildBaseInitializer(BaseType,
+ (Expr **)NewArgs.data(),
+ NewArgs.size(),
+ Init->getSourceLocation(),
+ Init->getRParenLoc(),
+ New->getParent());
+ } else if (Init->isMemberInitializer()) {
+ FieldDecl *Member;
+
+ // Is this an anonymous union?
+ if (FieldDecl *UnionInit = Init->getAnonUnionMember())
+ Member = cast<FieldDecl>(FindInstantiatedDecl(UnionInit, TemplateArgs));
+ else
+ Member = cast<FieldDecl>(FindInstantiatedDecl(Init->getMember(),
+ TemplateArgs));
+
+ NewInit = BuildMemberInitializer(Member, (Expr **)NewArgs.data(),
+ NewArgs.size(),
+ Init->getSourceLocation(),
+ Init->getRParenLoc());
+ }
+
+ if (NewInit.isInvalid())
+ New->setInvalidDecl();
+ else {
+ // FIXME: It would be nice if ASTOwningVector had a release function.
+ NewArgs.take();
+
+ NewInits.push_back((MemInitTy *)NewInit.get());
+ }
+ }
+
+ // Assign all the initializers to the new constructor.
+ ActOnMemInitializers(DeclPtrTy::make(New),
+ /*FIXME: ColonLoc */
+ SourceLocation(),
+ NewInits.data(), NewInits.size());
+}
+
+// TODO: this could be templated if the various decl types used the
+// same method name.
+static bool isInstantiationOf(ClassTemplateDecl *Pattern,
+ ClassTemplateDecl *Instance) {
+ Pattern = Pattern->getCanonicalDecl();
+
+ do {
+ Instance = Instance->getCanonicalDecl();
+ if (Pattern == Instance) return true;
+ Instance = Instance->getInstantiatedFromMemberTemplate();
+ } while (Instance);
+
+ return false;
+}
+
+static bool isInstantiationOf(FunctionTemplateDecl *Pattern,
+ FunctionTemplateDecl *Instance) {
+ Pattern = Pattern->getCanonicalDecl();
+
+ do {
+ Instance = Instance->getCanonicalDecl();
+ if (Pattern == Instance) return true;
+ Instance = Instance->getInstantiatedFromMemberTemplate();
+ } while (Instance);
+
+ return false;
+}
+
+static bool isInstantiationOf(CXXRecordDecl *Pattern,
+ CXXRecordDecl *Instance) {
+ Pattern = Pattern->getCanonicalDecl();
+
+ do {
+ Instance = Instance->getCanonicalDecl();
+ if (Pattern == Instance) return true;
+ Instance = Instance->getInstantiatedFromMemberClass();
+ } while (Instance);
+
+ return false;
+}
+
+static bool isInstantiationOf(FunctionDecl *Pattern,
+ FunctionDecl *Instance) {
+ Pattern = Pattern->getCanonicalDecl();
+
+ do {
+ Instance = Instance->getCanonicalDecl();
+ if (Pattern == Instance) return true;
+ Instance = Instance->getInstantiatedFromMemberFunction();
+ } while (Instance);
+
+ return false;
+}
+
+static bool isInstantiationOf(EnumDecl *Pattern,
+ EnumDecl *Instance) {
+ Pattern = Pattern->getCanonicalDecl();
+
+ do {
+ Instance = Instance->getCanonicalDecl();
+ if (Pattern == Instance) return true;
+ Instance = Instance->getInstantiatedFromMemberEnum();
+ } while (Instance);
+
+ return false;
+}
+
+static bool isInstantiationOf(UnresolvedUsingDecl *Pattern,
+ UsingDecl *Instance,
+ ASTContext &C) {
+ return C.getInstantiatedFromUnresolvedUsingDecl(Instance) == Pattern;
+}
+
+static bool isInstantiationOfStaticDataMember(VarDecl *Pattern,
+ VarDecl *Instance) {
+ assert(Instance->isStaticDataMember());
+
+ Pattern = Pattern->getCanonicalDecl();
+
+ do {
+ Instance = Instance->getCanonicalDecl();
+ if (Pattern == Instance) return true;
+ Instance = Instance->getInstantiatedFromStaticDataMember();
+ } while (Instance);
+
+ return false;
}
static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) {
- if (D->getKind() != Other->getKind())
+ if (D->getKind() != Other->getKind()) {
+ if (UnresolvedUsingDecl *UUD = dyn_cast<UnresolvedUsingDecl>(D)) {
+ if (UsingDecl *UD = dyn_cast<UsingDecl>(Other)) {
+ return isInstantiationOf(UUD, UD, Ctx);
+ }
+ }
+
return false;
+ }
if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Other))
- return Ctx.getCanonicalDecl(Record->getInstantiatedFromMemberClass())
- == Ctx.getCanonicalDecl(D);
+ return isInstantiationOf(cast<CXXRecordDecl>(D), Record);
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Other))
- return Ctx.getCanonicalDecl(Function->getInstantiatedFromMemberFunction())
- == Ctx.getCanonicalDecl(D);
+ return isInstantiationOf(cast<FunctionDecl>(D), Function);
if (EnumDecl *Enum = dyn_cast<EnumDecl>(Other))
- return Ctx.getCanonicalDecl(Enum->getInstantiatedFromMemberEnum())
- == Ctx.getCanonicalDecl(D);
+ return isInstantiationOf(cast<EnumDecl>(D), Enum);
+
+ if (VarDecl *Var = dyn_cast<VarDecl>(Other))
+ if (Var->isStaticDataMember())
+ return isInstantiationOfStaticDataMember(cast<VarDecl>(D), Var);
+
+ if (ClassTemplateDecl *Temp = dyn_cast<ClassTemplateDecl>(Other))
+ return isInstantiationOf(cast<ClassTemplateDecl>(D), Temp);
+
+ if (FunctionTemplateDecl *Temp = dyn_cast<FunctionTemplateDecl>(Other))
+ return isInstantiationOf(cast<FunctionTemplateDecl>(D), Temp);
- // FIXME: How can we find instantiations of anonymous unions?
+ if (FieldDecl *Field = dyn_cast<FieldDecl>(Other)) {
+ if (!Field->getDeclName()) {
+ // This is an unnamed field.
+ return Ctx.getInstantiatedFromUnnamedFieldDecl(Field) ==
+ cast<FieldDecl>(D);
+ }
+ }
return D->getDeclName() && isa<NamedDecl>(Other) &&
D->getDeclName() == cast<NamedDecl>(Other)->getDeclName();
}
template<typename ForwardIterator>
-static NamedDecl *findInstantiationOf(ASTContext &Ctx,
+static NamedDecl *findInstantiationOf(ASTContext &Ctx,
NamedDecl *D,
ForwardIterator first,
ForwardIterator last) {
@@ -808,6 +1450,18 @@ static NamedDecl *findInstantiationOf(ASTContext &Ctx,
return 0;
}
+/// \brief Finds the instantiation of the given declaration context
+/// within the current instantiation.
+///
+/// \returns NULL if there was an error
+DeclContext *Sema::FindInstantiatedContext(DeclContext* DC,
+ const MultiLevelTemplateArgumentList &TemplateArgs) {
+ if (NamedDecl *D = dyn_cast<NamedDecl>(DC)) {
+ Decl* ID = FindInstantiatedDecl(D, TemplateArgs);
+ return cast_or_null<DeclContext>(ID);
+ } else return DC;
+}
+
/// \brief Find the instantiation of the given declaration within the
/// current instantiation.
///
@@ -834,7 +1488,24 @@ static NamedDecl *findInstantiationOf(ASTContext &Ctx,
/// 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) {
+NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D,
+ const MultiLevelTemplateArgumentList &TemplateArgs) {
+ if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(D)) {
+ // Transform all of the elements of the overloaded function set.
+ OverloadedFunctionDecl *Result
+ = OverloadedFunctionDecl::Create(Context, CurContext, Ovl->getDeclName());
+
+ for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
+ FEnd = Ovl->function_end();
+ F != FEnd; ++F) {
+ Result->addOverload(
+ AnyFunctionDecl::getFromNamedDecl(FindInstantiatedDecl(*F,
+ TemplateArgs)));
+ }
+
+ return Result;
+ }
+
DeclContext *ParentDC = D->getDeclContext();
if (isa<ParmVarDecl>(D) || ParentDC->isFunctionOrMethod()) {
// D is a local of some kind. Look into the map of local
@@ -842,14 +1513,71 @@ NamedDecl * Sema::InstantiateCurrentDeclRef(NamedDecl *D) {
return cast<NamedDecl>(CurrentInstantiationScope->getInstantiationOf(D));
}
- if (NamedDecl *ParentDecl = dyn_cast<NamedDecl>(ParentDC)) {
- ParentDecl = InstantiateCurrentDeclRef(ParentDecl);
- if (!ParentDecl)
- return 0;
+ if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) {
+ if (!Record->isDependentContext())
+ return D;
+
+ // If the RecordDecl is actually the injected-class-name or a "templated"
+ // declaration for a class template or class template partial
+ // specialization, substitute into the injected-class-name of the
+ // class template or partial specialization to find the new DeclContext.
+ QualType T;
+ ClassTemplateDecl *ClassTemplate = Record->getDescribedClassTemplate();
+
+ if (ClassTemplate) {
+ T = ClassTemplate->getInjectedClassNameType(Context);
+ } else if (ClassTemplatePartialSpecializationDecl *PartialSpec
+ = dyn_cast<ClassTemplatePartialSpecializationDecl>(Record)) {
+ T = Context.getTypeDeclType(Record);
+ ClassTemplate = PartialSpec->getSpecializedTemplate();
+ }
+
+ if (!T.isNull()) {
+ // Substitute into the injected-class-name to get the type corresponding
+ // to the instantiation we want. This substitution should never fail,
+ // since we know we can instantiate the injected-class-name or we wouldn't
+ // have gotten to the injected-class-name!
+ // FIXME: Can we use the CurrentInstantiationScope to avoid this extra
+ // instantiation in the common case?
+ T = SubstType(T, TemplateArgs, SourceLocation(), DeclarationName());
+ assert(!T.isNull() && "Instantiation of injected-class-name cannot fail.");
+
+ if (!T->isDependentType()) {
+ assert(T->isRecordType() && "Instantiation must produce a record type");
+ return T->getAs<RecordType>()->getDecl();
+ }
+
+ // We are performing "partial" template instantiation to create the
+ // member declarations for the members of a class template
+ // specialization. Therefore, D is actually referring to something in
+ // the current instantiation. Look through the current context,
+ // which contains actual instantiations, to find the instantiation of
+ // the "current instantiation" that D refers to.
+ for (DeclContext *DC = CurContext; !DC->isFileContext();
+ DC = DC->getParent()) {
+ if (ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(DC))
+ if (isInstantiationOf(ClassTemplate,
+ Spec->getSpecializedTemplate()))
+ return Spec;
+ }
- ParentDC = cast<DeclContext>(ParentDecl);
+ assert(false &&
+ "Unable to find declaration for the current instantiation");
+ return Record;
+ }
+
+ // Fall through to deal with other dependent record types (e.g.,
+ // anonymous unions in class templates).
}
+ if (!ParentDC->isDependentContext())
+ return D;
+
+ ParentDC = FindInstantiatedContext(ParentDC, TemplateArgs);
+ if (!ParentDC)
+ return 0;
+
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
@@ -867,51 +1595,47 @@ NamedDecl * Sema::InstantiateCurrentDeclRef(NamedDecl *D) {
// - unnamed class/struct/union/enum within a template
//
// FIXME: Find a better way to find these instantiations!
- Result = findInstantiationOf(Context, D,
+ Result = findInstantiationOf(Context, D,
ParentDC->decls_begin(),
ParentDC->decls_end());
}
+
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;
}
-/// \brief Performs template instantiation for all implicit template
+/// \brief Performs template instantiation for all implicit template
/// instantiations we have seen until this point.
void Sema::PerformPendingImplicitInstantiations() {
while (!PendingImplicitInstantiations.empty()) {
PendingImplicitInstantiation Inst = PendingImplicitInstantiations.front();
PendingImplicitInstantiations.pop_front();
-
- if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Inst.first))
+
+ // Instantiate function definitions
+ if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Inst.first)) {
+ PrettyStackTraceActionsDecl CrashInfo(DeclPtrTy::make(Function),
+ Function->getLocation(), *this,
+ Context.getSourceManager(),
+ "instantiating function definition");
+
if (!Function->getBody())
InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true);
-
- // FIXME: instantiate static member variables
+ continue;
+ }
+
+ // Instantiate static data member definitions.
+ VarDecl *Var = cast<VarDecl>(Inst.first);
+ assert(Var->isStaticDataMember() && "Not a static data member?");
+
+ PrettyStackTraceActionsDecl CrashInfo(DeclPtrTy::make(Var),
+ Var->getLocation(), *this,
+ Context.getSourceManager(),
+ "instantiating static data member "
+ "definition");
+
+ InstantiateStaticDataMemberDefinition(/*FIXME:*/Inst.second, Var, true);
}
}
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 3756df8..3cdf615 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -13,9 +13,12 @@
#include "Sema.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/TypeLoc.h"
#include "clang/AST/Expr.h"
+#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Parse/DeclSpec.h"
#include "llvm/ADT/SmallPtrSet.h"
using namespace clang;
@@ -23,8 +26,8 @@ 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.
+/// 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()) {
@@ -48,15 +51,17 @@ QualType Sema::adjustParameterType(QualType T) {
/// object.
/// \param DS the declaration specifiers
/// \param DeclLoc The location of the declarator identifier or invalid if none.
+/// \param SourceTy QualType representing the type as written in source form.
/// \returns The type described by the declaration specifiers. This function
/// never returns null.
QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS,
SourceLocation DeclLoc,
- bool &isInvalid) {
+ bool &isInvalid, QualType &SourceTy) {
// FIXME: Should move the logic from DeclSpec::Finish to here for validity
// checking.
QualType Result;
-
+ SourceTy = Result;
+
switch (DS.getTypeSpecType()) {
case DeclSpec::TST_void:
Result = Context.VoidTy;
@@ -87,14 +92,28 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS,
Result = Context.getUnsignedWCharType();
}
break;
+ case DeclSpec::TST_char16:
+ assert(DS.getTypeSpecSign() == DeclSpec::TSS_unspecified &&
+ "Unknown TSS value");
+ Result = Context.Char16Ty;
+ break;
+ case DeclSpec::TST_char32:
+ assert(DS.getTypeSpecSign() == DeclSpec::TSS_unspecified &&
+ "Unknown TSS value");
+ Result = Context.Char32Ty;
+ break;
case DeclSpec::TST_unspecified:
// "<proto1,proto2>" is an objc qualified ID with a missing id.
if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) {
- Result = Context.getObjCObjectPointerType(0, (ObjCProtocolDecl**)PQ,
+ SourceTy = Context.getObjCProtocolListType(QualType(),
+ (ObjCProtocolDecl**)PQ,
+ DS.getNumProtocolQualifiers());
+ Result = Context.getObjCObjectPointerType(Context.ObjCBuiltinIdTy,
+ (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.
@@ -125,7 +144,7 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS,
if (getLangOptions().CPlusPlus && !getLangOptions().Microsoft) {
Diag(DeclLoc, diag::err_missing_type_specifier)
<< DS.getSourceRange();
-
+
// When this occurs in C++ code, often something is very broken with the
// value being declared, poison it as invalid so we don't get chains of
// errors.
@@ -135,8 +154,8 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS,
<< DS.getSourceRange();
}
}
-
- // FALL THROUGH.
+
+ // FALL THROUGH.
case DeclSpec::TST_int: {
if (DS.getTypeSpecSign() != DeclSpec::TSS_unsigned) {
switch (DS.getTypeSpecWidth()) {
@@ -175,40 +194,64 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS,
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?");
+ if (!D) {
+ // This can happen in C++ with ambiguous lookups.
+ Result = Context.IntTy;
+ isInvalid = true;
+ break;
+ }
+
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));
-
+
+ // In C++, make an ElaboratedType.
+ if (getLangOptions().CPlusPlus) {
+ TagDecl::TagKind Tag
+ = TagDecl::getTagKindForTypeSpec(DS.getTypeSpecType());
+ Result = Context.getElaboratedType(Result, Tag);
+ }
+
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());
+ Result = GetTypeFromParser(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.getObjCObjectPointerType(0, (ObjCProtocolDecl**)PQ,
+ SourceTy = Context.getObjCProtocolListType(Result,
+ (ObjCProtocolDecl**)PQ,
DS.getNumProtocolQualifiers());
- else if (Result == Context.getObjCClassType()) {
+ if (const ObjCInterfaceType *
+ Interface = Result->getAs<ObjCInterfaceType>()) {
+ // It would be nice if protocol qualifiers were only stored with the
+ // ObjCObjectPointerType. Unfortunately, this isn't possible due
+ // to the following typedef idiom (which is uncommon, but allowed):
+ //
+ // typedef Foo<P> T;
+ // static void func() {
+ // Foo<P> *yy;
+ // T *zz;
+ // }
+ Result = Context.getObjCInterfaceType(Interface->getDecl(),
+ (ObjCProtocolDecl**)PQ,
+ DS.getNumProtocolQualifiers());
+ } else if (Result->isObjCIdType())
+ // id<protocol-list>
+ Result = Context.getObjCObjectPointerType(Context.ObjCBuiltinIdTy,
+ (ObjCProtocolDecl**)PQ, DS.getNumProtocolQualifiers());
+ else if (Result->isObjCClassType()) {
if (DeclLoc.isInvalid())
DeclLoc = DS.getSourceRange().getBegin();
// Class<protocol-list>
- Diag(DeclLoc, diag::err_qualified_class_unsupported)
- << DS.getSourceRange();
+ Result = Context.getObjCObjectPointerType(Context.ObjCBuiltinClassTy,
+ (ObjCProtocolDecl**)PQ, DS.getNumProtocolQualifiers());
} else {
if (DeclLoc.isInvalid())
DeclLoc = DS.getSourceRange().getBegin();
@@ -217,17 +260,18 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS,
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());
+ // FIXME: Preserve type source info.
+ Result = GetTypeFromParser(DS.getTypeRep());
assert(!Result.isNull() && "Didn't get a type for typeof?");
// TypeQuals handled by caller.
Result = Context.getTypeOfType(Result);
@@ -255,73 +299,75 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS,
Result = Context.UndeducedAutoTy;
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 (TypeQuals & DeclSpec::TQ_restrict) {
if (Result->isPointerType() || Result->isReferenceType()) {
- QualType EltTy = Result->isPointerType() ?
- Result->getAsPointerType()->getPointeeType() :
- Result->getAsReferenceType()->getPointeeType();
-
+ QualType EltTy = Result->isPointerType() ?
+ Result->getAs<PointerType>()->getPointeeType() :
+ Result->getAs<ReferenceType>()->getPointeeType();
+
// If we have a pointer or reference, the pointee must have an object
// incomplete type.
if (!EltTy->isIncompleteOrObjectType()) {
Diag(DS.getRestrictSpecLoc(),
diag::err_typecheck_invalid_restrict_invalid_pointee)
<< EltTy << DS.getSourceRange();
- TypeQuals &= ~QualType::Restrict; // Remove the restrict qualifier.
+ TypeQuals &= ~DeclSpec::TQ_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.
+ TypeQuals &= ~DeclSpec::TQ_restrict; // Remove the restrict qualifier.
}
}
-
+
// Warn about CV qualifiers on functions: C99 6.7.3p8: "If the specification
// of a function type includes any type qualifiers, the behavior is
// undefined."
if (Result->isFunctionType() && TypeQuals) {
// Get some location to point at, either the C or V location.
SourceLocation Loc;
- if (TypeQuals & QualType::Const)
+ if (TypeQuals & DeclSpec::TQ_const)
Loc = DS.getConstSpecLoc();
- else {
- assert((TypeQuals & QualType::Volatile) &&
- "Has CV quals but not C or V?");
+ else if (TypeQuals & DeclSpec::TQ_volatile)
Loc = DS.getVolatileSpecLoc();
+ else {
+ assert((TypeQuals & DeclSpec::TQ_restrict) &&
+ "Has CVR quals but not C, V, or R?");
+ Loc = DS.getRestrictSpecLoc();
}
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
@@ -330,19 +376,23 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS,
// 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);
+ TypeQuals &= ~DeclSpec::TQ_const;
+ TypeQuals &= ~DeclSpec::TQ_volatile;
+ }
+
+ Qualifiers Quals = Qualifiers::fromCVRMask(TypeQuals);
+ Result = Context.getQualifiedType(Result, Quals);
}
+
+ if (SourceTy.isNull())
+ SourceTy = Result;
return Result;
}
static std::string getPrintableNameForEntity(DeclarationName Entity) {
if (Entity)
return Entity.getAsString();
-
+
return "type name";
}
@@ -361,7 +411,7 @@ static std::string getPrintableNameForEntity(DeclarationName Entity) {
///
/// \returns A suitable pointer type, if there are no
/// errors. Otherwise, returns a NULL type.
-QualType Sema::BuildPointerType(QualType T, unsigned Quals,
+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 ...
@@ -370,23 +420,25 @@ QualType Sema::BuildPointerType(QualType T, unsigned Quals,
return QualType();
}
+ Qualifiers Qs = Qualifiers::fromCVRMask(Quals);
+
// 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()) {
+ if (Qs.hasRestrict() && !T->isIncompleteOrObjectType()) {
Diag(Loc, diag::err_typecheck_invalid_restrict_invalid_pointee)
<< T;
- Quals &= ~QualType::Restrict;
+ Qs.removeRestrict();
}
// Build the pointer type.
- return Context.getPointerType(T).getQualifiedType(Quals);
+ return Context.getQualifiedType(Context.getPointerType(T), Qs);
}
/// \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 CVR 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
@@ -397,22 +449,23 @@ QualType Sema::BuildPointerType(QualType T, unsigned Quals,
///
/// \returns A suitable reference type, if there are no
/// errors. Otherwise, returns a NULL type.
-QualType Sema::BuildReferenceType(QualType T, bool LValueRef, unsigned Quals,
+QualType Sema::BuildReferenceType(QualType T, bool LValueRef, unsigned CVR,
SourceLocation Loc, DeclarationName Entity) {
+ Qualifiers Quals = Qualifiers::fromCVRMask(CVR);
if (LValueRef) {
- if (const RValueReferenceType *R = T->getAsRValueReferenceType()) {
+ if (const RValueReferenceType *R = T->getAs<RValueReferenceType>()) {
// 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());
+ QualType LVRT = Context.getLValueReferenceType(R->getPointeeType());
+ return Context.getQualifiedType(LVRT, T.getQualifiers());
}
}
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:
@@ -420,7 +473,7 @@ QualType Sema::BuildReferenceType(QualType T, bool LValueRef, unsigned Quals,
// typedef int& intref;
// typedef intref& intref2;
//
- // Parser::ParserDeclaratorInternal diagnoses the case where
+ // Parser::ParseDeclaratorInternal 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.
@@ -428,7 +481,7 @@ QualType Sema::BuildReferenceType(QualType T, bool LValueRef, unsigned Quals,
}
// C++ [dcl.ref]p1:
- // A declarator that specifies the type “reference to cv void”
+ // A declarator that specifies the type "reference to cv void"
// is ill-formed.
if (T->isVoidType()) {
Diag(Loc, diag::err_reference_to_void);
@@ -437,10 +490,10 @@ QualType Sema::BuildReferenceType(QualType T, bool LValueRef, unsigned Quals,
// 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()) {
+ if (Quals.hasRestrict() && !T->isIncompleteOrObjectType()) {
Diag(Loc, diag::err_typecheck_invalid_restrict_invalid_pointee)
<< T;
- Quals &= ~QualType::Restrict;
+ Quals.removeRestrict();
}
// C++ [dcl.ref]p1:
@@ -452,13 +505,13 @@ QualType Sema::BuildReferenceType(QualType T, bool LValueRef, unsigned Quals,
// 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;
+ Quals.removeConst();
+ Quals.removeVolatile();
// Handle restrict on references.
if (LValueRef)
- return Context.getLValueReferenceType(T).getQualifiedType(Quals);
- return Context.getRValueReferenceType(T).getQualifiedType(Quals);
+ return Context.getQualifiedType(Context.getLValueReferenceType(T), Quals);
+ return Context.getQualifiedType(Context.getRValueReferenceType(T), Quals);
}
/// \brief Build an array type.
@@ -466,8 +519,8 @@ QualType Sema::BuildReferenceType(QualType T, bool LValueRef, unsigned Quals,
/// \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 ArraySize Expression describing the size of the array.
///
/// \param Quals The cvr-qualifiers to be applied to the array's
/// element type.
@@ -483,10 +536,12 @@ QualType Sema::BuildReferenceType(QualType T, bool LValueRef, unsigned Quals,
/// 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,
+ SourceRange Brackets, DeclarationName Entity) {
+
+ SourceLocation Loc = Brackets.getBegin();
+ // 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,
+ if (RequireCompleteType(Loc, T,
diag::err_illegal_decl_array_incomplete_type))
return QualType();
@@ -495,21 +550,21 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
<< 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 (Context.getCanonicalType(T) == Context.UndeducedAutoTy) {
- Diag(Loc, diag::err_illegal_decl_array_of_auto)
+ Diag(Loc, diag::err_illegal_decl_array_of_auto)
<< getPrintableNameForEntity(Entity);
return QualType();
}
-
- if (const RecordType *EltTy = T->getAsRecordType()) {
+
+ if (const RecordType *EltTy = T->getAs<RecordType>()) {
// 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())
@@ -518,7 +573,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
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()) {
@@ -530,16 +585,16 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
llvm::APSInt ConstVal(32);
if (!ArraySize) {
if (ASM == ArrayType::Star)
- T = Context.getVariableArrayType(T, 0, ASM, Quals);
+ T = Context.getVariableArrayType(T, 0, ASM, Quals, Brackets);
else
T = Context.getIncompleteArrayType(T, ASM, Quals);
} else if (ArraySize->isValueDependent()) {
- T = Context.getDependentSizedArrayType(T, ArraySize, ASM, Quals);
+ T = Context.getDependentSizedArrayType(T, ArraySize, ASM, Quals, Brackets);
} 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);
+ T = Context.getVariableArrayType(T, ArraySize, ASM, Quals, Brackets);
} else {
// C99 6.7.5.2p1: If the expression is a constant expression, it shall
// have a value greater than zero.
@@ -554,17 +609,20 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
Diag(ArraySize->getLocStart(), diag::ext_typecheck_zero_array_size)
<< ArraySize->getSourceRange();
}
- }
- T = Context.getConstantArrayType(T, ConstVal, ASM, Quals);
+ }
+ T = Context.getConstantArrayWithExprType(T, ConstVal, ArraySize,
+ ASM, Quals, Brackets);
}
// If this is not C99, extwarn about VLA's and C99 array size modifiers.
if (!getLangOptions().C99) {
- if (ArraySize && !ArraySize->isTypeDependent() &&
- !ArraySize->isValueDependent() &&
+ if (ArraySize && !ArraySize->isTypeDependent() &&
+ !ArraySize->isValueDependent() &&
!ArraySize->isIntegerConstantExpr(Context))
- Diag(Loc, diag::ext_vla);
+ Diag(Loc, getLangOptions().CPlusPlus? diag::err_vla_cxx : diag::ext_vla);
else if (ASM != ArrayType::Normal || Quals != 0)
- Diag(Loc, diag::ext_c99_array_usage);
+ Diag(Loc,
+ getLangOptions().CPlusPlus? diag::err_c99_array_usage_cxx
+ : diag::ext_c99_array_usage);
}
return T;
@@ -573,14 +631,14 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
/// \brief Build an ext-vector type.
///
/// Run the required checks for the extended vector type.
-QualType Sema::BuildExtVectorType(QualType T, ExprArg ArraySize,
+QualType Sema::BuildExtVectorType(QualType T, ExprArg ArraySize,
SourceLocation AttrLoc) {
Expr *Arg = (Expr *)ArraySize.get();
// unlike gcc's vector_size attribute, we do not allow vectors to be defined
// in conjunction with complex types (pointers, arrays, functions, etc.).
- if (!T->isDependentType() &&
+ if (!T->isDependentType() &&
!T->isIntegerType() && !T->isRealFloatingType()) {
Diag(AttrLoc, diag::err_attribute_invalid_vector_type) << T;
return QualType();
@@ -593,25 +651,25 @@ QualType Sema::BuildExtVectorType(QualType T, ExprArg ArraySize,
<< "ext_vector_type" << Arg->getSourceRange();
return QualType();
}
-
- // unlike gcc's vector_size attribute, the size is specified as the
+
+ // 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());
-
+ unsigned vectorSize = static_cast<unsigned>(vecSize.getZExtValue());
+
if (vectorSize == 0) {
Diag(AttrLoc, diag::err_attribute_zero_size)
<< Arg->getSourceRange();
return QualType();
}
-
+
if (!T->isDependentType())
return Context.getExtVectorType(T, vectorSize);
- }
-
- return Context.getDependentSizedExtVectorType(T, ArraySize.takeAs<Expr>(),
+ }
+
+ return Context.getDependentSizedExtVectorType(T, ArraySize.takeAs<Expr>(),
AttrLoc);
}
-
+
/// \brief Build a function type.
///
/// This routine checks the function type according to C++ rules and
@@ -642,7 +700,7 @@ QualType Sema::BuildExtVectorType(QualType T, ExprArg ArraySize,
/// \returns A suitable function type, if there are no
/// errors. Otherwise, returns a NULL type.
QualType Sema::BuildFunctionType(QualType T,
- QualType *ParamTypes,
+ QualType *ParamTypes,
unsigned NumParamTypes,
bool Variadic, unsigned Quals,
SourceLocation Loc, DeclarationName Entity) {
@@ -650,7 +708,7 @@ QualType Sema::BuildFunctionType(QualType T,
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]);
@@ -659,29 +717,31 @@ QualType Sema::BuildFunctionType(QualType T,
Invalid = true;
}
- ParamTypes[Idx] = ParamType;
+ ParamTypes[Idx] = adjustFunctionParamType(ParamType);
}
if (Invalid)
return QualType();
- return Context.getFunctionType(T, ParamTypes, NumParamTypes, Variadic,
+ return Context.getFunctionType(T, ParamTypes, NumParamTypes, Variadic,
Quals);
}
-
+
/// \brief Build a member pointer type \c T Class::*.
///
/// \param T the type to which the member pointer refers.
/// \param Class the class type into which the member pointer points.
-/// \param Quals Qualifiers applied to the member pointer type
+/// \param CVR Qualifiers applied to the member pointer type
/// \param Loc the location where this type begins
/// \param Entity the name of the entity that will have this member pointer type
///
/// \returns a member pointer type, if successful, or a NULL type if there was
/// an error.
-QualType Sema::BuildMemberPointerType(QualType T, QualType Class,
- unsigned Quals, SourceLocation Loc,
+QualType Sema::BuildMemberPointerType(QualType T, QualType Class,
+ unsigned CVR, SourceLocation Loc,
DeclarationName Entity) {
+ Qualifiers Quals = Qualifiers::fromCVRMask(CVR);
+
// Verify that we're not building a pointer to pointer to function with
// exception specification.
if (CheckDistantExceptionSpec(T)) {
@@ -711,13 +771,13 @@ QualType Sema::BuildMemberPointerType(QualType T, QualType Class,
// 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()) {
+ if (Quals.hasRestrict() && !T->isIncompleteOrObjectType()) {
Diag(Loc, diag::err_typecheck_invalid_restrict_invalid_pointee)
<< T;
// FIXME: If we're doing this as part of template instantiation,
// we should return immediately.
- Quals &= ~QualType::Restrict;
+ Quals.removeRestrict();
}
if (!Class->isDependentType() && !Class->isRecordType()) {
@@ -725,15 +785,15 @@ QualType Sema::BuildMemberPointerType(QualType T, QualType Class,
return QualType();
}
- return Context.getMemberPointerType(T, Class.getTypePtr())
- .getQualifiedType(Quals);
+ return Context.getQualifiedType(
+ Context.getMemberPointerType(T, Class.getTypePtr()), Quals);
}
-
+
/// \brief Build a block pointer type.
///
/// \param T The type to which we'll be building a block pointer.
///
-/// \param Quals The cvr-qualifiers to be applied to the block pointer type.
+/// \param CVR The cvr-qualifiers to be applied to the block pointer type.
///
/// \param Loc The location of the entity whose type involves this
/// block pointer type or, if there is no such entity, the location of the
@@ -744,15 +804,28 @@ QualType Sema::BuildMemberPointerType(QualType T, QualType Class,
///
/// \returns A suitable block pointer type, if there are no
/// errors. Otherwise, returns a NULL type.
-QualType Sema::BuildBlockPointerType(QualType T, unsigned Quals,
- SourceLocation Loc,
+QualType Sema::BuildBlockPointerType(QualType T, unsigned CVR,
+ SourceLocation Loc,
DeclarationName Entity) {
- if (!T.getTypePtr()->isFunctionType()) {
+ if (!T->isFunctionType()) {
Diag(Loc, diag::err_nonfunction_block_type);
return QualType();
}
-
- return Context.getBlockPointerType(T).getQualifiedType(Quals);
+
+ Qualifiers Quals = Qualifiers::fromCVRMask(CVR);
+ return Context.getQualifiedType(Context.getBlockPointerType(T), Quals);
+}
+
+QualType Sema::GetTypeFromParser(TypeTy *Ty, DeclaratorInfo **DInfo) {
+ QualType QT = QualType::getFromOpaquePtr(Ty);
+ DeclaratorInfo *DI = 0;
+ if (LocInfoType *LIT = dyn_cast<LocInfoType>(QT)) {
+ QT = LIT->getType();
+ DI = LIT->getDeclaratorInfo();
+ }
+
+ if (DInfo) *DInfo = DI;
+ return QT;
}
/// GetTypeForDeclarator - Convert the type for the specified
@@ -762,7 +835,8 @@ QualType Sema::BuildBlockPointerType(QualType T, unsigned Quals,
/// 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,
+QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
+ DeclaratorInfo **DInfo, unsigned Skip,
TagDecl **OwnedDecl) {
bool OmittedReturnType = false;
@@ -782,10 +856,15 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
// Determine the type of the declarator. Not all forms of declarator
// have a type.
QualType T;
+ // The QualType referring to the type as written in source code. We can't use
+ // T because it can change due to semantic analysis.
+ QualType SourceTy;
+
switch (D.getKind()) {
case Declarator::DK_Abstract:
case Declarator::DK_Normal:
- case Declarator::DK_Operator: {
+ case Declarator::DK_Operator:
+ case Declarator::DK_TemplateId: {
const DeclSpec &DS = D.getDeclSpec();
if (OmittedReturnType) {
// We default to a dependent type initially. Can be modified by
@@ -793,7 +872,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
T = Context.DependentTy;
} else {
bool isInvalid = false;
- T = ConvertDeclSpecToType(DS, D.getIdentifierLoc(), isInvalid);
+ T = ConvertDeclSpecToType(DS, D.getIdentifierLoc(), isInvalid, SourceTy);
if (isInvalid)
D.setInvalidType(true);
else if (OwnedDecl && DS.isTypeSpecOwned())
@@ -811,10 +890,13 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
T = Context.VoidTy;
break;
}
+
+ if (SourceTy.isNull())
+ SourceTy = T;
if (T == Context.UndeducedAutoTy) {
int Error = -1;
-
+
switch (D.getContext()) {
case Declarator::KNRTypeListContext:
assert(0 && "K&R type lists aren't allowed in C++");
@@ -828,7 +910,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
case TagDecl::TK_struct: Error = 1; /* Struct member */ break;
case TagDecl::TK_union: Error = 2; /* Union member */ break;
case TagDecl::TK_class: Error = 3; /* Class member */ break;
- }
+ }
break;
case Declarator::CXXCatchContext:
Error = 4; // Exception declaration
@@ -854,12 +936,14 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
D.setInvalidType(true);
}
}
-
+
// The name we're declaring, if any.
DeclarationName Name;
if (D.getIdentifier())
Name = D.getIdentifier();
+ bool ShouldBuildInfo = DInfo != 0;
+
// Walk the DeclTypeInfo, building the recursive type as we go.
// DeclTypeInfos are ordered from the identifier out, which is
// opposite of what we want :).
@@ -868,14 +952,29 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
switch (DeclType.Kind) {
default: assert(0 && "Unknown decltype!");
case DeclaratorChunk::BlockPointer:
+ if (ShouldBuildInfo) {
+ if (SourceTy->isFunctionType())
+ SourceTy
+ = Context.getQualifiedType(Context.getBlockPointerType(SourceTy),
+ Qualifiers::fromCVRMask(DeclType.Cls.TypeQuals));
+ else
+ // If not function type Context::getBlockPointerType asserts,
+ // so just give up.
+ ShouldBuildInfo = false;
+ }
+
// If blocks are disabled, emit an error.
if (!LangOpts.Blocks)
Diag(DeclType.Loc, diag::err_blocks_disable);
-
- T = BuildBlockPointerType(T, DeclType.Cls.TypeQuals, D.getIdentifierLoc(),
+
+ T = BuildBlockPointerType(T, DeclType.Cls.TypeQuals, D.getIdentifierLoc(),
Name);
break;
case DeclaratorChunk::Pointer:
+ //FIXME: Use ObjCObjectPointer for info when appropriate.
+ if (ShouldBuildInfo)
+ SourceTy = Context.getQualifiedType(Context.getPointerType(SourceTy),
+ Qualifiers::fromCVRMask(DeclType.Ptr.TypeQuals));
// Verify that we're not building a pointer to pointer to function with
// exception specification.
if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) {
@@ -883,9 +982,27 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
D.setInvalidType(true);
// Build the type anyway.
}
+ if (getLangOptions().ObjC1 && T->isObjCInterfaceType()) {
+ const ObjCInterfaceType *OIT = T->getAs<ObjCInterfaceType>();
+ T = Context.getObjCObjectPointerType(T,
+ (ObjCProtocolDecl **)OIT->qual_begin(),
+ OIT->getNumProtocols());
+ break;
+ }
T = BuildPointerType(T, DeclType.Ptr.TypeQuals, DeclType.Loc, Name);
break;
- case DeclaratorChunk::Reference:
+ case DeclaratorChunk::Reference: {
+ Qualifiers Quals;
+ if (DeclType.Ref.HasRestrict) Quals.addRestrict();
+
+ if (ShouldBuildInfo) {
+ if (DeclType.Ref.LValueRef)
+ SourceTy = Context.getLValueReferenceType(SourceTy);
+ else
+ SourceTy = Context.getRValueReferenceType(SourceTy);
+ SourceTy = Context.getQualifiedType(SourceTy, Quals);
+ }
+
// Verify that we're not building a reference to pointer to function with
// exception specification.
if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) {
@@ -893,11 +1010,16 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
D.setInvalidType(true);
// Build the type anyway.
}
- T = BuildReferenceType(T, DeclType.Ref.LValueRef,
- DeclType.Ref.HasRestrict ? QualType::Restrict : 0,
+ T = BuildReferenceType(T, DeclType.Ref.LValueRef, Quals,
DeclType.Loc, Name);
break;
+ }
case DeclaratorChunk::Array: {
+ if (ShouldBuildInfo)
+ // We just need to get an array type, the exact type doesn't matter.
+ SourceTy = Context.getIncompleteArrayType(SourceTy, ArrayType::Normal,
+ DeclType.Arr.TypeQuals);
+
// Verify that we're not building an array of pointers to function with
// exception specification.
if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) {
@@ -923,10 +1045,30 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
ASM = ArrayType::Normal;
D.setInvalidType(true);
}
- T = BuildArrayType(T, ASM, ArraySize, ATI.TypeQuals, DeclType.Loc, Name);
+ T = BuildArrayType(T, ASM, ArraySize,
+ Qualifiers::fromCVRMask(ATI.TypeQuals),
+ SourceRange(DeclType.Loc, DeclType.EndLoc), Name);
break;
}
case DeclaratorChunk::Function: {
+ if (ShouldBuildInfo) {
+ const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun;
+ llvm::SmallVector<QualType, 16> ArgTys;
+
+ for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) {
+ ParmVarDecl *Param = FTI.ArgInfo[i].Param.getAs<ParmVarDecl>();
+ if (Param) {
+ QualType ArgTy = adjustFunctionParamType(Param->getType());
+
+ ArgTys.push_back(ArgTy);
+ }
+ }
+ SourceTy = Context.getFunctionType(SourceTy, ArgTys.data(),
+ ArgTys.size(),
+ FTI.isVariadic,
+ FTI.TypeQuals);
+ }
+
// 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 ().
@@ -960,8 +1102,9 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
// 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);
+ for (unsigned ei = 0, ee = FTI.NumExceptions; ei != ee; ++ei) {
+ // FIXME: Preserve type source info.
+ QualType ET = GetTypeFromParser(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))
@@ -993,12 +1136,12 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
}
} 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);
+ 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>());
@@ -1027,28 +1170,29 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
Param->setType(ArgTy);
} else {
// Reject, but continue to parse 'float(const void)'.
- if (ArgTy.getCVRQualifiers())
+ if (ArgTy.hasQualifiers())
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()) {
+ ArgTy = Context.getPromotedIntegerType(ArgTy);
+ } else if (const BuiltinType* BTy = ArgTy->getAs<BuiltinType>()) {
if (BTy->getKind() == BuiltinType::Float)
ArgTy = Context.DoubleTy;
}
}
-
- ArgTys.push_back(ArgTy);
+
+ ArgTys.push_back(adjustFunctionParamType(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);
+ for (unsigned ei = 0, ee = FTI.NumExceptions; ei != ee; ++ei) {
+ // FIXME: Preserve type source info.
+ QualType ET = GetTypeFromParser(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))
@@ -1074,11 +1218,11 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
// The scope spec must refer to a class, or be dependent.
QualType ClsType;
if (isDependentScopeSpecifier(DeclType.Mem.Scope())) {
- NestedNameSpecifier *NNS
+ NestedNameSpecifier *NNS
= (NestedNameSpecifier *)DeclType.Mem.Scope().getScopeRep();
assert(NNS->getAsType() && "Nested-name-specifier must name a type");
ClsType = QualType(NNS->getAsType(), 0);
- } else if (CXXRecordDecl *RD
+ } else if (CXXRecordDecl *RD
= dyn_cast_or_null<CXXRecordDecl>(
computeDeclContext(DeclType.Mem.Scope()))) {
ClsType = Context.getTagDeclType(RD);
@@ -1090,6 +1234,13 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
D.setInvalidType(true);
}
+ if (ShouldBuildInfo) {
+ QualType cls = !ClsType.isNull() ? ClsType : Context.IntTy;
+ SourceTy = Context.getQualifiedType(
+ Context.getMemberPointerType(SourceTy, cls.getTypePtr()),
+ Qualifiers::fromCVRMask(DeclType.Mem.TypeQuals));
+ }
+
if (!ClsType.isNull())
T = BuildMemberPointerType(T, ClsType, DeclType.Mem.TypeQuals,
DeclType.Loc, D.getIdentifier());
@@ -1111,7 +1262,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
}
if (getLangOptions().CPlusPlus && T->isFunctionType()) {
- const FunctionProtoType *FnTy = T->getAsFunctionProtoType();
+ const FunctionProtoType *FnTy = T->getAs<FunctionProtoType>();
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
@@ -1122,7 +1273,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef &&
((D.getContext() != Declarator::MemberContext &&
(!D.getCXXScopeSpec().isSet() ||
- !computeDeclContext(D.getCXXScopeSpec())->isRecord())) ||
+ !computeDeclContext(D.getCXXScopeSpec(), /*FIXME:*/true)
+ ->isRecord())) ||
D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)) {
if (D.isFunctionDeclarator())
Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_function_type);
@@ -1135,103 +1287,130 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
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);
-
+
+ if (ShouldBuildInfo)
+ *DInfo = GetDeclaratorInfoForDeclarator(D, SourceTy, Skip);
+
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;
+static void FillTypeSpecLoc(TypeLoc TSL, const DeclSpec &DS) {
+ if (TSL.isNull()) return;
- if (T->isIncompleteType() && !T->isVoidType())
- return Diag(Range.getBegin(), diag::err_incomplete_in_exception_spec)
- << Range << T << /*indirect*/kind;
+ if (TypedefLoc *TL = dyn_cast<TypedefLoc>(&TSL)) {
+ TL->setNameLoc(DS.getTypeSpecTypeLoc());
- return false;
-}
+ } else if (ObjCInterfaceLoc *TL = dyn_cast<ObjCInterfaceLoc>(&TSL)) {
+ TL->setNameLoc(DS.getTypeSpecTypeLoc());
-/// 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;
+ } else if (ObjCProtocolListLoc *PLL = dyn_cast<ObjCProtocolListLoc>(&TSL)) {
+ assert(PLL->getNumProtocols() == DS.getNumProtocolQualifiers());
+ PLL->setLAngleLoc(DS.getProtocolLAngleLoc());
+ PLL->setRAngleLoc(DS.getSourceRange().getEnd());
+ for (unsigned i = 0; i != DS.getNumProtocolQualifiers(); ++i)
+ PLL->setProtocolLoc(i, DS.getProtocolLocs()[i]);
+ FillTypeSpecLoc(PLL->getBaseTypeLoc(), DS);
- const FunctionProtoType *FnT = T->getAsFunctionProtoType();
- if (!FnT)
- return false;
-
- return FnT->hasExceptionSpec();
+ } else {
+ //FIXME: Other typespecs.
+ DefaultTypeSpecLoc &DTL = cast<DefaultTypeSpecLoc>(TSL);
+ DTL.setStartLoc(DS.getSourceRange().getBegin());
+ }
}
-/// CheckEquivalentExceptionSpec - Check if the two types have equivalent
-/// exception specifications. Exception specifications are equivalent if
-/// they allow exactly the same set of exception types. It does not matter how
-/// that is achieved. See C++ [except.spec]p2.
-bool Sema::CheckEquivalentExceptionSpec(
- const FunctionProtoType *Old, SourceLocation OldLoc,
- const FunctionProtoType *New, SourceLocation NewLoc) {
- bool OldAny = !Old->hasExceptionSpec() || Old->hasAnyExceptionSpec();
- bool NewAny = !New->hasExceptionSpec() || New->hasAnyExceptionSpec();
- if (OldAny && NewAny)
- return false;
- if (OldAny || NewAny) {
- Diag(NewLoc, diag::err_mismatched_exception_spec);
- Diag(OldLoc, diag::note_previous_declaration);
- return true;
- }
+/// \brief Create and instantiate a DeclaratorInfo with type source information.
+///
+/// \param T QualType referring to the type as written in source code.
+DeclaratorInfo *
+Sema::GetDeclaratorInfoForDeclarator(Declarator &D, QualType T, unsigned Skip) {
+ DeclaratorInfo *DInfo = Context.CreateDeclaratorInfo(T);
+ TypeLoc CurrTL = DInfo->getTypeLoc();
- bool Success = true;
- // Both have a definite exception spec. Collect the first set, then compare
- // to the second.
- llvm::SmallPtrSet<const Type*, 8> Types;
- for (FunctionProtoType::exception_iterator I = Old->exception_begin(),
- E = Old->exception_end(); I != E; ++I)
- Types.insert(Context.getCanonicalType(*I).getTypePtr());
+ for (unsigned i = Skip, e = D.getNumTypeObjects(); i != e; ++i) {
+ assert(!CurrTL.isNull());
- for (FunctionProtoType::exception_iterator I = New->exception_begin(),
- E = New->exception_end(); I != E && Success; ++I)
- Success = Types.erase(Context.getCanonicalType(*I).getTypePtr());
+ DeclaratorChunk &DeclType = D.getTypeObject(i);
+ switch (DeclType.Kind) {
+ default: assert(0 && "Unknown decltype!");
+ case DeclaratorChunk::BlockPointer: {
+ BlockPointerLoc &BPL = cast<BlockPointerLoc>(CurrTL);
+ BPL.setCaretLoc(DeclType.Loc);
+ break;
+ }
+ case DeclaratorChunk::Pointer: {
+ //FIXME: ObjCObject pointers.
+ PointerLoc &PL = cast<PointerLoc>(CurrTL);
+ PL.setStarLoc(DeclType.Loc);
+ break;
+ }
+ case DeclaratorChunk::Reference: {
+ ReferenceLoc &RL = cast<ReferenceLoc>(CurrTL);
+ RL.setAmpLoc(DeclType.Loc);
+ break;
+ }
+ case DeclaratorChunk::Array: {
+ DeclaratorChunk::ArrayTypeInfo &ATI = DeclType.Arr;
+ ArrayLoc &AL = cast<ArrayLoc>(CurrTL);
+ AL.setLBracketLoc(DeclType.Loc);
+ AL.setRBracketLoc(DeclType.EndLoc);
+ AL.setSizeExpr(static_cast<Expr*>(ATI.NumElts));
+ //FIXME: Star location for [*].
+ break;
+ }
+ case DeclaratorChunk::Function: {
+ const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun;
+ FunctionLoc &FL = cast<FunctionLoc>(CurrTL);
+ FL.setLParenLoc(DeclType.Loc);
+ FL.setRParenLoc(DeclType.EndLoc);
+ for (unsigned i = 0, e = FTI.NumArgs, tpi = 0; i != e; ++i) {
+ ParmVarDecl *Param = FTI.ArgInfo[i].Param.getAs<ParmVarDecl>();
+ if (Param) {
+ assert(tpi < FL.getNumArgs());
+ FL.setArg(tpi++, Param);
+ }
+ }
+ break;
+ //FIXME: Exception specs.
+ }
+ case DeclaratorChunk::MemberPointer: {
+ MemberPointerLoc &MPL = cast<MemberPointerLoc>(CurrTL);
+ MPL.setStarLoc(DeclType.Loc);
+ //FIXME: Class location.
+ break;
+ }
- Success = Success && Types.empty();
+ }
- if (Success) {
- return false;
+ CurrTL = CurrTL.getNextTypeLoc();
}
- Diag(NewLoc, diag::err_mismatched_exception_spec);
- Diag(OldLoc, diag::note_previous_declaration);
- return true;
+
+ FillTypeSpecLoc(CurrTL, D.getDeclSpec());
+
+ return DInfo;
+}
+
+/// \brief Create a LocInfoType to hold the given QualType and DeclaratorInfo.
+QualType Sema::CreateLocInfoType(QualType T, DeclaratorInfo *DInfo) {
+ // FIXME: LocInfoTypes are "transient", only needed for passing to/from Parser
+ // and Sema during declaration parsing. Try deallocating/caching them when
+ // it's appropriate, instead of allocating them and keeping them around.
+ LocInfoType *LocT = (LocInfoType*)BumpAlloc.Allocate(sizeof(LocInfoType), 8);
+ new (LocT) LocInfoType(T, DInfo);
+ assert(LocT->getTypeClass() != T->getTypeClass() &&
+ "LocInfoType's TypeClass conflicts with an existing Type class");
+ return QualType(LocT, 0);
+}
+
+void LocInfoType::getAsStringInternal(std::string &Str,
+ const PrintingPolicy &Policy) const {
+ assert(false && "LocInfoType leaked into the type system; an opaque TypeTy*"
+ " was used directly instead of getting the QualType through"
+ " GetTypeFromParser");
}
/// ObjCGetTypeForMethodDefinition - Builds the type for a method definition
@@ -1240,7 +1419,7 @@ 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());
@@ -1249,7 +1428,7 @@ QualType Sema::ObjCGetTypeForMethodDefinition(DeclPtrTy D) {
} 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();
@@ -1271,16 +1450,16 @@ QualType Sema::ObjCGetTypeForMethodDefinition(DeclPtrTy D) {
/// 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();
+ const PointerType *T1PtrType = T1->getAs<PointerType>(),
+ *T2PtrType = T2->getAs<PointerType>();
if (T1PtrType && T2PtrType) {
T1 = T1PtrType->getPointeeType();
T2 = T2PtrType->getPointeeType();
return true;
}
- const MemberPointerType *T1MPType = T1->getAsMemberPointerType(),
- *T2MPType = T2->getAsMemberPointerType();
+ const MemberPointerType *T1MPType = T1->getAs<MemberPointerType>(),
+ *T2MPType = T2->getAs<MemberPointerType>();
if (T1MPType && T2MPType &&
Context.getCanonicalType(T1MPType->getClass()) ==
Context.getCanonicalType(T2MPType->getClass())) {
@@ -1295,9 +1474,10 @@ 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!");
-
+
+ DeclaratorInfo *DInfo = 0;
TagDecl *OwnedTag = 0;
- QualType T = GetTypeForDeclarator(D, S, /*Skip=*/0, &OwnedTag);
+ QualType T = GetTypeForDeclarator(D, S, &DInfo, /*Skip=*/0, &OwnedTag);
if (D.isInvalidType())
return true;
@@ -1314,6 +1494,9 @@ Sema::TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) {
<< Context.getTypeDeclType(OwnedTag);
}
+ if (DInfo)
+ T = CreateLocInfoType(T, DInfo);
+
return T.getAsOpaquePtr();
}
@@ -1326,8 +1509,9 @@ Sema::TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) {
/// 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,
+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."
@@ -1335,7 +1519,7 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
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;
@@ -1349,43 +1533,76 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
return;
}
- unsigned ASIdx = static_cast<unsigned>(addrSpace.getZExtValue());
+ // Bounds checking.
+ if (addrSpace.isSigned()) {
+ if (addrSpace.isNegative()) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_address_space_negative)
+ << ASArgExpr->getSourceRange();
+ return;
+ }
+ addrSpace.setIsSigned(false);
+ }
+ llvm::APSInt max(addrSpace.getBitWidth());
+ max = Qualifiers::MaxAddressSpace;
+ if (addrSpace > max) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_address_space_too_high)
+ << Qualifiers::MaxAddressSpace << 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,
+static void HandleObjCGCTypeAttribute(QualType &Type,
const AttributeList &Attr, Sema &S) {
- if (Type.getObjCGCAttr() != QualType::GCNone) {
+ if (Type.getObjCGCAttr() != Qualifiers::GCNone) {
S.Diag(Attr.getLoc(), diag::err_attribute_multiple_objc_gc);
return;
}
-
+
// Check the attribute arguments.
- if (!Attr.getParameterName()) {
+ if (!Attr.getParameterName()) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
<< "objc_gc" << 1;
return;
}
- QualType::GCAttrTypes GCAttr;
+ Qualifiers::GC 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;
+ if (Attr.getParameterName()->isStr("weak"))
+ GCAttr = Qualifiers::Weak;
else if (Attr.getParameterName()->isStr("strong"))
- GCAttr = QualType::Strong;
+ GCAttr = Qualifiers::Strong;
else {
S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported)
<< "objc_gc" << Attr.getParameterName();
return;
}
-
+
Type = S.Context.getObjCGCQualType(Type, GCAttr);
}
+/// HandleNoReturnTypeAttribute - Process the noreturn attribute on the
+/// specified type. The attribute contains 0 arguments.
+static void HandleNoReturnTypeAttribute(QualType &Type,
+ const AttributeList &Attr, Sema &S) {
+ if (Attr.getNumArgs() != 0)
+ return;
+
+ // We only apply this to a pointer to function or a pointer to block.
+ if (!Type->isFunctionPointerType()
+ && !Type->isBlockPointerType()
+ && !Type->isFunctionType())
+ return;
+
+ Type = S.Context.getNoReturnType(Type);
+}
+
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
@@ -1402,11 +1619,14 @@ void Sema::ProcessTypeAttributeList(QualType &Result, const AttributeList *AL) {
case AttributeList::AT_objc_gc:
HandleObjCGCTypeAttribute(Result, *AL, *this);
break;
+ case AttributeList::AT_noreturn:
+ HandleNoReturnTypeAttribute(Result, *AL, *this);
+ break;
}
}
}
-/// @brief Ensure that the type T is a complete type.
+/// @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
@@ -1421,31 +1641,21 @@ void Sema::ProcessTypeAttributeList(QualType &Result, const AttributeList *AL) {
///
/// @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.
+/// @param PD The partial diagnostic that will be printed out if T is not a
+/// complete type.
///
/// @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) {
+bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
+ const PartialDiagnostic &PD,
+ std::pair<SourceLocation,
+ PartialDiagnostic> Note) {
+ unsigned diag = PD.getDiagID();
+
// FIXME: Add this assertion to help us flush out problems with
// checking for dependent types and type-dependent expressions.
//
- // assert(!T->isDependentType() &&
+ // assert(!T->isDependentType() &&
// "Can't ask whether a dependent type is complete");
// If we have a complete type, we're done.
@@ -1454,49 +1664,54 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, unsigned diag,
// 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 (const RecordType *Record = T->getAs<RecordType>()) {
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);
+ ClassTemplateSpec->setPointOfInstantiation(Loc);
return InstantiateClassTemplateSpecialization(ClassTemplateSpec,
- /*ExplicitInstantiation=*/false);
+ TSK_ImplicitInstantiation,
+ /*Complain=*/diag != 0);
}
- } else if (CXXRecordDecl *Rec
+ } 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);
+ MemberSpecializationInfo *MSInfo = Rec->getMemberSpecializationInfo();
+ assert(MSInfo && "Missing member specialization information?");
+ // This record was instantiated from a class within a template.
+ if (MSInfo->getTemplateSpecializationKind()
+ != TSK_ExplicitSpecialization) {
+ MSInfo->setPointOfInstantiation(Loc);
+ return InstantiateClass(Loc, Rec, Pattern,
+ getTemplateInstantiationArgs(Rec),
+ TSK_ImplicitInstantiation,
+ /*Complain=*/diag != 0);
+ }
}
}
}
- if (PrintType.isNull())
- PrintType = T;
+ if (diag == 0)
+ return true;
// We have an incomplete type. Produce a diagnostic.
- Diag(Loc, diag) << PrintType << Range1 << Range2;
+ Diag(Loc, PD) << T;
+ // If we have a note, produce it.
+ if (!Note.first.isInvalid())
+ Diag(Note.first, Note.second);
+
// If the type was a forward declaration of a class/struct/union
- // type, produce
+ // type, produce
const TagType *Tag = 0;
- if (const RecordType *Record = T->getAsRecordType())
+ if (const RecordType *Record = T->getAs<RecordType>())
Tag = Record;
- else if (const EnumType *Enum = T->getAsEnumType())
+ else if (const EnumType *Enum = T->getAs<EnumType>())
Tag = Enum;
if (Tag && !Tag->getDecl()->isInvalidDecl())
- Diag(Tag->getDecl()->getLocation(),
+ Diag(Tag->getDecl()->getLocation(),
Tag->isBeingDefined() ? diag::note_type_being_defined
: diag::note_forward_declaration)
<< QualType(Tag, 0);
@@ -1509,7 +1724,7 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, unsigned diag,
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);
@@ -1521,7 +1736,7 @@ QualType Sema::BuildTypeofExprType(Expr *E) {
QualType Sema::BuildDecltypeType(Expr *E) {
if (E->getType() == Context.OverloadTy) {
- Diag(E->getLocStart(),
+ Diag(E->getLocStart(),
diag::err_cannot_determine_declared_type_of_overloaded_function);
return QualType();
}
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
new file mode 100644
index 0000000..ec5c667
--- /dev/null
+++ b/lib/Sema/TreeTransform.h
@@ -0,0 +1,4829 @@
+//===------- TreeTransform.h - Semantic Tree Transformation ---------------===/
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//===----------------------------------------------------------------------===/
+//
+// This file implements a semantic tree transformation that takes a given
+// AST and rebuilds it, possibly transforming some nodes in the process.
+//
+//===----------------------------------------------------------------------===/
+#ifndef LLVM_CLANG_SEMA_TREETRANSFORM_H
+#define LLVM_CLANG_SEMA_TREETRANSFORM_H
+
+#include "Sema.h"
+#include "clang/Sema/SemaDiagnostic.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/AST/Stmt.h"
+#include "clang/AST/StmtCXX.h"
+#include "clang/AST/StmtObjC.h"
+#include "clang/Parse/Ownership.h"
+#include "clang/Parse/Designator.h"
+#include "clang/Lex/Preprocessor.h"
+#include <algorithm>
+
+namespace clang {
+
+/// \brief A semantic tree transformation that allows one to transform one
+/// abstract syntax tree into another.
+///
+/// A new tree transformation is defined by creating a new subclass \c X of
+/// \c TreeTransform<X> and then overriding certain operations to provide
+/// behavior specific to that transformation. For example, template
+/// instantiation is implemented as a tree transformation where the
+/// transformation of TemplateTypeParmType nodes involves substituting the
+/// template arguments for their corresponding template parameters; a similar
+/// transformation is performed for non-type template parameters and
+/// template template parameters.
+///
+/// This tree-transformation template uses static polymorphism to allow
+/// subclasses to customize any of its operations. Thus, a subclass can
+/// override any of the transformation or rebuild operators by providing an
+/// operation with the same signature as the default implementation. The
+/// overridding function should not be virtual.
+///
+/// Semantic tree transformations are split into two stages, either of which
+/// can be replaced by a subclass. The "transform" step transforms an AST node
+/// or the parts of an AST node using the various transformation functions,
+/// then passes the pieces on to the "rebuild" step, which constructs a new AST
+/// node of the appropriate kind from the pieces. The default transformation
+/// routines recursively transform the operands to composite AST nodes (e.g.,
+/// the pointee type of a PointerType node) and, if any of those operand nodes
+/// were changed by the transformation, invokes the rebuild operation to create
+/// a new AST node.
+///
+/// Subclasses can customize the transformation at various levels. The
+/// most coarse-grained transformations involve replacing TransformType(),
+/// TransformExpr(), TransformDecl(), TransformNestedNameSpecifier(),
+/// TransformTemplateName(), or TransformTemplateArgument() with entirely
+/// new implementations.
+///
+/// For more fine-grained transformations, subclasses can replace any of the
+/// \c TransformXXX functions (where XXX is the name of an AST node, e.g.,
+/// PointerType, StmtExpr) to alter the transformation. As mentioned previously,
+/// replacing TransformTemplateTypeParmType() allows template instantiation
+/// to substitute template arguments for their corresponding template
+/// parameters. Additionally, subclasses can override the \c RebuildXXX
+/// functions to control how AST nodes are rebuilt when their operands change.
+/// By default, \c TreeTransform will invoke semantic analysis to rebuild
+/// AST nodes. However, certain other tree transformations (e.g, cloning) may
+/// be able to use more efficient rebuild steps.
+///
+/// There are a handful of other functions that can be overridden, allowing one
+/// to avoid traversing nodes that don't need any transformation
+/// (\c AlreadyTransformed()), force rebuilding AST nodes even when their
+/// operands have not changed (\c AlwaysRebuild()), and customize the
+/// default locations and entity names used for type-checking
+/// (\c getBaseLocation(), \c getBaseEntity()).
+template<typename Derived>
+class TreeTransform {
+protected:
+ Sema &SemaRef;
+
+public:
+ typedef Sema::OwningStmtResult OwningStmtResult;
+ typedef Sema::OwningExprResult OwningExprResult;
+ typedef Sema::StmtArg StmtArg;
+ typedef Sema::ExprArg ExprArg;
+ typedef Sema::MultiExprArg MultiExprArg;
+ typedef Sema::MultiStmtArg MultiStmtArg;
+
+ /// \brief Initializes a new tree transformer.
+ TreeTransform(Sema &SemaRef) : SemaRef(SemaRef) { }
+
+ /// \brief Retrieves a reference to the derived class.
+ Derived &getDerived() { return static_cast<Derived&>(*this); }
+
+ /// \brief Retrieves a reference to the derived class.
+ const Derived &getDerived() const {
+ return static_cast<const Derived&>(*this);
+ }
+
+ /// \brief Retrieves a reference to the semantic analysis object used for
+ /// this tree transform.
+ Sema &getSema() const { return SemaRef; }
+
+ /// \brief Whether the transformation should always rebuild AST nodes, even
+ /// if none of the children have changed.
+ ///
+ /// Subclasses may override this function to specify when the transformation
+ /// should rebuild all AST nodes.
+ bool AlwaysRebuild() { return false; }
+
+ /// \brief Returns the location of the entity being transformed, if that
+ /// information was not available elsewhere in the AST.
+ ///
+ /// By default, returns no source-location information. Subclasses can
+ /// provide an alternative implementation that provides better location
+ /// information.
+ SourceLocation getBaseLocation() { return SourceLocation(); }
+
+ /// \brief Returns the name of the entity being transformed, if that
+ /// information was not available elsewhere in the AST.
+ ///
+ /// By default, returns an empty name. Subclasses can provide an alternative
+ /// implementation with a more precise name.
+ DeclarationName getBaseEntity() { return DeclarationName(); }
+
+ /// \brief Sets the "base" location and entity when that
+ /// information is known based on another transformation.
+ ///
+ /// By default, the source location and entity are ignored. Subclasses can
+ /// override this function to provide a customized implementation.
+ void setBase(SourceLocation Loc, DeclarationName Entity) { }
+
+ /// \brief RAII object that temporarily sets the base location and entity
+ /// used for reporting diagnostics in types.
+ class TemporaryBase {
+ TreeTransform &Self;
+ SourceLocation OldLocation;
+ DeclarationName OldEntity;
+
+ public:
+ TemporaryBase(TreeTransform &Self, SourceLocation Location,
+ DeclarationName Entity) : Self(Self) {
+ OldLocation = Self.getDerived().getBaseLocation();
+ OldEntity = Self.getDerived().getBaseEntity();
+ Self.getDerived().setBase(Location, Entity);
+ }
+
+ ~TemporaryBase() {
+ Self.getDerived().setBase(OldLocation, OldEntity);
+ }
+ };
+
+ /// \brief Determine whether the given type \p T has already been
+ /// transformed.
+ ///
+ /// Subclasses can provide an alternative implementation of this routine
+ /// to short-circuit evaluation when it is known that a given type will
+ /// not change. For example, template instantiation need not traverse
+ /// non-dependent types.
+ bool AlreadyTransformed(QualType T) {
+ return T.isNull();
+ }
+
+ /// \brief Transforms the given type into another type.
+ ///
+ /// By default, this routine transforms a type by delegating to the
+ /// appropriate TransformXXXType to build a new type, then applying
+ /// the qualifiers on \p T to the resulting type with AddTypeQualifiers.
+ /// Subclasses may override this function (to take over all type
+ /// transformations), some set of the TransformXXXType functions, or
+ /// the AddTypeQualifiers function to alter the transformation.
+ ///
+ /// \returns the transformed type.
+ QualType TransformType(QualType T);
+
+ /// \brief Transform the given type by adding the given set of qualifiers
+ /// and returning the result.
+ ///
+ /// FIXME: By default, this routine adds type qualifiers only to types that
+ /// can have qualifiers, and silently suppresses those qualifiers that are
+ /// not permitted (e.g., qualifiers on reference or function types). This
+ /// is the right thing for template instantiation, but probably not for
+ /// other clients.
+ QualType AddTypeQualifiers(QualType T, Qualifiers Qs);
+
+ /// \brief Transform the given statement.
+ ///
+ /// By default, this routine transforms a statement by delegating to the
+ /// appropriate TransformXXXStmt function to transform a specific kind of
+ /// statement or the TransformExpr() function to transform an expression.
+ /// Subclasses may override this function to transform statements using some
+ /// other mechanism.
+ ///
+ /// \returns the transformed statement.
+ OwningStmtResult TransformStmt(Stmt *S);
+
+ /// \brief Transform the given expression.
+ ///
+ /// By default, this routine transforms an expression by delegating to the
+ /// appropriate TransformXXXExpr function to build a new expression.
+ /// Subclasses may override this function to transform expressions using some
+ /// other mechanism.
+ ///
+ /// \returns the transformed expression.
+ OwningExprResult TransformExpr(Expr *E) {
+ return getDerived().TransformExpr(E, /*isAddressOfOperand=*/false);
+ }
+
+ /// \brief Transform the given expression.
+ ///
+ /// By default, this routine transforms an expression by delegating to the
+ /// appropriate TransformXXXExpr function to build a new expression.
+ /// Subclasses may override this function to transform expressions using some
+ /// other mechanism.
+ ///
+ /// \returns the transformed expression.
+ OwningExprResult TransformExpr(Expr *E, bool isAddressOfOperand);
+
+ /// \brief Transform the given declaration, which is referenced from a type
+ /// or expression.
+ ///
+ /// By default, acts as the identity function on declarations. Subclasses
+ /// may override this function to provide alternate behavior.
+ Decl *TransformDecl(Decl *D) { return D; }
+
+ /// \brief Transform the definition of the given declaration.
+ ///
+ /// By default, invokes TransformDecl() to transform the declaration.
+ /// Subclasses may override this function to provide alternate behavior.
+ Decl *TransformDefinition(Decl *D) { return getDerived().TransformDecl(D); }
+
+ /// \brief Transform the given nested-name-specifier.
+ ///
+ /// By default, transforms all of the types and declarations within the
+ /// nested-name-specifier. Subclasses may override this function to provide
+ /// alternate behavior.
+ NestedNameSpecifier *TransformNestedNameSpecifier(NestedNameSpecifier *NNS,
+ SourceRange Range,
+ QualType ObjectType = QualType(),
+ NamedDecl *FirstQualifierInScope = 0);
+
+ /// \brief Transform the given declaration name.
+ ///
+ /// By default, transforms the types of conversion function, constructor,
+ /// and destructor names and then (if needed) rebuilds the declaration name.
+ /// Identifiers and selectors are returned unmodified. Sublcasses may
+ /// override this function to provide alternate behavior.
+ DeclarationName TransformDeclarationName(DeclarationName Name,
+ SourceLocation Loc);
+
+ /// \brief Transform the given template name.
+ ///
+ /// By default, transforms the template name by transforming the declarations
+ /// and nested-name-specifiers that occur within the template name.
+ /// Subclasses may override this function to provide alternate behavior.
+ TemplateName TransformTemplateName(TemplateName Name,
+ QualType ObjectType = QualType());
+
+ /// \brief Transform the given template argument.
+ ///
+ /// By default, this operation transforms the type, expression, or
+ /// declaration stored within the template argument and constructs a
+ /// new template argument from the transformed result. Subclasses may
+ /// override this function to provide alternate behavior.
+ TemplateArgument TransformTemplateArgument(const TemplateArgument &Arg);
+
+#define ABSTRACT_TYPE(CLASS, PARENT)
+#define TYPE(CLASS, PARENT) \
+ QualType Transform##CLASS##Type(const CLASS##Type *T);
+#include "clang/AST/TypeNodes.def"
+
+ OwningStmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr);
+
+#define STMT(Node, Parent) \
+ OwningStmtResult Transform##Node(Node *S);
+#define EXPR(Node, Parent) \
+ OwningExprResult Transform##Node(Node *E);
+#define ABSTRACT_EXPR(Node, Parent)
+#include "clang/AST/StmtNodes.def"
+
+ /// \brief Build a new pointer type given its pointee type.
+ ///
+ /// By default, performs semantic analysis when building the pointer type.
+ /// Subclasses may override this routine to provide different behavior.
+ QualType RebuildPointerType(QualType PointeeType);
+
+ /// \brief Build a new block pointer type given its pointee type.
+ ///
+ /// By default, performs semantic analysis when building the block pointer
+ /// type. Subclasses may override this routine to provide different behavior.
+ QualType RebuildBlockPointerType(QualType PointeeType);
+
+ /// \brief Build a new lvalue reference type given the type it references.
+ ///
+ /// By default, performs semantic analysis when building the lvalue reference
+ /// type. Subclasses may override this routine to provide different behavior.
+ QualType RebuildLValueReferenceType(QualType ReferentType);
+
+ /// \brief Build a new rvalue reference type given the type it references.
+ ///
+ /// By default, performs semantic analysis when building the rvalue reference
+ /// type. Subclasses may override this routine to provide different behavior.
+ QualType RebuildRValueReferenceType(QualType ReferentType);
+
+ /// \brief Build a new member pointer type given the pointee type and the
+ /// class type it refers into.
+ ///
+ /// By default, performs semantic analysis when building the member pointer
+ /// type. Subclasses may override this routine to provide different behavior.
+ QualType RebuildMemberPointerType(QualType PointeeType, QualType ClassType);
+
+ /// \brief Build a new array type given the element type, size
+ /// modifier, size of the array (if known), size expression, and index type
+ /// qualifiers.
+ ///
+ /// By default, performs semantic analysis when building the array type.
+ /// Subclasses may override this routine to provide different behavior.
+ /// Also by default, all of the other Rebuild*Array
+ QualType RebuildArrayType(QualType ElementType,
+ ArrayType::ArraySizeModifier SizeMod,
+ const llvm::APInt *Size,
+ Expr *SizeExpr,
+ unsigned IndexTypeQuals,
+ SourceRange BracketsRange);
+
+ /// \brief Build a new constant array type given the element type, size
+ /// modifier, (known) size of the array, and index type qualifiers.
+ ///
+ /// By default, performs semantic analysis when building the array type.
+ /// Subclasses may override this routine to provide different behavior.
+ QualType RebuildConstantArrayType(QualType ElementType,
+ ArrayType::ArraySizeModifier SizeMod,
+ const llvm::APInt &Size,
+ unsigned IndexTypeQuals);
+
+ /// \brief Build a new constant array type given the element type, size
+ /// modifier, (known) size of the array, size expression, and index type
+ /// qualifiers.
+ ///
+ /// By default, performs semantic analysis when building the array type.
+ /// Subclasses may override this routine to provide different behavior.
+ QualType RebuildConstantArrayWithExprType(QualType ElementType,
+ ArrayType::ArraySizeModifier SizeMod,
+ const llvm::APInt &Size,
+ Expr *SizeExpr,
+ unsigned IndexTypeQuals,
+ SourceRange BracketsRange);
+
+ /// \brief Build a new constant array type given the element type, size
+ /// modifier, (known) size of the array, and index type qualifiers.
+ ///
+ /// By default, performs semantic analysis when building the array type.
+ /// Subclasses may override this routine to provide different behavior.
+ QualType RebuildConstantArrayWithoutExprType(QualType ElementType,
+ ArrayType::ArraySizeModifier SizeMod,
+ const llvm::APInt &Size,
+ unsigned IndexTypeQuals);
+
+ /// \brief Build a new incomplete array type given the element type, size
+ /// modifier, and index type qualifiers.
+ ///
+ /// By default, performs semantic analysis when building the array type.
+ /// Subclasses may override this routine to provide different behavior.
+ QualType RebuildIncompleteArrayType(QualType ElementType,
+ ArrayType::ArraySizeModifier SizeMod,
+ unsigned IndexTypeQuals);
+
+ /// \brief Build a new variable-length array type given the element type,
+ /// size modifier, size expression, and index type qualifiers.
+ ///
+ /// By default, performs semantic analysis when building the array type.
+ /// Subclasses may override this routine to provide different behavior.
+ QualType RebuildVariableArrayType(QualType ElementType,
+ ArrayType::ArraySizeModifier SizeMod,
+ ExprArg SizeExpr,
+ unsigned IndexTypeQuals,
+ SourceRange BracketsRange);
+
+ /// \brief Build a new dependent-sized array type given the element type,
+ /// size modifier, size expression, and index type qualifiers.
+ ///
+ /// By default, performs semantic analysis when building the array type.
+ /// Subclasses may override this routine to provide different behavior.
+ QualType RebuildDependentSizedArrayType(QualType ElementType,
+ ArrayType::ArraySizeModifier SizeMod,
+ ExprArg SizeExpr,
+ unsigned IndexTypeQuals,
+ SourceRange BracketsRange);
+
+ /// \brief Build a new vector type given the element type and
+ /// number of elements.
+ ///
+ /// By default, performs semantic analysis when building the vector type.
+ /// Subclasses may override this routine to provide different behavior.
+ QualType RebuildVectorType(QualType ElementType, unsigned NumElements);
+
+ /// \brief Build a new extended vector type given the element type and
+ /// number of elements.
+ ///
+ /// By default, performs semantic analysis when building the vector type.
+ /// Subclasses may override this routine to provide different behavior.
+ QualType RebuildExtVectorType(QualType ElementType, unsigned NumElements,
+ SourceLocation AttributeLoc);
+
+ /// \brief Build a new potentially dependently-sized extended vector type
+ /// given the element type and number of elements.
+ ///
+ /// By default, performs semantic analysis when building the vector type.
+ /// Subclasses may override this routine to provide different behavior.
+ QualType RebuildDependentSizedExtVectorType(QualType ElementType,
+ ExprArg SizeExpr,
+ SourceLocation AttributeLoc);
+
+ /// \brief Build a new function type.
+ ///
+ /// By default, performs semantic analysis when building the function type.
+ /// Subclasses may override this routine to provide different behavior.
+ QualType RebuildFunctionProtoType(QualType T,
+ QualType *ParamTypes,
+ unsigned NumParamTypes,
+ bool Variadic, unsigned Quals);
+
+ /// \brief Build a new typedef type.
+ QualType RebuildTypedefType(TypedefDecl *Typedef) {
+ return SemaRef.Context.getTypeDeclType(Typedef);
+ }
+
+ /// \brief Build a new class/struct/union type.
+ QualType RebuildRecordType(RecordDecl *Record) {
+ return SemaRef.Context.getTypeDeclType(Record);
+ }
+
+ /// \brief Build a new Enum type.
+ QualType RebuildEnumType(EnumDecl *Enum) {
+ return SemaRef.Context.getTypeDeclType(Enum);
+ }
+
+ /// \brief Build a new elaborated type.
+ QualType RebuildElaboratedType(QualType T, ElaboratedType::TagKind Tag) {
+ return SemaRef.Context.getElaboratedType(T, Tag);
+ }
+
+ /// \brief Build a new typeof(expr) type.
+ ///
+ /// By default, performs semantic analysis when building the typeof type.
+ /// Subclasses may override this routine to provide different behavior.
+ QualType RebuildTypeOfExprType(ExprArg Underlying);
+
+ /// \brief Build a new typeof(type) type.
+ ///
+ /// By default, builds a new TypeOfType with the given underlying type.
+ QualType RebuildTypeOfType(QualType Underlying);
+
+ /// \brief Build a new C++0x decltype type.
+ ///
+ /// By default, performs semantic analysis when building the decltype type.
+ /// Subclasses may override this routine to provide different behavior.
+ QualType RebuildDecltypeType(ExprArg Underlying);
+
+ /// \brief Build a new template specialization type.
+ ///
+ /// By default, performs semantic analysis when building the template
+ /// specialization type. Subclasses may override this routine to provide
+ /// different behavior.
+ QualType RebuildTemplateSpecializationType(TemplateName Template,
+ const TemplateArgument *Args,
+ unsigned NumArgs);
+
+ /// \brief Build a new qualified name type.
+ ///
+ /// By default, builds a new QualifiedNameType type from the
+ /// nested-name-specifier and the named type. Subclasses may override
+ /// this routine to provide different behavior.
+ QualType RebuildQualifiedNameType(NestedNameSpecifier *NNS, QualType Named) {
+ return SemaRef.Context.getQualifiedNameType(NNS, Named);
+ }
+
+ /// \brief Build a new typename type that refers to a template-id.
+ ///
+ /// By default, builds a new TypenameType type from the nested-name-specifier
+ /// and the given type. Subclasses may override this routine to provide
+ /// different behavior.
+ QualType RebuildTypenameType(NestedNameSpecifier *NNS, QualType T) {
+ if (NNS->isDependent())
+ return SemaRef.Context.getTypenameType(NNS,
+ cast<TemplateSpecializationType>(T));
+
+ return SemaRef.Context.getQualifiedNameType(NNS, T);
+ }
+
+ /// \brief Build a new typename type that refers to an identifier.
+ ///
+ /// By default, performs semantic analysis when building the typename type
+ /// (or qualified name type). Subclasses may override this routine to provide
+ /// different behavior.
+ QualType RebuildTypenameType(NestedNameSpecifier *NNS,
+ const IdentifierInfo *Id) {
+ return SemaRef.CheckTypenameType(NNS, *Id,
+ SourceRange(getDerived().getBaseLocation()));
+ }
+
+ /// \brief Build a new nested-name-specifier given the prefix and an
+ /// identifier that names the next step in the nested-name-specifier.
+ ///
+ /// By default, performs semantic analysis when building the new
+ /// nested-name-specifier. Subclasses may override this routine to provide
+ /// different behavior.
+ NestedNameSpecifier *RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
+ SourceRange Range,
+ IdentifierInfo &II,
+ QualType ObjectType,
+ NamedDecl *FirstQualifierInScope);
+
+ /// \brief Build a new nested-name-specifier given the prefix and the
+ /// namespace named in the next step in the nested-name-specifier.
+ ///
+ /// By default, performs semantic analysis when building the new
+ /// nested-name-specifier. Subclasses may override this routine to provide
+ /// different behavior.
+ NestedNameSpecifier *RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
+ SourceRange Range,
+ NamespaceDecl *NS);
+
+ /// \brief Build a new nested-name-specifier given the prefix and the
+ /// type named in the next step in the nested-name-specifier.
+ ///
+ /// By default, performs semantic analysis when building the new
+ /// nested-name-specifier. Subclasses may override this routine to provide
+ /// different behavior.
+ NestedNameSpecifier *RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
+ SourceRange Range,
+ bool TemplateKW,
+ QualType T);
+
+ /// \brief Build a new template name given a nested name specifier, a flag
+ /// indicating whether the "template" keyword was provided, and the template
+ /// that the template name refers to.
+ ///
+ /// By default, builds the new template name directly. Subclasses may override
+ /// this routine to provide different behavior.
+ TemplateName RebuildTemplateName(NestedNameSpecifier *Qualifier,
+ bool TemplateKW,
+ TemplateDecl *Template);
+
+ /// \brief Build a new template name given a nested name specifier, a flag
+ /// indicating whether the "template" keyword was provided, and a set of
+ /// overloaded function templates.
+ ///
+ /// By default, builds the new template name directly. Subclasses may override
+ /// this routine to provide different behavior.
+ TemplateName RebuildTemplateName(NestedNameSpecifier *Qualifier,
+ bool TemplateKW,
+ OverloadedFunctionDecl *Ovl);
+
+ /// \brief Build a new template name given a nested name specifier and the
+ /// name that is referred to as a template.
+ ///
+ /// By default, performs semantic analysis to determine whether the name can
+ /// be resolved to a specific template, then builds the appropriate kind of
+ /// template name. Subclasses may override this routine to provide different
+ /// behavior.
+ TemplateName RebuildTemplateName(NestedNameSpecifier *Qualifier,
+ const IdentifierInfo &II,
+ QualType ObjectType);
+
+
+ /// \brief Build a new compound statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildCompoundStmt(SourceLocation LBraceLoc,
+ MultiStmtArg Statements,
+ SourceLocation RBraceLoc,
+ bool IsStmtExpr) {
+ return getSema().ActOnCompoundStmt(LBraceLoc, RBraceLoc, move(Statements),
+ IsStmtExpr);
+ }
+
+ /// \brief Build a new case statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildCaseStmt(SourceLocation CaseLoc,
+ ExprArg LHS,
+ SourceLocation EllipsisLoc,
+ ExprArg RHS,
+ SourceLocation ColonLoc) {
+ return getSema().ActOnCaseStmt(CaseLoc, move(LHS), EllipsisLoc, move(RHS),
+ ColonLoc);
+ }
+
+ /// \brief Attach the body to a new case statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildCaseStmtBody(StmtArg S, StmtArg Body) {
+ getSema().ActOnCaseStmtBody(S.get(), move(Body));
+ return move(S);
+ }
+
+ /// \brief Build a new default statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildDefaultStmt(SourceLocation DefaultLoc,
+ SourceLocation ColonLoc,
+ StmtArg SubStmt) {
+ return getSema().ActOnDefaultStmt(DefaultLoc, ColonLoc, move(SubStmt),
+ /*CurScope=*/0);
+ }
+
+ /// \brief Build a new label statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildLabelStmt(SourceLocation IdentLoc,
+ IdentifierInfo *Id,
+ SourceLocation ColonLoc,
+ StmtArg SubStmt) {
+ return SemaRef.ActOnLabelStmt(IdentLoc, Id, ColonLoc, move(SubStmt));
+ }
+
+ /// \brief Build a new "if" statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildIfStmt(SourceLocation IfLoc, Sema::FullExprArg Cond,
+ StmtArg Then, SourceLocation ElseLoc,
+ StmtArg Else) {
+ return getSema().ActOnIfStmt(IfLoc, Cond, move(Then), ElseLoc, move(Else));
+ }
+
+ /// \brief Start building a new switch statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildSwitchStmtStart(ExprArg Cond) {
+ return getSema().ActOnStartOfSwitchStmt(move(Cond));
+ }
+
+ /// \brief Attach the body to the switch statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildSwitchStmtBody(SourceLocation SwitchLoc,
+ StmtArg Switch, StmtArg Body) {
+ return getSema().ActOnFinishSwitchStmt(SwitchLoc, move(Switch),
+ move(Body));
+ }
+
+ /// \brief Build a new while statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildWhileStmt(SourceLocation WhileLoc,
+ Sema::FullExprArg Cond,
+ StmtArg Body) {
+ return getSema().ActOnWhileStmt(WhileLoc, Cond, move(Body));
+ }
+
+ /// \brief Build a new do-while statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildDoStmt(SourceLocation DoLoc, StmtArg Body,
+ SourceLocation WhileLoc,
+ SourceLocation LParenLoc,
+ ExprArg Cond,
+ SourceLocation RParenLoc) {
+ return getSema().ActOnDoStmt(DoLoc, move(Body), WhileLoc, LParenLoc,
+ move(Cond), RParenLoc);
+ }
+
+ /// \brief Build a new for statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildForStmt(SourceLocation ForLoc,
+ SourceLocation LParenLoc,
+ StmtArg Init, ExprArg Cond, ExprArg Inc,
+ SourceLocation RParenLoc, StmtArg Body) {
+ return getSema().ActOnForStmt(ForLoc, LParenLoc, move(Init), move(Cond),
+ move(Inc), RParenLoc, move(Body));
+ }
+
+ /// \brief Build a new goto statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildGotoStmt(SourceLocation GotoLoc,
+ SourceLocation LabelLoc,
+ LabelStmt *Label) {
+ return getSema().ActOnGotoStmt(GotoLoc, LabelLoc, Label->getID());
+ }
+
+ /// \brief Build a new indirect goto statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildIndirectGotoStmt(SourceLocation GotoLoc,
+ SourceLocation StarLoc,
+ ExprArg Target) {
+ return getSema().ActOnIndirectGotoStmt(GotoLoc, StarLoc, move(Target));
+ }
+
+ /// \brief Build a new return statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildReturnStmt(SourceLocation ReturnLoc,
+ ExprArg Result) {
+
+ return getSema().ActOnReturnStmt(ReturnLoc, move(Result));
+ }
+
+ /// \brief Build a new declaration statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildDeclStmt(Decl **Decls, unsigned NumDecls,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ return getSema().Owned(
+ new (getSema().Context) DeclStmt(
+ DeclGroupRef::Create(getSema().Context,
+ Decls, NumDecls),
+ StartLoc, EndLoc));
+ }
+
+ /// \brief Build a new C++ exception declaration.
+ ///
+ /// By default, performs semantic analysis to build the new decaration.
+ /// Subclasses may override this routine to provide different behavior.
+ VarDecl *RebuildExceptionDecl(VarDecl *ExceptionDecl, QualType T,
+ DeclaratorInfo *Declarator,
+ IdentifierInfo *Name,
+ SourceLocation Loc,
+ SourceRange TypeRange) {
+ return getSema().BuildExceptionDeclaration(0, T, Declarator, Name, Loc,
+ TypeRange);
+ }
+
+ /// \brief Build a new C++ catch statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildCXXCatchStmt(SourceLocation CatchLoc,
+ VarDecl *ExceptionDecl,
+ StmtArg Handler) {
+ return getSema().Owned(
+ new (getSema().Context) CXXCatchStmt(CatchLoc, ExceptionDecl,
+ Handler.takeAs<Stmt>()));
+ }
+
+ /// \brief Build a new C++ try statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildCXXTryStmt(SourceLocation TryLoc,
+ StmtArg TryBlock,
+ MultiStmtArg Handlers) {
+ return getSema().ActOnCXXTryBlock(TryLoc, move(TryBlock), move(Handlers));
+ }
+
+ /// \brief Build a new expression that references a declaration.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildDeclRefExpr(NamedDecl *ND, SourceLocation Loc) {
+ return getSema().BuildDeclarationNameExpr(Loc, ND,
+ /*FIXME:*/false,
+ /*SS=*/0,
+ /*FIXME:*/false);
+ }
+
+ /// \brief Build a new expression in parentheses.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildParenExpr(ExprArg SubExpr, SourceLocation LParen,
+ SourceLocation RParen) {
+ return getSema().ActOnParenExpr(LParen, RParen, move(SubExpr));
+ }
+
+ /// \brief Build a new pseudo-destructor expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCXXPseudoDestructorExpr(ExprArg Base,
+ SourceLocation OperatorLoc,
+ bool isArrow,
+ SourceLocation DestroyedTypeLoc,
+ QualType DestroyedType,
+ NestedNameSpecifier *Qualifier,
+ SourceRange QualifierRange) {
+ CXXScopeSpec SS;
+ if (Qualifier) {
+ SS.setRange(QualifierRange);
+ SS.setScopeRep(Qualifier);
+ }
+
+ DeclarationName Name
+ = SemaRef.Context.DeclarationNames.getCXXDestructorName(
+ SemaRef.Context.getCanonicalType(DestroyedType));
+
+ return getSema().BuildMemberReferenceExpr(/*Scope=*/0, move(Base),
+ OperatorLoc,
+ isArrow? tok::arrow : tok::period,
+ DestroyedTypeLoc,
+ Name,
+ Sema::DeclPtrTy::make((Decl *)0),
+ &SS);
+ }
+
+ /// \brief Build a new unary operator expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildUnaryOperator(SourceLocation OpLoc,
+ UnaryOperator::Opcode Opc,
+ ExprArg SubExpr) {
+ return getSema().CreateBuiltinUnaryOp(OpLoc, Opc, move(SubExpr));
+ }
+
+ /// \brief Build a new sizeof or alignof expression with a type argument.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildSizeOfAlignOf(QualType T, SourceLocation OpLoc,
+ bool isSizeOf, SourceRange R) {
+ return getSema().CreateSizeOfAlignOfExpr(T, OpLoc, isSizeOf, R);
+ }
+
+ /// \brief Build a new sizeof or alignof expression with an expression
+ /// argument.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildSizeOfAlignOf(ExprArg SubExpr, SourceLocation OpLoc,
+ bool isSizeOf, SourceRange R) {
+ OwningExprResult Result
+ = getSema().CreateSizeOfAlignOfExpr((Expr *)SubExpr.get(),
+ OpLoc, isSizeOf, R);
+ if (Result.isInvalid())
+ return getSema().ExprError();
+
+ SubExpr.release();
+ return move(Result);
+ }
+
+ /// \brief Build a new array subscript expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildArraySubscriptExpr(ExprArg LHS,
+ SourceLocation LBracketLoc,
+ ExprArg RHS,
+ SourceLocation RBracketLoc) {
+ return getSema().ActOnArraySubscriptExpr(/*Scope=*/0, move(LHS),
+ LBracketLoc, move(RHS),
+ RBracketLoc);
+ }
+
+ /// \brief Build a new call expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCallExpr(ExprArg Callee, SourceLocation LParenLoc,
+ MultiExprArg Args,
+ SourceLocation *CommaLocs,
+ SourceLocation RParenLoc) {
+ return getSema().ActOnCallExpr(/*Scope=*/0, move(Callee), LParenLoc,
+ move(Args), CommaLocs, RParenLoc);
+ }
+
+ /// \brief Build a new member access expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildMemberExpr(ExprArg Base, SourceLocation OpLoc,
+ bool isArrow,
+ NestedNameSpecifier *Qualifier,
+ SourceRange QualifierRange,
+ SourceLocation MemberLoc,
+ NamedDecl *Member) {
+ if (!Member->getDeclName()) {
+ // We have a reference to an unnamed field.
+ assert(!Qualifier && "Can't have an unnamed field with a qualifier!");
+
+ MemberExpr *ME =
+ new (getSema().Context) MemberExpr(Base.takeAs<Expr>(), isArrow,
+ Member, MemberLoc,
+ cast<FieldDecl>(Member)->getType());
+ return getSema().Owned(ME);
+ }
+
+ CXXScopeSpec SS;
+ if (Qualifier) {
+ SS.setRange(QualifierRange);
+ SS.setScopeRep(Qualifier);
+ }
+
+ return getSema().BuildMemberReferenceExpr(/*Scope=*/0, move(Base), OpLoc,
+ isArrow? tok::arrow : tok::period,
+ MemberLoc,
+ Member->getDeclName(),
+ /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0),
+ &SS);
+ }
+
+ /// \brief Build a new binary operator expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildBinaryOperator(SourceLocation OpLoc,
+ BinaryOperator::Opcode Opc,
+ ExprArg LHS, ExprArg RHS) {
+ OwningExprResult Result
+ = getSema().CreateBuiltinBinOp(OpLoc, Opc, (Expr *)LHS.get(),
+ (Expr *)RHS.get());
+ if (Result.isInvalid())
+ return SemaRef.ExprError();
+
+ LHS.release();
+ RHS.release();
+ return move(Result);
+ }
+
+ /// \brief Build a new conditional operator expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildConditionalOperator(ExprArg Cond,
+ SourceLocation QuestionLoc,
+ ExprArg LHS,
+ SourceLocation ColonLoc,
+ ExprArg RHS) {
+ return getSema().ActOnConditionalOp(QuestionLoc, ColonLoc, move(Cond),
+ move(LHS), move(RHS));
+ }
+
+ /// \brief Build a new implicit cast expression.
+ ///
+ /// By default, builds a new implicit cast without any semantic analysis.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildImplicitCastExpr(QualType T, CastExpr::CastKind Kind,
+ ExprArg SubExpr, bool isLvalue) {
+ ImplicitCastExpr *ICE
+ = new (getSema().Context) ImplicitCastExpr(T, Kind,
+ (Expr *)SubExpr.release(),
+ isLvalue);
+ return getSema().Owned(ICE);
+ }
+
+ /// \brief Build a new C-style cast expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCStyleCaseExpr(SourceLocation LParenLoc,
+ QualType ExplicitTy,
+ SourceLocation RParenLoc,
+ ExprArg SubExpr) {
+ return getSema().ActOnCastExpr(/*Scope=*/0,
+ LParenLoc,
+ ExplicitTy.getAsOpaquePtr(),
+ RParenLoc,
+ move(SubExpr));
+ }
+
+ /// \brief Build a new compound literal expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCompoundLiteralExpr(SourceLocation LParenLoc,
+ QualType T,
+ SourceLocation RParenLoc,
+ ExprArg Init) {
+ return getSema().ActOnCompoundLiteral(LParenLoc, T.getAsOpaquePtr(),
+ RParenLoc, move(Init));
+ }
+
+ /// \brief Build a new extended vector element access expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildExtVectorElementExpr(ExprArg Base,
+ SourceLocation OpLoc,
+ SourceLocation AccessorLoc,
+ IdentifierInfo &Accessor) {
+ return getSema().ActOnMemberReferenceExpr(/*Scope=*/0, move(Base), OpLoc,
+ tok::period, AccessorLoc,
+ Accessor,
+ /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0));
+ }
+
+ /// \brief Build a new initializer list expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildInitList(SourceLocation LBraceLoc,
+ MultiExprArg Inits,
+ SourceLocation RBraceLoc) {
+ return SemaRef.ActOnInitList(LBraceLoc, move(Inits), RBraceLoc);
+ }
+
+ /// \brief Build a new designated initializer expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildDesignatedInitExpr(Designation &Desig,
+ MultiExprArg ArrayExprs,
+ SourceLocation EqualOrColonLoc,
+ bool GNUSyntax,
+ ExprArg Init) {
+ OwningExprResult Result
+ = SemaRef.ActOnDesignatedInitializer(Desig, EqualOrColonLoc, GNUSyntax,
+ move(Init));
+ if (Result.isInvalid())
+ return SemaRef.ExprError();
+
+ ArrayExprs.release();
+ return move(Result);
+ }
+
+ /// \brief Build a new value-initialized expression.
+ ///
+ /// By default, builds the implicit value initialization without performing
+ /// any semantic analysis. Subclasses may override this routine to provide
+ /// different behavior.
+ OwningExprResult RebuildImplicitValueInitExpr(QualType T) {
+ return SemaRef.Owned(new (SemaRef.Context) ImplicitValueInitExpr(T));
+ }
+
+ /// \brief Build a new \c va_arg expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildVAArgExpr(SourceLocation BuiltinLoc, ExprArg SubExpr,
+ QualType T, SourceLocation RParenLoc) {
+ return getSema().ActOnVAArg(BuiltinLoc, move(SubExpr), T.getAsOpaquePtr(),
+ RParenLoc);
+ }
+
+ /// \brief Build a new expression list in parentheses.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildParenListExpr(SourceLocation LParenLoc,
+ MultiExprArg SubExprs,
+ SourceLocation RParenLoc) {
+ return getSema().ActOnParenListExpr(LParenLoc, RParenLoc, move(SubExprs));
+ }
+
+ /// \brief Build a new address-of-label expression.
+ ///
+ /// By default, performs semantic analysis, using the name of the label
+ /// rather than attempting to map the label statement itself.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildAddrLabelExpr(SourceLocation AmpAmpLoc,
+ SourceLocation LabelLoc,
+ LabelStmt *Label) {
+ return getSema().ActOnAddrLabel(AmpAmpLoc, LabelLoc, Label->getID());
+ }
+
+ /// \brief Build a new GNU statement expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildStmtExpr(SourceLocation LParenLoc,
+ StmtArg SubStmt,
+ SourceLocation RParenLoc) {
+ return getSema().ActOnStmtExpr(LParenLoc, move(SubStmt), RParenLoc);
+ }
+
+ /// \brief Build a new __builtin_types_compatible_p expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildTypesCompatibleExpr(SourceLocation BuiltinLoc,
+ QualType T1, QualType T2,
+ SourceLocation RParenLoc) {
+ return getSema().ActOnTypesCompatibleExpr(BuiltinLoc,
+ T1.getAsOpaquePtr(),
+ T2.getAsOpaquePtr(),
+ RParenLoc);
+ }
+
+ /// \brief Build a new __builtin_choose_expr expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildChooseExpr(SourceLocation BuiltinLoc,
+ ExprArg Cond, ExprArg LHS, ExprArg RHS,
+ SourceLocation RParenLoc) {
+ return SemaRef.ActOnChooseExpr(BuiltinLoc,
+ move(Cond), move(LHS), move(RHS),
+ RParenLoc);
+ }
+
+ /// \brief Build a new overloaded operator call expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// The semantic analysis provides the behavior of template instantiation,
+ /// copying with transformations that turn what looks like an overloaded
+ /// operator call into a use of a builtin operator, performing
+ /// argument-dependent lookup, etc. Subclasses may override this routine to
+ /// provide different behavior.
+ OwningExprResult RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
+ SourceLocation OpLoc,
+ ExprArg Callee,
+ ExprArg First,
+ ExprArg Second);
+
+ /// \brief Build a new C++ "named" cast expression, such as static_cast or
+ /// reinterpret_cast.
+ ///
+ /// By default, this routine dispatches to one of the more-specific routines
+ /// for a particular named case, e.g., RebuildCXXStaticCastExpr().
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCXXNamedCastExpr(SourceLocation OpLoc,
+ Stmt::StmtClass Class,
+ SourceLocation LAngleLoc,
+ QualType T,
+ SourceLocation RAngleLoc,
+ SourceLocation LParenLoc,
+ ExprArg SubExpr,
+ SourceLocation RParenLoc) {
+ switch (Class) {
+ case Stmt::CXXStaticCastExprClass:
+ return getDerived().RebuildCXXStaticCastExpr(OpLoc, LAngleLoc, T,
+ RAngleLoc, LParenLoc,
+ move(SubExpr), RParenLoc);
+
+ case Stmt::CXXDynamicCastExprClass:
+ return getDerived().RebuildCXXDynamicCastExpr(OpLoc, LAngleLoc, T,
+ RAngleLoc, LParenLoc,
+ move(SubExpr), RParenLoc);
+
+ case Stmt::CXXReinterpretCastExprClass:
+ return getDerived().RebuildCXXReinterpretCastExpr(OpLoc, LAngleLoc, T,
+ RAngleLoc, LParenLoc,
+ move(SubExpr),
+ RParenLoc);
+
+ case Stmt::CXXConstCastExprClass:
+ return getDerived().RebuildCXXConstCastExpr(OpLoc, LAngleLoc, T,
+ RAngleLoc, LParenLoc,
+ move(SubExpr), RParenLoc);
+
+ default:
+ assert(false && "Invalid C++ named cast");
+ break;
+ }
+
+ return getSema().ExprError();
+ }
+
+ /// \brief Build a new C++ static_cast expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCXXStaticCastExpr(SourceLocation OpLoc,
+ SourceLocation LAngleLoc,
+ QualType T,
+ SourceLocation RAngleLoc,
+ SourceLocation LParenLoc,
+ ExprArg SubExpr,
+ SourceLocation RParenLoc) {
+ return getSema().ActOnCXXNamedCast(OpLoc, tok::kw_static_cast,
+ LAngleLoc, T.getAsOpaquePtr(), RAngleLoc,
+ LParenLoc, move(SubExpr), RParenLoc);
+ }
+
+ /// \brief Build a new C++ dynamic_cast expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCXXDynamicCastExpr(SourceLocation OpLoc,
+ SourceLocation LAngleLoc,
+ QualType T,
+ SourceLocation RAngleLoc,
+ SourceLocation LParenLoc,
+ ExprArg SubExpr,
+ SourceLocation RParenLoc) {
+ return getSema().ActOnCXXNamedCast(OpLoc, tok::kw_dynamic_cast,
+ LAngleLoc, T.getAsOpaquePtr(), RAngleLoc,
+ LParenLoc, move(SubExpr), RParenLoc);
+ }
+
+ /// \brief Build a new C++ reinterpret_cast expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCXXReinterpretCastExpr(SourceLocation OpLoc,
+ SourceLocation LAngleLoc,
+ QualType T,
+ SourceLocation RAngleLoc,
+ SourceLocation LParenLoc,
+ ExprArg SubExpr,
+ SourceLocation RParenLoc) {
+ return getSema().ActOnCXXNamedCast(OpLoc, tok::kw_reinterpret_cast,
+ LAngleLoc, T.getAsOpaquePtr(), RAngleLoc,
+ LParenLoc, move(SubExpr), RParenLoc);
+ }
+
+ /// \brief Build a new C++ const_cast expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCXXConstCastExpr(SourceLocation OpLoc,
+ SourceLocation LAngleLoc,
+ QualType T,
+ SourceLocation RAngleLoc,
+ SourceLocation LParenLoc,
+ ExprArg SubExpr,
+ SourceLocation RParenLoc) {
+ return getSema().ActOnCXXNamedCast(OpLoc, tok::kw_const_cast,
+ LAngleLoc, T.getAsOpaquePtr(), RAngleLoc,
+ LParenLoc, move(SubExpr), RParenLoc);
+ }
+
+ /// \brief Build a new C++ functional-style cast expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCXXFunctionalCastExpr(SourceRange TypeRange,
+ QualType T,
+ SourceLocation LParenLoc,
+ ExprArg SubExpr,
+ SourceLocation RParenLoc) {
+ void *Sub = SubExpr.takeAs<Expr>();
+ return getSema().ActOnCXXTypeConstructExpr(TypeRange,
+ T.getAsOpaquePtr(),
+ LParenLoc,
+ Sema::MultiExprArg(getSema(), &Sub, 1),
+ /*CommaLocs=*/0,
+ RParenLoc);
+ }
+
+ /// \brief Build a new C++ typeid(type) expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCXXTypeidExpr(SourceLocation TypeidLoc,
+ SourceLocation LParenLoc,
+ QualType T,
+ SourceLocation RParenLoc) {
+ return getSema().ActOnCXXTypeid(TypeidLoc, LParenLoc, true,
+ T.getAsOpaquePtr(), RParenLoc);
+ }
+
+ /// \brief Build a new C++ typeid(expr) expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCXXTypeidExpr(SourceLocation TypeidLoc,
+ SourceLocation LParenLoc,
+ ExprArg Operand,
+ SourceLocation RParenLoc) {
+ OwningExprResult Result
+ = getSema().ActOnCXXTypeid(TypeidLoc, LParenLoc, false, Operand.get(),
+ RParenLoc);
+ if (Result.isInvalid())
+ return getSema().ExprError();
+
+ Operand.release(); // FIXME: since ActOnCXXTypeid silently took ownership
+ return move(Result);
+ }
+
+ /// \brief Build a new C++ "this" expression.
+ ///
+ /// By default, builds a new "this" expression without performing any
+ /// semantic analysis. Subclasses may override this routine to provide
+ /// different behavior.
+ OwningExprResult RebuildCXXThisExpr(SourceLocation ThisLoc,
+ QualType ThisType) {
+ return getSema().Owned(
+ new (getSema().Context) CXXThisExpr(ThisLoc, ThisType));
+ }
+
+ /// \brief Build a new C++ throw expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCXXThrowExpr(SourceLocation ThrowLoc, ExprArg Sub) {
+ return getSema().ActOnCXXThrow(ThrowLoc, move(Sub));
+ }
+
+ /// \brief Build a new C++ default-argument expression.
+ ///
+ /// By default, builds a new default-argument expression, which does not
+ /// require any semantic analysis. Subclasses may override this routine to
+ /// provide different behavior.
+ OwningExprResult RebuildCXXDefaultArgExpr(ParmVarDecl *Param) {
+ return getSema().Owned(CXXDefaultArgExpr::Create(getSema().Context, Param));
+ }
+
+ /// \brief Build a new C++ zero-initialization expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCXXZeroInitValueExpr(SourceLocation TypeStartLoc,
+ SourceLocation LParenLoc,
+ QualType T,
+ SourceLocation RParenLoc) {
+ return getSema().ActOnCXXTypeConstructExpr(SourceRange(TypeStartLoc),
+ T.getAsOpaquePtr(), LParenLoc,
+ MultiExprArg(getSema(), 0, 0),
+ 0, RParenLoc);
+ }
+
+ /// \brief Build a new C++ conditional declaration expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCXXConditionDeclExpr(SourceLocation StartLoc,
+ SourceLocation EqLoc,
+ VarDecl *Var) {
+ return SemaRef.Owned(new (SemaRef.Context) CXXConditionDeclExpr(StartLoc,
+ EqLoc,
+ Var));
+ }
+
+ /// \brief Build a new C++ "new" expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCXXNewExpr(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) {
+ return getSema().BuildCXXNew(StartLoc, UseGlobal,
+ PlacementLParen,
+ move(PlacementArgs),
+ PlacementRParen,
+ ParenTypeId,
+ AllocType,
+ TypeLoc,
+ TypeRange,
+ move(ArraySize),
+ ConstructorLParen,
+ move(ConstructorArgs),
+ ConstructorRParen);
+ }
+
+ /// \brief Build a new C++ "delete" expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCXXDeleteExpr(SourceLocation StartLoc,
+ bool IsGlobalDelete,
+ bool IsArrayForm,
+ ExprArg Operand) {
+ return getSema().ActOnCXXDelete(StartLoc, IsGlobalDelete, IsArrayForm,
+ move(Operand));
+ }
+
+ /// \brief Build a new unary type trait expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildUnaryTypeTrait(UnaryTypeTrait Trait,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ QualType T,
+ SourceLocation RParenLoc) {
+ return getSema().ActOnUnaryTypeTrait(Trait, StartLoc, LParenLoc,
+ T.getAsOpaquePtr(), RParenLoc);
+ }
+
+ /// \brief Build a new qualified declaration reference expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildQualifiedDeclRefExpr(NestedNameSpecifier *NNS,
+ SourceRange QualifierRange,
+ NamedDecl *ND,
+ SourceLocation Location,
+ bool IsAddressOfOperand) {
+ CXXScopeSpec SS;
+ SS.setRange(QualifierRange);
+ SS.setScopeRep(NNS);
+ return getSema().ActOnDeclarationNameExpr(/*Scope=*/0,
+ Location,
+ ND->getDeclName(),
+ /*Trailing lparen=*/false,
+ &SS,
+ IsAddressOfOperand);
+ }
+
+ /// \brief Build a new (previously unresolved) declaration reference
+ /// expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildUnresolvedDeclRefExpr(NestedNameSpecifier *NNS,
+ SourceRange QualifierRange,
+ DeclarationName Name,
+ SourceLocation Location,
+ bool IsAddressOfOperand) {
+ CXXScopeSpec SS;
+ SS.setRange(QualifierRange);
+ SS.setScopeRep(NNS);
+ return getSema().ActOnDeclarationNameExpr(/*Scope=*/0,
+ Location,
+ Name,
+ /*Trailing lparen=*/false,
+ &SS,
+ IsAddressOfOperand);
+ }
+
+ /// \brief Build a new template-id expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildTemplateIdExpr(TemplateName Template,
+ SourceLocation TemplateLoc,
+ SourceLocation LAngleLoc,
+ TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ SourceLocation RAngleLoc) {
+ return getSema().BuildTemplateIdExpr(Template, TemplateLoc,
+ LAngleLoc,
+ TemplateArgs, NumTemplateArgs,
+ RAngleLoc);
+ }
+
+ /// \brief Build a new object-construction expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCXXConstructExpr(QualType T,
+ CXXConstructorDecl *Constructor,
+ bool IsElidable,
+ MultiExprArg Args) {
+ return getSema().BuildCXXConstructExpr(/*FIXME:ConstructLoc*/
+ SourceLocation(),
+ T, Constructor, IsElidable,
+ move(Args));
+ }
+
+ /// \brief Build a new object-construction expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCXXTemporaryObjectExpr(SourceLocation TypeBeginLoc,
+ QualType T,
+ SourceLocation LParenLoc,
+ MultiExprArg Args,
+ SourceLocation *Commas,
+ SourceLocation RParenLoc) {
+ return getSema().ActOnCXXTypeConstructExpr(SourceRange(TypeBeginLoc),
+ T.getAsOpaquePtr(),
+ LParenLoc,
+ move(Args),
+ Commas,
+ RParenLoc);
+ }
+
+ /// \brief Build a new object-construction expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCXXUnresolvedConstructExpr(SourceLocation TypeBeginLoc,
+ QualType T,
+ SourceLocation LParenLoc,
+ MultiExprArg Args,
+ SourceLocation *Commas,
+ SourceLocation RParenLoc) {
+ return getSema().ActOnCXXTypeConstructExpr(SourceRange(TypeBeginLoc,
+ /*FIXME*/LParenLoc),
+ T.getAsOpaquePtr(),
+ LParenLoc,
+ move(Args),
+ Commas,
+ RParenLoc);
+ }
+
+ /// \brief Build a new member reference expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCXXUnresolvedMemberExpr(ExprArg BaseE,
+ bool IsArrow,
+ SourceLocation OperatorLoc,
+ NestedNameSpecifier *Qualifier,
+ SourceRange QualifierRange,
+ DeclarationName Name,
+ SourceLocation MemberLoc,
+ NamedDecl *FirstQualifierInScope) {
+ OwningExprResult Base = move(BaseE);
+ tok::TokenKind OpKind = IsArrow? tok::arrow : tok::period;
+
+ CXXScopeSpec SS;
+ SS.setRange(QualifierRange);
+ SS.setScopeRep(Qualifier);
+
+ return SemaRef.BuildMemberReferenceExpr(/*Scope=*/0,
+ move(Base), OperatorLoc, OpKind,
+ MemberLoc,
+ Name,
+ /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0),
+ &SS,
+ FirstQualifierInScope);
+ }
+
+ /// \brief Build a new member reference expression with explicit template
+ /// arguments.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCXXUnresolvedMemberExpr(ExprArg BaseE,
+ bool IsArrow,
+ SourceLocation OperatorLoc,
+ NestedNameSpecifier *Qualifier,
+ SourceRange QualifierRange,
+ TemplateName Template,
+ SourceLocation TemplateNameLoc,
+ NamedDecl *FirstQualifierInScope,
+ SourceLocation LAngleLoc,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ SourceLocation RAngleLoc) {
+ OwningExprResult Base = move(BaseE);
+ tok::TokenKind OpKind = IsArrow? tok::arrow : tok::period;
+
+ CXXScopeSpec SS;
+ SS.setRange(QualifierRange);
+ SS.setScopeRep(Qualifier);
+
+ // FIXME: We're going to end up looking up the template based on its name,
+ // twice! Also, duplicates part of Sema::ActOnMemberTemplateIdReferenceExpr.
+ DeclarationName Name;
+ if (TemplateDecl *ActualTemplate = Template.getAsTemplateDecl())
+ Name = ActualTemplate->getDeclName();
+ else if (OverloadedFunctionDecl *Ovl
+ = Template.getAsOverloadedFunctionDecl())
+ Name = Ovl->getDeclName();
+ else
+ Name = Template.getAsDependentTemplateName()->getName();
+
+ return SemaRef.BuildMemberReferenceExpr(/*Scope=*/0, move(Base),
+ OperatorLoc, OpKind,
+ TemplateNameLoc, Name, true,
+ LAngleLoc, TemplateArgs,
+ NumTemplateArgs, RAngleLoc,
+ Sema::DeclPtrTy(), &SS);
+ }
+
+ /// \brief Build a new Objective-C @encode expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildObjCEncodeExpr(SourceLocation AtLoc,
+ QualType T,
+ SourceLocation RParenLoc) {
+ return SemaRef.Owned(SemaRef.BuildObjCEncodeExpression(AtLoc, T,
+ RParenLoc));
+ }
+
+ /// \brief Build a new Objective-C protocol expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildObjCProtocolExpr(ObjCProtocolDecl *Protocol,
+ SourceLocation AtLoc,
+ SourceLocation ProtoLoc,
+ SourceLocation LParenLoc,
+ SourceLocation RParenLoc) {
+ return SemaRef.Owned(SemaRef.ParseObjCProtocolExpression(
+ Protocol->getIdentifier(),
+ AtLoc,
+ ProtoLoc,
+ LParenLoc,
+ RParenLoc));
+ }
+
+ /// \brief Build a new shuffle vector expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildShuffleVectorExpr(SourceLocation BuiltinLoc,
+ MultiExprArg SubExprs,
+ SourceLocation RParenLoc) {
+ // 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(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(),
+ BuiltinLoc, false, false);
+ SemaRef.UsualUnaryConversions(Callee);
+
+ // Build the CallExpr
+ unsigned NumSubExprs = SubExprs.size();
+ Expr **Subs = (Expr **)SubExprs.release();
+ CallExpr *TheCall = new (SemaRef.Context) CallExpr(SemaRef.Context, Callee,
+ Subs, NumSubExprs,
+ Builtin->getResultType(),
+ RParenLoc);
+ 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);
+ }
+};
+
+template<typename Derived>
+Sema::OwningStmtResult TreeTransform<Derived>::TransformStmt(Stmt *S) {
+ if (!S)
+ return SemaRef.Owned(S);
+
+ switch (S->getStmtClass()) {
+ case Stmt::NoStmtClass: break;
+
+ // Transform individual statement nodes
+#define STMT(Node, Parent) \
+ case Stmt::Node##Class: return getDerived().Transform##Node(cast<Node>(S));
+#define EXPR(Node, Parent)
+#include "clang/AST/StmtNodes.def"
+
+ // Transform expressions by calling TransformExpr.
+#define STMT(Node, Parent)
+#define EXPR(Node, Parent) case Stmt::Node##Class:
+#include "clang/AST/StmtNodes.def"
+ {
+ Sema::OwningExprResult E = getDerived().TransformExpr(cast<Expr>(S));
+ if (E.isInvalid())
+ return getSema().StmtError();
+
+ return getSema().Owned(E.takeAs<Stmt>());
+ }
+ }
+
+ return SemaRef.Owned(S->Retain());
+}
+
+
+template<typename Derived>
+Sema::OwningExprResult TreeTransform<Derived>::TransformExpr(Expr *E,
+ bool isAddressOfOperand) {
+ if (!E)
+ return SemaRef.Owned(E);
+
+ switch (E->getStmtClass()) {
+ case Stmt::NoStmtClass: break;
+#define STMT(Node, Parent) case Stmt::Node##Class: break;
+#define EXPR(Node, Parent) \
+ case Stmt::Node##Class: return getDerived().Transform##Node(cast<Node>(E));
+#include "clang/AST/StmtNodes.def"
+ }
+
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+NestedNameSpecifier *
+TreeTransform<Derived>::TransformNestedNameSpecifier(NestedNameSpecifier *NNS,
+ SourceRange Range,
+ QualType ObjectType,
+ NamedDecl *FirstQualifierInScope) {
+ if (!NNS)
+ return 0;
+
+ // Transform the prefix of this nested name specifier.
+ NestedNameSpecifier *Prefix = NNS->getPrefix();
+ if (Prefix) {
+ Prefix = getDerived().TransformNestedNameSpecifier(Prefix, Range,
+ ObjectType,
+ FirstQualifierInScope);
+ if (!Prefix)
+ return 0;
+
+ // Clear out the object type and the first qualifier in scope; they only
+ // apply to the first element in the nested-name-specifier.
+ ObjectType = QualType();
+ FirstQualifierInScope = 0;
+ }
+
+ switch (NNS->getKind()) {
+ case NestedNameSpecifier::Identifier:
+ assert((Prefix || !ObjectType.isNull()) &&
+ "Identifier nested-name-specifier with no prefix or object type");
+ if (!getDerived().AlwaysRebuild() && Prefix == NNS->getPrefix() &&
+ ObjectType.isNull())
+ return NNS;
+
+ return getDerived().RebuildNestedNameSpecifier(Prefix, Range,
+ *NNS->getAsIdentifier(),
+ ObjectType,
+ FirstQualifierInScope);
+
+ case NestedNameSpecifier::Namespace: {
+ NamespaceDecl *NS
+ = cast_or_null<NamespaceDecl>(
+ getDerived().TransformDecl(NNS->getAsNamespace()));
+ if (!getDerived().AlwaysRebuild() &&
+ Prefix == NNS->getPrefix() &&
+ NS == NNS->getAsNamespace())
+ return NNS;
+
+ return getDerived().RebuildNestedNameSpecifier(Prefix, Range, NS);
+ }
+
+ case NestedNameSpecifier::Global:
+ // There is no meaningful transformation that one could perform on the
+ // global scope.
+ return NNS;
+
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ case NestedNameSpecifier::TypeSpec: {
+ QualType T = getDerived().TransformType(QualType(NNS->getAsType(), 0));
+ if (T.isNull())
+ return 0;
+
+ if (!getDerived().AlwaysRebuild() &&
+ Prefix == NNS->getPrefix() &&
+ T == QualType(NNS->getAsType(), 0))
+ return NNS;
+
+ return getDerived().RebuildNestedNameSpecifier(Prefix, Range,
+ NNS->getKind() == NestedNameSpecifier::TypeSpecWithTemplate,
+ T);
+ }
+ }
+
+ // Required to silence a GCC warning
+ return 0;
+}
+
+template<typename Derived>
+DeclarationName
+TreeTransform<Derived>::TransformDeclarationName(DeclarationName Name,
+ SourceLocation Loc) {
+ if (!Name)
+ return Name;
+
+ switch (Name.getNameKind()) {
+ case DeclarationName::Identifier:
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector:
+ case DeclarationName::CXXOperatorName:
+ case DeclarationName::CXXUsingDirective:
+ return Name;
+
+ case DeclarationName::CXXConstructorName:
+ case DeclarationName::CXXDestructorName:
+ case DeclarationName::CXXConversionFunctionName: {
+ TemporaryBase Rebase(*this, Loc, Name);
+ QualType T = getDerived().TransformType(Name.getCXXNameType());
+ if (T.isNull())
+ return DeclarationName();
+
+ return SemaRef.Context.DeclarationNames.getCXXSpecialName(
+ Name.getNameKind(),
+ SemaRef.Context.getCanonicalType(T));
+ }
+ }
+
+ return DeclarationName();
+}
+
+template<typename Derived>
+TemplateName
+TreeTransform<Derived>::TransformTemplateName(TemplateName Name,
+ QualType ObjectType) {
+ if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) {
+ NestedNameSpecifier *NNS
+ = getDerived().TransformNestedNameSpecifier(QTN->getQualifier(),
+ /*FIXME:*/SourceRange(getDerived().getBaseLocation()));
+ if (!NNS)
+ return TemplateName();
+
+ if (TemplateDecl *Template = QTN->getTemplateDecl()) {
+ TemplateDecl *TransTemplate
+ = cast_or_null<TemplateDecl>(getDerived().TransformDecl(Template));
+ if (!TransTemplate)
+ return TemplateName();
+
+ if (!getDerived().AlwaysRebuild() &&
+ NNS == QTN->getQualifier() &&
+ TransTemplate == Template)
+ return Name;
+
+ return getDerived().RebuildTemplateName(NNS, QTN->hasTemplateKeyword(),
+ TransTemplate);
+ }
+
+ OverloadedFunctionDecl *Ovl = QTN->getOverloadedFunctionDecl();
+ assert(Ovl && "Not a template name or an overload set?");
+ OverloadedFunctionDecl *TransOvl
+ = cast_or_null<OverloadedFunctionDecl>(getDerived().TransformDecl(Ovl));
+ if (!TransOvl)
+ return TemplateName();
+
+ if (!getDerived().AlwaysRebuild() &&
+ NNS == QTN->getQualifier() &&
+ TransOvl == Ovl)
+ return Name;
+
+ return getDerived().RebuildTemplateName(NNS, QTN->hasTemplateKeyword(),
+ TransOvl);
+ }
+
+ if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) {
+ NestedNameSpecifier *NNS
+ = getDerived().TransformNestedNameSpecifier(DTN->getQualifier(),
+ /*FIXME:*/SourceRange(getDerived().getBaseLocation()));
+ if (!NNS && DTN->getQualifier())
+ return TemplateName();
+
+ if (!getDerived().AlwaysRebuild() &&
+ NNS == DTN->getQualifier())
+ return Name;
+
+ return getDerived().RebuildTemplateName(NNS, *DTN->getName(), ObjectType);
+ }
+
+ if (TemplateDecl *Template = Name.getAsTemplateDecl()) {
+ TemplateDecl *TransTemplate
+ = cast_or_null<TemplateDecl>(getDerived().TransformDecl(Template));
+ if (!TransTemplate)
+ return TemplateName();
+
+ if (!getDerived().AlwaysRebuild() &&
+ TransTemplate == Template)
+ return Name;
+
+ return TemplateName(TransTemplate);
+ }
+
+ OverloadedFunctionDecl *Ovl = Name.getAsOverloadedFunctionDecl();
+ assert(Ovl && "Not a template name or an overload set?");
+ OverloadedFunctionDecl *TransOvl
+ = cast_or_null<OverloadedFunctionDecl>(getDerived().TransformDecl(Ovl));
+ if (!TransOvl)
+ return TemplateName();
+
+ if (!getDerived().AlwaysRebuild() &&
+ TransOvl == Ovl)
+ return Name;
+
+ return TemplateName(TransOvl);
+}
+
+template<typename Derived>
+TemplateArgument
+TreeTransform<Derived>::TransformTemplateArgument(const TemplateArgument &Arg) {
+ switch (Arg.getKind()) {
+ case TemplateArgument::Null:
+ case TemplateArgument::Integral:
+ return Arg;
+
+ case TemplateArgument::Type: {
+ QualType T = getDerived().TransformType(Arg.getAsType());
+ if (T.isNull())
+ return TemplateArgument();
+ return TemplateArgument(Arg.getLocation(), T);
+ }
+
+ case TemplateArgument::Declaration: {
+ Decl *D = getDerived().TransformDecl(Arg.getAsDecl());
+ if (!D)
+ return TemplateArgument();
+ return TemplateArgument(Arg.getLocation(), D);
+ }
+
+ case TemplateArgument::Expression: {
+ // Template argument expressions are not potentially evaluated.
+ EnterExpressionEvaluationContext Unevaluated(getSema(),
+ Action::Unevaluated);
+
+ Sema::OwningExprResult E = getDerived().TransformExpr(Arg.getAsExpr());
+ if (E.isInvalid())
+ return TemplateArgument();
+ return TemplateArgument(E.takeAs<Expr>());
+ }
+
+ case TemplateArgument::Pack: {
+ llvm::SmallVector<TemplateArgument, 4> TransformedArgs;
+ TransformedArgs.reserve(Arg.pack_size());
+ for (TemplateArgument::pack_iterator A = Arg.pack_begin(),
+ AEnd = Arg.pack_end();
+ A != AEnd; ++A) {
+ TemplateArgument TA = getDerived().TransformTemplateArgument(*A);
+ if (TA.isNull())
+ return TA;
+
+ TransformedArgs.push_back(TA);
+ }
+ TemplateArgument Result;
+ Result.setArgumentPack(TransformedArgs.data(), TransformedArgs.size(),
+ true);
+ return Result;
+ }
+ }
+
+ // Work around bogus GCC warning
+ return TemplateArgument();
+}
+
+//===----------------------------------------------------------------------===//
+// Type transformation
+//===----------------------------------------------------------------------===//
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformType(QualType T) {
+ if (getDerived().AlreadyTransformed(T))
+ return T;
+
+ QualifierCollector Qs;
+ const Type *Ty = Qs.strip(T);
+
+ QualType Result;
+ switch (Ty->getTypeClass()) {
+#define ABSTRACT_TYPE(CLASS, PARENT)
+#define TYPE(CLASS, PARENT) \
+ case Type::CLASS: \
+ Result = getDerived().Transform##CLASS##Type( \
+ static_cast<const CLASS##Type*>(Ty)); \
+ break;
+#include "clang/AST/TypeNodes.def"
+ }
+
+ if (Result.isNull() || T == Result)
+ return Result;
+
+ return getDerived().AddTypeQualifiers(Result, Qs);
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::AddTypeQualifiers(QualType T, Qualifiers Quals) {
+ if (!Quals.empty() && !T->isFunctionType() && !T->isReferenceType())
+ return SemaRef.Context.getQualifiedType(T, Quals);
+
+ return T;
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformBuiltinType(const BuiltinType *T) {
+ // Nothing to do
+ return QualType(T, 0);
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformFixedWidthIntType(
+ const FixedWidthIntType *T) {
+ // FIXME: Implement
+ return QualType(T, 0);
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformComplexType(const ComplexType *T) {
+ // FIXME: Implement
+ return QualType(T, 0);
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformPointerType(const PointerType *T) {
+ QualType PointeeType = getDerived().TransformType(T->getPointeeType());
+ if (PointeeType.isNull())
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ PointeeType == T->getPointeeType())
+ return QualType(T, 0);
+
+ return getDerived().RebuildPointerType(PointeeType);
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::TransformBlockPointerType(const BlockPointerType *T) {
+ QualType PointeeType = getDerived().TransformType(T->getPointeeType());
+ if (PointeeType.isNull())
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ PointeeType == T->getPointeeType())
+ return QualType(T, 0);
+
+ return getDerived().RebuildBlockPointerType(PointeeType);
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::TransformLValueReferenceType(
+ const LValueReferenceType *T) {
+ QualType PointeeType = getDerived().TransformType(T->getPointeeType());
+ if (PointeeType.isNull())
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ PointeeType == T->getPointeeType())
+ return QualType(T, 0);
+
+ return getDerived().RebuildLValueReferenceType(PointeeType);
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::TransformRValueReferenceType(
+ const RValueReferenceType *T) {
+ QualType PointeeType = getDerived().TransformType(T->getPointeeType());
+ if (PointeeType.isNull())
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ PointeeType == T->getPointeeType())
+ return QualType(T, 0);
+
+ return getDerived().RebuildRValueReferenceType(PointeeType);
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::TransformMemberPointerType(const MemberPointerType *T) {
+ QualType PointeeType = getDerived().TransformType(T->getPointeeType());
+ if (PointeeType.isNull())
+ return QualType();
+
+ QualType ClassType = getDerived().TransformType(QualType(T->getClass(), 0));
+ if (ClassType.isNull())
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ PointeeType == T->getPointeeType() &&
+ ClassType == QualType(T->getClass(), 0))
+ return QualType(T, 0);
+
+ return getDerived().RebuildMemberPointerType(PointeeType, ClassType);
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::TransformConstantArrayType(const ConstantArrayType *T) {
+ QualType ElementType = getDerived().TransformType(T->getElementType());
+ if (ElementType.isNull())
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ ElementType == T->getElementType())
+ return QualType(T, 0);
+
+ return getDerived().RebuildConstantArrayType(ElementType,
+ T->getSizeModifier(),
+ T->getSize(),
+ T->getIndexTypeCVRQualifiers());
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::TransformConstantArrayWithExprType(
+ const ConstantArrayWithExprType *T) {
+ QualType ElementType = getDerived().TransformType(T->getElementType());
+ if (ElementType.isNull())
+ return QualType();
+
+ // Array bounds are not potentially evaluated contexts
+ EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
+
+ Sema::OwningExprResult Size = getDerived().TransformExpr(T->getSizeExpr());
+ if (Size.isInvalid())
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ ElementType == T->getElementType() &&
+ Size.get() == T->getSizeExpr())
+ return QualType(T, 0);
+
+ return getDerived().RebuildConstantArrayWithExprType(ElementType,
+ T->getSizeModifier(),
+ T->getSize(),
+ Size.takeAs<Expr>(),
+ T->getIndexTypeCVRQualifiers(),
+ T->getBracketsRange());
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::TransformConstantArrayWithoutExprType(
+ const ConstantArrayWithoutExprType *T) {
+ QualType ElementType = getDerived().TransformType(T->getElementType());
+ if (ElementType.isNull())
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ ElementType == T->getElementType())
+ return QualType(T, 0);
+
+ return getDerived().RebuildConstantArrayWithoutExprType(ElementType,
+ T->getSizeModifier(),
+ T->getSize(),
+ T->getIndexTypeCVRQualifiers());
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformIncompleteArrayType(
+ const IncompleteArrayType *T) {
+ QualType ElementType = getDerived().TransformType(T->getElementType());
+ if (ElementType.isNull())
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ ElementType == T->getElementType())
+ return QualType(T, 0);
+
+ return getDerived().RebuildIncompleteArrayType(ElementType,
+ T->getSizeModifier(),
+ T->getIndexTypeCVRQualifiers());
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformVariableArrayType(
+ const VariableArrayType *T) {
+ QualType ElementType = getDerived().TransformType(T->getElementType());
+ if (ElementType.isNull())
+ return QualType();
+
+ // Array bounds are not potentially evaluated contexts
+ EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
+
+ Sema::OwningExprResult Size = getDerived().TransformExpr(T->getSizeExpr());
+ if (Size.isInvalid())
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ ElementType == T->getElementType() &&
+ Size.get() == T->getSizeExpr()) {
+ Size.take();
+ return QualType(T, 0);
+ }
+
+ return getDerived().RebuildVariableArrayType(ElementType,
+ T->getSizeModifier(),
+ move(Size),
+ T->getIndexTypeCVRQualifiers(),
+ T->getBracketsRange());
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformDependentSizedArrayType(
+ const DependentSizedArrayType *T) {
+ QualType ElementType = getDerived().TransformType(T->getElementType());
+ if (ElementType.isNull())
+ return QualType();
+
+ // Array bounds are not potentially evaluated contexts
+ EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
+
+ Sema::OwningExprResult Size = getDerived().TransformExpr(T->getSizeExpr());
+ if (Size.isInvalid())
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ ElementType == T->getElementType() &&
+ Size.get() == T->getSizeExpr()) {
+ Size.take();
+ return QualType(T, 0);
+ }
+
+ return getDerived().RebuildDependentSizedArrayType(ElementType,
+ T->getSizeModifier(),
+ move(Size),
+ T->getIndexTypeCVRQualifiers(),
+ T->getBracketsRange());
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformDependentSizedExtVectorType(
+ const DependentSizedExtVectorType *T) {
+ QualType ElementType = getDerived().TransformType(T->getElementType());
+ if (ElementType.isNull())
+ return QualType();
+
+ // Vector sizes are not potentially evaluated contexts
+ EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
+
+ Sema::OwningExprResult Size = getDerived().TransformExpr(T->getSizeExpr());
+ if (Size.isInvalid())
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ ElementType == T->getElementType() &&
+ Size.get() == T->getSizeExpr()) {
+ Size.take();
+ return QualType(T, 0);
+ }
+
+ return getDerived().RebuildDependentSizedExtVectorType(ElementType,
+ move(Size),
+ T->getAttributeLoc());
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformVectorType(const VectorType *T) {
+ QualType ElementType = getDerived().TransformType(T->getElementType());
+ if (ElementType.isNull())
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ ElementType == T->getElementType())
+ return QualType(T, 0);
+
+ return getDerived().RebuildVectorType(ElementType, T->getNumElements());
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::TransformExtVectorType(const ExtVectorType *T) {
+ QualType ElementType = getDerived().TransformType(T->getElementType());
+ if (ElementType.isNull())
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ ElementType == T->getElementType())
+ return QualType(T, 0);
+
+ return getDerived().RebuildExtVectorType(ElementType, T->getNumElements(),
+ /*FIXME*/SourceLocation());
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformFunctionProtoType(
+ const FunctionProtoType *T) {
+ QualType ResultType = getDerived().TransformType(T->getResultType());
+ if (ResultType.isNull())
+ return QualType();
+
+ 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 = getDerived().TransformType(*Param);
+ if (P.isNull())
+ return QualType();
+
+ ParamTypes.push_back(P);
+ }
+
+ if (!getDerived().AlwaysRebuild() &&
+ ResultType == T->getResultType() &&
+ std::equal(T->arg_type_begin(), T->arg_type_end(), ParamTypes.begin()))
+ return QualType(T, 0);
+
+ return getDerived().RebuildFunctionProtoType(ResultType, ParamTypes.data(),
+ ParamTypes.size(), T->isVariadic(),
+ T->getTypeQuals());
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformFunctionNoProtoType(
+ const FunctionNoProtoType *T) {
+ // FIXME: Implement
+ return QualType(T, 0);
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformTypedefType(const TypedefType *T) {
+ TypedefDecl *Typedef
+ = cast_or_null<TypedefDecl>(getDerived().TransformDecl(T->getDecl()));
+ if (!Typedef)
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ Typedef == T->getDecl())
+ return QualType(T, 0);
+
+ return getDerived().RebuildTypedefType(Typedef);
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformTypeOfExprType(
+ const TypeOfExprType *T) {
+ // typeof expressions are not potentially evaluated contexts
+ EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
+
+ Sema::OwningExprResult E = getDerived().TransformExpr(T->getUnderlyingExpr());
+ if (E.isInvalid())
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ E.get() == T->getUnderlyingExpr()) {
+ E.take();
+ return QualType(T, 0);
+ }
+
+ return getDerived().RebuildTypeOfExprType(move(E));
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformTypeOfType(const TypeOfType *T) {
+ QualType Underlying = getDerived().TransformType(T->getUnderlyingType());
+ if (Underlying.isNull())
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ Underlying == T->getUnderlyingType())
+ return QualType(T, 0);
+
+ return getDerived().RebuildTypeOfType(Underlying);
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformDecltypeType(const DecltypeType *T) {
+ // decltype expressions are not potentially evaluated contexts
+ EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
+
+ Sema::OwningExprResult E = getDerived().TransformExpr(T->getUnderlyingExpr());
+ if (E.isInvalid())
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ E.get() == T->getUnderlyingExpr()) {
+ E.take();
+ return QualType(T, 0);
+ }
+
+ return getDerived().RebuildDecltypeType(move(E));
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformRecordType(const RecordType *T) {
+ RecordDecl *Record
+ = cast_or_null<RecordDecl>(getDerived().TransformDecl(T->getDecl()));
+ if (!Record)
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ Record == T->getDecl())
+ return QualType(T, 0);
+
+ return getDerived().RebuildRecordType(Record);
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformEnumType(const EnumType *T) {
+ EnumDecl *Enum
+ = cast_or_null<EnumDecl>(getDerived().TransformDecl(T->getDecl()));
+ if (!Enum)
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ Enum == T->getDecl())
+ return QualType(T, 0);
+
+ return getDerived().RebuildEnumType(Enum);
+}
+
+template <typename Derived>
+QualType TreeTransform<Derived>::TransformElaboratedType(
+ const ElaboratedType *T) {
+ QualType Underlying = getDerived().TransformType(T->getUnderlyingType());
+ if (Underlying.isNull())
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ Underlying == T->getUnderlyingType())
+ return QualType(T, 0);
+
+ return getDerived().RebuildElaboratedType(Underlying, T->getTagKind());
+}
+
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformTemplateTypeParmType(
+ const TemplateTypeParmType *T) {
+ // Nothing to do
+ return QualType(T, 0);
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformTemplateSpecializationType(
+ const TemplateSpecializationType *T) {
+ TemplateName Template
+ = getDerived().TransformTemplateName(T->getTemplateName());
+ if (Template.isNull())
+ return QualType();
+
+ llvm::SmallVector<TemplateArgument, 4> NewTemplateArgs;
+ NewTemplateArgs.reserve(T->getNumArgs());
+ for (TemplateSpecializationType::iterator Arg = T->begin(), ArgEnd = T->end();
+ Arg != ArgEnd; ++Arg) {
+ TemplateArgument NewArg = getDerived().TransformTemplateArgument(*Arg);
+ if (NewArg.isNull())
+ return QualType();
+
+ NewTemplateArgs.push_back(NewArg);
+ }
+
+ // FIXME: early abort if all of the template arguments and such are the
+ // same.
+
+ // FIXME: We're missing the locations of the template name, '<', and '>'.
+ return getDerived().RebuildTemplateSpecializationType(Template,
+ NewTemplateArgs.data(),
+ NewTemplateArgs.size());
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformQualifiedNameType(
+ const QualifiedNameType *T) {
+ NestedNameSpecifier *NNS
+ = getDerived().TransformNestedNameSpecifier(T->getQualifier(),
+ SourceRange());
+ if (!NNS)
+ return QualType();
+
+ QualType Named = getDerived().TransformType(T->getNamedType());
+ if (Named.isNull())
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ NNS == T->getQualifier() &&
+ Named == T->getNamedType())
+ return QualType(T, 0);
+
+ return getDerived().RebuildQualifiedNameType(NNS, Named);
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformTypenameType(const TypenameType *T) {
+ NestedNameSpecifier *NNS
+ = getDerived().TransformNestedNameSpecifier(T->getQualifier(),
+ SourceRange(/*FIXME:*/getDerived().getBaseLocation()));
+ if (!NNS)
+ return QualType();
+
+ if (const TemplateSpecializationType *TemplateId = T->getTemplateId()) {
+ QualType NewTemplateId
+ = getDerived().TransformType(QualType(TemplateId, 0));
+ if (NewTemplateId.isNull())
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ NNS == T->getQualifier() &&
+ NewTemplateId == QualType(TemplateId, 0))
+ return QualType(T, 0);
+
+ return getDerived().RebuildTypenameType(NNS, NewTemplateId);
+ }
+
+ return getDerived().RebuildTypenameType(NNS, T->getIdentifier());
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformObjCInterfaceType(
+ const ObjCInterfaceType *T) {
+ // FIXME: Implement
+ return QualType(T, 0);
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformObjCObjectPointerType(
+ const ObjCObjectPointerType *T) {
+ // FIXME: Implement
+ return QualType(T, 0);
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformObjCProtocolListType(
+ const ObjCProtocolListType *T) {
+ assert(false && "Should not see ObjCProtocolList types");
+ return QualType(T, 0);
+}
+
+//===----------------------------------------------------------------------===//
+// Statement transformation
+//===----------------------------------------------------------------------===//
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformNullStmt(NullStmt *S) {
+ return SemaRef.Owned(S->Retain());
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformCompoundStmt(CompoundStmt *S) {
+ return getDerived().TransformCompoundStmt(S, false);
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformCompoundStmt(CompoundStmt *S,
+ bool IsStmtExpr) {
+ bool SubStmtChanged = false;
+ ASTOwningVector<&ActionBase::DeleteStmt> Statements(getSema());
+ for (CompoundStmt::body_iterator B = S->body_begin(), BEnd = S->body_end();
+ B != BEnd; ++B) {
+ OwningStmtResult Result = getDerived().TransformStmt(*B);
+ if (Result.isInvalid())
+ return getSema().StmtError();
+
+ SubStmtChanged = SubStmtChanged || Result.get() != *B;
+ Statements.push_back(Result.takeAs<Stmt>());
+ }
+
+ if (!getDerived().AlwaysRebuild() &&
+ !SubStmtChanged)
+ return SemaRef.Owned(S->Retain());
+
+ return getDerived().RebuildCompoundStmt(S->getLBracLoc(),
+ move_arg(Statements),
+ S->getRBracLoc(),
+ IsStmtExpr);
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformCaseStmt(CaseStmt *S) {
+ // The case value expressions are not potentially evaluated.
+ EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
+
+ // Transform the left-hand case value.
+ OwningExprResult LHS = getDerived().TransformExpr(S->getLHS());
+ if (LHS.isInvalid())
+ return SemaRef.StmtError();
+
+ // Transform the right-hand case value (for the GNU case-range extension).
+ OwningExprResult RHS = getDerived().TransformExpr(S->getRHS());
+ if (RHS.isInvalid())
+ return SemaRef.StmtError();
+
+ // Build the case statement.
+ // Case statements are always rebuilt so that they will attached to their
+ // transformed switch statement.
+ OwningStmtResult Case = getDerived().RebuildCaseStmt(S->getCaseLoc(),
+ move(LHS),
+ S->getEllipsisLoc(),
+ move(RHS),
+ S->getColonLoc());
+ if (Case.isInvalid())
+ return SemaRef.StmtError();
+
+ // Transform the statement following the case
+ OwningStmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt());
+ if (SubStmt.isInvalid())
+ return SemaRef.StmtError();
+
+ // Attach the body to the case statement
+ return getDerived().RebuildCaseStmtBody(move(Case), move(SubStmt));
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformDefaultStmt(DefaultStmt *S) {
+ // Transform the statement following the default case
+ OwningStmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt());
+ if (SubStmt.isInvalid())
+ return SemaRef.StmtError();
+
+ // Default statements are always rebuilt
+ return getDerived().RebuildDefaultStmt(S->getDefaultLoc(), S->getColonLoc(),
+ move(SubStmt));
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformLabelStmt(LabelStmt *S) {
+ OwningStmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt());
+ if (SubStmt.isInvalid())
+ return SemaRef.StmtError();
+
+ // FIXME: Pass the real colon location in.
+ SourceLocation ColonLoc = SemaRef.PP.getLocForEndOfToken(S->getIdentLoc());
+ return getDerived().RebuildLabelStmt(S->getIdentLoc(), S->getID(), ColonLoc,
+ move(SubStmt));
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformIfStmt(IfStmt *S) {
+ // Transform the condition
+ OwningExprResult Cond = getDerived().TransformExpr(S->getCond());
+ if (Cond.isInvalid())
+ return SemaRef.StmtError();
+
+ Sema::FullExprArg FullCond(getSema().FullExpr(Cond));
+
+ // Transform the "then" branch.
+ OwningStmtResult Then = getDerived().TransformStmt(S->getThen());
+ if (Then.isInvalid())
+ return SemaRef.StmtError();
+
+ // Transform the "else" branch.
+ OwningStmtResult Else = getDerived().TransformStmt(S->getElse());
+ if (Else.isInvalid())
+ return SemaRef.StmtError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ FullCond->get() == S->getCond() &&
+ Then.get() == S->getThen() &&
+ Else.get() == S->getElse())
+ return SemaRef.Owned(S->Retain());
+
+ return getDerived().RebuildIfStmt(S->getIfLoc(), FullCond, move(Then),
+ S->getElseLoc(), move(Else));
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformSwitchStmt(SwitchStmt *S) {
+ // Transform the condition.
+ OwningExprResult Cond = getDerived().TransformExpr(S->getCond());
+ if (Cond.isInvalid())
+ return SemaRef.StmtError();
+
+ // Rebuild the switch statement.
+ OwningStmtResult Switch = getDerived().RebuildSwitchStmtStart(move(Cond));
+ if (Switch.isInvalid())
+ return SemaRef.StmtError();
+
+ // Transform the body of the switch statement.
+ OwningStmtResult Body = getDerived().TransformStmt(S->getBody());
+ if (Body.isInvalid())
+ return SemaRef.StmtError();
+
+ // Complete the switch statement.
+ return getDerived().RebuildSwitchStmtBody(S->getSwitchLoc(), move(Switch),
+ move(Body));
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformWhileStmt(WhileStmt *S) {
+ // Transform the condition
+ OwningExprResult Cond = getDerived().TransformExpr(S->getCond());
+ if (Cond.isInvalid())
+ return SemaRef.StmtError();
+
+ Sema::FullExprArg FullCond(getSema().FullExpr(Cond));
+
+ // Transform the body
+ OwningStmtResult Body = getDerived().TransformStmt(S->getBody());
+ if (Body.isInvalid())
+ return SemaRef.StmtError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ FullCond->get() == S->getCond() &&
+ Body.get() == S->getBody())
+ return SemaRef.Owned(S->Retain());
+
+ return getDerived().RebuildWhileStmt(S->getWhileLoc(), FullCond, move(Body));
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformDoStmt(DoStmt *S) {
+ // Transform the condition
+ OwningExprResult Cond = getDerived().TransformExpr(S->getCond());
+ if (Cond.isInvalid())
+ return SemaRef.StmtError();
+
+ // Transform the body
+ OwningStmtResult Body = getDerived().TransformStmt(S->getBody());
+ if (Body.isInvalid())
+ return SemaRef.StmtError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ Cond.get() == S->getCond() &&
+ Body.get() == S->getBody())
+ return SemaRef.Owned(S->Retain());
+
+ return getDerived().RebuildDoStmt(S->getDoLoc(), move(Body), S->getWhileLoc(),
+ /*FIXME:*/S->getWhileLoc(), move(Cond),
+ S->getRParenLoc());
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformForStmt(ForStmt *S) {
+ // Transform the initialization statement
+ OwningStmtResult Init = getDerived().TransformStmt(S->getInit());
+ if (Init.isInvalid())
+ return SemaRef.StmtError();
+
+ // Transform the condition
+ OwningExprResult Cond = getDerived().TransformExpr(S->getCond());
+ if (Cond.isInvalid())
+ return SemaRef.StmtError();
+
+ // Transform the increment
+ OwningExprResult Inc = getDerived().TransformExpr(S->getInc());
+ if (Inc.isInvalid())
+ return SemaRef.StmtError();
+
+ // Transform the body
+ OwningStmtResult Body = getDerived().TransformStmt(S->getBody());
+ if (Body.isInvalid())
+ return SemaRef.StmtError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ Init.get() == S->getInit() &&
+ Cond.get() == S->getCond() &&
+ Inc.get() == S->getInc() &&
+ Body.get() == S->getBody())
+ return SemaRef.Owned(S->Retain());
+
+ return getDerived().RebuildForStmt(S->getForLoc(), S->getLParenLoc(),
+ move(Init), move(Cond), move(Inc),
+ S->getRParenLoc(), move(Body));
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformGotoStmt(GotoStmt *S) {
+ // Goto statements must always be rebuilt, to resolve the label.
+ return getDerived().RebuildGotoStmt(S->getGotoLoc(), S->getLabelLoc(),
+ S->getLabel());
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformIndirectGotoStmt(IndirectGotoStmt *S) {
+ OwningExprResult Target = getDerived().TransformExpr(S->getTarget());
+ if (Target.isInvalid())
+ return SemaRef.StmtError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ Target.get() == S->getTarget())
+ return SemaRef.Owned(S->Retain());
+
+ return getDerived().RebuildIndirectGotoStmt(S->getGotoLoc(), S->getStarLoc(),
+ move(Target));
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformContinueStmt(ContinueStmt *S) {
+ return SemaRef.Owned(S->Retain());
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformBreakStmt(BreakStmt *S) {
+ return SemaRef.Owned(S->Retain());
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformReturnStmt(ReturnStmt *S) {
+ Sema::OwningExprResult Result = getDerived().TransformExpr(S->getRetValue());
+ if (Result.isInvalid())
+ return SemaRef.StmtError();
+
+ // FIXME: We always rebuild the return statement because there is no way
+ // to tell whether the return type of the function has changed.
+ return getDerived().RebuildReturnStmt(S->getReturnLoc(), move(Result));
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformDeclStmt(DeclStmt *S) {
+ bool DeclChanged = false;
+ llvm::SmallVector<Decl *, 4> Decls;
+ for (DeclStmt::decl_iterator D = S->decl_begin(), DEnd = S->decl_end();
+ D != DEnd; ++D) {
+ Decl *Transformed = getDerived().TransformDefinition(*D);
+ if (!Transformed)
+ return SemaRef.StmtError();
+
+ if (Transformed != *D)
+ DeclChanged = true;
+
+ Decls.push_back(Transformed);
+ }
+
+ if (!getDerived().AlwaysRebuild() && !DeclChanged)
+ return SemaRef.Owned(S->Retain());
+
+ return getDerived().RebuildDeclStmt(Decls.data(), Decls.size(),
+ S->getStartLoc(), S->getEndLoc());
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformSwitchCase(SwitchCase *S) {
+ assert(false && "SwitchCase is abstract and cannot be transformed");
+ return SemaRef.Owned(S->Retain());
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformAsmStmt(AsmStmt *S) {
+ // FIXME: Implement!
+ assert(false && "Inline assembly cannot be transformed");
+ return SemaRef.Owned(S->Retain());
+}
+
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformObjCAtTryStmt(ObjCAtTryStmt *S) {
+ // FIXME: Implement this
+ assert(false && "Cannot transform an Objective-C @try statement");
+ return SemaRef.Owned(S->Retain());
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformObjCAtCatchStmt(ObjCAtCatchStmt *S) {
+ // FIXME: Implement this
+ assert(false && "Cannot transform an Objective-C @catch statement");
+ return SemaRef.Owned(S->Retain());
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
+ // FIXME: Implement this
+ assert(false && "Cannot transform an Objective-C @finally statement");
+ return SemaRef.Owned(S->Retain());
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformObjCAtThrowStmt(ObjCAtThrowStmt *S) {
+ // FIXME: Implement this
+ assert(false && "Cannot transform an Objective-C @throw statement");
+ return SemaRef.Owned(S->Retain());
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformObjCAtSynchronizedStmt(
+ ObjCAtSynchronizedStmt *S) {
+ // FIXME: Implement this
+ assert(false && "Cannot transform an Objective-C @synchronized statement");
+ return SemaRef.Owned(S->Retain());
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformObjCForCollectionStmt(
+ ObjCForCollectionStmt *S) {
+ // FIXME: Implement this
+ assert(false && "Cannot transform an Objective-C for-each statement");
+ return SemaRef.Owned(S->Retain());
+}
+
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformCXXCatchStmt(CXXCatchStmt *S) {
+ // Transform the exception declaration, if any.
+ VarDecl *Var = 0;
+ if (S->getExceptionDecl()) {
+ VarDecl *ExceptionDecl = S->getExceptionDecl();
+ TemporaryBase Rebase(*this, ExceptionDecl->getLocation(),
+ ExceptionDecl->getDeclName());
+
+ QualType T = getDerived().TransformType(ExceptionDecl->getType());
+ if (T.isNull())
+ return SemaRef.StmtError();
+
+ Var = getDerived().RebuildExceptionDecl(ExceptionDecl,
+ T,
+ ExceptionDecl->getDeclaratorInfo(),
+ ExceptionDecl->getIdentifier(),
+ ExceptionDecl->getLocation(),
+ /*FIXME: Inaccurate*/
+ SourceRange(ExceptionDecl->getLocation()));
+ if (!Var || Var->isInvalidDecl()) {
+ if (Var)
+ Var->Destroy(SemaRef.Context);
+ return SemaRef.StmtError();
+ }
+ }
+
+ // Transform the actual exception handler.
+ OwningStmtResult Handler = getDerived().TransformStmt(S->getHandlerBlock());
+ if (Handler.isInvalid()) {
+ if (Var)
+ Var->Destroy(SemaRef.Context);
+ return SemaRef.StmtError();
+ }
+
+ if (!getDerived().AlwaysRebuild() &&
+ !Var &&
+ Handler.get() == S->getHandlerBlock())
+ return SemaRef.Owned(S->Retain());
+
+ return getDerived().RebuildCXXCatchStmt(S->getCatchLoc(),
+ Var,
+ move(Handler));
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformCXXTryStmt(CXXTryStmt *S) {
+ // Transform the try block itself.
+ OwningStmtResult TryBlock
+ = getDerived().TransformCompoundStmt(S->getTryBlock());
+ if (TryBlock.isInvalid())
+ return SemaRef.StmtError();
+
+ // Transform the handlers.
+ bool HandlerChanged = false;
+ ASTOwningVector<&ActionBase::DeleteStmt> Handlers(SemaRef);
+ for (unsigned I = 0, N = S->getNumHandlers(); I != N; ++I) {
+ OwningStmtResult Handler
+ = getDerived().TransformCXXCatchStmt(S->getHandler(I));
+ if (Handler.isInvalid())
+ return SemaRef.StmtError();
+
+ HandlerChanged = HandlerChanged || Handler.get() != S->getHandler(I);
+ Handlers.push_back(Handler.takeAs<Stmt>());
+ }
+
+ if (!getDerived().AlwaysRebuild() &&
+ TryBlock.get() == S->getTryBlock() &&
+ !HandlerChanged)
+ return SemaRef.Owned(S->Retain());
+
+ return getDerived().RebuildCXXTryStmt(S->getTryLoc(), move(TryBlock),
+ move_arg(Handlers));
+}
+
+//===----------------------------------------------------------------------===//
+// Expression transformation
+//===----------------------------------------------------------------------===//
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformPredefinedExpr(PredefinedExpr *E) {
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformDeclRefExpr(DeclRefExpr *E) {
+ NamedDecl *ND
+ = dyn_cast_or_null<NamedDecl>(getDerived().TransformDecl(E->getDecl()));
+ if (!ND)
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() && ND == E->getDecl())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildDeclRefExpr(ND, E->getLocation());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformIntegerLiteral(IntegerLiteral *E) {
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformFloatingLiteral(FloatingLiteral *E) {
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformImaginaryLiteral(ImaginaryLiteral *E) {
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformStringLiteral(StringLiteral *E) {
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCharacterLiteral(CharacterLiteral *E) {
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformParenExpr(ParenExpr *E) {
+ OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr());
+ if (SubExpr.isInvalid())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getSubExpr())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildParenExpr(move(SubExpr), E->getLParen(),
+ E->getRParen());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformUnaryOperator(UnaryOperator *E) {
+ OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr());
+ if (SubExpr.isInvalid())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getSubExpr())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildUnaryOperator(E->getOperatorLoc(),
+ E->getOpcode(),
+ move(SubExpr));
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
+ if (E->isArgumentType()) {
+ QualType T = getDerived().TransformType(E->getArgumentType());
+ if (T.isNull())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() && T == E->getArgumentType())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildSizeOfAlignOf(T, E->getOperatorLoc(),
+ E->isSizeOf(),
+ E->getSourceRange());
+ }
+
+ Sema::OwningExprResult SubExpr(SemaRef);
+ {
+ // C++0x [expr.sizeof]p1:
+ // The operand is either an expression, which is an unevaluated operand
+ // [...]
+ EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
+
+ SubExpr = getDerived().TransformExpr(E->getArgumentExpr());
+ if (SubExpr.isInvalid())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getArgumentExpr())
+ return SemaRef.Owned(E->Retain());
+ }
+
+ return getDerived().RebuildSizeOfAlignOf(move(SubExpr), E->getOperatorLoc(),
+ E->isSizeOf(),
+ E->getSourceRange());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformArraySubscriptExpr(ArraySubscriptExpr *E) {
+ OwningExprResult LHS = getDerived().TransformExpr(E->getLHS());
+ if (LHS.isInvalid())
+ return SemaRef.ExprError();
+
+ OwningExprResult RHS = getDerived().TransformExpr(E->getRHS());
+ if (RHS.isInvalid())
+ return SemaRef.ExprError();
+
+
+ if (!getDerived().AlwaysRebuild() &&
+ LHS.get() == E->getLHS() &&
+ RHS.get() == E->getRHS())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildArraySubscriptExpr(move(LHS),
+ /*FIXME:*/E->getLHS()->getLocStart(),
+ move(RHS),
+ E->getRBracketLoc());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCallExpr(CallExpr *E) {
+ // Transform the callee.
+ OwningExprResult Callee = getDerived().TransformExpr(E->getCallee());
+ if (Callee.isInvalid())
+ return SemaRef.ExprError();
+
+ // Transform arguments.
+ bool ArgChanged = false;
+ ASTOwningVector<&ActionBase::DeleteExpr> Args(SemaRef);
+ llvm::SmallVector<SourceLocation, 4> FakeCommaLocs;
+ for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) {
+ OwningExprResult Arg = getDerived().TransformExpr(E->getArg(I));
+ if (Arg.isInvalid())
+ return SemaRef.ExprError();
+
+ // FIXME: Wrong source location information for the ','.
+ FakeCommaLocs.push_back(
+ SemaRef.PP.getLocForEndOfToken(E->getArg(I)->getSourceRange().getEnd()));
+
+ ArgChanged = ArgChanged || Arg.get() != E->getArg(I);
+ Args.push_back(Arg.takeAs<Expr>());
+ }
+
+ if (!getDerived().AlwaysRebuild() &&
+ Callee.get() == E->getCallee() &&
+ !ArgChanged)
+ return SemaRef.Owned(E->Retain());
+
+ // FIXME: Wrong source location information for the '('.
+ SourceLocation FakeLParenLoc
+ = ((Expr *)Callee.get())->getSourceRange().getBegin();
+ return getDerived().RebuildCallExpr(move(Callee), FakeLParenLoc,
+ move_arg(Args),
+ FakeCommaLocs.data(),
+ E->getRParenLoc());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) {
+ OwningExprResult Base = getDerived().TransformExpr(E->getBase());
+ if (Base.isInvalid())
+ return SemaRef.ExprError();
+
+ NestedNameSpecifier *Qualifier = 0;
+ if (E->hasQualifier()) {
+ Qualifier
+ = getDerived().TransformNestedNameSpecifier(E->getQualifier(),
+ E->getQualifierRange());
+ if (Qualifier == 0)
+ return SemaRef.ExprError();
+ }
+
+ NamedDecl *Member
+ = cast_or_null<NamedDecl>(getDerived().TransformDecl(E->getMemberDecl()));
+ if (!Member)
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ Base.get() == E->getBase() &&
+ Qualifier == E->getQualifier() &&
+ Member == E->getMemberDecl())
+ return SemaRef.Owned(E->Retain());
+
+ // FIXME: Bogus source location for the operator
+ SourceLocation FakeOperatorLoc
+ = SemaRef.PP.getLocForEndOfToken(E->getBase()->getSourceRange().getEnd());
+
+ return getDerived().RebuildMemberExpr(move(Base), FakeOperatorLoc,
+ E->isArrow(),
+ Qualifier,
+ E->getQualifierRange(),
+ E->getMemberLoc(),
+ Member);
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCastExpr(CastExpr *E) {
+ assert(false && "Cannot transform abstract class");
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformBinaryOperator(BinaryOperator *E) {
+ OwningExprResult LHS = getDerived().TransformExpr(E->getLHS());
+ if (LHS.isInvalid())
+ return SemaRef.ExprError();
+
+ OwningExprResult RHS = getDerived().TransformExpr(E->getRHS());
+ if (RHS.isInvalid())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ LHS.get() == E->getLHS() &&
+ RHS.get() == E->getRHS())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildBinaryOperator(E->getOperatorLoc(), E->getOpcode(),
+ move(LHS), move(RHS));
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCompoundAssignOperator(
+ CompoundAssignOperator *E) {
+ return getDerived().TransformBinaryOperator(E);
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformConditionalOperator(ConditionalOperator *E) {
+ OwningExprResult Cond = getDerived().TransformExpr(E->getCond());
+ if (Cond.isInvalid())
+ return SemaRef.ExprError();
+
+ OwningExprResult LHS = getDerived().TransformExpr(E->getLHS());
+ if (LHS.isInvalid())
+ return SemaRef.ExprError();
+
+ OwningExprResult RHS = getDerived().TransformExpr(E->getRHS());
+ if (RHS.isInvalid())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ Cond.get() == E->getCond() &&
+ LHS.get() == E->getLHS() &&
+ RHS.get() == E->getRHS())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildConditionalOperator(move(Cond),
+ E->getQuestionLoc(),
+ move(LHS),
+ E->getColonLoc(),
+ move(RHS));
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformImplicitCastExpr(ImplicitCastExpr *E) {
+ QualType T = getDerived().TransformType(E->getType());
+ if (T.isNull())
+ return SemaRef.ExprError();
+
+ OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr());
+ if (SubExpr.isInvalid())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ T == E->getType() &&
+ SubExpr.get() == E->getSubExpr())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildImplicitCastExpr(T, E->getCastKind(),
+ move(SubExpr),
+ E->isLvalueCast());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformExplicitCastExpr(ExplicitCastExpr *E) {
+ assert(false && "Cannot transform abstract class");
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCStyleCastExpr(CStyleCastExpr *E) {
+ QualType T;
+ {
+ // FIXME: Source location isn't quite accurate.
+ SourceLocation TypeStartLoc
+ = SemaRef.PP.getLocForEndOfToken(E->getLParenLoc());
+ TemporaryBase Rebase(*this, TypeStartLoc, DeclarationName());
+
+ T = getDerived().TransformType(E->getTypeAsWritten());
+ if (T.isNull())
+ return SemaRef.ExprError();
+ }
+
+ OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr());
+ if (SubExpr.isInvalid())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ T == E->getTypeAsWritten() &&
+ SubExpr.get() == E->getSubExpr())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildCStyleCaseExpr(E->getLParenLoc(), T,
+ E->getRParenLoc(),
+ move(SubExpr));
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCompoundLiteralExpr(CompoundLiteralExpr *E) {
+ QualType T;
+ {
+ // FIXME: Source location isn't quite accurate.
+ SourceLocation FakeTypeLoc
+ = SemaRef.PP.getLocForEndOfToken(E->getLParenLoc());
+ TemporaryBase Rebase(*this, FakeTypeLoc, DeclarationName());
+
+ T = getDerived().TransformType(E->getType());
+ if (T.isNull())
+ return SemaRef.ExprError();
+ }
+
+ OwningExprResult Init = getDerived().TransformExpr(E->getInitializer());
+ if (Init.isInvalid())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ T == E->getType() &&
+ Init.get() == E->getInitializer())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildCompoundLiteralExpr(E->getLParenLoc(), T,
+ /*FIXME:*/E->getInitializer()->getLocEnd(),
+ move(Init));
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformExtVectorElementExpr(ExtVectorElementExpr *E) {
+ OwningExprResult Base = getDerived().TransformExpr(E->getBase());
+ if (Base.isInvalid())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ Base.get() == E->getBase())
+ return SemaRef.Owned(E->Retain());
+
+ // FIXME: Bad source location
+ SourceLocation FakeOperatorLoc
+ = SemaRef.PP.getLocForEndOfToken(E->getBase()->getLocEnd());
+ return getDerived().RebuildExtVectorElementExpr(move(Base), FakeOperatorLoc,
+ E->getAccessorLoc(),
+ E->getAccessor());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformInitListExpr(InitListExpr *E) {
+ bool InitChanged = false;
+
+ ASTOwningVector<&ActionBase::DeleteExpr, 4> Inits(SemaRef);
+ for (unsigned I = 0, N = E->getNumInits(); I != N; ++I) {
+ OwningExprResult Init = getDerived().TransformExpr(E->getInit(I));
+ if (Init.isInvalid())
+ return SemaRef.ExprError();
+
+ InitChanged = InitChanged || Init.get() != E->getInit(I);
+ Inits.push_back(Init.takeAs<Expr>());
+ }
+
+ if (!getDerived().AlwaysRebuild() && !InitChanged)
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildInitList(E->getLBraceLoc(), move_arg(Inits),
+ E->getRBraceLoc());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformDesignatedInitExpr(DesignatedInitExpr *E) {
+ Designation Desig;
+
+ // transform the initializer value
+ OwningExprResult Init = getDerived().TransformExpr(E->getInit());
+ if (Init.isInvalid())
+ return SemaRef.ExprError();
+
+ // transform the designators.
+ ASTOwningVector<&ActionBase::DeleteExpr, 4> ArrayExprs(SemaRef);
+ bool ExprChanged = false;
+ 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 = getDerived().TransformExpr(E->getArrayIndex(*D));
+ if (Index.isInvalid())
+ return SemaRef.ExprError();
+
+ Desig.AddDesignator(Designator::getArray(Index.get(),
+ D->getLBracketLoc()));
+
+ ExprChanged = ExprChanged || Init.get() != E->getArrayIndex(*D);
+ ArrayExprs.push_back(Index.release());
+ continue;
+ }
+
+ assert(D->isArrayRangeDesignator() && "New kind of designator?");
+ OwningExprResult Start
+ = getDerived().TransformExpr(E->getArrayRangeStart(*D));
+ if (Start.isInvalid())
+ return SemaRef.ExprError();
+
+ OwningExprResult End = getDerived().TransformExpr(E->getArrayRangeEnd(*D));
+ if (End.isInvalid())
+ return SemaRef.ExprError();
+
+ Desig.AddDesignator(Designator::getArrayRange(Start.get(),
+ End.get(),
+ D->getLBracketLoc(),
+ D->getEllipsisLoc()));
+
+ ExprChanged = ExprChanged || Start.get() != E->getArrayRangeStart(*D) ||
+ End.get() != E->getArrayRangeEnd(*D);
+
+ ArrayExprs.push_back(Start.release());
+ ArrayExprs.push_back(End.release());
+ }
+
+ if (!getDerived().AlwaysRebuild() &&
+ Init.get() == E->getInit() &&
+ !ExprChanged)
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildDesignatedInitExpr(Desig, move_arg(ArrayExprs),
+ E->getEqualOrColonLoc(),
+ E->usesGNUSyntax(), move(Init));
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformImplicitValueInitExpr(
+ ImplicitValueInitExpr *E) {
+ QualType T = getDerived().TransformType(E->getType());
+ if (T.isNull())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ T == E->getType())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildImplicitValueInitExpr(T);
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformVAArgExpr(VAArgExpr *E) {
+ // FIXME: Do we want the type as written?
+ QualType T;
+
+ {
+ // FIXME: Source location isn't quite accurate.
+ TemporaryBase Rebase(*this, E->getBuiltinLoc(), DeclarationName());
+ T = getDerived().TransformType(E->getType());
+ if (T.isNull())
+ return SemaRef.ExprError();
+ }
+
+ OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr());
+ if (SubExpr.isInvalid())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ T == E->getType() &&
+ SubExpr.get() == E->getSubExpr())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildVAArgExpr(E->getBuiltinLoc(), move(SubExpr),
+ T, E->getRParenLoc());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformParenListExpr(ParenListExpr *E) {
+ bool ArgumentChanged = false;
+ ASTOwningVector<&ActionBase::DeleteExpr, 4> Inits(SemaRef);
+ for (unsigned I = 0, N = E->getNumExprs(); I != N; ++I) {
+ OwningExprResult Init = getDerived().TransformExpr(E->getExpr(I));
+ if (Init.isInvalid())
+ return SemaRef.ExprError();
+
+ ArgumentChanged = ArgumentChanged || Init.get() != E->getExpr(I);
+ Inits.push_back(Init.takeAs<Expr>());
+ }
+
+ return getDerived().RebuildParenListExpr(E->getLParenLoc(),
+ move_arg(Inits),
+ E->getRParenLoc());
+}
+
+/// \brief Transform an address-of-label expression.
+///
+/// By default, the transformation of an address-of-label expression always
+/// rebuilds the expression, so that the label identifier can be resolved to
+/// the corresponding label statement by semantic analysis.
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformAddrLabelExpr(AddrLabelExpr *E) {
+ return getDerived().RebuildAddrLabelExpr(E->getAmpAmpLoc(), E->getLabelLoc(),
+ E->getLabel());
+}
+
+template<typename Derived>
+Sema::OwningExprResult TreeTransform<Derived>::TransformStmtExpr(StmtExpr *E) {
+ OwningStmtResult SubStmt
+ = getDerived().TransformCompoundStmt(E->getSubStmt(), true);
+ if (SubStmt.isInvalid())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ SubStmt.get() == E->getSubStmt())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildStmtExpr(E->getLParenLoc(),
+ move(SubStmt),
+ E->getRParenLoc());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformTypesCompatibleExpr(TypesCompatibleExpr *E) {
+ QualType T1, T2;
+ {
+ // FIXME: Source location isn't quite accurate.
+ TemporaryBase Rebase(*this, E->getBuiltinLoc(), DeclarationName());
+
+ T1 = getDerived().TransformType(E->getArgType1());
+ if (T1.isNull())
+ return SemaRef.ExprError();
+
+ T2 = getDerived().TransformType(E->getArgType2());
+ if (T2.isNull())
+ return SemaRef.ExprError();
+ }
+
+ if (!getDerived().AlwaysRebuild() &&
+ T1 == E->getArgType1() &&
+ T2 == E->getArgType2())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildTypesCompatibleExpr(E->getBuiltinLoc(),
+ T1, T2, E->getRParenLoc());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformChooseExpr(ChooseExpr *E) {
+ OwningExprResult Cond = getDerived().TransformExpr(E->getCond());
+ if (Cond.isInvalid())
+ return SemaRef.ExprError();
+
+ OwningExprResult LHS = getDerived().TransformExpr(E->getLHS());
+ if (LHS.isInvalid())
+ return SemaRef.ExprError();
+
+ OwningExprResult RHS = getDerived().TransformExpr(E->getRHS());
+ if (RHS.isInvalid())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ Cond.get() == E->getCond() &&
+ LHS.get() == E->getLHS() &&
+ RHS.get() == E->getRHS())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildChooseExpr(E->getBuiltinLoc(),
+ move(Cond), move(LHS), move(RHS),
+ E->getRParenLoc());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformGNUNullExpr(GNUNullExpr *E) {
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
+ OwningExprResult Callee = getDerived().TransformExpr(E->getCallee());
+ if (Callee.isInvalid())
+ return SemaRef.ExprError();
+
+ OwningExprResult First = getDerived().TransformExpr(E->getArg(0));
+ if (First.isInvalid())
+ return SemaRef.ExprError();
+
+ OwningExprResult Second(SemaRef);
+ if (E->getNumArgs() == 2) {
+ Second = getDerived().TransformExpr(E->getArg(1));
+ if (Second.isInvalid())
+ return SemaRef.ExprError();
+ }
+
+ if (!getDerived().AlwaysRebuild() &&
+ Callee.get() == E->getCallee() &&
+ First.get() == E->getArg(0) &&
+ (E->getNumArgs() != 2 || Second.get() == E->getArg(1)))
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildCXXOperatorCallExpr(E->getOperator(),
+ E->getOperatorLoc(),
+ move(Callee),
+ move(First),
+ move(Second));
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXMemberCallExpr(CXXMemberCallExpr *E) {
+ return getDerived().TransformCallExpr(E);
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) {
+ QualType ExplicitTy;
+ {
+ // FIXME: Source location isn't quite accurate.
+ SourceLocation TypeStartLoc
+ = SemaRef.PP.getLocForEndOfToken(E->getOperatorLoc());
+ TemporaryBase Rebase(*this, TypeStartLoc, DeclarationName());
+
+ ExplicitTy = getDerived().TransformType(E->getTypeAsWritten());
+ if (ExplicitTy.isNull())
+ return SemaRef.ExprError();
+ }
+
+ OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr());
+ if (SubExpr.isInvalid())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ ExplicitTy == E->getTypeAsWritten() &&
+ SubExpr.get() == E->getSubExpr())
+ return SemaRef.Owned(E->Retain());
+
+ // FIXME: Poor source location information here.
+ SourceLocation FakeLAngleLoc
+ = SemaRef.PP.getLocForEndOfToken(E->getOperatorLoc());
+ SourceLocation FakeRAngleLoc = E->getSubExpr()->getSourceRange().getBegin();
+ SourceLocation FakeRParenLoc
+ = SemaRef.PP.getLocForEndOfToken(
+ E->getSubExpr()->getSourceRange().getEnd());
+ return getDerived().RebuildCXXNamedCastExpr(E->getOperatorLoc(),
+ E->getStmtClass(),
+ FakeLAngleLoc,
+ ExplicitTy,
+ FakeRAngleLoc,
+ FakeRAngleLoc,
+ move(SubExpr),
+ FakeRParenLoc);
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXStaticCastExpr(CXXStaticCastExpr *E) {
+ return getDerived().TransformCXXNamedCastExpr(E);
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXDynamicCastExpr(CXXDynamicCastExpr *E) {
+ return getDerived().TransformCXXNamedCastExpr(E);
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXReinterpretCastExpr(
+ CXXReinterpretCastExpr *E) {
+ return getDerived().TransformCXXNamedCastExpr(E);
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXConstCastExpr(CXXConstCastExpr *E) {
+ return getDerived().TransformCXXNamedCastExpr(E);
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXFunctionalCastExpr(
+ CXXFunctionalCastExpr *E) {
+ QualType ExplicitTy;
+ {
+ TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName());
+
+ ExplicitTy = getDerived().TransformType(E->getTypeAsWritten());
+ if (ExplicitTy.isNull())
+ return SemaRef.ExprError();
+ }
+
+ OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr());
+ if (SubExpr.isInvalid())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ ExplicitTy == E->getTypeAsWritten() &&
+ SubExpr.get() == E->getSubExpr())
+ return SemaRef.Owned(E->Retain());
+
+ // FIXME: The end of the type's source range is wrong
+ return getDerived().RebuildCXXFunctionalCastExpr(
+ /*FIXME:*/SourceRange(E->getTypeBeginLoc()),
+ ExplicitTy,
+ /*FIXME:*/E->getSubExpr()->getLocStart(),
+ move(SubExpr),
+ E->getRParenLoc());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXTypeidExpr(CXXTypeidExpr *E) {
+ if (E->isTypeOperand()) {
+ TemporaryBase Rebase(*this, /*FIXME*/E->getLocStart(), DeclarationName());
+
+ QualType T = getDerived().TransformType(E->getTypeOperand());
+ if (T.isNull())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ T == E->getTypeOperand())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildCXXTypeidExpr(E->getLocStart(),
+ /*FIXME:*/E->getLocStart(),
+ T,
+ E->getLocEnd());
+ }
+
+ // We don't know whether the expression is potentially evaluated until
+ // after we perform semantic analysis, so the expression is potentially
+ // potentially evaluated.
+ EnterExpressionEvaluationContext Unevaluated(SemaRef,
+ Action::PotentiallyPotentiallyEvaluated);
+
+ OwningExprResult SubExpr = getDerived().TransformExpr(E->getExprOperand());
+ if (SubExpr.isInvalid())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ SubExpr.get() == E->getExprOperand())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildCXXTypeidExpr(E->getLocStart(),
+ /*FIXME:*/E->getLocStart(),
+ move(SubExpr),
+ E->getLocEnd());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) {
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXNullPtrLiteralExpr(
+ CXXNullPtrLiteralExpr *E) {
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXThisExpr(CXXThisExpr *E) {
+ TemporaryBase Rebase(*this, E->getLocStart(), DeclarationName());
+
+ QualType T = getDerived().TransformType(E->getType());
+ if (T.isNull())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ T == E->getType())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildCXXThisExpr(E->getLocStart(), T);
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXThrowExpr(CXXThrowExpr *E) {
+ OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr());
+ if (SubExpr.isInvalid())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ SubExpr.get() == E->getSubExpr())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildCXXThrowExpr(E->getThrowLoc(), move(SubExpr));
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
+ ParmVarDecl *Param
+ = cast_or_null<ParmVarDecl>(getDerived().TransformDecl(E->getParam()));
+ if (!Param)
+ return SemaRef.ExprError();
+
+ if (getDerived().AlwaysRebuild() &&
+ Param == E->getParam())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildCXXDefaultArgExpr(Param);
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) {
+ TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName());
+
+ QualType T = getDerived().TransformType(E->getType());
+ if (T.isNull())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ T == E->getType())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildCXXZeroInitValueExpr(E->getTypeBeginLoc(),
+ /*FIXME:*/E->getTypeBeginLoc(),
+ T,
+ E->getRParenLoc());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXConditionDeclExpr(CXXConditionDeclExpr *E) {
+ VarDecl *Var
+ = cast_or_null<VarDecl>(getDerived().TransformDefinition(E->getVarDecl()));
+ if (!Var)
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ Var == E->getVarDecl())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildCXXConditionDeclExpr(E->getStartLoc(),
+ /*FIXME:*/E->getStartLoc(),
+ Var);
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
+ // Transform the type that we're allocating
+ TemporaryBase Rebase(*this, E->getLocStart(), DeclarationName());
+ QualType AllocType = getDerived().TransformType(E->getAllocatedType());
+ if (AllocType.isNull())
+ return SemaRef.ExprError();
+
+ // Transform the size of the array we're allocating (if any).
+ OwningExprResult ArraySize = getDerived().TransformExpr(E->getArraySize());
+ if (ArraySize.isInvalid())
+ return SemaRef.ExprError();
+
+ // Transform the placement arguments (if any).
+ bool ArgumentChanged = false;
+ ASTOwningVector<&ActionBase::DeleteExpr> PlacementArgs(SemaRef);
+ for (unsigned I = 0, N = E->getNumPlacementArgs(); I != N; ++I) {
+ OwningExprResult Arg = getDerived().TransformExpr(E->getPlacementArg(I));
+ if (Arg.isInvalid())
+ return SemaRef.ExprError();
+
+ ArgumentChanged = ArgumentChanged || Arg.get() != E->getPlacementArg(I);
+ PlacementArgs.push_back(Arg.take());
+ }
+
+ // transform the constructor arguments (if any).
+ ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(SemaRef);
+ for (unsigned I = 0, N = E->getNumConstructorArgs(); I != N; ++I) {
+ OwningExprResult Arg = getDerived().TransformExpr(E->getConstructorArg(I));
+ if (Arg.isInvalid())
+ return SemaRef.ExprError();
+
+ ArgumentChanged = ArgumentChanged || Arg.get() != E->getConstructorArg(I);
+ ConstructorArgs.push_back(Arg.take());
+ }
+
+ if (!getDerived().AlwaysRebuild() &&
+ AllocType == E->getAllocatedType() &&
+ ArraySize.get() == E->getArraySize() &&
+ !ArgumentChanged)
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildCXXNewExpr(E->getLocStart(),
+ E->isGlobalNew(),
+ /*FIXME:*/E->getLocStart(),
+ move_arg(PlacementArgs),
+ /*FIXME:*/E->getLocStart(),
+ E->isParenTypeId(),
+ AllocType,
+ /*FIXME:*/E->getLocStart(),
+ /*FIXME:*/SourceRange(),
+ move(ArraySize),
+ /*FIXME:*/E->getLocStart(),
+ move_arg(ConstructorArgs),
+ E->getLocEnd());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXDeleteExpr(CXXDeleteExpr *E) {
+ OwningExprResult Operand = getDerived().TransformExpr(E->getArgument());
+ if (Operand.isInvalid())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ Operand.get() == E->getArgument())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildCXXDeleteExpr(E->getLocStart(),
+ E->isGlobalDelete(),
+ E->isArrayForm(),
+ move(Operand));
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXPseudoDestructorExpr(
+ CXXPseudoDestructorExpr *E) {
+ OwningExprResult Base = getDerived().TransformExpr(E->getBase());
+ if (Base.isInvalid())
+ return SemaRef.ExprError();
+
+ NestedNameSpecifier *Qualifier
+ = getDerived().TransformNestedNameSpecifier(E->getQualifier(),
+ E->getQualifierRange());
+ if (E->getQualifier() && !Qualifier)
+ return SemaRef.ExprError();
+
+ QualType DestroyedType;
+ {
+ TemporaryBase Rebase(*this, E->getDestroyedTypeLoc(), DeclarationName());
+ DestroyedType = getDerived().TransformType(E->getDestroyedType());
+ if (DestroyedType.isNull())
+ return SemaRef.ExprError();
+ }
+
+ if (!getDerived().AlwaysRebuild() &&
+ Base.get() == E->getBase() &&
+ Qualifier == E->getQualifier() &&
+ DestroyedType == E->getDestroyedType())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildCXXPseudoDestructorExpr(move(Base),
+ E->getOperatorLoc(),
+ E->isArrow(),
+ E->getDestroyedTypeLoc(),
+ DestroyedType,
+ Qualifier,
+ E->getQualifierRange());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformUnresolvedFunctionNameExpr(
+ UnresolvedFunctionNameExpr *E) {
+ // There is no transformation we can apply to an unresolved function name.
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) {
+ TemporaryBase Rebase(*this, /*FIXME*/E->getLocStart(), DeclarationName());
+
+ QualType T = getDerived().TransformType(E->getQueriedType());
+ if (T.isNull())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ T == E->getQueriedType())
+ return SemaRef.Owned(E->Retain());
+
+ // FIXME: Bad location information
+ SourceLocation FakeLParenLoc
+ = SemaRef.PP.getLocForEndOfToken(E->getLocStart());
+
+ return getDerived().RebuildUnaryTypeTrait(E->getTrait(),
+ E->getLocStart(),
+ /*FIXME:*/FakeLParenLoc,
+ T,
+ E->getLocEnd());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformQualifiedDeclRefExpr(QualifiedDeclRefExpr *E) {
+ NestedNameSpecifier *NNS
+ = getDerived().TransformNestedNameSpecifier(E->getQualifier(),
+ E->getQualifierRange());
+ if (!NNS)
+ return SemaRef.ExprError();
+
+ NamedDecl *ND
+ = dyn_cast_or_null<NamedDecl>(getDerived().TransformDecl(E->getDecl()));
+ if (!ND)
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ NNS == E->getQualifier() &&
+ ND == E->getDecl())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildQualifiedDeclRefExpr(NNS,
+ E->getQualifierRange(),
+ ND,
+ E->getLocation(),
+ /*FIXME:*/false);
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformUnresolvedDeclRefExpr(
+ UnresolvedDeclRefExpr *E) {
+ NestedNameSpecifier *NNS
+ = getDerived().TransformNestedNameSpecifier(E->getQualifier(),
+ E->getQualifierRange());
+ if (!NNS)
+ return SemaRef.ExprError();
+
+ DeclarationName Name
+ = getDerived().TransformDeclarationName(E->getDeclName(), E->getLocation());
+ if (!Name)
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ NNS == E->getQualifier() &&
+ Name == E->getDeclName())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildUnresolvedDeclRefExpr(NNS,
+ E->getQualifierRange(),
+ Name,
+ E->getLocation(),
+ /*FIXME:*/false);
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformTemplateIdRefExpr(TemplateIdRefExpr *E) {
+ TemplateName Template
+ = getDerived().TransformTemplateName(E->getTemplateName());
+ if (Template.isNull())
+ return SemaRef.ExprError();
+
+ llvm::SmallVector<TemplateArgument, 4> TransArgs;
+ for (unsigned I = 0, N = E->getNumTemplateArgs(); I != N; ++I) {
+ TemplateArgument TransArg
+ = getDerived().TransformTemplateArgument(E->getTemplateArgs()[I]);
+ if (TransArg.isNull())
+ return SemaRef.ExprError();
+
+ TransArgs.push_back(TransArg);
+ }
+
+ // FIXME: Would like to avoid rebuilding if nothing changed, but we can't
+ // compare template arguments (yet).
+
+ // FIXME: It's possible that we'll find out now that the template name
+ // actually refers to a type, in which case the caller is actually dealing
+ // with a functional cast. Give a reasonable error message!
+ return getDerived().RebuildTemplateIdExpr(Template, E->getTemplateNameLoc(),
+ E->getLAngleLoc(),
+ TransArgs.data(),
+ TransArgs.size(),
+ E->getRAngleLoc());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) {
+ TemporaryBase Rebase(*this, /*FIXME*/E->getLocStart(), DeclarationName());
+
+ QualType T = getDerived().TransformType(E->getType());
+ if (T.isNull())
+ return SemaRef.ExprError();
+
+ CXXConstructorDecl *Constructor
+ = cast_or_null<CXXConstructorDecl>(
+ getDerived().TransformDecl(E->getConstructor()));
+ if (!Constructor)
+ return SemaRef.ExprError();
+
+ bool ArgumentChanged = false;
+ ASTOwningVector<&ActionBase::DeleteExpr> Args(SemaRef);
+ for (CXXConstructExpr::arg_iterator Arg = E->arg_begin(),
+ ArgEnd = E->arg_end();
+ Arg != ArgEnd; ++Arg) {
+ OwningExprResult TransArg = getDerived().TransformExpr(*Arg);
+ if (TransArg.isInvalid())
+ return SemaRef.ExprError();
+
+ ArgumentChanged = ArgumentChanged || TransArg.get() != *Arg;
+ Args.push_back(TransArg.takeAs<Expr>());
+ }
+
+ if (!getDerived().AlwaysRebuild() &&
+ T == E->getType() &&
+ Constructor == E->getConstructor() &&
+ !ArgumentChanged)
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildCXXConstructExpr(T, Constructor, E->isElidable(),
+ move_arg(Args));
+}
+
+/// \brief Transform a C++ temporary-binding expression.
+///
+/// The transformation of a temporary-binding expression always attempts to
+/// bind a new temporary variable to its subexpression, even if the
+/// subexpression itself did not change, because the temporary variable itself
+/// must be unique.
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
+ OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr());
+ if (SubExpr.isInvalid())
+ return SemaRef.ExprError();
+
+ return SemaRef.MaybeBindToTemporary(SubExpr.takeAs<Expr>());
+}
+
+/// \brief Transform a C++ expression that contains temporaries that should
+/// be destroyed after the expression is evaluated.
+///
+/// The transformation of a full expression always attempts to build a new
+/// CXXExprWithTemporaries expression, even if the
+/// subexpression itself did not change, because it will need to capture the
+/// the new temporary variables introduced in the subexpression.
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXExprWithTemporaries(
+ CXXExprWithTemporaries *E) {
+ OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr());
+ if (SubExpr.isInvalid())
+ return SemaRef.ExprError();
+
+ return SemaRef.Owned(
+ SemaRef.MaybeCreateCXXExprWithTemporaries(SubExpr.takeAs<Expr>(),
+ E->shouldDestroyTemporaries()));
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXTemporaryObjectExpr(
+ CXXTemporaryObjectExpr *E) {
+ TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName());
+ QualType T = getDerived().TransformType(E->getType());
+ if (T.isNull())
+ return SemaRef.ExprError();
+
+ CXXConstructorDecl *Constructor
+ = cast_or_null<CXXConstructorDecl>(
+ getDerived().TransformDecl(E->getConstructor()));
+ if (!Constructor)
+ return SemaRef.ExprError();
+
+ bool ArgumentChanged = false;
+ 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 TransArg = getDerived().TransformExpr(*Arg);
+ if (TransArg.isInvalid())
+ return SemaRef.ExprError();
+
+ ArgumentChanged = ArgumentChanged || TransArg.get() != *Arg;
+ Args.push_back((Expr *)TransArg.release());
+ }
+
+ if (!getDerived().AlwaysRebuild() &&
+ T == E->getType() &&
+ Constructor == E->getConstructor() &&
+ !ArgumentChanged)
+ return SemaRef.Owned(E->Retain());
+
+ // FIXME: Bogus location information
+ SourceLocation CommaLoc;
+ if (Args.size() > 1) {
+ Expr *First = (Expr *)Args[0];
+ CommaLoc
+ = SemaRef.PP.getLocForEndOfToken(First->getSourceRange().getEnd());
+ }
+ return getDerived().RebuildCXXTemporaryObjectExpr(E->getTypeBeginLoc(),
+ T,
+ /*FIXME:*/E->getTypeBeginLoc(),
+ move_arg(Args),
+ &CommaLoc,
+ E->getLocEnd());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXUnresolvedConstructExpr(
+ CXXUnresolvedConstructExpr *E) {
+ TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName());
+ QualType T = getDerived().TransformType(E->getTypeAsWritten());
+ if (T.isNull())
+ return SemaRef.ExprError();
+
+ bool ArgumentChanged = false;
+ 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 TransArg = getDerived().TransformExpr(*Arg);
+ if (TransArg.isInvalid())
+ return SemaRef.ExprError();
+
+ ArgumentChanged = ArgumentChanged || TransArg.get() != *Arg;
+ FakeCommaLocs.push_back(
+ SemaRef.PP.getLocForEndOfToken((*Arg)->getLocEnd()));
+ Args.push_back(TransArg.takeAs<Expr>());
+ }
+
+ if (!getDerived().AlwaysRebuild() &&
+ T == E->getTypeAsWritten() &&
+ !ArgumentChanged)
+ return SemaRef.Owned(E->Retain());
+
+ // FIXME: we're faking the locations of the commas
+ return getDerived().RebuildCXXUnresolvedConstructExpr(E->getTypeBeginLoc(),
+ T,
+ E->getLParenLoc(),
+ move_arg(Args),
+ FakeCommaLocs.data(),
+ E->getRParenLoc());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXUnresolvedMemberExpr(
+ CXXUnresolvedMemberExpr *E) {
+ // Transform the base of the expression.
+ OwningExprResult Base = getDerived().TransformExpr(E->getBase());
+ if (Base.isInvalid())
+ return SemaRef.ExprError();
+
+ Sema::TypeTy *ObjectType = 0;
+ Base = SemaRef.ActOnStartCXXMemberReference(0, move(Base),
+ E->getOperatorLoc(),
+ E->isArrow()? tok::arrow : tok::period,
+ ObjectType);
+ if (Base.isInvalid())
+ return SemaRef.ExprError();
+
+ // FIXME: The first qualifier found might be a template type parameter,
+ // in which case there is no transformed declaration to refer to (it might
+ // refer to a built-in type!).
+ NamedDecl *FirstQualifierInScope
+ = cast_or_null<NamedDecl>(
+ getDerived().TransformDecl(E->getFirstQualifierFoundInScope()));
+
+ NestedNameSpecifier *Qualifier = 0;
+ if (E->getQualifier()) {
+ Qualifier = getDerived().TransformNestedNameSpecifier(E->getQualifier(),
+ E->getQualifierRange(),
+ QualType::getFromOpaquePtr(ObjectType),
+ FirstQualifierInScope);
+ if (!Qualifier)
+ return SemaRef.ExprError();
+ }
+
+ DeclarationName Name
+ = getDerived().TransformDeclarationName(E->getMember(), E->getMemberLoc());
+ if (!Name)
+ return SemaRef.ExprError();
+
+ if (!E->hasExplicitTemplateArgumentList()) {
+ // This is a reference to a member without an explicitly-specified
+ // template argument list. Optimize for this common case.
+ if (!getDerived().AlwaysRebuild() &&
+ Base.get() == E->getBase() &&
+ Qualifier == E->getQualifier() &&
+ Name == E->getMember() &&
+ FirstQualifierInScope == E->getFirstQualifierFoundInScope())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildCXXUnresolvedMemberExpr(move(Base),
+ E->isArrow(),
+ E->getOperatorLoc(),
+ Qualifier,
+ E->getQualifierRange(),
+ Name,
+ E->getMemberLoc(),
+ FirstQualifierInScope);
+ }
+
+ // FIXME: This is an ugly hack, which forces the same template name to
+ // be looked up multiple times. Yuck!
+ // FIXME: This also won't work for, e.g., x->template operator+<int>
+ TemplateName OrigTemplateName
+ = SemaRef.Context.getDependentTemplateName(0, Name.getAsIdentifierInfo());
+
+ TemplateName Template
+ = getDerived().TransformTemplateName(OrigTemplateName,
+ QualType::getFromOpaquePtr(ObjectType));
+ if (Template.isNull())
+ return SemaRef.ExprError();
+
+ llvm::SmallVector<TemplateArgument, 4> TransArgs;
+ for (unsigned I = 0, N = E->getNumTemplateArgs(); I != N; ++I) {
+ TemplateArgument TransArg
+ = getDerived().TransformTemplateArgument(E->getTemplateArgs()[I]);
+ if (TransArg.isNull())
+ return SemaRef.ExprError();
+
+ TransArgs.push_back(TransArg);
+ }
+
+ return getDerived().RebuildCXXUnresolvedMemberExpr(move(Base),
+ E->isArrow(),
+ E->getOperatorLoc(),
+ Qualifier,
+ E->getQualifierRange(),
+ Template,
+ E->getMemberLoc(),
+ FirstQualifierInScope,
+ E->getLAngleLoc(),
+ TransArgs.data(),
+ TransArgs.size(),
+ E->getRAngleLoc());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformObjCStringLiteral(ObjCStringLiteral *E) {
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformObjCEncodeExpr(ObjCEncodeExpr *E) {
+ // FIXME: poor source location
+ TemporaryBase Rebase(*this, E->getAtLoc(), DeclarationName());
+ QualType EncodedType = getDerived().TransformType(E->getEncodedType());
+ if (EncodedType.isNull())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ EncodedType == E->getEncodedType())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildObjCEncodeExpr(E->getAtLoc(),
+ EncodedType,
+ E->getRParenLoc());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) {
+ // FIXME: Implement this!
+ assert(false && "Cannot transform Objective-C expressions yet");
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformObjCSelectorExpr(ObjCSelectorExpr *E) {
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformObjCProtocolExpr(ObjCProtocolExpr *E) {
+ ObjCProtocolDecl *Protocol
+ = cast_or_null<ObjCProtocolDecl>(
+ getDerived().TransformDecl(E->getProtocol()));
+ if (!Protocol)
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ Protocol == E->getProtocol())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildObjCProtocolExpr(Protocol,
+ E->getAtLoc(),
+ /*FIXME:*/E->getAtLoc(),
+ /*FIXME:*/E->getAtLoc(),
+ E->getRParenLoc());
+
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformObjCIvarRefExpr(ObjCIvarRefExpr *E) {
+ // FIXME: Implement this!
+ assert(false && "Cannot transform Objective-C expressions yet");
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
+ // FIXME: Implement this!
+ assert(false && "Cannot transform Objective-C expressions yet");
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformObjCImplicitSetterGetterRefExpr(
+ ObjCImplicitSetterGetterRefExpr *E) {
+ // FIXME: Implement this!
+ assert(false && "Cannot transform Objective-C expressions yet");
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformObjCSuperExpr(ObjCSuperExpr *E) {
+ // FIXME: Implement this!
+ assert(false && "Cannot transform Objective-C expressions yet");
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformObjCIsaExpr(ObjCIsaExpr *E) {
+ // FIXME: Implement this!
+ assert(false && "Cannot transform Objective-C expressions yet");
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformShuffleVectorExpr(ShuffleVectorExpr *E) {
+ bool ArgumentChanged = false;
+ ASTOwningVector<&ActionBase::DeleteExpr> SubExprs(SemaRef);
+ for (unsigned I = 0, N = E->getNumSubExprs(); I != N; ++I) {
+ OwningExprResult SubExpr = getDerived().TransformExpr(E->getExpr(I));
+ if (SubExpr.isInvalid())
+ return SemaRef.ExprError();
+
+ ArgumentChanged = ArgumentChanged || SubExpr.get() != E->getExpr(I);
+ SubExprs.push_back(SubExpr.takeAs<Expr>());
+ }
+
+ if (!getDerived().AlwaysRebuild() &&
+ !ArgumentChanged)
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildShuffleVectorExpr(E->getBuiltinLoc(),
+ move_arg(SubExprs),
+ E->getRParenLoc());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
+ // FIXME: Implement this!
+ assert(false && "Cannot transform block expressions yet");
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformBlockDeclRefExpr(BlockDeclRefExpr *E) {
+ // FIXME: Implement this!
+ assert(false && "Cannot transform block-related expressions yet");
+ return SemaRef.Owned(E->Retain());
+}
+
+//===----------------------------------------------------------------------===//
+// Type reconstruction
+//===----------------------------------------------------------------------===//
+
+template<typename Derived>
+QualType TreeTransform<Derived>::RebuildPointerType(QualType PointeeType) {
+ return SemaRef.BuildPointerType(PointeeType, Qualifiers(),
+ getDerived().getBaseLocation(),
+ getDerived().getBaseEntity());
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::RebuildBlockPointerType(QualType PointeeType) {
+ return SemaRef.BuildBlockPointerType(PointeeType, Qualifiers(),
+ getDerived().getBaseLocation(),
+ getDerived().getBaseEntity());
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::RebuildLValueReferenceType(QualType ReferentType) {
+ return SemaRef.BuildReferenceType(ReferentType, true, Qualifiers(),
+ getDerived().getBaseLocation(),
+ getDerived().getBaseEntity());
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::RebuildRValueReferenceType(QualType ReferentType) {
+ return SemaRef.BuildReferenceType(ReferentType, false, Qualifiers(),
+ getDerived().getBaseLocation(),
+ getDerived().getBaseEntity());
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::RebuildMemberPointerType(QualType PointeeType,
+ QualType ClassType) {
+ return SemaRef.BuildMemberPointerType(PointeeType, ClassType, Qualifiers(),
+ getDerived().getBaseLocation(),
+ getDerived().getBaseEntity());
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::RebuildArrayType(QualType ElementType,
+ ArrayType::ArraySizeModifier SizeMod,
+ const llvm::APInt *Size,
+ Expr *SizeExpr,
+ unsigned IndexTypeQuals,
+ SourceRange BracketsRange) {
+ if (SizeExpr || !Size)
+ return SemaRef.BuildArrayType(ElementType, SizeMod, SizeExpr,
+ IndexTypeQuals, BracketsRange,
+ getDerived().getBaseEntity());
+
+ 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, /*FIXME*/BracketsRange.getBegin());
+ return SemaRef.BuildArrayType(ElementType, SizeMod, &ArraySize,
+ IndexTypeQuals, BracketsRange,
+ getDerived().getBaseEntity());
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::RebuildConstantArrayType(QualType ElementType,
+ ArrayType::ArraySizeModifier SizeMod,
+ const llvm::APInt &Size,
+ unsigned IndexTypeQuals) {
+ return getDerived().RebuildArrayType(ElementType, SizeMod, &Size, 0,
+ IndexTypeQuals, SourceRange());
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::RebuildConstantArrayWithExprType(QualType ElementType,
+ ArrayType::ArraySizeModifier SizeMod,
+ const llvm::APInt &Size,
+ Expr *SizeExpr,
+ unsigned IndexTypeQuals,
+ SourceRange BracketsRange) {
+ return getDerived().RebuildArrayType(ElementType, SizeMod, &Size, SizeExpr,
+ IndexTypeQuals, BracketsRange);
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::RebuildConstantArrayWithoutExprType(
+ QualType ElementType,
+ ArrayType::ArraySizeModifier SizeMod,
+ const llvm::APInt &Size,
+ unsigned IndexTypeQuals) {
+ return getDerived().RebuildArrayType(ElementType, SizeMod, &Size, 0,
+ IndexTypeQuals, SourceRange());
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::RebuildIncompleteArrayType(QualType ElementType,
+ ArrayType::ArraySizeModifier SizeMod,
+ unsigned IndexTypeQuals) {
+ return getDerived().RebuildArrayType(ElementType, SizeMod, 0, 0,
+ IndexTypeQuals, SourceRange());
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::RebuildVariableArrayType(QualType ElementType,
+ ArrayType::ArraySizeModifier SizeMod,
+ ExprArg SizeExpr,
+ unsigned IndexTypeQuals,
+ SourceRange BracketsRange) {
+ return getDerived().RebuildArrayType(ElementType, SizeMod, 0,
+ SizeExpr.takeAs<Expr>(),
+ IndexTypeQuals, BracketsRange);
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::RebuildDependentSizedArrayType(QualType ElementType,
+ ArrayType::ArraySizeModifier SizeMod,
+ ExprArg SizeExpr,
+ unsigned IndexTypeQuals,
+ SourceRange BracketsRange) {
+ return getDerived().RebuildArrayType(ElementType, SizeMod, 0,
+ SizeExpr.takeAs<Expr>(),
+ IndexTypeQuals, BracketsRange);
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::RebuildVectorType(QualType ElementType,
+ unsigned NumElements) {
+ // FIXME: semantic checking!
+ return SemaRef.Context.getVectorType(ElementType, NumElements);
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::RebuildExtVectorType(QualType ElementType,
+ unsigned NumElements,
+ SourceLocation AttributeLoc) {
+ llvm::APInt numElements(SemaRef.Context.getIntWidth(SemaRef.Context.IntTy),
+ NumElements, true);
+ IntegerLiteral *VectorSize
+ = new (SemaRef.Context) IntegerLiteral(numElements, SemaRef.Context.IntTy,
+ AttributeLoc);
+ return SemaRef.BuildExtVectorType(ElementType, SemaRef.Owned(VectorSize),
+ AttributeLoc);
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::RebuildDependentSizedExtVectorType(QualType ElementType,
+ ExprArg SizeExpr,
+ SourceLocation AttributeLoc) {
+ return SemaRef.BuildExtVectorType(ElementType, move(SizeExpr), AttributeLoc);
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::RebuildFunctionProtoType(QualType T,
+ QualType *ParamTypes,
+ unsigned NumParamTypes,
+ bool Variadic,
+ unsigned Quals) {
+ return SemaRef.BuildFunctionType(T, ParamTypes, NumParamTypes, Variadic,
+ Quals,
+ getDerived().getBaseLocation(),
+ getDerived().getBaseEntity());
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::RebuildTypeOfExprType(ExprArg E) {
+ return SemaRef.BuildTypeofExprType(E.takeAs<Expr>());
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::RebuildTypeOfType(QualType Underlying) {
+ return SemaRef.Context.getTypeOfType(Underlying);
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::RebuildDecltypeType(ExprArg E) {
+ return SemaRef.BuildDecltypeType(E.takeAs<Expr>());
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::RebuildTemplateSpecializationType(
+ TemplateName Template,
+ const TemplateArgument *Args,
+ unsigned NumArgs) {
+ // FIXME: Missing source locations for the template name, <, >.
+ return SemaRef.CheckTemplateIdType(Template, getDerived().getBaseLocation(),
+ SourceLocation(), Args, NumArgs,
+ SourceLocation());
+}
+
+template<typename Derived>
+NestedNameSpecifier *
+TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
+ SourceRange Range,
+ IdentifierInfo &II,
+ QualType ObjectType,
+ NamedDecl *FirstQualifierInScope) {
+ CXXScopeSpec SS;
+ // FIXME: The source location information is all wrong.
+ SS.setRange(Range);
+ SS.setScopeRep(Prefix);
+ return static_cast<NestedNameSpecifier *>(
+ SemaRef.BuildCXXNestedNameSpecifier(0, SS, Range.getEnd(),
+ Range.getEnd(), II,
+ ObjectType,
+ FirstQualifierInScope,
+ false));
+}
+
+template<typename Derived>
+NestedNameSpecifier *
+TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
+ SourceRange Range,
+ NamespaceDecl *NS) {
+ return NestedNameSpecifier::Create(SemaRef.Context, Prefix, NS);
+}
+
+template<typename Derived>
+NestedNameSpecifier *
+TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
+ SourceRange Range,
+ bool TemplateKW,
+ QualType T) {
+ if (T->isDependentType() || T->isRecordType() ||
+ (SemaRef.getLangOptions().CPlusPlus0x && T->isEnumeralType())) {
+ assert(!T.hasQualifiers() && "Can't get cv-qualifiers here");
+ return NestedNameSpecifier::Create(SemaRef.Context, Prefix, TemplateKW,
+ T.getTypePtr());
+ }
+
+ SemaRef.Diag(Range.getBegin(), diag::err_nested_name_spec_non_tag) << T;
+ return 0;
+}
+
+template<typename Derived>
+TemplateName
+TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier,
+ bool TemplateKW,
+ TemplateDecl *Template) {
+ return SemaRef.Context.getQualifiedTemplateName(Qualifier, TemplateKW,
+ Template);
+}
+
+template<typename Derived>
+TemplateName
+TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier,
+ bool TemplateKW,
+ OverloadedFunctionDecl *Ovl) {
+ return SemaRef.Context.getQualifiedTemplateName(Qualifier, TemplateKW, Ovl);
+}
+
+template<typename Derived>
+TemplateName
+TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier,
+ const IdentifierInfo &II,
+ QualType ObjectType) {
+ CXXScopeSpec SS;
+ SS.setRange(SourceRange(getDerived().getBaseLocation()));
+ SS.setScopeRep(Qualifier);
+ return getSema().ActOnDependentTemplateName(
+ /*FIXME:*/getDerived().getBaseLocation(),
+ II,
+ /*FIXME:*/getDerived().getBaseLocation(),
+ SS,
+ ObjectType.getAsOpaquePtr())
+ .template getAsVal<TemplateName>();
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
+ SourceLocation OpLoc,
+ ExprArg Callee,
+ ExprArg First,
+ ExprArg Second) {
+ Expr *FirstExpr = (Expr *)First.get();
+ Expr *SecondExpr = (Expr *)Second.get();
+ bool isPostIncDec = SecondExpr && (Op == OO_PlusPlus || Op == OO_MinusMinus);
+
+ // Determine whether this should be a builtin operation.
+ if (SecondExpr == 0 || isPostIncDec) {
+ if (!FirstExpr->getType()->isOverloadableType()) {
+ // The argument is not of overloadable type, so try to create a
+ // built-in unary operation.
+ UnaryOperator::Opcode Opc
+ = UnaryOperator::getOverloadedOpcode(Op, isPostIncDec);
+
+ return getSema().CreateBuiltinUnaryOp(OpLoc, Opc, move(First));
+ }
+ } else {
+ if (!FirstExpr->getType()->isOverloadableType() &&
+ !SecondExpr->getType()->isOverloadableType()) {
+ // Neither of the arguments is an overloadable type, so try to
+ // create a built-in binary operation.
+ BinaryOperator::Opcode Opc = BinaryOperator::getOverloadedOpcode(Op);
+ OwningExprResult Result
+ = SemaRef.CreateBuiltinBinOp(OpLoc, Opc, FirstExpr, SecondExpr);
+ if (Result.isInvalid())
+ return SemaRef.ExprError();
+
+ First.release();
+ Second.release();
+ return move(Result);
+ }
+ }
+
+ // Compute the transformed set of functions (and function templates) to be
+ // used during overload resolution.
+ Sema::FunctionSet Functions;
+
+ DeclRefExpr *DRE
+ = cast<DeclRefExpr>(((Expr *)Callee.get())->IgnoreParenCasts());
+
+ // FIXME: Do we have to check
+ // IsAcceptableNonMemberOperatorCandidate for each of these?
+ for (OverloadIterator F(DRE->getDecl()), FEnd; F != FEnd; ++F)
+ Functions.insert(*F);
+
+ // Add any functions found via argument-dependent lookup.
+ Expr *Args[2] = { FirstExpr, SecondExpr };
+ unsigned NumArgs = 1 + (SecondExpr != 0);
+ DeclarationName OpName
+ = SemaRef.Context.DeclarationNames.getCXXOperatorName(Op);
+ SemaRef.ArgumentDependentLookup(OpName, Args, NumArgs, Functions);
+
+ // Create the overloaded operator invocation for unary operators.
+ if (NumArgs == 1 || isPostIncDec) {
+ UnaryOperator::Opcode Opc
+ = UnaryOperator::getOverloadedOpcode(Op, isPostIncDec);
+ return SemaRef.CreateOverloadedUnaryOp(OpLoc, Opc, Functions, move(First));
+ }
+
+ // Create the overloaded operator invocation for binary operators.
+ BinaryOperator::Opcode Opc =
+ BinaryOperator::getOverloadedOpcode(Op);
+ OwningExprResult Result
+ = SemaRef.CreateOverloadedBinOp(OpLoc, Opc, Functions, Args[0], Args[1]);
+ if (Result.isInvalid())
+ return SemaRef.ExprError();
+
+ First.release();
+ Second.release();
+ return move(Result);
+}
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_SEMA_TREETRANSFORM_H
diff --git a/test/Analysis/CFDateGC.m b/test/Analysis/CFDateGC.m
index dfc7366..557e7e8 100644
--- a/test/Analysis/CFDateGC.m
+++ b/test/Analysis/CFDateGC.m
@@ -1,6 +1,6 @@
-// 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=basic -verify -fobjc-gc -analyzer-constraints=basic %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -verify -fobjc-gc -analyzer-constraints=range %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -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
@@ -25,7 +25,7 @@ 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) {}
+static __inline__ __attribute__((always_inline)) id NSMakeCollectable(CFTypeRef cf) { return 0; }
@protocol NSObject - (BOOL)isEqual:(id)object;
- (oneway void)release;
- (id)retain;
diff --git a/test/Analysis/CheckNSError.m b/test/Analysis/CheckNSError.m
index 779b865..5f92594 100644
--- a/test/Analysis/CheckNSError.m
+++ b/test/Analysis/CheckNSError.m
@@ -24,7 +24,7 @@ extern NSString * const NSXMLParserErrorDomain ;
@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.}}
+- (void)myMethodWhichMayFail:(NSError **)error { // expected-warning {{Method accepting NSError** should have a non-void return value to indicate whether or not an error occurred}}
*error = [NSError errorWithDomain:@"domain" code:1 userInfo:0]; // expected-warning {{Potential null dereference.}}
}
@@ -37,7 +37,7 @@ extern NSString * const NSXMLParserErrorDomain ;
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.}}
+void foo(CFErrorRef* error) { // expected-warning {{Function accepting CFErrorRef* should have a non-void return value to indicate whether or not an error occurred}}
*error = 0; // expected-warning {{Potential null dereference.}}
}
diff --git a/test/Analysis/NSPanel.m b/test/Analysis/NSPanel.m
index c4d4c22..801620a 100644
--- a/test/Analysis/NSPanel.m
+++ b/test/Analysis/NSPanel.m
@@ -28,7 +28,7 @@ typedef struct _NSZone NSZone;
@end
typedef float CGFloat;
typedef struct _NSPoint {} NSRect;
-static __inline__ __attribute__((always_inline)) NSRect NSMakeRect(CGFloat x, CGFloat y, CGFloat w, CGFloat h) {}
+static __inline__ __attribute__((always_inline)) NSRect NSMakeRect(CGFloat x, CGFloat y, CGFloat w, CGFloat h) { NSRect r; return r; }
typedef struct {} NSFastEnumerationState;
@protocol NSFastEnumeration
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len;
diff --git a/test/Analysis/NSString.m b/test/Analysis/NSString.m
index b707071..0ba3cda 100644
--- a/test/Analysis/NSString.m
+++ b/test/Analysis/NSString.m
@@ -1,9 +1,7 @@
// 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
+// RUN: clang-cc -triple i386-pc-linux-gnu -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s &&
+// RUN: clang-cc -triple i386-pc-linux-gnu -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s &&
+// RUN: 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
@@ -157,6 +155,7 @@ NSString* f11(CFDictionaryRef dict, const char* key) {
if (s) {
[s release];
}
+ return 0;
}
// Test case for passing a tracked object by-reference to a function we
@@ -285,6 +284,12 @@ void testOSCompareAndSwap32Barrier() {
[old release];
}
+int testOSCompareAndSwap32Barrier_id(Class myclass, id xclass) {
+ if (OSAtomicCompareAndSwap32Barrier(0, (int32_t) myclass, (int32_t*) &xclass))
+ return 1;
+ return 0;
+}
+
void test_objc_atomicCompareAndSwap() {
NSString *old = 0;
NSString *s = [[NSString alloc] init]; // no-warning
diff --git a/test/Analysis/PR2978.m b/test/Analysis/PR2978.m
index 7bc90b8..0cb3dea 100644
--- a/test/Analysis/PR2978.m
+++ b/test/Analysis/PR2978.m
@@ -55,6 +55,7 @@
[self setW:@"newW"]; // This will release '_W', but retain the new value
self.O = 0; // no-warning
[super dealloc];
+ return 0;
}
@end
diff --git a/test/Analysis/PR3991.m b/test/Analysis/PR3991.m
index 20d4b5b..bbc1377 100644
--- a/test/Analysis/PR3991.m
+++ b/test/Analysis/PR3991.m
@@ -43,6 +43,7 @@ typedef struct _NSZone NSZone;
- (void)setCurrentPathComponentIndex:(unsigned int)aCurrentPathComponentIndex;
- (NSURL *)folderFeedURL;
@end @implementation IHGoogleDocsAdapter - (id)initWithUsername:(NSString *)inUsername password:(NSString *)inPassword owner:(NSObject <IHGoogleDocsAdapterDelegate> *)owner {
+ return 0;
}
//===----------------------------------------------------------------------===//
diff --git a/test/Analysis/array-struct.c b/test/Analysis/array-struct.c
index da7df4b..d6b6076 100644
--- a/test/Analysis/array-struct.c
+++ b/test/Analysis/array-struct.c
@@ -1,7 +1,5 @@
// 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.
+// 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
@@ -145,7 +143,7 @@ void f15() {
int a[10];
bar(a);
if (a[1]) // no-warning
- 1;
+ (void)1;
}
struct s3 p[1];
diff --git a/test/Analysis/casts.c b/test/Analysis/casts.c
index 5e4222b..ae51ffb 100644
--- a/test/Analysis/casts.c
+++ b/test/Analysis/casts.c
@@ -1,9 +1,16 @@
-// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region --verify %s
+// RUN: clang-cc -triple x86_64-apple-darwin9 -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>
+typedef unsigned char __uint8_t;
+typedef unsigned int __uint32_t;
+typedef __uint32_t __darwin_socklen_t;
+typedef __uint8_t sa_family_t;
+typedef __darwin_socklen_t socklen_t;
+struct sockaddr { sa_family_t sa_family; };
+struct sockaddr_storage {};
+
void f(int sock) {
struct sockaddr_storage storage;
struct sockaddr* sockaddr = (struct sockaddr*)&storage;
@@ -19,14 +26,14 @@ struct s {
struct s *value;
};
-int f1(struct s **pval) {
+void f1(struct s **pval) {
int *tbool = ((void*)0);
struct s *t = *pval;
pval = &(t->value);
- tbool = (int *)pval; // Should record the cast-to type here.
+ tbool = (int *)pval; // use the cast-to type 'int *' to create element region.
char c = (unsigned char) *tbool; // Should use cast-to type to create symbol.
- if (*tbool == -1)
- 3;
+ if (*tbool == -1) // here load the element region with the correct type 'int'
+ (void)3;
}
void f2(const char *str) {
diff --git a/test/Analysis/cfref_rdar6080742.c b/test/Analysis/cfref_rdar6080742.c
index 5d95761..9bbaf9b 100644
--- a/test/Analysis/cfref_rdar6080742.c
+++ b/test/Analysis/cfref_rdar6080742.c
@@ -44,15 +44,15 @@ Boolean DebugDisplayOSStatusMsg(OSStatus status, const char *statusStr,
#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. */
+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;
+ 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
index cef6245..3633b21 100644
--- a/test/Analysis/complex.c
+++ b/test/Analysis/complex.c
@@ -5,7 +5,7 @@
#include <stdint.h>
-int f1(int * p) {
+void f1(int * p) {
// This branch should be infeasible
// because __imag__ p is 0.
diff --git a/test/Analysis/dead-stores.c b/test/Analysis/dead-stores.c
index 6d3b7e6..c4ff7fa 100644
--- a/test/Analysis/dead-stores.c
+++ b/test/Analysis/dead-stores.c
@@ -57,7 +57,7 @@ int f7(int *p) {
int f8(int *p) {
extern int *baz();
- if (p = baz()) // expected-warning{{Although the value}}
+ if ((p = baz())) // expected-warning{{Although the value}}
return 1;
return 0;
}
@@ -129,14 +129,15 @@ int f16(int x) {
}
// Self-assignments should not be flagged as dead stores.
-int f17() {
+void 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...".
+// 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)
@@ -171,3 +172,167 @@ void f20(void) {
#pragma unused(x)
}
+void halt() __attribute__((noreturn));
+int f21() {
+ int x = 4;
+
+ ++x; // expected-warning{{never read}}
+ if (1) {
+ halt();
+ (void)x;
+ }
+ return 1;
+}
+
+int j;
+void f22() {
+ int x = 4;
+ int y1 = 4;
+ int y2 = 4;
+ int y3 = 4;
+ int y4 = 4;
+ int y5 = 4;
+ int y6 = 4;
+ int y7 = 4;
+ int y8 = 4;
+ int y9 = 4;
+ int y10 = 4;
+ int y11 = 4;
+ int y12 = 4;
+ int y13 = 4;
+ int y14 = 4;
+ int y15 = 4;
+ int y16 = 4;
+ int y17 = 4;
+ int y18 = 4;
+ int y19 = 4;
+ int y20 = 4;
+
+ ++x; // expected-warning{{never read}}
+ ++y1;
+ ++y2;
+ ++y3;
+ ++y4;
+ ++y5;
+ ++y6;
+ ++y7;
+ ++y8;
+ ++y9;
+ ++y10;
+ ++y11;
+ ++y12;
+ ++y13;
+ ++y14;
+ ++y15;
+ ++y16;
+ ++y17;
+ ++y18;
+ ++y19;
+ ++y20;
+
+ switch (j) {
+ case 1:
+ if (0)
+ (void)x;
+ if (1) {
+ (void)y1;
+ return;
+ }
+ (void)x;
+ break;
+ case 2:
+ if (0)
+ (void)x;
+ else {
+ (void)y2;
+ return;
+ }
+ (void)x;
+ break;
+ case 3:
+ if (1) {
+ (void)y3;
+ return;
+ } else
+ (void)x;
+ (void)x;
+ break;
+ case 4:
+ 0 ? : ((void)y4, ({ return; }));
+ (void)x;
+ break;
+ case 5:
+ 1 ? : (void)x;
+ 0 ? (void)x : ((void)y5, ({ return; }));
+ (void)x;
+ break;
+ case 6:
+ 1 ? ((void)y6, ({ return; })) : (void)x;
+ (void)x;
+ break;
+ case 7:
+ (void)(0 && x);
+ (void)y7;
+ (void)(0 || (y8, ({ return; }), 1));
+ (void)x;
+ break;
+ case 8:
+ (void)(1 && (y9, ({ return; }), 1));
+ (void)x;
+ break;
+ case 9:
+ (void)(1 || x);
+ (void)y10;
+ break;
+ case 10:
+ while (0) {
+ (void)x;
+ }
+ (void)y11;
+ break;
+ case 11:
+ while (1) {
+ (void)y12;
+ }
+ (void)x;
+ break;
+ case 12:
+ do {
+ (void)y13;
+ } while (0);
+ (void)y14;
+ break;
+ case 13:
+ do {
+ (void)y15;
+ } while (1);
+ (void)x;
+ break;
+ case 14:
+ for (;;) {
+ (void)y16;
+ }
+ (void)x;
+ break;
+ case 15:
+ for (;1;) {
+ (void)y17;
+ }
+ (void)x;
+ break;
+ case 16:
+ for (;0;) {
+ (void)x;
+ }
+ (void)y18;
+ break;
+ case 17:
+ __builtin_choose_expr(0, (void)x, ((void)y19, ({ return; })));
+ (void)x;
+ break;
+ case 19:
+ __builtin_choose_expr(1, ((void)y20, ({ return; })), (void)x);
+ (void)x;
+ break;
+ }
+}
diff --git a/test/Analysis/dead-stores.cpp b/test/Analysis/dead-stores.cpp
new file mode 100644
index 0000000..9ddb797
--- /dev/null
+++ b/test/Analysis/dead-stores.cpp
@@ -0,0 +1,19 @@
+// RUN: clang-cc -analyze -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
+
+int j;
+void f1() {
+ int x = 4;
+
+ ++x; // expected-warning{{never read}}
+
+ switch (j) {
+ case 1:
+ throw 1;
+ (void)x;
+ break;
+ }
+}
diff --git a/test/Analysis/exercise-ps.c b/test/Analysis/exercise-ps.c
index c309349..1e31b18 100644
--- a/test/Analysis/exercise-ps.c
+++ b/test/Analysis/exercise-ps.c
@@ -5,7 +5,7 @@
// (i.e., no assertions or crashes).
-static const char * f1(const char *x, char *y) {
+static void f1(const char *x, char *y) {
while (*x != 0) {
*y++ = *x++;
}
diff --git a/test/Analysis/misc-ps-basic-store.m b/test/Analysis/misc-ps-basic-store.m
index 1207f86..c6ae20c 100644
--- a/test/Analysis/misc-ps-basic-store.m
+++ b/test/Analysis/misc-ps-basic-store.m
@@ -19,3 +19,17 @@ void checkaccess_union() {
).__i))) & 0xff00) >> 8) == 1)
ret = 1;
}
+
+// BasicStore handles this case incorrectly because it doesn't reason about
+// the value pointed to by 'x' and thus creates different symbolic values
+// at the declarations of 'a' and 'b' respectively. See the companion test
+// in 'misc-ps-region-store.m'.
+void test_trivial_symbolic_comparison_pointer_parameter(int *x) {
+ int a = *x;
+ int b = *x;
+ if (a != b) {
+ int *p = 0;
+ *p = 0xDEADBEEF; // expected-warning{{null}}
+ }
+}
+
diff --git a/test/Analysis/misc-ps-region-store-i386.m b/test/Analysis/misc-ps-region-store-i386.m
new file mode 100644
index 0000000..c2c4d5b
--- /dev/null
+++ b/test/Analysis/misc-ps-region-store-i386.m
@@ -0,0 +1,14 @@
+// RUN: clang-cc -triple i386-apple-darwin9 -analyze -checker-cfref --analyzer-store=region --verify -fblocks %s
+
+// Here is a case where a pointer is treated as integer, invalidated as an
+// integer, and then used again as a pointer. This test just makes sure
+// we don't crash.
+typedef unsigned uintptr_t;
+void test_pointer_invalidated_as_int_aux(uintptr_t* ptr);
+void test_pointer_invalidated_as_int() {
+ void *x;
+ test_pointer_invalidated_as_int_aux((uintptr_t*) &x);
+ // Here we have a pointer to integer cast.
+ uintptr_t y = (uintptr_t) x;
+}
+
diff --git a/test/Analysis/misc-ps-region-store-x86_64.m b/test/Analysis/misc-ps-region-store-x86_64.m
new file mode 100644
index 0000000..154ffaf
--- /dev/null
+++ b/test/Analysis/misc-ps-region-store-x86_64.m
@@ -0,0 +1,14 @@
+// RUN: clang-cc -triple x86_64-apple-darwin9 -analyze -checker-cfref --analyzer-store=region --verify -fblocks %s
+
+// Here is a case where a pointer is treated as integer, invalidated as an
+// integer, and then used again as a pointer. This test just makes sure
+// we don't crash.
+typedef unsigned long uintptr_t;
+void test_pointer_invalidated_as_int_aux(uintptr_t* ptr);
+void test_pointer_invalidated_as_int() {
+ void *x;
+ test_pointer_invalidated_as_int_aux((uintptr_t*) &x);
+ // Here we have a pointer to integer cast.
+ uintptr_t y = (uintptr_t) x;
+}
+
diff --git a/test/Analysis/misc-ps-region-store.m b/test/Analysis/misc-ps-region-store.m
index 8c8815e..e849042 100644
--- a/test/Analysis/misc-ps-region-store.m
+++ b/test/Analysis/misc-ps-region-store.m
@@ -1,4 +1,5 @@
-// RUN: clang-cc -analyze -checker-cfref --analyzer-store=region --verify -fblocks %s
+// RUN: clang-cc -triple i386-apple-darwin9 -analyze -checker-cfref --analyzer-store=region --verify -fblocks %s &&
+// RUN: clang-cc -triple x86_64-apple-darwin9 -analyze -checker-cfref --analyzer-store=region --verify -fblocks %s
typedef struct objc_selector *SEL;
typedef signed char BOOL;
@@ -31,10 +32,12 @@ extern NSString * const NSConnectionReplyMode;
// 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.}}
+ // Since RegionStore doesn't handle unions yet,
+ // this branch condition won't be triggered
+ // as involving an uninitialized value.
+ if (((((__extension__ (((union { // no-warning
__typeof (status) __in; int __i;}
)
{
@@ -43,7 +46,6 @@ void checkaccess_union() {
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);
@@ -68,3 +70,236 @@ char test2() {
return 'a';
}
+// BasicStore handles this case incorrectly because it doesn't reason about
+// the value pointed to by 'x' and thus creates different symbolic values
+// at the declarations of 'a' and 'b' respectively. RegionStore handles
+// it correctly. See the companion test in 'misc-ps-basic-store.m'.
+void test_trivial_symbolic_comparison_pointer_parameter(int *x) {
+ int a = *x;
+ int b = *x;
+ if (a != b) {
+ int *p = 0;
+ *p = 0xDEADBEEF; // no-warning
+ }
+}
+
+// This is a modified test from 'misc-ps.m'. Here we have the extra
+// NULL dereferences which are pruned out by RegionStore's symbolic reasoning
+// of fields.
+typedef struct _BStruct { void *grue; } BStruct;
+void testB_aux(void *ptr);
+
+void testB(BStruct *b) {
+ {
+ int *__gruep__ = ((int *)&((b)->grue));
+ int __gruev__ = *__gruep__;
+ int __gruev2__ = *__gruep__;
+ if (__gruev__ != __gruev2__) {
+ int *p = 0;
+ *p = 0xDEADBEEF; // no-warning
+ }
+
+ testB_aux(__gruep__);
+ }
+ {
+ int *__gruep__ = ((int *)&((b)->grue));
+ int __gruev__ = *__gruep__;
+ int __gruev2__ = *__gruep__;
+ if (__gruev__ != __gruev2__) {
+ int *p = 0;
+ *p = 0xDEADBEEF; // no-warning
+ }
+
+ if (~0 != __gruev__) {}
+ }
+}
+
+void testB_2(BStruct *b) {
+ {
+ int **__gruep__ = ((int **)&((b)->grue));
+ int *__gruev__ = *__gruep__;
+ testB_aux(__gruep__);
+ }
+ {
+ int **__gruep__ = ((int **)&((b)->grue));
+ int *__gruev__ = *__gruep__;
+ if ((int*)~0 != __gruev__) {}
+ }
+}
+
+// This test case is a reduced case of a caching bug discovered by an
+// assertion failure in RegionStoreManager::BindArray. Essentially the
+// DeclStmt is evaluated twice, but on the second loop iteration the
+// engine caches out. Previously a false transition would cause UnknownVal
+// to bind to the variable, firing an assertion failure. This bug was fixed
+// in r76262.
+void test_declstmt_caching() {
+again:
+ {
+ const char a[] = "I like to crash";
+ goto again;
+ }
+}
+
+// Reduced test case from <rdar://problem/7114618>.
+// Basically a null check is performed on the field value, which is then
+// assigned to a variable and then checked again.
+struct s_7114618 { int *p; };
+void test_rdar_7114618(struct s_7114618 *s) {
+ if (s->p) {
+ int *p = s->p;
+ if (!p) {
+ // Infeasible
+ int *dead = 0;
+ *dead = 0xDEADBEEF; // no-warning
+ }
+ }
+}
+
+// Test pointers increment correctly.
+void f() {
+ int a[2];
+ a[1] = 3;
+ int *p = a;
+ p++;
+ if (*p != 3) {
+ int *q = 0;
+ *q = 3; // no-warning
+ }
+}
+
+// <rdar://problem/7185607>
+// Bit-fields of a struct should be invalidated when blasting the entire
+// struct with an integer constant.
+struct test_7185607 {
+ int x : 10;
+ int y : 22;
+};
+int rdar_test_7185607() {
+ struct test_7185607 s; // Uninitialized.
+ *((unsigned *) &s) = 0U;
+ return s.x; // no-warning
+}
+
+// <rdar://problem/7242006> [RegionStore] compound literal assignment with
+// floats not honored
+// This test case is mirrored in misc-ps.m, but this case is a negative.
+typedef float CGFloat;
+typedef struct _NSSize {
+ CGFloat width;
+ CGFloat height;
+} NSSize;
+
+CGFloat rdar7242006_negative(CGFloat x) {
+ NSSize y;
+ return y.width; // expected-warning{{garbage}}
+}
+
+// <rdar://problem/7249340> - Allow binding of values to symbolic regions.
+// This test case shows how RegionStore tracks the value bound to 'x'
+// after the assignment.
+typedef int* ptr_rdar_7249340;
+void rdar_7249340(ptr_rdar_7249340 x) {
+ *x = 1;
+ if (*x)
+ return;
+ int *p = 0; // This is unreachable.
+ *p = 0xDEADBEEF; // no-warning
+}
+
+// <rdar://problem/7249327> - This test case tests both value tracking of
+// array values and that we handle symbolic values that are casted
+// between different integer types. Note the assignment 'n = *a++'; here
+// 'n' is and 'int' and '*a' is 'unsigned'. Previously we got a false positive
+// at 'x += *b++' (undefined value) because we got a false path.
+int rdar_7249327_aux(void);
+
+void rdar_7249327(unsigned int A[2*32]) {
+ int B[2*32];
+ int *b;
+ unsigned int *a;
+ int x = 0;
+
+ int n;
+
+ a = A;
+ b = B;
+
+ n = *a++;
+ if (n)
+ *b++ = rdar_7249327_aux();
+
+ a = A;
+ b = B;
+
+ n = *a++;
+ if (n)
+ x += *b++; // no-warning
+}
+
+// <rdar://problem/6914474> - Check that 'x' is invalidated because its
+// address is passed in as a value to a struct.
+struct doodad_6914474 { int *v; };
+extern void prod_6914474(struct doodad_6914474 *d);
+int rdar_6914474(void) {
+ int x;
+ struct doodad_6914474 d;
+ d.v = &x;
+ prod_6914474(&d);
+ return x; // no-warning
+}
+
+// Test invalidation of a single field.
+struct s_test_field_invalidate {
+ int x;
+};
+extern void test_invalidate_field(int *x);
+int test_invalidate_field_test() {
+ struct s_test_field_invalidate y;
+ test_invalidate_field(&y.x);
+ return y.x; // no-warning
+}
+int test_invalidate_field_test_positive() {
+ struct s_test_field_invalidate y;
+ return y.x; // expected-warning{{garbage}}
+}
+
+// This test case illustrates how a typeless array of bytes casted to a
+// struct should be treated as initialized. RemoveDeadBindings previously
+// had a bug that caused 'x' to lose its default symbolic value after the
+// assignment to 'p', thus causing 'p->z' to evaluate to "undefined".
+struct ArrayWrapper { unsigned char y[16]; };
+struct WrappedStruct { unsigned z; };
+
+int test_handle_array_wrapper() {
+ struct ArrayWrapper x;
+ test_handle_array_wrapper(&x);
+ struct WrappedStruct *p = (struct WrappedStruct*) x.y;
+ return p->z; // no-warning
+}
+
+// <rdar://problem/7261075> [RegionStore] crash when
+// handling load: '*((unsigned int *)"????")'
+int rdar_7261075(void) {
+ unsigned int var = 0;
+ if (var == *((unsigned int *)"????"))
+ return 1;
+ return 0;
+}
+
+// <rdar://problem/7275774> false path due to limited pointer
+// arithmetic constraints
+void rdar_7275774(void *data, unsigned n) {
+ if (!(data || n == 0))
+ return;
+
+ unsigned short *p = (unsigned short*) data;
+ unsigned short *q = p + (n / 2);
+
+ if (p < q) {
+ // If we reach here, 'p' cannot be null. If 'p' is null, then 'n' must
+ // be '0', meaning that this branch is not feasible.
+ *p = *q; // no-warning
+ }
+}
+
diff --git a/test/Analysis/misc-ps.m b/test/Analysis/misc-ps.m
index ea41b5b..10e5823 100644
--- a/test/Analysis/misc-ps.m
+++ b/test/Analysis/misc-ps.m
@@ -1,24 +1,43 @@
-// RUN: clang-cc -analyze -checker-cfref --analyzer-store=basic -analyzer-constraints=basic --verify -fblocks %s &&
+// NOTE: Use '-fobjc-gc' to test the analysis being run twice, and multiple reports are not issued.
+// RUN: clang-cc -analyze -checker-cfref --analyzer-store=basic -fobjc-gc -analyzer-constraints=basic --verify -fblocks %s &&
// 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=basic --verify -fblocks %s &&
// RUN: clang-cc -analyze -checker-cfref --analyzer-store=region -analyzer-constraints=range --verify -fblocks %s
+typedef struct objc_ivar *Ivar;
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
+@class NSInvocation, NSArray, 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; @end
+@protocol NSCoding
+- (void)encodeWithCoder:(NSCoder *)aCoder;
+@end
+@interface NSObject <NSObject> {}
+- (id)init;
++ (id)allocWithZone:(NSZone *)zone;
+@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 NSValue : NSObject <NSCopying, NSCoding>
+- (void)getValue:(void *)value;
+@end
+@interface NSNumber : NSValue
+- (char)charValue;
+- (id)initWithBool:(BOOL)value;
+@end
@interface NSAssertionHandler : NSObject {}
+ (NSAssertionHandler *)currentHandler;
- (void)handleFailureInMethod:(SEL)selector object:(id)object file:(NSString *)fileName lineNumber:(NSInteger)line description:(NSString *)format,...;
@@ -144,7 +163,7 @@ void pr3422() {
}
// PR 3543 (handle empty statement expressions)
-int pr_3543(void) {
+void pr_3543(void) {
({});
}
@@ -295,4 +314,381 @@ void rdar_7027684(int x, int y) {
(rdar_7027684_aux() ? rdar_7027684_aux_2() : (void) 0);
}
+// Test that we handle casts of string literals to arbitrary types.
+unsigned const char *string_literal_test1() {
+ return (const unsigned char*) "hello";
+}
+
+const float *string_literal_test2() {
+ return (const float*) "hello";
+}
+
+// Test that we handle casts *from* incomplete struct types.
+extern const struct _FooAssertStruct _cmd;
+void test_cast_from_incomplete_struct_aux(volatile const void *x);
+void test_cast_from_incomplete_struct() {
+ test_cast_from_incomplete_struct_aux(&_cmd);
+}
+
+// Test for <rdar://problem/7034511>
+// "ValueManager::makeIntVal(uint64_t X, QualType T) should return a 'Loc'
+// when 'T' is a pointer"
+//
+// Previously this case would crash.
+void test_rdar_7034511(NSArray *y) {
+ NSObject *x;
+ for (x in y) {}
+ if (x == ((void*) 0)) {}
+}
+
+// Handle casts of function pointers (CodeTextRegions) to arbitrary pointer
+// types. This was previously causing a crash in CastRegion.
+void handle_funcptr_voidptr_casts() {
+ void **ptr;
+ typedef void *PVOID;
+ typedef void *PCHAR;
+ typedef long INT_PTR, *PINT_PTR;
+ typedef INT_PTR (*FARPROC)();
+ FARPROC handle_funcptr_voidptr_casts_aux();
+ PVOID handle_funcptr_voidptr_casts_aux_2(PVOID volatile *x);
+ PVOID handle_funcptr_voidptr_casts_aux_3(PCHAR volatile *x);
+
+ ptr = (void**) handle_funcptr_voidptr_casts_aux();
+ handle_funcptr_voidptr_casts_aux_2(ptr);
+ handle_funcptr_voidptr_casts_aux_3(ptr);
+}
+
+// RegionStore::Retrieve previously crashed on this example. This example
+// was previously in the test file 'xfail_regionstore_wine_crash.c'.
+void testA() {
+ long x = 0;
+ char *y = (char *) &x;
+ if (!*y)
+ return;
+}
+
+// RegionStoreManager previously crashed on this example. The problem is that
+// the value bound to the field of b->grue after the call to testB_aux is
+// a symbolic region. The second '*__gruep__' involves performing a load
+// from a 'int*' that really is a 'void**'. The loaded location must be
+// implicitly converted to an integer that wraps a location. Previosly we would
+// get a crash here due to an assertion failure.
+typedef struct _BStruct { void *grue; } BStruct;
+void testB_aux(void *ptr);
+void testB(BStruct *b) {
+ {
+ int *__gruep__ = ((int *)&((b)->grue));
+ int __gruev__ = *__gruep__;
+ testB_aux(__gruep__);
+ }
+ {
+ int *__gruep__ = ((int *)&((b)->grue));
+ int __gruev__ = *__gruep__;
+ if (~0 != __gruev__) {}
+ }
+}
+
+void test_trivial_symbolic_comparison(int *x) {
+ int test_trivial_symbolic_comparison_aux();
+ int a = test_trivial_symbolic_comparison_aux();
+ int b = a;
+ if (a != b) {
+ int *p = 0;
+ *p = 0xDEADBEEF; // no-warning
+ }
+
+ a = a == 1;
+ b = b == 1;
+ if (a != b) {
+ int *p = 0;
+ *p = 0xDEADBEEF; // no-warning
+ }
+}
+
+// Test for:
+// <rdar://problem/7062158> false positive null dereference due to
+// BasicStoreManager not tracking *static* globals
+//
+// This just tests the proper tracking of symbolic values for globals (both
+// static and non-static).
+//
+static int* x_rdar_7062158;
+void rdar_7062158() {
+ int *current = x_rdar_7062158;
+ if (current == x_rdar_7062158)
+ return;
+
+ int *p = 0;
+ *p = 0xDEADBEEF; // no-warning
+}
+
+int* x_rdar_7062158_2;
+void rdar_7062158_2() {
+ int *current = x_rdar_7062158_2;
+ if (current == x_rdar_7062158_2)
+ return;
+
+ int *p = 0;
+ *p = 0xDEADBEEF; // no-warning
+}
+
+// This test reproduces a case for a crash when analyzing ClamAV using
+// RegionStoreManager (the crash doesn't exhibit in BasicStoreManager because
+// it isn't doing anything smart about arrays). The problem is that on the
+// second line, 'p = &p[i]', p is assigned an ElementRegion whose index
+// is a 16-bit integer. On the third line, a new ElementRegion is created
+// based on the previous region, but there the region uses a 32-bit integer,
+// resulting in a clash of values (an assertion failure at best). We resolve
+// this problem by implicitly converting index values to 'int' when the
+// ElementRegion is created.
+unsigned char test_array_index_bitwidth(const unsigned char *p) {
+ unsigned short i = 0;
+ for (i = 0; i < 2; i++) p = &p[i];
+ return p[i+1];
+}
+
+// This case tests that CastRegion handles casts involving BlockPointerTypes.
+// It should not crash.
+void test_block_cast() {
+ id test_block_cast_aux();
+ (void (^)(void *))test_block_cast_aux(); // expected-warning{{expression result unused}}
+}
+
+// Test comparison of 'id' instance variable to a null void* constant after
+// performing an OSAtomicCompareAndSwap32Barrier.
+// This previously was a crash in RegionStoreManager.
+@interface TestIdNull {
+ id x;
+}
+-(int)foo;
+@end
+@implementation TestIdNull
+-(int)foo {
+ OSAtomicCompareAndSwap32Barrier(0, (signed)2, (signed*)&x);
+ if (x == (void*) 0) { return 0; }
+ return 1;
+}
+@end
+
+// PR 4594 - This was a crash when handling casts in SimpleSValuator.
+void PR4594() {
+ char *buf[1];
+ char **foo = buf;
+ *foo = "test";
+}
+
+// Test invalidation logic where an integer is casted to an array with a
+// different sign and then invalidated.
+void test_invalidate_cast_int() {
+ void test_invalidate_cast_int_aux(unsigned *i);
+ signed i;
+ test_invalidate_cast_int_aux((unsigned*) &i);
+ if (i < 0)
+ return;
+}
+
+// Reduced from a crash involving the cast of an Objective-C symbolic region to
+// 'char *'
+static NSNumber *test_ivar_offset(id self, SEL _cmd, Ivar inIvar) {
+ return [[[NSNumber allocWithZone:((void*)0)] initWithBool:*(_Bool *)((char *)self + ivar_getOffset(inIvar))] autorelease];
+}
+
+// Reduced from a crash in StoreManager::CastRegion involving a divide-by-zero.
+// This resulted from not properly handling region casts to 'const void*'.
+void test_cast_const_voidptr() {
+ char x[10];
+ char *p = &x[1];
+ const void* q = p;
+}
+
+// Reduced from a crash when analyzing Wine. This test handles loads from
+// function addresses.
+typedef long (*FARPROC)();
+FARPROC test_load_func(FARPROC origfun) {
+ if (!*(unsigned char*) origfun)
+ return origfun;
+ return 0;
+}
+
+// Test passing-by-value an initialized struct variable.
+struct test_pass_val {
+ int x;
+ int y;
+};
+void test_pass_val_aux(struct test_pass_val s);
+void test_pass_val() {
+ struct test_pass_val s;
+ s.x = 1;
+ s.y = 2;
+ test_pass_val_aux(s);
+}
+
+// This is a reduced test case of a false positive that previously appeared
+// in RegionStoreManager. Previously the array access resulted in dereferencing
+// an undefined value.
+int test_array_compound(int *q, int *r, int *z) {
+ int *array[] = { q, r, z };
+ int j = 0;
+ for (unsigned i = 0; i < 3 ; ++i)
+ if (*array[i]) ++j; // no-warning
+ return j;
+}
+
+// This test case previously crashed with -analyzer-store=basic because the
+// symbolic value stored in 'x' wouldn't be implicitly casted to a signed value
+// during the comparison.
+int rdar_7124210(unsigned int x) {
+ enum { SOME_CONSTANT = 123 };
+ int compare = ((signed) SOME_CONSTANT) == *((signed *) &x);
+ return compare ? 0 : 1; // Forces the evaluation of the symbolic constraint.
+}
+
+void pr4781(unsigned long *raw1) {
+ unsigned long *cook, *raw0;
+ unsigned long dough[32];
+ int i;
+ cook = dough;
+ for( i = 0; i < 16; i++, raw1++ ) {
+ raw0 = raw1++;
+ *cook = (*raw0 & 0x00fc0000L) << 6;
+ *cook |= (*raw0 & 0x00000fc0L) << 10;
+ }
+}
+
+// <rdar://problem/7185647> - 'self' should be treated as being non-null
+// upon entry to an objective-c method.
+@interface RDar7185647
+- (id)foo;
+@end
+@implementation RDar7185647
+- (id) foo {
+ if (self)
+ return self;
+ *((int *) 0x0) = 0xDEADBEEF; // no-warning
+ return self;
+}
+@end
+
+// Test reasoning of __builtin_offsetof;
+struct test_offsetof_A {
+ int x;
+ int y;
+};
+struct test_offsetof_B {
+ int w;
+ int z;
+};
+void test_offsetof_1() {
+ if (__builtin_offsetof(struct test_offsetof_A, x) ==
+ __builtin_offsetof(struct test_offsetof_B, w))
+ return;
+ int *p = 0;
+ *p = 0xDEADBEEF; // no-warning
+}
+void test_offsetof_2() {
+ if (__builtin_offsetof(struct test_offsetof_A, y) ==
+ __builtin_offsetof(struct test_offsetof_B, z))
+ return;
+ int *p = 0;
+ *p = 0xDEADBEEF; // no-warning
+}
+void test_offsetof_3() {
+ if (__builtin_offsetof(struct test_offsetof_A, y) -
+ __builtin_offsetof(struct test_offsetof_A, x)
+ ==
+ __builtin_offsetof(struct test_offsetof_B, z) -
+ __builtin_offsetof(struct test_offsetof_B, w))
+ return;
+ int *p = 0;
+ *p = 0xDEADBEEF; // no-warning
+}
+void test_offsetof_4() {
+ if (__builtin_offsetof(struct test_offsetof_A, y) ==
+ __builtin_offsetof(struct test_offsetof_B, w))
+ return;
+ int *p = 0;
+ *p = 0xDEADBEEF; // expected-warning{{Dereference of null pointer}}
+}
+
+// <rdar://problem/6829164> "nil receiver" false positive: make tracking
+// of the MemRegion for 'self' path-sensitive
+@interface RDar6829164 : NSObject {
+ double x; int y;
+}
+- (id) init;
+@end
+
+id rdar_6829164_1();
+double rdar_6829164_2();
+
+@implementation RDar6829164
+- (id) init {
+ if((self = [super init]) != 0) {
+ id z = rdar_6829164_1();
+ y = (z != 0);
+ if (y)
+ x = rdar_6829164_2();
+ }
+ return self;
+}
+@end
+
+// <rdar://problem/7242015> - Invalidate values passed-by-reference
+// to functions when the pointer to the value is passed as an integer.
+void test_7242015_aux(unsigned long);
+int rdar_7242015() {
+ int x;
+ test_7242015_aux((unsigned long) &x); // no-warning
+ return x; // Previously we return and uninitialized value when
+ // using RegionStore.
+}
+
+// <rdar://problem/7242006> [RegionStore] compound literal assignment with
+// floats not honored
+CGFloat rdar7242006(CGFloat x) {
+ NSSize y = (NSSize){x, 10};
+ return y.width; // no-warning
+}
+
+// PR 4988 - This test exhibits a case where a function can be referenced
+// when not explicitly used in an "lvalue" context (as far as the analyzer is
+// concerned). This previously triggered a crash due to an invalid assertion.
+void pr_4988(void) {
+ pr_4988; // expected-warning{{expression result unused}}
+}
+
+// <rdar://problem/7152418> - A 'signed char' is used as a flag, which is
+// implicitly converted to an int.
+void *rdar7152418_bar();
+@interface RDar7152418 {
+ signed char x;
+}
+-(char)foo;
+@end;
+@implementation RDar7152418
+-(char)foo {
+ char *p = 0;
+ void *result = 0;
+ if (x) {
+ result = rdar7152418_bar();
+ p = "hello";
+ }
+ if (!result) {
+ result = rdar7152418_bar();
+ if (result && x)
+ return *p; // no-warning
+ }
+ return 1;
+}
+
+// Test constant-folding of symbolic values, automatically handling type
+// conversions of the symbol as necessary. Previously this would crash
+// once we started eagerly evaluating symbols whose values were constrained
+// to a single value.
+void test_constant_symbol(signed char x) {
+ while (1) {
+ if (x == ((signed char) 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
index 9a64b30..87faab6 100644
--- a/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m
+++ b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m
@@ -1,4 +1,5 @@
-// RUN: clang-cc -triple i386-apple-darwin9 -analyze -checker-cfref -analyzer-constraints=basic -analyzer-store=basic %s -verify
+// RUN: clang-cc -triple i386-apple-darwin9 -analyze -checker-cfref -analyzer-constraints=basic -analyzer-store=basic %s -verify &&
+// RUN: clang-cc -triple i386-apple-darwin9 -analyze -checker-cfref -analyzer-constraints=basic -analyzer-store=region %s -verify
@interface MyClass {}
- (void *)voidPtrM;
diff --git a/test/Analysis/no-outofbounds.c b/test/Analysis/no-outofbounds.c
new file mode 100644
index 0000000..9405280
--- /dev/null
+++ b/test/Analysis/no-outofbounds.c
@@ -0,0 +1,12 @@
+// RUN: clang-cc -checker-cfref -analyze -analyzer-store=basic -verify %s &&
+// RUN: clang-cc -checker-cfref -analyze -analyzer-store=region -verify %s
+
+//===----------------------------------------------------------------------===//
+// This file tests cases where we should not flag out-of-bounds warnings.
+//===----------------------------------------------------------------------===//
+
+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.c b/test/Analysis/null-deref-ps.c
index 6e20741..f37b441 100644
--- a/test/Analysis/null-deref-ps.c
+++ b/test/Analysis/null-deref-ps.c
@@ -1,10 +1,16 @@
-// RUN: clang-cc -analyze -std=gnu99 -checker-cfref -verify %s -analyzer-constraints=basic -analyzer-store=basic &&
-// RUN: clang-cc -analyze -std=gnu99 -checker-cfref -verify %s -analyzer-constraints=range -analyzer-store=basic &&
-// RUN: clang-cc -analyze -std=gnu99 -checker-cfref -analyzer-store=region -analyzer-constraints=range -analyzer-purge-dead=false -verify %s &&
-// RUN: clang-cc -analyze -std=gnu99 -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: clang-cc -triple i386-apple-darwin10 -analyze -std=gnu99 -checker-cfref -verify %s -analyzer-constraints=basic -analyzer-store=basic &&
+// RUN: clang-cc -triple i386-apple-darwin10 -analyze -std=gnu99 -checker-cfref -verify %s -analyzer-constraints=range -analyzer-store=basic &&
+// RUN: clang-cc -triple i386-apple-darwin10 -analyze -std=gnu99 -checker-cfref -analyzer-store=region -analyzer-constraints=range -analyzer-purge-dead=false -verify %s &&
+// RUN: clang-cc -triple i386-apple-darwin10 -analyze -std=gnu99 -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s
-#include<stdint.h>
-#include <assert.h>
+typedef unsigned uintptr_t;
+
+extern void __assert_fail (__const char *__assertion, __const char *__file,
+ unsigned int __line, __const char *__function)
+ __attribute__ ((__noreturn__));
+
+#define assert(expr) \
+ ((expr) ? (void)(0) : __assert_fail (#expr, __FILE__, __LINE__, __func__))
void f1(int *p) {
if (p) *p = 1;
@@ -72,6 +78,7 @@ int f4_b() {
else return; // expected-warning {{non-void function 'f4_b' should return a value}}
*p += 10; // expected-warning{{Dereference of null pointer}}
+ return 0;
}
@@ -102,6 +109,15 @@ int f6c(int *p, int *q) {
: bar3(p, 2, q); // no-warning
}
+void f6d(int *p) {
+ bar(p, 0);
+ // At this point, 'p' cannot be null.
+ if (!p) {
+ int *q = 0;
+ *q = 0xDEADBEEF; // no-warning
+ }
+}
+
int* qux();
int f7(int x) {
@@ -160,7 +176,7 @@ int* f7c2(int *x) {
}
-int f8(int *p, int *q) {
+void f8(int *p, int *q) {
if (!p)
if (p)
*p = 1; // no-warning
@@ -262,4 +278,13 @@ void f13() {
if (((((int) x) << 2) + 1) >> 1) *x = 1; // no-warning
}
+// PR 4759 - Attribute non-null checking by the analyzer was not correctly
+// handling pointer values that were undefined.
+void pr4759_aux(int *p) __attribute__((nonnull));
+
+void pr4759() {
+ int *p;
+ pr4759_aux(p); // expected-warning{{undefined}}
+}
+
diff --git a/test/Analysis/outofbound.c b/test/Analysis/outofbound.c
index 527a311..568f143 100644
--- a/test/Analysis/outofbound.c
+++ b/test/Analysis/outofbound.c
@@ -1,4 +1,5 @@
// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -verify %s
+// XFAIL
char f1() {
char* s = "abcd";
diff --git a/test/Analysis/pr4209.m b/test/Analysis/pr4209.m
index 7d7d8fc..991d0d6 100644
--- a/test/Analysis/pr4209.m
+++ b/test/Analysis/pr4209.m
@@ -1,4 +1,4 @@
-// RUN: clang-cc -triple i386-apple-darwin9 -analyze -checker-cfref -verify %s &&
+// RUN: clang-cc -triple i386-apple-darwin9 -analyze -checker-cfref -analyzer-store=basic -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
@@ -56,6 +56,7 @@ CMProfileLocation;
- (GSEbayCategory *) parent;
- (GSEbayCategory*) subcategoryWithID:(int) inID;
@end @implementation GBCategoryChooserPanelController + (int) chooseCategoryIDFromCategories:(NSArray*) inCategories searchRequest:(GBSearchRequest*)inRequest parentWindow:(NSWindow*) inParent {
+ return 0;
}
- (void) addCategory:(EBayCategoryType*)inCategory toRootTreeCategory:(NSMutableArray*)inRootTreeCategories {
GSEbayCategory *category = [rootCategory subcategoryWithID:[[inCategory categoryID] intValue]];
diff --git a/test/Analysis/rdar-6442306-1.m b/test/Analysis/rdar-6442306-1.m
index 15d3498..bfda115 100644
--- a/test/Analysis/rdar-6442306-1.m
+++ b/test/Analysis/rdar-6442306-1.m
@@ -28,4 +28,5 @@ __Beeble_check__Request__SetPortalSize_t(__attribute__((__unused__)) __Request__
}
while (0);
}
+ return 0;
}
diff --git a/test/Analysis/rdar-6540084.m b/test/Analysis/rdar-6540084.m
index 18ab038..cfe5220 100644
--- a/test/Analysis/rdar-6540084.m
+++ b/test/Analysis/rdar-6540084.m
@@ -32,5 +32,6 @@ typedef struct {} TazVersion;
}
}
}
+ while (1) {}
}
@end
diff --git a/test/Analysis/rdar-6541136-region.c b/test/Analysis/rdar-6541136-region.c
index 1e7a2d9..e2779e8 100644
--- a/test/Analysis/rdar-6541136-region.c
+++ b/test/Analysis/rdar-6541136-region.c
@@ -13,7 +13,10 @@ void foo( void )
struct load_wine *cmd = (void*) &wonky[1];
cmd = cmd;
char *p = (void*) &wonky[1];
- *p = 1;
+ *p = 1; // no-warning
kernel_tea_cheese_t *q = &wonky[1];
- kernel_tea_cheese_t r = *q; // expected-warning{{out-of-bound memory position}}
+ // This test case tests both the RegionStore logic (doesn't crash) and
+ // the out-of-bounds checking. We don't expect the warning for now since
+ // out-of-bound checking is temporarily disabled.
+ kernel_tea_cheese_t r = *q; // eventually-warning{{out-of-bound memory position}}
}
diff --git a/test/Analysis/rdar-6562655.m b/test/Analysis/rdar-6562655.m
index 581d6ea..3c1c281 100644
--- a/test/Analysis/rdar-6562655.m
+++ b/test/Analysis/rdar-6562655.m
@@ -1,4 +1,5 @@
-// RUN: clang-cc -analyze -checker-cfref -analyzer-constraints=basic -analyzer-store=basic -verify %s
+// RUN: clang-cc -analyze -checker-cfref -analyzer-constraints=basic -analyzer-store=basic -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-constraints=basic -analyzer-store=region -verify %s
//
// This test case mainly checks that the retain/release checker doesn't crash
// on this file.
@@ -51,7 +52,7 @@ typedef struct _NSRunArrayItem {
@end
@implementation Bar
static Baz Qux = 0;
-- (id)copyWithZone:(NSZone *)zone {}
+- (id)copyWithZone:(NSZone *)zone { return 0; }
- (void)encodeWithCoder:(NSCoder *)coder {}
@end
@implementation Bar (BarBotnet)
@@ -59,5 +60,6 @@ static Baz Qux = 0;
if (!(*(BarAuxiliary **)&self->_support)->auxCFlags.botnetIsSet) {
_cFlags.botnet = [self _initialBotnetZorg];
}
+ while (1) {}
}
@end
diff --git a/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m b/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m
index 5d1fa37..49ef7c3 100644
--- a/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m
+++ b/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m
@@ -1,4 +1,5 @@
-// RUN: clang-cc -analyze -checker-cfref -analyzer-constraints=basic -analyzer-store=basic %s -verify
+// RUN: clang-cc -analyze -checker-cfref -analyzer-constraints=basic -analyzer-store=basic %s -verify &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-constraints=basic -analyzer-store=region %s -verify
typedef struct Foo { int x; } Bar;
diff --git a/test/Analysis/rdar-7168531.m b/test/Analysis/rdar-7168531.m
new file mode 100644
index 0000000..bdbd22d
--- /dev/null
+++ b/test/Analysis/rdar-7168531.m
@@ -0,0 +1,19 @@
+// RUN: clang-cc -analyze -checker-cfref -triple i386-apple-darwin10 -analyzer-store=region &&
+// RUN: clang-cc -analyze -checker-cfref -triple i386-apple-darwin10 -analyzer-store=basic
+
+// Note that the target triple is important for this test case. It specifies that we use the
+// fragile Objective-C ABI.
+
+@interface Foo {
+ int x;
+}
+@end
+
+@implementation Foo
+static Foo* bar(Foo *p) {
+ if (p->x)
+ return ++p; // This is only valid for the fragile ABI.
+
+ return p;
+}
+@end
diff --git a/test/Analysis/region-1.m b/test/Analysis/region-1.m
index ed172e4..68a375b 100644
--- a/test/Analysis/region-1.m
+++ b/test/Analysis/region-1.m
@@ -79,6 +79,7 @@ typedef NSUInteger JabaSourceLanguage;
Dos_CharacterRangeType = 0, Dos_LineRangeType = 1 }
DosTextRangeType;
@implementation JabaSCSharedDiagramViewController + (NSImage *)findImageNamed:(NSString *)name {
+ return 0;
}
- (void)revealSourceInEditor:(JabasectItem *)sectItem duperGesture:(BOOL)duperGesture {
id <EcoNamedElement> selectedElement = [sectItem representedObject];
diff --git a/test/Analysis/region-only-test.c b/test/Analysis/region-only-test.c
index 64d3fcd..8908adb 100644
--- a/test/Analysis/region-only-test.c
+++ b/test/Analysis/region-only-test.c
@@ -9,5 +9,5 @@ void foo(int* p) {
if (p[0] == 1)
x = &a;
if (p[0] == 1)
- *x; // no-warning
+ (void)*x; // no-warning
}
diff --git a/test/Analysis/retain-release-gc-only.m b/test/Analysis/retain-release-gc-only.m
index ec33a57..2833b02 100644
--- a/test/Analysis/retain-release-gc-only.m
+++ b/test/Analysis/retain-release-gc-only.m
@@ -1,16 +1,26 @@
-// RUN: clang-cc -analyze -checker-cfref -verify -fobjc-gc-only %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -verify -fobjc-gc-only %s &&
// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -fobjc-gc-only -verify %s
//===----------------------------------------------------------------------===//
// Header stuff.
//===----------------------------------------------------------------------===//
-typedef struct objc_class *Class;
-
typedef unsigned int __darwin_natural_t;
-typedef struct {} div_t;
-typedef unsigned long UInt32;
+typedef unsigned long uintptr_t;
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+typedef unsigned int UInt32;
typedef signed long CFIndex;
+typedef struct {
+ CFIndex location;
+ CFIndex length;
+} CFRange;
+static __inline__ __attribute__((always_inline)) CFRange CFRangeMake(CFIndex loc, CFIndex len) {
+ CFRange range;
+ range.location = loc;
+ range.length = len;
+ return range;
+}
typedef const void * CFTypeRef;
typedef const struct __CFString * CFStringRef;
typedef const struct __CFAllocator * CFAllocatorRef;
@@ -26,7 +36,17 @@ 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 struct {
+}
+CFDictionaryKeyCallBacks;
+extern const CFDictionaryKeyCallBacks kCFTypeDictionaryKeyCallBacks;
+typedef struct {
+}
+CFDictionaryValueCallBacks;
+extern const CFDictionaryValueCallBacks kCFTypeDictionaryValueCallBacks;
typedef const struct __CFDictionary * CFDictionaryRef;
+typedef struct __CFDictionary * CFMutableDictionaryRef;
+extern CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFDictionaryKeyCallBacks *keyCallBacks, const CFDictionaryValueCallBacks *valueCallBacks);
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 };
@@ -40,44 +60,96 @@ 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 int kern_return_t;
+typedef kern_return_t mach_error_t;
+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 const struct __CFAttributedString *CFAttributedStringRef;
+typedef struct __CFAttributedString *CFMutableAttributedStringRef;
+extern CFAttributedStringRef CFAttributedStringCreate(CFAllocatorRef alloc, CFStringRef str, CFDictionaryRef attributes) ;
+extern CFMutableAttributedStringRef CFAttributedStringCreateMutableCopy(CFAllocatorRef alloc, CFIndex maxLength, CFAttributedStringRef aStr) ;
+extern void CFAttributedStringSetAttribute(CFMutableAttributedStringRef aStr, CFRange range, CFStringRef attrName, CFTypeRef value) ;
typedef signed char BOOL;
-typedef unsigned int NSUInteger;
+typedef unsigned long 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;
+@protocol NSObject
+- (BOOL)isEqual:(id)object;
- (id)retain;
- (oneway void)release;
- (id)autorelease;
+- (Class)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> {}
-- (Class)class;
-+ (id)alloc;
+ (id)allocWithZone:(NSZone *)zone;
-@end typedef float CGFloat;
++ (id)alloc;
+- (void)dealloc;
+@end
+@interface NSObject (NSCoderMethods)
+- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder;
+@end
+extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone);
+typedef struct {
+}
+NSFastEnumerationState;
+@protocol NSFastEnumeration - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len;
+@end @class NSString, NSDictionary;
+@interface NSValue : NSObject <NSCopying, NSCoding> - (void)getValue:(void *)value;
+@end @interface NSNumber : NSValue - (char)charValue;
+- (id)initWithInt:(int)value;
+@end @class NSString;
+@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> - (NSUInteger)count;
+@end @interface NSArray (NSArrayCreation) + (id)array;
+@end @interface NSAutoreleasePool : NSObject {
+}
+- (void)drain;
+@end extern NSString * const NSBundleDidLoadNotification;
+typedef double NSTimeInterval;
+@interface NSDate : NSObject <NSCopying, NSCoding> - (NSTimeInterval)timeIntervalSinceReferenceDate;
+@end typedef unsigned short unichar;
@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding> - (NSUInteger)length;
-- (const char *)UTF8String;
+- ( 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;
+@end @class NSString, NSURL, NSError;
+@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 @class NSLocale, NSDate, NSCalendar, NSTimeZone, NSError, NSArray, NSMutableDictionary;
+@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;
+@end typedef double CGFloat;
+struct CGSize {
+};
+typedef struct CGSize CGSize;
+struct CGRect {
+};
+typedef struct CGRect CGRect;
typedef mach_port_t io_object_t;
+typedef char io_name_t[128];
+typedef io_object_t io_iterator_t;
typedef io_object_t io_service_t;
+typedef struct IONotificationPort * IONotificationPortRef;
+typedef void (*IOServiceMatchingCallback)( void * refcon, io_iterator_t iterator );
+io_service_t IOServiceGetMatchingService( mach_port_t masterPort, CFDictionaryRef matching );
+kern_return_t IOServiceGetMatchingServices( mach_port_t masterPort, CFDictionaryRef matching, io_iterator_t * existing );
+kern_return_t IOServiceAddNotification( mach_port_t masterPort, const io_name_t notificationType, CFDictionaryRef matching, mach_port_t wakePort, uintptr_t reference, io_iterator_t * notification ) __attribute__((deprecated));
+kern_return_t IOServiceAddMatchingNotification( IONotificationPortRef notifyPort, const io_name_t notificationType, CFDictionaryRef matching, IOServiceMatchingCallback callback, void * refCon, io_iterator_t * notification );
+CFMutableDictionaryRef IOServiceMatching( const char * name );
+CFMutableDictionaryRef IOServiceNameMatching( const char * name );
+CFMutableDictionaryRef IOBSDNameMatching( mach_port_t masterPort, uint32_t options, const char * bsdName );
+CFMutableDictionaryRef IOOpenFirmwarePathMatching( mach_port_t masterPort, uint32_t options, const char * path );
+CFMutableDictionaryRef IORegistryEntryIDMatching( uint64_t entryID );
typedef struct __DASession * DASessionRef;
extern DASessionRef DASessionCreate( CFAllocatorRef allocator );
typedef struct __DADisk * DADiskRef;
@@ -85,23 +157,62 @@ extern DADiskRef DADiskCreateFromBSDName( CFAllocatorRef allocator, DASessionRef
extern DADiskRef DADiskCreateFromIOMedia( CFAllocatorRef allocator, DASessionRef session, io_service_t media );
extern CFDictionaryRef DADiskCopyDescription( DADiskRef disk );
extern DADiskRef DADiskCopyWholeDisk( DADiskRef disk );
+@interface NSTask : NSObject - (id)init;
+@end typedef struct CGColorSpace *CGColorSpaceRef;
+typedef struct CGImage *CGImageRef;
+typedef struct CGLayer *CGLayerRef;
@interface NSResponder : NSObject <NSCoding> {
}
-@end @class NSColor, NSFont, NSNotification;
-typedef struct __CFlags {
+@end @protocol NSAnimatablePropertyContainer - (id)animator;
+@end extern NSString *NSAnimationTriggerOrderIn ;
+@interface NSView : NSResponder <NSAnimatablePropertyContainer> {
}
-_CFlags;
+@end @protocol NSValidatedUserInterfaceItem - (SEL)action;
+@end @protocol NSUserInterfaceValidations - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)anItem;
+@end @class NSDate, NSDictionary, NSError, NSException, NSNotification;
+@interface NSApplication : NSResponder <NSUserInterfaceValidations> {
+}
+@end enum {
+NSTerminateCancel = 0, NSTerminateNow = 1, NSTerminateLater = 2 };
+typedef NSUInteger NSApplicationTerminateReply;
+@protocol NSApplicationDelegate <NSObject> @optional - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender;
+@end @class NSAttributedString, NSEvent, NSFont, NSFormatter, NSImage, NSMenu, NSText, NSView, NSTextView;
@interface NSCell : NSObject <NSCopying, NSCoding> {
}
-@end @class NSDate, NSDictionary, NSError, NSException, NSNotification;
-@interface NSManagedObjectContext : NSObject <NSCoding, NSLocking> {
+@end @class NSTextField, NSPanel, NSArray, NSWindow, NSImage, NSButton, NSError;
+typedef struct {
+}
+CVTimeStamp;
+@interface CIImage : NSObject <NSCoding, NSCopying> {
}
-@end enum {
+typedef int CIFormat;
+@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 );
-
+@interface CIContext: NSObject {
+}
+- (CGImageRef)createCGImage:(CIImage *)im fromRect:(CGRect)r;
+- (CGImageRef)createCGImage:(CIImage *)im fromRect:(CGRect)r format:(CIFormat)f colorSpace:(CGColorSpaceRef)cs;
+- (CGLayerRef)createCGLayerWithSize:(CGSize)size info:(CFDictionaryRef)d;
+@end extern NSString* const QCRendererEventKey;
+@protocol QCCompositionRenderer - (NSDictionary*) attributes;
+@end @interface QCRenderer : NSObject <QCCompositionRenderer> {
+}
+- (id) createSnapshotImageOfType:(NSString*)type;
+@end extern NSString* const QCViewDidStartRenderingNotification;
+@interface QCView : NSView <QCCompositionRenderer> {
+}
+- (id) createSnapshotImageOfType:(NSString*)type;
+@end enum {
+ICEXIFOrientation1 = 1, ICEXIFOrientation2 = 2, ICEXIFOrientation3 = 3, ICEXIFOrientation4 = 4, ICEXIFOrientation5 = 5, ICEXIFOrientation6 = 6, ICEXIFOrientation7 = 7, ICEXIFOrientation8 = 8, };
+@class ICDevice;
+@protocol ICDeviceDelegate <NSObject> @required - (void)didRemoveDevice:(ICDevice*)device;
+@end extern NSString *const ICScannerStatusWarmingUp;
+@class ICScannerDevice;
+@protocol ICScannerDeviceDelegate <ICDeviceDelegate> @optional - (void)scannerDeviceDidBecomeAvailable:(ICScannerDevice*)scanner;
+@end
CFTypeRef CFMakeCollectable(CFTypeRef cf) ;
static __inline__ __attribute__((always_inline)) id NSMakeCollectable(CFTypeRef
@@ -198,6 +309,19 @@ void f5b() {
@end
//===----------------------------------------------------------------------===//
+// <rdar://problem/7174400> 'ciContext createCGImage:outputImage fromRect:' returns a retained CF object (not GC'ed)//===----------------------------------------------------------------------===//
+//===----------------------------------------------------------------------===//
+
+void rdar_7174400(QCView *view, QCRenderer *renderer, CIContext *context,
+ NSString *str, CIImage *img, CGRect rect,
+ CIFormat form, CGColorSpaceRef cs) {
+ [view createSnapshotImageOfType:str]; // no-warning
+ [renderer createSnapshotImageOfType:str]; // no-warning
+ [context createCGImage:img fromRect:rect]; // expected-warning{{leak}}
+ [context createCGImage:img fromRect:rect format:form colorSpace:cs]; // expected-warning{{leak}}
+}
+
+//===----------------------------------------------------------------------===//
// Tests of ownership attributes.
//===----------------------------------------------------------------------===//
diff --git a/test/Analysis/retain-release-region-store.m b/test/Analysis/retain-release-region-store.m
index 66950e2..7a69683 100644
--- a/test/Analysis/retain-release-region-store.m
+++ b/test/Analysis/retain-release-region-store.m
@@ -1,4 +1,5 @@
// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -verify %s
+// XFAIL
//===----------------------------------------------------------------------===//
// The following code is reduced using delta-debugging from
@@ -115,4 +116,27 @@ CFAbsoluteTime f4() {
}
@end
+//===----------------------------------------------------------------------===//
+// <rdar://problem/7257223> - False positive due to not invalidating the
+// reference count of a tracked region that was itself invalidated.
+//===----------------------------------------------------------------------===//
+
+typedef struct __rdar_7257223 { CFDateRef x; } RDar7257223;
+void rdar_7257223_aux(RDar7257223 *p);
+
+// THIS CASE CURRENTLY FAILS.
+CFDateRef rdar7257223_Create(void) {
+ RDar7257223 s;
+ CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
+ s.x = CFDateCreate(0, t); // no-warning
+ rdar_7257223_aux(&s);
+ return s.x;
+}
+
+CFDateRef rdar7257223_Create_2(void) {
+ RDar7257223 s;
+ CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
+ s.x = CFDateCreate(0, t); // no-warning
+ return s.x;
+}
diff --git a/test/Analysis/retain-release.m b/test/Analysis/retain-release.m
index da0ae80..7076bb2 100644
--- a/test/Analysis/retain-release.m
+++ b/test/Analysis/retain-release.m
@@ -1,6 +1,12 @@
-//>>SLICER
-// RUN: clang-cc -analyze -checker-cfref -verify %s &&
-// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -verify %s
+// RUN: clang-cc -triple x86_64-apple-darwin10 -analyze -checker-cfref -analyzer-store=basic -verify %s &&
+// RUN: clang-cc -triple x86_64-apple-darwin10 -analyze -checker-cfref -analyzer-store=region -verify %s
+
+#if __has_feature(attribute_ns_returns_retained)
+#define NS_RETURNS_RETAINED __attribute__((ns_returns_retained))
+#endif
+#if __has_feature(attribute_cf_returns_retained)
+#define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))
+#endif
//===----------------------------------------------------------------------===//
// The following code is reduced using delta-debugging from Mac OS X headers:
@@ -21,6 +27,16 @@ typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
typedef unsigned int UInt32;
typedef signed long CFIndex;
+typedef struct {
+ CFIndex location;
+ CFIndex length;
+} CFRange;
+static __inline__ __attribute__((always_inline)) CFRange CFRangeMake(CFIndex loc, CFIndex len) {
+ CFRange range;
+ range.location = loc;
+ range.length = len;
+ return range;
+}
typedef const void * CFTypeRef;
typedef const struct __CFString * CFStringRef;
typedef const struct __CFAllocator * CFAllocatorRef;
@@ -36,8 +52,17 @@ 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 struct {
+}
+CFDictionaryKeyCallBacks;
+extern const CFDictionaryKeyCallBacks kCFTypeDictionaryKeyCallBacks;
+typedef struct {
+}
+CFDictionaryValueCallBacks;
+extern const CFDictionaryValueCallBacks kCFTypeDictionaryValueCallBacks;
typedef const struct __CFDictionary * CFDictionaryRef;
typedef struct __CFDictionary * CFMutableDictionaryRef;
+extern CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFDictionaryKeyCallBacks *keyCallBacks, const CFDictionaryValueCallBacks *valueCallBacks);
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 };
@@ -53,29 +78,48 @@ 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;
+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 const struct __CFAttributedString *CFAttributedStringRef;
+typedef struct __CFAttributedString *CFMutableAttributedStringRef;
+extern CFAttributedStringRef CFAttributedStringCreate(CFAllocatorRef alloc, CFStringRef str, CFDictionaryRef attributes) ;
+extern CFMutableAttributedStringRef CFAttributedStringCreateMutableCopy(CFAllocatorRef alloc, CFIndex maxLength, CFAttributedStringRef aStr) ;
+extern void CFAttributedStringSetAttribute(CFMutableAttributedStringRef aStr, CFRange range, CFStringRef attrName, CFTypeRef value) ;
typedef signed char BOOL;
typedef unsigned long 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;
+@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> {
-}
+@end
+@interface NSObject <NSObject> {}
+ (id)allocWithZone:(NSZone *)zone;
+ (id)alloc;
- (void)dealloc;
-@end extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone);
+@end
+@interface NSObject (NSCoderMethods)
+- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder;
+@end
+extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone);
typedef struct {
}
NSFastEnumerationState;
@protocol NSFastEnumeration - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len;
+@end @class NSString, NSDictionary;
+@interface NSValue : NSObject <NSCopying, NSCoding> - (void)getValue:(void *)value;
+@end @interface NSNumber : NSValue - (char)charValue;
+- (id)initWithInt:(int)value;
@end @class NSString;
@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> - (NSUInteger)count;
@end @interface NSArray (NSArrayCreation) + (id)array;
@@ -90,11 +134,11 @@ typedef double NSTimeInterval;
- ( const char *)UTF8String;
- (id)initWithUTF8String:(const char *)nullTerminatedCString;
+ (id)stringWithUTF8String:(const char *)nullTerminatedCString;
-@end @class NSString, NSData;
+@end @class NSString, NSURL, NSError;
@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 @class NSString;
+@end @class NSLocale, NSDate, NSCalendar, NSTimeZone, NSError, NSArray, NSMutableDictionary;
@interface NSDictionary : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> - (NSUInteger)count;
@end @interface NSMutableDictionary : NSDictionary - (void)removeObjectForKey:(id)aKey;
- (void)setObject:(id)anObject forKey:(id)aKey;
@@ -106,9 +150,6 @@ typedef struct CGSize CGSize;
struct CGRect {
};
typedef struct CGRect CGRect;
-@protocol NSLocking - (void)lock;
-- (id)init;
-@end @class NSURLAuthenticationChallenge;
typedef mach_port_t io_object_t;
typedef char io_name_t[128];
typedef io_object_t io_iterator_t;
@@ -131,37 +172,32 @@ extern DADiskRef DADiskCreateFromBSDName( CFAllocatorRef allocator, DASessionRef
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;
+@interface NSTask : NSObject - (id)init;
+@end typedef struct CGColorSpace *CGColorSpaceRef;
typedef struct CGImage *CGImageRef;
- typedef struct CGLayer *CGLayerRef;
- @class NSArray, NSError, NSEvent, NSMenu, NSUndoManager, NSWindow;
+typedef struct CGLayer *CGLayerRef;
@interface NSResponder : NSObject <NSCoding> {
}
@end @protocol NSAnimatablePropertyContainer - (id)animator;
@end extern NSString *NSAnimationTriggerOrderIn ;
@interface NSView : NSResponder <NSAnimatablePropertyContainer> {
-struct __VFlags2 {
-}
-_vFlags2;
-}
-@end extern NSString * const NSFullScreenModeAllScreens;
-@protocol NSChangeSpelling - (void)changeSpelling:(id)sender;
-@end @protocol NSIgnoreMisspelledWords - (void)ignoreSpelling:(id)sender;
-@end @class NSColor, NSFont, NSNotification;
-@interface NSText : NSView <NSChangeSpelling, NSIgnoreMisspelledWords> {
}
@end @protocol NSValidatedUserInterfaceItem - (SEL)action;
@end @protocol NSUserInterfaceValidations - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)anItem;
-@end @class NSArray, NSError, NSImage, NSView, NSNotificationCenter, NSURL, NSScreen, NSRunningApplication;
+@end @class NSDate, NSDictionary, NSError, NSException, NSNotification;
@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 {
+@end @class NSAttributedString, NSEvent, NSFont, NSFormatter, NSImage, NSMenu, NSText, NSView, NSTextView;
+@interface NSCell : NSObject <NSCopying, NSCoding> {
}
-_CFlags;
+@end @class NSTextField, NSPanel, NSArray, NSWindow, NSImage, NSButton, NSError;
+typedef struct {
+}
+CVTimeStamp;
@interface CIImage : NSObject <NSCoding, NSCopying> {
}
typedef int CIFormat;
@@ -175,7 +211,7 @@ extern DADissenterRef DADissenterCreate( CFAllocatorRef allocator, DAReturn stat
- (CGImageRef)createCGImage:(CIImage *)im fromRect:(CGRect)r;
- (CGImageRef)createCGImage:(CIImage *)im fromRect:(CGRect)r format:(CIFormat)f colorSpace:(CGColorSpaceRef)cs;
- (CGLayerRef)createCGLayerWithSize:(CGSize)size info:(CFDictionaryRef)d;
-@end @class NSURL;
+@end extern NSString* const QCRendererEventKey;
@protocol QCCompositionRenderer - (NSDictionary*) attributes;
@end @interface QCRenderer : NSObject <QCCompositionRenderer> {
}
@@ -188,11 +224,34 @@ extern DADissenterRef DADissenterCreate( CFAllocatorRef allocator, DAReturn stat
ICEXIFOrientation1 = 1, ICEXIFOrientation2 = 2, ICEXIFOrientation3 = 3, ICEXIFOrientation4 = 4, ICEXIFOrientation5 = 5, ICEXIFOrientation6 = 6, ICEXIFOrientation7 = 7, ICEXIFOrientation8 = 8, };
@class ICDevice;
@protocol ICDeviceDelegate <NSObject> @required - (void)didRemoveDevice:(ICDevice*)device;
-@end @class ICCameraDevice;
+@end extern NSString *const ICScannerStatusWarmingUp;
@class ICScannerDevice;
@protocol ICScannerDeviceDelegate <ICDeviceDelegate> @optional - (void)scannerDeviceDidBecomeAvailable:(ICScannerDevice*)scanner;
@end
-
+
+typedef long unsigned int __darwin_size_t;
+typedef __darwin_size_t size_t;
+typedef unsigned long CFTypeID;
+struct CGPoint {
+ CGFloat x;
+ CGFloat y;
+};
+typedef struct CGPoint CGPoint;
+typedef struct CGGradient *CGGradientRef;
+typedef uint32_t CGGradientDrawingOptions;
+extern CFTypeID CGGradientGetTypeID(void);
+extern CGGradientRef CGGradientCreateWithColorComponents(CGColorSpaceRef
+ space, const CGFloat components[], const CGFloat locations[], size_t count);
+extern CGGradientRef CGGradientCreateWithColors(CGColorSpaceRef space,
+ CFArrayRef colors, const CGFloat locations[]);
+extern CGGradientRef CGGradientRetain(CGGradientRef gradient);
+extern void CGGradientRelease(CGGradientRef gradient);
+typedef struct CGContext *CGContextRef;
+extern void CGContextDrawLinearGradient(CGContextRef context,
+ CGGradientRef gradient, CGPoint startPoint, CGPoint endPoint,
+ CGGradientDrawingOptions options);
+extern CGColorSpaceRef CGColorSpaceCreateDeviceRGB(void);
+
//===----------------------------------------------------------------------===//
// Test cases.
//===----------------------------------------------------------------------===//
@@ -371,6 +430,7 @@ CFMutableArrayRef f13_autorelease_d() {
[(id) A autorelease];
CFMutableArrayRef B = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // expected-warning{{Object sent -autorelease too many times}}
CFRelease(B); // no-warning
+ while (1) {}
}
@@ -389,6 +449,18 @@ void f15() {
CFRelease(*B); // no-warning
}
+// Test when we pass NULL to CFRetain/CFRelease.
+void f16(int x, CFTypeRef p) {
+ if (p)
+ return;
+
+ if (x) {
+ CFRelease(p); // expected-warning{{Null pointer argument in call to CFRelease}}
+ }
+ else {
+ CFRetain(p); // expected-warning{{Null pointer argument in call to CFRetain}}
+ }
+}
// Test basic tracking of ivars associated with 'self'. For the retain/release
// checker we currently do not want to flag leaks associated with stores
@@ -559,7 +631,7 @@ void rdar6704930(unsigned char *s, unsigned int length) {
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}}
+ [array release]; // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
[pool drain];
return 0;
}
@@ -603,7 +675,8 @@ typedef CFTypeRef OtherRef;
@end
//===----------------------------------------------------------------------===//
-//<rdar://problem/6320065> false positive - init method returns an object owned by caller
+//<rdar://problem/6320065> false positive - init method returns an object
+// owned by caller
//===----------------------------------------------------------------------===//
@interface RDar6320065 : NSObject {
@@ -646,7 +719,21 @@ int RDar6320065_test() {
}
//===----------------------------------------------------------------------===//
-// <rdar://problem/6859457> [NSData dataWithBytesNoCopy] does not return a retained object
+// <rdar://problem/7129086> -awakeAfterUsingCoder: returns an owned object
+// and claims the receiver
+//===----------------------------------------------------------------------===//
+
+@interface RDar7129086 : NSObject {} @end
+@implementation RDar7129086
+- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder {
+ [self release]; // no-warning
+ return [NSString alloc]; // no-warning
+}
+@end
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/6859457> [NSData dataWithBytesNoCopy] does not return a
+// retained object
//===----------------------------------------------------------------------===//
@interface RDar6859457 : NSObject {}
@@ -750,7 +837,7 @@ void IOServiceNameMatching_wrapper(const char * name) {
IOServiceNameMatching(name); // expected-warning{{leak}}
}
-__attribute__((cf_returns_retained)) CFDictionaryRef CreateDict();
+CF_RETURNS_RETAINED CFDictionaryRef CreateDict();
void IOServiceAddNotification_wrapper(mach_port_t masterPort, const io_name_t notificationType,
mach_port_t wakePort, uintptr_t reference, io_iterator_t * notification ) {
@@ -791,19 +878,241 @@ void IOServiceAddMatchingNotification_wrapper(IONotificationPortRef notifyPort,
}
//===----------------------------------------------------------------------===//
+// Test of handling objects whose references "escape" to containers.
+//===----------------------------------------------------------------------===//
+
+// <rdar://problem/6539791>
+void rdar_6539791(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 rdar_6560661(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
+}
+
+// <rdar://problem/7152619>
+// Same issue, excwept with "CFAttributeStringSetAttribute".
+void rdar_7152619(CFStringRef str) {
+ CFAttributedStringRef string = CFAttributedStringCreate(kCFAllocatorDefault, str, 0);
+ CFMutableAttributedStringRef attrString = CFAttributedStringCreateMutableCopy(kCFAllocatorDefault, 100, string);
+ CFRelease(string);
+ NSNumber *number = [[NSNumber alloc] initWithInt:5]; // expected-warning{{leak}}
+ CFAttributedStringSetAttribute(attrString, CFRangeMake(0, 1), str, number);
+ [number release];
+ [number retain];
+ CFRelease(attrString);
+}
+
+//===----------------------------------------------------------------------===//
+// Test of handling CGGradientXXX functions.
+//===----------------------------------------------------------------------===//
+
+void rdar_7184450(CGContextRef myContext, CGFloat x, CGPoint myStartPoint,
+ CGPoint myEndPoint) {
+ size_t num_locations = 6;
+ CGFloat locations[6] = { 0.0, 0.265, 0.28, 0.31, 0.36, 1.0 };
+ CGFloat components[28] = { 239.0/256.0, 167.0/256.0, 170.0/256.0,
+ x, // Start color
+ 207.0/255.0, 39.0/255.0, 39.0/255.0, x,
+ 147.0/255.0, 21.0/255.0, 22.0/255.0, x,
+ 175.0/255.0, 175.0/255.0, 175.0/255.0, x,
+ 255.0/255.0,255.0/255.0, 255.0/255.0, x,
+ 255.0/255.0,255.0/255.0, 255.0/255.0, x
+ }; // End color
+
+ CGGradientRef myGradient =
+ CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(), // expected-warning{{leak}}
+ components, locations, num_locations);
+
+ CGContextDrawLinearGradient(myContext, myGradient, myStartPoint, myEndPoint,
+ 0);
+ CGGradientRelease(myGradient);
+}
+
+void rdar_7184450_pos(CGContextRef myContext, CGFloat x, CGPoint myStartPoint,
+ CGPoint myEndPoint) {
+ size_t num_locations = 6;
+ CGFloat locations[6] = { 0.0, 0.265, 0.28, 0.31, 0.36, 1.0 };
+ CGFloat components[28] = { 239.0/256.0, 167.0/256.0, 170.0/256.0,
+ x, // Start color
+ 207.0/255.0, 39.0/255.0, 39.0/255.0, x,
+ 147.0/255.0, 21.0/255.0, 22.0/255.0, x,
+ 175.0/255.0, 175.0/255.0, 175.0/255.0, x,
+ 255.0/255.0,255.0/255.0, 255.0/255.0, x,
+ 255.0/255.0,255.0/255.0, 255.0/255.0, x
+ }; // End color
+
+ CGGradientRef myGradient =
+ CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(), components, locations, num_locations); // expected-warning 2 {{leak}}
+
+ CGContextDrawLinearGradient(myContext, myGradient, myStartPoint, myEndPoint,
+ 0);
+}
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/7299394> clang false positive: retained instance passed to
+// thread in pthread_create marked as leak
+//
+// Until we have full IPA, the analyzer should stop tracking the reference
+// count of objects passed to pthread_create.
+//
+//===----------------------------------------------------------------------===//
+
+struct _opaque_pthread_t {};
+struct _opaque_pthread_attr_t {};
+typedef struct _opaque_pthread_t *__darwin_pthread_t;
+typedef struct _opaque_pthread_attr_t __darwin_pthread_attr_t;
+typedef __darwin_pthread_t pthread_t;
+typedef __darwin_pthread_attr_t pthread_attr_t;
+
+int pthread_create(pthread_t * restrict, const pthread_attr_t * restrict,
+ void *(*)(void *), void * restrict);
+
+void *rdar_7299394_start_routine(void *p) {
+ [((id) p) release];
+ return 0;
+}
+void rdar_7299394(pthread_attr_t *attr, pthread_t *thread, void *args) {
+ NSNumber *number = [[NSNumber alloc] initWithInt:5]; // no-warning
+ pthread_create(thread, attr, rdar_7299394_start_routine, number);
+}
+void rdar_7299394_positive(pthread_attr_t *attr, pthread_t *thread) {
+ NSNumber *number = [[NSNumber alloc] initWithInt:5]; // expected-warning{{leak}}
+}
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/7283567> False leak associated with call to
+// CVPixelBufferCreateWithBytes ()
+//
+// According to the Core Video Reference (ADC), CVPixelBufferCreateWithBytes and
+// CVPixelBufferCreateWithPlanarBytes can release (via a callback) the
+// pixel buffer object. These test cases show how the analyzer stops tracking
+// the reference count for the objects passed for this argument. This
+// could be made smarter.
+//===----------------------------------------------------------------------===//
+
+typedef int int32_t;
+typedef UInt32 FourCharCode;
+typedef FourCharCode OSType;
+typedef uint64_t CVOptionFlags;
+typedef int32_t CVReturn;
+typedef struct __CVBuffer *CVBufferRef;
+typedef CVBufferRef CVImageBufferRef;
+typedef CVImageBufferRef CVPixelBufferRef;
+typedef void (*CVPixelBufferReleaseBytesCallback)( void *releaseRefCon, const void *baseAddress );
+
+extern CVReturn CVPixelBufferCreateWithBytes(CFAllocatorRef allocator,
+ size_t width,
+ size_t height,
+ OSType pixelFormatType,
+ void *baseAddress,
+ size_t bytesPerRow,
+ CVPixelBufferReleaseBytesCallback releaseCallback,
+ void *releaseRefCon,
+ CFDictionaryRef pixelBufferAttributes,
+ CVPixelBufferRef *pixelBufferOut) ;
+
+typedef void (*CVPixelBufferReleasePlanarBytesCallback)( void *releaseRefCon, const void *dataPtr, size_t dataSize, size_t numberOfPlanes, const void *planeAddresses[] );
+
+extern CVReturn CVPixelBufferCreateWithPlanarBytes(CFAllocatorRef allocator,
+ size_t width,
+ size_t height,
+ OSType pixelFormatType,
+ void *dataPtr,
+ size_t dataSize,
+ size_t numberOfPlanes,
+ void *planeBaseAddress[],
+ size_t planeWidth[],
+ size_t planeHeight[],
+ size_t planeBytesPerRow[],
+ CVPixelBufferReleasePlanarBytesCallback releaseCallback,
+ void *releaseRefCon,
+ CFDictionaryRef pixelBufferAttributes,
+ CVPixelBufferRef *pixelBufferOut) ;
+
+extern CVReturn CVPixelBufferCreateWithBytes(CFAllocatorRef allocator,
+ size_t width,
+ size_t height,
+ OSType pixelFormatType,
+ void *baseAddress,
+ size_t bytesPerRow,
+ CVPixelBufferReleaseBytesCallback releaseCallback,
+ void *releaseRefCon,
+ CFDictionaryRef pixelBufferAttributes,
+ CVPixelBufferRef *pixelBufferOut) ;
+
+CVReturn rdar_7283567(CFAllocatorRef allocator, size_t width, size_t height,
+ OSType pixelFormatType, void *baseAddress,
+ size_t bytesPerRow,
+ CVPixelBufferReleaseBytesCallback releaseCallback,
+ CFDictionaryRef pixelBufferAttributes,
+ CVPixelBufferRef *pixelBufferOut) {
+
+ // For the allocated object, it doesn't really matter what type it is
+ // for the purpose of this test. All we want to show is that
+ // this is freed later by the callback.
+ NSNumber *number = [[NSNumber alloc] initWithInt:5]; // no-warning
+
+ return CVPixelBufferCreateWithBytes(allocator, width, height, pixelFormatType,
+ baseAddress, bytesPerRow, releaseCallback,
+ number, // potentially released by callback
+ pixelBufferAttributes, pixelBufferOut) ;
+}
+
+CVReturn rdar_7283567_2(CFAllocatorRef allocator, size_t width, size_t height,
+ OSType pixelFormatType, void *dataPtr, size_t dataSize,
+ size_t numberOfPlanes, void *planeBaseAddress[],
+ size_t planeWidth[], size_t planeHeight[], size_t planeBytesPerRow[],
+ CVPixelBufferReleasePlanarBytesCallback releaseCallback,
+ CFDictionaryRef pixelBufferAttributes,
+ CVPixelBufferRef *pixelBufferOut) {
+
+ // For the allocated object, it doesn't really matter what type it is
+ // for the purpose of this test. All we want to show is that
+ // this is freed later by the callback.
+ NSNumber *number = [[NSNumber alloc] initWithInt:5]; // no-warning
+
+ return CVPixelBufferCreateWithPlanarBytes(allocator,
+ width, height, pixelFormatType, dataPtr, dataSize,
+ numberOfPlanes, planeBaseAddress, planeWidth,
+ planeHeight, planeBytesPerRow, releaseCallback,
+ number, // potentially released by callback
+ pixelBufferAttributes, pixelBufferOut) ;
+}
+
+//===----------------------------------------------------------------------===//
// Tests of ownership attributes.
//===----------------------------------------------------------------------===//
typedef NSString* MyStringTy;
+@protocol FooP;
+
@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}}
+- (NSString*) returnsAnOwnedString NS_RETURNS_RETAINED; // no-warning
+- (NSString*) returnsAnOwnedCFString CF_RETURNS_RETAINED; // no-warning
+- (MyStringTy) returnsAnOwnedTypedString NS_RETURNS_RETAINED; // no-warning
+- (int) returnsAnOwnedInt 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}}
+static int ownership_attribute_doesnt_go_here 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}}
@@ -814,12 +1123,14 @@ void test_attr_1b(TestOwnershipAttr *X) {
}
@interface MyClassTestCFAttr : NSObject {}
-- (NSDate*) returnsCFRetained __attribute__((cf_returns_retained));
+- (NSDate*) returnsCFRetained CF_RETURNS_RETAINED;
+- (CFDateRef) returnsCFRetainedAsCF CF_RETURNS_RETAINED;
- (NSDate*) alsoReturnsRetained;
-- (NSDate*) returnsNSRetained __attribute__((ns_returns_retained));
+- (CFDateRef) alsoReturnsRetainedAsCF;
+- (NSDate*) returnsNSRetained NS_RETURNS_RETAINED;
@end
-__attribute__((cf_returns_retained))
+CF_RETURNS_RETAINED
CFDateRef returnsRetainedCFDate() {
return CFDateCreate(0, CFAbsoluteTimeGetCurrent());
}
@@ -829,14 +1140,58 @@ CFDateRef returnsRetainedCFDate() {
return (NSDate*) returnsRetainedCFDate(); // No leak.
}
+- (CFDateRef) returnsCFRetainedAsCF {
+ return returnsRetainedCFDate(); // No leak.
+}
+
+
- (NSDate*) alsoReturnsRetained {
return (NSDate*) returnsRetainedCFDate(); // expected-warning{{leak}}
}
+- (CFDateRef) alsoReturnsRetainedAsCF {
+ return returnsRetainedCFDate(); // expected-warning{{leak}}
+}
+
+
- (NSDate*) returnsNSRetained {
return (NSDate*) returnsRetainedCFDate(); // no-warning
}
@end
+//===----------------------------------------------------------------------===//
+// Test that leaks post-dominated by "panic" functions are not reported.
+//
+// <rdar://problem/5905851> do not report a leak when post-dominated by a call
+// to a noreturn or panic function
+//===----------------------------------------------------------------------===//
+
+void panic() __attribute__((noreturn));
+
+void test_panic_negative() {
+ signed z = 1;
+ CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &z); // expected-warning{{leak}}
+}
+
+void test_panic_positive() {
+ signed z = 1;
+ CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &z); // no-warning
+ panic();
+}
+void test_panic_neg_2(int x) {
+ signed z = 1;
+ CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &z); // expected-warning{{leak}}
+ if (x)
+ panic();
+}
+
+void test_panic_pos_2(int x) {
+ signed z = 1;
+ CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &z); // no-warning
+ if (x)
+ panic();
+ if (!x)
+ panic();
+}
diff --git a/test/Analysis/security-syntax-checks.m b/test/Analysis/security-syntax-checks.m
new file mode 100644
index 0000000..ebd7d17
--- /dev/null
+++ b/test/Analysis/security-syntax-checks.m
@@ -0,0 +1,91 @@
+// RUN: clang-cc -triple i386-apple-darwin10 -analyze -warn-security-syntactic %s -verify
+
+// <rdar://problem/6336718> rule request: floating point used as loop
+// condition (FLP30-C, FLP-30-CPP)
+//
+// For reference: https://www.securecoding.cert.org/confluence/display/seccode/FLP30-C.+Do+not+use+floating+point+variables+as+loop+counters
+//
+void test_float_condition() {
+ for (float x = 0.1f; x <= 1.0f; x += 0.1f) {} // expected-warning{{Variable 'x' with floating point type 'float'}}
+ for (float x = 100000001.0f; x <= 100000010.0f; x += 1.0f) {} // expected-warning{{Variable 'x' with floating point type 'float'}}
+ for (float x = 100000001.0f; x <= 100000010.0f; x++ ) {} // expected-warning{{Variable 'x' with floating point type 'float'}}
+ for (double x = 100000001.0; x <= 100000010.0; x++ ) {} // expected-warning{{Variable 'x' with floating point type 'double'}}
+ for (double x = 100000001.0; ((x)) <= 100000010.0; ((x))++ ) {} // expected-warning{{Variable 'x' with floating point type 'double'}}
+
+ for (double x = 100000001.0; 100000010.0 >= x; x = x + 1.0 ) {} // expected-warning{{Variable 'x' with floating point type 'double'}}
+
+ int i = 0;
+ for (double x = 100000001.0; ((x)) <= 100000010.0; ((x))++, ++i ) {} // expected-warning{{Variable 'x' with floating point type 'double'}}
+
+ typedef float FooType;
+ for (FooType x = 100000001.0f; x <= 100000010.0f; x++ ) {} // expected-warning{{Variable 'x' with floating point type 'FooType'}}
+}
+
+// <rdar://problem/6335715> rule request: gets() buffer overflow
+// Part of recommendation: 300-BSI (buildsecurityin.us-cert.gov)
+char* gets(char *buf);
+
+void test_gets() {
+ char buff[1024];
+ gets(buff); // expected-warning{{Call to function 'gets' is extremely insecure as it can always result in a buffer overflow}}
+}
+
+// <rdar://problem/6337132> CWE-273: Failure to Check Whether Privileges Were
+// Dropped Successfully
+typedef unsigned int __uint32_t;
+typedef __uint32_t __darwin_uid_t;
+typedef __uint32_t __darwin_gid_t;
+typedef __darwin_uid_t uid_t;
+typedef __darwin_gid_t gid_t;
+int setuid(uid_t);
+int setregid(gid_t, gid_t);
+int setreuid(uid_t, uid_t);
+extern void check(int);
+
+void test_setuid()
+{
+ setuid(2); // expected-warning{{The return value from the call to 'setuid' is not checked. If an error occurs in 'setuid', the following code may execute with unexpected privileges}}
+ setuid(0); // expected-warning{{The return value from the call to 'setuid' is not checked. If an error occurs in 'setuid', the following code may execute with unexpected privileges}}
+ if (setuid (2) != 0)
+ abort();
+
+ // Currently the 'setuid' check is not flow-sensitive, and only looks
+ // at whether the function was called in a compound statement. This
+ // will lead to false negatives, but there should be no false positives.
+ int t = setuid(2); // no-warning
+ (void)setuid (2); // no-warning
+
+ check(setuid (2)); // no-warning
+
+ setreuid(2,2); // expected-warning{{The return value from the call to 'setreuid' is not checked. If an error occurs in 'setreuid', the following code may execute with unexpected privileges}}
+ setregid(2,2); // expected-warning{{The return value from the call to 'setregid' is not checked. If an error occurs in 'setregid', the following code may execute with unexpected privileges}}
+}
+
+// <rdar://problem/6337100> CWE-338: Use of cryptographically weak prng
+int rand(void);
+double drand48(void);
+double erand48(unsigned short[3]);
+long jrand48(unsigned short[3]);
+void lcong48(unsigned short[7]);
+long lrand48(void);
+long mrand48(void);
+long nrand48(unsigned short[3]);
+long random(void);
+int rand_r(unsigned *);
+
+void test_rand()
+{
+ unsigned short a[7];
+ unsigned b;
+
+ rand(); // expected-warning{{Function 'rand' is obsolete because it implements a poor random number generator. Use 'arc4random' instead}}
+ drand48(); // expected-warning{{Function 'drand48' is obsolete because it implements a poor random number generator. Use 'arc4random' instead}}
+ erand48(a); // expected-warning{{Function 'erand48' is obsolete because it implements a poor random number generator. Use 'arc4random' instead}}
+ jrand48(a); // expected-warning{{Function 'jrand48' is obsolete because it implements a poor random number generator. Use 'arc4random' instead}}
+ lcong48(a); // expected-warning{{Function 'lcong48' is obsolete because it implements a poor random number generator. Use 'arc4random' instead}}
+ lrand48(); // expected-warning{{Function 'lrand48' is obsolete because it implements a poor random number generator. Use 'arc4random' instead}}
+ mrand48(); // expected-warning{{Function 'mrand48' is obsolete because it implements a poor random number generator. Use 'arc4random' instead}}
+ nrand48(a); // expected-warning{{Function 'nrand48' is obsolete because it implements a poor random number generator. Use 'arc4random' instead}}
+ rand_r(&b); // expected-warning{{Function 'rand_r' is obsolete because it implements a poor random number generator. Use 'arc4random' instead}}
+ random(); // expected-warning{{The 'random' function produces a sequence of values that an adversary may be able to predict. Use 'arc4random' instead}}
+}
diff --git a/test/Analysis/uninit-vals-ps-region.c b/test/Analysis/uninit-vals-ps-region.c
index 32f787d..1561f11 100644
--- a/test/Analysis/uninit-vals-ps-region.c
+++ b/test/Analysis/uninit-vals-ps-region.c
@@ -15,3 +15,21 @@ void f4() {
if (global.data == 0) // When the true branch is feasible 'a = 3'.
g(a); // no-warning
}
+
+
+// Test uninitialized value due to part of the structure being uninitialized.
+struct TestUninit { int x; int y; };
+struct TestUninit test_uninit_aux();
+void test_uninit_pos() {
+ struct TestUninit v1 = { 0, 0 };
+ struct TestUninit v2 = test_uninit_aux();
+ int z;
+ v1.y = z;
+ test_unit_aux2(v2.x + v1.y); // expected-warning{{The right operand of '+' is a garbage value}}
+}
+void test_uninit_neg() {
+ struct TestUninit v1 = { 0, 0 };
+ struct TestUninit v2 = test_uninit_aux();
+ test_unit_aux2(v2.x + v1.y); // no-warning
+}
+
diff --git a/test/Analysis/uninit-vals-ps.c b/test/Analysis/uninit-vals-ps.c
index 4177126..759c7ed 100644
--- a/test/Analysis/uninit-vals-ps.c
+++ b/test/Analysis/uninit-vals-ps.c
@@ -1,4 +1,4 @@
-// RUN: clang-cc -analyze -checker-cfref -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -verify %s &&
// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -verify %s
struct FPRec {
@@ -22,7 +22,7 @@ int f2() {
int x;
- if (x+1) // expected-warning{{Branch}}
+ if (x+1) // expected-warning{{The left operand of '+' is a garbage value}}
return 1;
return 2;
@@ -31,13 +31,13 @@ int f2() {
int f2_b() {
int x;
- return ((x+1)+2+((x))) + 1 ? 1 : 2; // expected-warning{{Branch}}
+ return ((1+x)+2+((x))) + 1 ? 1 : 2; // expected-warning{{The right operand of '+' is a garbage value}}
}
int f3(void) {
int i;
int *p = &i;
- if (*p > 0) // expected-warning{{Branch condition evaluates to an uninitialized value}}
+ if (*p > 0) // expected-warning{{The left operand of '>' is a garbage value}}
return 0;
else
return 1;
@@ -61,7 +61,7 @@ int f5(void) {
int ret_uninit() {
int i;
int *p = &i;
- return *p; // expected-warning{{Uninitialized or undefined value returned to caller.}}
+ return *p; // expected-warning{{Undefined or garbage value returned to caller}}
}
// <rdar://problem/6451816>
@@ -83,3 +83,43 @@ CFStringRef rdar_6451816(CFNumberRef nr) {
return CFStringConvertEncodingToIANACharSetName(encoding); // no-warning
}
+// PR 4630 - false warning with nonnull attribute
+// This false positive (due to a regression) caused the analyzer to falsely
+// flag a "return of uninitialized value" warning in the first branch due to
+// the nonnull attribute.
+void pr_4630_aux(char *x, int *y) __attribute__ ((nonnull (1)));
+void pr_4630_aux_2(char *x, int *y);
+int pr_4630(char *a, int y) {
+ int x;
+ if (y) {
+ pr_4630_aux(a, &x);
+ return x; // no-warning
+ }
+ else {
+ pr_4630_aux_2(a, &x);
+ return x; // no-warning
+ }
+}
+
+// PR 4631 - False positive with union initializer
+// Previously the analyzer didn't examine the compound initializers of unions,
+// resulting in some false positives for initializers with side-effects.
+union u_4631 { int a; };
+struct s_4631 { int a; };
+int pr4631_f2(int *p);
+int pr4631_f3(void *q);
+int pr4631_f1(void)
+{
+ int x;
+ union u_4631 m = { pr4631_f2(&x) };
+ pr4631_f3(&m); // tell analyzer that we use m
+ return x; // no-warning
+}
+int pr4631_f1_b(void)
+{
+ int x;
+ struct s_4631 m = { pr4631_f2(&x) };
+ pr4631_f3(&m); // tell analyzer that we use m
+ return x; // no-warning
+}
+
diff --git a/test/Analysis/uninit-vals.c b/test/Analysis/uninit-vals.c
index d69250b..8428ca4 100644
--- a/test/Analysis/uninit-vals.c
+++ b/test/Analysis/uninit-vals.c
@@ -23,7 +23,7 @@ int f4(int x) {
return y; // expected-warning {{use of uninitialized variable}}
}
-int f5() {
+void f5() {
int a;
a = 30; // no-warning
}
diff --git a/test/Analysis/unions-region.m b/test/Analysis/unions-region.m
new file mode 100644
index 0000000..be4f185
--- /dev/null
+++ b/test/Analysis/unions-region.m
@@ -0,0 +1,41 @@
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=range %s -verify
+
+//===-- unions-region.m ---------------------------------------------------===//
+//
+// This file tests the analyzer's reasoning about unions.
+//
+//===----------------------------------------------------------------------===//
+
+// [testA] When using RegionStore, this test case previously had a
+// false positive of a 'pass-by-value argument is uninitialized'
+// warning at the call to 'testA_aux' and 'testA_aux_2'.
+union u_testA {
+ unsigned i;
+ float f;
+};
+
+float testA(float f) {
+ int testA_aux(unsigned x);
+ int testA_aux_2(union u_testA z);
+
+ union u_testA swap;
+ swap.f = f;
+
+ if (testA_aux(swap.i)) // no-warning
+ swap.i = ((swap.i & 0xffff0000) >> 16) | ((swap.i & 0x0000fffff) << 16);
+
+ testA_aux_2(swap); // no-warning
+
+ return swap.f;
+}
+
+// [testB] When using RegionStore, this test case previously had a
+// false positive of a 'pass-by-value argument is uninitialized'
+// warning at the call to 'testB_aux'.
+void testB(int i) {
+ void testB_aux(short z);
+ union { short x[2]; unsigned y; } val;
+ val.y = 10;
+ testB_aux(val.x[1]); // no-warning
+}
+
diff --git a/test/Analysis/unused-ivars.m b/test/Analysis/unused-ivars.m
index 632b395..aacd44e 100644
--- a/test/Analysis/unused-ivars.m
+++ b/test/Analysis/unused-ivars.m
@@ -1,10 +1,45 @@
-// RUN: clang-cc -analyze -warn-objc-unused-ivars %s -verify
+// RUN: clang-cc -triple x86_64-apple-darwin10 -analyze -warn-objc-unused-ivars %s -verify
-@interface A
-{
- @private int x; // expected-warning {{Instance variable 'x' in class 'A' is never used}}
+//===--- BEGIN: Delta-debugging reduced headers. --------------------------===//
+
+@protocol NSObject
+- (id)retain;
+- (oneway void)release;
+@end
+@interface NSObject <NSObject> {}
+- (id)init;
++ (id)alloc;
+@end
+
+//===--- END: Delta-debugging reduced headers. ----------------------------===//
+
+// This test case tests the basic functionality of the unused ivar test.
+@interface TestA {
+@private
+ int x; // expected-warning {{Instance variable 'x' in class 'TestA' is never used}}
}
@end
+@implementation TestA @end
-@implementation A @end
+// This test case tests whether the unused ivar check handles blocks that
+// reference an instance variable. (<rdar://problem/7075531>)
+@interface TestB : NSObject {
+@private
+ id _ivar; // no-warning
+}
+@property (readwrite,retain) id ivar;
+@end
+
+@implementation TestB
+- (id)ivar {
+ __attribute__((__blocks__(byref))) id value = ((void*)0);
+ void (^b)() = ^{ value = _ivar; };
+ b();
+ return value;
+}
+- (void)setIvar:(id)newValue {
+ void (^b)() = ^{ [_ivar release]; _ivar = [newValue retain]; };
+ b();
+}
+@end
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index d5e2327..2a7f132 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -1,5 +1,6 @@
set(CLANG_TEST_DIRECTORIES
"Analysis"
+ "CodeCompletion"
"CodeGen"
"CodeGenCXX"
"CodeGenObjC"
@@ -24,37 +25,59 @@ set(CLANG_TEST_DIRECTORIES
include(FindPythonInterp)
if(PYTHONINTERP_FOUND)
get_target_property(LLVM_TOOLS_PATH clang RUNTIME_OUTPUT_DIRECTORY)
- set(TESTING_EXTRA_PATHS
- "${LLVM_TOOLS_PATH}/${CMAKE_CFG_INTDIR}:${LLVM_SOURCE_DIR}/test/Scripts")
+ get_target_property(LLVM_LIBS_PATH clang LIBRARY_OUTPUT_DIRECTORY)
set(CLANG_TEST_EXTRA_ARGS)
if (MSVC OR XCODE)
set(CLANG_TEST_EXTRA_ARGS "--no-progress-bar")
endif()
- set(all_testdirs)
- foreach(testdir ${CLANG_TEST_DIRECTORIES})
- add_custom_target(clang-test-${testdir}
- ${PYTHON_EXECUTABLE}
- ${LLVM_SOURCE_DIR}/tools/clang/utils/test/MultiTestRunner.py
- "--path=${TESTING_EXTRA_PATHS}"
- -s ${CLANG_TEST_EXTRA_ARGS}
- --clang=${LLVM_TOOLS_PATH}/${CMAKE_CFG_INTDIR}/clang
- --clang-cc=${LLVM_TOOLS_PATH}/${CMAKE_CFG_INTDIR}/clang-cc
- ${CMAKE_CURRENT_SOURCE_DIR}/${testdir}/
- WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
- COMMENT "Running Clang regression tests in ${testdir}")
- list(APPEND all_testdirs ${CMAKE_CURRENT_SOURCE_DIR}/${testdir}/)
+ foreach(testdir ${CLANG_TEST_DIRECTORIES})
+ add_custom_target(clang-test-${testdir}
+ COMMAND sed -e "s#\@LLVM_SOURCE_DIR\@#${LLVM_MAIN_SRC_DIR}#"
+ -e "s#\@LLVM_BINARY_DIR\@#${LLVM_BINARY_DIR}#"
+ -e "s#\@LLVM_TOOLS_DIR\@#${LLVM_TOOLS_PATH}/${CMAKE_CFG_INTDIR}#"
+ -e "s#\@LLVM_LIBS_DIR\@#${LLVM_LIBS_PATH}/${CMAKE_CFG_INTDIR}#"
+ -e "s#\@CLANG_SOURCE_DIR\@#${CMAKE_CURRENT_SOURCE_DIR}/..#"
+ -e "s#\@CLANG_BINARY_DIR\@#${CMAKE_CURRENT_BINARY_DIR}/..#"
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in >
+ ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
+ COMMAND ${PYTHON_EXECUTABLE}
+ ${LLVM_SOURCE_DIR}/utils/lit/lit.py
+ -sv ${CLANG_TEST_EXTRA_ARGS}
+ ${CMAKE_CURRENT_BINARY_DIR}/${testdir}
+ DEPENDS clang clang-cc index-test
+ COMMENT "Running Clang regression tests in ${testdir}")
endforeach()
add_custom_target(clang-test
- ${PYTHON_EXECUTABLE}
- ${LLVM_SOURCE_DIR}/tools/clang/utils/test/MultiTestRunner.py
- "--path=${TESTING_EXTRA_PATHS}"
- -s ${CLANG_TEST_EXTRA_ARGS}
- --clang=${LLVM_TOOLS_PATH}/${CMAKE_CFG_INTDIR}/clang
- --clang-cc=${LLVM_TOOLS_PATH}/${CMAKE_CFG_INTDIR}/clang-cc
- ${all_testdirs}
- WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
- DEPENDS clang clang-cc index-test
- COMMENT "Running Clang regression tests")
+ COMMAND sed -e "s#\@LLVM_SOURCE_DIR\@#${LLVM_MAIN_SRC_DIR}#"
+ -e "s#\@LLVM_BINARY_DIR\@#${LLVM_BINARY_DIR}#"
+ -e "s#\@LLVM_TOOLS_DIR\@#${LLVM_TOOLS_PATH}/${CMAKE_CFG_INTDIR}#"
+ -e "s#\@LLVM_LIBS_DIR\@#${LLVM_LIBS_PATH}/${CMAKE_CFG_INTDIR}#"
+ -e "s#\@CLANG_SOURCE_DIR\@#${CMAKE_CURRENT_SOURCE_DIR}/..#"
+ -e "s#\@CLANG_BINARY_DIR\@#${CMAKE_CURRENT_BINARY_DIR}/..#"
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in >
+ ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
+ COMMAND ${PYTHON_EXECUTABLE}
+ ${LLVM_SOURCE_DIR}/utils/lit/lit.py
+ -sv ${CLANG_TEST_EXTRA_ARGS}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ DEPENDS clang clang-cc index-test
+ COMMENT "Running Clang regression tests")
+
+ add_custom_target(clang-c++tests
+ COMMAND sed -e "s#\@LLVM_SOURCE_DIR\@#${LLVM_MAIN_SRC_DIR}#"
+ -e "s#\@LLVM_BINARY_DIR\@#${LLVM_BINARY_DIR}#"
+ -e "s#\@LLVM_TOOLS_DIR\@#${LLVM_TOOLS_PATH}/${CMAKE_CFG_INTDIR}#"
+ -e "s#\@LLVM_LIBS_DIR\@#${LLVM_LIBS_PATH}/${CMAKE_CFG_INTDIR}#"
+ -e "s#\@CLANG_SOURCE_DIR\@#${CMAKE_CURRENT_SOURCE_DIR}/..#"
+ -e "s#\@CLANG_BINARY_DIR\@#${CMAKE_CURRENT_BINARY_DIR}/..#"
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in >
+ ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
+ COMMAND ${PYTHON_EXECUTABLE}
+ ${LLVM_SOURCE_DIR}/utils/lit/lit.py
+ -sv ${CLANG_TEST_EXTRA_ARGS}
+ ${CMAKE_CURRENT_SOURCE_DIR}/../utils/C++Tests
+ DEPENDS clang clang-cc index-test
+ COMMENT "Running Clang regression tests")
endif()
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-template-id.cpp b/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-template-id.cpp
new file mode 100644
index 0000000..e2c76f9
--- /dev/null
+++ b/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-template-id.cpp
@@ -0,0 +1,27 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+namespace N1 {
+ struct X { };
+ int& f(void*);
+}
+
+namespace N2 {
+ template<typename T> struct Y { };
+}
+
+namespace N3 {
+ void test() {
+ int &ir = f((N2::Y<N1::X>*)0);
+ }
+}
+
+int g(void *);
+long g(N1::X);
+
+namespace N1 {
+ void h(int (*)(void *));
+}
+
+void test() {
+ h((&g));
+}
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp b/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp
new file mode 100644
index 0000000..677df828
--- /dev/null
+++ b/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp
@@ -0,0 +1,73 @@
+// 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);
+}
+
+struct Z { };
+int& f(Z);
+
+namespace O {
+ char &f();
+ void test_global_scope_adl(Z z) {
+ {
+ int& ir = f(z);
+ }
+ }
+}
+
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp b/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp
new file mode 100644
index 0000000..8f0bed8
--- /dev/null
+++ b/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp
@@ -0,0 +1,42 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+namespace A {
+ class A {
+ friend void func(A);
+ friend A operator+(A,A);
+ };
+}
+
+namespace B {
+ class B {
+ static void func(B);
+ };
+ B operator+(B,B);
+}
+
+namespace D {
+ class D {};
+}
+
+namespace C {
+ class C {};
+ void func(C);
+ C operator+(C,C);
+ D::D operator+(D::D,D::D);
+}
+
+namespace D {
+ using namespace C;
+}
+
+namespace Test {
+ void test() {
+ func(A::A());
+ func(B::B()); // expected-error {{ no matching function for call to 'func' }}
+ func(C::C());
+ A::A() + A::A();
+ B::B() + B::B();
+ C::C() + C::C();
+ D::D() + D::D(); // expected-error {{ invalid operands to binary expression ('D::D' and 'D::D') }}
+ }
+}
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.elab/templateid.cpp b/test/CXX/basic/basic.lookup/basic.lookup.elab/templateid.cpp
new file mode 100644
index 0000000..cb9d942
--- /dev/null
+++ b/test/CXX/basic/basic.lookup/basic.lookup.elab/templateid.cpp
@@ -0,0 +1,18 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// elaborated-type-specifier:
+// class-key '::'? nested-name-specifier? 'template'? simple-template-id
+// Tests that this form is accepted by the compiler but does not follow
+// the elaborated lookup rules of [basic.lookup.elab].
+
+template <typename> class Ident {}; // expected-note {{previous use is here}}
+
+namespace A {
+ template <typename> void Ident();
+
+ class Ident<int> AIdent; // expected-error {{refers to a function template}}
+ class ::Ident<int> AnotherIdent;
+}
+
+class Ident<int> GlobalIdent;
+union Ident<int> GlobalIdent; // expected-error {{ tag type that does not match }}
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p2.cpp b/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p2.cpp
new file mode 100644
index 0000000..b32948b
--- /dev/null
+++ b/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p2.cpp
@@ -0,0 +1,65 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+namespace Ints {
+ int zero = 0; // expected-note {{candidate found by name lookup is 'Ints::zero'}}
+ void f(int); // expected-note 3 {{candidate function}}
+ void g(int);
+}
+
+namespace Floats {
+ float zero = 0.0f; // expected-note {{candidate found by name lookup is 'Floats::zero'}}
+ void f(float); // expected-note 3 {{candidate function}}
+ void g(float);
+}
+
+namespace Numbers {
+ using namespace Ints;
+ using namespace Floats;
+}
+
+void test() {
+ int i = Ints::zero;
+ Ints::f(i);
+
+ float f = Floats::zero;
+ Floats::f(f);
+
+ double n = Numbers::zero; // expected-error {{reference to 'zero' is ambiguous}}
+ Numbers::f(n); // expected-error{{call to 'f' is ambiguous}}
+ Numbers::f(i);
+ Numbers::f(f);
+}
+
+namespace Numbers {
+ struct Number {
+ explicit Number(double d) : d(d) {}
+ double d;
+ };
+ Number zero(0.0f);
+ void g(Number);
+}
+
+void test2() {
+ Numbers::Number n = Numbers::zero;
+ Numbers::f(n); // expected-error {{no matching function for call to 'f'}}
+ Numbers::g(n);
+}
+
+namespace Numbers2 {
+ using Numbers::f;
+ using Numbers::g;
+}
+
+void test3() {
+ Numbers::Number n = Numbers::zero;
+ Numbers2::f(n); // expected-error {{no matching function for call to 'f'}}
+ Numbers2::g(n);
+
+ int i = Ints::zero;
+ Numbers2::f(i);
+ Numbers2::g(i); // expected-error {{incompatible type passing 'int'}}
+
+ float f = Floats::zero;
+ Numbers2::f(f);
+ Numbers2::g(f); // expected-error {{incompatible type passing 'float'}}
+}
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p3.cpp b/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p3.cpp
new file mode 100644
index 0000000..7a51a7b
--- /dev/null
+++ b/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p3.cpp
@@ -0,0 +1,41 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// This is basically paraphrased from the standard.
+
+namespace Root {
+ int i = 0;
+ void f();
+}
+
+namespace A {
+ using namespace Root;
+}
+
+namespace B {
+ using namespace Root;
+}
+
+namespace AB {
+ using namespace A;
+ using namespace B;
+}
+
+void test() {
+ if (AB::i)
+ AB::f();
+}
+
+namespace C {
+ using Root::i;
+ using Root::f;
+}
+
+namespace AC {
+ using namespace A;
+ using namespace C;
+}
+
+void test2() {
+ if (AC::i)
+ AC::f();
+}
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p4.cpp b/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p4.cpp
new file mode 100644
index 0000000..2c0ce80
--- /dev/null
+++ b/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p4.cpp
@@ -0,0 +1,25 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+namespace A {
+ int a;
+}
+
+namespace C {
+ int c;
+}
+
+namespace B {
+ using namespace C;
+ int b;
+}
+
+namespace C {
+ using namespace B;
+ using namespace A;
+}
+
+void test() {
+ C::a++;
+ C::b++;
+ C::c++;
+}
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p5.cpp b/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p5.cpp
new file mode 100644
index 0000000..78af521
--- /dev/null
+++ b/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p5.cpp
@@ -0,0 +1,35 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+namespace A {
+ struct x {}; // expected-note {{candidate found by name lookup is 'A::x'}}
+ int x; // expected-note {{candidate found by name lookup is 'A::x'}}
+
+ struct y {}; // expected-note {{type declaration hidden}}
+
+ struct z;
+ void z(float);
+}
+
+namespace B {
+ struct x {}; // expected-note {{candidate found by name lookup is 'B::x'}}
+ float x; // expected-note {{candidate found by name lookup is 'B::x'}}
+
+ float y; // expected-note {{declaration hides type}}
+
+ void z(int);
+}
+
+namespace AB {
+ using namespace A;
+ using namespace B;
+}
+
+void test() {
+ struct AB::x foo; // expected-error {{reference to 'x' is ambiguous}}
+ int i = AB::x; // expected-error {{reference to 'x' is ambiguous}}
+
+ struct AB::y bar;
+ float f = AB::y; // expected-error {{a type named 'y' is hidden by a declaration in a different namespace}}
+ AB::z(i);
+ AB::z(f);
+}
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.unqual/p3.cpp b/test/CXX/basic/basic.lookup/basic.lookup.unqual/p3.cpp
index 1daf0dd..7fd1b53 100644
--- a/test/CXX/basic/basic.lookup/basic.lookup.unqual/p3.cpp
+++ b/test/CXX/basic/basic.lookup/basic.lookup.unqual/p3.cpp
@@ -1,9 +1,7 @@
// RUN: clang-cc -fsyntax-only -verify %s
-// XFAIL
-// FIXME: This part is here to demonstrate the failure in looking up 'f', it can
-// be removed once the whole test passes.
typedef int f;
+
namespace N0 {
struct A {
friend void f();
diff --git a/test/CXX/basic/basic.start/basic.start.main/p2a.cpp b/test/CXX/basic/basic.start/basic.start.main/p2a.cpp
new file mode 100644
index 0000000..a6a7587
--- /dev/null
+++ b/test/CXX/basic/basic.start/basic.start.main/p2a.cpp
@@ -0,0 +1,8 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+typedef int Int;
+typedef char Char;
+typedef Char* Carp;
+
+Int main(Int argc, Carp argv[]) {
+}
diff --git a/test/CXX/basic/basic.start/basic.start.main/p2b.cpp b/test/CXX/basic/basic.start/basic.start.main/p2b.cpp
new file mode 100644
index 0000000..caecf60
--- /dev/null
+++ b/test/CXX/basic/basic.start/basic.start.main/p2b.cpp
@@ -0,0 +1,8 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+typedef int Int;
+typedef char Char;
+typedef Char* Carp;
+
+Int main(Int argc, Carp argv[], Char *env[]) {
+}
diff --git a/test/CXX/basic/basic.start/basic.start.main/p2c.cpp b/test/CXX/basic/basic.start/basic.start.main/p2c.cpp
new file mode 100644
index 0000000..8587d8c
--- /dev/null
+++ b/test/CXX/basic/basic.start/basic.start.main/p2c.cpp
@@ -0,0 +1,4 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+int main() {
+}
diff --git a/test/CXX/basic/basic.start/basic.start.main/p2d.cpp b/test/CXX/basic/basic.start/basic.start.main/p2d.cpp
new file mode 100644
index 0000000..777b5ce
--- /dev/null
+++ b/test/CXX/basic/basic.start/basic.start.main/p2d.cpp
@@ -0,0 +1,4 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+static int main() { // expected-error {{'main' is not allowed to be declared static}}
+}
diff --git a/test/CXX/basic/basic.start/basic.start.main/p2e.cpp b/test/CXX/basic/basic.start/basic.start.main/p2e.cpp
new file mode 100644
index 0000000..087cf77
--- /dev/null
+++ b/test/CXX/basic/basic.start/basic.start.main/p2e.cpp
@@ -0,0 +1,4 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+inline int main() { // expected-error {{'main' is not allowed to be declared inline}}
+}
diff --git a/test/CXX/basic/basic.start/basic.start.main/p2f.cpp b/test/CXX/basic/basic.start/basic.start.main/p2f.cpp
new file mode 100644
index 0000000..b7845b1
--- /dev/null
+++ b/test/CXX/basic/basic.start/basic.start.main/p2f.cpp
@@ -0,0 +1,7 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+void // expected-error {{error: 'main' must return 'int'}}
+main( // expected-error {{error: first argument of 'main' should be of type 'int'}}
+ float a
+) {
+}
diff --git a/test/CXX/basic/basic.start/basic.start.main/p2g.cpp b/test/CXX/basic/basic.start/basic.start.main/p2g.cpp
new file mode 100644
index 0000000..4cedcdb
--- /dev/null
+++ b/test/CXX/basic/basic.start/basic.start.main/p2g.cpp
@@ -0,0 +1,4 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+int main(int argc, const char* const* argv) {
+}
diff --git a/test/CXX/basic/basic.stc/basic.stc.dynamic/p2-nodef.cpp b/test/CXX/basic/basic.stc/basic.stc.dynamic/p2-nodef.cpp
new file mode 100644
index 0000000..ff653d5
--- /dev/null
+++ b/test/CXX/basic/basic.stc/basic.stc.dynamic/p2-nodef.cpp
@@ -0,0 +1,7 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+int *use_new(int N) {
+ return new int [N];
+}
+
+int std = 17;
diff --git a/test/CXX/basic/basic.stc/basic.stc.dynamic/p2.cpp b/test/CXX/basic/basic.stc/basic.stc.dynamic/p2.cpp
new file mode 100644
index 0000000..f3499e4
--- /dev/null
+++ b/test/CXX/basic/basic.stc/basic.stc.dynamic/p2.cpp
@@ -0,0 +1,25 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+int *use_new(int N) {
+ if (N == 1)
+ return new int;
+
+ return new int [N];
+}
+
+void use_delete(int* ip, int N) {
+ if (N == 1)
+ delete ip;
+ else
+ delete [] ip;
+}
+
+namespace std {
+ class bad_alloc { };
+
+ typedef __SIZE_TYPE__ size_t;
+}
+
+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();
diff --git a/test/CXX/class.derived/class.virtual/p12.cpp b/test/CXX/class.derived/class.virtual/p12.cpp
new file mode 100644
index 0000000..b5974a0
--- /dev/null
+++ b/test/CXX/class.derived/class.virtual/p12.cpp
@@ -0,0 +1,19 @@
+// RUN: clang-cc -ast-print %s | FileCheck %s
+
+// CHECK: test12_A::foo()
+struct test12_A {
+ virtual void foo();
+
+ void bar() {
+ test12_A::foo();
+ }
+};
+
+// CHECK: xp->test24_B::wibble()
+struct test24_B {
+ virtual void wibble();
+};
+
+void foo(test24_B *xp) {
+ xp->test24_B::wibble();
+}
diff --git a/test/CXX/class/class.friend/p1-ambiguous.cpp b/test/CXX/class/class.friend/p1-ambiguous.cpp
new file mode 100644
index 0000000..a02bc53
--- /dev/null
+++ b/test/CXX/class/class.friend/p1-ambiguous.cpp
@@ -0,0 +1,37 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// Make sure that friend declarations don't introduce ambiguous
+// declarations.
+
+// Test case courtesy of Shantonu Sen.
+// Bug 4784.
+
+class foo;
+
+extern "C" {
+ int c_func(foo *a);
+};
+int cpp_func(foo *a);
+
+class foo {
+public:
+ friend int c_func(foo *a);
+ friend int cpp_func(foo *a);
+ int caller();
+private:
+ int x;
+};
+
+int c_func(foo *a) {
+ return a->x;
+}
+
+int cpp_func(foo *a) {
+ return a->x;
+}
+
+int foo::caller() {
+ c_func(this);
+ cpp_func(this);
+ return 0;
+}
diff --git a/test/CXX/class/class.friend/p1.cpp b/test/CXX/class/class.friend/p1.cpp
new file mode 100644
index 0000000..7065a7e
--- /dev/null
+++ b/test/CXX/class/class.friend/p1.cpp
@@ -0,0 +1,76 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+struct Outer {
+ struct Inner {
+ int intfield;
+ };
+};
+
+struct Base {
+ void base_member();
+
+ typedef int Int;
+ Int typedeffed_member();
+};
+
+struct Derived : public Base {
+};
+
+int myglobal;
+
+void global_function();
+extern "C" {
+ void global_c_function();
+}
+
+class A {
+ class AInner {
+ };
+
+ friend class PreDeclared;
+ friend class Outer::Inner;
+ friend int Outer::Inner::intfield; // expected-error {{ friends can only be classes or functions }}
+ friend int Outer::Inner::missing_field; //expected-error {{ friends can only be classes or functions }}
+ friend int myoperation(float); // okay
+ friend int myglobal; // expected-error {{ friends can only be classes or functions }}
+
+ friend void global_function();
+ friend void global_c_function();
+
+ friend class UndeclaredSoFar;
+ UndeclaredSoFar x; // expected-error {{ unknown type name 'UndeclaredSoFar' }}
+
+ void a_member();
+ friend void A::a_member(); // expected-error {{ friends cannot be members of the declaring class }}
+ friend void a_member(); // okay (because we ignore class scopes when looking up friends)
+ friend class A::AInner; // this is okay as an extension
+ friend class AInner; // okay, refers to ::AInner
+
+ friend void Derived::missing_member(); // expected-error {{ no function named 'missing_member' with type 'void ()' was found in the specified scope }}
+
+ friend void Derived::base_member(); // expected-error {{ no function named 'base_member' with type 'void ()' was found in the specified scope }}
+
+ friend int Base::typedeffed_member(); // okay: should look through typedef
+
+ // These test that the friend is properly not being treated as a
+ // member function.
+ friend A operator|(const A& l, const A& r); // okay
+ friend A operator|(const A& r); // expected-error {{ overloaded 'operator|' must be a binary operator (has 1 parameter) }}
+
+ friend operator bool() const; // expected-error {{ must use a qualified name when declaring a conversion operator as a friend }}
+
+ typedef void ftypedef();
+ friend ftypedef typedeffed_function; // okay (because it's not declared as a member)
+
+ class facet;
+ friend class facet; // should not assert
+ class facet {};
+};
+
+A::UndeclaredSoFar y; // expected-error {{no type named 'UndeclaredSoFar' in 'class A'}}
+
+class PreDeclared;
+
+int myoperation(float f) {
+ return (int) f;
+}
diff --git a/test/CXX/class/class.friend/p2.cpp b/test/CXX/class/class.friend/p2.cpp
new file mode 100644
index 0000000..98be204
--- /dev/null
+++ b/test/CXX/class/class.friend/p2.cpp
@@ -0,0 +1,10 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+struct B0;
+
+class A {
+ friend class B {}; // expected-error {{cannot define a type in a friend declaration}}
+ friend int; // expected-error {{friends can only be classes or functions}}
+ friend B0; // expected-error {{must specify 'struct' to befriend}}
+ friend class C; // okay
+};
diff --git a/test/CXX/class/class.friend/p6.cpp b/test/CXX/class/class.friend/p6.cpp
new file mode 100644
index 0000000..2e8153c
--- /dev/null
+++ b/test/CXX/class/class.friend/p6.cpp
@@ -0,0 +1,10 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+class A {
+ friend static class B; // expected-error {{'static' is invalid in friend declarations}}
+ friend extern class C; // expected-error {{'extern' is invalid in friend declarations}}
+ friend auto class D; // expected-error {{'auto' is invalid in friend declarations}}
+ friend register class E; // expected-error {{'register' is invalid in friend declarations}}
+ friend mutable class F; // expected-error {{'mutable' is invalid in friend declarations}}
+ friend typedef class G; // expected-error {{'typedef' is invalid in friend declarations}}
+};
diff --git a/test/CXX/class/class.local/p3.cpp b/test/CXX/class/class.local/p3.cpp
index d888a6d..9c625d1 100644
--- a/test/CXX/class/class.local/p3.cpp
+++ b/test/CXX/class/class.local/p3.cpp
@@ -27,4 +27,4 @@ void f3(int a) { // expected-note{{'a' declared here}}
int f() { return a; } // expected-error{{reference to local variable 'a' declared in enclosed function 'f3'}}
};
};
-} \ No newline at end of file
+}
diff --git a/test/CXX/class/class.local/p4.cpp b/test/CXX/class/class.local/p4.cpp
index 40702ad..f2432ec 100644
--- a/test/CXX/class/class.local/p4.cpp
+++ b/test/CXX/class/class.local/p4.cpp
@@ -7,4 +7,4 @@ void f() {
static void f() { }
};
-} \ No newline at end of file
+}
diff --git a/test/CXX/class/class.nest/p1.cpp b/test/CXX/class/class.nest/p1.cpp
new file mode 100644
index 0000000..bbc49f9
--- /dev/null
+++ b/test/CXX/class/class.nest/p1.cpp
@@ -0,0 +1,14 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+class Outer {
+ int x;
+ static int sx;
+
+ // C++0x will likely relax this rule in this specific case, but
+ // we'll still need to enforce it in C++03 mode. See N2253 (or
+ // successor).
+ class Inner {
+ static char a[sizeof(x)]; // expected-error {{ invalid use of nonstatic data member 'x' }}
+ static char b[sizeof(sx)]; // okay
+ };
+};
diff --git a/test/CXX/class/class.nested.type/p1.cpp b/test/CXX/class/class.nested.type/p1.cpp
index 33bf4b4..61ccd28 100644
--- a/test/CXX/class/class.nested.type/p1.cpp
+++ b/test/CXX/class/class.nested.type/p1.cpp
@@ -1,3 +1,5 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
class X {
public:
typedef int I;
@@ -8,4 +10,4 @@ public:
I b; // expected-error{{unknown type name 'I'}}
Y c; // expected-error{{unknown type name 'Y'}}
X::Y d;
-X::I e; \ No newline at end of file
+X::I e;
diff --git a/test/CXX/class/class.union/p1.cpp b/test/CXX/class/class.union/p1.cpp
new file mode 100644
index 0000000..15c2634
--- /dev/null
+++ b/test/CXX/class/class.union/p1.cpp
@@ -0,0 +1,105 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+void abort() __attribute__((noreturn));
+
+class Okay {
+ int a_;
+};
+
+class Virtual {
+ virtual void foo() { abort(); } // expected-note 3 {{because type 'class Virtual' has a virtual member function}}
+};
+
+class VirtualBase : virtual Okay { // expected-note 3 {{because type 'class VirtualBase' has a virtual base class}}
+};
+
+class Ctor {
+ Ctor() { abort(); } // expected-note 3 {{because type 'class Ctor' has a user-declared constructor}}
+};
+
+class CopyCtor {
+ CopyCtor(CopyCtor &cc) { abort(); } // expected-note 3 {{because type 'class CopyCtor' has a user-declared copy constructor}}
+};
+
+// FIXME: this should eventually trigger on the operator's declaration line
+class CopyAssign { // expected-note 3 {{because type 'class CopyAssign' has a user-declared copy assignment operator}}
+ CopyAssign& operator=(CopyAssign& CA) { abort(); }
+};
+
+class Dtor {
+ ~Dtor() { abort(); } // expected-note 3 {{because type 'class Dtor' has a user-declared destructor}}
+};
+
+union U1 {
+ Virtual v; // expected-error {{union member 'v' has a non-trivial copy constructor}}
+ VirtualBase vbase; // expected-error {{union member 'vbase' has a non-trivial copy constructor}}
+ Ctor ctor; // expected-error {{union member 'ctor' has a non-trivial constructor}}
+ CopyCtor copyctor; // expected-error {{union member 'copyctor' has a non-trivial copy constructor}}
+ CopyAssign copyassign; // expected-error {{union member 'copyassign' has a non-trivial copy assignment operator}}
+ Dtor dtor; // expected-error {{union member 'dtor' has a non-trivial destructor}}
+ Okay okay;
+};
+
+union U2 {
+ struct {
+ Virtual v; // expected-note {{because type 'struct U2::<anonymous>' has a member with a non-trivial copy constructor}}
+ } m1; // expected-error {{union member 'm1' has a non-trivial copy constructor}}
+ struct {
+ VirtualBase vbase; // expected-note {{because type 'struct U2::<anonymous>' has a member with a non-trivial copy constructor}}
+ } m2; // expected-error {{union member 'm2' has a non-trivial copy constructor}}
+ struct {
+ Ctor ctor; // expected-note {{because type 'struct U2::<anonymous>' has a member with a non-trivial constructor}}
+ } m3; // expected-error {{union member 'm3' has a non-trivial constructor}}
+ struct {
+ CopyCtor copyctor; // expected-note {{because type 'struct U2::<anonymous>' has a member with a non-trivial copy constructor}}
+ } m4; // expected-error {{union member 'm4' has a non-trivial copy constructor}}
+ struct {
+ CopyAssign copyassign; // expected-note {{because type 'struct U2::<anonymous>' has a member with a non-trivial copy assignment operator}}
+ } m5; // expected-error {{union member 'm5' has a non-trivial copy assignment operator}}
+ struct {
+ Dtor dtor; // expected-note {{because type 'struct U2::<anonymous>' has a member with a non-trivial destructor}}
+ } m6; // expected-error {{union member 'm6' has a non-trivial destructor}}
+ struct {
+ Okay okay;
+ } m7;
+};
+
+union U3 {
+ struct s1 : Virtual { // expected-note {{because type 'struct U3::s1' has a base class with a non-trivial copy constructor}}
+ } m1; // expected-error {{union member 'm1' has a non-trivial copy constructor}}
+ struct s2 : VirtualBase { // expected-note {{because type 'struct U3::s2' has a base class with a non-trivial copy constructor}}
+ } m2; // expected-error {{union member 'm2' has a non-trivial copy constructor}}
+ struct s3 : Ctor { // expected-note {{because type 'struct U3::s3' has a base class with a non-trivial constructor}}
+ } m3; // expected-error {{union member 'm3' has a non-trivial constructor}}
+ struct s4 : CopyCtor { // expected-note {{because type 'struct U3::s4' has a base class with a non-trivial copy constructor}}
+ } m4; // expected-error {{union member 'm4' has a non-trivial copy constructor}}
+ struct s5 : CopyAssign { // expected-note {{because type 'struct U3::s5' has a base class with a non-trivial copy assignment operator}}
+ } m5; // expected-error {{union member 'm5' has a non-trivial copy assignment operator}}
+ struct s6 : Dtor { // expected-note {{because type 'struct U3::s6' has a base class with a non-trivial destructor}}
+ } m6; // expected-error {{union member 'm6' has a non-trivial destructor}}
+ struct s7 : Okay {
+ } m7;
+};
+
+template <class A, class B> struct Either {
+ bool tag;
+ union {
+ A a;
+ B b;
+ };
+
+ Either(A& a) : tag(true), a(a) {}
+ Either(B& b) : tag(false), b(b) {}
+};
+
+/* FIXME: this should work, but crashes in template code.
+void fred() {
+ Either<int,Virtual> virt(0);
+ Either<int,VirtualBase> vbase(0);
+ Either<int,Ctor> ctor(0);
+ Either<int,CopyCtor> copyctor(0);
+ Either<int,CopyAssign> copyassign(0);
+ Either<int,Dtor> dtor(0);
+ Either<int,Okay> okay(0);
+}
+ */
diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.def/namespace.memdef/p3.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.def/namespace.memdef/p3.cpp
new file mode 100644
index 0000000..2ca7165
--- /dev/null
+++ b/test/CXX/dcl.dcl/basic.namespace/namespace.def/namespace.memdef/p3.cpp
@@ -0,0 +1,15 @@
+// RUN: clang-cc -fsyntax-only %s
+
+template<typename T> struct X0 { };
+struct X1 { };
+
+struct Y {
+ template<typename T> union X0;
+ template<typename T> friend union X0;
+
+ union X1;
+ friend union X1;
+};
+
+
+// FIXME: Woefully inadequate for testing
diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3-cxx0x.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3-cxx0x.cpp
new file mode 100644
index 0000000..d701f88
--- /dev/null
+++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3-cxx0x.cpp
@@ -0,0 +1,20 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+// C++0x N2914.
+
+struct B {
+ void f(char);
+ void g(char);
+ enum E { e };
+ union { int x; };
+};
+
+class C {
+ int g();
+};
+
+class D2 : public B {
+ using B::f;
+ using B::e;
+ using B::x;
+ using C::g; // expected-error{{using declaration refers into 'C::', which is not a base class of 'D2'}}
+};
diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p5-cxx0x.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p5-cxx0x.cpp
new file mode 100644
index 0000000..63e5c3c
--- /dev/null
+++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p5-cxx0x.cpp
@@ -0,0 +1,12 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+// C++0x N2914.
+
+struct A {
+ template<class T> void f(T);
+ template<class T> struct X { };
+};
+
+struct B : A {
+ using A::f<double>; // expected-error{{using declaration can not refer to template specialization}}
+ using A::X<int>; // expected-error{{using declaration can not refer to template specialization}}
+}; \ No newline at end of file
diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p6-cxx0x.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p6-cxx0x.cpp
new file mode 100644
index 0000000..f86f8fb
--- /dev/null
+++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p6-cxx0x.cpp
@@ -0,0 +1,8 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+// C++0x N2914.
+
+namespace A {
+ namespace B { }
+}
+
+using A::B; // expected-error{{using declaration can not refer to namespace}}
diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8-cxx0x.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8-cxx0x.cpp
new file mode 100644
index 0000000..59137eb
--- /dev/null
+++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8-cxx0x.cpp
@@ -0,0 +1,15 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+// C++0x N2914.
+
+struct X {
+ int i;
+ static int a;
+};
+
+using X::i; // expected-error{{using declaration can not refer to class member}}
+using X::s; // expected-error{{using declaration can not refer to class member}}
+
+void f() {
+ using X::i; // expected-error{{using declaration can not refer to class member}}
+ using X::s; // expected-error{{using declaration can not refer to class member}}
+}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p9.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p9.cpp
index 5d9f9e7..907a91a 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p9.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p9.cpp
@@ -2,11 +2,11 @@
struct S; // expected-note {{forward declaration of 'struct S'}}
extern S a;
-extern S f();
+extern S f(); // expected-note {{'f' declared here}}
extern void g(S a); // expected-note {{candidate function}}
void h() {
// FIXME: This diagnostic could be better.
g(a); // expected-error {{no matching function for call to 'g'}}
- f(); // expected-error {{return type of called function ('struct S') is incomplete}}
+ f(); // expected-error {{calling 'f' with incomplete return type 'struct S'}}
}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp
new file mode 100644
index 0000000..6bdea20
--- /dev/null
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp
@@ -0,0 +1,10 @@
+// RUN: clang-cc -fsyntax-only -verify %s -std=c++0x
+void f() {
+ auto a = a; // expected-error{{variable 'a' declared with 'auto' type cannot appear in its own initializer}}
+}
+
+void g() {
+ auto a; // expected-error{{declaration of variable 'a' with type 'auto' requires an initializer}}
+
+ auto *b; // expected-error{{declaration of variable 'b' with type 'auto *' requires an initializer}}
+}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp
new file mode 100644
index 0000000..fa3101c
--- /dev/null
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp
@@ -0,0 +1,13 @@
+// RUN: clang-cc -fsyntax-only -verify %s -std=c++0x
+void f() {
+ auto a = a; // expected-error{{variable 'a' declared with 'auto' type cannot appear in its own initializer}}
+}
+
+struct S { auto a; }; // expected-error{{'auto' not allowed in struct member}}
+
+void f(auto a) // expected-error{{'auto' not allowed in function prototype}}
+{
+ try { } catch (auto a) { } // expected-error{{'auto' not allowed in exception declaration}}
+}
+
+template <auto a = 10> class C { }; // expected-error{{'auto' not allowed in template parameter}}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp
new file mode 100644
index 0000000..b9cdb52
--- /dev/null
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp
@@ -0,0 +1,60 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+class A {}; // expected-note 3 {{previous use is here}}
+
+void a1(struct A);
+void a2(class A);
+void a3(union A); // expected-error {{use of 'A' with tag type that does not match previous declaration}}
+void a4(enum A); // expected-error {{use of 'A' with tag type that does not match previous declaration}}
+
+class A1 {
+ friend struct A;
+ friend class A;
+ friend union A; // expected-error {{use of 'A' with tag type that does not match previous declaration}}
+
+ friend enum A; // expected-error {{ISO C++ forbids forward references to 'enum' types}} \
+ // expected-error {{enum types cannot be friends}}
+};
+
+template <class T> struct B { // expected-note {{previous use is here}}
+ class Member {}; // expected-note 2 {{previous use is here}}
+};
+
+template <> class B<int> {
+ // no type Member
+};
+
+template <> struct B<A> {
+ // FIXME: the error here should be associated with the use at "void foo..."
+ union Member { // expected-note 4 {{previous use is here}} expected-error {{tag type that does not match previous declaration}}
+ void* a;
+ };
+};
+
+void b1(struct B<float>);
+void b2(class B<float>);
+void b3(union B<float>); // expected-error {{use of 'B<float>' with tag type that does not match previous declaration}}
+//void b4(enum B<float>); // this just doesn't parse; you can't template an enum directly
+
+void c1(struct B<float>::Member);
+void c2(class B<float>::Member);
+void c3(union B<float>::Member); // expected-error {{use of 'Member' with tag type that does not match previous declaration}}
+void c4(enum B<float>::Member); // expected-error {{use of 'Member' with tag type that does not match previous declaration}}
+
+void d1(struct B<int>::Member); // expected-error {{'Member' does not name a tag member in the specified scope}}
+void d2(class B<int>::Member); // expected-error {{'Member' does not name a tag member in the specified scope}}
+void d3(union B<int>::Member); // expected-error {{'Member' does not name a tag member in the specified scope}}
+void d4(enum B<int>::Member); // expected-error {{'Member' does not name a tag member in the specified scope}}
+
+void e1(struct B<A>::Member); // expected-error {{use of 'Member' with tag type that does not match previous declaration}}
+void e2(class B<A>::Member); // expected-error {{use of 'Member' with tag type that does not match previous declaration}}
+void e3(union B<A>::Member);
+void e4(enum B<A>::Member); // expected-error {{use of 'Member' with tag type that does not match previous declaration}}
+
+template <class T> struct C {
+ void foo(class B<T>::Member); // expected-error{{no type named 'Member' in 'B<int>'}}
+};
+
+C<float> f1;
+C<int> f2; // expected-note {{in instantiation of template class}}
+C<A> f3; // expected-note {{in instantiation of template class}}
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p10.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p10.cpp
new file mode 100644
index 0000000..82f5267
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p10.cpp
@@ -0,0 +1,16 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+struct A {
+ virtual void f(int a = 7);
+};
+
+struct B : public A {
+ void f(int a);
+};
+
+void m() {
+ B* pb = new B;
+ A* pa = pb;
+ pa->f(); // OK, calls pa->B::f(7)
+ pb->f(); // expected-error{{too few arguments}}
+}
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p2.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p2.cpp
new file mode 100644
index 0000000..143a0ca
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p2.cpp
@@ -0,0 +1,9 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+void point(int = 3, int = 4);
+
+void test_point() {
+ point(1,2);
+ point(1);
+ point();
+}
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp
new file mode 100644
index 0000000..ea16f64
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp
@@ -0,0 +1,13 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+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}}}
+}
+
+struct X0 {
+ 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}}
+};
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp
new file mode 100644
index 0000000..bbfaf90
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp
@@ -0,0 +1,55 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+void f0(int i, int j, int k = 3);
+void f0(int i, int j, int k);
+void f0(int i, int j = 2, int k);
+void f0(int i, int j, int k);
+void f0(int i = 1, // expected-note{{previous definition}}
+ int j, int k);
+void f0(int i, int j, int k);
+
+namespace N0 {
+ void f0(int, int, int); // expected-note{{candidate}}
+
+ void test_f0_inner_scope() {
+ f0(); // expected-error{{no matching}}
+ }
+}
+
+void test_f0_outer_scope() {
+ f0(); // okay
+}
+
+void f0(int i = 1, // expected-error{{redefinition of default argument}}
+ int, int);
+
+template<typename T> void f1(T); // expected-note{{previous}}
+
+template<typename T>
+void f1(T = T()); // expected-error{{cannot be added}}
+
+
+namespace N1 {
+ // example from C++03 standard
+ // FIXME: make these "f2"s into "f"s, then fix our scoping issues
+ void f2(int, int);
+ void f2(int, int = 7);
+ void h() {
+ f2(3); // OK, calls f(3, 7)
+ void f(int = 1, int); // expected-error{{missing default argument}}
+ }
+
+ void m()
+ {
+ void f(int, int); // expected-note{{candidate}}
+ f(4); // expected-error{{no matching}}
+ void f(int, int = 5); // expected-note{{previous definition}}
+ f(4); // okay
+ void f(int, int = 5); // expected-error{{redefinition of default argument}}
+ }
+
+ void n()
+ {
+ f2(6); // okay
+ }
+} \ No newline at end of file
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p5.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p5.cpp
new file mode 100644
index 0000000..894c9b5
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p5.cpp
@@ -0,0 +1,18 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+float global_f;
+
+void f0(int *ip = &global_f); // expected-error{{incompatible}}
+
+// Example from C++03 standard
+int a = 1;
+int f(int);
+int g(int x = f(a));
+
+void h() {
+ a = 2;
+ {
+ int *a = 0;
+ g(); // FIXME: check that a is called with a value of 2
+ }
+}
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p6.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p6.cpp
new file mode 100644
index 0000000..ef00e7b
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p6.cpp
@@ -0,0 +1,32 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+class C {
+ void f(int i = 3); // expected-note{{here}}
+ void g(int i, int j = 99);
+};
+
+void C::f(int i = 3) { } // expected-error{{redefinition of default argument}}
+
+void C::g(int i = 88, int j) { }
+
+void test_C(C c) {
+ c.f();
+ c.g();
+}
+
+template<typename T>
+struct X0 {
+ void f(int);
+
+ struct Inner {
+ void g(int);
+ };
+};
+
+// DR217
+template<typename T>
+void X0<T>::f(int = 17) { } // expected-error{{cannot be added}}
+
+// DR217 + DR205 (reading tea leaves)
+template<typename T>
+void X0<T>::Inner::g(int = 17) { } // expected-error{{cannot be added}}
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p7.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p7.cpp
new file mode 100644
index 0000000..9c1d3a9
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p7.cpp
@@ -0,0 +1,7 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+void h()
+{
+ int i;
+ extern void h2(int x = sizeof(i)); // expected-error {{default argument references local variable 'i' of enclosing function}}
+}
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p8.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p8.cpp
new file mode 100644
index 0000000..574237e
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p8.cpp
@@ -0,0 +1,4 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+class A {
+ void f(A* p = this) { } // expected-error{{invalid use of 'this'}}
+};
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p3.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p3.cpp
new file mode 100644
index 0000000..6f71978c
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p3.cpp
@@ -0,0 +1,3 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+void f(int) { } // expected-note {{previous definition is here}}
+void f(const int) { } // expected-error {{redefinition of 'f'}} \ No newline at end of file
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.mptr/p3.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.mptr/p3.cpp
new file mode 100644
index 0000000..101d75f
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.mptr/p3.cpp
@@ -0,0 +1,26 @@
+// RUN: clang-cc -fsyntax-only -verify %t
+class A {
+public:
+ int& i;
+
+ A(int& i) : i(i) { }
+
+ static int s;
+};
+
+template<typename T> void ft(T& t) {
+ t.*&T::i = 10; // expected-error{{cannot form a pointer-to-member to member 'i' of reference type 'int &'}}
+}
+
+void f() {
+ int b;
+ A a(b);
+
+ int A::*ip = &A::s; // expected-error {{incompatible type initializing 'int *', expected 'int class A::*'}}
+ a.*&A::s = 10; // expected-error{{right hand operand to .* has non pointer-to-member type 'int *'}}
+
+ a.*&A::i = 10; // expected-error{{cannot form a pointer-to-member to member 'i' of reference type 'int &'}}
+ ft(a); // expected-note{{in instantiation of function template specialization 'ft' requested here}}
+
+ void A::*p = 0; // expected-error{{'p' declared as a member pointer to void}}
+}
diff --git a/test/CXX/expr/p3.cpp b/test/CXX/expr/p3.cpp
new file mode 100644
index 0000000..40fe052
--- /dev/null
+++ b/test/CXX/expr/p3.cpp
@@ -0,0 +1,15 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+double operator +(double, double); // expected-error{{overloaded 'operator+' must have at least one parameter of class or enumeration type}}
+
+struct A
+{
+ operator int();
+};
+
+int main()
+{
+ A a, b;
+ int i0 = a + 1;
+ int i1 = a + b;
+}
diff --git a/test/CXX/expr/p8.cpp b/test/CXX/expr/p8.cpp
new file mode 100644
index 0000000..4f02497
--- /dev/null
+++ b/test/CXX/expr/p8.cpp
@@ -0,0 +1,18 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+int a0;
+const volatile int a1;
+int a2[16];
+int a3();
+
+void f0(int);
+void f1(int *);
+void f2(int (*)());
+
+int main()
+{
+ f0(a0);
+ f0(a1);
+ f1(a2);
+ f2(a3);
+}
diff --git a/test/CXX/expr/p9.cpp b/test/CXX/expr/p9.cpp
new file mode 100644
index 0000000..1eec3cf
--- /dev/null
+++ b/test/CXX/expr/p9.cpp
@@ -0,0 +1,50 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// floating-point overloads
+
+__typeof__(0 + 0.0L) ld0;
+long double &ldr = ld0;
+
+__typeof__(0 + 0.0) d0;
+double &dr = d0;
+
+__typeof__(0 + 0.0f) f0;
+float &fr = f0;
+
+// integral promotions
+
+signed char c0;
+__typeof__(c0 + c0) c1;
+int &cr = c1;
+
+unsigned char uc0;
+__typeof__(uc0 + uc0) uc1;
+int &ucr = uc1;
+
+short s0;
+__typeof__(s0 + s0) s1;
+int &sr = s1;
+
+unsigned short us0;
+__typeof__(us0 + us0) us1;
+int &usr = us1;
+
+// integral overloads
+
+__typeof__(0 + 0UL) ul0;
+unsigned long &ulr = ul0;
+
+template<bool T> struct selector;
+template<> struct selector<true> { typedef long type; };
+template<> struct selector<false> {typedef unsigned long type; };
+__typeof__(0U + 0L) ui_l0;
+selector<(sizeof(long) > sizeof(unsigned int))>::type &ui_lr = ui_l0;
+
+__typeof__(0 + 0L) l0;
+long &lr = l0;
+
+__typeof__(0 + 0U) u0;
+unsigned &ur = u0;
+
+__typeof__(0 + 0) i0;
+int &ir = i0;
diff --git a/test/CXX/lex/lex.trigraph/p1.cpp b/test/CXX/lex/lex.trigraph/p1.cpp
new file mode 100644
index 0000000..2a9a34b
--- /dev/null
+++ b/test/CXX/lex/lex.trigraph/p1.cpp
@@ -0,0 +1,19 @@
+// RUN: clang-cc -fsyntax-only -trigraphs -Wtrigraphs -verify %s
+
+??=pragma // expected-warning {{trigraph converted to '#' character}}
+
+int a = '??/0'; // expected-warning {{trigraph converted to '\' character}}
+
+int b = 1 ??' 0; // expected-warning {{trigraph converted to '^' character}}
+
+int c ??(1]; // expected-warning {{trigraph converted to '[' character}}
+
+int d [1??); // expected-warning {{trigraph converted to ']' character}}
+
+int e = 1 ??! 0; // expected-warning {{trigraph converted to '|' character}}
+
+void f() ??<} // expected-warning {{trigraph converted to '{' character}}
+
+void g() {??> // expected-warning {{trigraph converted to '}' character}}
+
+int h = ??- 0; // expected-warning {{trigraph converted to '~' character}}
diff --git a/test/CXX/lex/lex.trigraph/p2.cpp b/test/CXX/lex/lex.trigraph/p2.cpp
new file mode 100644
index 0000000..5be2d46
--- /dev/null
+++ b/test/CXX/lex/lex.trigraph/p2.cpp
@@ -0,0 +1,3 @@
+// RUN: clang-cc -fsyntax-only -trigraphs -Wtrigraphs -verify %s
+
+??=define arraycheck(a,b) a??(b??) ??!??! b??(a??) // expected-warning {{trigraph converted to '#' character}} expected-warning {{trigraph converted to '[' character}} expected-warning {{trigraph converted to ']' character}} expected-warning {{trigraph converted to '|' character}} expected-warning {{trigraph converted to '|' character}} expected-warning {{trigraph converted to '[' character}} expected-warning {{trigraph converted to ']' character}}
diff --git a/test/CXX/lex/lex.trigraph/p3.cpp b/test/CXX/lex/lex.trigraph/p3.cpp
new file mode 100644
index 0000000..f32af49
--- /dev/null
+++ b/test/CXX/lex/lex.trigraph/p3.cpp
@@ -0,0 +1,8 @@
+// RUN: clang-cc -fsyntax-only -trigraphs -Wtrigraphs -verify %s
+
+char a[] =
+"?? ??\"??#??$??%??&??*??+??,??.??0??1??2??3??4??5??6"
+"??7??8??9??:??;?????@??A??B??C??D??E??F??G??H??I??J"
+"??K??L??M??N??O??P??Q??R??S??T??U??V??W??X??Y??Z??["
+"??\\??]??^??_??`??a??b??c??d??e??f??g??h??i??j??k??l"
+"??m??n??o??p??q??r??s??t??u??v??w??x??y??z??{??|??}??~";
diff --git a/test/CXX/over/over.match/over.match.best/p1.cpp b/test/CXX/over/over.match/over.match.best/p1.cpp
new file mode 100644
index 0000000..df51983
--- /dev/null
+++ b/test/CXX/over/over.match/over.match.best/p1.cpp
@@ -0,0 +1,16 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T> int &f0(T*, int);
+float &f0(void*, int);
+
+void test_f0(int* ip, void *vp) {
+ // One argument is better...
+ int &ir = f0(ip, 0);
+
+ // Prefer non-templates to templates
+ float &fr = f0(vp, 0);
+}
+
+// Partial ordering of function template specializations will be tested
+// elsewhere
+// FIXME: Initialization by user-defined conversion is tested elsewhere
diff --git a/test/CXX/over/over.over/p1.cpp b/test/CXX/over/over.over/p1.cpp
new file mode 100644
index 0000000..e7f7d18
--- /dev/null
+++ b/test/CXX/over/over.over/p1.cpp
@@ -0,0 +1,94 @@
+// RUN: clang-cc -fsyntax-only %s
+
+template<typename T> T f0(T);
+int f0(int);
+
+// -- an object or reference being initialized
+struct S {
+ int (*f0)(int);
+ float (*f1)(float);
+};
+
+void test_init_f0() {
+ int (*f0a)(int) = f0;
+ int (*f0b)(int) = &f0;
+ int (*f0c)(int) = (f0);
+ float (*f0d)(float) = f0;
+ float (*f0e)(float) = &f0;
+ float (*f0f)(float) = (f0);
+ int (&f0g)(int) = f0;
+ int (&f0h)(int) = (f0);
+ float (&f0i)(float) = f0;
+ float (&f0j)(float) = (f0);
+ S s = { f0, f0 };
+}
+
+// -- the left side of an assignment (5.17),
+void test_assign_f0() {
+ int (*f0a)(int) = 0;
+ float (*f0b)(float) = 0;
+
+ f0a = f0;
+ f0a = &f0;
+ f0a = (f0);
+ f0b = f0;
+ f0b = &f0;
+ f0b = (f0);
+}
+
+// -- a parameter of a function (5.2.2),
+void eat_f0(int a(int), float (*b)(float), int (&c)(int), float (&d)(float));
+
+void test_pass_f0() {
+ eat_f0(f0, f0, f0, f0);
+ eat_f0(&f0, &f0, (f0), (f0));
+}
+
+// -- a parameter of a user-defined operator (13.5),
+struct X { };
+void operator+(X, int(int));
+void operator-(X, float(*)(float));
+void operator*(X, int (&)(int));
+void operator/(X, float (&)(float));
+
+void test_operator_pass_f0(X x) {
+ x + f0;
+ x + &f0;
+ x - f0;
+ x - &f0;
+ x * f0;
+ x * (f0);
+ x / f0;
+ x / (f0);
+}
+
+// -- the return value of a function, operator function, or conversion (6.6.3),
+int (*test_return_f0_a())(int) { return f0; }
+int (*test_return_f0_b())(int) { return &f0; }
+int (*test_return_f0_c())(int) { return (f0); }
+float (*test_return_f0_d())(float) { return f0; }
+float (*test_return_f0_e())(float) { return &f0; }
+float (*test_return_f0_f())(float) { return (f0); }
+
+// -- an explicit type conversion (5.2.3, 5.2.9, 5.4), or
+void test_convert_f0() {
+ (void)((int (*)(int))f0);
+ (void)((int (*)(int))&f0);
+ (void)((int (*)(int))(f0));
+ (void)((float (*)(float))f0);
+ (void)((float (*)(float))&f0);
+ (void)((float (*)(float))(f0));
+}
+
+// -- a non-type template-parameter(14.3.2).
+template<int(int)> struct Y0 { };
+template<float(float)> struct Y1 { };
+template<int (&)(int)> struct Y2 { };
+template<float (&)(float)> struct Y3 { };
+
+Y0<f0> y0;
+Y0<&f0> y0a;
+Y1<f0> y1;
+Y1<&f0> y1a;
+Y2<f0> y2;
+Y3<f0> y3;
diff --git a/test/CXX/over/over.over/p2.cpp b/test/CXX/over/over.over/p2.cpp
new file mode 100644
index 0000000..9ab0260
--- /dev/null
+++ b/test/CXX/over/over.over/p2.cpp
@@ -0,0 +1,10 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T> T f0(T, T);
+
+void test_f0() {
+ int (*f0a)(int, int) = f0;
+ int (*f0b)(int, int) = &f0;
+ int (*f0c)(int, float) = f0; // expected-error{{incompatible type}}
+ // FIXME: poor error message above!
+}
diff --git a/test/CXX/over/over.over/p4.cpp b/test/CXX/over/over.over/p4.cpp
new file mode 100644
index 0000000..a05dbae
--- /dev/null
+++ b/test/CXX/over/over.over/p4.cpp
@@ -0,0 +1,23 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T> T f0(T);
+int f0(int); // expected-note{{candidate function}}
+
+void test_f0() {
+ int (*fp0)(int) = f0;
+ int (*fp1)(int) = &f0;
+ float (*fp2)(float) = &f0;
+}
+
+namespace N {
+ int f0(int); // expected-note{{candidate function}}
+}
+
+int f0(int);
+
+void test_f0_2() {
+ using namespace N;
+ int (*fp0)(int) = f0; // expected-error{{ambiguous}} \
+ // expected-error{{initializing}}
+ float (*fp1)(float) = f0;
+}
diff --git a/test/CXX/temp/temp.decls/temp.class.spec/p6.cpp b/test/CXX/temp/temp.decls/temp.class.spec/p6.cpp
new file mode 100644
index 0000000..afe6ab2
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.class.spec/p6.cpp
@@ -0,0 +1,20 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T>
+struct X0 {
+ template<typename U> struct Inner0 {
+ static const unsigned value = 0;
+ };
+
+ template<typename U> struct Inner0<U*> {
+ static const unsigned value = 1;
+ };
+};
+
+template<typename T> template<typename U>
+struct X0<T>::Inner0<const U*> {
+ static const unsigned value = 2;
+};
+
+// FIXME: Test instantiation of these partial specializations (once they are
+// implemented).
diff --git a/test/CXX/temp/temp.decls/temp.class.spec/temp.class.order/p2.cpp b/test/CXX/temp/temp.decls/temp.class.spec/temp.class.order/p2.cpp
new file mode 100644
index 0000000..b3b7635
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.class.spec/temp.class.order/p2.cpp
@@ -0,0 +1,16 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+template<int I, int J, class T> class X {
+ static const int value = 0;
+};
+
+template<int I, int J> class X<I, J, int> {
+ static const int value = 1;
+};
+
+template<int I> class X<I, I, int> {
+ static const int value = 2;
+};
+
+int array0[X<0, 0, float>::value == 0? 1 : -1];
+int array1[X<0, 1, int>::value == 1? 1 : -1];
+int array2[X<0, 0, int>::value == 2? 1 : -1];
diff --git a/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1-neg.cpp b/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1-neg.cpp
new file mode 100644
index 0000000..47cf837
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1-neg.cpp
@@ -0,0 +1,25 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T, int N>
+struct A;
+
+template<typename T> // expected-note{{previous template declaration}}
+struct A<T*, 2> {
+ void f0();
+ void f1();
+ void f2();
+};
+
+template<>
+struct A<int, 1> {
+ void g0();
+};
+
+// FIXME: We should probably give more precise diagnostics here, but the
+// diagnostics we give aren't terrible.
+// FIXME: why not point to the first parameter that's "too many"?
+template<typename T, int N> // expected-error{{too many template parameters}}
+void A<T*, 2>::f0() { }
+
+template<typename T, int N>
+void A<T, N>::f1() { } // expected-error{{out-of-line definition}}
diff --git a/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1.cpp b/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1.cpp
new file mode 100644
index 0000000..b63c56c
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1.cpp
@@ -0,0 +1,26 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T, int N>
+struct A;
+
+template<typename T>
+struct A<T*, 2> {
+ A(T);
+ ~A();
+
+ void f(T*);
+
+ operator T*();
+
+ static T value;
+};
+
+template<class X> void A<X*, 2>::f(X*) { }
+
+template<class X> X A<X*, 2>::value;
+
+template<class X> A<X*, 2>::A(X) { value = 0; }
+
+template<class X> A<X*, 2>::~A() { }
+
+template<class X> A<X*, 2>::operator X*() { return 0; }
diff --git a/test/CXX/temp/temp.decls/temp.class/temp.mem.class/p1.cpp b/test/CXX/temp/temp.decls/temp.class/temp.mem.class/p1.cpp
new file mode 100644
index 0000000..bc4bb5d
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.class/temp.mem.class/p1.cpp
@@ -0,0 +1,27 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T, typename U>
+struct X0 {
+ struct Inner;
+};
+
+template<typename T, typename U>
+struct X0<T, U>::Inner {
+ T x;
+ U y;
+
+ void f() { x = y; } // expected-error{{incompatible}}
+};
+
+
+void test(int i, float f) {
+ X0<int, float>::Inner inner;
+ inner.x = 5;
+ inner.y = 3.4;
+ inner.f();
+
+ X0<int*, float *>::Inner inner2;
+ inner2.x = &i;
+ inner2.y = &f;
+ inner2.f(); // expected-note{{instantiation}}
+}
diff --git a/test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1-retmem.cpp b/test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1-retmem.cpp
new file mode 100644
index 0000000..fd3fb0b
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1-retmem.cpp
@@ -0,0 +1,28 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T> struct X1 { };
+
+template<typename T>
+struct X0 {
+ typedef int size_type;
+ typedef T value_type;
+
+ size_type f0() const;
+ value_type *f1();
+ X1<value_type*> f2();
+};
+
+template<typename T>
+typename X0<T>::size_type X0<T>::f0() const {
+ return 0;
+}
+
+template<typename U>
+typename X0<U>::value_type *X0<U>::f1() {
+ return 0;
+};
+
+template<typename U>
+X1<typename X0<U>::value_type*> X0<U>::f2() {
+ return 0;
+};
diff --git a/test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1.cpp b/test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1.cpp
new file mode 100644
index 0000000..725b61c
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1.cpp
@@ -0,0 +1,68 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T, typename U> // expected-note{{previous template}}
+class X0 {
+public:
+ typedef int size_type;
+
+ X0(int);
+ ~X0();
+
+ void f0(const T&, const U&);
+
+ T& operator[](int i) const;
+
+ void f1(size_type) const;
+ void f2(size_type) const;
+ void f3(size_type) const;
+ void f4() ;
+
+ operator T*() const;
+
+ T value;
+};
+
+template<typename T, typename U>
+void X0<T, U>::f0(const T&, const U&) { // expected-note{{previous definition}}
+}
+
+template<class X, class Y>
+X& X0<X, Y>::operator[](int i) const {
+ (void)i;
+ return value;
+}
+
+template<class X, class Y>
+void X0<X, Y>::f1(int) const { }
+
+template<class X, class Y>
+void X0<X, Y>::f2(size_type) const { }
+
+template<class X, class Y, class Z> // expected-error{{too many template parameters}}
+void X0<X, Y>::f3(size_type) const {
+}
+
+template<class X, class Y>
+void X0<Y, X>::f4() { } // expected-error{{does not refer}}
+
+// FIXME: error message should probably say, "redefinition of 'X0<T, U>::f0'"
+// rather than just "redefinition of 'f0'"
+template<typename T, typename U>
+void X0<T, U>::f0(const T&, const U&) { // expected-error{{redefinition}}
+}
+
+// Test out-of-line constructors, destructors
+template<typename T, typename U>
+X0<T, U>::X0(int x) : value(x) { }
+
+template<typename T, typename U>
+X0<T, U>::~X0() { }
+
+// Test out-of-line conversion functions.
+template<typename T, typename U>
+X0<T, U>::operator T*() const {
+ return &value;
+}
+
+namespace N { template <class X> class A {void a();}; }
+namespace N { template <class X> void A<X>::a() {} }
diff --git a/test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1inst.cpp b/test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1inst.cpp
new file mode 100644
index 0000000..a09d0ef
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1inst.cpp
@@ -0,0 +1,17 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+// Test instantiation of member functions of class templates defined out-of-line
+template<typename T, typename U>
+struct X0 {
+ void f(T *t, const U &u);
+ void f(T *);
+};
+
+template<typename T, typename U>
+void X0<T, U>::f(T *t, const U &u) {
+ *t = u; // expected-error{{not assignable}}
+}
+
+void test_f(X0<float, int> xfi, X0<void, int> xvi, float *fp, void *vp, int i) {
+ xfi.f(fp, i);
+ xvi.f(vp, i); // expected-note{{instantiation}}
+}
diff --git a/test/CXX/temp/temp.decls/temp.class/temp.mem.func/pr5056.cpp b/test/CXX/temp/temp.decls/temp.class/temp.mem.func/pr5056.cpp
new file mode 100644
index 0000000..602fd37
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.class/temp.mem.func/pr5056.cpp
@@ -0,0 +1,17 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+extern "C" void * malloc(int);
+
+template <typename T> struct A {
+ void *malloc(int);
+};
+
+template <typename T>
+inline void *A<T>::malloc(int)
+{
+ return 0;
+}
+
+void f() {
+ malloc(10);
+}
diff --git a/test/CXX/temp/temp.decls/temp.class/temp.static/p1-inst.cpp b/test/CXX/temp/temp.decls/temp.class/temp.static/p1-inst.cpp
new file mode 100644
index 0000000..2ddb8ea
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.class/temp.static/p1-inst.cpp
@@ -0,0 +1,28 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// Test instantiation of static data members declared out-of-line.
+
+template<typename T>
+struct X {
+ static T value;
+};
+
+template<typename T>
+ T X<T>::value = 17; // expected-error{{initialize}}
+
+struct InitOkay {
+ InitOkay(int) { }
+};
+
+struct CannotInit { };
+
+int &returnInt() { return X<int>::value; }
+float &returnFloat() { return X<float>::value; }
+
+InitOkay &returnInitOkay() { return X<InitOkay>::value; }
+
+unsigned long sizeOkay() { return sizeof(X<CannotInit>::value); }
+
+CannotInit &returnError() {
+ return X<CannotInit>::value; // expected-note{{instantiation}}
+}
diff --git a/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp b/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp
new file mode 100644
index 0000000..949a8b0
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp
@@ -0,0 +1,26 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T>
+struct X0 {
+ static T value;
+};
+
+template<typename T>
+T X0<T>::value = 0; // expected-error{{initialize}}
+
+struct X1 {
+ X1(int);
+};
+
+struct X2 { };
+
+int& get_int() { return X0<int>::value; }
+X1& get_X1() { return X0<X1>::value; }
+
+double*& get_double_ptr() { return X0<int*>::value; } // expected-error{{initialized}}
+
+X2& get_X2() {
+ return X0<X2>::value; // expected-note{{instantiation}}
+}
+
+template<typename T> T x; // expected-error{{variable 'x' declared as a template}}
diff --git a/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p4.cpp b/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p4.cpp
new file mode 100644
index 0000000..fe42ba4
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p4.cpp
@@ -0,0 +1,23 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<class T> struct A { A(); };
+template<class T> int &f(T);
+template<class T> float &f(T*);
+template<class T> double &f(const T*);
+
+template<class T> void g(T); // expected-note{{candidate}}
+template<class T> void g(T&); // expected-note{{candidate}}
+
+template<class T> int &h(const T&);
+template<class T> float &h(A<T>&);
+
+void m() {
+ const int *p;
+ double &dr1 = f(p);
+ float x;
+ g(x); // expected-error{{ambiguous}}
+ A<int> z;
+ float &fr1 = h(z);
+ const A<int> z2;
+ int &ir1 = h(z2);
+}
diff --git a/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p5.cpp b/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p5.cpp
new file mode 100644
index 0000000..27e4426
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p5.cpp
@@ -0,0 +1,12 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+template<class T> int &f(T);
+template<class T> float &f(T*, int=1);
+
+template<class T> int &g(T);
+template<class T> float &g(T*, ...);
+
+int main() {
+ int* ip;
+ float &fr1 = f(ip);
+ float &fr2 = g(ip);
+}
diff --git a/test/CXX/temp/temp.decls/temp.fct/temp.over.link/p4-neg.cpp b/test/CXX/temp/temp.decls/temp.fct/temp.over.link/p4-neg.cpp
index b482955..399dcc4 100644
--- a/test/CXX/temp/temp.decls/temp.fct/temp.over.link/p4-neg.cpp
+++ b/test/CXX/temp/temp.decls/temp.fct/temp.over.link/p4-neg.cpp
@@ -17,11 +17,11 @@ template<typename T>
struct MetaFun;
template<typename T>
- typename MetaFun<T*>::type f0(const T&) { } // expected-note{{previous}}
+ typename MetaFun<T*>::type f0(const T&) { while (1) {} } // expected-note{{previous}}
template<class U>
- typename MetaFun<U*>::type f0(const U&) { } // expected-error{{redefinition}}
+ typename MetaFun<U*>::type f0(const U&) { while (1) {} } // expected-error{{redefinition}}
// FIXME: We need canonicalization of expressions for this to work
// template<int> struct A { };
// template<int I> void f0(A<I>) { } // Xpected-note{{previous}}
-// template<int J> void f0(A<J>) { } // Xpected-error{{redefinition}} \ No newline at end of file
+// template<int J> void f0(A<J>) { } // Xpected-error{{redefinition}}
diff --git a/test/CXX/temp/temp.decls/temp.fct/temp.over.link/p6.cpp b/test/CXX/temp/temp.decls/temp.fct/temp.over.link/p6.cpp
new file mode 100644
index 0000000..2571e45
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.fct/temp.over.link/p6.cpp
@@ -0,0 +1,16 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<int N, int M>
+struct A0 {
+ void g0();
+};
+
+template<int X, int Y> void f0(A0<X, Y>) { } // expected-note{{previous}}
+template<int N, int M> void f0(A0<M, N>) { }
+template<int V1, int V2> void f0(A0<V1, V2>) { } // expected-error{{redefinition}}
+
+template<int X, int Y> void f1(A0<0, (X + Y)>) { } // expected-note{{previous}}
+template<int X, int Y> void f1(A0<0, (X - Y)>) { }
+template<int A, int B> void f1(A0<0, (A + B)>) { } // expected-error{{redefinition}}
+
+template<int X, int Y> void A0<X, Y>::g0() { }
diff --git a/test/CXX/temp/temp.decls/temp.friend/p1.cpp b/test/CXX/temp/temp.decls/temp.friend/p1.cpp
new file mode 100644
index 0000000..fc392da
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.friend/p1.cpp
@@ -0,0 +1,56 @@
+// RUN: clang-cc -emit-llvm-only %s
+
+template <typename T> struct Num {
+ T value_;
+
+public:
+ Num(T value) : value_(value) {}
+ T get() const { return value_; }
+
+ template <typename U> struct Rep {
+ U count_;
+ Rep(U count) : count_(count) {}
+
+ friend Num operator*(const Num &a, const Rep &n) {
+ Num x = 0;
+ for (U count = n.count_; count; --count)
+ x += a;
+ return x;
+ }
+ };
+
+ friend Num operator+(const Num &a, const Num &b) {
+ return a.value_ + b.value_;
+ }
+
+ Num& operator+=(const Num& b) {
+ value_ += b.value_;
+ return *this;
+ }
+
+ class Representation {};
+ friend class Representation;
+};
+
+class A {
+ template <typename T> friend bool iszero(const A &a) throw();
+};
+
+template <class T> class B_iterator;
+template <class T> class B {
+ friend class B_iterator<T>;
+};
+
+int calc1() {
+ Num<int> left = -1;
+ Num<int> right = 1;
+ Num<int> result = left + right;
+ return result.get();
+}
+
+int calc2() {
+ Num<int> x = 3;
+ Num<int>::Rep<char> n = (char) 10;
+ Num<int> result = x * n;
+ return result.get();
+}
diff --git a/test/CXX/temp/temp.decls/temp.friend/p3.cpp b/test/CXX/temp/temp.decls/temp.friend/p3.cpp
new file mode 100644
index 0000000..4615beb
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.friend/p3.cpp
@@ -0,0 +1,13 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template <class T> class A {
+ typedef int Member;
+};
+
+class B {
+ template <class T> friend class A;
+ template <class T> friend class Undeclared;
+
+ // FIXME: Diagnostic below could be (and was) better.
+ template <class T> friend typename A<T>::Member; // expected-error {{classes or functions}}
+};
diff --git a/test/CXX/temp/temp.decls/temp.friend/p5.cpp b/test/CXX/temp/temp.decls/temp.friend/p5.cpp
new file mode 100644
index 0000000..f1142a4
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.friend/p5.cpp
@@ -0,0 +1,11 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template <class T> class A {
+ class Member {
+ };
+};
+
+class B {
+ template <class T> friend class A<T>::Member;
+};
+
diff --git a/test/CXX/temp/temp.decls/temp.mem/p1.cpp b/test/CXX/temp/temp.decls/temp.mem/p1.cpp
new file mode 100644
index 0000000..80b1846
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.mem/p1.cpp
@@ -0,0 +1,16 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template <class T> struct A {
+ static T cond;
+
+ template <class U> struct B {
+ static T twice(U value) {
+ return (cond ? value + value : value);
+ }
+ };
+};
+
+int foo() {
+ A<bool>::cond = true;
+ return A<bool>::B<int>::twice(4);
+}
diff --git a/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3.cpp b/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3.cpp
index f4970b8..01030b2 100644
--- a/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3.cpp
@@ -8,4 +8,4 @@ void g() {
f<int>("aa",3.0); // Y is deduced to be char*, and
// Z is deduced to be double
f("aa",3.0); // expected-error{{no matching}}
-} \ No newline at end of file
+}
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp
index c014c66..dbe2ff3 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp
@@ -1,4 +1,4 @@
-// RUN: clang-cc -fsyntax-only %s
+// RUN: clang-cc -fsyntax-only -verify %s
template<typename T> struct A { };
@@ -57,4 +57,32 @@ void test_f3(int ***ip, volatile int ***vip) {
A<volatile int> a1 = f3(vip);
}
-// FIXME: the next bullet requires a lot of effort.
+// - If P is a class, and P has the form template-id, then A can be a
+// derived class of the deduced A. Likewise, if P is a pointer to a class
+// of the form template-id, A can be a pointer to a derived class pointed
+// to by the deduced A.
+template<typename T, int I> struct C { };
+
+struct D : public C<int, 1> { };
+struct E : public D { };
+struct F : A<float> { };
+struct G : A<float>, C<int, 1> { };
+
+template<typename T, int I>
+ C<T, I> *f4a(const C<T, I>&);
+template<typename T, int I>
+ C<T, I> *f4b(C<T, I>);
+template<typename T, int I>
+ C<T, I> *f4c(C<T, I>*);
+int *f4c(...);
+
+void test_f4(D d, E e, F f, G g) {
+ C<int, 1> *ci1a = f4a(d);
+ C<int, 1> *ci2a = f4a(e);
+ C<int, 1> *ci1b = f4b(d);
+ C<int, 1> *ci2b = f4b(e);
+ C<int, 1> *ci1c = f4c(&d);
+ C<int, 1> *ci2c = f4c(&e);
+ C<int, 1> *ci3c = f4c(&g);
+ int *ip1 = f4c(&f);
+}
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p2.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p2.cpp
new file mode 100644
index 0000000..7d17578
--- /dev/null
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p2.cpp
@@ -0,0 +1,36 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// FIXME: [temp.deduct.conv]p2 bullets 1 and 2 can't actually happen without
+// references?
+// struct ConvertibleToArray {
+// // template<typename T, unsigned N>
+// // operator T(()[]) const;
+
+// private:
+// typedef int array[17];
+
+// operator array() const;
+// };
+
+// void test_array(ConvertibleToArray cta) {
+// int *ip = cta;
+// ip = cta;
+// const float *cfp = cta;
+// }
+
+// bullet 2
+// struct ConvertibleToFunction {
+// template<typename T, typename A1, typename A2>
+// operator T(A1, A2) const () { };
+// };
+
+// bullet 3
+struct ConvertibleToCVQuals {
+ template<typename T>
+ operator T* const() const;
+};
+
+void test_cvqual_conv(ConvertibleToCVQuals ctcv) {
+ int *ip = ctcv;
+ const int *icp = ctcv;
+}
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p3.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p3.cpp
new file mode 100644
index 0000000..95bd7fe
--- /dev/null
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p3.cpp
@@ -0,0 +1,30 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+struct AnyPtr {
+ template<typename T>
+ operator T*() const;
+};
+
+// If A is a cv-qualified type, the top level cv-qualifiers of A's type
+// are ignored for type deduction.
+void test_cvquals(AnyPtr ap) {
+ int* const ip = ap;
+ const float * const volatile fp = ap;
+}
+
+// If A is a reference type, the type referred to by A is used for
+// type deduction.
+void test_ref_arg(AnyPtr ap) {
+ const int* const &ip = ap;
+ double * const &dp = ap;
+}
+
+struct AnyRef {
+ template<typename T>
+ operator T&() const;
+};
+
+void test_ref_param(AnyRef ar) {
+ int &ir = ar;
+ const float &fr = ar;
+ int i = ar;
+}
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p4.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p4.cpp
new file mode 100644
index 0000000..50d31fb
--- /dev/null
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p4.cpp
@@ -0,0 +1,44 @@
+// RUN: clang-cc -fsyntax-only %s
+
+struct AnyT {
+ template<typename T>
+ operator T();
+};
+
+void test_cvqual_ref(AnyT any) {
+ const int &cir = any;
+}
+
+struct AnyThreeLevelPtr {
+ template<typename T>
+ operator T***() const
+ {
+ T x = 0;
+ // FIXME: looks like we get this wrong, too!
+ // x = 0; // will fail if T is deduced to a const type
+ // (EDG and GCC get this wrong)
+ return 0;
+ }
+};
+
+struct X { };
+
+void test_deduce_with_qual(AnyThreeLevelPtr a3) {
+ int * const * const * const ip = a3;
+}
+
+struct AnyPtrMem {
+ template<typename Class, typename T>
+ operator T Class::*() const
+ {
+ T x = 0;
+ // FIXME: looks like we get this wrong, too!
+ // x = 0; // will fail if T is deduced to a const type.
+ // (EDG and GCC get this wrong)
+ return 0;
+ }
+};
+
+void test_deduce_ptrmem_with_qual(AnyPtrMem apm) {
+ const float X::* pm = apm;
+}
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.funcaddr/p1.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.funcaddr/p1.cpp
new file mode 100644
index 0000000..86a3450
--- /dev/null
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.funcaddr/p1.cpp
@@ -0,0 +1,22 @@
+// RUN: clang-cc -fsyntax-only %s
+
+template<typename T>
+ T f0(T, int);
+
+void test_f0() {
+ int (*f0a)(int, int) = f0;
+ int (*f0b)(int, int) = &f0;
+ float (*f0c)(float, int) = &f0;
+}
+
+template<typename T> T f1(T, int);
+template<typename T> T f1(T);
+
+void test_f1() {
+ float (*f1a)(float, int) = f1;
+ float (*f1b)(float, int) = &f1;
+ float (*f1c)(float) = f1;
+ float (*f1d)(float) = (f1);
+ float (*f1e)(float) = &f1;
+ float (*f1f)(float) = (&f1);
+}
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.partial/p11.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.partial/p11.cpp
new file mode 100644
index 0000000..072789c
--- /dev/null
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.partial/p11.cpp
@@ -0,0 +1,22 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template <class T> T* f(int); // #1
+template <class T, class U> T& f(U); // #2
+
+void g() {
+ int *ip = f<int>(1); // calls #1
+}
+
+template<typename T>
+struct identity {
+ typedef T type;
+};
+
+template <class T>
+ T* f2(int, typename identity<T>::type = 0); // expected-note{{candidate}}
+template <class T, class U>
+ T& f2(U, typename identity<T>::type = 0); // expected-note{{candidate}}
+
+void g2() {
+ f2<int>(1); // expected-error{{ambiguous}}
+}
diff --git a/test/CXX/temp/temp.param/p1.cpp b/test/CXX/temp/temp.param/p1.cpp
index 488c3a0..a6638b4 100644
--- a/test/CXX/temp/temp.param/p1.cpp
+++ b/test/CXX/temp/temp.param/p1.cpp
@@ -1 +1,4 @@
+// Suppress 'no run line' failure.
+// RUN: true
+
// Paragraph 1 is descriptive, and therefore requires no tests.
diff --git a/test/CXX/temp/temp.res/temp.dep/p3.cpp b/test/CXX/temp/temp.res/temp.dep/p3.cpp
new file mode 100644
index 0000000..d47f0d6
--- /dev/null
+++ b/test/CXX/temp/temp.res/temp.dep/p3.cpp
@@ -0,0 +1,43 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+struct A0 {
+ struct K { };
+};
+
+template <typename T> struct B0: A0 {
+ static void f() {
+ K k;
+ }
+};
+
+namespace E1 {
+ typedef double A;
+
+ template<class T> class B {
+ typedef int A;
+ };
+
+ template<class T>
+ struct X : B<T> {
+ A* blarg(double *dp) {
+ return dp;
+ }
+ };
+}
+
+namespace E2 {
+ struct A {
+ struct B;
+ int *a;
+ int Y;
+ };
+
+ int a;
+ template<class T> struct Y : T {
+ struct B { /* ... */ };
+ B b;
+ void f(int i) { a = i; }
+ Y* p;
+ };
+
+ Y<A> ya;
+}
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p1.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p1.cpp
new file mode 100644
index 0000000..239b8ae
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p1.cpp
@@ -0,0 +1,99 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// This test creates cases where implicit instantiations of various entities
+// would cause a diagnostic, but provides expliict specializations for those
+// entities that avoid the diagnostic. The intent is to verify that
+// implicit instantiations do not occur (because the explicit specialization
+// is used instead).
+struct NonDefaultConstructible {
+ NonDefaultConstructible(int);
+};
+
+
+// C++ [temp.expl.spec]p1:
+// An explicit specialization of any of the following:
+
+// -- function template
+template<typename T> void f0(T) {
+ T t;
+}
+
+template<> void f0(NonDefaultConstructible) { }
+
+void test_f0(NonDefaultConstructible NDC) {
+ f0(NDC);
+}
+
+// -- class template
+template<typename T>
+struct X0 {
+ static T member;
+
+ void f1(T t) {
+ t = 17;
+ }
+
+ struct Inner : public T { };
+
+ template<typename U>
+ struct InnerTemplate : public T { };
+
+ template<typename U>
+ void ft1(T t, U u);
+};
+
+template<typename T>
+template<typename U>
+void X0<T>::ft1(T t, U u) {
+ t = u;
+}
+
+template<typename T> T X0<T>::member;
+
+template<> struct X0<void> { };
+X0<void> test_X0;
+
+
+// -- member function of a class template
+template<> void X0<void*>::f1(void *) { }
+
+void test_spec(X0<void*> xvp, void *vp) {
+ xvp.f1(vp);
+}
+
+// -- static data member of a class template
+template<>
+NonDefaultConstructible X0<NonDefaultConstructible>::member = 17;
+
+NonDefaultConstructible &get_static_member() {
+ return X0<NonDefaultConstructible>::member;
+}
+
+// -- member class of a class template
+template<>
+struct X0<void*>::Inner { };
+
+X0<void*>::Inner inner0;
+
+// -- member class template of a class template
+template<>
+template<>
+struct X0<void*>::InnerTemplate<int> { };
+
+X0<void*>::InnerTemplate<int> inner_template0;
+
+// -- member function template of a class template
+template<>
+template<>
+void X0<void*>::ft1(void*, const void*) { }
+
+void test_func_template(X0<void *> xvp, void *vp, const void *cvp) {
+ xvp.ft1(vp, cvp);
+}
+
+// example from the standard:
+template<class T> class stream;
+template<> class stream<char> { /* ... */ };
+template<class T> class Array { /* ... */ };
+template<class T> void sort(Array<T>& v) { /* ... */ }
+template<> void sort<char*>(Array<char*>&) ;
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p10.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p10.cpp
new file mode 100644
index 0000000..61f1710
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p10.cpp
@@ -0,0 +1,7 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<class T> class X;
+template<> class X<int>; // expected-note{{forward}}
+X<int>* p;
+
+X<int> x; // expected-error{{incomplete type}}
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p11.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p11.cpp
new file mode 100644
index 0000000..e794e67
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p11.cpp
@@ -0,0 +1,8 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<class T> class Array { /* ... */ };
+template<class T> void sort(Array<T>& v);
+
+// explicit specialization for sort(Array<int>&)
+// with deduced template-argument of type int
+template<> void sort(Array<int>&);
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p13.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p13.cpp
new file mode 100644
index 0000000..63cf9f5
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p13.cpp
@@ -0,0 +1,6 @@
+// RUN: clang-cc -fsyntax-only %s
+
+template<typename T> void f(T);
+
+template<> void f(int) { }
+void f(int) { }
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p14.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p14.cpp
new file mode 100644
index 0000000..a5d5b9e
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p14.cpp
@@ -0,0 +1,42 @@
+// RUN: clang-cc -emit-llvm -o - %s | FileCheck %s
+
+template<class T> void f(T) { /* ... */ }
+template<class T> inline void g(T) { /* ... */ }
+
+// CHECK: define void @_Z1gIiEvT_
+template<> void g<>(int) { /* ... */ }
+
+template<class T>
+struct X {
+ void f() { }
+ void g();
+ void h();
+};
+
+template<class T>
+void X<T>::g() {
+}
+
+template<class T>
+inline void X<T>::h() {
+}
+
+// CHECK: define void @_ZN1XIiE1fEv
+template<> void X<int>::f() { }
+
+// CHECK: define void @_ZN1XIiE1hEv
+template<> void X<int>::h() { }
+
+// CHECK: define linkonce_odr void @_Z1fIiEvT_
+template<> inline void f<>(int) { /* ... */ }
+
+// CHECK: define linkonce_odr void @_ZN1XIiE1gEv
+template<> inline void X<int>::g() { }
+
+void test(X<int> xi) {
+ f(17);
+ g(17);
+ xi.f();
+ xi.g();
+ xi.h();
+}
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p15.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p15.cpp
new file mode 100644
index 0000000..840f566
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p15.cpp
@@ -0,0 +1,22 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+struct NonDefaultConstructible {
+ NonDefaultConstructible(const NonDefaultConstructible&);
+};
+
+template<typename T, typename U>
+struct X {
+ static T member;
+};
+
+template<typename T, typename U>
+T X<T, U>::member; // expected-error{{no matching constructor}}
+
+// Okay; this is a declaration, not a definition.
+template<>
+NonDefaultConstructible X<NonDefaultConstructible, long>::member;
+
+NonDefaultConstructible &test(bool b) {
+ return b? X<NonDefaultConstructible, int>::member // expected-note{{instantiation}}
+ : X<NonDefaultConstructible, long>::member;
+}
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p16.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p16.cpp
new file mode 100644
index 0000000..ce40afd
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p16.cpp
@@ -0,0 +1,26 @@
+// RUN: clang-cc -fsyntax-only %s
+template<class T> struct A {
+ void f(T);
+ template<class X1> void g1(T, X1);
+ template<class X2> void g2(T, X2);
+ void h(T) { }
+};
+
+// specialization
+template<> void A<int>::f(int);
+
+// out of class member template definition
+template<class T> template<class X1> void A<T>::g1(T, X1) { }
+
+// member template specialization
+template<> template<class X1> void A<int>::g1(int, X1);
+
+// member template specialization
+template<> template<>
+ void A<int>::g1(int, char); // X1 deduced as char
+
+template<> template<>
+ void A<int>::g2<char>(int, char); // X2 specified as char
+ // member specialization even if defined in class definition
+
+template<> void A<int>::h(int) { }
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p17.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p17.cpp
new file mode 100644
index 0000000..883cb71
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p17.cpp
@@ -0,0 +1,12 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+template<class T1>
+class A {
+ template<class T2> class B {
+ void mf();
+ };
+};
+
+template<> template<> class A<int>::B<double>;
+template<> template<> void A<char>::B<char>::mf();
+
+template<> void A<char>::B<int>::mf(); // expected-error{{requires 'template<>'}}
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p18.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p18.cpp
new file mode 100644
index 0000000..a5877d2
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p18.cpp
@@ -0,0 +1,20 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+template<class T1> class A {
+ template<class T2> class B {
+ template<class T3> void mf1(T3);
+ void mf2();
+ };
+};
+
+template<> template<class X>
+class A<long>::B { };
+
+template<> template<> template<class T>
+ void A<int>::B<double>::mf1(T t) { }
+
+template<> template<> template<class T>
+void A<long>::B<double>::mf1(T t) { } // expected-error{{does not match}}
+
+// FIXME: This diagnostic could probably be better.
+template<class Y> template<>
+ void A<Y>::B<double>::mf2() { } // expected-error{{does not refer}}
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p19.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p19.cpp
new file mode 100644
index 0000000..1f38e5a
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p19.cpp
@@ -0,0 +1,30 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T>
+struct X {
+ template<typename U> struct Inner { };
+
+ template<typename U> void f(T, U) { }
+};
+
+template<> template<typename U>
+struct X<int>::Inner {
+ U member;
+};
+
+template<> template<typename U>
+void X<int>::f(int x, U y) {
+ x = y; // expected-error{{incompatible type}}
+}
+
+void test(X<int> xi, X<long> xl, float *fp) {
+ X<int>::Inner<float*> xii;
+ xii.member = fp;
+ xi.f(17, 25);
+ xi.f(17, 3.14159);
+ xi.f(17, fp); // expected-note{{instantiation}}
+ X<long>::Inner<float*> xli;
+
+ xli.member = fp; // expected-error{{no member}}
+ xl.f(17, fp); // okay
+}
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp
new file mode 100644
index 0000000..6485660
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp
@@ -0,0 +1,239 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// This test creates cases where implicit instantiations of various entities
+// would cause a diagnostic, but provides expliict specializations for those
+// entities that avoid the diagnostic. The specializations are alternately
+// declarations and definitions, and the intent of this test is to verify
+// that we allow specializations only in the appropriate namespaces (and
+// nowhere else).
+struct NonDefaultConstructible {
+ NonDefaultConstructible(int);
+};
+
+
+// C++ [temp.expl.spec]p1:
+// An explicit specialization of any of the following:
+
+// -- function template
+namespace N0 {
+ template<typename T> void f0(T) { // expected-note{{here}}
+ T t;
+ }
+
+ template<> void f0(NonDefaultConstructible) { }
+
+ void test_f0(NonDefaultConstructible NDC) {
+ f0(NDC);
+ }
+
+ template<> void f0(int);
+ template<> void f0(long);
+}
+
+template<> void N0::f0(int) { } // okay
+
+namespace N1 {
+ template<> void N0::f0(long) { } // expected-error{{not in a namespace enclosing}}
+}
+
+template<> void N0::f0(double) { } // expected-error{{originally be declared}}
+
+struct X1 {
+ template<typename T> void f(T);
+
+ template<> void f(int); // expected-error{{in class scope}}
+};
+
+// -- class template
+namespace N0 {
+
+template<typename T>
+struct X0 { // expected-note 2{{here}}
+ static T member; // expected-note{{here}}
+
+ void f1(T t) { // expected-note{{explicitly specialized declaration is here}}
+ t = 17;
+ }
+
+ struct Inner : public T { }; // expected-note 3{{here}}
+
+ template<typename U>
+ struct InnerTemplate : public T { }; // expected-note 2{{explicitly specialized}} \
+ // expected-error{{base specifier}}
+
+ template<typename U>
+ void ft1(T t, U u); // expected-note{{explicitly specialized}}
+};
+
+}
+
+template<typename T>
+template<typename U>
+void N0::X0<T>::ft1(T t, U u) {
+ t = u;
+}
+
+template<typename T> T N0::X0<T>::member;
+
+template<> struct N0::X0<void> { }; // expected-error{{originally}}
+N0::X0<void> test_X0;
+
+namespace N1 {
+ template<> struct N0::X0<const void> { }; // expected-error{{originally}}
+}
+
+namespace N0 {
+ template<> struct X0<volatile void>;
+}
+
+template<> struct N0::X0<volatile void> {
+ void f1(void *);
+};
+
+// -- member function of a class template
+template<> void N0::X0<void*>::f1(void *) { } // expected-error{{member function specialization}}
+
+void test_spec(N0::X0<void*> xvp, void *vp) {
+ xvp.f1(vp);
+}
+
+namespace N0 {
+ template<> void X0<volatile void>::f1(void *) { } // expected-error{{no function template matches}}
+
+ template<> void X0<const volatile void*>::f1(const volatile void*);
+}
+
+void test_x0_cvvoid(N0::X0<const volatile void*> x0, const volatile void *cvp) {
+ x0.f1(cvp); // okay: we've explicitly specialized
+}
+
+// -- static data member of a class template
+namespace N0 {
+ // This actually tests p15; the following is a declaration, not a definition.
+ template<>
+ NonDefaultConstructible X0<NonDefaultConstructible>::member;
+
+ template<> long X0<long>::member = 17;
+
+ template<> float X0<float>::member;
+
+ template<> double X0<double>::member;
+}
+
+NonDefaultConstructible &get_static_member() {
+ return N0::X0<NonDefaultConstructible>::member;
+}
+
+template<> int N0::X0<int>::member; // expected-error{{originally}}
+
+template<> float N0::X0<float>::member = 3.14f;
+
+namespace N1 {
+ template<> double N0::X0<double>::member = 3.14; // expected-error{{not in a namespace enclosing}}
+}
+
+// -- member class of a class template
+namespace N0 {
+
+ template<>
+ struct X0<void*>::Inner { };
+
+ template<>
+ struct X0<int>::Inner { };
+
+ template<>
+ struct X0<unsigned>::Inner;
+
+ template<>
+ struct X0<float>::Inner;
+
+ template<>
+ struct X0<double>::Inner; // expected-note{{forward declaration}}
+}
+
+template<>
+struct N0::X0<long>::Inner { }; // expected-error{{originally}}
+
+template<>
+struct N0::X0<float>::Inner { };
+
+namespace N1 {
+ template<>
+ struct N0::X0<unsigned>::Inner { }; // expected-error{{member class specialization}}
+
+ template<>
+ struct N0::X0<unsigned long>::Inner { }; // expected-error{{member class specialization}}
+};
+
+N0::X0<void*>::Inner inner0;
+N0::X0<int>::Inner inner1;
+N0::X0<long>::Inner inner2;
+N0::X0<float>::Inner inner3;
+N0::X0<double>::Inner inner4; // expected-error{{incomplete}}
+
+// -- member class template of a class template
+namespace N0 {
+ template<>
+ template<>
+ struct X0<void*>::InnerTemplate<int> { };
+
+ template<> template<>
+ struct X0<int>::InnerTemplate<int>; // expected-note{{forward declaration}}
+
+ template<> template<>
+ struct X0<int>::InnerTemplate<long>;
+
+ template<> template<>
+ struct X0<int>::InnerTemplate<double>;
+}
+
+template<> template<>
+struct N0::X0<int>::InnerTemplate<long> { }; // okay
+
+template<> template<>
+struct N0::X0<int>::InnerTemplate<float> { }; // expected-error{{class template specialization}}
+
+namespace N1 {
+ template<> template<>
+ struct N0::X0<int>::InnerTemplate<double> { }; // expected-error{{enclosing}}
+}
+
+N0::X0<void*>::InnerTemplate<int> inner_template0;
+N0::X0<int>::InnerTemplate<int> inner_template1; // expected-error{{incomplete}}
+N0::X0<int>::InnerTemplate<long> inner_template2;
+N0::X0<int>::InnerTemplate<unsigned long> inner_template3; // expected-note{{instantiation}}
+
+// -- member function template of a class template
+namespace N0 {
+ template<>
+ template<>
+ void X0<void*>::ft1(void*, const void*) { }
+
+ template<> template<>
+ void X0<void*>::ft1(void *, int);
+
+ template<> template<>
+ void X0<void*>::ft1(void *, unsigned);
+
+ template<> template<>
+ void X0<void*>::ft1(void *, long);
+}
+
+template<> template<>
+void N0::X0<void*>::ft1(void *, unsigned) { } // okay
+
+template<> template<>
+void N0::X0<void*>::ft1(void *, float) { } // expected-error{{function template specialization}}
+
+namespace N1 {
+ template<> template<>
+ void N0::X0<void*>::ft1(void *, long) { } // expected-error{{enclosing}}
+}
+
+
+void test_func_template(N0::X0<void *> xvp, void *vp, const void *cvp,
+ int i, unsigned u) {
+ xvp.ft1(vp, cvp);
+ xvp.ft1(vp, i);
+ xvp.ft1(vp, u);
+}
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p20.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p20.cpp
new file mode 100644
index 0000000..d270b81
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p20.cpp
@@ -0,0 +1,14 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+template<typename T>
+void f(T);
+
+template<typename T>
+struct A { };
+
+struct X {
+ template<> friend void f<int>(int); // expected-error{{in class scope}}
+ template<> friend class A<int>; // expected-error{{cannot be a friend}}
+
+ friend void f<float>(float); // okay
+ friend class A<float>; // okay
+};
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p21.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p21.cpp
new file mode 100644
index 0000000..9dae3eb
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p21.cpp
@@ -0,0 +1,30 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T>
+struct X {
+ void mf1(T);
+ template<typename U> void mf2(T, U); // expected-note{{previous}}
+};
+
+template<>
+void X<int>::mf1(int i = 17) // expected-error{{default}}
+{
+}
+
+template<> template<>
+void X<int>::mf2(int, int = 17) // expected-error{{default}}
+{ }
+
+template<> template<typename U>
+void X<int>::mf2(int, U = U()) // expected-error{{default}}
+{
+}
+
+template<>
+struct X<float> {
+ void mf1(float);
+};
+
+void X<float>::mf1(float = 3.14f) // okay
+{
+}
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p3.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p3.cpp
new file mode 100644
index 0000000..2bd1400
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p3.cpp
@@ -0,0 +1,14 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+namespace N {
+ template<class T> class X;
+}
+
+// FIXME: this diagnostic is terrible (PR3844).
+template<> class X<int> { /* ... */ }; // expected-error {{unqualified-id}}
+
+namespace N {
+
+template<> class X<char*> { /* ... */ }; // OK: X is a template
+
+} \ No newline at end of file
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p4.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p4.cpp
new file mode 100644
index 0000000..8d91068
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p4.cpp
@@ -0,0 +1,59 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+struct IntHolder { // expected-note{{here}}
+ IntHolder(int);
+};
+
+template<typename T, typename U>
+struct X { // expected-note{{here}}
+ void f() {
+ T t; // expected-error{{no matching}}
+ }
+
+ void g() { }
+
+ struct Inner {
+ T value; // expected-note {{member is declared here}}
+ };
+
+ static T value;
+};
+
+template<typename T, typename U>
+T X<T, U>::value; // expected-error{{no matching constructor}}
+
+IntHolder &test_X_IntHolderInt(X<IntHolder, int> xih) {
+ xih.g(); // okay
+ xih.f(); // expected-note{{instantiation}}
+
+ // FIXME: diagnostic here has incorrect reason (PR5154)
+ X<IntHolder, int>::Inner inner; // expected-error{{implicit default}}
+
+ return X<IntHolder, int>::value; // expected-note{{instantiation}}
+}
+
+// Explicitly specialize the members of X<IntHolder, long> to not cause
+// problems with instantiation.
+template<>
+void X<IntHolder, long>::f() { }
+
+template<>
+struct X<IntHolder, long>::Inner {
+ Inner() : value(17) { }
+ IntHolder value;
+};
+
+template<>
+IntHolder X<IntHolder, long>::value = 17;
+
+IntHolder &test_X_IntHolderInt(X<IntHolder, long> xih) {
+ xih.g(); // okay
+ xih.f(); // okay, uses specialization
+
+ X<IntHolder, long>::Inner inner; // okay, uses specialization
+
+ return X<IntHolder, long>::value; // okay, uses specialization
+}
+
+template<>
+X<IntHolder, long>::X() { } // expected-error{{instantiated member}}
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p5.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p5.cpp
new file mode 100644
index 0000000..58682c7
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p5.cpp
@@ -0,0 +1,61 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+struct IntHolder {
+ IntHolder(int);
+};
+
+template<typename T, typename U>
+struct X {
+ void f() {
+ T t;
+ }
+
+ void g() { }
+
+ struct Inner {
+ T value;
+ };
+
+ static T value;
+};
+
+template<typename T, typename U>
+T X<T, U>::value;
+
+// Explicitly specialize the members of X<IntHolder, long> to not cause
+// problems with instantiation, but only provide declarations (not definitions).
+template<>
+void X<IntHolder, long>::f();
+
+template<>
+struct X<IntHolder, long>::Inner; // expected-note{{forward declaration}}
+
+template<>
+IntHolder X<IntHolder, long>::value;
+
+IntHolder &test_X_IntHolderInt(X<IntHolder, long> xih) {
+ xih.g(); // okay
+ xih.f(); // okay, uses specialization
+
+ X<IntHolder, long>::Inner inner; // expected-error {{incomplete}}
+
+ return X<IntHolder, long>::value; // okay, uses specialization
+}
+
+
+template<class T> struct A {
+ void f(T) { /* ... */ }
+};
+
+template<> struct A<int> {
+ void f(int);
+};
+
+void h() {
+ A<int> a;
+ a.f(16); // A<int>::f must be defined somewhere
+}
+
+// explicit specialization syntax not used for a member of
+// explicitly specialized class template specialization
+void A<int>::f(int) { /* ... */ }
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p6.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p6.cpp
new file mode 100644
index 0000000..e92d3f0
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p6.cpp
@@ -0,0 +1,56 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T>
+struct X0 {
+ void f();
+
+ template<typename U>
+ void g(U);
+
+ struct Nested {
+ };
+
+ static T member;
+};
+
+int &use_X0_int(X0<int> x0i, // expected-note{{implicit instantiation first required here}}
+ int i) {
+ x0i.f(); // expected-note{{implicit instantiation first required here}}
+ x0i.g(i); // expected-note{{implicit instantiation first required here}}
+ X0<int>::Nested nested; // expected-note{{implicit instantiation first required here}}
+ return X0<int>::member; // expected-note{{implicit instantiation first required here}}
+}
+
+template<>
+void X0<int>::f() { // expected-error{{after instantiation}}
+}
+
+template<> template<>
+void X0<int>::g(int) { // expected-error{{after instantiation}}
+}
+
+template<>
+struct X0<int>::Nested { }; // expected-error{{after instantiation}}
+
+template<>
+int X0<int>::member = 17; // expected-error{{after instantiation}}
+
+template<>
+struct X0<int> { }; // expected-error{{after instantiation}}
+
+// Example from the standard
+template<class T> class Array { /* ... */ };
+
+template<class T> void sort(Array<T>& v) { /* ... */ }
+
+struct String {};
+
+void f(Array<String>& v) {
+
+ sort(v); // expected-note{{required}}
+ // use primary template
+ // sort(Array<T>&), T is String
+}
+
+template<> void sort<String>(Array<String>& v); // // expected-error{{after instantiation}}
+template<> void sort<>(Array<char*>& v); // OK: sort<char*> not yet used
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p9.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p9.cpp
new file mode 100644
index 0000000..49481d2
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p9.cpp
@@ -0,0 +1,14 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+namespace N {
+ template<class T> class X { /* ... */ };
+ template<class T> class Y { /* ... */ };
+ template<> class X<int> { /* ... */ };
+ template<> class Y<double>;
+
+ const unsigned NumElements = 17;
+}
+
+template<> class N::Y<double> {
+ int array[NumElements];
+};
diff --git a/test/CodeCompletion/call.cpp b/test/CodeCompletion/call.cpp
new file mode 100644
index 0000000..90bf82b
--- /dev/null
+++ b/test/CodeCompletion/call.cpp
@@ -0,0 +1,28 @@
+// Note: the run lines follow their respective tests, since line/column
+// matter in this test.
+void f(float x, float y);
+void f(int i, int j, int k);
+struct X { };
+void f(X);
+namespace N {
+ struct Y {
+ Y(int = 0);
+
+ operator int() const;
+ };
+ void f(Y y, int ZZ);
+}
+typedef N::Y Y;
+void f();
+
+void test() {
+ f(Y(), 0, 0);
+ // RUN: clang-cc -fsyntax-only -code-completion-at=%s:19:9 %s -o - | FileCheck -check-prefix=CC1 %s &&
+ // CHECK-CC1: f(struct N::Y y, <#int ZZ#>)
+ // CHECK-CC1-NEXT: f(int i, <#int j#>, int k)
+ // CHECK-CC1-NEXT: f(float x, <#float y#>)
+ // RUN: clang-cc -fsyntax-only -code-completion-at=%s:19:13 %s -o - | FileCheck -check-prefix=CC2 %s &&
+ // CHECK-CC2-NOT: f(struct N::Y y, int ZZ)
+ // CHECK-CC2: f(int i, int j, <#int k#>)
+ // RUN: true
+}
diff --git a/test/CodeCompletion/enum-switch-case-qualified.cpp b/test/CodeCompletion/enum-switch-case-qualified.cpp
new file mode 100644
index 0000000..223aca8
--- /dev/null
+++ b/test/CodeCompletion/enum-switch-case-qualified.cpp
@@ -0,0 +1,33 @@
+namespace M {
+
+namespace N {
+ struct C {
+ enum Color {
+ Red,
+ Orange,
+ Yellow,
+ Green,
+ Blue,
+ Indigo,
+ Violet
+ };
+ };
+}
+
+}
+
+namespace M {
+
+void test(enum N::C::Color color) {
+ switch (color) {
+ case
+ // RUN: clang-cc -fsyntax-only -code-completion-at=%s:23:8 %s -o - | FileCheck -check-prefix=CC1 %s &&
+ // RUN: true
+ // CHECK-CC1: Blue : 0 : N::C::Blue
+ // CHECK-CC1-NEXT: Green : 0 : N::C::Green
+ // CHECK-CC1-NEXT: Indigo : 0 : N::C::Indigo
+ // CHECK-CC1-NEXT: Orange : 0 : N::C::Orange
+ // CHECK-CC1-NEXT: Red : 0 : N::C::Red
+ // CHECK-CC1-NEXT: Violet : 0 : N::C::Violet
+ // CHECK-CC1: Yellow : 0 : N::C::Yellow
+
diff --git a/test/CodeCompletion/enum-switch-case.c b/test/CodeCompletion/enum-switch-case.c
new file mode 100644
index 0000000..d8bb5e8
--- /dev/null
+++ b/test/CodeCompletion/enum-switch-case.c
@@ -0,0 +1,29 @@
+enum Color {
+ Red,
+ Orange,
+ Yellow,
+ Green,
+ Blue,
+ Indigo,
+ Violet
+};
+
+void test(enum Color color) {
+ switch (color) {
+ case Red:
+ break;
+
+ case Yellow:
+ break;
+
+ case Green:
+ break;
+
+ // RUN: clang-cc -fsyntax-only -code-completion-at=%s:19:10 %s -o - | FileCheck -check-prefix=CC1 %s &&
+ // CHECK-CC1: Blue : 0
+ // CHECK-CC1-NEXT: Green : 0
+ // CHECK-CC1-NEXT: Indigo : 0
+ // CHECK-CC1-NEXT: Orange : 0
+ // CHECK-CC1-NEXT: Violet : 0
+ // RUN: true
+
diff --git a/test/CodeCompletion/enum-switch-case.cpp b/test/CodeCompletion/enum-switch-case.cpp
new file mode 100644
index 0000000..7a388fc
--- /dev/null
+++ b/test/CodeCompletion/enum-switch-case.cpp
@@ -0,0 +1,29 @@
+namespace N {
+ enum Color {
+ Red,
+ Orange,
+ Yellow,
+ Green,
+ Blue,
+ Indigo,
+ Violet
+ };
+}
+
+void test(enum N::Color color) {
+ switch (color) {
+ case N::Red:
+ break;
+
+ case N::Yellow:
+ break;
+
+ case
+ // RUN: clang-cc -fsyntax-only -code-completion-at=%s:21:8 %s -o - | FileCheck -check-prefix=CC1 %s &&
+ // CHECK-CC1: Blue : 0 : N::Blue
+ // CHECK-CC1-NEXT: Green : 0 : N::Green
+ // CHECK-CC1-NEXT: Indigo : 0 : N::Indigo
+ // CHECK-CC1-NEXT: Orange : 0 : N::Orange
+ // CHECK-CC1-NEXT: Violet : 0 : N::Violet
+
+ // RUN: true
diff --git a/test/CodeCompletion/function-templates.cpp b/test/CodeCompletion/function-templates.cpp
new file mode 100644
index 0000000..52cba71
--- /dev/null
+++ b/test/CodeCompletion/function-templates.cpp
@@ -0,0 +1,15 @@
+namespace std {
+ template<typename RandomAccessIterator>
+ void sort(RandomAccessIterator first, RandomAccessIterator last);
+
+ template<class X, class Y>
+ X* dyn_cast(Y *Val);
+}
+
+void f() {
+ std::
+ // RUN: clang-cc -fsyntax-only -code-completion-at=%s:10:8 %s -o - | FileCheck -check-prefix=CC1 %s &&
+ // CHECK-CC1: dyn_cast<<#class X#>>(<#Y *Val#>)
+ // CHECK-CC1: sort(<#RandomAccessIterator first#>, <#RandomAccessIterator last#>)
+ // RUN: true
+
diff --git a/test/CodeCompletion/functions.cpp b/test/CodeCompletion/functions.cpp
new file mode 100644
index 0000000..2e1bc6e
--- /dev/null
+++ b/test/CodeCompletion/functions.cpp
@@ -0,0 +1,9 @@
+void f(int i, int j = 2, int k = 5);
+void f(float x, float y...);
+
+void test() {
+ ::
+ // RUN: clang-cc -fsyntax-only -code-completion-at=%s:5:5 %s -o - | FileCheck -check-prefix=CC1 %s &&
+ // CHECK-CC1: f(<#int i#>{#, <#int j#>{#, <#int k#>#}#})
+ // CHECK-CC1: f(<#float x#>, <#float y#><#, ...#>)
+ // RUN: true
diff --git a/test/CodeCompletion/member-access.c b/test/CodeCompletion/member-access.c
new file mode 100644
index 0000000..1e8e563
--- /dev/null
+++ b/test/CodeCompletion/member-access.c
@@ -0,0 +1,13 @@
+struct Point {
+ float x;
+ float y;
+ float z;
+};
+
+void test(struct Point *p) {
+ p->
+ // RUN: clang-cc -fsyntax-only -code-completion-at=%s:8:6 %s -o - | FileCheck -check-prefix=CC1 %s &&
+ // CHECK-CC1: x
+ // CHECK-CC1: y
+ // CHECK-CC1: z
+ // RUN: true
diff --git a/test/CodeCompletion/member-access.cpp b/test/CodeCompletion/member-access.cpp
new file mode 100644
index 0000000..b810366
--- /dev/null
+++ b/test/CodeCompletion/member-access.cpp
@@ -0,0 +1,43 @@
+struct Base1 {
+ int member1;
+ float member2;
+};
+
+struct Base2 {
+ int member1;
+ double member3;
+ void memfun1(int);
+};
+
+struct Base3 : Base1, Base2 {
+ void memfun1(float);
+ void memfun1(double);
+ void memfun2(int);
+};
+
+struct Derived : Base3 {
+ int member4;
+ int memfun3(int);
+};
+
+class Proxy {
+public:
+ Derived *operator->() const;
+};
+
+void test(const Proxy &p) {
+ p->
+ // RUN: clang-cc -fsyntax-only -code-completion-at=%s:29:6 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s &&
+ // CHECK-CC1: member1 : 0 : [#Base1::#]member1
+ // CHECK-CC1: member1 : 0 : [#Base2::#]member1
+ // CHECK-CC1: member2 : 0 : [#Base1::#]member2
+ // CHECK-CC1: member3 : 0
+ // CHECK-CC1: member4 : 0
+ // CHECK-CC1: memfun1 : 0 : [#Base3::#]memfun1(<#float#>)
+ // CHECK-CC1: memfun1 : 0 : [#Base3::#]memfun1(<#double#>)
+ // CHECK-CC1: memfun2 : 0 : [#Base3::#]memfun2(<#int#>)
+ // CHECK-CC1: memfun3 : 0 : memfun3(<#int#>)
+ // CHECK-CC1: Base1 : 0 : Base1::
+ // CHECK-CC1: memfun1 : 0 (Hidden) : Base2::memfun1(<#int#>)
+ // RUN: true
+
diff --git a/test/CodeCompletion/namespace-alias.cpp b/test/CodeCompletion/namespace-alias.cpp
new file mode 100644
index 0000000..0fa2ec2
--- /dev/null
+++ b/test/CodeCompletion/namespace-alias.cpp
@@ -0,0 +1,21 @@
+namespace N4 {
+ namespace N3 { }
+}
+
+class N3;
+
+namespace N2 {
+ namespace I1 { }
+ namespace I4 = I1;
+ namespace I5 { }
+ namespace I1 { }
+
+ namespace New =
+ // RUN: clang-cc -fsyntax-only -code-completion-at=%s:13:18 %s -o - | FileCheck -check-prefix=CC1 %s &&
+ // CHECK-CC1: I1 : 1
+ // CHECK-CC1: I4 : 1
+ // CHECK-CC1: I5 : 1
+ // CHECK-CC1: N2 : 3
+ // CHECK-CC1-NEXT: N4 : 3
+ // RUN: true
+
diff --git a/test/CodeCompletion/namespace.cpp b/test/CodeCompletion/namespace.cpp
new file mode 100644
index 0000000..d4ed639
--- /dev/null
+++ b/test/CodeCompletion/namespace.cpp
@@ -0,0 +1,15 @@
+namespace N3 {
+}
+
+namespace N2 {
+ namespace I1 { }
+ namespace I4 = I1;
+ namespace I5 { }
+ namespace I1 { }
+
+ namespace
+ // RUN: clang-cc -fsyntax-only -code-completion-at=%s:10:12 %s -o - | FileCheck -check-prefix=CC1 %s &&
+ // CHECK-CC1: I1 : 0
+ // CHECK-CC1-NEXT: I5 : 0
+ // RUN: true
+
diff --git a/test/CodeCompletion/nested-name-specifier.cpp b/test/CodeCompletion/nested-name-specifier.cpp
new file mode 100644
index 0000000..0cc5a19
--- /dev/null
+++ b/test/CodeCompletion/nested-name-specifier.cpp
@@ -0,0 +1,18 @@
+namespace N {
+ struct A { };
+ namespace M {
+ struct C { };
+ };
+}
+
+namespace N {
+ struct B { };
+}
+
+N::
+// RUN: clang-cc -fsyntax-only -code-completion-at=%s:12:4 %s -o - | FileCheck -check-prefix=CC1 %s &&
+// CHECK-CC1: A : 0
+// CHECK-CC1: B : 0
+// CHECK-CC1: M : 0
+// RUN: true
+
diff --git a/test/CodeCompletion/operator.cpp b/test/CodeCompletion/operator.cpp
new file mode 100644
index 0000000..a3950f6
--- /dev/null
+++ b/test/CodeCompletion/operator.cpp
@@ -0,0 +1,18 @@
+class T { };
+
+typedef int Integer;
+
+namespace N { }
+
+void f() {
+ typedef float Float;
+
+ operator
+ // RUN: clang-cc -fsyntax-only -code-completion-at=%s:10:11 %s -o - | FileCheck -check-prefix=CC1 %s &&
+ // CHECK-CC1: Float : 0
+ // CHECK-CC1: + : 0
+ // CHECK-CC1: short : 0
+ // CHECK-CC1: Integer : 2
+ // CHECK-CC1: T : 2
+ // CHECK-CC1: N : 6
+ // RUN: true
diff --git a/test/CodeCompletion/ordinary-name.c b/test/CodeCompletion/ordinary-name.c
new file mode 100644
index 0000000..586e2b3
--- /dev/null
+++ b/test/CodeCompletion/ordinary-name.c
@@ -0,0 +1,12 @@
+struct X { int x; };
+
+typedef struct t TYPEDEF;
+
+void foo() {
+ int y;
+ // RUN: clang-cc -fsyntax-only -code-completion-at=%s:6:9 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s &&
+ // CHECK-CC1: y : 0
+ // CHECK-CC1: foo : 2
+ // CHECK-NOT-CC1: y : 2
+ // CHECK-CC1-NEXT: TYPEDEF : 2
+ // RUN: true
diff --git a/test/CodeCompletion/property.m b/test/CodeCompletion/property.m
new file mode 100644
index 0000000..7f2321e
--- /dev/null
+++ b/test/CodeCompletion/property.m
@@ -0,0 +1,29 @@
+// Note: the run lines follow their respective tests, since line/column
+// matter in this test.
+
+@interface Foo {
+ void *isa;
+}
+@property(copy) Foo *myprop;
+@property(retain, nonatomic) id xx;
+// RUN: clang-cc -fsyntax-only -code-completion-at=%s:7:11 %s -o - | FileCheck -check-prefix=CC1 %s &&
+// CC1: assign
+// CC1-NEXT: copy
+// CC1-NEXT: getter
+// CC1-NEXT: nonatomic
+// CC1-NEXT: readonly
+// CC1-NEXT: readwrite
+// CC1-NEXT: retain
+// CC1-NEXT: setter
+// RUN: clang-cc -fsyntax-only -code-completion-at=%s:8:18 %s -o - | FileCheck -check-prefix=CC2 %s
+// CC2: assign
+// CC2-NEXT: copy
+// CC2-NEXT: getter
+// CC2-NEXT: nonatomic
+// CC2-NEXT: readonly
+// CC2-NEXT: readwrite
+// CC2-NEXT: setter
+@end
+
+
+
diff --git a/test/CodeCompletion/tag.c b/test/CodeCompletion/tag.c
new file mode 100644
index 0000000..e7250f5
--- /dev/null
+++ b/test/CodeCompletion/tag.c
@@ -0,0 +1,13 @@
+enum X { x };
+enum Y { y };
+struct Z { };
+
+void X();
+
+void test() {
+ enum X { x };
+ enum
+ // RUN: clang-cc -fsyntax-only -code-completion-at=%s:9:7 %s -o - | FileCheck -check-prefix=CC1 %s &&
+ // CHECK-CC1: X : 0
+ // CHECK-CC1: Y : 2
+ // RUN: true
diff --git a/test/CodeCompletion/tag.cpp b/test/CodeCompletion/tag.cpp
new file mode 100644
index 0000000..b00ff1f
--- /dev/null
+++ b/test/CodeCompletion/tag.cpp
@@ -0,0 +1,26 @@
+class X { };
+struct Y { };
+
+namespace N {
+ template<typename> class Z;
+}
+
+namespace M {
+ class A;
+}
+using M::A;
+
+namespace N {
+ class Y;
+
+ void test() {
+ class
+ // RUN: clang-cc -fsyntax-only -code-completion-at=%s:17:10 %s -o - | FileCheck -check-prefix=CC1 %s &&
+ // CHECK-CC1: Y : 2
+ // CHECK-CC1: Z : 2
+ // CHECK-CC1: A : 4
+ // CHECK-CC1: X : 4
+ // CHECK-CC1: Y : 4
+ // CHECK-CC1: M : 9 : M::
+ // CHECK-CC1: N : 9 : N::
+ // RUN: true
diff --git a/test/CodeCompletion/templates.cpp b/test/CodeCompletion/templates.cpp
new file mode 100644
index 0000000..22cca65
--- /dev/null
+++ b/test/CodeCompletion/templates.cpp
@@ -0,0 +1,17 @@
+namespace std {
+ template<typename T>
+ class allocator;
+
+ template<typename T, typename Alloc = std::allocator<T> >
+ class vector;
+}
+
+void f() {
+ std::
+ // RUN: clang-cc -fsyntax-only -code-completion-at=%s:10:8 %s -o - | FileCheck -check-prefix=CC1 %s &&
+ // CHECK-CC1: allocator<<#typename T#>>
+ // CHECK-CC1: vector<<#typename T#>{#, <#typename Alloc#>#}>
+ // RUN: true
+
+
+
diff --git a/test/CodeCompletion/truncation.c b/test/CodeCompletion/truncation.c
new file mode 100644
index 0000000..b72aa7f
--- /dev/null
+++ b/test/CodeCompletion/truncation.c
@@ -0,0 +1,12 @@
+#include "truncation.c.h"
+
+struct
+
+// RUN: clang-cc -fsyntax-only -code-completion-at=%s.h:4:8 -o - %s | FileCheck -check-prefix=CC1 %s &&
+// CHECK-CC1: X : 1
+// CHECK-CC1-NEXT: Y : 1
+// RUN: clang-cc -fsyntax-only -code-completion-at=%s:3:8 -o - %s | FileCheck -check-prefix=CC2 %s &&
+// CHECK-CC2: X : 1
+// CHECK-CC2: Xa : 1
+// CHECK-CC2: Y : 1
+// RUN: true
diff --git a/test/CodeCompletion/truncation.c.h b/test/CodeCompletion/truncation.c.h
new file mode 100644
index 0000000..a5ebbac
--- /dev/null
+++ b/test/CodeCompletion/truncation.c.h
@@ -0,0 +1,5 @@
+struct X { };
+struct Y { };
+
+struct Xa { };
+
diff --git a/test/CodeCompletion/using-namespace.cpp b/test/CodeCompletion/using-namespace.cpp
new file mode 100644
index 0000000..a332b88
--- /dev/null
+++ b/test/CodeCompletion/using-namespace.cpp
@@ -0,0 +1,21 @@
+namespace N4 {
+ namespace N3 { }
+}
+
+class N3;
+
+namespace N2 {
+ namespace I1 { }
+ namespace I4 = I1;
+ namespace I5 { }
+ namespace I1 { }
+
+ void foo() {
+ using namespace
+ // RUN: clang-cc -fsyntax-only -code-completion-at=%s:14:20 %s -o - | FileCheck -check-prefix=CC1 %s &&
+ // CHECK-CC1: I1 : 2
+ // CHECK-CC1: I4 : 2
+ // CHECK-CC1: I5 : 2
+ // CHECK-CC1: N2 : 4
+ // CHECK-CC1-NEXT: N4 : 4
+ // RUN: true
diff --git a/test/CodeCompletion/using.cpp b/test/CodeCompletion/using.cpp
new file mode 100644
index 0000000..57b3aa7
--- /dev/null
+++ b/test/CodeCompletion/using.cpp
@@ -0,0 +1,25 @@
+namespace N4 {
+ namespace N3 { }
+}
+
+class N3;
+
+namespace N2 {
+ namespace I1 { }
+ namespace I4 = I1;
+ namespace I5 { }
+ namespace I1 { }
+
+ void foo() {
+ int N3;
+
+ using
+ // RUN: clang-cc -fsyntax-only -code-completion-at=%s:16:10 %s -o - | FileCheck -check-prefix=CC1 %s &&
+ // CHECK-CC1: I1 : 2
+ // CHECK-CC1: I4 : 2
+ // CHECK-CC1: I5 : 2
+ // CHECK-CC1: N2 : 4
+ // CHECK-CC1: N3 : 4
+ // CHECK-CC1-NEXT: N4 : 4
+ // RUN: true
+
diff --git a/test/CodeGen/2008-07-17-no-emit-on-error.c b/test/CodeGen/2008-07-17-no-emit-on-error.c
index 89aeb18..51ba2b4 100644
--- a/test/CodeGen/2008-07-17-no-emit-on-error.c
+++ b/test/CodeGen/2008-07-17-no-emit-on-error.c
@@ -1,5 +1,5 @@
-// RUN: rm -f %t1.bc
-// RUN: not clang-cc %s -emit-llvm-bc -o %t1.bc
+// RUN: rm -f %t1.bc &&
+// RUN: not clang-cc %s -emit-llvm-bc -o %t1.bc &&
// RUN: not test -f %t1.bc
void f() {
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
index 19bf9a2..348ea75 100644
--- 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
@@ -1,5 +1,4 @@
-// RUN: clang-cc --emit-llvm -o %t %s &&
-// RUN: grep "i8 52" %t | count 1
+// RUN: clang-cc -triple=i686-apple-darwin9 --emit-llvm -o - %s | FileCheck %s
struct et7 {
float lv7[0];
@@ -9,3 +8,5 @@ struct et7 {
52,
};
+// CHECK: @yv7 = global
+// CHECK: i8 52, \ No newline at end of file
diff --git a/test/CodeGen/2008-07-29-override-alias-decl.c b/test/CodeGen/2008-07-29-override-alias-decl.c
index 43f4e3e..4a36e0f 100644
--- a/test/CodeGen/2008-07-29-override-alias-decl.c
+++ b/test/CodeGen/2008-07-29-override-alias-decl.c
@@ -1,6 +1,6 @@
// RUN: clang-cc -emit-llvm -o - %s | grep -e "^@f" | count 1
-int x() {}
+int x() { return 1; }
int f() __attribute__((weak, alias("x")));
diff --git a/test/CodeGen/2009-01-21-invalid-debug-info.m b/test/CodeGen/2009-01-21-invalid-debug-info.m
index 9a955a1..2662b922 100644
--- a/test/CodeGen/2009-01-21-invalid-debug-info.m
+++ b/test/CodeGen/2009-01-21-invalid-debug-info.m
@@ -10,7 +10,7 @@
@interface I1 @end
@implementation I1
--im0 {}
+-im0 { return 0; }
@end
I1 *f1(void) { return 0; }
diff --git a/test/CodeGen/2009-04-23-dbg.c b/test/CodeGen/2009-04-23-dbg.c
index 4be6dab..c6b1791 100644
--- a/test/CodeGen/2009-04-23-dbg.c
+++ b/test/CodeGen/2009-04-23-dbg.c
@@ -1,4 +1,4 @@
-// RUN: clang-cc -g -o %t %s -emit-llvm-bc && llc %t -f -o %t.s
+// RUN: clang-cc -g -o %t %s -emit-llvm-bc && llc %t -o %t.s
# 1 "a.c"
# 1 "a.c" 1
# 1 "<built-in>" 1
diff --git a/test/CodeGen/2009-06-01-addrofknr.c b/test/CodeGen/2009-06-01-addrofknr.c
index 16a5bbf..d51a4a4 100644
--- a/test/CodeGen/2009-06-01-addrofknr.c
+++ b/test/CodeGen/2009-06-01-addrofknr.c
@@ -2,20 +2,20 @@
// PR4289
struct funcptr {
- int (*func)();
+ int (*func)();
};
static int func(f)
- void *f;
+ void *f;
{
+ return 0;
}
int
main(int argc, char *argv[])
{
- struct funcptr fp;
+ struct funcptr fp;
- fp.func = &func;
- fp.func = func;
+ fp.func = &func;
+ fp.func = func;
}
-
diff --git a/test/CodeGen/2009-07-31-DbgDeclare.c b/test/CodeGen/2009-07-31-DbgDeclare.c
new file mode 100644
index 0000000..da49afe
--- /dev/null
+++ b/test/CodeGen/2009-07-31-DbgDeclare.c
@@ -0,0 +1,5 @@
+// RUN: clang-cc -S -g -o %t.s %s
+void foo() {
+ int i = 0;
+ i = 42;
+}
diff --git a/test/CodeGen/2009-08-14-vararray-crash.c b/test/CodeGen/2009-08-14-vararray-crash.c
new file mode 100644
index 0000000..40e071b
--- /dev/null
+++ b/test/CodeGen/2009-08-14-vararray-crash.c
@@ -0,0 +1,11 @@
+// RUN: clang-cc -emit-llvm < %s
+
+void sum1(int rb) {
+ typedef unsigned char imgrow[rb];
+ typedef imgrow img[rb];
+
+ const img *br;
+ int y;
+
+ (*br)[y];
+}
diff --git a/test/CodeGen/PR3613-static-decl.c b/test/CodeGen/PR3613-static-decl.c
index 365b9b2..2083581 100644
--- a/test/CodeGen/PR3613-static-decl.c
+++ b/test/CodeGen/PR3613-static-decl.c
@@ -1,5 +1,5 @@
// RUN: clang-cc -triple i386-unknown-unknown -emit-llvm -o %t %s &&
-// RUN: grep '@g0 = internal global .struct.s0 <{ i32 3 }>' %t | count 1
+// RUN: grep '@g0 = internal global %.truct.s0 { i32 3 }' %t | count 1
struct s0 {
int a;
diff --git a/test/CodeGen/PR4611-bitfield-layout.c b/test/CodeGen/PR4611-bitfield-layout.c
new file mode 100644
index 0000000..83ce4ff
--- /dev/null
+++ b/test/CodeGen/PR4611-bitfield-layout.c
@@ -0,0 +1,6 @@
+// RUN: clang-cc -triple i386-unknown-unknown %s -emit-llvm -o %t &&
+// RUN: grep "struct.object_entry = type { i8, \[2 x i8\], i8 }" %t
+
+struct object_entry {
+ unsigned int type:3, pack_id:16, depth:13;
+} entries;
diff --git a/test/CodeGen/PR5060-align.c b/test/CodeGen/PR5060-align.c
new file mode 100644
index 0000000..5d86408
--- /dev/null
+++ b/test/CodeGen/PR5060-align.c
@@ -0,0 +1,13 @@
+// RUN: clang-cc -emit-llvm %s -o - -verify | FileCheck %s
+
+// CHECK: @foo.p = internal global i8 0, align 32
+char *foo(void) {
+ static char p __attribute__((aligned(32)));
+ return &p;
+}
+
+void bar(long n) {
+ // CHECK: align 32
+ char p[n] __attribute__((aligned(32)));
+}
+
diff --git a/test/CodeGen/address-space-compound-literal.c b/test/CodeGen/address-space-compound-literal.c
new file mode 100644
index 0000000..79d19ed
--- /dev/null
+++ b/test/CodeGen/address-space-compound-literal.c
@@ -0,0 +1,5 @@
+// RUN: clang-cc -emit-llvm < %s | grep "internal addrspace(1) global i32 1"
+
+typedef int a __attribute__((address_space(1)));
+a* x = &(a){1};
+
diff --git a/test/CodeGen/address-space-field1.c b/test/CodeGen/address-space-field1.c
new file mode 100644
index 0000000..f8ec83c
--- /dev/null
+++ b/test/CodeGen/address-space-field1.c
@@ -0,0 +1,39 @@
+// RUN: clang-cc -emit-llvm < %s -o - | FileCheck %s
+// CHECK:%struct.S = type { i32, i32 }
+// CHECK:define void @test_addrspace(%struct.S addrspace(1)* %p1, %struct.S addrspace(2)* %p2) nounwind
+// CHECK:entry:
+// CHECK: %p1.addr = alloca %struct.S addrspace(1)* ; <%struct.S addrspace(1)**> [#uses=3]
+// CHECK: %p2.addr = alloca %struct.S addrspace(2)* ; <%struct.S addrspace(2)**> [#uses=3]
+// CHECK: store %struct.S addrspace(1)* %p1, %struct.S addrspace(1)** %p1.addr
+// CHECK: store %struct.S addrspace(2)* %p2, %struct.S addrspace(2)** %p2.addr
+// CHECK: %tmp = load %struct.S addrspace(2)** %p2.addr ; <%struct.S addrspace(2)*> [#uses=1]
+// CHECK: %tmp1 = getelementptr inbounds %struct.S addrspace(2)* %tmp, i32 0, i32 1 ; <i32 addrspace(2)*> [#uses=1]
+// CHECK: %tmp2 = load i32 addrspace(2)* %tmp1 ; <i32> [#uses=1]
+// CHECK: %tmp3 = load %struct.S addrspace(1)** %p1.addr ; <%struct.S addrspace(1)*> [#uses=1]
+// CHECK: %tmp4 = getelementptr inbounds %struct.S addrspace(1)* %tmp3, i32 0, i32 0 ; <i32 addrspace(1)*> [#uses=1]
+// CHECK: store i32 %tmp2, i32 addrspace(1)* %tmp4
+// CHECK: %tmp5 = load %struct.S addrspace(2)** %p2.addr ; <%struct.S addrspace(2)*> [#uses=1]
+// CHECK: %tmp6 = getelementptr inbounds %struct.S addrspace(2)* %tmp5, i32 0, i32 0 ; <i32 addrspace(2)*> [#uses=1]
+// CHECK: %tmp7 = load i32 addrspace(2)* %tmp6 ; <i32> [#uses=1]
+// CHECK: %tmp8 = load %struct.S addrspace(1)** %p1.addr ; <%struct.S addrspace(1)*> [#uses=1]
+// CHECK: %tmp9 = getelementptr inbounds %struct.S addrspace(1)* %tmp8, i32 0, i32 1 ; <i32 addrspace(1)*> [#uses=1]
+// CHECK: store i32 %tmp7, i32 addrspace(1)* %tmp9
+// CHECK: ret void
+// CHECK:}
+
+// Check that we don't lose the address space when accessing a member
+// of a structure.
+
+#define __addr1 __attribute__((address_space(1)))
+#define __addr2 __attribute__((address_space(2)))
+
+typedef struct S {
+ int a;
+ int b;
+} S;
+
+void test_addrspace(__addr1 S* p1, __addr2 S*p2) {
+ // swap
+ p1->a = p2->b;
+ p1->b = p2->a;
+}
diff --git a/test/CodeGen/address-space-field2.c b/test/CodeGen/address-space-field2.c
new file mode 100644
index 0000000..5576e55
--- /dev/null
+++ b/test/CodeGen/address-space-field2.c
@@ -0,0 +1,50 @@
+// RUN: clang-cc -emit-llvm %s -o - | FileCheck %s
+// CHECK: addrspace(1)
+// CHECK: addrspace(2)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(2)
+// CHECK: addrspace(2)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(2)
+// CHECK: addrspace(2)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(2)
+// CHECK: addrspace(2)
+// CHECK: addrspace(2)
+// CHECK: addrspace(2)
+// CHECK: addrspace(2)
+// CHECK: addrspace(2)
+// CHECK: addrspace(2)
+// CHECK: addrspace(2)
+// CHECK: addrspace(2)
+// CHECK: addrspace(2)
+// CHECK: addrspace(2)
+
+// Check that we don't lose the address space when accessing an array element
+// inside a structure.
+
+#define __addr1 __attribute__((address_space(1)))
+#define __addr2 __attribute__((address_space(2)))
+
+typedef struct S {
+ int arr[ 3 ];
+} S;
+
+void test_addrspace(__addr1 S* p1, __addr2 S*p2, int* val, int n) {
+ for (int i=0; i < 3; ++i) {
+ int t = val[i];
+ p1->arr[i] = t;
+ for (int j=0; j < n; ++j)
+ p2[j].arr[i] = t;
+ }
+}
diff --git a/test/CodeGen/address-space-field3.c b/test/CodeGen/address-space-field3.c
new file mode 100644
index 0000000..567757f
--- /dev/null
+++ b/test/CodeGen/address-space-field3.c
@@ -0,0 +1,46 @@
+// RUN: clang-cc -emit-llvm %s -o - | FileCheck %s
+// CHECK: addrspace(1)
+// CHECK: addrspace(2)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(2)
+// CHECK: addrspace(2)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(2)
+// CHECK: addrspace(2)
+// CHECK: addrspace(2)
+// CHECK: addrspace(2)
+// CHECK: addrspace(2)
+// CHECK: addrspace(2)
+// CHECK: addrspace(2)
+// CHECK: addrspace(2)
+// CHECK: addrspace(2)
+// CHECK: addrspace(2)
+// CHECK: addrspace(2)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+
+// Check that we don't lose the address space when accessing an array element
+// inside a structure.
+
+#define __addr1 __attribute__((address_space(1)))
+#define __addr2 __attribute__((address_space(2)))
+
+typedef struct S {
+ int arr[ 3 ];
+} S;
+
+void test_addrspace(__addr1 S* p1, __addr2 S*p2, int* val, int n) {
+ for (int i=0; i < 3; ++i) {
+ int t = val[i];
+ p1->arr[i] = p2->arr[i];
+ }
+}
diff --git a/test/CodeGen/address-space-field4.c b/test/CodeGen/address-space-field4.c
new file mode 100644
index 0000000..31df018
--- /dev/null
+++ b/test/CodeGen/address-space-field4.c
@@ -0,0 +1,61 @@
+// RUN: clang-cc -emit-llvm %s -o - | FileCheck %s
+// CHECK: addrspace(2)
+// CHECK: addrspace(3)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(3)
+// CHECK: addrspace(3)
+// CHECK: addrspace(1)
+// CHECK: addrspace(3)
+// CHECK: addrspace(3)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(1)
+// CHECK: addrspace(2)
+// CHECK: addrspace(1)
+// CHECK: addrspace(2)
+// CHECK: addrspace(2)
+// CHECK: addrspace(2)
+
+// Check the load and store are using the correct address space to access
+// the variables.
+
+#define __addr1 __attribute__((address_space(1)))
+#define __addr2 __attribute__((address_space(2)))
+#define __addr3 __attribute__((address_space(3)))
+
+typedef struct Pair {
+ __addr2 int* a;
+ __addr3 int* b;
+} Pair;
+
+typedef struct S {
+ Pair arr[ 3 ];
+} S;
+
+void test_addrspace(__addr1 S* p1, __addr1 S* p2) {
+ *p1->arr[0].a = *p2->arr[1].b;
+}
diff --git a/test/CodeGen/arm-arguments.c b/test/CodeGen/arm-arguments.c
new file mode 100644
index 0000000..c43ede2
--- /dev/null
+++ b/test/CodeGen/arm-arguments.c
@@ -0,0 +1,94 @@
+// RUN: clang-cc -triple armv7-apple-darwin9 -target-abi=apcs-gnu -emit-llvm -w -o - %s | FileCheck -check-prefix=APCS-GNU %s &&
+// RUN: clang-cc -triple armv7-apple-darwin9 -target-abi=aapcs -emit-llvm -w -o - %s | FileCheck -check-prefix=AAPCS %s
+
+// APCS-GNU: define arm_apcscc signext i8 @f0()
+// AAPCS: define arm_aapcscc signext i8 @f0()
+char f0(void) {
+ return 0;
+}
+
+// APCS-GNU: define arm_apcscc i8 @f1()
+// AAPCS: define arm_aapcscc i8 @f1()
+struct s1 { char f0; };
+struct s1 f1(void) {}
+
+// APCS-GNU: define arm_apcscc i16 @f2()
+// AAPCS: define arm_aapcscc i16 @f2()
+struct s2 { short f0; };
+struct s2 f2(void) {}
+
+// APCS-GNU: define arm_apcscc i32 @f3()
+// AAPCS: define arm_aapcscc i32 @f3()
+struct s3 { int f0; };
+struct s3 f3(void) {}
+
+// APCS-GNU: define arm_apcscc i32 @f4()
+// AAPCS: define arm_aapcscc i32 @f4()
+struct s4 { struct s4_0 { int f0; } f0; };
+struct s4 f4(void) {}
+
+// APCS-GNU: define arm_apcscc void @f5(
+// APCS-GNU: struct.s5* noalias sret
+// AAPCS: define arm_aapcscc i32 @f5()
+struct s5 { struct { } f0; int f1; };
+struct s5 f5(void) {}
+
+// APCS-GNU: define arm_apcscc void @f6(
+// APCS-GNU: struct.s6* noalias sret
+// AAPCS: define arm_aapcscc i32 @f6()
+struct s6 { int f0[1]; };
+struct s6 f6(void) {}
+
+// APCS-GNU: define arm_apcscc void @f7()
+// AAPCS: define arm_aapcscc void @f7()
+struct s7 { struct { int : 0; } f0; };
+struct s7 f7(void) {}
+
+// APCS-GNU: define arm_apcscc void @f8(
+// APCS-GNU: struct.s8* noalias sret
+// AAPCS: define arm_aapcscc void @f8()
+struct s8 { struct { int : 0; } f0[1]; };
+struct s8 f8(void) {}
+
+// APCS-GNU: define arm_apcscc i32 @f9()
+// AAPCS: define arm_aapcscc i32 @f9()
+struct s9 { int f0; int : 0; };
+struct s9 f9(void) {}
+
+// APCS-GNU: define arm_apcscc i32 @f10()
+// AAPCS: define arm_aapcscc i32 @f10()
+struct s10 { int f0; int : 0; int : 0; };
+struct s10 f10(void) {}
+
+// APCS-GNU: define arm_apcscc void @f11(
+// APCS-GNU: struct.s10* noalias sret
+// AAPCS: define arm_aapcscc i32 @f11()
+struct s11 { int : 0; int f0; };
+struct s11 f11(void) {}
+
+// APCS-GNU: define arm_apcscc i32 @f12()
+// AAPCS: define arm_aapcscc i32 @f12()
+union u12 { char f0; short f1; int f2; };
+union u12 f12(void) {}
+
+// APCS-GNU: define arm_apcscc void @f13(
+// APCS-GNU: struct.s13* noalias sret
+
+// FIXME: This should return a float.
+// AAPCS-FIXME: define arm_aapcscc float @f13()
+struct s13 { float f0; };
+struct s13 f13(void) {}
+
+// APCS-GNU: define arm_apcscc void @f14(
+// APCS-GNU: struct.s13* noalias sret
+// AAPCS: define arm_aapcscc i32 @f14()
+union u14 { float f0; };
+union u14 f14(void) {}
+
+// APCS-GNU: define arm_apcscc void @f15()
+// AAPCS: define arm_aapcscc void @f15()
+void f15(struct s7 a0) {}
+
+// APCS-GNU: define arm_apcscc void @f16()
+// AAPCS: define arm_aapcscc void @f16()
+void f16(struct s8 a0) {}
diff --git a/test/CodeGen/arm_asm_clobber.c b/test/CodeGen/arm_asm_clobber.c
new file mode 100644
index 0000000..34e2517
--- /dev/null
+++ b/test/CodeGen/arm_asm_clobber.c
@@ -0,0 +1,21 @@
+// RUN: clang -ccc-host-triple armv6-unknown-unknown -emit-llvm -S -o %t %s
+
+void test0(void) {
+ asm volatile("mov r0, r0" :: );
+}
+void test1(void) {
+ asm volatile("mov r0, r0" :::
+ "cc", "memory" );
+}
+void test2(void) {
+ asm volatile("mov r0, r0" :::
+ "r0", "r1", "r2", "r3");
+ asm volatile("mov r0, r0" :::
+ "r4", "r5", "r6", "r8");
+}
+void test3(void) {
+ asm volatile("mov r0, r0" :::
+ "a1", "a2", "a3", "a4");
+ asm volatile("mov r0, r0" :::
+ "v1", "v2", "v3", "v5");
+}
diff --git a/test/CodeGen/array.c b/test/CodeGen/array.c
index 5bcc26e..294dabf 100644
--- a/test/CodeGen/array.c
+++ b/test/CodeGen/array.c
@@ -1,11 +1,11 @@
// RUN: clang-cc -emit-llvm %s -o %t
-int f() {
+void f() {
int a[2];
a[0] = 0;
}
-int f2() {
+void f2() {
int x = 0;
int y = 1;
int a[10] = { y, x, 2, 3};
diff --git a/test/CodeGen/asm-inout.c b/test/CodeGen/asm-inout.c
new file mode 100644
index 0000000..0d8dbdf
--- /dev/null
+++ b/test/CodeGen/asm-inout.c
@@ -0,0 +1,18 @@
+// RUN: clang-cc -triple i386-unknown-unknown -emit-llvm %s -o %t &&
+// RUN: grep "load i8\*\*\* %p.addr" %t | count 1
+// XFAIL
+
+// PR3800
+void f(void **p)
+{
+ __asm__ volatile("" :"+m"(*p));
+}
+
+#if 0
+// FIXME: Once this works again, we must verify that the code below behaves as expected
+// See PR4677.
+void f() {
+ unsigned _data = 42;
+ __asm__("bswap %0":"+r"(_data));
+}
+#endif
diff --git a/test/CodeGen/asm.c b/test/CodeGen/asm.c
index 58373fc..52afc91 100644
--- a/test/CodeGen/asm.c
+++ b/test/CodeGen/asm.c
@@ -15,7 +15,7 @@ void t4() {
unsigned long long a;
struct reg { unsigned long long a, b; } b;
- __asm__ volatile ("":: "m"(a), "m"(b));
+ __asm__ volatile ("":: "m"(a), "m"(b));
}
// PR3417
@@ -33,7 +33,7 @@ void t7(int a) {
__asm__ volatile("T7 NAMED: %[input]" : "+r"(a): [input] "i" (4));
}
-// RUN: grep "T8 NAMED MODIFIER: \${0:c}" %t
+// RUN: grep "T8 NAMED MODIFIER: \${0:c}" %t &&
void t8() {
__asm__ volatile("T8 NAMED MODIFIER: %c[input]" :: [input] "i" (4));
}
@@ -101,3 +101,12 @@ void t14(struct S *P) {
}
+// PR4938
+int t16() {
+ int a,b;
+ asm ( "nop;"
+ :"=%c" (a)
+ : "r" (b)
+ );
+ return 0;
+}
diff --git a/test/CodeGen/attr-cleanup.c b/test/CodeGen/attr-cleanup.c
index 03dde33..9105ede 100644
--- a/test/CodeGen/attr-cleanup.c
+++ b/test/CodeGen/attr-cleanup.c
@@ -3,6 +3,6 @@
// <rdar://problem/6827047>
void f(void* arg);
void g() {
- __attribute__((cleanup(f))) void *g;
+ __attribute__((cleanup(f))) void *g;
}
diff --git a/test/CodeGen/attributes.c b/test/CodeGen/attributes.c
index 8f157f3..d539e03 100644
--- a/test/CodeGen/attributes.c
+++ b/test/CodeGen/attributes.c
@@ -1,69 +1,77 @@
-// 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 &&
+// RUN: clang-cc -emit-llvm -triple i386-linux-gnu -o %t %s &&
+// RUN: FileCheck --input-file=%t %s
-void t1() __attribute__((noreturn));
-void t1() {}
+// CHECK: @t5 = weak global i32 2
+int t5 __attribute__((weak)) = 2;
-void t2() __attribute__((nothrow));
-void t2() {}
+// CHECK: @t13 = global %0 zeroinitializer, section "SECT"
+struct s0 { int x; };
+struct s0 t13 __attribute__((section("SECT"))) = { 0 };
-void t3() __attribute__((weak));
-void t3() {}
+// CHECK: @t14.x = internal global i32 0, section "SECT"
+void t14(void) {
+ static int x __attribute__((section("SECT"))) = 0;
+}
-void t4() __attribute__((visibility("hidden")));
-void t4() {}
+// CHECK: @t18 = global i32 1, align 4
+extern int t18 __attribute__((weak_import));
+int t18 = 1;
-int t5 __attribute__((weak)) = 2;
+// CHECK: @t16 = extern_weak global i32
+extern int t16 __attribute__((weak_import));
+// CHECK: @t6 = common protected global i32 0
int t6 __attribute__((visibility("protected")));
-void t7() __attribute__((noreturn, nothrow));
-void t7() {}
+// CHECK: @t12 = global i32 0, section "SECT"
+int t12 __attribute__((section("SECT")));
+// CHECK: @t9 = alias weak bitcast (void ()* @__t8 to void (...)*)
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;
-}
-
+// CHECK: declare extern_weak i32 @t15()
int __attribute__((weak_import)) t15(void);
-extern int t16 __attribute__((weak_import));
int t17() {
return t15() + t16;
}
-// RUN: grep '@t18 = global i[0-9]* 1, align .*' %t &&
-extern int t18 __attribute__((weak_import));
-int t18 = 1;
+// CHECK: define void @t1() noreturn nounwind {
+void t1() __attribute__((noreturn));
+void t1() { while (1) {} }
+
+// CHECK: define void @t2() nounwind {
+void t2() __attribute__((nothrow));
+void t2() {}
-// RUN: grep 'define i[0-9]* @t19()' %t &&
+// CHECK: define weak void @t3() nounwind {
+void t3() __attribute__((weak));
+void t3() {}
+
+// CHECK: define hidden void @t4() nounwind {
+void t4() __attribute__((visibility("hidden")));
+void t4() {}
+
+// CHECK: define void @t7() noreturn nounwind {
+void t7() __attribute__((noreturn, nothrow));
+void t7() { while (1) {} }
+
+// CHECK: define void @t10() nounwind section "SECT" {
+void t10(void) __attribute__((section("SECT")));
+void t10(void) {}
+// CHECK: define void @t11() nounwind section "SECT" {
+void __attribute__((section("SECT"))) t11(void) {}
+
+// CHECK: define i32 @t19() nounwind {
extern int t19(void) __attribute__((weak_import));
int t19(void) {
return 10;
}
-// RUN: true
+// CHECK:define void @t20() nounwind {
+// CHECK-NEXT:entry:
+// CHECK-NEXT: call void @abort()
+// CHECK-NEXT: unreachable
+void t20(void) {
+ __builtin_abort();
+}
diff --git a/test/CodeGen/blocks-2.c b/test/CodeGen/blocks-2.c
index 5ee2a73..bc6c2b9 100644
--- a/test/CodeGen/blocks-2.c
+++ b/test/CodeGen/blocks-2.c
@@ -1,6 +1,7 @@
-// RUN: clang-cc -g %s -emit-llvm -o %t -fblocks
+// 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.
+// XFAIL
static __inline__ __attribute__((always_inline)) int bar(int va, int vb) { return (va == vb); }
diff --git a/test/CodeGen/blocks-aligned-byref-variable.c b/test/CodeGen/blocks-aligned-byref-variable.c
new file mode 100644
index 0000000..1ae3062
--- /dev/null
+++ b/test/CodeGen/blocks-aligned-byref-variable.c
@@ -0,0 +1,19 @@
+// RUN: clang-cc -emit-llvm -o - -triple x86_64-apple-darwin10 &&
+// RUN: clang-cc -emit-llvm -o - -triple i386-apple-darwin10
+typedef int __attribute__((aligned(32))) ai;
+
+void f() {
+ __block ai a = 10;
+
+ ^{
+ a = 20;
+ }();
+}
+
+void g() {
+ __block double a = 10;
+
+ ^{
+ a = 20;
+ }();
+}
diff --git a/test/CodeGen/blocks-seq.c b/test/CodeGen/blocks-seq.c
index f637fbc..3ff241e 100644
--- a/test/CodeGen/blocks-seq.c
+++ b/test/CodeGen/blocks-seq.c
@@ -1,13 +1,13 @@
-// 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
+// FIXME: We forcibly strip the names so that the test doesn't vary between
+// builds with and without asserts. We need a better solution for this.
+
+// RUN: clang-cc -fblocks -triple x86_64-apple-darwin10 -emit-llvm-bc -o - %s | opt -strip | llvm-dis > %t &&
+// RUN: grep '%6 = call i32 (...)\* @rhs()' %t | count 1 &&
+// RUN: grep '%7 = getelementptr inbounds %0\* %1, i32 0, i32 1' %t | count 1 &&
+// RUN: grep '%8 = load %0\*\* %7' %t | count 1 &&
+// RUN: grep '%10 = call i32 (...)\* @rhs()' %t | count 1 &&
+// RUN: grep '%11 = getelementptr inbounds %0\* %1, i32 0, i32 1' %t | count 1 &&
+// RUN: grep '%12 = load %0\*\* %11' %t | count 1
int rhs();
diff --git a/test/CodeGen/boolassign.c b/test/CodeGen/boolassign.c
index 2d14f8c..73aab8d 100644
--- a/test/CodeGen/boolassign.c
+++ b/test/CodeGen/boolassign.c
@@ -1,6 +1,7 @@
// RUN: clang-cc %s -emit-llvm -o %t
int testBoolAssign(void) {
-int ss;
-if ((ss = ss && ss)) {}
+ int ss;
+ if ((ss = ss && ss)) {}
+ return 1;
}
diff --git a/test/CodeGen/builtin-attributes.c b/test/CodeGen/builtin-attributes.c
new file mode 100644
index 0000000..184e967
--- /dev/null
+++ b/test/CodeGen/builtin-attributes.c
@@ -0,0 +1,12 @@
+// RUN: clang-cc -triple arm-unknown-unknown -emit-llvm -o - %s | FileCheck %s
+
+// CHECK: declare arm_aapcscc i32 @printf(i8*, ...)
+void f0() {
+ printf("a\n");
+}
+
+// CHECK: call arm_aapcscc void @exit
+// CHECK: unreachable
+void f1() {
+ exit(1);
+}
diff --git a/test/CodeGen/builtins-ffs_parity_popcount.c b/test/CodeGen/builtins-ffs_parity_popcount.c
index 4746998..e3fa4d2 100644
--- a/test/CodeGen/builtins-ffs_parity_popcount.c
+++ b/test/CodeGen/builtins-ffs_parity_popcount.c
@@ -1,5 +1,5 @@
-// RUN: clang-cc -emit-llvm -o - %s > %t
-// RUN: ! grep "__builtin" %t
+// RUN: clang-cc -emit-llvm -o - %s > %t &&
+// RUN: not grep "__builtin" %t
#include <stdio.h>
diff --git a/test/CodeGen/builtins-powi.c b/test/CodeGen/builtins-powi.c
index 73f752f..5b413a8 100644
--- a/test/CodeGen/builtins-powi.c
+++ b/test/CodeGen/builtins-powi.c
@@ -1,5 +1,5 @@
-// RUN: clang-cc -emit-llvm -o - %s > %t
-// RUN: ! grep "__builtin" %t
+// RUN: clang-cc -emit-llvm -o - %s > %t &&
+// RUN: not grep "__builtin" %t
#include <stdio.h>
#include <stdlib.h>
diff --git a/test/CodeGen/builtins.c b/test/CodeGen/builtins.c
index ce5cd74..165db9c 100644
--- a/test/CodeGen/builtins.c
+++ b/test/CodeGen/builtins.c
@@ -54,6 +54,8 @@ int main() {
P(islessgreater, (1., 2.));
P(isunordered, (1., 2.));
+ P(isnan, (1.));
+
// Bitwise & Numeric Functions
P(abs, (N));
diff --git a/test/CodeGen/cast-to-union.c b/test/CodeGen/cast-to-union.c
index 6098bcc..6742992 100644
--- a/test/CodeGen/cast-to-union.c
+++ b/test/CodeGen/cast-to-union.c
@@ -1,7 +1,7 @@
-// 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
+// RUN: clang-cc -emit-llvm %s -o - | FileCheck %s
+// CHECK: w = global %0 { i32 2, [4 x i8] zeroinitializer }
+// CHECK: y = global %union.u { double 7.300000e+0{{[0]*}}1 }
+// CHECK: store i32 351, i32
union u { int i; double d; };
diff --git a/test/CodeGen/conditional.c b/test/CodeGen/conditional.c
index 2228670..8a30463 100644
--- a/test/CodeGen/conditional.c
+++ b/test/CodeGen/conditional.c
@@ -1,11 +1,10 @@
// RUN: clang-cc -emit-llvm %s -o %t
-float test1(int cond, float a, float b)
-{
+float test1(int cond, float a, float b) {
return cond ? a : b;
}
-double test2(int cond, float a, double b)
-{
+
+double test2(int cond, float a, double b) {
return cond ? a : b;
}
@@ -16,8 +15,8 @@ void test3(){
}
void test4() {
-int i; short j;
-float* k = 1 ? &i : &j;
+ int i; short j;
+ float* k = 1 ? &i : &j;
}
void test5() {
@@ -33,12 +32,10 @@ void* test8() {return 1 ? test6 : test7;}
void _efree(void *ptr);
-void _php_stream_free3()
-{
- (1 ? free(0) : _efree(0));
+void _php_stream_free3() {
+ (1 ? free(0) : _efree(0));
}
-void _php_stream_free4()
-{
- 1 ? _efree(0) : free(0);
+void _php_stream_free4() {
+ 1 ? _efree(0) : free(0);
}
diff --git a/test/CodeGen/const-init.c b/test/CodeGen/const-init.c
index 0364cc1..29e9c55 100644
--- a/test/CodeGen/const-init.c
+++ b/test/CodeGen/const-init.c
@@ -1,4 +1,4 @@
-// RUN: clang-cc -triple i386-pc-linux-gnu -verify -emit-llvm -o %t %s &&
+// RUN: clang-cc -triple i386-pc-linux-gnu -verify -emit-llvm -o - %s | FileCheck %s
#include <stdint.h>
@@ -22,44 +22,57 @@ union s2 {
int g0 = (int)(&(((union s2 *) 0)->f0.f0) - 0);
-// RUN: grep '@g1x = global %. { double 1.000000e+00, double 0.000000e+00 }' %t &&
+// CHECK: @g1x = global {{%.}} { double 1.000000e+00{{[0]*}}, double 0.000000e+00{{[0]*}} }
_Complex double g1x = 1.0f;
-// RUN: grep '@g1y = global %. { double 0.000000e+00, double 1.000000e+00 }' %t &&
+// CHECK: @g1y = global {{%.}} { double 0.000000e+00{{[0]*}}, double 1.000000e+00{{[0]*}} }
_Complex double g1y = 1.0fi;
-// RUN: grep '@g1 = global %. { i8 1, i8 10 }' %t &&
+// CHECK: @g1 = global {{%.}} { i8 1, i8 10 }
_Complex char g1 = (char) 1 + (char) 10 * 1i;
-// RUN: grep '@g2 = global %2 { i32 1, i32 10 }' %t &&
+// CHECK: @g2 = global %2 { i32 1, i32 10 }
_Complex int g2 = 1 + 10i;
-// RUN: grep '@g3 = global %. { float 1.000000e+00, float 1.000000e+01 }' %t &&
+// CHECK: @g3 = global {{%.}} { float 1.000000e+00{{[0]*}}, float 1.000000e+0{{[0]*}}1 }
_Complex float g3 = 1.0 + 10.0i;
-// RUN: grep '@g4 = global %. { double 1.000000e+00, double 1.000000e+01 }' %t &&
+// CHECK: @g4 = global {{%.}} { double 1.000000e+00{{[0]*}}, double 1.000000e+0{{[0]*}}1 }
_Complex double g4 = 1.0 + 10.0i;
-// RUN: grep '@g5 = global %2 zeroinitializer' %t &&
+// CHECK: @g5 = global %2 zeroinitializer
_Complex int g5 = (2 + 3i) == (5 + 7i);
-// RUN: grep '@g6 = global %. { double -1.100000e+01, double 2.900000e+01 }' %t &&
+// CHECK: @g6 = global {{%.}} { double -1.100000e+0{{[0]*}}1, double 2.900000e+0{{[0]*}}1 }
_Complex double g6 = (2.0 + 3.0i) * (5.0 + 7.0i);
-// RUN: grep '@g7 = global i32 1' %t &&
+// CHECK: @g7 = global i32 1
int g7 = (2 + 3i) * (5 + 7i) == (-11 + 29i);
-// RUN: grep '@g8 = global i32 1' %t &&
+// CHECK: @g8 = global i32 1
int g8 = (2.0 + 3.0i) * (5.0 + 7.0i) == (-11.0 + 29.0i);
-// RUN: grep '@g9 = global i32 0' %t &&
+// CHECK: @g9 = global i32 0
int g9 = (2 + 3i) * (5 + 7i) != (-11 + 29i);
-// RUN: grep '@g10 = global i32 0' %t &&
+// CHECK: @g10 = global i32 0
int g10 = (2.0 + 3.0i) * (5.0 + 7.0i) != (-11.0 + 29.0i);
+// PR5108
+// CHECK: @gv1 = global %4 <{ i32 0, i8 7 }>, align 1
+struct {
+ unsigned long a;
+ unsigned long b:3;
+} __attribute__((__packed__)) gv1 = { .a = 0x0, .b = 7, };
+
+// PR5118
+// CHECK: @gv2 = global %5 <{ i8 1, i8* null }>, align 1
+struct {
+ unsigned char a;
+ char *b;
+} __attribute__((__packed__)) gv2 = { 1, (void*)0 };
// Global references
-// RUN: grep '@g11.l0 = internal global i32 ptrtoint (i32 ()\* @g11 to i32)' %t &&
+// CHECK: @g11.l0 = internal global i32 ptrtoint (i32 ()* @g11 to i32)
long g11() {
static long l0 = (long) g11;
return l0;
}
-// RUN: grep '@g12 = global i32 ptrtoint (i8\* @g12_tmp to i32)' %t &&
+// CHECK: @g12 = global i32 ptrtoint (i8* @g12_tmp to i32)
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 &&
+// CHECK: @g13 = global [1 x %struct.g13_s0] [%struct.g13_s0 { i32 ptrtoint (i8* @g12_tmp to i32) }]
struct g13_s0 {
long a;
};
@@ -67,26 +80,25 @@ struct g13_s0 g13[] = {
{ (long) &g12_tmp }
};
-// RUN: grep '@g14 = global i8\* inttoptr (i64 100 to i8\*)' %t &&
+// CHECK: @g14 = global i8* inttoptr (i64 100 to i8*)
void *g14 = (void*) 100;
-// RUN: grep '@g15 = global i32 -1' %t &&
+// CHECK: @g15 = global i32 -1
int g15 = (int) (char) ((void*) 0 + 255);
-// RUN: grep '@g16 = global i64 4294967295' %t &&
+// CHECK: @g16 = global i64 4294967295
long long g16 = (long long) ((void*) 0xFFFFFFFF);
-// RUN: grep '@g17 = global i32\* @g15' %t &&
+// CHECK: @g17 = global i32* @g15
int *g17 = (int *) ((long) &g15);
-// RUN: grep '@g18.p = internal global \[1 x i32\*\] \[i32\* @g19\]' %t &&
+// CHECK: @g18.p = internal global [1 x i32*] [i32* @g19]
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 &&
-
+// CHECK: @g20.l0 = internal global %struct.g20_s1 { %struct.g20_s0* null, %struct.g20_s0** getelementptr inbounds (%struct.g20_s1* @g20.l0, i32 0, i32 0) }
struct g20_s0;
struct g20_s1 {
struct g20_s0 *f0, **f1;
@@ -99,6 +111,3 @@ void *g20(void) {
// PR4108
struct g21 {int g21;};
const struct g21 g21 = (struct g21){1};
-
-// RUN: true
-
diff --git a/test/CodeGen/darwin-string-literals.c b/test/CodeGen/darwin-string-literals.c
index ff245fc..04e43a2 100644
--- a/test/CodeGen/darwin-string-literals.c
+++ b/test/CodeGen/darwin-string-literals.c
@@ -1,10 +1,16 @@
-// RUN: clang-cc -triple i386-apple-darwin9 -emit-llvm %s -o %t &&
+// RUN: clang-cc -triple i386-apple-darwin9 -emit-llvm %s -o - | FileCheck -check-prefix LSB %s &&
-// 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
+// CHECK-LSB: @.str = private constant [8 x i8] c"string0\00"
+// CHECK-LSB: @.str1 = private constant [8 x i8] c"string1\00"
+// CHECK-LSB: @.str2 = internal constant [36 x i8] c"h\00e\00l\00l\00o\00 \00\92! \00\03& \00\90! \00w\00o\00r\00l\00d\00\00\00", section "__TEXT,__ustring", align 2
+
+// RUN: clang-cc -triple powerpc-apple-darwin9 -emit-llvm %s -o - | FileCheck -check-prefix MSB %s
+
+// CHECK-MSB: @.str = private constant [8 x i8] c"string0\00"
+// CHECK-MSB: @.str1 = private constant [8 x i8] c"string1\00"
+// CHECK-MSB: @.str2 = internal constant [36 x i8] c"\00h\00e\00l\00l\00o\00 !\92\00 &\03\00 !\90\00 \00w\00o\00r\00l\00d\00\00", section "__TEXT,__ustring", align 2
const char *g0 = "string0";
const void *g1 = __builtin___CFStringMakeConstantString("string1");
const void *g2 = __builtin___CFStringMakeConstantString("hello \u2192 \u2603 \u2190 world");
+const void *g3 = __builtin___CFStringMakeConstantString("test™");
diff --git a/test/CodeGen/debug-info.c b/test/CodeGen/debug-info.c
index e0ec2c9..beee7ac 100644
--- a/test/CodeGen/debug-info.c
+++ b/test/CodeGen/debug-info.c
@@ -24,14 +24,14 @@ char xpto[];
// PR3427
struct foo {
- int a;
- void *ptrs[];
+ int a;
+ void *ptrs[];
};
struct foo bar;
// PR4143
struct foo2 {
- enum bar *bar;
+ enum bar *bar;
};
struct foo2 foo2;
diff --git a/test/CodeGen/designated-initializers.c b/test/CodeGen/designated-initializers.c
index 4669339..f20bc78 100644
--- a/test/CodeGen/designated-initializers.c
+++ b/test/CodeGen/designated-initializers.c
@@ -1,5 +1,6 @@
-// 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"
+// RUN: clang-cc -triple i386-unknown-unknown %s -emit-llvm -o %t &&
+// RUN: grep "{ i8\* null, i32 1024 }" %t &&
+// RUN: grep "i32 0, i32 22" %t
struct foo {
void *a;
diff --git a/test/CodeGen/exprs.c b/test/CodeGen/exprs.c
index 36cfff9..a0e5b76 100644
--- a/test/CodeGen/exprs.c
+++ b/test/CodeGen/exprs.c
@@ -15,7 +15,7 @@ void *test(int *i) {
}
_Bool test2b;
-int test2() {if (test2b);}
+int test2() { if (test2b); return 0; }
// PR1921
int test3() {
@@ -48,9 +48,9 @@ int ola() {
// this one shouldn't fold as well
void eMaisUma() {
- double t[1];
- if (*t)
- return;
+ double t[1];
+ if (*t)
+ return;
}
// rdar://6520707
diff --git a/test/CodeGen/ext-vector-shuffle.c b/test/CodeGen/ext-vector-shuffle.c
index 37d3ed4..f53db94 100644
--- a/test/CodeGen/ext-vector-shuffle.c
+++ b/test/CodeGen/ext-vector-shuffle.c
@@ -1,5 +1,5 @@
-// 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 - | 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;
diff --git a/test/CodeGen/ext-vector.c b/test/CodeGen/ext-vector.c
index e3b6211..6a246db 100644
--- a/test/CodeGen/ext-vector.c
+++ b/test/CodeGen/ext-vector.c
@@ -115,9 +115,21 @@ void test7(int4 *ap, int4 *bp, int c) {
a /= c;
a %= c;
- // Vector comparisons can sometimes crash the x86 backend: rdar://6326239,
- // reject them until the implementation is stable.
-#if 0
+ // Vector comparisons.
+ int4 cmp;
+ cmp = a < b;
+ cmp = a <= b;
+ cmp = a < b;
+ cmp = a >= b;
+ cmp = a == b;
+ cmp = a != b;
+}
+
+void test8(float4 *ap, float4 *bp, int c) {
+ float4 a = *ap;
+ float4 b = *bp;
+
+ // Vector comparisons.
int4 cmp;
cmp = a < b;
cmp = a <= b;
@@ -125,5 +137,4 @@ void test7(int4 *ap, int4 *bp, int c) {
cmp = a >= b;
cmp = a == b;
cmp = a != b;
-#endif
}
diff --git a/test/CodeGen/function-attributes.c b/test/CodeGen/function-attributes.c
index ba2e4e4..d2d3b03 100644
--- a/test/CodeGen/function-attributes.c
+++ b/test/CodeGen/function-attributes.c
@@ -56,7 +56,7 @@ int ai_1() { return 4; }
static __inline__ __attribute__((always_inline))
struct {
int a, b, c, d, e;
-} ai_2() { }
+} ai_2() { while (1) {} }
int foo() {
diff --git a/test/CodeGen/functions.c b/test/CodeGen/functions.c
index 12dff1b..dba2931 100644
--- a/test/CodeGen/functions.c
+++ b/test/CodeGen/functions.c
@@ -3,11 +3,11 @@
int g();
int foo(int i) {
- return g(i);
+ return g(i);
}
int g(int i) {
- return g(i);
+ return g(i);
}
// rdar://6110827
@@ -32,6 +32,7 @@ void f1() {}
// RUN: grep 'define .* @f3' %t | not grep -F '...'
struct foo { int X, Y, Z; } f3() {
+ while (1) {}
}
// PR4423 - This shouldn't crash in codegen
diff --git a/test/CodeGen/global-decls.c b/test/CodeGen/global-decls.c
index 80222ea..decb6a9 100644
--- a/test/CodeGen/global-decls.c
+++ b/test/CodeGen/global-decls.c
@@ -11,7 +11,7 @@ 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) {}
+int __attribute__((weak)) g1_def (void) { return 0; }
// Force _ext references
void f0() {
diff --git a/test/CodeGen/global-init.c b/test/CodeGen/global-init.c
index 4b769f8..2368422 100644
--- a/test/CodeGen/global-init.c
+++ b/test/CodeGen/global-init.c
@@ -1,7 +1,30 @@
-// RUN: clang-cc -emit-llvm -o - %s | not grep "common"
+// RUN: clang-cc -emit-llvm -o - -triple i386-linux-gnu %s | FileCheck %s
// This checks that the global won't be marked as common.
// (It shouldn't because it's being initialized).
int a;
int a = 242;
+// CHECK: @a = global i32 242
+
+// This should get normal weak linkage.
+int c __attribute__((weak))= 0;
+// CHECK: @c = weak global i32 0
+
+
+
+// Since this is marked const, it should get weak_odr linkage, since all
+// definitions have to be the same.
+// CHECK: @d = weak_odr constant i32 0
+const int d __attribute__((weak))= 0;
+
+
+
+// NOTE: tentative definitions are processed at the end of the translation unit.
+
+// This shouldn't be emitted as common because it has an explicit section.
+// rdar://7119244
+int b __attribute__((section("foo")));
+
+// CHECK: @b = global i32 0, section "foo"
+
diff --git a/test/CodeGen/global-with-initialiser.c b/test/CodeGen/global-with-initialiser.c
index 29b4e21..d253782 100644
--- a/test/CodeGen/global-with-initialiser.c
+++ b/test/CodeGen/global-with-initialiser.c
@@ -17,9 +17,9 @@ long double globalLongDouble = 1;
long double globalLongDoubleArray[5] = { 1.0, 2.0 };
struct Struct {
- int member1;
- float member2;
- char *member3;
+ 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
index 2798cae..b3d0cb5 100644
--- a/test/CodeGen/globalinit.c
+++ b/test/CodeGen/globalinit.c
@@ -37,7 +37,7 @@ static int a = { 1 };
// References to enums.
enum {
- EnumA, EnumB
+ EnumA, EnumB
};
int c[] = { EnumA, EnumB };
diff --git a/test/CodeGen/init-with-member-expr.c b/test/CodeGen/init-with-member-expr.c
index 7750dbf..197a9ab 100644
--- a/test/CodeGen/init-with-member-expr.c
+++ b/test/CodeGen/init-with-member-expr.c
@@ -14,7 +14,7 @@ typedef struct mark_header_tag {
} 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);
+ foo(rar_hdr);
return 0;
}
diff --git a/test/CodeGen/inline.c b/test/CodeGen/inline.c
index 234f1f8..bf17fd7 100644
--- a/test/CodeGen/inline.c
+++ b/test/CodeGen/inline.c
@@ -1,5 +1,5 @@
-// RUN: echo "C89 tests:" &&
-// RUN: clang %s -emit-llvm -S -o %t -std=c89 &&
+// RUN: echo "GNU89 tests:" &&
+// RUN: clang %s -emit-llvm -S -o %t -std=gnu89 &&
// RUN: grep "define available_externally i32 @ei()" %t &&
// RUN: grep "define i32 @foo()" %t &&
// RUN: grep "define i32 @bar()" %t &&
@@ -24,9 +24,9 @@
// 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 void @test3" %t &&
// RUN: grep "define available_externally i32 @test4" %t &&
-// RUN: grep "define i32 @test5" %t &&
+// RUN: grep "define available_externally i32 @test5" %t &&
// RUN: echo "\nC++ tests:" &&
// RUN: clang %s -emit-llvm -S -o %t -std=c++98 &&
@@ -67,20 +67,20 @@ void test_test2() { test2(); }
// PR3989
extern __inline void test3() __attribute__((gnu_inline));
-__inline void test3() {}
-
-void test_test3() { test3(); }
+__inline void __attribute__((gnu_inline)) test3() {}
extern int test4(void);
extern __inline __attribute__ ((__gnu_inline__)) int test4(void)
{
+ return 0;
}
void test_test4() { test4(); }
-extern __inline int test5(void);
+extern __inline int test5(void) __attribute__ ((__gnu_inline__));
extern __inline int __attribute__ ((__gnu_inline__)) test5(void)
{
+ return 0;
}
void test_test5() { test5(); }
diff --git a/test/CodeGen/inline2.c b/test/CodeGen/inline2.c
new file mode 100644
index 0000000..6f165f5
--- /dev/null
+++ b/test/CodeGen/inline2.c
@@ -0,0 +1,62 @@
+// RUN: clang-cc -std=gnu89 -triple i386-apple-darwin9 -emit-llvm %s -o - | FileCheck -check-prefix GNU89 %s &&
+// RUN: clang-cc -std=c99 -triple i386-apple-darwin9 -emit-llvm %s -o - | FileCheck -check-prefix C99 %s
+
+// CHECK-GNU89: define i32 @f0()
+// CHECK-C99: define i32 @f0()
+int f0(void);
+int f0(void) { return 0; }
+
+// CHECK-GNU89: define i32 @f1()
+// CHECK-C99: define i32 @f1()
+inline int f1(void);
+int f1(void) { return 0; }
+
+// CHECK-GNU89: define i32 @f2()
+// CHECK-C99: define i32 @f2()
+int f2(void);
+inline int f2(void) { return 0; }
+
+// CHECK-GNU89: define i32 @f3()
+// CHECK-C99: define i32 @f3()
+extern inline int f3(void);
+int f3(void) { return 0; }
+
+// CHECK-GNU89: define i32 @f5()
+// CHECK-C99: define i32 @f5()
+extern inline int f5(void);
+inline int f5(void) { return 0; }
+
+// CHECK-GNU89: define i32 @f6()
+// CHECK-C99: define i32 @f6()
+inline int f6(void);
+extern inline int f6(void) { return 0; }
+
+// CHECK-GNU89: define i32 @f7()
+// CHECK-C99: define i32 @f7()
+extern inline int f7(void);
+extern int f7(void) { return 0; }
+
+// CHECK-GNU89: define i32 @fA()
+inline int fA(void) { return 0; }
+
+// CHECK-GNU89: define available_externally i32 @f4()
+// CHECK-C99: define i32 @f4()
+int f4(void);
+extern inline int f4(void) { return 0; }
+
+// CHECK-GNU89: define available_externally i32 @f8()
+// CHECK-C99: define i32 @f8()
+extern int f8(void);
+extern inline int f8(void) { return 0; }
+
+// CHECK-GNU89: define available_externally i32 @f9()
+// CHECK-C99: define i32 @f9()
+extern inline int f9(void);
+extern inline int f9(void) { return 0; }
+
+// CHECK-C99: define available_externally i32 @fA()
+
+int test_all() {
+ return f0() + f1() + f2() + f3() + f4() + f5() + f6() + f7() + f8() + f9()
+ + fA();
+}
diff --git a/test/CodeGen/packed-union.c b/test/CodeGen/packed-union.c
new file mode 100644
index 0000000..d11d3a4
--- /dev/null
+++ b/test/CodeGen/packed-union.c
@@ -0,0 +1,16 @@
+// RUN: clang-cc -triple x86_64-apple-darwin10 -emit-llvm %s -o %t &&
+
+// RUN: grep "struct._attrs = type <{ i32, i8 }>" %t &&
+typedef struct _attrs {
+ unsigned file_attributes;
+ unsigned char filename_length;
+} __attribute__((__packed__)) attrs;
+
+// RUN: grep "union._attr_union = type <{ i32, i8 }>" %t
+typedef union _attr_union {
+ attrs file_attrs;
+ unsigned owner_id;
+} __attribute__((__packed__)) attr_union;
+
+attr_union u;
+
diff --git a/test/CodeGen/parameter-passing.c b/test/CodeGen/parameter-passing.c
index 2ace299..dce0ff8 100644
--- a/test/CodeGen/parameter-passing.c
+++ b/test/CodeGen/parameter-passing.c
@@ -11,7 +11,7 @@
// 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: clang-cc %s -triple powerpc-unknown-unknown -O3 -emit-llvm -o %t &&
// RUN: not grep '@g0' %t &&
// RUN: true
diff --git a/test/CodeGen/pragma-pack-1.c b/test/CodeGen/pragma-pack-1.c
new file mode 100644
index 0000000..bcfcd5a
--- /dev/null
+++ b/test/CodeGen/pragma-pack-1.c
@@ -0,0 +1,7 @@
+// RUN: clang-cc -emit-llvm -o -
+
+// PR4610
+#pragma pack(4)
+struct ref {
+ struct ref *next;
+} refs;
diff --git a/test/CodeGen/pragma-pack-2.c b/test/CodeGen/pragma-pack-2.c
new file mode 100644
index 0000000..306f02d
--- /dev/null
+++ b/test/CodeGen/pragma-pack-2.c
@@ -0,0 +1,23 @@
+// RUN: clang-cc -triple i386-apple-darwin9 %s -emit-llvm -o - | FileCheck -check-prefix X32 %s &&
+// CHECK-X32: %struct.s0 = type { i64, i64, i32, [12 x i32] }
+// CHECK-X32: %struct.s1 = type { [15 x i32], %struct.s0 }
+
+// RUN: clang-cc -triple x86_64-apple-darwin9 %s -emit-llvm -o - | FileCheck -check-prefix X64 %s
+// CHECK-X64: %struct.s0 = type <{ i64, i64, i32, [12 x i32] }>
+// CHECK-X64: %struct.s1 = type <{ [15 x i32], %struct.s0 }>
+
+// rdar://problem/7095436
+#pragma pack(4)
+
+struct s0 {
+ long long a __attribute__((aligned(8)));
+ long long b __attribute__((aligned(8)));
+ unsigned int c __attribute__((aligned(8)));
+ int d[12];
+} a;
+
+struct s1 {
+ int a[15];
+ struct s0 b;
+} b;
+
diff --git a/test/CodeGen/pragma-pack-3.c b/test/CodeGen/pragma-pack-3.c
new file mode 100644
index 0000000..b9166ae
--- /dev/null
+++ b/test/CodeGen/pragma-pack-3.c
@@ -0,0 +1,19 @@
+// RUN: clang-cc -triple i386-apple-darwin9 %s -emit-llvm -o - | FileCheck -check-prefix X32 %s &&
+// CHECK-X32: %struct.menu = type <{ i8*, i8, i8 }>
+// CHECK-X32: %union.command = type <{ i8*, [2 x i8] }>
+
+// RUN: clang-cc -triple x86_64-apple-darwin9 %s -emit-llvm -o - | FileCheck -check-prefix X64 %s
+// CHECK-X64: %struct.menu = type <{ i8*, i8, i8 }>
+// CHECK-X64: %union.command = type <{ i8*, [2 x i8] }>
+
+// <rdar://problem/7184250>
+#pragma pack(push, 2)
+typedef union command {
+ void *windowRef;
+ struct menu {
+ void *menuRef;
+ unsigned char menuItemIndex;
+ } menu;
+} command;
+
+command c;
diff --git a/test/CodeGen/pragma-weak.c b/test/CodeGen/pragma-weak.c
new file mode 100644
index 0000000..497039a
--- /dev/null
+++ b/test/CodeGen/pragma-weak.c
@@ -0,0 +1,165 @@
+// RUN: clang-cc -emit-llvm %s -o - -verify | FileCheck %s
+
+// CHECK: @weakvar = weak global
+// CHECK: @__weakvar_alias = common global
+// CHECK: @correct_linkage = weak global
+
+
+// CHECK: @both = alias void ()* @__both
+// CHECK: @both2 = alias void ()* @__both2
+// CHECK: @both3 = alias weak void ()* @__both3
+// CHECK: @a3 = alias weak void ()* @__a3
+// CHECK: @weakvar_alias = alias weak i32* @__weakvar_alias
+// CHECK: @foo = alias weak void ()* @__foo
+// CHECK: @foo2 = alias weak void ()* @__foo2
+// CHECK: @stutter = alias weak void ()* @__stutter
+// CHECK: @stutter2 = alias weak void ()* @__stutter2
+// CHECK: @declfirst = alias weak void ()* @__declfirst
+// CHECK: @declfirstattr = alias weak void ()* @__declfirstattr
+// CHECK: @mix2 = alias weak void ()* @__mix2
+// CHECK: @a1 = alias weak void ()* @__a1
+// CHECK: @xxx = alias weak void ()* @__xxx
+
+
+
+// CHECK: define weak void @weakdef()
+
+
+#pragma weak weakvar
+int weakvar;
+
+#pragma weak weakdef
+void weakdef(void) {}
+
+#pragma weak param // expected-warning {{weak identifier 'param' never declared}}
+#pragma weak correct_linkage
+void f(int param) {
+ int correct_linkage;
+}
+
+#pragma weak weakvar_alias = __weakvar_alias
+int __weakvar_alias;
+
+#pragma weak foo = __foo
+void __foo(void) {}
+// CHECK: define void @__foo()
+
+
+void __foo2(void) {}
+#pragma weak foo2 = __foo2
+// CHECK: define void @__foo2()
+
+
+///// test errors
+
+#pragma weak unused // expected-warning {{weak identifier 'unused' never declared}}
+#pragma weak unused_alias = __unused_alias // expected-warning {{weak identifier '__unused_alias' never declared}}
+
+#pragma weak td // expected-warning {{weak identifier 'td' never declared}}
+typedef int td;
+
+#pragma weak td2 = __td2 // expected-warning {{weak identifier '__td2' never declared}}
+typedef int __td2;
+
+
+///// test weird cases
+
+// test repeats
+
+#pragma weak stutter = __stutter
+#pragma weak stutter = __stutter
+void __stutter(void) {}
+// CHECK: define void @__stutter()
+
+void __stutter2(void) {}
+#pragma weak stutter2 = __stutter2
+#pragma weak stutter2 = __stutter2
+// CHECK: define void @__stutter2()
+
+
+// test decl/pragma weak order
+
+void __declfirst(void);
+#pragma weak declfirst = __declfirst
+void __declfirst(void) {}
+// CHECK: define void @__declfirst()
+
+void __declfirstattr(void) __attribute((noinline));
+#pragma weak declfirstattr = __declfirstattr
+void __declfirstattr(void) {}
+// CHECK: define void @__declfirstattr()
+
+//// test that other attributes are preserved
+
+//// ensure that pragma weak/__attribute((weak)) play nice
+
+void mix(void);
+#pragma weak mix
+__attribute((weak)) void mix(void) { }
+// CHECK: define weak void @mix()
+
+// ensure following __attributes are preserved and that only a single
+// alias is generated
+#pragma weak mix2 = __mix2
+void __mix2(void) __attribute((noinline));
+void __mix2(void) __attribute((noinline));
+void __mix2(void) {}
+// CHECK: define void @__mix2()
+
+////////////// test #pragma weak/__attribute combinations
+
+// if the SAME ALIAS is already declared then it overrides #pragma weak
+// resulting in a non-weak alias in this case
+void both(void) __attribute((alias("__both")));
+#pragma weak both = __both
+void __both(void) {}
+// CHECK: define void @__both()
+
+// if the TARGET is previously declared then whichever aliasing method
+// comes first applies and subsequent aliases are discarded.
+// TODO: warn about this
+
+void __both2(void);
+void both2(void) __attribute((alias("__both2"))); // first, wins
+#pragma weak both2 = __both2
+void __both2(void) {}
+// CHECK: define void @__both2()
+
+void __both3(void);
+#pragma weak both3 = __both3 // first, wins
+void both3(void) __attribute((alias("__both3")));
+void __both3(void) {}
+// CHECK: define void @__both3()
+
+///////////// ensure that #pragma weak does not alter existing __attributes()
+
+void __a1(void) __attribute((noinline));
+#pragma weak a1 = __a1
+void __a1(void) {}
+// CHECK: define void @__a1()
+
+// attributes introduced BEFORE a combination of #pragma weak and alias()
+// hold...
+void __a3(void) __attribute((noinline));
+#pragma weak a3 = __a3
+void a3(void) __attribute((alias("__a3")));
+void __a3(void) {}
+// CHECK: define void @__a3()
+
+#pragma weak xxx = __xxx
+__attribute((pure,noinline,const,fastcall)) void __xxx(void) { }
+// CHECK: void @__xxx()
+
+/// TODO: stuff that still doesn't work
+
+// due to the fact that disparate TopLevelDecls cannot affect each other
+// (due to clang's Parser and ASTConsumer behavior, and quite reasonable)
+// #pragma weak must appear before or within the same TopLevelDecl as it
+// references.
+void yyy(void){}
+void zzz(void){}
+#pragma weak yyy
+// NOTE: weak doesn't apply, not before or in same TopLevelDec(!)
+// CHECK: define void @yyy()
+
+int correct_linkage;
diff --git a/test/CodeGen/predefined-expr.c b/test/CodeGen/predefined-expr.c
new file mode 100644
index 0000000..9b64593
--- /dev/null
+++ b/test/CodeGen/predefined-expr.c
@@ -0,0 +1,45 @@
+// RUN: clang-cc %s -emit-llvm -o - | FileCheck %s
+
+// CHECK: @__func__.plainFunction = private constant [14 x i8] c"plainFunction\00"
+// CHECK: @__PRETTY_FUNCTION__.plainFunction = private constant [21 x i8] c"void plainFunction()\00"
+// CHECK: @__func__.externFunction = private constant [15 x i8] c"externFunction\00"
+// CHECK: @__PRETTY_FUNCTION__.externFunction = private constant [22 x i8] c"void externFunction()\00"
+// CHECK: @__func__.privateExternFunction = private constant [22 x i8] c"privateExternFunction\00"
+// CHECK: @__PRETTY_FUNCTION__.privateExternFunction = private constant [29 x i8] c"void privateExternFunction()\00"
+// CHECK: @__func__.staticFunction = private constant [15 x i8] c"staticFunction\00"
+// CHECK: @__PRETTY_FUNCTION__.staticFunction = private constant [22 x i8] c"void staticFunction()\00"
+
+#include <stdio.h>
+
+void plainFunction() {
+ printf("__func__ %s\n", __func__);
+ printf("__FUNCTION__ %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+}
+
+extern void externFunction() {
+ printf("__func__ %s\n", __func__);
+ printf("__FUNCTION__ %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+}
+
+__private_extern__ void privateExternFunction() {
+ printf("__func__ %s\n", __func__);
+ printf("__FUNCTION__ %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+}
+
+static void staticFunction() {
+ printf("__func__ %s\n", __func__);
+ printf("__FUNCTION__ %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+}
+
+int main() {
+ plainFunction();
+ externFunction();
+ privateExternFunction();
+ staticFunction();
+
+ return 0;
+}
diff --git a/test/CodeGen/regparm.c b/test/CodeGen/regparm.c
index fdf07ea..28dfae7 100644
--- a/test/CodeGen/regparm.c
+++ b/test/CodeGen/regparm.c
@@ -9,11 +9,10 @@ typedef struct {
} foo;
static void FASTCALL
-reduced(char b, double c, foo* d, double e, int f)
-{
+reduced(char b, double c, foo* d, double e, int f) {
}
int
main(void) {
- reduced(0, 0.0, 0, 0.0, 0);
+ reduced(0, 0.0, 0, 0.0, 0);
}
diff --git a/test/CodeGen/stack-protector.c b/test/CodeGen/stack-protector.c
index bdac853..0b5924d 100644
--- a/test/CodeGen/stack-protector.c
+++ b/test/CodeGen/stack-protector.c
@@ -12,8 +12,7 @@
// RUN: not grep 'ssp' %t &&
// RUN: true
-#include <stdio.h>
-#include <string.h>
+int printf(const char * _Format, ...);
void test1(const char *msg) {
char a[strlen(msg) + 1];
diff --git a/test/CodeGen/statements.c b/test/CodeGen/statements.c
index 1ff7601..45bbd9a 100644
--- a/test/CodeGen/statements.c
+++ b/test/CodeGen/statements.c
@@ -11,3 +11,25 @@ bar();
int test2() { return; }
void test3() { return 4; }
+
+void test4() {
+bar:
+baz:
+blong:
+bing:
+ ;
+
+// PR5131
+static long x = &&bar - &&baz;
+static long y = &&baz;
+ &&bing;
+ &&blong;
+ if (y)
+ goto *y;
+
+ goto *x;
+}
+
+// PR3869
+int test5(long long b) { goto *b; }
+
diff --git a/test/CodeGen/staticinit.c b/test/CodeGen/staticinit.c
index 91fcdcf..c68366f 100644
--- a/test/CodeGen/staticinit.c
+++ b/test/CodeGen/staticinit.c
@@ -2,9 +2,9 @@
// RUN: grep "g.b = internal global i8. getelementptr" %t &&
struct AStruct {
- int i;
- char *s;
- double d;
+ int i;
+ char *s;
+ double d;
};
void f() {
diff --git a/test/CodeGen/stdcall-fastcall.c b/test/CodeGen/stdcall-fastcall.c
index 11b6521..89ed8c9 100644
--- a/test/CodeGen/stdcall-fastcall.c
+++ b/test/CodeGen/stdcall-fastcall.c
@@ -1,4 +1,4 @@
-// RUN: clang-cc -emit-llvm < %s | grep 'fastcallcc' | count 4
+// 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);
diff --git a/test/CodeGen/string-init.c b/test/CodeGen/string-init.c
index 38c7ec0..4a80851 100644
--- a/test/CodeGen/string-init.c
+++ b/test/CodeGen/string-init.c
@@ -1,5 +1,5 @@
// RUN: clang-cc -emit-llvm %s -o %t &&
-// RUN: grep 'internal constant \[10 x i8\]' %t &&
+// RUN: grep 'private constant \[10 x i8\]' %t &&
// RUN: not grep -F "[5 x i8]" %t &&
// RUN: not grep "store " %t
diff --git a/test/CodeGen/struct-init.c b/test/CodeGen/struct-init.c
index a38442b..cb84fef 100644
--- a/test/CodeGen/struct-init.c
+++ b/test/CodeGen/struct-init.c
@@ -2,11 +2,11 @@
typedef struct _zend_ini_entry zend_ini_entry;
struct _zend_ini_entry {
- void *mh_arg1;
+ void *mh_arg1;
};
char a;
const zend_ini_entry ini_entries[] = {
- { ((char*)&((zend_ini_entry*)0)->mh_arg1 - (char*)(void*)0)},
+ { ((char*)&((zend_ini_entry*)0)->mh_arg1 - (char*)(void*)0)},
};
diff --git a/test/CodeGen/struct-x86-darwin.c b/test/CodeGen/struct-x86-darwin.c
index 050e26d..c61005f 100644
--- a/test/CodeGen/struct-x86-darwin.c
+++ b/test/CodeGen/struct-x86-darwin.c
@@ -1,13 +1,13 @@
-// 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
+// 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, 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, \[2 x i8\], i8, i8 }" %t1 &&
+// RUN: grep "STestB6 = type { i8, i8, \[2 x i8\] }" %t1
// Test struct layout for x86-darwin target
struct STest1 {int x; short y[4]; double z; } st1;
diff --git a/test/CodeGen/struct.c b/test/CodeGen/struct.c
index ed36842..d1e58a2 100644
--- a/test/CodeGen/struct.c
+++ b/test/CodeGen/struct.c
@@ -70,8 +70,7 @@ typedef struct {
int length;
} range;
extern range f6();
-void f7()
-{
+void f7() {
range r = f6();
}
@@ -81,27 +80,23 @@ typedef struct {
range range2;
} rangepair;
-void f8()
-{
+void f8() {
rangepair p;
range r = p.range1;
}
-void f9(range *p)
-{
+void f9(range *p) {
range r = *p;
}
-void f10(range *p)
-{
+void f10(range *p) {
range r = p[0];
}
/* _Bool types */
-struct _w
-{
+struct _w {
short a,b;
short c,d;
short e,f;
@@ -113,27 +108,24 @@ struct _w
} ws;
/* Implicit casts (due to typedefs) */
-typedef struct _a
-{
+typedef struct _a {
int a;
} a;
-void f11()
-{
- struct _a a1;
- a a2;
+void f11() {
+ struct _a a1;
+ a a2;
- a1 = a2;
- a2 = a1;
+ a1 = a2;
+ a2 = a1;
}
/* Implicit casts (due to const) */
-void f12()
-{
- struct _a a1;
- const struct _a a2;
-
- a1 = a2;
+void f12() {
+ struct _a a1;
+ const struct _a a2;
+
+ a1 = a2;
}
/* struct initialization */
@@ -147,8 +139,7 @@ struct a15 {char a; int b[];} c15;
int a16(void) {c15.a = 1;}
/* compound literals */
-void f13()
-{
+void f13() {
a13 x; x = (a13){1,2};
}
diff --git a/test/CodeGen/union-init.c b/test/CodeGen/union-init.c
index c882d31..f4e9e9a 100644
--- a/test/CodeGen/union-init.c
+++ b/test/CodeGen/union-init.c
@@ -4,19 +4,19 @@
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 */
+ 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 */
+ PyGC_Head head;
+ int threshold; /* collection threshold */
+ int count; /* count of allocations or collections of younger
+ generations */
};
#define NUM_GENERATIONS 3
@@ -24,8 +24,8 @@ struct gc_generation {
/* 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},
+ /* 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-init2.c b/test/CodeGen/union-init2.c
new file mode 100644
index 0000000..184d75f
--- /dev/null
+++ b/test/CodeGen/union-init2.c
@@ -0,0 +1,4 @@
+// RUN: clang-cc -emit-llvm %s -o - -triple i686-pc-linux-gnu | grep "bitcast (%0\* @r to %union.x\*), \[4 x i8\] zeroinitializer"
+
+// Make sure we generate something sane instead of a ptrtoint
+union x {long long b;union x* a;} r = {.a = &r};
diff --git a/test/CodeGen/unreachable.c b/test/CodeGen/unreachable.c
new file mode 100644
index 0000000..ea4f047
--- /dev/null
+++ b/test/CodeGen/unreachable.c
@@ -0,0 +1,37 @@
+// RUN: clang-cc -emit-llvm -o %t %s &&
+// RUN: grep '@unreachable' %t | count 0
+
+extern void abort() __attribute__((noreturn));
+extern int unreachable();
+
+int f0() {
+ return 0;
+ unreachable();
+}
+
+int f1(int i) {
+ goto L0;
+ int a = unreachable();
+ L0:
+ return 0;
+}
+
+int f2(int i) {
+ goto L0;
+ unreachable();
+ int a;
+ unreachable();
+ L0:
+ a = i + 1;
+ return a;
+}
+
+int f3(int i) {
+ if (i) {
+ return 0;
+ } else {
+ abort();
+ }
+ unreachable();
+ return 3;
+}
diff --git a/test/CodeGen/unwind-attr.c b/test/CodeGen/unwind-attr.c
index 4954a0b..86036f9 100644
--- a/test/CodeGen/unwind-attr.c
+++ b/test/CodeGen/unwind-attr.c
@@ -2,4 +2,5 @@
// RUN: clang-cc -emit-llvm -o - %s | grep "@foo()" | grep nounwind
int foo(void) {
+ return 0;
}
diff --git a/test/CodeGen/vector.c b/test/CodeGen/vector.c
index 1084f6d..5e48fd4 100644
--- a/test/CodeGen/vector.c
+++ b/test/CodeGen/vector.c
@@ -1,9 +1,8 @@
// RUN: clang-cc -emit-llvm %s -o -
typedef short __v4hi __attribute__ ((__vector_size__ (8)));
-void f()
-{
- __v4hi A = (__v4hi)0LL;
+void f() {
+ __v4hi A = (__v4hi)0LL;
}
__v4hi x = {1,2,3};
@@ -15,7 +14,6 @@ int a() { vty b; return b[2LL]; }
// PR4339
typedef float vec4 __attribute__((vector_size(16)));
-void vac ( vec4* a, char b, float c )
-{
- (*a)[b] = c;
+void vac ( vec4* a, char b, float c ) {
+ (*a)[b] = c;
}
diff --git a/test/CodeGen/visibility.c b/test/CodeGen/visibility.c
index bb9b6e0..958eb61 100644
--- a/test/CodeGen/visibility.c
+++ b/test/CodeGen/visibility.c
@@ -15,7 +15,7 @@
// 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_com = common hidden global i32 0' %t &&
// RUN: grep '@g_def = hidden global i32 0' %t &&
// RUN: grep '@g_ext = external global i32' %t &&
// RUN: grep '@g_deferred = internal global' %t &&
diff --git a/test/CodeGen/volatile.c b/test/CodeGen/volatile.c
index 212a0ae..87cb5ff 100644
--- a/test/CodeGen/volatile.c
+++ b/test/CodeGen/volatile.c
@@ -38,7 +38,7 @@ volatile extv4 vVE;
volatile struct {int x;} aggFct(void);
-void main() {
+int main() {
int i;
// load
diff --git a/test/CodeGen/x86.c b/test/CodeGen/x86.c
index 66d8251..be09302 100644
--- a/test/CodeGen/x86.c
+++ b/test/CodeGen/x86.c
@@ -1,4 +1,4 @@
-// RUN: clang-cc %s -triple=i686-pc-linux-gnu -emit-llvm -o - > %t1
+// 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 &&
diff --git a/test/CodeGen/x86_32-arguments.c b/test/CodeGen/x86_32-arguments.c
index 43a3ab2..78fb834 100644
--- a/test/CodeGen/x86_32-arguments.c
+++ b/test/CodeGen/x86_32-arguments.c
@@ -1,4 +1,4 @@
-// RUN: clang-cc -triple i386-apple-darwin9 -emit-llvm -o %t %s &&
+// RUN: clang-cc -fblocks -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 &&
@@ -11,39 +11,41 @@
// RUN: grep 'define void @f8_2(i32 %a0.0, i32 %a0.1)' %t &&
char f0(void) {
+ return 0;
}
short f1(void) {
+ return 0;
}
int f2(void) {
+ return 0;
}
float f3(void) {
+ return 0;
}
double f4(void) {
+ return 0;
}
long double f5(void) {
+ return 0;
}
-void f6(char a0, short a1, int a2, long long a3, void *a4) {
-}
+void f6(char a0, short a1, int a2, long long a3, void *a4) {}
typedef enum { A, B, C } E;
-void f7(E a0) {
-}
+void f7(E a0) {}
struct s8 {
int a;
int b;
};
-struct s8 f8_1(void) {
-}
-void f8_2(struct s8 a0) {
-}
+struct s8 f8_1(void) { while (1) {} }
+void f8_2(struct s8 a0) {}
// This should be passed just as s8.
@@ -56,10 +58,8 @@ struct s9 {
int a : 17;
int b;
};
-struct s9 f9_1(void) {
-}
-void f9_2(struct s9 a0) {
-}
+struct s9 f9_1(void) { while (1) {} }
+void f9_2(struct s9 a0) {}
// Return of small structures and unions
@@ -67,7 +67,7 @@ void f9_2(struct s9 a0) {
struct s10 {
union { };
float f;
-} f10(void) {}
+} f10(void) { while (1) {} }
// Small vectors and 1 x {i64,double} are returned in registers
@@ -78,17 +78,17 @@ struct s10 {
// RUN: grep '<2 x i64> @f15()' %t &&
// RUN: grep '<2 x i64> @f16()' %t &&
typedef short T11 __attribute__ ((vector_size (4)));
-T11 f11(void) {}
+T11 f11(void) { while (1) {} }
typedef int T12 __attribute__ ((vector_size (8)));
-T12 f12(void) {}
+T12 f12(void) { while (1) {} }
typedef long long T13 __attribute__ ((vector_size (8)));
-T13 f13(void) {}
+T13 f13(void) { while (1) {} }
typedef double T14 __attribute__ ((vector_size (8)));
-T14 f14(void) {}
+T14 f14(void) { while (1) {} }
typedef long long T15 __attribute__ ((vector_size (16)));
-T15 f15(void) {}
+T15 f15(void) { while (1) {} }
typedef double T16 __attribute__ ((vector_size (16)));
-T16 f16(void) {}
+T16 f16(void) { while (1) {} }
// And when the single element in a struct (but not for 64 and
// 128-bits).
@@ -99,64 +99,107 @@ T16 f16(void) {}
// 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) {}
+struct { T11 a; } f17(void) { while (1) {} }
+struct { T12 a; } f18(void) { while (1) {} }
+struct { T13 a; } f19(void) { while (1) {} }
+struct { T14 a; } f20(void) { while (1) {} }
+struct { T15 a; } f21(void) { while (1) {} }
+struct { T16 a; } f22(void) { while (1) {} }
// 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) {}
+struct { float a; } f23(void) { while (1) {} }
+struct { float a[1]; } f24(void) { while (1) {} }
+struct { struct {} a; struct { float a[1]; } b; } f25(void) { while (1) {} }
// 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) {}
+struct s26 { struct { char a, b; } a; struct { char a, b; } b; } f26(void) { while (1) {} }
+struct s27 { struct { char a, b, c; } a; struct { char a; } b; } f27(void) { while (1) {} }
// RUN: grep 'void @f28(%.truct.s28\* noalias sret %agg.result)' %t &&
-struct s28 { int a; int b[]; } f28(void) {}
+struct s28 { int a; int b[]; } f28(void) { while (1) {} }
// RUN: grep 'define i16 @f29()' %t &&
-struct s29 { struct { } a[1]; char b; char c; } f29(void) {}
+struct s29 { struct { } a[1]; char b; char c; } f29(void) { while (1) {} }
// RUN: grep 'define i16 @f30()' %t &&
-struct s30 { char a; char b : 4; } f30(void) {}
+struct s30 { char a; char b : 4; } f30(void) { while (1) {} }
// RUN: grep 'define float @f31()' %t &&
-struct s31 { char : 0; float b; char : 0; } f31(void) {}
+struct s31 { char : 0; float b; char : 0; } f31(void) { while (1) {} }
// RUN: grep 'define i32 @f32()' %t &&
-struct s32 { char a; unsigned : 0; } f32(void) {}
+struct s32 { char a; unsigned : 0; } f32(void) { while (1) {} }
// RUN: grep 'define float @f33()' %t &&
-struct s33 { float a; long long : 0; } f33(void) {}
+struct s33 { float a; long long : 0; } f33(void) { while (1) {} }
// RUN: grep 'define float @f34()' %t &&
-struct s34 { struct { int : 0; } a; float b; } f34(void) {}
+struct s34 { struct { int : 0; } a; float b; } f34(void) { while (1) {} }
// RUN: grep 'define i16 @f35()' %t &&
-struct s35 { struct { int : 0; } a; char b; char c; } f35(void) {}
+struct s35 { struct { int : 0; } a; char b; char c; } f35(void) { while (1) {} }
// RUN: grep 'define i16 @f36()' %t &&
-struct s36 { struct { int : 0; } a[2][10]; char b; char c; } f36(void) {}
+struct s36 { struct { int : 0; } a[2][10]; char b; char c; } f36(void) { while (1) {} }
// RUN: grep 'define float @f37()' %t &&
-struct s37 { float c[1][1]; } f37(void) {}
+struct s37 { float c[1][1]; } f37(void) { while (1) {} }
// RUN: grep 'define void @f38(.struct.s38. noalias sret .agg.result)' %t &&
-struct s38 { char a[3]; short b; } f38(void) {}
+struct s38 { char a[3]; short b; } f38(void) { while (1) {} }
// RUN: grep 'define void @f39(.struct.s39. byval align 16 .x)' %t &&
typedef int v39 __attribute((vector_size(16)));
struct s39 { v39 x; };
void f39(struct s39 x) {}
+// <rdar://problem/7247671>
+// RUN: grep 'define i32 @f40()' %t &&
+enum e40 { ec0 = 0 };
+enum e40 f40(void) { }
+
+// RUN: grep 'define void ()\* @f41()' %t &&
+typedef void (^vvbp)(void);
+vvbp f41(void) { }
+
+// RUN: grep 'define i32 @f42()' %t &&
+struct s42 { enum e40 f0; } f42(void) { }
+
+// RUN: grep 'define i64 @f43()' %t &&
+struct s43 { enum e40 f0; int f1; } f43(void) { }
+
+// RUN: grep 'define i32 @f44()' %t &&
+struct s44 { vvbp f0; } f44(void) { }
+
+// RUN: grep 'define i64 @f45()' %t &&
+struct s45 { vvbp f0; int f1; } f45(void) { }
+
+// RUN: grep 'define void @f46(i32 %a0)' %t &&
+void f46(enum e40 a0) { }
+
+// RUN: grep 'define void @f47(void ()\* %a1)' %t &&
+void f47(vvbp a1) { }
+
+// RUN: grep 'define void @f48(i32 %a0.0)' %t &&
+struct s48 { enum e40 f0; };
+void f48(struct s48 a0) { }
+
+// RUN: grep 'define void @f49(i32 %a0.0, i32 %a0.1)' %t &&
+struct s49 { enum e40 f0; int f1; };
+void f49(struct s49 a0) { }
+
+// RUN: grep 'define void @f50(void ()\* %a0.0)' %t &&
+struct s50 { vvbp f0; };
+void f50(struct s50 a0) { }
+
+// RUN: grep 'define void @f51(void ()\* %a0.0, i32 %a0.1)' %t &&
+struct s51 { vvbp f0; int f1; };
+void f51(struct s51 a0) { }
+
// RUN: true
diff --git a/test/CodeGen/x86_64-arguments.c b/test/CodeGen/x86_64-arguments.c
index 0b68afd..19f9cda 100644
--- a/test/CodeGen/x86_64-arguments.c
+++ b/test/CodeGen/x86_64-arguments.c
@@ -7,26 +7,32 @@
// 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 '.0 = type { i64, double }' %t &&
// RUN: grep 'define .0 @f8_1()' %t &&
// RUN: grep 'define void @f8_2(.0)' %t &&
char f0(void) {
+ return 0;
}
short f1(void) {
+ return 0;
}
int f2(void) {
+ return 0;
}
float f3(void) {
+ return 0;
}
double f4(void) {
+ return 0;
}
long double f5(void) {
+ return 0;
}
void f6(char a0, short a1, int a2, long long a3, void *a4) {
@@ -42,23 +48,23 @@ union u8 {
long double a;
int b;
};
-union u8 f8_1() {}
+union u8 f8_1() { while (1) {} }
void f8_2(union u8 a0) {}
// RUN: grep 'define i64 @f9()' %t &&
-struct s9 { int a; int b; int : 0; } f9(void) {}
+struct s9 { int a; int b; int : 0; } f9(void) { while (1) {} }
// 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() {}
+union { long double a; float b; } f11() { while (1) {} }
// 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) {}
+struct s12 f12_0(void) { while (1) {} }
void f12_1(struct s12 a0) {}
// Check that sret parameter is accounted for when checking available integer
@@ -66,8 +72,9 @@ void f12_1(struct s12 a0) {}
// 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_1 { long long f0[2]; };
struct s13_0 f13(int a, int b, int c, int d,
- struct s13_1 { long long f0[2]; } e, int f) {}
+ struct s13_1 e, int f) { while (1) {} }
// RUN: grep 'define void @f14(.*, i8 signext .X)' %t &&
void f14(int a, int b, int c, int d, int e, int f,
@@ -83,9 +90,10 @@ void f17(float a, float b, float c, float d, float e, float f, float g, float h,
long double X) {}
// Check for valid coercion.
-// RUN: grep '.1 = bitcast i64. .tmp to .struct.f18_s0.' %t &&
-// RUN: grep '.2 = load .struct.f18_s0. .1, align 1' %t &&
-// RUN: grep 'store .struct.f18_s0 .2, .struct.f18_s0. .f18_arg1' %t &&
-void f18(int a, struct f18_s0 { int f0; } f18_arg1) {}
+// RUN: grep '.. = bitcast i64. .* to .struct.f18_s0.' %t &&
+// RUN: grep '.. = load .struct.f18_s0. .., align 1' %t &&
+// RUN: grep 'store .struct.f18_s0 .., .struct.f18_s0. .f18_arg1' %t &&
+struct f18_s0 { int f0; };
+void f18(int a, struct f18_s0 f18_arg1) { while (1) {} }
// RUN: true
diff --git a/test/CodeGenCXX/PR4827-cast.cpp b/test/CodeGenCXX/PR4827-cast.cpp
new file mode 100644
index 0000000..958798d
--- /dev/null
+++ b/test/CodeGenCXX/PR4827-cast.cpp
@@ -0,0 +1,5 @@
+// RUN: clang-cc -emit-llvm -o - %s
+struct A;
+struct B;
+extern A *f();
+void a() { (B *) f(); }
diff --git a/test/CodeGenCXX/PR4890-debug-info-dtor.cpp b/test/CodeGenCXX/PR4890-debug-info-dtor.cpp
new file mode 100644
index 0000000..a0d3a8d
--- /dev/null
+++ b/test/CodeGenCXX/PR4890-debug-info-dtor.cpp
@@ -0,0 +1,6 @@
+// RUN: clang-cc -emit-llvm-only -g %s
+struct X {
+ ~X();
+};
+
+X::~X() { }
diff --git a/test/CodeGenCXX/PR4983-constructor-conversion.cpp b/test/CodeGenCXX/PR4983-constructor-conversion.cpp
new file mode 100644
index 0000000..31eae2e
--- /dev/null
+++ b/test/CodeGenCXX/PR4983-constructor-conversion.cpp
@@ -0,0 +1,16 @@
+// RUN: clang-cc -emit-llvm-only %s
+
+struct A {
+ A(const char *s){}
+};
+
+struct B {
+ A a;
+
+ B() : a("test") { }
+};
+
+void f() {
+ A a("test");
+}
+
diff --git a/test/CodeGenCXX/PR5050-constructor-conversion.cpp b/test/CodeGenCXX/PR5050-constructor-conversion.cpp
new file mode 100644
index 0000000..e5f722c
--- /dev/null
+++ b/test/CodeGenCXX/PR5050-constructor-conversion.cpp
@@ -0,0 +1,19 @@
+// RUN: clang-cc -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s &&
+// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s &&
+// RUN: clang-cc -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s &&
+// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s &&
+// RUN: true
+
+struct A { A(const A&, int i1 = 1); };
+
+struct B : A { };
+
+A f(const B &b) {
+ return b;
+}
+
+// CHECK-LP64: call __ZN1AC1ERKS_i
+
+// CHECK-LP32: call L__ZN1AC1ERKS_i
+
+
diff --git a/test/CodeGenCXX/PR5093-static-member-function.cpp b/test/CodeGenCXX/PR5093-static-member-function.cpp
new file mode 100644
index 0000000..a27b08f
--- /dev/null
+++ b/test/CodeGenCXX/PR5093-static-member-function.cpp
@@ -0,0 +1,9 @@
+// RUN: clang-cc %s -emit-llvm -o - | FileCheck %s
+struct a {
+ static void f();
+};
+
+void g(a *a) {
+ // CHECK: call void @_ZN1a1fEv()
+ a->f();
+}
diff --git a/test/CodeGenCXX/anonymous-namespaces.cpp b/test/CodeGenCXX/anonymous-namespaces.cpp
new file mode 100644
index 0000000..dcfd518
--- /dev/null
+++ b/test/CodeGenCXX/anonymous-namespaces.cpp
@@ -0,0 +1,22 @@
+// RUN: clang-cc -emit-llvm %s -o - | FileCheck %s
+
+namespace {
+ // CHECK: @_ZN12_GLOBAL__N_11aE = internal global i32 0
+ int a = 0;
+
+ // CHECK: define internal i32 @_ZN12_GLOBAL__N_13fooEv()
+ int foo() {
+ return 32;
+ }
+
+ // CHECK: define internal i32 @_ZN12_GLOBAL__N_11A3fooEv()
+ namespace A {
+ int foo() {
+ return 45;
+ }
+ }
+}
+
+int concrete() {
+ return a + foo() + A::foo();
+}
diff --git a/test/CodeGenCXX/anonymous-union-member-initializer.cpp b/test/CodeGenCXX/anonymous-union-member-initializer.cpp
new file mode 100644
index 0000000..2030f40
--- /dev/null
+++ b/test/CodeGenCXX/anonymous-union-member-initializer.cpp
@@ -0,0 +1,12 @@
+// RUN: clang-cc -emit-llvm -o - %s
+
+struct A {
+ union {
+ int a;
+ void* b;
+ };
+
+ A() : a(0) { }
+};
+
+A a;
diff --git a/test/CodeGenCXX/array-pointer-decay.cpp b/test/CodeGenCXX/array-pointer-decay.cpp
new file mode 100644
index 0000000..5751b67
--- /dev/null
+++ b/test/CodeGenCXX/array-pointer-decay.cpp
@@ -0,0 +1,7 @@
+// RUN: clang-cc %s -emit-llvm -o -
+
+void f(const char*);
+
+void g() {
+ f("hello");
+}
diff --git a/test/CodeGenCXX/attr.cpp b/test/CodeGenCXX/attr.cpp
new file mode 100644
index 0000000..8077b78
--- /dev/null
+++ b/test/CodeGenCXX/attr.cpp
@@ -0,0 +1,36 @@
+// RUN: clang-cc -triple x86_64-apple-darwin -O0 -S %s -o %t.s &&
+// RUN: FileCheck --input-file=%t.s %s
+
+int foo() __attribute__((aligned(1024)));
+int foo() { }
+
+// CHECK:.align 10, 0x90
+// CHECK:.globl __Z3foov
+// CHECK:__Z3foov:
+
+
+class C {
+ virtual void bar1() __attribute__((aligned(1)));
+ virtual void bar2() __attribute__((aligned(2)));
+ virtual void bar3() __attribute__((aligned(1024)));
+} c;
+
+void C::bar1() { }
+
+// CHECK:.align 1, 0x90
+// CHECK-NEXT:.globl __ZN1C4bar1Ev
+// CHECK-NEXT:__ZN1C4bar1Ev:
+
+
+void C::bar2() { }
+
+// CHECK:.align 1, 0x90
+// CHECK-NEXT:.globl __ZN1C4bar2Ev
+// CHECK-NEXT:__ZN1C4bar2Ev:
+
+
+void C::bar3() { }
+
+// CHECK:.align 10, 0x90
+// CHECK-NEXT:.globl __ZN1C4bar3Ev
+// CHECK-NEXT:__ZN1C4bar3Ev:
diff --git a/test/CodeGenCXX/cast-conversion.cpp b/test/CodeGenCXX/cast-conversion.cpp
new file mode 100644
index 0000000..f571f54
--- /dev/null
+++ b/test/CodeGenCXX/cast-conversion.cpp
@@ -0,0 +1,33 @@
+// RUN: clang-cc -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s &&
+// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s &&
+// RUN: clang-cc -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s &&
+// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s &&
+// RUN: true
+
+struct A {
+ A(int);
+};
+
+struct B {
+ B(A);
+};
+
+int main () {
+ (B)10;
+ B(10);
+ static_cast<B>(10);
+}
+
+// CHECK-LP64: call __ZN1AC1Ei
+// CHECK-LP64: call __ZN1BC1E1A
+// CHECK-LP64: call __ZN1AC1Ei
+// CHECK-LP64: call __ZN1BC1E1A
+// CHECK-LP64: call __ZN1AC1Ei
+// CHECK-LP64: call __ZN1BC1E1A
+
+// CHECK-LP32: call L__ZN1AC1Ei
+// CHECK-LP32: call L__ZN1BC1E1A
+// CHECK-LP32: call L__ZN1AC1Ei
+// CHECK-LP32: call L__ZN1BC1E1A
+// CHECK-LP32: call L__ZN1AC1Ei
+// CHECK-LP32: call L__ZN1BC1E1A
diff --git a/test/CodeGenCXX/class-layout.cpp b/test/CodeGenCXX/class-layout.cpp
new file mode 100644
index 0000000..7255d3e
--- /dev/null
+++ b/test/CodeGenCXX/class-layout.cpp
@@ -0,0 +1,5 @@
+// RUN: clang-cc %s -emit-llvm -o %t &&
+
+// An extra byte shoudl be allocated for an empty class.
+// RUN: grep '%.truct.A = type { i8 }' %t
+struct A { } a;
diff --git a/test/CodeGenCXX/conditional-expr-lvalue.cpp b/test/CodeGenCXX/conditional-expr-lvalue.cpp
new file mode 100644
index 0000000..7b3233a
--- /dev/null
+++ b/test/CodeGenCXX/conditional-expr-lvalue.cpp
@@ -0,0 +1,7 @@
+// RUN: clang-cc -emit-llvm-only %s
+void f(bool flag) {
+ int a = 1;
+ int b = 2;
+
+ (flag ? a : b) = 3;
+}
diff --git a/test/CodeGenCXX/constructor-conversion.cpp b/test/CodeGenCXX/constructor-conversion.cpp
new file mode 100644
index 0000000..980b230
--- /dev/null
+++ b/test/CodeGenCXX/constructor-conversion.cpp
@@ -0,0 +1,55 @@
+// RUN: clang-cc -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s &&
+// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s &&
+// RUN: clang-cc -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s &&
+// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s &&
+// RUN: true
+
+extern "C" int printf(...);
+
+class X { // ...
+public:
+ X(int) : iX(2), fX(2.3) , name("HELLO\n") { }
+
+ X(const char* arg, int ix=0) { iX = ix; fX = 6.0; name = arg+ix; }
+ X(): iX(100), fX(1.2) {}
+ int iX;
+ float fX;
+ const char *name;
+ void pr(void) {
+ printf("iX = %d fX = %f name = %s\n", iX, fX, name);
+ }
+};
+
+void g(X arg) {
+ arg.pr();
+}
+
+void f(X arg) {
+ X a = 1; // a = X(1)
+
+ a.pr();
+
+ X b = "Jessie"; // b=X("Jessie",0)
+
+ b.pr();
+
+
+ a = 2; // a = X(2)
+
+ a.pr();
+}
+
+
+int main() {
+ X x;
+ f(x);
+ g(3); // g(X(3))
+}
+
+// CHECK-LP64: call __ZN1XC1Ei
+// CHECK-LP64: call __ZN1XC1EPKci
+// CHECK-LP64: call __ZN1XC1Ev
+
+// CHECK-LP32: call L__ZN1XC1Ei
+// CHECK-LP32: call L__ZN1XC1EPKci
+// CHECK-LP32: call L__ZN1XC1Ev
diff --git a/test/CodeGenCXX/constructor-default-arg.cpp b/test/CodeGenCXX/constructor-default-arg.cpp
new file mode 100644
index 0000000..7e6a7cd
--- /dev/null
+++ b/test/CodeGenCXX/constructor-default-arg.cpp
@@ -0,0 +1,40 @@
+// RUN: clang-cc -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s &&
+// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s &&
+// RUN: clang-cc -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s &&
+// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s &&
+// RUN: true
+
+extern "C" int printf(...);
+
+
+struct C {
+ C() : iC(6) {}
+ int iC;
+};
+
+int foo() {
+ return 6;
+};
+
+class X { // ...
+public:
+ X(int) {}
+ X(const X&, int i = 1, int j = 2, int k = foo()) {
+ printf("X(const X&, %d, %d, %d)\n", i, j, k);
+ }
+};
+
+int main() {
+ X a(1);
+ X b(a, 2);
+ X c = b;
+ X d(a, 5, 6);
+}
+
+// CHECK-LP64: call __ZN1XC1ERKS_iii
+// CHECK-LP64: call __ZN1XC1ERKS_iii
+// CHECK-LP64: call __ZN1XC1ERKS_iii
+
+// CHECK-LP32: call L__ZN1XC1ERKS_iii
+// CHECK-LP32: call L__ZN1XC1ERKS_iii
+// CHECK-LP32: call L__ZN1XC1ERKS_iii
diff --git a/test/CodeGenCXX/constructor-for-array-members.cpp b/test/CodeGenCXX/constructor-for-array-members.cpp
new file mode 100644
index 0000000..fbb13e0
--- /dev/null
+++ b/test/CodeGenCXX/constructor-for-array-members.cpp
@@ -0,0 +1,44 @@
+// RUN: clang-cc -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s &&
+// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s &&
+// RUN: clang-cc -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s &&
+// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s &&
+// RUN: true
+
+extern "C" int printf(...);
+
+int i = 1234;
+float vf = 1.00;
+
+struct S {
+ S() : iS(i++), f1(vf++) {printf("S::S()\n");}
+ ~S(){printf("S::~S(iS = %d f1 = %f)\n", iS, f1); }
+ int iS;
+ float f1;
+};
+
+struct M {
+ double dM;
+ S ARR_S[3];
+ void pr() {
+ for (int i = 0; i < 3; i++)
+ printf("ARR_S[%d].iS = %d ARR_S[%d].f1 = %f\n", i, ARR_S[i].iS, i, ARR_S[i].f1);
+
+ for (int i = 0; i < 2; i++)
+ for (int j = 0; j < 3; j++)
+ for (int k = 0; k < 4; k++)
+ printf("MULTI_ARR[%d][%d][%d].iS = %d MULTI_ARR[%d][%d][%d].f1 = %f\n",
+ i,j,k, MULTI_ARR[i][j][k].iS, i,j,k, MULTI_ARR[i][j][k].f1);
+
+ }
+
+ S MULTI_ARR[2][3][4];
+};
+
+int main() {
+ M m1;
+ m1.pr();
+}
+
+// CHECK-LP64: call __ZN1SC1Ev
+
+// CHECK-LP32: call L__ZN1SC1Ev
diff --git a/test/CodeGenCXX/constructor-init-reference.cpp b/test/CodeGenCXX/constructor-init-reference.cpp
new file mode 100644
index 0000000..040441f
--- /dev/null
+++ b/test/CodeGenCXX/constructor-init-reference.cpp
@@ -0,0 +1,9 @@
+// RUN: clang-cc -emit-llvm -o - %s | grep "store i32\* @x, i32\*\*"
+
+int x;
+class A {
+ int& y;
+ A() : y(x) {}
+};
+A z;
+
diff --git a/test/CodeGenCXX/constructor-init.cpp b/test/CodeGenCXX/constructor-init.cpp
new file mode 100644
index 0000000..1b02512
--- /dev/null
+++ b/test/CodeGenCXX/constructor-init.cpp
@@ -0,0 +1,61 @@
+// RUN: clang-cc %s -emit-llvm -o %t
+
+extern "C" int printf(...);
+
+struct M {
+ M() { printf("M()\n"); }
+ M(int i) { iM = i; printf("M(%d)\n", i); }
+ int iM;
+ void MPR() {printf("iM = %d\n", iM); };
+};
+
+struct P {
+ P() { printf("P()\n"); }
+ P(int i) { iP = i; printf("P(%d)\n", i); }
+ int iP;
+ void PPR() {printf("iP = %d\n", iP); };
+};
+
+struct Q {
+ Q() { printf("Q()\n"); }
+ Q(int i) { iQ = i; printf("Q(%d)\n", i); }
+ int iQ;
+ void QPR() {printf("iQ = %d\n", iQ); };
+};
+
+struct N : M , P, Q {
+ N() : f1(1.314), P(2000), ld(00.1234+f1), M(1000), Q(3000),
+ d1(3.4567), i1(1234), m1(100) { printf("N()\n"); }
+ M m1;
+ M m2;
+ float f1;
+ int i1;
+ float d1;
+ void PR() {
+ printf("f1 = %f d1 = %f i1 = %d ld = %f \n", f1,d1,i1, ld);
+ MPR();
+ PPR();
+ QPR();
+ printf("iQ = %d\n", iQ);
+ printf("iP = %d\n", iP);
+ printf("iM = %d\n", iM);
+ // FIXME. We don't yet support this syntax.
+ // printf("iQ = %d\n", (*this).iQ);
+ printf("iQ = %d\n", this->iQ);
+ printf("iP = %d\n", this->iP);
+ printf("iM = %d\n", this->iM);
+ }
+ float ld;
+ float ff;
+ M arr_m[3];
+ P arr_p[1][3];
+ Q arr_q[2][3][4];
+};
+
+int main() {
+ M m1;
+
+ N n1;
+ n1.PR();
+}
+
diff --git a/test/CodeGenCXX/constructor-template.cpp b/test/CodeGenCXX/constructor-template.cpp
new file mode 100644
index 0000000..8c4f2c9
--- /dev/null
+++ b/test/CodeGenCXX/constructor-template.cpp
@@ -0,0 +1,56 @@
+// RUN: clang-cc -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s &&
+// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s &&
+// RUN: clang-cc -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s &&
+// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s &&
+// RUN: true
+
+// PR4826
+struct A {
+ A() {
+ }
+};
+
+template<typename T>
+struct B {
+ B(T) {}
+
+ A nodes;
+};
+
+
+// PR4853
+template <typename T> class List {
+public:
+ List(){ } // List<BinomialNode<int>*>::List() remains undefined.
+ ~List() {}
+};
+
+template <typename T> class Node {
+ int i;
+public:
+ Node(){ } // Node<BinomialNode<int>*>::Node() remains undefined.
+ ~Node() {}
+};
+
+
+template<typename T> class BinomialNode : Node<BinomialNode<T>*> {
+public:
+ BinomialNode(T value) {}
+ List<BinomialNode<T>*> nodes;
+};
+
+int main() {
+ B<int> *n = new B<int>(4);
+ BinomialNode<int> *node = new BinomialNode<int>(1);
+ delete node;
+}
+
+// CHECK-LP64: __ZN4ListIP12BinomialNodeIiEED1Ev:
+// CHECK-LP64: __ZN4ListIP12BinomialNodeIiEED2Ev:
+// CHECK-LP64: __ZN4NodeIP12BinomialNodeIiEEC1Ev:
+// CHECK-LP64: __ZN4ListIP12BinomialNodeIiEEC1Ev:
+
+// CHECK-LP32: __ZN4ListIP12BinomialNodeIiEED1Ev:
+// CHECK-LP32: __ZN4ListIP12BinomialNodeIiEED2Ev:
+// CHECK-LP32: __ZN4NodeIP12BinomialNodeIiEEC1Ev:
+// CHECK-LP32: __ZN4ListIP12BinomialNodeIiEEC1Ev:
diff --git a/test/CodeGenCXX/conversion-function.cpp b/test/CodeGenCXX/conversion-function.cpp
new file mode 100644
index 0000000..0bfd4af
--- /dev/null
+++ b/test/CodeGenCXX/conversion-function.cpp
@@ -0,0 +1,115 @@
+// RUN: clang-cc -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s &&
+// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s &&
+// RUN: clang-cc -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s &&
+// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s &&
+// RUN: true
+
+extern "C" int printf(...);
+struct S {
+ operator int();
+};
+
+S::operator int() {
+ return 10;
+}
+
+
+class X { // ...
+ public: operator int() { printf("operator int()\n"); return iX; }
+ public: operator float() { printf("operator float()\n"); return fX; }
+ X() : iX(100), fX(1.234) {}
+ int iX;
+ float fX;
+};
+
+X x;
+
+struct Z {
+ operator X() { printf("perator X()\n"); x.iX += iZ; x.fX += fZ; return x; }
+ int iZ;
+ float fZ;
+ Z() : iZ(1), fZ(1.00) {}
+};
+
+Z z;
+
+class Y { // ...
+ public: operator Z(){printf("perator Z()\n"); return z; }
+};
+
+Y y;
+
+int count=0;
+class O { // ...
+public:
+ operator int(){ return ++iO; }
+ O() : iO(count++) {}
+ int iO;
+};
+
+void g(O a, O b) {
+ int i = (a) ? 1+a : 0;
+ int j = (a&&b) ? a+b : i;
+ if (a) { }
+ printf("i = %d j = %d a.iO = %d b.iO = %d\n", i, j, a.iO, b.iO);
+}
+
+int main() {
+ int c = X(Z(y)); // OK: y.operator Z().operator X().operator int()
+ printf("c = %d\n", c);
+ float f = X(Z(y));
+ printf("f = %f\n", f);
+ int i = x;
+ printf("i = %d float = %f\n", i, float(x));
+ i = int(X(Z(y)));
+ f = float(X(Z(y)));
+ printf("i = %d float = %f\n", i,f);
+ f = (float)x;
+ i = (int)x;
+ printf("i = %d float = %f\n", i,f);
+
+ int d = (X)((Z)y);
+ printf("d = %d\n", d);
+
+ int e = (int)((X)((Z)y));
+ printf("e = %d\n", e);
+ O o1, o2;
+ g(o1, o2);
+}
+
+// Test. Conversion in base class is visible in derived class.
+class XB {
+ int a;
+public:
+ operator int();
+};
+
+class Yb : public XB {
+ double b;
+public:
+ operator char();
+};
+
+void f(Yb& a) {
+ int i = a; // OK. calls XB::operator int();
+ char ch = a; // OK. calls Yb::operator char();
+}
+
+
+// CHECK-LP64: .globl __ZN1ScviEv
+// CHECK-LP64-NEXT: __ZN1ScviEv:
+// CHECK-LP64: call __ZN1Ycv1ZEv
+// CHECK-LP64: call __ZN1Zcv1XEv
+// CHECK-LP64: call __ZN1XcviEv
+// CHECK-LP64: call __ZN1XcvfEv
+// CHECK-LP64: call __ZN2XBcviEv
+// CHECK-LP64: call __ZN2YbcvcEv
+
+// CHECK-LP32: .globl __ZN1ScviEv
+// CHECK-LP32-NEXT: __ZN1ScviEv:
+// CHECK-LP32: call L__ZN1Ycv1ZEv
+// CHECK-LP32: call L__ZN1Zcv1XEv
+// CHECK-LP32: call L__ZN1XcviEv
+// CHECK-LP32: call L__ZN1XcvfEv
+// CHECK-LP32: call L__ZN2XBcviEv
+// CHECK-LP32: call L__ZN2YbcvcEv
diff --git a/test/CodeGenCXX/convert-to-fptr.cpp b/test/CodeGenCXX/convert-to-fptr.cpp
new file mode 100644
index 0000000..c0bd2f7
--- /dev/null
+++ b/test/CodeGenCXX/convert-to-fptr.cpp
@@ -0,0 +1,47 @@
+// RUN: clang-cc -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s &&
+// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s &&
+// RUN: clang-cc -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s &&
+// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s &&
+// RUN: true
+
+extern "C" int printf(...);
+
+int f1(int arg) { return arg; };
+
+int f2(float arg) { return int(arg); };
+
+typedef int (*fp1)(int);
+
+typedef int (*fp2)(float);
+
+struct A {
+ operator fp1() { return f1; }
+ operator fp2() { return f2; }
+} a;
+
+
+// Test for function reference.
+typedef int (&fr1)(int);
+typedef int (&fr2)(float);
+
+struct B {
+ operator fr1() { return f1; }
+ operator fr2() { return f2; }
+} b;
+
+int main()
+{
+ int i = a(10); // Calls f1 via pointer returned from conversion function
+ printf("i = %d\n", i);
+
+ int j = b(20); // Calls f1 via pointer returned from conversion function
+ printf("j = %d\n", j);
+ return 0;
+}
+
+// CHECK-LP64: call __ZN1AcvPFiiEEv
+// CHECK-LP64: call __ZN1BcvRFiiEEv
+
+// CHECK-LP32: call L__ZN1AcvPFiiEEv
+// CHECK-LP32: call L__ZN1BcvRFiiEEv
+
diff --git a/test/CodeGenCXX/copy-assign-synthesis-1.cpp b/test/CodeGenCXX/copy-assign-synthesis-1.cpp
new file mode 100644
index 0000000..d4a93af
--- /dev/null
+++ b/test/CodeGenCXX/copy-assign-synthesis-1.cpp
@@ -0,0 +1,109 @@
+// RUN: clang-cc -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s &&
+// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s &&
+// RUN: clang-cc -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s &&
+// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s &&
+// RUN: true
+
+extern "C" int printf(...);
+
+struct B {
+ B() : B1(3.14), B2(3.15), auB2(3.16) {}
+ float B1;
+ float B2;
+ void pr() {
+ printf("B1 = %f B2 = %f auB1 = %f\n", B1, B2, auB1);
+ }
+
+ B& operator=(const B& arg) { B1 = arg.B1; B2 = arg.B2;
+ auB1 = arg.auB1; return *this; }
+ union {
+ float auB1;
+ float auB2;
+ };
+};
+
+struct M {
+ M() : M1(10), M2(11) , auM1(12) {}
+ int M1;
+ int M2;
+ void pr() {
+ printf("M1 = %d M2 = %d auM1 = %d auM2 = %d\n", M1, M2, auM1, auM2);
+ }
+ union {
+ int auM1;
+ int auM2;
+ };
+};
+
+struct N : B {
+ N() : N1(20), N2(21) {}
+ int N1;
+ int N2;
+ void pr() {
+ printf("N1 = %d N2 = %d\n", N1, N2);
+ for (unsigned i = 0; i < 3; i++)
+ for (unsigned j = 0; j < 2; j++)
+ printf("arr_b[%d][%d] = %f\n", i,j,arr_b[i][j].B1);
+ B::pr();
+ }
+ N& operator=(const N& arg) {
+ N1 = arg.N1; N2 = arg.N2;
+ for (unsigned i = 0; i < 3; i++)
+ for (unsigned j = 0; j < 2; j++)
+ arr_b[i][j] = arg.arr_b[i][j];
+ return *this;
+ }
+ B arr_b[3][2];
+};
+
+struct Q : B {
+ Q() : Q1(30), Q2(31) {}
+ int Q1;
+ int Q2;
+ void pr() {
+ printf("Q1 = %d Q2 = %d\n", Q1, Q2);
+ }
+};
+
+
+struct X : M , N {
+ X() : d(0.0), d1(1.1), d2(1.2), d3(1.3) {}
+ double d;
+ double d1;
+ double d2;
+ double d3;
+ void pr() {
+ printf("d = %f d1 = %f d2 = %f d3 = %f\n", d, d1,d2,d3);
+ M::pr(); N::pr();
+ q1.pr(); q2.pr();
+ }
+
+ Q q1, q2;
+};
+
+
+X srcX;
+X dstX;
+X dstY;
+
+int main() {
+ dstY = dstX = srcX;
+ srcX.pr();
+ dstX.pr();
+ dstY.pr();
+}
+
+// CHECK-LP64: .globl __ZN1XaSERKS_
+// CHECK-LP64: .weak_definition __ZN1XaSERKS_
+// CHECK-LP64: __ZN1XaSERKS_:
+// CHECK-LP64: .globl __ZN1QaSERKS_
+// CHECK-LP64: .weak_definition __ZN1QaSERKS_
+// CHECK-LP64: __ZN1QaSERKS_:
+
+// CHECK-LP32: .globl __ZN1XaSERKS_
+// CHECK-LP32: .weak_definition __ZN1XaSERKS_
+// CHECK-LP32: __ZN1XaSERKS_:
+// CHECK-LP32: .globl __ZN1QaSERKS_
+// CHECK-LP32: .weak_definition __ZN1QaSERKS_
+// CHECK-LP32: __ZN1QaSERKS_:
+
diff --git a/test/CodeGenCXX/copy-assign-synthesis.cpp b/test/CodeGenCXX/copy-assign-synthesis.cpp
new file mode 100644
index 0000000..f9baa8f
--- /dev/null
+++ b/test/CodeGenCXX/copy-assign-synthesis.cpp
@@ -0,0 +1,79 @@
+// RUN: clang-cc -emit-llvm -o %t %s &&
+// RUN: grep "_ZN1XaSERK1X" %t | count 0
+
+extern "C" int printf(...);
+
+struct B {
+ B() : B1(3.14), B2(3.15), auB2(3.16) {}
+ float B1;
+ float B2;
+ void pr() {
+ printf("B1 = %f B2 = %f auB1 = %f\n", B1, B2, auB1);
+ }
+
+ union {
+ float auB1;
+ float auB2;
+ };
+};
+
+struct M {
+ M() : M1(10), M2(11) , auM1(12) {}
+ int M1;
+ int M2;
+ void pr() {
+ printf("M1 = %d M2 = %d auM1 = %d auM2 = %d\n", M1, M2, auM1, auM2);
+ }
+ union {
+ int auM1;
+ int auM2;
+ };
+};
+
+struct N : B {
+ N() : N1(20), N2(21) {}
+ int N1;
+ int N2;
+ void pr() {
+ printf("N1 = %d N2 = %d\n", N1, N2);
+ B::pr();
+ }
+};
+
+struct Q {
+ Q() : Q1(30), Q2(31) {}
+ int Q1;
+ int Q2;
+ void pr() {
+ printf("Q1 = %d Q2 = %d\n", Q1, Q2);
+ }
+};
+
+
+struct X : M , N {
+ X() : d(0.0), d1(1.1), d2(1.2), d3(1.3) {}
+ double d;
+ double d1;
+ double d2;
+ double d3;
+ void pr() {
+ printf("d = %f d1 = %f d2 = %f d3 = %f\n", d, d1,d2,d3);
+ M::pr(); N::pr();
+ q1.pr(); q2.pr();
+ }
+
+ Q q1, q2;
+};
+
+
+X srcX;
+X dstX;
+X dstY;
+
+int main() {
+ dstY = dstX = srcX;
+ srcX.pr();
+ dstX.pr();
+ dstY.pr();
+}
+
diff --git a/test/CodeGenCXX/copy-constructor-elim.cpp b/test/CodeGenCXX/copy-constructor-elim.cpp
new file mode 100644
index 0000000..daef92c
--- /dev/null
+++ b/test/CodeGenCXX/copy-constructor-elim.cpp
@@ -0,0 +1,43 @@
+// RUN: clang-cc -emit-llvm -o %t %s &&
+// RUN: grep "_ZN1CC1ERK1C" %t | count 0 &&
+// RUN: grep "_ZN1SC1ERK1S" %t | count 0 &&
+// RUN: true
+
+extern "C" int printf(...);
+
+
+struct C {
+ C() : iC(6) {printf("C()\n"); }
+ C(const C& c) { printf("C(const C& c)\n"); }
+ int iC;
+};
+
+C foo() {
+ return C();
+};
+
+class X { // ...
+public:
+ X(int) {}
+ X(const X&, int i = 1, int j = 2, C c = foo()) {
+ printf("X(const X&, %d, %d, %d)\n", i, j, c.iC);
+ }
+};
+
+
+struct S {
+ S();
+};
+
+S::S() { printf("S()\n"); }
+
+void Call(S) {};
+
+int main() {
+ X a(1);
+ X b(a, 2);
+ X c = b;
+ X d(a, 5, 6);
+ S s;
+ Call(s);
+}
diff --git a/test/CodeGenCXX/copy-constructor-synthesis.cpp b/test/CodeGenCXX/copy-constructor-synthesis.cpp
new file mode 100644
index 0000000..47971af
--- /dev/null
+++ b/test/CodeGenCXX/copy-constructor-synthesis.cpp
@@ -0,0 +1,110 @@
+// RUN: clang-cc -triple x86_64-apple-darwin -S %s -o %t-64.s &&
+// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s &&
+// RUN: clang-cc -triple i386-apple-darwin -S %s -o %t-32.s &&
+// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s &&
+// RUN: true
+
+extern "C" int printf(...);
+
+int init = 100;
+
+struct M {
+ int iM;
+ M() : iM(init++) {}
+};
+
+struct N {
+ int iN;
+ N() : iN(200) {}
+ N(N const & arg){this->iN = arg.iN; }
+};
+
+struct P {
+ int iP;
+ P() : iP(init++) {}
+};
+
+
+struct X : M, N, P { // ...
+ X() : f1(1.0), d1(2.0), i1(3), name("HELLO"), bf1(0xff), bf2(0xabcd),
+ au_i1(1234), au1_4("MASKED") {}
+ P p0;
+ void pr() {
+ printf("iM = %d iN = %d, m1.iM = %d\n", iM, iN, m1.iM);
+ printf("im = %d p0.iP = %d, p1.iP = %d\n", iP, p0.iP, p1.iP);
+ printf("f1 = %f d1 = %f i1 = %d name(%s) \n", f1, d1, i1, name);
+ printf("bf1 = %x bf2 = %x\n", bf1, bf2);
+ printf("au_i2 = %d\n", au_i2);
+ printf("au1_1 = %s\n", au1_1);
+ }
+ M m1;
+ P p1;
+ float f1;
+ double d1;
+ int i1;
+ const char *name;
+ unsigned bf1 : 8;
+ unsigned bf2 : 16;
+
+ union {
+ int au_i1;
+ int au_i2;
+ };
+ union {
+ const char * au1_1;
+ float au1_2;
+ int au1_3;
+ const char * au1_4;
+ };
+};
+
+static int ix = 1;
+// class with user-defined copy constructor.
+struct S {
+ S() : iS(ix++) { }
+ S(const S& arg) { *this = arg; }
+ int iS;
+};
+
+// class with trivial copy constructor.
+struct I {
+ I() : iI(ix++) { }
+ int iI;
+};
+
+struct XM {
+ XM() { }
+ double dXM;
+ S ARR_S[3][4][2];
+ void pr() {
+ for (unsigned i = 0; i < 3; i++)
+ for (unsigned j = 0; j < 4; j++)
+ for (unsigned k = 0; k < 2; k++)
+ printf("ARR_S[%d][%d][%d] = %d\n", i,j,k, ARR_S[i][j][k].iS);
+ for (unsigned i = 0; i < 3; i++)
+ for (unsigned k = 0; k < 2; k++)
+ printf("ARR_I[%d][%d] = %d\n", i,k, ARR_I[i][k].iI);
+ }
+ I ARR_I[3][2];
+};
+
+int main() {
+ X a;
+ X b(a);
+ b.pr();
+ X x;
+ X c(x);
+ c.pr();
+
+ XM m0;
+ XM m1 = m0;
+ m1.pr();
+}
+
+// CHECK-LP64: .globl __ZN1XC1ERKS_
+// CHECK-LP64: .weak_definition __ZN1XC1ERKS_
+// CHECK-LP64: __ZN1XC1ERKS_:
+
+// CHECK-LP32: .globl __ZN1XC1ERKS_
+// CHECK-LP32: .weak_definition __ZN1XC1ERKS_
+// CHECK-LP32: __ZN1XC1ERKS_:
diff --git a/test/CodeGenCXX/decl-ref-init.cpp b/test/CodeGenCXX/decl-ref-init.cpp
new file mode 100644
index 0000000..27d200f
--- /dev/null
+++ b/test/CodeGenCXX/decl-ref-init.cpp
@@ -0,0 +1,31 @@
+// RUN: clang-cc -triple x86_64-apple-darwin -S %s -o %t-64.s &&
+// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s &&
+// RUN: clang-cc -triple i386-apple-darwin -S %s -o %t-32.s &&
+// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s &&
+// RUN: true
+
+struct A {};
+
+struct B
+{
+ operator A&();
+};
+
+
+struct D : public B {
+ operator A();
+};
+
+extern B f();
+extern D d();
+
+int main() {
+ const A& rca = f();
+ const A& rca2 = d();
+}
+
+// CHECK-LP64: call __ZN1BcvR1AEv
+// CHECK-LP64: call __ZN1BcvR1AEv
+
+// CHECK-LP32: call L__ZN1BcvR1AEv
+// CHECK-LP32: call L__ZN1BcvR1AEv
diff --git a/test/CodeGenCXX/default-arg-temps.cpp b/test/CodeGenCXX/default-arg-temps.cpp
index 2dcf773..2651446 100644
--- a/test/CodeGenCXX/default-arg-temps.cpp
+++ b/test/CodeGenCXX/default-arg-temps.cpp
@@ -7,9 +7,19 @@ struct T {
void f(const T& t = T());
+class X { // ...
+public:
+ X();
+ X(const X&, const T& t = T());
+};
+
void g() {
- // RUN: grep "call void @_ZN1TC1Ev" %t | count 2 &&
- // RUN: grep "call void @_ZN1TD1Ev" %t | count 2
+ // RUN: grep "call void @_ZN1TC1Ev" %t | count 4 &&
+ // RUN: grep "call void @_ZN1TD1Ev" %t | count 4
f();
f();
+
+ X a;
+ X b(a);
+ X c = a;
}
diff --git a/test/CodeGenCXX/default-constructor-for-members.cpp b/test/CodeGenCXX/default-constructor-for-members.cpp
new file mode 100644
index 0000000..2d04bc9
--- /dev/null
+++ b/test/CodeGenCXX/default-constructor-for-members.cpp
@@ -0,0 +1,24 @@
+// RUN: clang-cc -triple x86_64-apple-darwin -S %s -o %t-64.s &&
+// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s &&
+// RUN: clang-cc -triple i386-apple-darwin -S %s -o %t-32.s &&
+// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s &&
+// RUN: true
+
+extern "C" int printf(...);
+
+struct S {
+ S() { printf("S::S()\n"); }
+ int iS;
+};
+
+struct M {
+ S ARR_S;
+};
+
+int main() {
+ M m1;
+}
+
+// CHECK-LP64: call __ZN1SC1Ev
+
+// CHECK-LP32: call L__ZN1SC1Ev
diff --git a/test/CodeGenCXX/default-destructor-synthesis.cpp b/test/CodeGenCXX/default-destructor-synthesis.cpp
new file mode 100644
index 0000000..9cc802c
--- /dev/null
+++ b/test/CodeGenCXX/default-destructor-synthesis.cpp
@@ -0,0 +1,60 @@
+// RUN: clang-cc -triple x86_64-apple-darwin -std=c++0x -O0 -S %s -o %t-64.s &&
+// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s &&
+// RUN: clang-cc -triple i386-apple-darwin -std=c++0x -O0 -S %s -o %t-32.s &&
+// RUN: FileCheck -check-prefix LP32 -input-file=%t-32.s %s &&
+// RUN: true
+
+extern "C" int printf(...);
+
+int count = 1;
+
+struct S {
+ S() : iS(count++), fS(1.23) {};
+ ~S(){printf("S::~S(%d, %f)\n", iS, fS); };
+ int iS;
+ float fS;
+};
+
+struct Q {
+ Q() : iQ(count++), dQ(2.34) {};
+ ~Q(){printf("Q::~Q(%d, %f)\n", iQ, dQ); };
+ int iQ;
+ double dQ;
+};
+
+struct P {
+ P() : fP(3.45) , iP(count++) {};
+ ~P(){printf("P::~P(%d, %f)\n", iP, fP); };
+ float fP;
+ int iP;
+};
+
+struct M : Q, P {
+ S s;
+
+ Q q;
+
+ P p;
+
+ P p_arr[3];
+
+ Q q_arr[2][3];
+
+};
+
+M gm;
+
+int main() {M m1;}
+
+// CHECK-LP64: call __ZN1MC1Ev
+// CHECK-LP64: call __ZN1MD1Ev
+// CHECK-LP64: .globl __ZN1MD1Ev
+// CHECK-LP64-NEXT: .weak_definition __ZN1MD1Ev
+// CHECK-LP64-NEXT: __ZN1MD1Ev:
+
+
+// CHECK-LP32: call L__ZN1MC1Ev
+// CHECK-LP32: call L__ZN1MD1Ev
+// CHECK-LP32: .globl __ZN1MD1Ev
+// CHECK-LP32-NEXT: .weak_definition __ZN1MD1Ev
+// CHECK-LP32-NEXT:__ZN1MD1Ev:
diff --git a/test/CodeGenCXX/delete.cpp b/test/CodeGenCXX/delete.cpp
new file mode 100644
index 0000000..9e3feef
--- /dev/null
+++ b/test/CodeGenCXX/delete.cpp
@@ -0,0 +1,37 @@
+// RUN: clang-cc %s -emit-llvm -o %t &&
+
+void t1(int *a) {
+ delete a;
+}
+
+struct S {
+ int a;
+};
+
+// POD types.
+void t3(S *s) {
+ delete s;
+}
+
+// Non-POD
+struct T {
+ ~T();
+ int a;
+};
+
+void t4(T *t) {
+ // RUN: grep "call void @_ZN1TD1Ev" %t | count 1
+ delete t;
+}
+
+// PR5102
+template <typename T>
+class A {
+ operator T *() const;
+};
+
+void f() {
+ A<char*> a;
+
+ delete a;
+}
diff --git a/test/CodeGenCXX/derived-to-base.cpp b/test/CodeGenCXX/derived-to-base.cpp
new file mode 100644
index 0000000..63492d6
--- /dev/null
+++ b/test/CodeGenCXX/derived-to-base.cpp
@@ -0,0 +1,16 @@
+// RUN: clang-cc -emit-llvm %s -o -
+struct A {
+ void f();
+
+ int a;
+};
+
+struct B : A {
+ double b;
+};
+
+void f() {
+ B b;
+
+ b.f();
+}
diff --git a/test/CodeGenCXX/destructor-calls.cpp b/test/CodeGenCXX/destructor-calls.cpp
new file mode 100644
index 0000000..3f0288b
--- /dev/null
+++ b/test/CodeGenCXX/destructor-calls.cpp
@@ -0,0 +1,41 @@
+// RUN: clang-cc %s -emit-llvm -o %t
+
+extern "C" int printf(...);
+
+static int val;
+
+struct B {
+ B() : iB(++val) { printf("B()\n"); }
+ int iB;
+ ~B() { printf("~B(%d)\n", iB); --val; }
+};
+
+struct M : B {
+ M() : iM(++val) { printf("M()\n"); }
+ int iM;
+ ~M() { printf("~M(%d)\n", iM); --val; }
+};
+
+struct P {
+ P() : iP(++val) { printf("P()\n"); }
+ int iP;
+ ~P() { printf("~P(%d)\n", iP); --val; }
+};
+
+struct N : M, P {
+ N() { printf("N()\n"); iN = ++val; }
+ ~N() { printf("~N(%d) val = %d\n", iN, --val); }
+ int iN;
+ M m;
+ P p;
+};
+
+struct O : B {
+ ~O() { return; }
+};
+
+int main() {
+ N n1;
+ N n2;
+ O o;
+}
diff --git a/test/CodeGenCXX/destructors.cpp b/test/CodeGenCXX/destructors.cpp
new file mode 100644
index 0000000..44d2b29
--- /dev/null
+++ b/test/CodeGenCXX/destructors.cpp
@@ -0,0 +1,30 @@
+// RUN: clang-cc %s -emit-llvm -o -
+struct A {
+ int a;
+
+ ~A();
+};
+
+// Base with non-trivial destructor
+struct B : A {
+ ~B();
+};
+
+B::~B() { }
+
+// Field with non-trivial destructor
+struct C {
+ A a;
+
+ ~C();
+};
+
+C::~C() { }
+
+// PR5084
+template<typename T>
+class A1 {
+ ~A1();
+};
+
+template<> A1<char>::~A1();
diff --git a/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp b/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp
new file mode 100644
index 0000000..cbf55ad
--- /dev/null
+++ b/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp
@@ -0,0 +1,47 @@
+// RUN: clang-cc %s -emit-llvm -o - | FileCheck %s
+
+struct A {
+ virtual void f();
+
+ A h();
+};
+
+A g();
+
+void f(A a, A *ap, A& ar) {
+ // This should not be a virtual function call.
+
+ // CHECK: call void @_ZN1A1fEv(%struct.A* %a)
+ a.f();
+
+ // CHECK: call void %
+ ap->f();
+
+ // CHECK: call void %
+ ar.f();
+
+ // CHECK: call void @_ZN1A1fEv
+ A().f();
+
+ // CHECK: call void @_ZN1A1fEv
+ g().f();
+
+ // CHECK: call void @_ZN1A1fEv
+ a.h().f();
+}
+
+struct B {
+ virtual void f();
+ ~B();
+
+ B h();
+};
+
+
+void f() {
+ // CHECK: call void @_ZN1B1fEv
+ B().f();
+
+ // CHECK: call void @_ZN1B1fEv
+ B().h().f();
+}
diff --git a/test/CodeGenCXX/explicit-instantiation.cpp b/test/CodeGenCXX/explicit-instantiation.cpp
index 38966aa..8a9e65c 100644
--- a/test/CodeGenCXX/explicit-instantiation.cpp
+++ b/test/CodeGenCXX/explicit-instantiation.cpp
@@ -1,11 +1,14 @@
-// RUN: clang-cc -emit-llvm -femit-all-decls -o %t %s &&
-// RUN: grep "_ZNK4plusIillEclERKiRKl" %t | count 1
+// RUN: clang-cc -emit-llvm -triple i686-pc-linue-gnu -o %t %s &&
+// RUN: grep "define i32 @_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;
- }
+ Result operator()(const T& t, const U& u) const;
};
+template<typename T, typename U, typename Result>
+Result plus<T, U, Result>::operator()(const T& t, const U& u) const {
+ return t + u;
+}
+
template struct plus<int, long, long>;
diff --git a/test/CodeGenCXX/function-template-specialization.cpp b/test/CodeGenCXX/function-template-specialization.cpp
index bea3af2..677be4c 100644
--- a/test/CodeGenCXX/function-template-specialization.cpp
+++ b/test/CodeGenCXX/function-template-specialization.cpp
@@ -1,4 +1,4 @@
-// RUN: clang-cc -emit-llvm %s -o %t &&
+// RUN: clang-cc -emit-llvm %s -o - | FileCheck %s
template<typename T, typename U>
T* next(T* ptr, const U& diff);
@@ -8,11 +8,10 @@ T* next(T* ptr, const U& diff) {
}
void test(int *iptr, float *fptr, int diff) {
- // FIXME: should be "_Z4nextIiiEPT_S1_RKT0_"
- // RUN: grep "_Z4nextIiiEPiPiRKi" %t &&
+ // CHECK: _Z4nextIiiEPT_S1_RKT0_
iptr = next(iptr, diff);
- // FIXME: should be "_Z4nextIfiEPT_S1_RKT0_"
- // RUN: grep "_Z4nextIfiEPfPfRKi" %t &&
+
+ // CHECK: _Z4nextIfiEPT_S1_RKT0_
fptr = next(fptr, diff);
}
@@ -21,7 +20,7 @@ T* next(T* ptr, const U& diff);
void test2(int *iptr, double *dptr, int diff) {
iptr = next(iptr, diff);
- // FIXME: should be "_Z4nextIdiEPT_S1_RKT0_"
- // RUN: grep "_Z4nextIdiEPdPdRKi" %t
+
+ // CHECK: _Z4nextIdiEPT_S1_RKT0_
dptr = next(dptr, diff);
-} \ No newline at end of file
+}
diff --git a/test/CodeGenCXX/global-init.cpp b/test/CodeGenCXX/global-init.cpp
new file mode 100644
index 0000000..ae450e1
--- /dev/null
+++ b/test/CodeGenCXX/global-init.cpp
@@ -0,0 +1,16 @@
+// RUN: clang-cc -triple=x86_64-apple-darwin10 -emit-llvm %s -o - |FileCheck %s
+
+struct A {
+ A();
+ ~A();
+};
+
+struct B { B(); ~B(); };
+
+// CHECK: call void @_ZN1AC1Ev(%struct.A* @a)
+// CHECK: call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.A*)* @_ZN1AD1Ev to void (i8*)*), i8* getelementptr inbounds (%struct.A* @a, i32 0, i32 0), i8* bitcast (i8** @__dso_handle to i8*))
+A a;
+
+// CHECK: call void @_ZN1BC1Ev(%struct.A* @b)
+// CHECK: call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.A*)* @_ZN1BD1Ev to void (i8*)*), i8* getelementptr inbounds (%struct.A* @b, i32 0, i32 0), i8* bitcast (i8** @__dso_handle to i8*))
+B b;
diff --git a/test/CodeGenCXX/mangle-extreme.cpp b/test/CodeGenCXX/mangle-extreme.cpp
new file mode 100644
index 0000000..77558d2
--- /dev/null
+++ b/test/CodeGenCXX/mangle-extreme.cpp
@@ -0,0 +1,47 @@
+// RUN: clang-cc -emit-llvm %s -o - -triple=x86_64-apple-darwin9 | FileCheck %s
+
+struct X { };
+
+// CHECK: define void @_Z1fPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP1XS13_S12_S11_S10_SZ_SY_SX_SW_SV_SU_ST_SS_SR_SQ_SP_SO_SN_SM_SL_SK_SJ_SI_SH_SG_SF_SE_SD_SC_SB_SA_S9_S8_S7_S6_S5_S4_S3_S2_S1_S0_S_(
+void f(X****************************************,
+ X****************************************,
+ X***************************************,
+ X**************************************,
+ X*************************************,
+ X************************************,
+ X***********************************,
+ X**********************************,
+ X*********************************,
+ X********************************,
+ X*******************************,
+ X******************************,
+ X*****************************,
+ X****************************,
+ X***************************,
+ X**************************,
+ X*************************,
+ X************************,
+ X***********************,
+ X**********************,
+ X*********************,
+ X********************,
+ X*******************,
+ X******************,
+ X*****************,
+ X****************,
+ X***************,
+ X**************,
+ X*************,
+ X************,
+ X***********,
+ X**********,
+ X*********,
+ X********,
+ X*******,
+ X******,
+ X*****,
+ X****,
+ X***,
+ X**,
+ X*,
+ X) { }
diff --git a/test/CodeGenCXX/mangle-subst-std.cpp b/test/CodeGenCXX/mangle-subst-std.cpp
new file mode 100644
index 0000000..fbce204
--- /dev/null
+++ b/test/CodeGenCXX/mangle-subst-std.cpp
@@ -0,0 +1,39 @@
+// RUN: clang-cc -emit-llvm %s -o - -triple=x86_64-apple-darwin9 | FileCheck %s
+
+namespace std {
+ struct A { A(); };
+
+ // CHECK: define void @_ZNSt1AC1Ev
+ // CHECK: define void @_ZNSt1AC2Ev
+ A::A() { }
+};
+
+namespace std {
+ template<typename> struct allocator { };
+}
+
+// CHECK: define void @_Z1fSaIcESaIiE
+void f(std::allocator<char>, std::allocator<int>) { }
+
+namespace std {
+ template<typename, typename, typename> struct basic_string { };
+}
+
+// CHECK: define void @_Z1fSbIcciE
+void f(std::basic_string<char, char, int>) { }
+
+namespace std {
+ template<typename> struct char_traits { };
+
+ typedef std::basic_string<char, std::char_traits<char>, std::allocator<char> > string;
+}
+
+// CHECK: _Z1fSs
+void f(std::string) { }
+
+namespace std {
+ template<typename, typename> struct basic_ostream { };
+}
+
+// CHECK: _Z1fSo
+void f(std::basic_ostream<char, std::char_traits<char> >) { }
diff --git a/test/CodeGenCXX/mangle-subst.cpp b/test/CodeGenCXX/mangle-subst.cpp
new file mode 100644
index 0000000..c53a630
--- /dev/null
+++ b/test/CodeGenCXX/mangle-subst.cpp
@@ -0,0 +1,56 @@
+// RUN: clang-cc -emit-llvm %s -o - -triple=x86_64-apple-darwin9 | FileCheck %s
+
+struct X {};
+
+// CHECK: define void @_Z1f1XS_(
+void f(X, X) { }
+
+// CHECK: define void @_Z1fR1XS0_(
+void f(X&, X&) { }
+
+// CHECK: define void @_Z1fRK1XS1_(
+void f(const X&, const X&) { }
+
+typedef void T();
+struct S {};
+
+// CHECK: define void @_Z1fPFvvEM1SFvvE(
+void f(T*, T (S::*)) {}
+
+namespace A {
+ struct A { };
+ struct B { };
+};
+
+// CHECK: define void @_Z1fN1A1AENS_1BE(
+void f(A::A a, A::B b) { }
+
+struct C {
+ struct D { };
+};
+
+// CHECK: define void @_Z1fN1C1DERS_PS_S1_(
+void f(C::D, C&, C*, C&) { }
+
+template<typename T>
+struct V {
+ typedef int U;
+};
+
+template <typename T> void f1(typename V<T>::U, V<T>) { }
+
+// CHECK: @_Z2f1IiEvN1VIT_E1UES2_
+template void f1<int>(int, V<int>);
+
+template <typename T> void f2(V<T>, typename V<T>::U) { }
+
+// CHECK: @_Z2f2IiEv1VIT_ENS2_1UE
+template void f2<int>(V<int>, int);
+
+namespace NS {
+template <typename T> struct S1 {};
+template<typename T> void ft3(S1<T>, S1<char>) { }
+
+// CHECK: @_ZN2NS3ft3IiEEvNS_2S1IT_EENS1_IcEE
+template void ft3<int>(S1<int>, S1<char>);
+}
diff --git a/test/CodeGenCXX/mangle.cpp b/test/CodeGenCXX/mangle.cpp
index ef36a8b..2ffbae7 100644
--- a/test/CodeGenCXX/mangle.cpp
+++ b/test/CodeGenCXX/mangle.cpp
@@ -1,87 +1,223 @@
-// RUN: clang-cc -emit-llvm %s -o %t -triple=x86_64-apple-darwin9 &&
+// RUN: clang-cc -emit-llvm %s -o - -triple=x86_64-apple-darwin9 | FileCheck %s
-// 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 &&
+// CHECK: @unmangled_variable = global
+// CHECK: @_ZN1N1iE = global
+// CHECK: @_ZZN1N1fEiiE1b = internal global
+// CHECK: @_ZZN1N1gEvE1a = internal global
+// CHECK: @_ZGVZN1N1gEvE1a = internal global
+
+// CHECK: define zeroext i1 @_ZplRK1YRA100_P1X
bool operator+(const Y&, X* (&xs)[100]) { return false; }
-// RUN: grep _Z1f1s %t | count 1 &&
+// CHECK: define void @_Z1f1s
typedef struct { int a; } s;
void f(s) { }
-// RUN: grep _Z1f1e %t| count 1 &&
+// CHECK: define void @_Z1f1e
typedef enum { foo } e;
void f(e) { }
-// RUN: grep _Z1f1u %t | count 1 &&
+// CHECK: define void @_Z1f1u
typedef union { int a; } u;
void f(u) { }
-// RUN: grep _Z1f1x %t | count 1 &&
+// CHECK: define void @_Z1f1x
typedef struct { int a; } x,y;
void f(y) { }
-// RUN: grep _Z1fv %t | count 1 &&
+// CHECK: define void @_Z1fv
void f() { }
-// RUN: grep _ZN1N1fEv %t | count 1 &&
+// CHECK: define void @_ZN1N1fEv
namespace N { void f() { } }
-// RUN: grep _ZN1N1N1fEv %t | count 1 &&
+// CHECK: define void @_ZN1N1N1fEv
namespace N { namespace N { void f() { } } }
-// RUN: grep unmangled_function %t | count 1 &&
+// CHECK: define void @unmangled_function
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 &&
+// CHECK: define void @_Z1fno
void f(__int128_t, __uint128_t) { }
template <typename T> struct S1 {};
-// RUN: grep "_Z1f2S1IiE" %t | count 1 &&
+// CHECK: define void @_Z1f2S1IiE
void f(S1<int>) {}
-// RUN: grep "_Z1f2S1IdE" %t | count 1 &&
+// CHECK: define void @_Z1f2S1IdE
void f(S1<double>) {}
template <int N> struct S2 {};
-// RUN: grep "_Z1f2S2ILi100EE" %t | count 1 &&
+// CHECK: define void @_Z1f2S2ILi100EE
void f(S2<100>) {}
-// RUN: grep "_Z1f2S2ILin100EE" %t | count 1 &&
+// CHECK: define void @_Z1f2S2ILin100EE
void f(S2<-100>) {}
template <bool B> struct S3 {};
-// RUN: grep "_Z1f2S3ILb1EE" %t | count 1 &&
+// CHECK: define void @_Z1f2S3ILb1EE
void f(S3<true>) {}
-// RUN: grep "_Z1f2S3ILb0EE" %t | count 1 &&
+// CHECK: define void @_Z1f2S3ILb0EE
void f(S3<false>) {}
-// RUN: grep "_Z2f22S3ILb1EE" %t | count 1 &&
+// CHECK: define void @_Z2f22S3ILb1EE
void f2(S3<100>) {}
struct S;
-// RUN: grep "_Z1fM1SKFvvE" %t | count 1 &&
+// CHECK: define void @_Z1fM1SKFvvE
void f(void (S::*)() const) {}
-// RUN: grep "_Z1fM1SFvvE" %t | count 1
+// CHECK: define void @_Z1fM1SFvvE
void f(void (S::*)()) {}
+
+// CHECK: define void @_Z1fi
+void f(const int) { }
+
+template<typename T, typename U> void ft1(U u, T t) { }
+
+template<typename T> void ft2(T t, void (*)(T), void (*)(T)) { }
+
+template<typename T, typename U = S1<T> > struct S4 { };
+template<typename T> void ft3(S4<T>*) { }
+
+namespace NS {
+ template<typename T> void ft1(T) { }
+}
+
+void g1() {
+ // CHECK: @_Z3ft1IidEvT0_T_
+ ft1<int, double>(1, 0);
+
+ // CHECK: @_Z3ft2IcEvT_PFvS0_ES2_
+ ft2<char>(1, 0, 0);
+
+ // CHECK: @_Z3ft3IiEvP2S4IT_2S1IS1_EE
+ ft3<int>(0);
+
+ // CHECK: @_ZN2NS3ft1IiEEvT_
+ NS::ft1<int>(1);
+}
+
+// Expressions
+template<int I> struct S5 { };
+
+template<int I> void ft4(S5<I>) { }
+void g2() {
+ // CHECK: @_Z3ft4ILi10EEv2S5IXT_EE
+ ft4(S5<10>());
+
+ // CHECK: @_Z3ft4ILi20EEv2S5IXT_EE
+ ft4(S5<20>());
+}
+
+extern "C++" {
+ // CHECK: @_Z1hv
+ void h() { }
+}
+
+// PR5019
+extern "C" { struct a { int b; }; }
+
+// CHECK: @_Z1fP1a
+int f(struct a *x) {
+ return x->b;
+}
+
+// PR5017
+extern "C" {
+struct Debug {
+ const Debug& operator<< (unsigned a) const { }
+};
+Debug dbg;
+// CHECK: @_ZNK5DebuglsEj
+int main(void) { dbg << 32 ;}
+}
+
+template<typename T> struct S6 {
+ typedef int B;
+};
+
+template<typename T> void ft5(typename S6<T>::B) { }
+// CHECK: @_Z3ft5IiEvN2S6IT_E1BE
+template void ft5<int>(int);
+
+template<typename T> class A {};
+
+namespace NS {
+template<typename T> bool operator==(const A<T>&, const A<T>&) { return true; }
+}
+
+// CHECK: @_ZN2NSeqIcEEbRK1AIT_ES5_
+template bool NS::operator==(const ::A<char>&, const ::A<char>&);
+
+namespace std {
+template<typename T> bool operator==(const A<T>&, const A<T>&) { return true; }
+}
+
+// CHECK: @_ZSteqIcEbRK1AIT_ES4_
+template bool std::operator==(const ::A<char>&, const ::A<char>&);
+
+struct S {
+ typedef int U;
+};
+
+template <typename T> typename T::U ft6(const T&) { return 0; }
+
+// CHECK: @_Z3ft6I1SENT_1UERKS1_
+template int ft6<S>(const S&);
+
+template<typename> struct __is_scalar {
+ enum { __value = 1 };
+};
+
+template<bool, typename> struct __enable_if { };
+
+template<typename T> struct __enable_if<true, T> {
+ typedef T __type;
+};
+
+// PR5063
+template<typename T> typename __enable_if<__is_scalar<T>::__value, void>::__type ft7() { }
+
+// CHECK: @_Z3ft7IiEN11__enable_ifIXsr11__is_scalarIT_E7__valueEvE6__typeEv
+template void ft7<int>();
+// CHECK: @_Z3ft7IPvEN11__enable_ifIXsr11__is_scalarIT_E7__valueEvE6__typeEv
+template void ft7<void*>();
+
+// PR5144
+extern "C" {
+void extern_f(void);
+};
+
+// CHECK: @extern_f
+void extern_f(void) { }
+
+struct S7 {
+ struct S { S(); };
+
+ struct {
+ S s;
+ } a;
+};
+
+// PR5139
+// CHECK: @_ZN2S7C1Ev
+// CHECK: @_ZN2S7C2Ev
+// CHECK: @"_ZN2S73$_0C1Ev"
+S7::S7() {}
+
diff --git a/test/CodeGenCXX/member-function-pointers.cpp b/test/CodeGenCXX/member-function-pointers.cpp
new file mode 100644
index 0000000..13f7de5
--- /dev/null
+++ b/test/CodeGenCXX/member-function-pointers.cpp
@@ -0,0 +1,73 @@
+// RUN: clang-cc %s -emit-llvm -o - -triple=x86_64-apple-darwin9 | FileCheck %s
+
+struct A { int a; void f(); virtual void vf(); };
+struct B { int b; virtual void g(); };
+struct C : B, A { };
+
+void (A::*pa)();
+void (A::*volatile vpa)();
+void (B::*pb)();
+void (C::*pc)();
+
+// CHECK: @pa2 = global %0 { i64 ptrtoint (void ()* @_ZN1A1fEv to i64), i64 0 }, align 8
+void (A::*pa2)() = &A::f;
+
+// CHECK: @pa3 = global %0 { i64 1, i64 0 }, align 8
+void (A::*pa3)() = &A::vf;
+
+// CHECK: @pc2 = global %0 { i64 ptrtoint (void ()* @_ZN1A1fEv to i64), i64 16 }, align 8
+void (C::*pc2)() = &C::f;
+
+// CHECK: @pc3 = global %0 { i64 1, i64 0 }, align 8
+void (A::*pc3)() = &A::vf;
+
+void f() {
+ // CHECK: store i64 0, i64* getelementptr inbounds (%0* @pa, i32 0, i32 0)
+ // CHECK: store i64 0, i64* getelementptr inbounds (%0* @pa, i32 0, i32 1)
+ pa = 0;
+
+ // CHECK: volatile store i64 0, i64* getelementptr inbounds (%0* @vpa, i32 0, i32 0)
+ // CHECK: volatile store i64 0, i64* getelementptr inbounds (%0* @vpa, i32 0, i32 1)
+ vpa = 0;
+
+ // CHECK: store i64 %0, i64* getelementptr inbounds (%0* @pc, i32 0, i32 0)
+ // CHECK: [[ADJ:%[a-zA-Z0-9\.]+]] = add i64 %1, 16
+ // CHECK: store i64 [[ADJ]], i64* getelementptr inbounds (%0* @pc, i32 0, i32 1)
+ pc = pa;
+}
+
+void f2() {
+ // CHECK: [[pa2ptr:%[a-zA-Z0-9\.]+]] = getelementptr inbounds %0* %pa2, i32 0, i32 0
+ // CHECK: store i64 ptrtoint (void ()* @_ZN1A1fEv to i64), i64* [[pa2ptr]]
+ // CHECK: [[pa2adj:%[a-zA-Z0-9\.]+]] = getelementptr inbounds %0* %pa2, i32 0, i32 1
+ // CHECK: store i64 0, i64* [[pa2adj]]
+ void (A::*pa2)() = &A::f;
+
+ // CHECK: [[pa3ptr:%[a-zA-Z0-9\.]+]] = getelementptr inbounds %0* %pa3, i32 0, i32 0
+ // CHECK: store i64 1, i64* [[pa3ptr]]
+ // CHECK: [[pa3adj:%[a-zA-Z0-9\.]+]] = getelementptr inbounds %0* %pa3, i32 0, i32 1
+ // CHECK: store i64 0, i64* [[pa2adj]]
+ void (A::*pa3)() = &A::vf;
+}
+
+void f3(A *a, A &ar) {
+ (a->*pa)();
+ (ar.*pa)();
+}
+
+// PR5177
+namespace PR5177 {
+ struct A {
+ bool foo(int*) const;
+ } a;
+
+ struct B1 {
+ bool (A::*pmf)(int*) const;
+ const A* pa;
+
+ B1() : pmf(&A::foo), pa(&a) {}
+ bool operator()() const { return (pa->*pmf)(new int); }
+ };
+
+ void bar(B1 b2) { while (b2()) ; }
+}
diff --git a/test/CodeGenCXX/member-functions.cpp b/test/CodeGenCXX/member-functions.cpp
index 8ada907..29629d5 100644
--- a/test/CodeGenCXX/member-functions.cpp
+++ b/test/CodeGenCXX/member-functions.cpp
@@ -58,6 +58,6 @@ struct T {
void test3() {
T t1, t2;
- // RUN: grep "call void @_ZN1TpsERK1T" %t
+ // RUN: grep "call void @_ZN1TpsERKS_" %t
T result = t1 + t2;
}
diff --git a/test/CodeGenCXX/member-pointers-zero-init.cpp b/test/CodeGenCXX/member-pointers-zero-init.cpp
new file mode 100644
index 0000000..e7b0fda
--- /dev/null
+++ b/test/CodeGenCXX/member-pointers-zero-init.cpp
@@ -0,0 +1,34 @@
+// RUN: clang-cc -emit-llvm %s -o %t -triple=x86_64-apple-darwin9 &&
+
+struct A {
+ int i;
+};
+
+// RUN: grep "@a = global i64 -1" %t &&
+int A::* a;
+
+// RUN: grep "@aa = global \[2 x i64\] \[i64 -1, i64 -1\]" %t &&
+int A::* aa[2];
+
+// RUN: grep "@aaa = global \[2 x \[2 x i64\]\] \[\[2 x i64\] \[i64 -1, i64 -1\], \[2 x i64\] \[i64 -1, i64 -1\]\]" %t &&
+int A::* aaa[2][2];
+
+// RUN: grep "@b = global i64 -1" %t &&
+int A::* b = 0;
+
+void f() {
+ // RUN: grep "%.* = icmp ne i64 %.*, -1" %t | count 2 &&
+ if (a) { }
+ if (a != 0) { }
+
+ // RUN: grep "%.* = icmp ne i64 -1, %.*" %t | count 1 &&
+ if (0 != a) { }
+
+ // RUN: grep "%.* = icmp eq i64 %.*, -1" %t | count 1 &&
+ if (a == 0) { }
+
+ // RUN: grep "%.* = icmp eq i64 -1, %.*" %t | count 1
+ if (0 == a) { }
+
+}
+
diff --git a/test/CodeGenCXX/namespace-aliases.cpp b/test/CodeGenCXX/namespace-aliases.cpp
new file mode 100644
index 0000000..5baea87
--- /dev/null
+++ b/test/CodeGenCXX/namespace-aliases.cpp
@@ -0,0 +1,3 @@
+// RUN: clang-cc -emit-llvm-only %s
+namespace A { }
+namespace B = A;
diff --git a/test/CodeGenCXX/nested-base-member-access.cpp b/test/CodeGenCXX/nested-base-member-access.cpp
new file mode 100644
index 0000000..308f952
--- /dev/null
+++ b/test/CodeGenCXX/nested-base-member-access.cpp
@@ -0,0 +1,52 @@
+// RUN: clang-cc %s -emit-llvm -o %t
+
+extern "C" int printf(...);
+
+struct M {
+ M(int i){ iM = i; }
+ int iM;
+ void MPR() { printf("iM = %d\n", iM); }
+
+};
+
+struct Q {
+ Q(int i){ iQ = i; }
+ int iQ;
+ void QPR() { printf("iQ = %d\n", iQ); }
+};
+
+struct IQ {
+ IQ(int i) { iIQ = i; }
+ void IQPR() { printf("iIQ = %d\n", iIQ); }
+ int iIQ;
+};
+
+struct L : IQ {
+ L(int i) : IQ(i+100) { iL = i; }
+ int iL;
+};
+
+struct P : Q, L {
+ P(int i) : Q(i+100), L(i+200) { iP = i; }
+ int iP;
+ void PPR() { printf("iP = %d\n", iP); }
+};
+
+
+struct N : M,P {
+ N() : M(100), P(200) {}
+ void PR() {
+ this->MPR(); this->PPR(); this->QPR();
+ IQPR();
+ printf("iM = %d\n", iM);
+ printf("iP = %d\n", iP);
+ printf("iQ = %d\n", iQ);
+ printf("iL = %d\n", iL);
+ printf("iIQ = %d\n", iIQ);
+ }
+};
+
+int main() {
+ N n1;
+ n1.PR();
+}
diff --git a/test/CodeGenCXX/new.cpp b/test/CodeGenCXX/new.cpp
index 480bbce..c6cee18 100644
--- a/test/CodeGenCXX/new.cpp
+++ b/test/CodeGenCXX/new.cpp
@@ -1,4 +1,4 @@
-// RUN: clang-cc %s -emit-llvm -o %t &&
+// RUN: clang-cc %s -emit-llvm -o - | FileCheck %s
void t1() {
int* a = new int;
@@ -32,7 +32,7 @@ struct T {
};
void t4() {
- // RUN: grep "call void @_ZN1TC1Ev" %t | count 1 &&
+ // CHECK: call void @_ZN1TC1Ev
T *t = new T;
}
@@ -42,7 +42,7 @@ struct T2 {
};
void t5() {
- // RUN: grep "call void @_ZN2T2C1Eii" %t | count 1
+ // CHECK: call void @_ZN2T2C1Eii
T2 *t2 = new T2(10, 10);
}
@@ -54,3 +54,20 @@ int *t6() {
void t7() {
new int();
}
+
+struct U {
+ ~U();
+};
+
+void t8(int n) {
+ new int[10];
+ new int[n];
+
+ // Non-POD
+ new T[10];
+ new T[n];
+
+ // Cookie required
+ new U[10];
+ new U[n];
+}
diff --git a/test/CodeGenCXX/nullptr.cpp b/test/CodeGenCXX/nullptr.cpp
new file mode 100644
index 0000000..7bc52ad
--- /dev/null
+++ b/test/CodeGenCXX/nullptr.cpp
@@ -0,0 +1,7 @@
+// RUN: clang-cc -std=c++0x %s -emit-llvm -o %t
+
+int* a = nullptr;
+
+void f() {
+ int* a = nullptr;
+}
diff --git a/test/CodeGenCXX/overload-binop-implicitconvert.cpp b/test/CodeGenCXX/overload-binop-implicitconvert.cpp
new file mode 100644
index 0000000..f17a458
--- /dev/null
+++ b/test/CodeGenCXX/overload-binop-implicitconvert.cpp
@@ -0,0 +1,22 @@
+// RUN: clang-cc %s -emit-llvm-only
+class T
+{};
+
+void print(const char *t);
+
+T& operator<< (T& t,const char* c)
+{
+ print(c);
+ return t;
+}
+
+
+int main()
+{
+ T t;
+ print("foo");
+ t<<"foo";
+
+ return 0;
+}
+
diff --git a/test/CodeGenCXX/predefined-expr-sizeof.cpp b/test/CodeGenCXX/predefined-expr-sizeof.cpp
new file mode 100644
index 0000000..e318fbe
--- /dev/null
+++ b/test/CodeGenCXX/predefined-expr-sizeof.cpp
@@ -0,0 +1,30 @@
+// RUN: clang-cc %s -emit-llvm -o - | FileCheck %s
+
+// CHECK: store i32 49, i32* %size
+// CHECK: store i32 52, i32* %size
+template<typename T>
+class TemplateClass {
+public:
+ void templateClassFunction() {
+ int size = sizeof(__PRETTY_FUNCTION__);
+ }
+};
+
+// CHECK: store i32 27, i32* %size
+// CHECK: store i32 30, i32* %size
+template<typename T>
+void functionTemplate(T t) {
+ int size = sizeof(__PRETTY_FUNCTION__);
+}
+
+int main() {
+ TemplateClass<int> t1;
+ t1.templateClassFunction();
+ TemplateClass<double> t2;
+ t2.templateClassFunction();
+
+ functionTemplate<int>(0);
+ functionTemplate(0.0);
+
+ return 0;
+}
diff --git a/test/CodeGenCXX/predefined-expr.cpp b/test/CodeGenCXX/predefined-expr.cpp
new file mode 100644
index 0000000..95bc255
--- /dev/null
+++ b/test/CodeGenCXX/predefined-expr.cpp
@@ -0,0 +1,226 @@
+// RUN: clang-cc %s -emit-llvm -o - | FileCheck %s
+
+// CHECK: private constant [15 x i8] c"externFunction\00"
+// CHECK: private constant [26 x i8] c"void NS::externFunction()\00"
+
+// CHECK: private constant [22 x i8] c"classTemplateFunction\00"
+// CHECK: private constant [60 x i8] c"void NS::ClassTemplate<NS::Base *>::classTemplateFunction()\00"
+// CHECK: private constant [53 x i8] c"void NS::ClassTemplate<int>::classTemplateFunction()\00"
+
+// CHECK: private constant [18 x i8] c"functionTemplate1\00"
+// CHECK: private constant [45 x i8] c"void NS::Base::functionTemplate1(NS::Base *)\00"
+// CHECK: private constant [38 x i8] c"void NS::Base::functionTemplate1(int)\00"
+
+// CHECK: private constant [12 x i8] c"~Destructor\00"
+// CHECK: private constant [35 x i8] c"void NS::Destructor::~Destructor()\00"
+
+// CHECK: private constant [12 x i8] c"Constructor\00"
+// CHECK: private constant [46 x i8] c"void NS::Constructor::Constructor(NS::Base *)\00"
+// CHECK: private constant [39 x i8] c"void NS::Constructor::Constructor(int)\00"
+// CHECK: private constant [36 x i8] c"void NS::Constructor::Constructor()\00"
+
+// CHECK: private constant [16 x i8] c"virtualFunction\00"
+// CHECK: private constant [44 x i8] c"virtual void NS::Derived::virtualFunction()\00"
+
+// CHECK: private constant [26 x i8] c"functionReturingTemplate2\00"
+// CHECK: private constant [64 x i8] c"ClassTemplate<NS::Base *> NS::Base::functionReturingTemplate2()\00"
+
+// CHECK: private constant [26 x i8] c"functionReturingTemplate1\00"
+// CHECK: private constant [57 x i8] c"ClassTemplate<int> NS::Base::functionReturingTemplate1()\00"
+
+// CHECK: private constant [23 x i8] c"withTemplateParameter2\00"
+// CHECK: private constant [65 x i8] c"void NS::Base::withTemplateParameter2(ClassTemplate<NS::Base *>)\00"
+
+// CHECK: private constant [23 x i8] c"withTemplateParameter1\00"
+// CHECK: private constant [58 x i8] c"void NS::Base::withTemplateParameter1(ClassTemplate<int>)\00"
+
+// CHECK: private constant [23 x i8] c"functionReturningClass\00"
+// CHECK: private constant [45 x i8] c"NS::Base *NS::Base::functionReturningClass()\00"
+
+// CHECK: private constant [23 x i8] c"functionWithParameters\00"
+// CHECK: private constant [64 x i8] c"void NS::Base::functionWithParameters(int, float *, NS::Base *)\00"
+
+// CHECK: private constant [17 x i8] c"variadicFunction\00"
+// CHECK: private constant [42 x i8] c"void NS::Base::variadicFunction(int, ...)\00"
+
+// CHECK: private constant [41 x i8] c"virtual void NS::Base::virtualFunction()\00"
+
+// CHECK: private constant [15 x i8] c"inlineFunction\00"
+// CHECK: private constant [32 x i8] c"void NS::Base::inlineFunction()\00"
+
+// CHECK: private constant [11 x i8] c"staticFunc\00"
+// CHECK: private constant [28 x i8] c"void NS::Base::staticFunc()\00"
+
+int printf(const char * _Format, ...);
+
+namespace NS {
+
+template<typename T>
+class ClassTemplate {
+public:
+ void classTemplateFunction() {
+ printf("__func__ %s\n", __func__);
+ printf("__FUNCTION__ %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+ }
+};
+
+class Base {
+public:
+ static void staticFunc() {
+ printf("__func__ %s\n", __func__);
+ printf("__FUNCTION__ %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+ }
+
+ inline void inlineFunction() {
+ printf("__func__ %s\n", __func__);
+ printf("__FUNCTION__ %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+ }
+
+ virtual void virtualFunction() {
+ printf("__func__ %s\n", __func__);
+ printf("__FUNCTION__ %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+ }
+
+ void functionWithParameters(int, float*, Base* base) {
+ printf("__func__ %s\n", __func__);
+ printf("__FUNCTION__ %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+ }
+
+ Base *functionReturningClass() {
+ printf("__func__ %s\n", __func__);
+ printf("__FUNCTION__ %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+ return 0;
+ }
+
+ void variadicFunction(int, ...) {
+ printf("__func__ %s\n", __func__);
+ printf("__FUNCTION__ %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+ }
+
+ void withTemplateParameter1(ClassTemplate<int>) {
+ printf("__func__ %s\n", __func__);
+ printf("__FUNCTION__ %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+ }
+
+ void withTemplateParameter2(ClassTemplate<Base *>) {
+ printf("__func__ %s\n", __func__);
+ printf("__FUNCTION__ %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+ }
+
+ ClassTemplate<int> functionReturingTemplate1() {
+ printf("__func__ %s\n", __func__);
+ printf("__FUNCTION__ %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+ return ClassTemplate<int>();
+ }
+
+ ClassTemplate<Base *> functionReturingTemplate2() {
+ printf("__func__ %s\n", __func__);
+ printf("__FUNCTION__ %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+ return ClassTemplate<Base *>();
+ }
+
+ template<typename T>
+ void functionTemplate1(T t) {
+ printf("__func__ %s\n", __func__);
+ printf("__FUNCTION__ %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+ }
+};
+
+class Derived : public Base {
+public:
+ // Virtual function without being explicitally written.
+ void virtualFunction() {
+ printf("__func__ %s\n", __func__);
+ printf("__FUNCTION__ %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+ }
+};
+
+class Constructor {
+public:
+ Constructor() {
+ printf("__func__ %s\n", __func__);
+ printf("__FUNCTION__ %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+ }
+
+ Constructor(int) {
+ printf("__func__ %s\n", __func__);
+ printf("__FUNCTION__ %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+ }
+
+ Constructor(Base *) {
+ printf("__func__ %s\n", __func__);
+ printf("__FUNCTION__ %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+ }
+
+};
+
+class Destructor {
+public:
+ ~Destructor() {
+ printf("__func__ %s\n", __func__);
+ printf("__FUNCTION__ %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+ }
+};
+
+extern void externFunction() {
+ printf("__func__ %s\n", __func__);
+ printf("__FUNCTION__ %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+}
+
+}
+
+int main() {
+ NS::Base::staticFunc();
+
+ NS::Base b;
+ b.inlineFunction();
+ b.virtualFunction();
+ b.variadicFunction(0);
+ b.functionWithParameters(0, 0, 0);
+ b.functionReturningClass();
+
+ b.withTemplateParameter1(NS::ClassTemplate<int>());
+ b.withTemplateParameter2(NS::ClassTemplate<NS::Base *>());
+ b.functionReturingTemplate1();
+ b.functionReturingTemplate2();
+ b.functionTemplate1<int>(0);
+ b.functionTemplate1<NS::Base *>(0);
+
+ NS::Derived d;
+ d.virtualFunction();
+
+ NS::ClassTemplate<int> t1;
+ t1.classTemplateFunction();
+ NS::ClassTemplate<NS::Base *> t2;
+ t2.classTemplateFunction();
+
+ NS::Constructor c1;
+ NS::Constructor c2(0);
+ NS::Constructor c3((NS::Base *)0);
+
+ {
+ NS::Destructor destructor;
+ }
+
+ NS::externFunction();
+
+ return 0;
+}
diff --git a/test/CodeGenCXX/references.cpp b/test/CodeGenCXX/references.cpp
index 8e19356..c235521 100644
--- a/test/CodeGenCXX/references.cpp
+++ b/test/CodeGenCXX/references.cpp
@@ -87,3 +87,16 @@ int reference_decl() {
const int& b = 1;
return a+b;
}
+
+struct A {
+ int& b();
+};
+
+void f(A* a) {
+ int b = a->b();
+}
+
+// PR5122
+void *foo = 0;
+void * const & kFoo = foo;
+
diff --git a/test/CodeGenCXX/reinterpret-cast.cpp b/test/CodeGenCXX/reinterpret-cast.cpp
new file mode 100644
index 0000000..ae3ab2f
--- /dev/null
+++ b/test/CodeGenCXX/reinterpret-cast.cpp
@@ -0,0 +1,12 @@
+// RUN: clang-cc -emit-llvm -o - %s -std=c++0x
+void *f1(unsigned long l) {
+ return reinterpret_cast<void *>(l);
+}
+
+unsigned long f2() {
+ return reinterpret_cast<unsigned long>(nullptr);
+}
+
+unsigned long f3(void *p) {
+ return reinterpret_cast<unsigned long>(p);
+} \ No newline at end of file
diff --git a/test/CodeGenCXX/static-data-member.cpp b/test/CodeGenCXX/static-data-member.cpp
new file mode 100644
index 0000000..6e2abcc
--- /dev/null
+++ b/test/CodeGenCXX/static-data-member.cpp
@@ -0,0 +1,8 @@
+// RUN: clang-cc -emit-llvm -o - %s
+struct S {
+ static int i;
+};
+
+void f() {
+ int a = S::i;
+}
diff --git a/test/CodeGenCXX/static-init.cpp b/test/CodeGenCXX/static-init.cpp
new file mode 100644
index 0000000..44dd142
--- /dev/null
+++ b/test/CodeGenCXX/static-init.cpp
@@ -0,0 +1,13 @@
+// RUN: clang-cc -triple=x86_64-apple-darwin9 -emit-llvm %s -o %t &&
+// RUN: grep "call void @_ZN1AC1Ev" %t | count 1 &&
+// RUN: grep "call i32 @__cxa_atexit(void (i8\*)\* bitcast (void (%.truct.A\*)\* @_ZN1AD1Ev to void (i8\*)\*), i8\* getelementptr inbounds (%.truct.A\* @_ZZ1fvE1a, i32 0, i32 0), i8\* bitcast (i8\*\* @__dso_handle to i8\*))" %t | count 1
+
+struct A {
+ A();
+ ~A();
+};
+
+void f() {
+ static A a;
+}
+
diff --git a/test/CodeGenCXX/temp-1.cpp b/test/CodeGenCXX/temp-1.cpp
new file mode 100644
index 0000000..9b97f00
--- /dev/null
+++ b/test/CodeGenCXX/temp-1.cpp
@@ -0,0 +1,83 @@
+// RUN: clang-cc -emit-llvm %s -o %t -triple=x86_64-apple-darwin9 &&
+struct A {
+ A();
+ ~A();
+ void f();
+};
+
+// RUN: grep "call void @_ZN1AC1Ev" %t | count 2 &&
+// RUN: grep "call void @_ZN1AD1Ev" %t | count 2 &&
+void f1() {
+ (void)A();
+ A().f();
+}
+
+// Function calls
+struct B {
+ B();
+ ~B();
+};
+
+B g();
+
+// RUN: grep "call void @_ZN1BC1Ev" %t | count 0 &&
+// RUN: grep "call void @_ZN1BD1Ev" %t | count 1 &&
+void f2() {
+ (void)g();
+}
+
+// Member function calls
+struct C {
+ C();
+ ~C();
+
+ C f();
+};
+
+// RUN: grep "call void @_ZN1CC1Ev" %t | count 1 &&
+// RUN: grep "call void @_ZN1CD1Ev" %t | count 2 &&
+void f3() {
+ C().f();
+}
+
+// Function call operator
+struct D {
+ D();
+ ~D();
+
+ D operator()();
+};
+
+// RUN: grep "call void @_ZN1DC1Ev" %t | count 1 &&
+// RUN: grep "call void @_ZN1DD1Ev" %t | count 2 &&
+void f4() {
+ D()();
+}
+
+// Overloaded operators
+struct E {
+ E();
+ ~E();
+ E operator+(const E&);
+ E operator!();
+};
+
+// RUN: grep "call void @_ZN1EC1Ev" %t | count 3 &&
+// RUN: grep "call void @_ZN1ED1Ev" %t | count 5 &&
+void f5() {
+ E() + E();
+ !E();
+}
+
+struct F {
+ F();
+ ~F();
+ F& f();
+};
+
+// RUN: grep "call void @_ZN1FC1Ev" %t | count 1 &&
+// RUN: grep "call void @_ZN1FD1Ev" %t | count 1
+void f6() {
+ F().f();
+}
+
diff --git a/test/CodeGenCXX/template-anonymous-union-member-initializer.cpp b/test/CodeGenCXX/template-anonymous-union-member-initializer.cpp
new file mode 100644
index 0000000..f845428
--- /dev/null
+++ b/test/CodeGenCXX/template-anonymous-union-member-initializer.cpp
@@ -0,0 +1,10 @@
+// RUN: clang-cc -emit-llvm -o %t %s
+template <typename T>
+class A
+{
+ union { void *d; };
+
+ A() : d(0) { }
+};
+
+A<int> a0;
diff --git a/test/CodeGenCXX/trivial-constructor-init.cpp b/test/CodeGenCXX/trivial-constructor-init.cpp
new file mode 100644
index 0000000..183b31a
--- /dev/null
+++ b/test/CodeGenCXX/trivial-constructor-init.cpp
@@ -0,0 +1,21 @@
+// RUN: clang-cc -S %s -o %t-64.s &&
+// RUN: clang-cc -S %s -o %t-32.s &&
+// RUN: true
+
+extern "C" int printf(...);
+
+struct S {
+ S() { printf("S::S\n"); }
+};
+
+struct A {
+ double x;
+ A() : x(), y(), s() { printf("x = %f y = %x \n", x, y); }
+ int *y;
+ S s;
+};
+
+A a;
+
+int main() {
+}
diff --git a/test/CodeGenCXX/virt.cpp b/test/CodeGenCXX/virt.cpp
new file mode 100644
index 0000000..9ae81e5
--- /dev/null
+++ b/test/CodeGenCXX/virt.cpp
@@ -0,0 +1,1024 @@
+// RUN: clang-cc -triple x86_64-apple-darwin -std=c++0x -O0 -S %s -o %t-64.s &&
+// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s &&
+// RUN: clang-cc -triple i386-apple-darwin -std=c++0x -O0 -S %s -o %t-32.s &&
+// RUN: FileCheck -check-prefix LP32 -input-file=%t-32.s %s &&
+
+// RUN: clang-cc -triple x86_64-apple-darwin -std=c++0x -O3 -S %s -o %t-O3-64.s &&
+// RUN: FileCheck -check-prefix LPOPT64 --input-file=%t-O3-64.s %s &&
+// RUN: clang-cc -triple i386-apple-darwin -std=c++0x -O3 -S %s -o %t-O3-32.s &&
+// RUN: FileCheck -check-prefix LPOPT32 -input-file=%t-O3-32.s %s &&
+
+// RUN: true
+
+struct B {
+ virtual void bar1();
+ virtual void bar2();
+ int b;
+};
+void B::bar1() { }
+void B::bar2() { }
+
+struct C {
+ virtual void bee1();
+ virtual void bee2();
+};
+void C::bee1() { }
+void C::bee2() { }
+
+struct D {
+ virtual void boo();
+};
+void D::boo() { }
+
+struct D1 {
+ virtual void bar();
+ virtual void bar2();
+ virtual void bar3();
+ virtual void bar4();
+ virtual void bar5();
+ void *d1;
+};
+void D1::bar() { }
+
+class F : virtual public D1, virtual public D {
+public:
+ virtual void foo();
+ void *f;
+};
+void F::foo() { }
+
+int j;
+void test2() {
+ F f;
+ static int sz = (char *)(&f.f) - (char *)(&f);
+ j = sz;
+ // FIXME: These should result in a frontend constant a la fold, no run time
+ // initializer
+ // CHECK-LPOPT32: movl $4, __ZZ5test2vE2sz
+ // CHECK-LPOPT64: movl $8, __ZZ5test2vE2sz(%rip)
+}
+
+static_assert(sizeof(F) == sizeof(void*)*4, "invalid vbase size");
+
+struct E {
+ int e;
+};
+
+static_assert (sizeof (C) == (sizeof(void *)), "vtable pointer layout");
+
+class A : public E, public B, public C {
+public:
+ virtual void foo1();
+ virtual void foo2();
+ A() { }
+ int a;
+} *ap;
+void A::foo1() { }
+void A::foo2() { }
+
+int main() {
+ A a;
+ B b;
+ ap->e = 1;
+ ap->b = 2;
+}
+
+// CHECK-LP32: main:
+// CHECK-LP32: movl $1, 8(%eax)
+// CHECK-LP32: movl $2, 4(%eax)
+
+// CHECK-LP64: main:
+// CHECK-LP64: movl $1, 12(%rax)
+// CHECK-LP64: movl $2, 8(%rax)
+
+struct test12_A {
+ virtual void foo0() { }
+ virtual void foo();
+} *test12_pa;
+
+struct test12_B : public test12_A {
+ virtual void foo() { }
+} *test12_pb;
+
+struct test12_D : public test12_B {
+} *test12_pd;
+void test12_foo() {
+ test12_pa->foo0();
+ test12_pb->foo0();
+ test12_pd->foo0();
+ test12_pa->foo();
+ test12_pb->foo();
+ test12_pd->foo();
+ test12_pa->test12_A::foo();
+}
+
+// CHECK-LPOPT32:__Z10test12_foov:
+// CHECK-LPOPT32: movl _test12_pa, %eax
+// CHECK-LPOPT32-NEXT: movl (%eax), %ecx
+// CHECK-LPOPT32-NEXT: movl %eax, (%esp)
+// CHECK-LPOPT32-NEXT: call *(%ecx)
+// CHECK-LPOPT32-NEXT: movl _test12_pb, %eax
+// CHECK-LPOPT32-NEXT: movl (%eax), %ecx
+// CHECK-LPOPT32-NEXT: movl %eax, (%esp)
+// CHECK-LPOPT32-NEXT: call *(%ecx)
+// CHECK-LPOPT32-NEXT: movl _test12_pd, %eax
+// CHECK-LPOPT32-NEXT: movl (%eax), %ecx
+// CHECK-LPOPT32-NEXT: movl %eax, (%esp)
+// CHECK-LPOPT32-NEXT: call *(%ecx)
+// CHECK-LPOPT32-NEXT: movl _test12_pa, %eax
+// CHECK-LPOPT32-NEXT: movl (%eax), %ecx
+// CHECK-LPOPT32-NEXT: movl %eax, (%esp)
+// CHECK-LPOPT32-NEXT: call *4(%ecx)
+// CHECK-LPOPT32-NEXT: movl _test12_pb, %eax
+// CHECK-LPOPT32-NEXT: movl (%eax), %ecx
+// CHECK-LPOPT32-NEXT: movl %eax, (%esp)
+// CHECK-LPOPT32-NEXT: call *4(%ecx)
+// CHECK-LPOPT32-NEXT: movl _test12_pd, %eax
+// CHECK-LPOPT32-NEXT: movl (%eax), %ecx
+// CHECK-LPOPT32-NEXT: movl %eax, (%esp)
+// CHECK-LPOPT32-NEXT: call *4(%ecx)
+// CHECK-LPOPT32-NEXT: movl _test12_pa, %eax
+// CHECK-LPOPT32-NEXT: movl %eax, (%esp)
+// CHECK-LPOPT32-NEXT: call L__ZN8test12_A3fooEv$stub
+
+// CHECK-LPOPT64:__Z10test12_foov:
+// CHECK-LPOPT64: movq _test12_pa(%rip), %rdi
+// CHECK-LPOPT64-NEXT: movq (%rdi), %rax
+// CHECK-LPOPT64-NEXT: call *(%rax)
+// CHECK-LPOPT64-NEXT: movq _test12_pb(%rip), %rdi
+// CHECK-LPOPT64-NEXT: movq (%rdi), %rax
+// CHECK-LPOPT64-NEXT: call *(%rax)
+// CHECK-LPOPT64-NEXT: movq _test12_pd(%rip), %rdi
+// CHECK-LPOPT64-NEXT: movq (%rdi), %rax
+// CHECK-LPOPT64-NEXT: call *(%rax)
+// CHECK-LPOPT64-NEXT: movq _test12_pa(%rip), %rdi
+// CHECK-LPOPT64-NEXT: movq (%rdi), %rax
+// CHECK-LPOPT64-NEXT: call *8(%rax)
+// CHECK-LPOPT64-NEXT: movq _test12_pb(%rip), %rdi
+// CHECK-LPOPT64-NEXT: movq (%rdi), %rax
+// CHECK-LPOPT64-NEXT: call *8(%rax)
+// CHECK-LPOPT64-NEXT: movq _test12_pd(%rip), %rdi
+// CHECK-LPOPT64-NEXT: movq (%rdi), %rax
+// CHECK-LPOPT64-NEXT: call *8(%rax)
+// CHECK-LPOPT64-NEXT: movq _test12_pa(%rip), %rdi
+// CHECK-LPOPT64-NEXT: call __ZN8test12_A3fooEv
+
+struct test6_B2 { virtual void funcB2(); char b[1000]; };
+struct test6_B1 : virtual test6_B2 { virtual void funcB1(); };
+
+struct test6_D : test6_B2, virtual test6_B1 {
+};
+
+// CHECK-LP32: .zerofill __DATA, __common, _d6, 2012, 4
+// CHECK-LP64: .zerofill __DATA, __common, _d6, 2024, 4
+
+struct test7_B2 { virtual void funcB2(); };
+struct test7_B1 : virtual test7_B2 { virtual void funcB1(); };
+
+struct test7_D : test7_B2, virtual test7_B1 {
+};
+
+// CHECK-LP32: .zerofill __DATA, __common, _d7, 8, 3
+// CHECK-LP64: .zerofill __DATA, __common, _d7, 16, 3
+
+
+struct test3_B3 { virtual void funcB3(); };
+struct test3_B2 : virtual test3_B3 { virtual void funcB2(); };
+struct test3_B1 : virtual test3_B2 { virtual void funcB1(); };
+
+struct test3_D : virtual test3_B1 {
+ virtual void funcD() { }
+};
+
+// CHECK-LP32:__ZTV7test3_D:
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long __ZTI7test3_D
+// CHECK-LP32-NEXT: .long __ZN8test3_B36funcB3Ev
+// CHECK-LP32-NEXT: .long __ZN8test3_B26funcB2Ev
+// CHECK-LP32-NEXT: .long __ZN8test3_B16funcB1Ev
+// CHECK-LP32-NEXT: .long __ZN7test3_D5funcDEv
+
+// CHECK-LP64:__ZTV7test3_D:
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad __ZTI7test3_D
+// CHECK-LP64-NEXT: .quad __ZN8test3_B36funcB3Ev
+// CHECK-LP64-NEXT: .quad __ZN8test3_B26funcB2Ev
+// CHECK-LP64-NEXT: .quad __ZN8test3_B16funcB1Ev
+// CHECK-LP64-NEXT: .quad __ZN7test3_D5funcDEv
+
+struct test4_D : virtual B, virtual C {
+};
+
+// CHECK-LP32:__ZTV7test4_D:
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long 4
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long __ZTI7test4_D
+// CHECK-LP32-NEXT: .long __ZN1C4bee1Ev
+// CHECK-LP32-NEXT: .long __ZN1C4bee2Ev
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long 4294967292
+// CHECK-LP32-NEXT: .long __ZTI7test4_D
+// CHECK-LP32-NEXT: .long __ZN1B4bar1Ev
+// CHECK-LP32-NEXT: .long __ZN1B4bar2Ev
+
+// CHECK-LP64:__ZTV7test4_D:
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad 8
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad __ZTI7test4_D
+// CHECK-LP64-NEXT: .quad __ZN1C4bee1Ev
+// CHECK-LP64-NEXT: .quad __ZN1C4bee2Ev
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad 18446744073709551608
+// CHECK-LP64-NEXT: .quad __ZTI7test4_D
+// CHECK-LP64-NEXT: .quad __ZN1B4bar1Ev
+// CHECK-LP64-NEXT: .quad __ZN1B4bar2Ev
+
+
+struct test5_B3 { virtual void funcB3(); };
+struct test5_B2 : virtual test5_B3 { virtual void funcB2(); };
+struct test5_B1 : virtual test5_B2 { virtual void funcB1(); };
+
+struct test5_B23 { virtual void funcB23(); };
+struct test5_B22 : virtual test5_B23 { virtual void funcB22(); };
+struct test5_B21 : virtual test5_B22 { virtual void funcB21(); };
+
+
+struct B232 { virtual void funcB232(); };
+struct B231 { virtual void funcB231(); };
+
+struct test5_B33 { virtual void funcB33(); };
+struct test5_B32 : virtual test5_B33, virtual B232 { virtual void funcB32(); };
+struct test5_B31 : virtual test5_B32, virtual B231 { virtual void funcB31(); };
+
+struct test5_D : virtual test5_B1, virtual test5_B21, virtual test5_B31 {
+ virtual void funcD() { }
+};
+
+// CHECK-LP32:__ZTV7test5_D:
+// CHECK-LP32-NEXT: .long 16
+// CHECK-LP32-NEXT: .long 12
+// CHECK-LP32-NEXT: .long 8
+// CHECK-LP32-NEXT: .long 8
+// CHECK-LP32-NEXT: .long 8
+// CHECK-LP32-NEXT: .long 4
+// CHECK-LP32-NEXT: .long 4
+// CHECK-LP32-NEXT: .long 4
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long __ZTI7test5_D
+// CHECK-LP32-NEXT: .long __ZN8test5_B36funcB3Ev
+// CHECK-LP32-NEXT: .long __ZN8test5_B26funcB2Ev
+// CHECK-LP32-NEXT: .long __ZN8test5_B16funcB1Ev
+// CHECK-LP32-NEXT: .long __ZN7test5_D5funcDEv
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long 4294967292
+// CHECK-LP32-NEXT: .long __ZTI7test5_D
+// CHECK-LP32-NEXT: .long __ZN9test5_B237funcB23Ev
+// CHECK-LP32-NEXT: .long __ZN9test5_B227funcB22Ev
+// CHECK-LP32-NEXT: .long __ZN9test5_B217funcB21Ev
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32: .long 8
+// CHECK-LP32 .space 4
+// CHECK-LP32 .space 4 FIXME
+// CHECK-LP32: .long 4
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long 4294967288
+// CHECK-LP32-NEXT: .long __ZTI7test5_D
+// CHECK-LP32-NEXT: .long __ZN9test5_B337funcB33Ev
+// CHECK-LP32-NEXT: .long __ZN9test5_B327funcB32Ev
+// CHECK-LP32-NEXT: .long __ZN9test5_B317funcB31Ev
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long 4294967284
+// CHECK-LP32-NEXT: .long __ZTI7test5_D
+// CHECK-LP32-NEXT: .long __ZN4B2328funcB232Ev
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long 4294967280
+// CHECK-LP32-NEXT: .long __ZTI7test5_D
+// CHECK-LP32-NEXT: .long __ZN4B2318funcB231Ev
+
+// CHECK-LP64:__ZTV7test5_D:
+// CHECK-LP64-NEXT: .quad 32
+// CHECK-LP64-NEXT: .quad 24
+// CHECK-LP64-NEXT: .quad 16
+// CHECK-LP64-NEXT: .quad 16
+// CHECK-LP64-NEXT: .quad 16
+// CHECK-LP64-NEXT: .quad 8
+// CHECK-LP64-NEXT: .quad 8
+// CHECK-LP64-NEXT: .quad 8
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad __ZTI7test5_D
+// CHECK-LP64-NEXT: .quad __ZN8test5_B36funcB3Ev
+// CHECK-LP64-NEXT: .quad __ZN8test5_B26funcB2Ev
+// CHECK-LP64-NEXT: .quad __ZN8test5_B16funcB1Ev
+// CHECK-LP64-NEXT: .quad __ZN7test5_D5funcDEv
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad 18446744073709551608
+// CHECK-LP64-NEXT: .quad __ZTI7test5_D
+// CHECK-LP64-NEXT: .quad __ZN9test5_B237funcB23Ev
+// CHECK-LP64-NEXT: .quad __ZN9test5_B227funcB22Ev
+// CHECK-LP64-NEXT: .quad __ZN9test5_B217funcB21Ev
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64: .quad 16
+// CHECK-LP64 .space 8
+// CHECK-LP64 .space 8
+// CHECK-LP64: .quad 8
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad 18446744073709551600
+// CHECK-LP64-NEXT: .quad __ZTI7test5_D
+// CHECK-LP64-NEXT: .quad __ZN9test5_B337funcB33Ev
+// CHECK-LP64-NEXT: .quad __ZN9test5_B327funcB32Ev
+// CHECK-LP64-NEXT: .quad __ZN9test5_B317funcB31Ev
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad 18446744073709551592
+// CHECK-LP64-NEXT: .quad __ZTI7test5_D
+// CHECK-LP64-NEXT: .quad __ZN4B2328funcB232Ev
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad 18446744073709551584
+// CHECK-LP64-NEXT: .quad __ZTI7test5_D
+// CHECK-LP64-NEXT: .quad __ZN4B2318funcB231Ev
+
+struct test8_B1 {
+ virtual void ftest8_B1() { }
+};
+struct test8_B2aa {
+ virtual void ftest8_B2aa() { }
+ int i;
+};
+struct test8_B2ab {
+ virtual void ftest8_B2ab() { }
+ int i;
+};
+struct test8_B2a : virtual test8_B2aa, virtual test8_B2ab {
+ virtual void ftest8_B2a() { }
+};
+struct test8_B2b {
+ virtual void ftest8_B2b() { }
+};
+struct test8_B2 : test8_B2a, test8_B2b {
+ virtual void ftest8_B2() { }
+};
+struct test8_B3 {
+ virtual void ftest8_B3() { }
+};
+class test8_D : test8_B1, test8_B2, test8_B3 {
+};
+
+// CHECK-LP32:__ZTV7test8_D:
+// CHECK-LP32-NEXT: .long 24
+// CHECK-LP32-NEXT: .long 16
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long __ZTI7test8_D
+// CHECK-LP32-NEXT: .long __ZN8test8_B19ftest8_B1Ev
+// CHECK-LP32-NEXT: .long 20
+// CHECK-LP32-NEXT: .long 12
+// CHECK-LP32-NEXT: .long 4294967292
+// CHECK-LP32-NEXT: .long __ZTI7test8_D
+// CHECK-LP32-NEXT: .long __ZN9test8_B2a10ftest8_B2aEv
+// CHECK-LP32-NEXT: .long __ZN8test8_B29ftest8_B2Ev
+// CHECK-LP32-NEXT: .long 4294967288
+// CHECK-LP32-NEXT: .long __ZTI7test8_D
+// CHECK-LP32-NEXT: .long __ZN9test8_B2b10ftest8_B2bEv
+// CHECK-LP32-NEXT: .long 4294967284
+// CHECK-LP32-NEXT: .long __ZTI7test8_D
+// CHECK-LP32-NEXT: .long __ZN8test8_B39ftest8_B3Ev
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long 4294967280
+// CHECK-LP32-NEXT: .long __ZTI7test8_D
+// CHECK-LP32-NEXT: .long __ZN10test8_B2aa11ftest8_B2aaEv
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long 4294967272
+// CHECK-LP32-NEXT: .long __ZTI7test8_D
+// CHECK-LP32-NEXT: .long __ZN10test8_B2ab11ftest8_B2abEv
+
+// CHECK-LP64:__ZTV7test8_D:
+// CHECK-LP64-NEXT: .quad 48
+// CHECK-LP64-NEXT: .quad 32
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad __ZTI7test8_D
+// CHECK-LP64-NEXT: .quad __ZN8test8_B19ftest8_B1Ev
+// CHECK-LP64-NEXT: .quad 40
+// CHECK-LP64-NEXT: .quad 24
+// CHECK-LP64-NEXT: .quad 18446744073709551608
+// CHECK-LP64-NEXT: .quad __ZTI7test8_D
+// CHECK-LP64-NEXT: .quad __ZN9test8_B2a10ftest8_B2aEv
+// CHECK-LP64-NEXT: .quad __ZN8test8_B29ftest8_B2Ev
+// CHECK-LP64-NEXT: .quad 18446744073709551600
+// CHECK-LP64-NEXT: .quad __ZTI7test8_D
+// CHECK-LP64-NEXT: .quad __ZN9test8_B2b10ftest8_B2bEv
+// CHECK-LP64-NEXT: .quad 18446744073709551592
+// CHECK-LP64-NEXT: .quad __ZTI7test8_D
+// CHECK-LP64-NEXT: .quad __ZN8test8_B39ftest8_B3Ev
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad 18446744073709551584
+// CHECK-LP64-NEXT: .quad __ZTI7test8_D
+// CHECK-LP64-NEXT: .quad __ZN10test8_B2aa11ftest8_B2aaEv
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad 18446744073709551568
+// CHECK-LP64-NEXT: .quad __ZTI7test8_D
+// CHECK-LP64-NEXT: .quad __ZN10test8_B2ab11ftest8_B2abEv
+
+
+struct test9_B3 { virtual void funcB3(); int i; };
+struct test9_B2 : virtual test9_B3 { virtual void funcB2(); int i; };
+struct test9_B1 : virtual test9_B2 { virtual void funcB1(); int i; };
+
+struct test9_B23 { virtual void funcB23(); int i; };
+struct test9_B22 : virtual test9_B23 { virtual void funcB22(); int i; };
+struct test9_B21 : virtual test9_B22 { virtual void funcB21(); int i; };
+
+
+struct test9_B232 { virtual void funcB232(); int i; };
+struct test9_B231 { virtual void funcB231(); int i; };
+
+struct test9_B33 { virtual void funcB33(); int i; };
+struct test9_B32 : virtual test9_B33, virtual test9_B232 { virtual void funcB32(); int i; };
+struct test9_B31 : virtual test9_B32, virtual test9_B231 { virtual void funcB31(); int i; };
+
+struct test9_D : virtual test9_B1, virtual test9_B21, virtual test9_B31 {
+ virtual void funcD() { }
+};
+
+// CHECK-LP64: __ZTV7test9_D:
+// CHECK-LP64-NEXT: .quad 168
+// CHECK-LP64-NEXT: .quad 152
+// CHECK-LP64-NEXT: .quad 136
+// CHECK-LP64-NEXT: .quad 120
+// CHECK-LP64-NEXT: .quad 104
+// CHECK-LP64-NEXT: .quad 88
+// CHECK-LP64-NEXT: .quad 72
+// CHECK-LP64-NEXT: .quad 56
+// CHECK-LP64-NEXT: .quad 40
+// CHECK-LP64-NEXT: .quad 24
+// CHECK-LP64-NEXT: .quad 8
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad __ZTI7test9_D
+// CHECK-LP64-NEXT: .quad __ZN7test9_D5funcDEv
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad 32
+// CHECK-LP64-NEXT: .quad 16
+// CHECK-LP64-NEXT: .quad 18446744073709551608
+// CHECK-LP64-NEXT: .quad __ZTI7test9_D
+// CHECK-LP64-NEXT: .quad __ZN8test9_B16funcB1Ev
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad 16
+// CHECK-LP64-NEXT: .quad 18446744073709551592
+// CHECK-LP64-NEXT: .quad __ZTI7test9_D
+// CHECK-LP64-NEXT: .quad __ZN8test9_B26funcB2Ev
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad 18446744073709551576
+// CHECK-LP64-NEXT: .quad __ZTI7test9_D
+// CHECK-LP64-NEXT: .quad __ZN8test9_B36funcB3Ev
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad 32
+// CHECK-LP64-NEXT: .quad 16
+// CHECK-LP64-NEXT: .quad 18446744073709551560
+// CHECK-LP64-NEXT: .quad __ZTI7test9_D
+// CHECK-LP64-NEXT: .quad __ZN9test9_B217funcB21Ev
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad 16
+// CHECK-LP64-NEXT: .quad 18446744073709551544
+// CHECK-LP64-NEXT: .quad __ZTI7test9_D
+// CHECK-LP64-NEXT: .quad __ZN9test9_B227funcB22Ev
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad 18446744073709551528
+// CHECK-LP64-NEXT: .quad __ZTI7test9_D
+// CHECK-LP64-NEXT: .quad __ZN9test9_B237funcB23Ev
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad 64
+// CHECK-LP64-NEXT: .quad 48
+// CHECK-LP64-NEXT: .quad 32
+// CHECK-LP64-NEXT: .quad 16
+// CHECK-LP64-NEXT: .quad 18446744073709551512
+// CHECK-LP64-NEXT: .quad __ZTI7test9_D
+// CHECK-LP64-NEXT: .quad __ZN9test9_B317funcB31Ev
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad 32
+// CHECK-LP64-NEXT: .quad 16
+// CHECK-LP64-NEXT: .quad 18446744073709551496
+// CHECK-LP64-NEXT: .quad __ZTI7test9_D
+// CHECK-LP64-NEXT: .quad __ZN9test9_B327funcB32Ev
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad 18446744073709551480
+// CHECK-LP64-NEXT: .quad __ZTI7test9_D
+// CHECK-LP64-NEXT: .quad __ZN9test9_B337funcB33Ev
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad 18446744073709551464
+// CHECK-LP64-NEXT: .quad __ZTI7test9_D
+// CHECK-LP64-NEXT: .quad __ZN10test9_B2328funcB232Ev
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad 18446744073709551448
+// CHECK-LP64-NEXT: .quad __ZTI7test9_D
+// CHECK-LP64-NEXT: .quad __ZN10test9_B2318funcB231Ev
+
+// CHECK-LP32: __ZTV7test9_D:
+// CHECK-LP32-NEXT: .long 84
+// CHECK-LP32-NEXT: .long 76
+// CHECK-LP32-NEXT: .long 68
+// CHECK-LP32-NEXT: .long 60
+// CHECK-LP32-NEXT: .long 52
+// CHECK-LP32-NEXT: .long 44
+// CHECK-LP32-NEXT: .long 36
+// CHECK-LP32-NEXT: .long 28
+// CHECK-LP32-NEXT: .long 20
+// CHECK-LP32-NEXT: .long 12
+// CHECK-LP32-NEXT: .long 4
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long __ZTI7test9_D
+// CHECK-LP32-NEXT: .long __ZN7test9_D5funcDEv
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long 16
+// CHECK-LP32-NEXT: .long 8
+// CHECK-LP32-NEXT: .long 4294967292
+// CHECK-LP32-NEXT: .long __ZTI7test9_D
+// CHECK-LP32-NEXT: .long __ZN8test9_B16funcB1Ev
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long 8
+// CHECK-LP32-NEXT: .long 4294967284
+// CHECK-LP32-NEXT: .long __ZTI7test9_D
+// CHECK-LP32-NEXT: .long __ZN8test9_B26funcB2Ev
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long 4294967276
+// CHECK-LP32-NEXT: .long __ZTI7test9_D
+// CHECK-LP32-NEXT: .long __ZN8test9_B36funcB3Ev
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long 16
+// CHECK-LP32-NEXT: .long 8
+// CHECK-LP32-NEXT: .long 4294967268
+// CHECK-LP32-NEXT: .long __ZTI7test9_D
+// CHECK-LP32-NEXT: .long __ZN9test9_B217funcB21Ev
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long 8
+// CHECK-LP32-NEXT: .long 4294967260
+// CHECK-LP32-NEXT: .long __ZTI7test9_D
+// CHECK-LP32-NEXT: .long __ZN9test9_B227funcB22Ev
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long 4294967252
+// CHECK-LP32-NEXT: .long __ZTI7test9_D
+// CHECK-LP32-NEXT: .long __ZN9test9_B237funcB23Ev
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long 32
+// CHECK-LP32-NEXT: .long 24
+// CHECK-LP32-NEXT: .long 16
+// CHECK-LP32-NEXT: .long 8
+// CHECK-LP32-NEXT: .long 4294967244
+// CHECK-LP32-NEXT: .long __ZTI7test9_D
+// CHECK-LP32-NEXT: .long __ZN9test9_B317funcB31Ev
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long 16
+// CHECK-LP32-NEXT: .long 8
+// CHECK-LP32-NEXT: .long 4294967236
+// CHECK-LP32-NEXT: .long __ZTI7test9_D
+// CHECK-LP32-NEXT: .long __ZN9test9_B327funcB32Ev
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long 4294967228
+// CHECK-LP32-NEXT: .long __ZTI7test9_D
+// CHECK-LP32-NEXT: .long __ZN9test9_B337funcB33Ev
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long 4294967220
+// CHECK-LP32-NEXT: .long __ZTI7test9_D
+// CHECK-LP32-NEXT: .long __ZN10test9_B2328funcB232Ev
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long 4294967212
+// CHECK-LP32-NEXT: .long __ZTI7test9_D
+// CHECK-LP32-NEXT: .long __ZN10test9_B2318funcB231Ev
+
+struct test10_O { int i; };
+
+struct test10_B1 : virtual test10_O {
+ virtual void ftest10_B1() { }
+};
+
+struct test10_B2aa : virtual test10_O {
+ int i;
+};
+struct test10_B2ab : virtual test10_O {
+ int i;
+};
+struct test10_B2a : virtual test10_B2aa, virtual test10_B2ab,virtual test10_O {
+ virtual void ftest10_B2a() { }
+};
+struct test10_B2b : virtual test10_O {
+ virtual void ftest10_B2b() { }
+};
+struct test10_B2 : test10_B2a {
+ virtual void ftest10_B2() { }
+};
+class test10_D : test10_B1, test10_B2 {
+
+ void ftest10_B2aa() { }
+};
+
+// CHECK-LP64:__ZTV8test10_D:
+// CHECK-LP64-NEXT: .quad 40
+// CHECK-LP64-NEXT: .quad 24
+// CHECK-LP64-NEXT: .quad 16
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad __ZTI8test10_D
+// CHECK-LP64-NEXT: .quad __ZN9test10_B110ftest10_B1Ev
+// CHECK-LP64-NEXT: .quad 32
+// CHECK-LP64-NEXT: .quad 8
+// CHECK-LP64-NEXT: .quad 16
+// CHECK-LP64-NEXT: .quad 18446744073709551608
+// CHECK-LP64-NEXT: .quad __ZTI8test10_D
+// CHECK-LP64-NEXT: .quad __ZN10test10_B2a11ftest10_B2aEv
+// CHECK-LP64-NEXT: .quad __ZN9test10_B210ftest10_B2Ev
+// CHECK-LP64-NEXT: .quad 18446744073709551608
+// CHECK-LP64-NEXT: .quad 18446744073709551592
+// CHECK-LP64-NEXT: .quad __ZTI8test10_D
+// CHECK-LP64-NEXT: .quad 18446744073709551592
+// CHECK-LP64-NEXT: .quad 18446744073709551576
+// CHECK-LP64-NEXT: .quad __ZTI8test10_D
+
+// CHECK-LP32: __ZTV8test10_D:
+// CHECK-LP32-NEXT: .long 20
+// CHECK-LP32-NEXT: .long 12
+// CHECK-LP32-NEXT: .long 8
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long __ZTI8test10_D
+// CHECK-LP32-NEXT: .long __ZN9test10_B110ftest10_B1Ev
+// CHECK-LP32-NEXT: .long 16
+// CHECK-LP32-NEXT: .long 4
+// CHECK-LP32-NEXT: .long 8
+// CHECK-LP32-NEXT: .long 4294967292
+// CHECK-LP32-NEXT: .long __ZTI8test10_D
+// CHECK-LP32-NEXT: .long __ZN10test10_B2a11ftest10_B2aEv
+// CHECK-LP32-NEXT: .long __ZN9test10_B210ftest10_B2Ev
+// CHECK-LP32-NEXT: .long 4294967292
+// CHECK-LP32-NEXT: .long 4294967284
+// CHECK-LP32-NEXT: .long __ZTI8test10_D
+// CHECK-LP32-NEXT: .long 4294967284
+// CHECK-LP32-NEXT: .long 4294967276
+// CHECK-LP32-NEXT: .long __ZTI8test10_D
+
+struct test11_B {
+ virtual void B1() { }
+ virtual void D() { }
+ virtual void B2() { }
+};
+
+struct test11_D : test11_B {
+ virtual void D1() { }
+ virtual void D() { }
+ virtual void D2() { }
+};
+
+// CHECK-LP32:__ZTV8test11_D:
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long __ZTI8test11_D
+// CHECK-LP32-NEXT: .long __ZN8test11_B2B1Ev
+// CHECK-LP32-NEXT: .long __ZN8test11_D1DEv
+// CHECK-LP32-NEXT: .long __ZN8test11_B2B2Ev
+// CHECK-LP32-NEXT: .long __ZN8test11_D2D1Ev
+// CHECK-LP32-NEXT: .long __ZN8test11_D2D2Ev
+
+
+// CHECK-LP64:__ZTV8test11_D:
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad __ZTI8test11_D
+// CHECK-LP64-NEXT: .quad __ZN8test11_B2B1Ev
+// CHECK-LP64-NEXT: .quad __ZN8test11_D1DEv
+// CHECK-LP64-NEXT: .quad __ZN8test11_B2B2Ev
+// CHECK-LP64-NEXT: .quad __ZN8test11_D2D1Ev
+// CHECK-LP64-NEXT: .quad __ZN8test11_D2D2Ev
+
+struct test13_B {
+ virtual void B1() { }
+ virtual void D() { }
+ virtual void Da();
+ virtual void Db() { }
+ virtual void Dc() { }
+ virtual void B2() { }
+ int i;
+};
+
+
+struct test13_NV1 {
+ virtual void fooNV1() { }
+ virtual void D() { }
+};
+
+
+struct test13_B2 : /* test13_NV1, */ virtual test13_B {
+ virtual void B2a() { }
+ virtual void B2() { }
+ virtual void D() { }
+ virtual void Da();
+ virtual void Dd() { }
+ virtual void B2b() { }
+ int i;
+};
+
+
+struct test13_D : test13_NV1, virtual test13_B2 {
+ virtual void D1() { }
+ virtual void D() { }
+ virtual void Db() { }
+ virtual void Dd() { }
+ virtual void D2() { }
+ virtual void fooNV1() { }
+};
+
+// CHECK-LP64:__ZTV8test13_D:
+// CHECK-LP64-NEXT: .quad 24
+// CHECK-LP64-NEXT: .quad 8
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad __ZTI8test13_D
+// CHECK-LP64-NEXT: .quad __ZN8test13_D6fooNV1Ev
+// CHECK-LP64-NEXT: .quad __ZN8test13_D1DEv
+// CHECK-LP64-NEXT: .quad __ZN8test13_D2D1Ev
+// CHECK-LP64-NEXT: .quad __ZN8test13_D2DbEv
+// CHECK-LP64-NEXT: .quad __ZN8test13_D2DdEv
+// CHECK-LP64-NEXT: .quad __ZN8test13_D2D2Ev
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad 18446744073709551608
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad 18446744073709551608
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad 16
+// CHECK-LP64-NEXT: .quad 18446744073709551608
+// CHECK-LP64-NEXT: .quad __ZTI8test13_D
+// CHECK-LP64-NEXT: .quad __ZN9test13_B23B2aEv
+// CHECK-LP64-NEXT: .quad __ZN9test13_B22B2Ev
+// CHECK-LP64-NEXT: .quad __ZTv0_n48_N8test13_D1DEv
+// CHECK-LP64-NEXT: .quad __ZN9test13_B22DaEv
+// CHECK-LP64-NEXT: .quad __ZTv0_n64_N8test13_D2DdEv
+// CHECK-LP64-NEXT: .quad __ZN9test13_B23B2bEv
+// CHECK-LP64-NEXT: .quad 18446744073709551600
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad 18446744073709551592
+// CHECK-LP64-NEXT: .quad 18446744073709551600
+// CHECK-LP64-NEXT: .quad 18446744073709551592
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad 18446744073709551592
+// CHECK-LP64-NEXT: .quad __ZTI8test13_D
+// CHECK-LP64-NEXT: .quad __ZN8test13_B2B1Ev
+// CHECK-LP64-NEXT: .quad __ZTv0_n32_N8test13_D1DEv
+// CHECK-LP64-NEXT: .quad __ZTv0_n40_N9test13_B22DaEv
+// CHECK-LP64-NEXT: .quad __ZTv0_n48_N8test13_D2DbEv
+// CHECK-LP64-NEXT: .quad __ZN8test13_B2DcEv
+// CHECK-LP64-NEXT: .quad __ZTv0_n64_N9test13_B22B2Ev
+
+// CHECK-LP32:__ZTV8test13_D:
+// CHECK-LP32-NEXT: .long 12
+// CHECK-LP32-NEXT: .long 4
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long __ZTI8test13_D
+// CHECK-LP32-NEXT: .long __ZN8test13_D6fooNV1Ev
+// CHECK-LP32-NEXT: .long __ZN8test13_D1DEv
+// CHECK-LP32-NEXT: .long __ZN8test13_D2D1Ev
+// CHECK-LP32-NEXT: .long __ZN8test13_D2DbEv
+// CHECK-LP32-NEXT: .long __ZN8test13_D2DdEv
+// CHECK-LP32-NEXT: .long __ZN8test13_D2D2Ev
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long 4294967292
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long 4294967292
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long 8
+// CHECK-LP32-NEXT: .long 4294967292
+// CHECK-LP32-NEXT: .long __ZTI8test13_D
+// CHECK-LP32-NEXT: .long __ZN9test13_B23B2aEv
+// CHECK-LP32-NEXT: .long __ZN9test13_B22B2Ev
+// CHECK-LP32-NEXT: .long __ZTv0_n24_N8test13_D1DEv
+// CHECK-LP32-NEXT: .long __ZN9test13_B22DaEv
+// CHECK-LP32-NEXT: .long __ZTv0_n32_N8test13_D2DdEv
+// CHECK-LP32-NEXT: .long __ZN9test13_B23B2bEv
+// CHECK-LP32-NEXT: .long 4294967288
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long 4294967284
+// CHECK-LP32-NEXT: .long 4294967288
+// CHECK-LP32-NEXT: .long 4294967284
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long 4294967284
+// CHECK-LP32-NEXT: .long __ZTI8test13_D
+// CHECK-LP32-NEXT: .long __ZN8test13_B2B1Ev
+// CHECK-LP32-NEXT: .long __ZTv0_n16_N8test13_D1DEv
+// CHECK-LP32-NEXT: .long __ZTv0_n20_N9test13_B22DaEv
+// CHECK-LP32-NEXT: .long __ZTv0_n24_N8test13_D2DbEv
+// CHECK-LP32-NEXT: .long __ZN8test13_B2DcEv
+// CHECK-LP32-NEXT: .long __ZTv0_n32_N9test13_B22B2Ev
+
+
+class test14 {
+public:
+ virtual void initWithInt(int a);
+ static test14 *withInt(int a);
+};
+
+void test14::initWithInt(int a) { }
+
+test14 *test14::withInt(int a) {
+ test14 *me = new test14;
+ me->initWithInt(a);
+ return me;
+}
+
+
+struct test15_B {
+ virtual test15_B *foo1() { return 0; }
+ virtual test15_B *foo2() { return 0; }
+ virtual test15_B *foo3() { return 0; }
+ int i;
+};
+
+struct test15_NV1 {
+ virtual void fooNV1() { }
+ int i;
+};
+
+struct test15_B2 : test15_NV1, virtual test15_B {
+ virtual test15_B2 *foo1() { return 0; }
+ virtual test15_B2 *foo2() { return 0; }
+ int i;
+};
+
+struct test15_D : test15_NV1, virtual test15_B2 {
+ virtual test15_D *foo1() { return 0; }
+};
+
+// CHECK-LP64:__ZTV8test15_D:
+// CHECK-LP64-NEXT: .quad 32
+// CHECK-LP64-NEXT: .quad 16
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad __ZTI8test15_D
+// CHECK-LP64-NEXT: .quad __ZN10test15_NV16fooNV1Ev
+// CHECK-LP64-NEXT: .quad __ZN8test15_D4foo1Ev
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad 18446744073709551600
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad 16
+// CHECK-LP64-NEXT: .quad 18446744073709551600
+// CHECK-LP64-NEXT: .quad __ZTI8test15_D
+// CHECK-LP64-NEXT: .quad __ZN10test15_NV16fooNV1Ev
+// CHECK-LP64-NEXT: .quad __ZTcv0_n40_v0_n24_N8test15_D4foo1Ev
+// CHECK-LP64-NEXT: .quad __ZN9test15_B24foo2Ev
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad 18446744073709551600
+// CHECK-LP64-NEXT: .quad 18446744073709551584
+// CHECK-LP64-NEXT: .quad 18446744073709551584
+// CHECK-LP64-NEXT: .quad __ZTI8test15_D
+// CHECK-LP64-NEXT: .quad __ZTcv0_n24_v0_n32_N8test15_D4foo1Ev
+// CHECK-LP64-NEXT: .quad __ZTcv0_n32_v0_n24_N9test15_B24foo2Ev
+// CHECK-LP64-NEXT: .quad __ZN8test15_B4foo3Ev
+
+// CHECK-LP32:__ZTV8test15_D:
+// CHECK-LP32-NEXT: .long 20
+// CHECK-LP32-NEXT: .long 8
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long __ZTI8test15_D
+// CHECK-LP32-NEXT: .long __ZN10test15_NV16fooNV1Ev
+// CHECK-LP32-NEXT: .long __ZN8test15_D4foo1Ev
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long 4294967288
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long 12
+// CHECK-LP32-NEXT: .long 4294967288
+// CHECK-LP32-NEXT: .long __ZTI8test15_D
+// CHECK-LP32-NEXT: .long __ZN10test15_NV16fooNV1Ev
+// CHECK-LP32-NEXT: .long __ZTcv0_n20_v0_n12_N8test15_D4foo1Ev
+// CHECK-LP32-NEXT: .long __ZN9test15_B24foo2Ev
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long 4294967284
+// CHECK-LP32-NEXT: .long 4294967276
+// CHECK-LP32-NEXT: .long 4294967276
+// CHECK-LP32-NEXT: .long __ZTI8test15_D
+// CHECK-LP32-NEXT: .long __ZTcv0_n12_v0_n16_N8test15_D4foo1Ev
+// CHECK-LP32-NEXT: .long __ZTcv0_n16_v0_n12_N9test15_B24foo2Ev
+// CHECK-LP32-NEXT: .long __ZN8test15_B4foo3Ev
+
+
+
+// CHECK-LP64: __ZTV1B:
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad __ZTI1B
+// CHECK-LP64-NEXT: .quad __ZN1B4bar1Ev
+// CHECK-LP64-NEXT: .quad __ZN1B4bar2Ev
+
+// CHECK-LP32: __ZTV1B:
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long __ZTI1B
+// CHECK-LP32-NEXT: .long __ZN1B4bar1Ev
+// CHECK-LP32-NEXT: .long __ZN1B4bar2Ev
+
+// CHECK-LP64: __ZTV1A:
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad __ZTI1A
+// CHECK-LP64-NEXT: .quad __ZN1B4bar1Ev
+// CHECK-LP64-NEXT: .quad __ZN1B4bar2Ev
+// CHECK-LP64-NEXT: .quad __ZN1A4foo1Ev
+// CHECK-LP64-NEXT: .quad __ZN1A4foo2Ev
+// CHECK-LP64-NEXT: .quad 18446744073709551600
+// CHECK-LP64-NEXT: .quad __ZTI1A
+// CHECK-LP64-NEXT: .quad __ZN1C4bee1Ev
+// CHECK-LP64-NEXT: .quad __ZN1C4bee2Ev
+
+// CHECK-LP32: __ZTV1A:
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long __ZTI1A
+// CHECK-LP32-NEXT: .long __ZN1B4bar1Ev
+// CHECK-LP32-NEXT: .long __ZN1B4bar2Ev
+// CHECK-LP32-NEXT: .long __ZN1A4foo1Ev
+// CHECK-LP32-NEXT: .long __ZN1A4foo2Ev
+// CHECK-LP32-NEXT: .long 4294967284
+// CHECK-LP32-NEXT: .long __ZTI1A
+// CHECK-LP32-NEXT: .long __ZN1C4bee1Ev
+// CHECK-LP32-NEXT: .long __ZN1C4bee2Ev
+
+// CHECK-LP32:__ZTV1F:
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long 8
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long __ZTI1F
+// CHECK-LP32-NEXT: .long __ZN1D3booEv
+// CHECK-LP32-NEXT: .long __ZN1F3fooEv
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long 4294967288
+// CHECK-LP32-NEXT: .long __ZTI1F
+// CHECK-LP32-NEXT: .long __ZN2D13barEv
+// CHECK-LP32-NEXT: .long __ZN2D14bar2Ev
+// CHECK-LP32-NEXT: .long __ZN2D14bar3Ev
+// CHECK-LP32-NEXT: .long __ZN2D14bar4Ev
+// CHECK-LP32-NEXT: .long __ZN2D14bar5Ev
+
+// CHECK-LP64: __ZTV1F:
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad 16
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad __ZTI1F
+// CHECK-LP64-NEXT: .quad __ZN1D3booEv
+// CHECK-LP64-NEXT: .quad __ZN1F3fooEv
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad 18446744073709551600
+// CHECK-LP64-NEXT: .quad __ZTI1F
+// CHECK-LP64-NEXT: .quad __ZN2D13barEv
+// CHECK-LP64-NEXT: .quad __ZN2D14bar2Ev
+// CHECK-LP64-NEXT: .quad __ZN2D14bar3Ev
+// CHECK-LP64-NEXT: .quad __ZN2D14bar4Ev
+// CHECK-LP64-NEXT: .quad __ZN2D14bar5Ev
+
+test15_D d15;
+test13_D d13;
+test11_D d11;
+test10_D d10;
+test9_D d9;
+test8_D d8;
+
+test5_D d5;
+test4_D d4;
+test3_D d3;
+
+test6_D d6;
+test7_D d7;
diff --git a/test/CodeGenCXX/virtual-base-cast.cpp b/test/CodeGenCXX/virtual-base-cast.cpp
new file mode 100644
index 0000000..a825120
--- /dev/null
+++ b/test/CodeGenCXX/virtual-base-cast.cpp
@@ -0,0 +1,9 @@
+// RUN: clang-cc -emit-llvm-only %s
+
+struct A { virtual ~A(); };
+struct B : A { virtual ~B(); };
+struct C : virtual B { virtual ~C(); };
+
+void f(C *c) {
+ A* a = c;
+}
diff --git a/test/CodeGenCXX/virtual-function-calls.cpp b/test/CodeGenCXX/virtual-function-calls.cpp
new file mode 100644
index 0000000..ca5acba
--- /dev/null
+++ b/test/CodeGenCXX/virtual-function-calls.cpp
@@ -0,0 +1,11 @@
+// RUN: clang-cc %s -emit-llvm -o - | FileCheck %s
+
+// PR5021
+struct A {
+ virtual void f(char);
+};
+
+void f(A *a) {
+ // CHECK: call void %
+ a->f('c');
+}
diff --git a/test/CodeGenCXX/vtable-cast-crash.cpp b/test/CodeGenCXX/vtable-cast-crash.cpp
new file mode 100644
index 0000000..a91d979
--- /dev/null
+++ b/test/CodeGenCXX/vtable-cast-crash.cpp
@@ -0,0 +1,21 @@
+// RUN: clang-cc -emit-llvm-only %s
+struct A
+{
+A();
+virtual ~A();
+};
+
+struct B: A
+{
+ B();
+ ~B();
+};
+
+B::B()
+{
+}
+
+B::~B()
+{
+}
+
diff --git a/test/CodeGenCXX/x86_64-arguments.cpp b/test/CodeGenCXX/x86_64-arguments.cpp
new file mode 100644
index 0000000..426c867
--- /dev/null
+++ b/test/CodeGenCXX/x86_64-arguments.cpp
@@ -0,0 +1,10 @@
+// RUN: clang-cc -triple x86_64-unknown-unknown -emit-llvm -o %t %s &&
+struct A { ~A(); };
+
+// RUN: grep 'define void @_Z2f11A(.struct.A\* .a)' %t &&
+void f1(A a) { }
+
+// RUN: grep 'define void @_Z2f2v(.struct.A\* noalias sret .agg.result)' %t &&
+A f2() { return A(); }
+
+// RUN: true
diff --git a/test/CodeGenObjC/PR4541.m b/test/CodeGenObjC/PR4541.m
new file mode 100644
index 0000000..9a65116
--- /dev/null
+++ b/test/CodeGenObjC/PR4541.m
@@ -0,0 +1,19 @@
+// RUN: clang-cc -o %t -w -g %s
+
+
+@class NSString;
+@interface NSAttributedString
+- (NSString *)string;
+@end
+@interface NSMutableAttributedString : NSAttributedString
+@end
+@class NSImage;
+@implementation CYObjectsController
++ (void)initialize {
+}
++ (NSAttributedString *)attributedStringWithString:(id)string image:(NSImage *)image {
+ NSMutableAttributedString *attrStr;
+}
+@end
+
+
diff --git a/test/CodeGenObjC/PR4894-recursive-debug-crash.m b/test/CodeGenObjC/PR4894-recursive-debug-crash.m
new file mode 100644
index 0000000..c5f901c
--- /dev/null
+++ b/test/CodeGenObjC/PR4894-recursive-debug-crash.m
@@ -0,0 +1,40 @@
+// RUN: clang-cc -triple i386-apple-darwin9 -g -emit-llvm %s -o - | FileCheck %s
+// PR4894
+//
+// This test is actually just making sure we can generate the debug info for the
+// return type from im0 without crashing.
+// XFAIL
+
+@interface I0 {
+ I0 *_iv0;
+}
+@end
+@protocol P0 @end
+
+@interface I1 @end
+@implementation I1
+- (I0<P0> *) im0 {
+// CHECK: @"\01-[I1 im0]"
+// CHECK: llvm.dbg.func.start
+ return 0;
+}
+@end
+
+// FIXME: This was another PR4894 test case, which is crashing somewhere
+// else. PR5025.
+#if 0
+typedef const struct objc_selector {
+ void *sel_id;
+ const char *sel_types;
+} *SEL;
+
+@interface I2
++(id) dictionary;
+@end
+
+@implementation I3;
++(void) initialize {
+ I2 *a0 = [I2 dictionary];
+}
+@end
+#endif
diff --git a/test/CodeGenObjC/constant-strings.m b/test/CodeGenObjC/constant-strings.m
index d4fefd9..82cd916 100644
--- a/test/CodeGenObjC/constant-strings.m
+++ b/test/CodeGenObjC/constant-strings.m
@@ -1,4 +1,6 @@
-// RUN: clang-cc -fnext-runtime -emit-llvm -o %t %s
+// RUN: clang-cc -fnext-runtime -emit-llvm -o %t %s &&
+// RUN: clang-cc -fgnu-runtime -emit-llvm -o %t %s && grep NXConstantString %t | count 1 &&
+// RUN: clang-cc -fgnu-runtime -fconstant-string-class=NSConstantString -emit-llvm -o %t %s && grep NSConstantString %t | count 1
id a = @"Hello World!";
diff --git a/test/CodeGenObjC/debug-info-linkagename.m b/test/CodeGenObjC/debug-info-linkagename.m
new file mode 100644
index 0000000..7305689
--- /dev/null
+++ b/test/CodeGenObjC/debug-info-linkagename.m
@@ -0,0 +1,17 @@
+// RUN: clang-cc -g -S -o %t %s &&
+// RUN: not grep 001 %t
+
+@interface F
+-(int) bar;
+@end
+
+@implementation F
+-(int) bar {
+ return 42;
+}
+@end
+
+extern int f(F *fn) {
+ return [fn bar];
+}
+
diff --git a/test/CodeGenObjC/for-in.m b/test/CodeGenObjC/for-in.m
new file mode 100644
index 0000000..434ff79
--- /dev/null
+++ b/test/CodeGenObjC/for-in.m
@@ -0,0 +1,44 @@
+// RUN: clang-cc -emit-llvm %s -o %t
+
+void p(const char*, ...);
+
+@interface NSArray
++(NSArray*) arrayWithObjects: (id) first, ...;
+-(unsigned) count;
+@end
+@interface NSString
+-(const char*) cString;
+@end
+
+#define S(n) @#n
+#define L1(n) S(n+0),S(n+1)
+#define L2(n) L1(n+0),L1(n+2)
+#define L3(n) L2(n+0),L2(n+4)
+#define L4(n) L3(n+0),L3(n+8)
+#define L5(n) L4(n+0),L4(n+16)
+#define L6(n) L5(n+0),L5(n+32)
+
+void t0() {
+ NSArray *array = [NSArray arrayWithObjects: L1(0), (void*)0];
+
+ p("array.length: %d\n", [array count]);
+ unsigned index = 0;
+ for (NSString *i in array) {
+ p("element %d: %s\n", index++, [i cString]);
+ }
+}
+
+void t1() {
+ NSArray *array = [NSArray arrayWithObjects: L6(0), (void*)0];
+
+ p("array.length: %d\n", [array count]);
+ unsigned index = 0;
+ for (NSString *i in array) {
+ index++;
+ if (index == 10)
+ continue;
+ p("element %d: %s\n", index, [i cString]);
+ if (index == 55)
+ break;
+ }
+}
diff --git a/test/CodeGenObjC/ivar-layout-64-bitfields.m b/test/CodeGenObjC/ivar-layout-64-bitfields.m
new file mode 100644
index 0000000..cb56118
--- /dev/null
+++ b/test/CodeGenObjC/ivar-layout-64-bitfields.m
@@ -0,0 +1,40 @@
+// RUN: clang-cc -triple x86_64-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s
+@interface I
+{
+ struct {
+ unsigned int d : 1;
+ } bitfield;
+}
+@end
+
+@implementation I
+@end
+
+@interface J
+{
+ struct {
+ unsigned short _reserved : 16;
+
+ _Bool _draggedNodesAreDeletable: 1;
+ _Bool _draggedOutsideOutlineView : 1;
+ _Bool _adapterRespondsTo_addRootPaths : 1;
+ _Bool _adapterRespondsTo_moveDataNodes : 1;
+ _Bool _adapterRespondsTo_removeRootDataNode : 1;
+ _Bool _adapterRespondsTo_doubleClickDataNode : 1;
+ _Bool _adapterRespondsTo_selectDataNode : 1;
+ _Bool _adapterRespondsTo_textDidEndEditing : 1;
+
+ _Bool _adapterRespondsTo_updateAndSaveRoots : 1;
+ _Bool _adapterRespondsTo_askToDeleteRootNodes : 1;
+ _Bool _adapterRespondsTo_contextMenuForSelectedNodes : 1;
+ _Bool _adapterRespondsTo_pasteboardFilenamesForNodes : 1;
+ _Bool _adapterRespondsTo_writeItemsToPasteboard : 1;
+ _Bool _adapterRespondsTo_writeItemsToPasteboardXXXX : 1;
+ } _flags;
+}
+@end
+
+@implementation J
+@end
+
+
diff --git a/test/CodeGenObjC/ivar-layout-no-optimize.m b/test/CodeGenObjC/ivar-layout-no-optimize.m
new file mode 100644
index 0000000..d7796bc
--- /dev/null
+++ b/test/CodeGenObjC/ivar-layout-no-optimize.m
@@ -0,0 +1,18 @@
+// RUN: clang-cc -fobjc-gc -triple x86_64-apple-darwin -O0 -S %s -o %t-64.s &&
+// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s &&
+// RUN: true
+
+@interface NSObject {
+ id isa;
+}
+@end
+
+@interface AllPointers : NSObject {
+ id foo;
+ void *__strong bar; NSObject *bletch;}
+@end
+@implementation AllPointers
+@end
+
+// CHECK-LP64: L_OBJC_CLASS_NAME_6:
+// CHECK-LP64-NEXT: .asciz "\004"
diff --git a/test/CodeGenObjC/messages.m b/test/CodeGenObjC/messages.m
index f9b9be6..b7f42d1 100644
--- a/test/CodeGenObjC/messages.m
+++ b/test/CodeGenObjC/messages.m
@@ -2,8 +2,8 @@
// 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: clang-cc -fgnu-runtime -fobjc-nonfragile-abi --emit-llvm -o %t %s &&
+// RUN: grep "objc_msg_lookup_sender" %t | count 6 &&
// RUN: true
typedef struct {
diff --git a/test/CodeGenObjC/objc-assign-ivar.m b/test/CodeGenObjC/objc-assign-ivar.m
new file mode 100644
index 0000000..f79faaf
--- /dev/null
+++ b/test/CodeGenObjC/objc-assign-ivar.m
@@ -0,0 +1,53 @@
+// RUN: clang-cc -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s &&
+// RUN: grep -F '@objc_assign_ivar' %t | count 14 &&
+// RUN: true
+
+typedef struct {
+ id element;
+ id elementArray[10];
+ __strong id cfElement;
+ __strong id cfElementArray[10];
+} struct_with_ids_t;
+
+
+@interface NSString @end
+
+@interface Foo {
+@public
+// assignments to any/all of these fields should generate objc_assign_ivar
+ __strong id dict;
+ __strong id dictArray[3];
+ id ivar;
+ id array[10];
+ id nsobject;
+ NSString *stringArray[10];
+ struct_with_ids_t inner;
+
+ Foo *obj[20];
+ short idx[5];
+}
+@end
+
+// The test cases
+int IvarAssigns;
+void *rhs = 0;
+#define ASSIGNTEST(expr, global) expr = rhs
+
+void testIvars() {
+ Foo *foo;
+ ASSIGNTEST(foo->ivar, IvarAssigns); // objc_assign_ivar
+ ASSIGNTEST(foo->dict, IvarAssigns); // objc_assign_ivar
+ ASSIGNTEST(foo->dictArray[0], IvarAssigns); // objc_assign_ivar
+ ASSIGNTEST(foo->array[0], IvarAssigns); // objc_assign_ivar
+ ASSIGNTEST(foo->nsobject, IvarAssigns); // objc_assign_ivar
+ ASSIGNTEST(foo->stringArray[0], IvarAssigns); // objc_assign_ivar
+ ASSIGNTEST(foo->inner.element, IvarAssigns); // objc_assign_ivar
+ ASSIGNTEST(foo->inner.elementArray[0], IvarAssigns); // objc_assign_ivar
+ ASSIGNTEST(foo->inner.cfElement, IvarAssigns); // objc_assign_ivar
+ ASSIGNTEST(foo->inner.cfElementArray[0], IvarAssigns); // objc_assign_ivar
+ int counter=1;
+ ASSIGNTEST(foo->obj[5], IvarAssigns); // objc_assign_ivar
+ ASSIGNTEST(foo->obj[++counter], IvarAssigns); // objc_assign_ivar
+ foo->idx[++counter] = 15;
+ ASSIGNTEST(foo->obj[foo->idx[2]], IvarAssigns); // objc_assign_ivar
+}
diff --git a/test/CodeGenObjC/objc-gc-aggr-assign.m b/test/CodeGenObjC/objc-gc-aggr-assign.m
new file mode 100644
index 0000000..96a9fdf
--- /dev/null
+++ b/test/CodeGenObjC/objc-gc-aggr-assign.m
@@ -0,0 +1,46 @@
+// RUN: clang-cc -fnext-runtime -fobjc-gc -emit-llvm -o %t %s &&
+// RUN: grep objc_memmove_collectable %t | grep call | count 3
+
+static int count;
+
+typedef struct S {
+ int ii;
+} SS;
+
+struct type_s {
+ SS may_recurse;
+ id id_val;
+};
+
+@interface NamedObject
+{
+ struct type_s type_s_ivar;
+}
+- (void) setSome : (struct type_s) arg;
+- (struct type_s) getSome;
+@property(assign) struct type_s aggre_prop;
+@end
+
+@implementation NamedObject
+- (void) setSome : (struct type_s) arg
+ {
+ type_s_ivar = arg;
+ }
+- (struct type_s) getSome
+ {
+ return type_s_ivar;
+ }
+@synthesize aggre_prop = type_s_ivar;
+@end
+
+struct type_s some = {{1234}, (id)0};
+
+struct type_s get(void)
+{
+ return some;
+}
+
+void f(const struct type_s *in, struct type_s *out) {
+ *out = *in;
+}
+
diff --git a/test/CodeGenObjC/objc-read-weak-byref.m b/test/CodeGenObjC/objc-read-weak-byref.m
new file mode 100644
index 0000000..7c297be
--- /dev/null
+++ b/test/CodeGenObjC/objc-read-weak-byref.m
@@ -0,0 +1,26 @@
+// RUN: clang-cc -fblocks -fobjc-gc -triple x86_64-apple-darwin -S %s -o %t-64.s &&
+// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s &&
+// RUN: clang-cc -fblocks -fobjc-gc -triple i386-apple-darwin -S %s -o %t-32.s &&
+// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s &&
+// RUN: true
+
+@interface NSObject
+- copy;
+@end
+
+int main() {
+ NSObject *object = 0;
+ __weak __block NSObject* weak_object = object;
+ void (^callback) (void) = [^{
+ if (weak_object)
+ [weak_object copy];
+ } copy];
+ callback();
+ return 0;
+}
+
+// CHECK-LP64: call _objc_read_weak
+// CHECK-LP64: call _objc_read_weak
+
+// CHECK-LP32: call L_objc_read_weak
+// CHECK-LP32: call L_objc_read_weak
diff --git a/test/CodeGenObjC/objc2-assign-global.m b/test/CodeGenObjC/objc2-assign-global.m
index ae40761..9b6b415 100644
--- a/test/CodeGenObjC/objc2-assign-global.m
+++ b/test/CodeGenObjC/objc2-assign-global.m
@@ -1,8 +1,81 @@
-// RUN: clang-cc -fnext-runtime -fobjc-gc -emit-llvm -o %t %s &&
-// RUN: grep -F '@objc_assign_global' %t | count 2 &&
+// RUN: clang-cc -triple x86_64-apple-darwin10 -fnext-runtime -fobjc-gc -emit-llvm -o %t %s &&
+// RUN: grep -F '@objc_assign_global' %t | count 26 &&
// RUN: true
-id a;
+
+@class NSObject;
+typedef const struct __CFDictionary * CFDictionaryRef;
+typedef struct {
+ id element;
+ id elementArray[10];
+ __strong CFDictionaryRef cfElement;
+ __strong CFDictionaryRef cfElementArray[10];
+} struct_with_ids_t;
+
+
+// assignments to these should generate objc_assign_global
+@interface A
+@end
+
+typedef struct s0 {
+ A *a[4];
+} T;
+
+T g0;
+
+extern id FileExternID;
+static id FileStaticID;
+id GlobalId;
+id GlobalArray[20];
+NSObject *GlobalObject;
+NSObject *GlobalObjectArray[20];
+__strong CFDictionaryRef Gdict;
+__strong CFDictionaryRef Gdictarray[10];
+struct_with_ids_t GlobalStruct;
+struct_with_ids_t GlobalStructArray[10];
+
+#define ASSIGNTEST(expr, global) expr = rhs
+void *rhs = 0;
+
int main() {
- a = 0;
-}
+ static id staticGlobalId;
+ static id staticGlobalArray[20];
+ static NSObject *staticGlobalObject;
+ static NSObject *staticGlobalObjectArray[20];
+ static __strong CFDictionaryRef staticGdict;
+ static __strong CFDictionaryRef staticGdictarray[10];
+ static struct_with_ids_t staticGlobalStruct;
+ static struct_with_ids_t staticGlobalStructArray[10];
+ extern id ExID;
+ id localID;
+
+ ASSIGNTEST(GlobalId, GlobalAssigns); // objc_assign_global
+ ASSIGNTEST(GlobalArray[0], GlobalAssigns); // objc_assign_global
+ ASSIGNTEST(GlobalObject, GlobalAssigns); // objc_assign_global
+ ASSIGNTEST(GlobalObjectArray[0], GlobalAssigns); // objc_assign_global
+ ASSIGNTEST(Gdict, GlobalAssigns); // objc_assign_global
+ ASSIGNTEST(Gdictarray[1], GlobalAssigns); // objc_assign_global
+
+ ASSIGNTEST(GlobalStruct.element, GlobalAssigns); // objc_assign_global
+ ASSIGNTEST(GlobalStruct.elementArray[0], GlobalAssigns); // objc_assign_global
+ ASSIGNTEST(GlobalStruct.cfElement, GlobalAssigns); // objc_assign_global
+ ASSIGNTEST(GlobalStruct.cfElementArray[0], GlobalAssigns); // objc_assign_global
+ ASSIGNTEST(staticGlobalId, GlobalAssigns); // objc_assign_global
+ ASSIGNTEST(staticGlobalArray[0], GlobalAssigns); // objc_assign_global
+ ASSIGNTEST(staticGlobalObject, GlobalAssigns); // objc_assign_global
+ ASSIGNTEST(staticGlobalObjectArray[0], GlobalAssigns); // objc_assign_global
+ ASSIGNTEST(staticGdict, GlobalAssigns); // objc_assign_global
+ ASSIGNTEST(staticGdictarray[1], GlobalAssigns); // objc_assign_global
+
+ ASSIGNTEST(staticGlobalStruct.element, GlobalAssigns); // objc_assign_global
+ ASSIGNTEST(staticGlobalStruct.elementArray[0], GlobalAssigns); // objc_assign_global
+ ASSIGNTEST(staticGlobalStruct.cfElement, GlobalAssigns); // objc_assign_global
+ ASSIGNTEST(staticGlobalStruct.cfElementArray[0], GlobalAssigns); // objc_assign_global
+
+ ExID = 0;
+ localID = 0;
+ FileStaticID = 0;
+ FileExternID=0;
+ g0.a[0] = 0;
+ ((T*) &g0)->a[0] = 0;
+}
diff --git a/test/CodeGenObjC/objc2-ivar-assign.m b/test/CodeGenObjC/objc2-ivar-assign.m
new file mode 100644
index 0000000..cfdf87f2
--- /dev/null
+++ b/test/CodeGenObjC/objc2-ivar-assign.m
@@ -0,0 +1,41 @@
+// RUN: clang-cc -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s &&
+// RUN: grep objc_assign_ivar %t | count 6 &&
+// RUN: true
+
+@interface I @end
+
+typedef I TI;
+typedef I* TPI;
+
+typedef id ID;
+
+@interface MyClass {
+}
+
+@property id property;
+@property I* propertyI;
+
+@property TI* propertyTI;
+
+@property TPI propertyTPI;
+
+@property ID propertyID;
+@end
+
+@implementation MyClass
+ @synthesize property=_property;
+ @synthesize propertyI;
+ @synthesize propertyTI=_propertyTI;
+ @synthesize propertyTPI=_propertyTPI;
+ @synthesize propertyID = _propertyID;
+@end
+
+int main () {
+ MyClass *myObj;
+ myObj.property = 0;
+ myObj.propertyI = 0;
+ myObj.propertyTI = 0;
+ myObj.propertyTPI = 0;
+ myObj.propertyID = 0;
+ return 0;
+}
diff --git a/test/CodeGenObjC/objc2-new-gc-api-strongcast.m b/test/CodeGenObjC/objc2-new-gc-api-strongcast.m
new file mode 100644
index 0000000..6a1aea6
--- /dev/null
+++ b/test/CodeGenObjC/objc2-new-gc-api-strongcast.m
@@ -0,0 +1,26 @@
+// RUN: clang-cc -triple x86_64-apple-darwin10 -fblocks -fnext-runtime -fobjc-gc -emit-llvm -o %t %s &&
+// RUN: grep -F '@objc_assign_strongCast' %t | count 4 &&
+// RUN: true
+
+@interface DSATextSearch @end
+
+DSATextSearch **_uniqueIdToIdentifierArray = ((void *)0);
+void foo (int _nextId)
+{
+ _uniqueIdToIdentifierArray[_nextId] = 0; // objc_assign_strongCast
+}
+
+typedef struct {
+ unsigned long state;
+ id *itemsPtr;
+ void (^bp)();
+ unsigned long *mutationsPtr;
+ unsigned long extra[5];
+} NSFastEnumerationState;
+
+void foo1 (NSFastEnumerationState * state)
+{
+ state->itemsPtr = 0;
+ state->bp = ^{};
+}
+
diff --git a/test/CodeGenObjC/objc2-weak-assign.m b/test/CodeGenObjC/objc2-weak-assign.m
index a3740b2..635ca38 100644
--- a/test/CodeGenObjC/objc2-weak-assign.m
+++ b/test/CodeGenObjC/objc2-weak-assign.m
@@ -9,6 +9,10 @@ __weak id* a1[20];
id* __weak a2[30];
id** __weak a3[40];
+void foo (__weak id *param) {
+ *param = 0;
+}
+
int main()
{
*x = 0;
diff --git a/test/CodeGenObjC/objc2-weak-ivar-debug.m b/test/CodeGenObjC/objc2-weak-ivar-debug.m
new file mode 100644
index 0000000..24a7757
--- /dev/null
+++ b/test/CodeGenObjC/objc2-weak-ivar-debug.m
@@ -0,0 +1,15 @@
+// RUN: clang-cc -triple x86_64-apple-darwin9 -fobjc-gc -g -emit-llvm -o - %s &&
+// RUN: clang-cc -triple i386-apple-darwin9 -fobjc-gc -g -emit-llvm -o - %s
+
+// rdar://7252252
+@interface Loop {
+@public
+ __weak Loop *_loop;
+}
+@end
+
+@implementation Loop @end
+
+void loop(Loop *L) {
+ L->_loop = 0;
+}
diff --git a/test/CodeGenObjC/objc2-write-barrier-2.m b/test/CodeGenObjC/objc2-write-barrier-2.m
new file mode 100644
index 0000000..c47224f
--- /dev/null
+++ b/test/CodeGenObjC/objc2-write-barrier-2.m
@@ -0,0 +1,80 @@
+// RUN: clang-cc -triple x86_64-apple-darwin10 -fnext-runtime -fobjc-gc -emit-llvm -o %t %s &&
+// RUN: grep -F '@objc_assign_global' %t | count 7 &&
+// RUN: grep -F '@objc_assign_ivar' %t | count 5 &&
+// RUN: grep -F '@objc_assign_strongCast' %t | count 8 &&
+// RUN: true
+
+extern id **somefunc(void);
+extern id *somefunc2(void);
+
+
+// Globals
+
+id W, *X, **Y;
+
+void func(id a, id *b, id **c) {
+ static id w, *x, **y;
+ W = a;
+ w = a;
+ X = b;
+ x = b;
+ Y = c;
+ y = c;
+}
+
+// Instances
+
+@interface something {
+ id w, *x, **y;
+}
+@end
+
+@implementation something
+- (void)amethod {
+ id badIdea = *somefunc2();
+ w = badIdea;
+ x = &badIdea;
+ y = &x;
+}
+@end
+
+typedef struct {
+ int junk;
+ id alfred;
+} AStruct;
+
+void funct2(AStruct *aptr) {
+ id **ppptr = somefunc();
+ aptr->alfred = 0;
+ **ppptr = aptr->alfred;
+ *ppptr = somefunc2();
+}
+
+typedef const struct __CFString * CFStringRef;
+@interface DSATextSearch {
+__strong CFStringRef *_documentNames;
+ struct {
+ id *innerNames;
+ struct {
+ id *nestedDeeperNames;
+ struct I {
+ id *is1;
+ id is2[5];
+ } arrI [3];
+ } inner_most;
+ } inner;
+
+}
+- filter;
+@end
+@implementation DSATextSearch
+- filter {
+ int filteredPos = 0;
+ _documentNames[filteredPos] = 0; // storing into an element of array ivar. objc_assign_strongCast is needed.
+ inner.innerNames[filteredPos] = 0;
+ inner.inner_most.nestedDeeperNames[filteredPos] = 0;
+ inner.inner_most.arrI[3].is1[5] = 0;
+ inner.inner_most.arrI[3].is2[5] = 0;
+}
+@end
+
diff --git a/test/CodeGenObjC/objc2-write-barrier-3.m b/test/CodeGenObjC/objc2-write-barrier-3.m
new file mode 100644
index 0000000..2fb416b
--- /dev/null
+++ b/test/CodeGenObjC/objc2-write-barrier-3.m
@@ -0,0 +1,47 @@
+// RUN: clang-cc -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s &&
+// RUN: grep objc_assign_ivar %t | count 3 &&
+// RUN: grep objc_assign_strongCast %t | count 6 &&
+// RUN: true
+
+struct Slice {
+ void *__strong * items;
+};
+
+typedef struct Slice Slice;
+
+@interface ISlice {
+@public
+ void *__strong * IvarItem;
+}
+@end
+
+typedef void (^observer_block_t)(id object);
+@interface Observer {
+@public
+ observer_block_t block;
+}
+@end
+
+
+void foo (int i) {
+ // storing into an array of strong pointer types.
+ void *__strong* items;
+ items[i] = 0;
+
+ // storing indirectly into an array of strong pointer types.
+ void *__strong* *vitems;
+ *vitems[i] = 0;
+
+ Slice *slice;
+ slice->items = 0;
+ // storing into a struct element of an array of strong pointer types.
+ slice->items[i] = 0;
+
+ ISlice *islice;
+ islice->IvarItem = 0;
+ // Storing into an ivar of an array of strong pointer types.
+ islice->IvarItem[i] = (void*)0;
+
+ Observer *observer;
+ observer->block = 0;
+}
diff --git a/test/CodeGenObjC/objc2-write-barrier-4.m b/test/CodeGenObjC/objc2-write-barrier-4.m
new file mode 100644
index 0000000..f96a233
--- /dev/null
+++ b/test/CodeGenObjC/objc2-write-barrier-4.m
@@ -0,0 +1,28 @@
+// RUN: clang-cc -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s &&
+// RUN: grep objc_assign_global %t | count 3 &&
+// RUN: grep objc_assign_strongCast %t | count 2 &&
+// 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-write-barrier-5.m b/test/CodeGenObjC/objc2-write-barrier-5.m
new file mode 100644
index 0000000..5b8f02c
--- /dev/null
+++ b/test/CodeGenObjC/objc2-write-barrier-5.m
@@ -0,0 +1,27 @@
+// RUN: clang-cc -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s &&
+// RUN: grep objc_assign_ivar %t | count 0 &&
+// RUN: grep objc_assign_strongCast %t | count 5 &&
+// RUN: true
+
+@interface TestUnarchiver
+{
+ void *allUnarchivedObjects;
+}
+@end
+
+@implementation TestUnarchiver
+
+struct unarchive_list {
+ int ifield;
+ id *list;
+};
+
+- (id)init {
+ (*((struct unarchive_list *)allUnarchivedObjects)).list = 0;
+ ((struct unarchive_list *)allUnarchivedObjects)->list = 0;
+ (**((struct unarchive_list **)allUnarchivedObjects)).list = 0;
+ (*((struct unarchive_list **)allUnarchivedObjects))->list = 0;
+ return 0;
+}
+
+@end
diff --git a/test/CodeGenObjC/objc2-write-barrier.m b/test/CodeGenObjC/objc2-write-barrier.m
new file mode 100644
index 0000000..53fa10a
--- /dev/null
+++ b/test/CodeGenObjC/objc2-write-barrier.m
@@ -0,0 +1,114 @@
+// RUN: clang-cc -triple x86_64-apple-darwin10 -fnext-runtime -fobjc-gc -emit-llvm -o %t %s &&
+// RUN: grep -F '@objc_assign_global' %t | count 21 &&
+// RUN: grep -F '@objc_assign_ivar' %t | count 11 &&
+// RUN: true
+
+
+typedef const struct __CFDictionary * CFDictionaryRef;
+
+// callouts to these are generated with cc -fobjc-gc
+
+int GlobalAssigns;
+int IvarAssigns;
+int StrongCastAssigns;
+
+
+// The test case elements;
+@class NSObject;
+@class NSString;
+
+typedef struct {
+ id element;
+ id elementArray[10];
+ __strong CFDictionaryRef cfElement;
+ __strong CFDictionaryRef cfElementArray[10];
+} struct_with_ids_t;
+
+@interface Foo {
+@public
+// assignments to any/all of these fields should generate objc_assign_ivar
+ __strong CFDictionaryRef dict;
+ __strong CFDictionaryRef dictArray[3];
+ id ivar;
+ id array[10];
+ NSObject *nsobject;
+ NSString *stringArray[10];
+ struct_with_ids_t inner;
+}
+
+@end
+
+// assignments to these should generate objc_assign_global
+id GlobalId;
+id GlobalArray[20];
+NSObject *GlobalObject;
+NSObject *GlobalObjectArray[20];
+__strong CFDictionaryRef Gdict;
+__strong CFDictionaryRef Gdictarray[10];
+struct_with_ids_t GlobalStruct;
+struct_with_ids_t GlobalStructArray[10];
+
+
+// The test cases
+void *rhs = 0;
+
+#define ASSIGNTEST(expr, global) expr = rhs
+
+int testGlobals() {
+ // Everything in this function generates assign_global intercepts
+ int counter = 0;
+
+ static id staticGlobalId;
+ static id staticGlobalArray[20];
+ static NSObject *staticGlobalObject;
+ static NSObject *staticGlobalObjectArray[20];
+ static __strong CFDictionaryRef staticGdict;
+ static __strong CFDictionaryRef staticGdictarray[10];
+ static struct_with_ids_t staticGlobalStruct;
+ static struct_with_ids_t staticGlobalStructArray[10];
+
+ ASSIGNTEST(GlobalId, GlobalAssigns); // objc_assign_global
+ ASSIGNTEST(GlobalArray[0], GlobalAssigns); // objc_assign_global
+ ASSIGNTEST(GlobalObject, GlobalAssigns); // objc_assign_global
+ ASSIGNTEST(GlobalObjectArray[0], GlobalAssigns); // objc_assign_global
+ ASSIGNTEST(Gdict, GlobalAssigns); // objc_assign_global
+ ASSIGNTEST(Gdictarray[1], GlobalAssigns); // objc_assign_global
+
+ ASSIGNTEST(GlobalStruct.element, GlobalAssigns); // objc_assign_global
+ ASSIGNTEST(GlobalStruct.elementArray[0], GlobalAssigns); // objc_assign_global
+ ASSIGNTEST(GlobalStruct.cfElement, GlobalAssigns); // objc_assign_global
+ ASSIGNTEST(GlobalStruct.cfElementArray[0], GlobalAssigns); // objc_assign_global
+
+ ASSIGNTEST(staticGlobalId, GlobalAssigns); // objc_assign_global
+ ASSIGNTEST(staticGlobalArray[0], GlobalAssigns); // objc_assign_global
+ ASSIGNTEST(staticGlobalObject, GlobalAssigns); // objc_assign_global
+ ASSIGNTEST(staticGlobalObjectArray[0], GlobalAssigns); // objc_assign_global
+ ASSIGNTEST(staticGdict, GlobalAssigns); // objc_assign_global
+ ASSIGNTEST(staticGdictarray[1], GlobalAssigns); // objc_assign_global
+
+ ASSIGNTEST(staticGlobalStruct.element, GlobalAssigns); // objc_assign_global
+ ASSIGNTEST(staticGlobalStruct.elementArray[0], GlobalAssigns); // objc_assign_global
+ ASSIGNTEST(staticGlobalStruct.cfElement, GlobalAssigns); // objc_assign_global
+ ASSIGNTEST(staticGlobalStruct.cfElementArray[0], GlobalAssigns); // objc_assign_global
+
+ return counter;
+}
+
+
+int testIvars() {
+ Foo *foo;
+ int counter = 0;
+
+ ASSIGNTEST(foo->ivar, IvarAssigns); // objc_assign_ivar
+ ASSIGNTEST(foo->dict, IvarAssigns); // objc_assign_ivar
+ ASSIGNTEST(foo->dictArray[0], IvarAssigns); // objc_assign_ivar
+ ASSIGNTEST(foo->array[0], IvarAssigns); // objc_assign_ivar
+ ASSIGNTEST(foo->nsobject, IvarAssigns); // objc_assign_ivar
+ ASSIGNTEST(foo->stringArray[0], IvarAssigns); // objc_assign_ivar
+ ASSIGNTEST(foo->inner.element, IvarAssigns); // objc_assign_ivar
+ ASSIGNTEST(foo->inner.elementArray[0], IvarAssigns); // objc_assign_ivar
+ ASSIGNTEST(foo->inner.cfElement, IvarAssigns); // objc_assign_ivar
+ ASSIGNTEST(foo->inner.cfElementArray[0], IvarAssigns); // objc_assign_ivar
+
+ return counter;
+}
diff --git a/test/CodeGenObjC/object-incr-decr-1.m b/test/CodeGenObjC/object-incr-decr-1.m
new file mode 100644
index 0000000..53311f7
--- /dev/null
+++ b/test/CodeGenObjC/object-incr-decr-1.m
@@ -0,0 +1,19 @@
+// RUN: clang-cc -triple i386-apple-darwin9 -fnext-runtime -emit-llvm %s -o %t
+
+@interface Foo
+{
+ double d1,d3,d4;
+}
+@end
+
+Foo* foo()
+{
+ Foo *f;
+
+ // Both of these crash clang nicely
+ ++f;
+ --f;
+ f--;
+ f++;
+ return f;
+}
diff --git a/test/CodeGenObjC/overloadable.m b/test/CodeGenObjC/overloadable.m
index 972dc4e..7e9cc3d 100644
--- a/test/CodeGenObjC/overloadable.m
+++ b/test/CodeGenObjC/overloadable.m
@@ -4,7 +4,7 @@
@class C;
// RUN: grep _Z1fP11objc_object %t | count 1 &&
-void __attribute__((overloadable)) f(C *c) { }
+void __attribute__((overloadable)) f(id c) { }
// RUN: grep _Z1fP1C %t | count 1
-void __attribute__((overloadable)) f(id c) { }
+void __attribute__((overloadable)) f(C *c) { }
diff --git a/test/CodeGenObjC/predefined-expr.m b/test/CodeGenObjC/predefined-expr.m
new file mode 100644
index 0000000..b27bb34
--- /dev/null
+++ b/test/CodeGenObjC/predefined-expr.m
@@ -0,0 +1,90 @@
+// RUN: clang-cc -triple i386-apple-darwin9 %s -emit-llvm -o - | FileCheck %s
+
+// CHECK: @"__func__.-[Foo instanceTest1]" = private constant [21 x i8] c"-[Foo instanceTest1]\00"
+// CHECK: @"__func__.-[Foo instanceTest2:]" = private constant [22 x i8] c"-[Foo instanceTest2:]\00"
+// CHECK: @"__func__.-[Foo instanceTest3:withB:]" = private constant [28 x i8] c"-[Foo instanceTest3:withB:]\00"
+// CHECK: @"__func__.-[Foo instanceTest4]" = private constant [21 x i8] c"-[Foo instanceTest4]\00"
+// CHECK: @"__func__.+[Foo classTest1]" = private constant [18 x i8] c"+[Foo classTest1]\00"
+// CHECK: @"__func__.+[Foo classTest2:]" = private constant [19 x i8] c"+[Foo classTest2:]\00"
+// CHECK: @"__func__.+[Foo classTest3:withB:]" = private constant [25 x i8] c"+[Foo classTest3:withB:]\00"
+// CHECK: @"__func__.+[Foo classTest4]" = private constant [18 x i8] c"+[Foo classTest4]\00"
+// CHECK: @"__func__.-[Foo(Category) instanceTestWithCategory]" = private constant [42 x i8] c"-[Foo(Category) instanceTestWithCategory]\00"
+// CHECK: @"__func__.+[Foo(Category) classTestWithCategory]" = private constant [39 x i8] c"+[Foo(Category) classTestWithCategory]\00"
+
+int printf(const char * _Format, ...);
+
+@interface Foo
+@end
+
+@implementation Foo
+
+- (void)instanceTest1 {
+ printf("__func__: %s\n", __func__);
+ printf("__FUNCTION__: %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__: %s\n\n", __PRETTY_FUNCTION__);
+}
+
+- (void)instanceTest2:(int)i {
+ printf("__func__: %s\n", __func__);
+ printf("__FUNCTION__: %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__: %s\n\n", __PRETTY_FUNCTION__);
+}
+
+- (void)instanceTest3:(int)a withB:(double)b {
+ printf("__func__: %s\n", __func__);
+ printf("__FUNCTION__: %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__: %s\n\n", __PRETTY_FUNCTION__);
+}
+
+- (int)instanceTest4 {
+ printf("__func__: %s\n", __func__);
+ printf("__FUNCTION__: %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__: %s\n\n", __PRETTY_FUNCTION__);
+ return 0;
+}
+
++ (void)classTest1 {
+ printf("__func__: %s\n", __func__);
+ printf("__FUNCTION__: %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__: %s\n\n", __PRETTY_FUNCTION__);
+}
+
++ (void)classTest2:(int)i {
+ printf("__func__: %s\n", __func__);
+ printf("__FUNCTION__: %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__: %s\n\n", __PRETTY_FUNCTION__);
+}
+
++ (void)classTest3:(int)a withB:(double)b {
+ printf("__func__: %s\n", __func__);
+ printf("__FUNCTION__: %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__: %s\n\n", __PRETTY_FUNCTION__);
+}
+
++ (int)classTest4 {
+ printf("__func__: %s\n", __func__);
+ printf("__FUNCTION__: %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__: %s\n\n", __PRETTY_FUNCTION__);
+ return 0;
+}
+
+@end
+
+@interface Foo (Category)
+@end
+
+@implementation Foo (Category)
+
+- (void)instanceTestWithCategory {
+ printf("__func__: %s\n", __func__);
+ printf("__FUNCTION__: %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__: %s\n\n", __PRETTY_FUNCTION__);
+}
+
++ (void)classTestWithCategory {
+ printf("__func__: %s\n", __func__);
+ printf("__FUNCTION__: %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__: %s\n\n", __PRETTY_FUNCTION__);
+}
+
+@end
diff --git a/test/CodeGenObjC/property-agrr-getter.m b/test/CodeGenObjC/property-agrr-getter.m
index 0a1df12..4620579 100644
--- a/test/CodeGenObjC/property-agrr-getter.m
+++ b/test/CodeGenObjC/property-agrr-getter.m
@@ -9,9 +9,30 @@ typedef struct {
@end
@implementation A
--(s0) f0{}
+-(s0) f0{ while (1) {} }
- (unsigned) bar {
return self.f0.f0;
}
@end
+
+typedef struct _NSSize {
+ float width;
+ float height;
+} NSSize;
+
+
+@interface AnObject
+{
+ NSSize size;
+}
+
+@property NSSize size;
+
+@end
+
+float f ()
+{
+ AnObject* obj;
+ return (obj.size).width;
+}
diff --git a/test/CodeGenObjC/property-setter-attr.m b/test/CodeGenObjC/property-setter-attr.m
index 3903924..5f0edf8 100644
--- a/test/CodeGenObjC/property-setter-attr.m
+++ b/test/CodeGenObjC/property-setter-attr.m
@@ -1,4 +1,4 @@
-// RUN: clang-cc -emit-llvm -triple=i686-apple-darwin8 -o %t %s
+// RUN: clang-cc -emit-llvm -triple=i686-apple-darwin8 -o %t %s &&
// RUN: grep -e "SiSetOtherThings:" %t
@interface A
diff --git a/test/CodeGenObjC/protocol-in-extended-class.m b/test/CodeGenObjC/protocol-in-extended-class.m
new file mode 100644
index 0000000..87bda46
--- /dev/null
+++ b/test/CodeGenObjC/protocol-in-extended-class.m
@@ -0,0 +1,29 @@
+// RUN: clang-cc -triple x86_64-apple-darwin10 -S %s -o %t-64.s &&
+// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s &&
+// RUN: clang-cc -triple i386-apple-darwin -S %s -o %t-32.s &&
+// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s &&
+// RUN: true
+
+@protocol MyProtocol
+@end
+
+@protocol ExtendedProtocol
+@end
+
+@interface ItDoesntWork<MyProtocol> {
+}
+-(void) Meth;
+@end
+
+@interface ItDoesntWork() <MyProtocol, ExtendedProtocol>
+@end
+
+@implementation ItDoesntWork
+-(void) Meth {
+ ItDoesntWork <MyProtocol, ExtendedProtocol> *p = 0;
+ }
+@end
+
+// CHECK-LP64: l_OBJC_PROTOCOL_$_ExtendedProtocol:
+
+// CHECK-LP32: L_OBJC_PROTOCOL_ExtendedProtocol:
diff --git a/test/CodeGenObjC/protocols-lazy.m b/test/CodeGenObjC/protocols-lazy.m
index e91cc0a..a8f7902 100644
--- a/test/CodeGenObjC/protocols-lazy.m
+++ b/test/CodeGenObjC/protocols-lazy.m
@@ -26,7 +26,7 @@ void f1() { id x = @protocol(P3); }
// RUN: grep OBJC_PROTOCOL_INSTANCE_METHODS_P4 %t | count 3 &&
@protocol P4 -im1; @end
@interface I0<P4> @end
-@implementation I0 -im1 {}; @end
+@implementation I0 -im1 { return 0; }; @end
// Definition following forward reference.
// RUN: grep OBJC_PROTOCOL_P5 %t | count 3 &&
@@ -42,7 +42,7 @@ void f2() { id x = @protocol(P5); } // This generates a forward
// RUN: grep OBJC_PROTOCOL_INSTANCE_METHODS_P6 %t | count 3 &&
@protocol P6 -im1; @end
@interface I1<P6> @end
-@implementation I1 -im1 {}; @end
+@implementation I1 -im1 { return 0; }; @end
void f3() { id x = @protocol(P6); }
// RUN: true
diff --git a/test/CodeGenObjC/protocols.m b/test/CodeGenObjC/protocols.m
new file mode 100644
index 0000000..4cfb83b
--- /dev/null
+++ b/test/CodeGenObjC/protocols.m
@@ -0,0 +1,50 @@
+// RUN: clang-cc -fnext-runtime -emit-llvm %s -o %t
+
+void p(const char*, ...);
+
+@interface Root
+-(int) conformsTo: (id) x;
+@end
+
+@protocol P0;
+
+@protocol P1
++(void) classMethodReq0;
+-(void) methodReq0;
+@optional
++(void) classMethodOpt1;
+-(void) methodOpt1;
+@required
++(void) classMethodReq2;
+-(void) methodReq2;
+@end
+
+@protocol P2
+//@property(readwrite) int x;
+@end
+
+@protocol P3<P1, P2>
+-(id <P1>) print0;
+-(void) print1;
+@end
+
+void foo(const id a) {
+ void *p = @protocol(P3);
+}
+
+int main() {
+ Protocol *P0 = @protocol(P0);
+ Protocol *P1 = @protocol(P1);
+ Protocol *P2 = @protocol(P2);
+ Protocol *P3 = @protocol(P3);
+
+#define Pbool(X) p(#X ": %s\n", X ? "yes" : "no");
+ Pbool([P0 conformsTo: P1]);
+ Pbool([P1 conformsTo: P0]);
+ Pbool([P1 conformsTo: P2]);
+ Pbool([P2 conformsTo: P1]);
+ Pbool([P3 conformsTo: P1]);
+ Pbool([P1 conformsTo: P3]);
+
+ return 0;
+}
diff --git a/test/CodeGenObjC/variadic-sends.m b/test/CodeGenObjC/variadic-sends.m
new file mode 100644
index 0000000..8697fee
--- /dev/null
+++ b/test/CodeGenObjC/variadic-sends.m
@@ -0,0 +1,41 @@
+// RUN: clang-cc -triple i386-unknown-unknown -fnext-runtime -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-X86-32 %s &&
+// RUN: clang-cc -triple x86_64-unknown-unknown -fnext-runtime -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-X86-64 %s
+
+@interface A
+-(void) im0;
+-(void) im1: (int) x;
+-(void) im2: (int) x, ...;
+@end
+
+void f0(A *a) {
+ // CHECK-X86-32: call void bitcast (i8* (i8*, %struct.objc_selector*, ...)* @objc_msgSend to void (i8*, %struct.objc_selector*)*)
+ // CHECK-X86-64: call void bitcast (i8* (i8*, %struct.objc_selector*, ...)* @objc_msgSend to void (i8*, %struct.objc_selector*)*)
+ [a im0];
+}
+
+void f1(A *a) {
+ // CHECK-X86-32: call void bitcast (i8* (i8*, %struct.objc_selector*, ...)* @objc_msgSend to void (i8*, %struct.objc_selector*, i32)*)
+ // CHECK-X86-64: call void bitcast (i8* (i8*, %struct.objc_selector*, ...)* @objc_msgSend to void (i8*, %struct.objc_selector*, i32)*)
+ [a im1: 1];
+}
+
+void f2(A *a) {
+ // CHECK-X86-32: call void (i8*, %struct.objc_selector*, i32, i32, ...)* bitcast (i8* (i8*, %struct.objc_selector*, ...)* @objc_msgSend to void (i8*, %struct.objc_selector*, i32, i32, ...)*)
+ // CHECK-X86-64: call void (i8*, %struct.objc_selector*, i32, i32, ...)* bitcast (i8* (i8*, %struct.objc_selector*, ...)* @objc_msgSend to void (i8*, %struct.objc_selector*, i32, i32, ...)*)
+ [a im2: 1, 2];
+}
+
+@interface B : A @end
+@implementation B : A
+-(void) foo {
+ // CHECK-X86-32: call void bitcast (i8* (%struct._objc_super*, %struct.objc_selector*, ...)* @objc_msgSendSuper to void (%struct._objc_super*, %struct.objc_selector*, i32)*)
+ // CHECK-X86-64: call void bitcast (i8* (%struct._objc_super*, %struct.objc_selector*, ...)* @objc_msgSendSuper to void (%struct._objc_super*, %struct.objc_selector*, i32)*)
+ [super im1: 1];
+}
+-(void) bar {
+ // CHECK-X86-32: call void (%struct._objc_super*, %struct.objc_selector*, i32, i32, ...)* bitcast (i8* (%struct._objc_super*, %struct.objc_selector*, ...)* @objc_msgSendSuper to void (%struct._objc_super*, %struct.objc_selector*, i32, i32, ...)*)
+ // CHECK-X86-64: call void (%struct._objc_super*, %struct.objc_selector*, i32, i32, ...)* bitcast (i8* (%struct._objc_super*, %struct.objc_selector*, ...)* @objc_msgSendSuper to void (%struct._objc_super*, %struct.objc_selector*, i32, i32, ...)*)
+ [super im2: 1, 2];
+}
+
+@end
diff --git a/test/Coverage/targets.c b/test/Coverage/targets.c
index 5a547a5..5a87b4d 100644
--- a/test/Coverage/targets.c
+++ b/test/Coverage/targets.c
@@ -1,18 +1,19 @@
-// RUN: clang-cc -g -triple i686-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 armv6-unknown-unknown -emit-llvm -o %t %s &&
+// RUN: clang-cc -g -triple bfin-unknown-unknown -emit-llvm -o %t %s &&
+// RUN: clang-cc -g -triple i686-apple-darwin9 -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-unknown -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: clang-cc -g -triple powerpc-apple-darwin9 -emit-llvm -o %t %s &&
+// RUN: clang-cc -g -triple powerpc-unknown-unknown -emit-llvm -o %t %s &&
+// RUN: clang-cc -g -triple powerpc64-apple-darwin9 -emit-llvm -o %t %s &&
+// RUN: clang-cc -g -triple powerpc64-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 sparc-unknown-unknown -emit-llvm -o %t %s &&
+// RUN: clang-cc -g -triple x86_64-apple-darwin9 -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-unknown-unknown -emit-llvm -o %t %s &&
// RUN: true
diff --git a/test/Driver/arm-darwin-builtin.c b/test/Driver/arm-darwin-builtin.c
new file mode 100644
index 0000000..5da8074
--- /dev/null
+++ b/test/Driver/arm-darwin-builtin.c
@@ -0,0 +1,14 @@
+// FIXME: Disable pending PR4941.
+// RUX: clang -ccc-host-triple x86_64-apple-darwin9 -arch arm -### -fsyntax-only %s 2> %t &&
+// RUX: grep -- "-fno-builtin-strcat" %t &&
+// RUX: grep -- "-fno-builtin-strcpy" %t &&
+
+// FIXME: Disable pending PR4941.
+// RUX: clang -ccc-host-triple x86_64-apple-darwin9 -arch arm -### -fsyntax-only %s -fbuiltin-strcat -fbuiltin-strcpy 2> %t &&
+// RUX: not grep -- "-fno-builtin-strcat" %t &&
+// RUX: not grep -- "-fno-builtin-strcpy" %t &&
+
+// RUN: clang -ccc-no-clang -ccc-host-triple x86_64-apple-darwin9 -arch arm -### -fsyntax-only %s -fbuiltin-strcat -fbuiltin-strcpy 2> %t &&
+// RUN: not grep -- "-fno-builtin-strcat" %t &&
+// RUN: not grep -- "-fno-builtin-strcpy" %t
+
diff --git a/test/Driver/ast.c b/test/Driver/ast.c
new file mode 100644
index 0000000..814b597
--- /dev/null
+++ b/test/Driver/ast.c
@@ -0,0 +1,26 @@
+// RUN: clang -ccc-host-triple i386-unknown-unknown -ccc-print-phases -emit-ast %s 2> %t &&
+// RUN: echo 'END' >> %t &&
+// RUN: FileCheck -check-prefix EMIT-AST-PHASES -input-file %t %s &&
+
+// EMIT-AST-PHASES: 0: input,
+// EMIT-AST-PHASES: , c
+// EMIT-AST-PHASES: 1: preprocessor, {0}, cpp-output
+// EMIT-AST-PHASES: 2: compiler, {1}, ast
+// EMIT-AST-PHASES-NOT: 3:
+// EMIT-AST-PHASES: END
+
+// RUN: touch %t.ast &&
+// RUN: clang -ccc-host-triple i386-unknown-unknown -ccc-print-phases -c %t.ast 2> %t &&
+// RUN: echo 'END' >> %t &&
+// RUN: FileCheck -check-prefix COMPILE-AST-PHASES -input-file %t %s
+
+// COMPILE-AST-PHASES: 0: input,
+// COMPILE-AST-PHASES: , ast
+// COMPILE-AST-PHASES: 1: compiler, {0}, assembler
+// COMPILE-AST-PHASES: 2: assembler, {1}, object
+// COMPILE-AST-PHASES-NOT: 3:
+// COMPILE-AST-PHASES: END
+
+// FIXME: There is a problem with compiling AST's in that the input language is
+// not availabe for use by other tools (for example, to automatically add
+// -lstdc++). We may need -x [objective-]c++-ast and all that goodness. :(
diff --git a/test/Driver/bindings.c b/test/Driver/bindings.c
index 3cac22c..3937390 100644
--- a/test/Driver/bindings.c
+++ b/test/Driver/bindings.c
@@ -30,7 +30,7 @@
// 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: clang -ccc-host-triple i386-unknown-unknown -ccc-print-bindings -ccc-no-clang-cxx -fsyntax-only -x c++ %s 2> %t &&
// RUN: grep '"gcc::Compile", inputs: \[".*bindings.c"\], output: (nothing)' %t &&
// RUN: clang -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 &&
@@ -39,12 +39,12 @@
// 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: clang -ccc-host-triple i386-apple-darwin9 -ccc-print-bindings -ccc-clang-archs powerpc %s -S -arch ppc 2> %t &&
// RUN: grep '"clang", inputs: \[".*bindings.c"\], output: "bindings.s"' %t &&
// RUN: clang -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: clang -ccc-host-triple powerpc-unknown-unknown -ccc-print-bindings -ccc-clang-archs "i386" %s -S 2> %t &&
// RUN: grep '"gcc::Compile", inputs: \[".*bindings.c"\], output: "bindings.s"' %t &&
// Darwin bindings
diff --git a/test/Driver/clang-translation.c b/test/Driver/clang-translation.c
index ca60a8d..e0b9e3a 100644
--- a/test/Driver/clang-translation.c
+++ b/test/Driver/clang-translation.c
@@ -1,4 +1,4 @@
-// RUN: clang -ccc-host-triple i386-unknown-unknown -### -S -O0 -Os %s -o %t.s -fverbose-asm 2> %t.log
+// 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 &&
@@ -7,10 +7,10 @@
// 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 '"-o" .*clang-translation.*' %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: 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: 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/darwin-arm.c b/test/Driver/darwin-arm.c
new file mode 100644
index 0000000..8b4c23d5
--- /dev/null
+++ b/test/Driver/darwin-arm.c
@@ -0,0 +1,4 @@
+// RUN: clang -ccc-host-triple i386-apple-darwin9 -arch arm -print-search-dirs | FileCheck %s
+
+// Check that we look in the relative libexec directory.
+// CHECK: {{programs: =.*/../libexec:}}
diff --git a/test/Driver/darwin-as.c b/test/Driver/darwin-as.c
new file mode 100644
index 0000000..486dc2e
--- /dev/null
+++ b/test/Driver/darwin-as.c
@@ -0,0 +1,10 @@
+// RUN: clang -ccc-host-triple i386-apple-darwin10 -### -x assembler -c %s -static -dynamic 2>%t &&
+// RUN: FileCheck -check-prefix=STATIC_AND_DYNAMIC-32 --input-file %t %s &&
+
+// CHECK-STATIC_AND_DYNAMIC-32: as{{(.exe)?}}" "-arch" "i386" "-force_cpusubtype_ALL" "-static" "-o"
+
+// RUN: clang -ccc-host-triple x86_64-apple-darwin10 -### -x assembler -c %s -static 2>%t &&
+// RUN: FileCheck -check-prefix=STATIC-64 --input-file %t %s
+
+// CHECK-STATIC-64: as{{(.exe)?}}" "-arch" "x86_64" "-force_cpusubtype_ALL" "-o"
+
diff --git a/test/Driver/darwin-cc.c b/test/Driver/darwin-cc.c
index ac5d9a9..77193cd 100644
--- a/test/Driver/darwin-cc.c
+++ b/test/Driver/darwin-cc.c
@@ -1,4 +1,3 @@
-// RUN: unset MACOSX_DEPLOYMENT_TARGET &&
// 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 &&
diff --git a/test/Driver/darwin-ld.c b/test/Driver/darwin-ld.c
index 2e6fc57..d81605b 100644
--- a/test/Driver/darwin-ld.c
+++ b/test/Driver/darwin-ld.c
@@ -1,8 +1,7 @@
// Check that ld gets arch_multiple.
-// RUN: unset MACOSX_DEPLOYMENT_TARGET &&
// 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: 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 &&
@@ -33,8 +32,8 @@
//
// 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 &&
+// 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 -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" "-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 &&
diff --git a/test/Driver/default-toolchain.c b/test/Driver/default-toolchain.c
index 216394f..0e8a026 100644
--- a/test/Driver/default-toolchain.c
+++ b/test/Driver/default-toolchain.c
@@ -1,8 +1,8 @@
-// RUN: clang -ccc-host-triple i386-unknown-unknown -m64 -v 2> %t
+// RUN: clang -ccc-host-triple i386-unknown-unknown -m64 -v 2> %t &&
// RUN: grep 'Target: x86_64-unknown-unknown' %t &&
-// RUN: clang -ccc-host-triple i386-apple-darwin9 -arch ppc -m64 -v 2> %t
+// RUN: clang -ccc-host-triple i386-apple-darwin9 -arch ppc -m64 -v 2> %t &&
// RUN: grep 'Target: powerpc64-apple-darwin9' %t &&
-// RUN: clang -ccc-host-triple i386-apple-darwin9 -arch ppc64 -m32 -v 2> %t
+// RUN: clang -ccc-host-triple i386-apple-darwin9 -arch ppc64 -m32 -v 2> %t &&
// RUN: grep 'Target: powerpc-apple-darwin9' %t
diff --git a/test/Driver/dragonfly.c b/test/Driver/dragonfly.c
index 5d7b0b0..f0b09f7 100644
--- a/test/Driver/dragonfly.c
+++ b/test/Driver/dragonfly.c
@@ -1,6 +1,8 @@
// 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
+// RUN: FileCheck -input-file %t.log %s
+
+// CHECK: clang-cc{{.*}}" "-triple" "amd64-pc-dragonfly"
+// CHECK: as{{.*}}" "-o" "{{.*}}.o" "{{.*}}.s
+// CHECK: ld{{.*}}" "-dynamic-linker" "{{.*}}ld-elf.{{.*}}" "-o" "a.out" "{{.*}}crt1.o" "{{.*}}crti.o" "{{.*}}crtbegin.o" "{{.*}}.o" "-L{{.*}}/gcc{{.*}}" {{.*}} "-lc" "-lgcc" "{{.*}}crtend.o" "{{.*}}crtn.o"
+
diff --git a/test/Driver/freebsd.c b/test/Driver/freebsd.c
index 91258d9..d50c85b 100644
--- a/test/Driver/freebsd.c
+++ b/test/Driver/freebsd.c
@@ -1,7 +1,7 @@
-// RUN: clang -ccc-clang-archs "" -ccc-host-triple ppc64-pc-freebsd8 %s -### 2> %t.log &&
+// RUN: clang -ccc-clang-archs "" -ccc-host-triple powerpc64-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
+// RUN: FileCheck -input-file %t.log %s
+// CHECK: clang-cc{{.*}}" "-triple" "powerpc64-pc-freebsd8"
+// CHECK: as{{.*}}" "-o" "{{.*}}.o" "{{.*}}.s
+// CHECK: 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"
diff --git a/test/Driver/openbsd.c b/test/Driver/openbsd.c
index fd0d4fa..c73ef20 100644
--- a/test/Driver/openbsd.c
+++ b/test/Driver/openbsd.c
@@ -1,6 +1,6 @@
// RUN: clang -ccc-clang-archs "" -ccc-host-triple i686-pc-openbsd %s -### 2> %t.log &&
-// RUN: grep 'clang-cc" "-triple" "i386-pc-openbsd"' %t.log &&
-// RUN: grep 'as" "-o" ".*\.o" ".*\.s' %t.log &&
-// RUN: grep 'ld" "--eh-frame-hdr" "-dynamic-linker" ".*ld.so" "-o" "a\.out" ".*crt0.o" ".*crtbegin.o" ".*\.o" "-lc" ".*crtend.o"' %t.log &&
-// RUN: true
+// RUN: FileCheck -input-file %t.log %s
+// CHECK: clang-cc{{.*}}" "-triple" "i686-pc-openbsd"
+// CHECK: as{{.*}}" "-o" "{{.*}}.o" "{{.*}}.s
+// CHECK: ld{{.*}}" "-e" "__start" "--eh-frame-hdr" "-Bdynamic" "-dynamic-linker" "{{.*}}ld.so" "-o" "a.out" "{{.*}}crt0.o" "{{.*}}crtbegin.o" "{{.*}}.o" "-lgcc" "-lc" "-lgcc" "{{.*}}crtend.o"
diff --git a/test/Driver/pth.c b/test/Driver/pth.c
index 7480538..5c83aea 100644
--- a/test/Driver/pth.c
+++ b/test/Driver/pth.c
@@ -1,8 +1,12 @@
// 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: FileCheck -check-prefix CHECK1 -input-file %t.log %s &&
+
+// CHECK1: "{{.*}}/clang-cc{{.*}}" {{.*}} "-o" "{{.*}}.h.pth" "-x" "c-header" "{{.*}}pth.c"
// 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
+// RUN: FileCheck -check-prefix CHECK2 -input-file %t.log %s
+
+// CHECK2: "{{.*}}/clang-cc{{.*}}" {{.*}}"-include-pth" "{{.*}}.h.pth" {{.*}}"-x" "c" "{{.*}}pth.c"
diff --git a/test/Driver/qa_override.c b/test/Driver/qa_override.c
index 0ff578c..46e150c 100644
--- a/test/Driver/qa_override.c
+++ b/test/Driver/qa_override.c
@@ -1,4 +1,5 @@
-// 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: 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 '### ' %t | count 0 &&
// 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 &&
diff --git a/test/Driver/redzone.c b/test/Driver/redzone.c
index 8709e71..64729ac 100644
--- a/test/Driver/redzone.c
+++ b/test/Driver/redzone.c
@@ -1,6 +1,6 @@
-// RUN: clang -mno-red-zone %s -S -emit-llvm -o %t.log &&
-// RUN: grep 'noredzone' %t.log
-// RUN: clang -mred-zone %s -S -emit-llvm -o %t.log &&
+// RUN: clang -ccc-host-triple i386-unknown-unknown -mno-red-zone %s -S -emit-llvm -o %t.log &&
+// RUN: grep 'noredzone' %t.log &&
+// RUN: clang -ccc-host-triple i386-unknown-unknown -mred-zone %s -S -emit-llvm -o %t.log &&
// RUN: grep -v 'noredzone' %t.log
int foo() { return 42; }
diff --git a/test/Frontend/ast-codegen.c b/test/Frontend/ast-codegen.c
new file mode 100644
index 0000000..1fe74d4
--- /dev/null
+++ b/test/Frontend/ast-codegen.c
@@ -0,0 +1,12 @@
+// RUN: clang -emit-ast -o %t.ast %s &&
+// RUN: clang -emit-llvm -S -o - %t.ast | FileCheck %s
+
+// CHECK: module asm "foo"
+__asm__("foo");
+
+// CHECK: @g0 = common global i32 0, align 4
+int g0;
+
+// CHECK: define i32 @f0()
+int f0() {
+}
diff --git a/test/Frontend/ast-main.c b/test/Frontend/ast-main.c
new file mode 100644
index 0000000..7831406
--- /dev/null
+++ b/test/Frontend/ast-main.c
@@ -0,0 +1,8 @@
+// RUN: clang -emit-llvm -S -o %t1.ll -x c - < %s &&
+// RUN: clang -emit-ast -o %t.ast %s &&
+// RUN: clang -emit-llvm -S -o %t2.ll -x ast - < %t.ast &&
+// RUN: diff %t1.ll %t2.ll
+
+int main() {
+ return 0;
+}
diff --git a/test/Frontend/dependency-gen.c b/test/Frontend/dependency-gen.c
index 456ce94..4a1611a 100644
--- a/test/Frontend/dependency-gen.c
+++ b/test/Frontend/dependency-gen.c
@@ -1,6 +1,6 @@
// 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 '.*dependency-gen.*:' %t.d &&
// RUN: grep '/dev/null' %t.d &&
// RUN: clang -M -x c /dev/null -o %t.deps &&
diff --git a/test/Frontend/stdin.c b/test/Frontend/stdin.c
index 35fe45d..5b719b2 100644
--- a/test/Frontend/stdin.c
+++ b/test/Frontend/stdin.c
@@ -1,3 +1,3 @@
-// RUN: clang-cc -E - < /dev/null > %t
+// RUN: clang-cc -E - < /dev/null > %t &&
// RUN: grep '<built-in>' %t
diff --git a/test/Index/c-index-api-test.m b/test/Index/c-index-api-test.m
new file mode 100644
index 0000000..20d4d7b
--- /dev/null
+++ b/test/Index/c-index-api-test.m
@@ -0,0 +1,224 @@
+// RUN: clang-cc -triple x86_64-apple-darwin10 -emit-pch -x objective-c %s -o %t.ast &&
+// RUN: c-index-test %t.ast all | FileCheck %s
+
+// CHECK: <invalid loc>:0:0: TypedefDecl=__int128_t:0:0 [Context=c-index-api-test.m]
+// CHECK: <invalid loc>:0:0: TypedefDecl=__uint128_t:0:0 [Context=c-index-api-test.m]
+// CHECK: <invalid loc>:0:0: StructDecl=objc_selector:0:0 [Context=c-index-api-test.m]
+// CHECK: <invalid loc>:0:0: TypedefDecl=SEL:0:0 [Context=c-index-api-test.m]
+// CHECK: <invalid loc>:0:0: ObjCInterfaceDecl=Protocol:0:0 [Context=c-index-api-test.m]
+// CHECK: <invalid loc>:0:0: TypedefDecl=id:0:0 [Context=c-index-api-test.m]
+// CHECK: <invalid loc>:0:0: TypedefDecl=Class:0:0 [Context=c-index-api-test.m]
+// CHECK: <built-in>:79:16: StructDecl=__va_list_tag:79:16 [Context=c-index-api-test.m]
+// CHECK: <built-in>:79:42: FieldDecl=gp_offset:79:42 [Context=__va_list_tag]
+// CHECK: <built-in>:79:63: FieldDecl=fp_offset:79:63 [Context=__va_list_tag]
+// CHECK: <built-in>:79:81: FieldDecl=overflow_arg_area:79:81 [Context=__va_list_tag]
+// CHECK: <built-in>:79:107: FieldDecl=reg_save_area:79:107 [Context=__va_list_tag]
+// CHECK: <built-in>:79:123: TypedefDecl=__va_list_tag:79:123 [Context=c-index-api-test.m]
+// CHECK: <built-in>:79:159: TypedefDecl=__builtin_va_list:79:159 [Context=c-index-api-test.m]
+//
+
+@interface Foo
+{
+}
+
+- foo;
++ fooC;
+
+@end
+
+@interface Bar : Foo
+{
+}
+
+@end
+
+@interface Foo (FooCat)
+- (int) catMethodWithFloat:(float) fArg;
+- (float) floatMethod;
+@end
+
+@protocol Proto
+- pMethod;
+@end
+
+@protocol SubP <Proto>
+- spMethod;
+@end
+
+@interface Baz : Bar <SubP>
+{
+ int _anIVar;
+}
+
+- (Foo *) bazMethod;
+
+@end
+
+enum {
+ someEnum
+};
+
+// CHECK: c-index-api-test.m:20:12: ObjCInterfaceDecl=Foo:20:1 [Context=c-index-api-test.m]
+// CHECK: c-index-api-test.m:24:1: ObjCInstanceMethodDecl=foo:24:1 [Context=Foo]
+// CHECK: c-index-api-test.m:25:1: ObjCClassMethodDecl=fooC:25:1 [Context=Foo]
+// CHECK: c-index-api-test.m:29:12: ObjCInterfaceDecl=Bar:29:1 [Context=c-index-api-test.m]
+// CHECK: c-index-api-test.m:29:18: ObjCSuperClassRef=Foo:29:1 [Context=Bar]
+// CHECK: c-index-api-test.m:35:1: ObjCCategoryDecl=FooCat:35:1 [Context=c-index-api-test.m]
+// CHECK: c-index-api-test.m:20:1: ObjCClassRef=Foo:35:1 [Context=FooCat]
+// CHECK: c-index-api-test.m:36:1: ObjCInstanceMethodDecl=catMethodWithFloat::36:1 [Context=FooCat]
+// CHECK: c-index-api-test.m:37:1: ObjCInstanceMethodDecl=floatMethod:37:1 [Context=FooCat]
+// CHECK: c-index-api-test.m:40:1: ObjCProtocolDecl=Proto:40:1 [Context=c-index-api-test.m]
+// CHECK: c-index-api-test.m:41:1: ObjCInstanceMethodDecl=pMethod:41:1 [Context=Proto]
+// CHECK: c-index-api-test.m:44:1: ObjCProtocolDecl=SubP:44:1 [Context=c-index-api-test.m]
+// CHECK: c-index-api-test.m:40:1: ObjCProtocolRef=Proto:40:1 [Context=SubP]
+// CHECK: c-index-api-test.m:45:1: ObjCInstanceMethodDecl=spMethod:45:1 [Context=SubP]
+// CHECK: c-index-api-test.m:48:12: ObjCInterfaceDecl=Baz:48:1 [Context=c-index-api-test.m]
+// CHECK: c-index-api-test.m:48:18: ObjCSuperClassRef=Bar:48:1 [Context=Baz]
+// CHECK: c-index-api-test.m:44:1: ObjCProtocolRef=SubP:44:1 [Context=Baz]
+// CHECK: c-index-api-test.m:50:9: ObjCIvarDecl=_anIVar:50:9 [Context=Baz]
+// CHECK: c-index-api-test.m:53:1: ObjCInstanceMethodDecl=bazMethod:53:1 [Context=Baz]
+// CHECK: c-index-api-test.m:57:1: EnumDecl=:57:1 [Context=c-index-api-test.m]
+// CHECK: c-index-api-test.m:58:3: EnumConstantDecl=someEnum:58:3 [Context=]
+
+int main (int argc, const char * argv[]) {
+ Baz * bee;
+ id a = [bee foo];
+ id <SubP> c = [Foo fooC];
+ id <Proto> d;
+ d = c;
+ [d pMethod];
+ [bee catMethodWithFloat:[bee floatMethod]];
+ main(someEnum, (const char **)bee);
+}
+
+// CHECK: c-index-api-test.m:83:5: FunctionDefn=main [Context=c-index-api-test.m]
+// CHECK: c-index-api-test.m:83:15: ParmDecl=argc:83:15 [Context=main]
+// CHECK: c-index-api-test.m:83:34: ParmDecl=argv:83:34 [Context=main]
+// CHECK: c-index-api-test.m:84:8: VarDecl=bee:84:8 [Context=main]
+// CHECK: c-index-api-test.m:85:5: VarDecl=a:85:5 [Context=main]
+// CHECK: c-index-api-test.m:86:12: VarDecl=c:86:12 [Context=main]
+// CHECK: c-index-api-test.m:87:13: VarDecl=d:87:13 [Context=main]
+// CHECK: c-index-api-test.m:84:2: ObjCClassRef=Baz:84:8 [Context:Baz]
+// CHECK: c-index-api-test.m:84:3: ObjCClassRef=Baz:84:8 [Context:Baz]
+// CHECK: c-index-api-test.m:84:4: ObjCClassRef=Baz:84:8 [Context:Baz]
+// CHECK: c-index-api-test.m:84:6: VarDecl=bee:84:8 [Context:bee]
+// CHECK: c-index-api-test.m:84:8: VarDecl=bee:84:8 [Context:bee]
+// CHECK: c-index-api-test.m:84:9: VarDecl=bee:84:8 [Context:bee]
+// CHECK: c-index-api-test.m:84:10: VarDecl=bee:84:8 [Context:bee]
+// CHECK: <invalid loc>:85:2: TypedefDecl=id:0:0 [Context:id]
+// CHECK: <invalid loc>:85:3: TypedefDecl=id:0:0 [Context:id]
+// CHECK: c-index-api-test.m:85:5: VarDecl=a:85:5 [Context:a]
+// CHECK: c-index-api-test.m:85:6: VarDecl=a:85:5 [Context:a]
+// CHECK: c-index-api-test.m:85:7: VarDecl=a:85:5 [Context:a]
+// CHECK: c-index-api-test.m:85:8: VarDecl=a:85:5 [Context:a]
+// CHECK: c-index-api-test.m:85:9: ObjCSelectorRef=foo:24:1 [Context:a]
+// CHECK: c-index-api-test.m:85:10: VarRef=bee:84:8 [Context:a]
+// CHECK: c-index-api-test.m:85:11: VarRef=bee:84:8 [Context:a]
+// CHECK: c-index-api-test.m:85:12: VarRef=bee:84:8 [Context:a]
+// CHECK: c-index-api-test.m:85:13: ObjCSelectorRef=foo:24:1 [Context:a]
+// CHECK: c-index-api-test.m:85:14: ObjCSelectorRef=foo:24:1 [Context:a]
+// CHECK: c-index-api-test.m:85:15: ObjCSelectorRef=foo:24:1 [Context:a]
+// CHECK: c-index-api-test.m:85:16: ObjCSelectorRef=foo:24:1 [Context:a]
+// CHECK: c-index-api-test.m:85:17: ObjCSelectorRef=foo:24:1 [Context:a]
+// CHECK: <invalid loc>:86:2: TypedefDecl=id:0:0 [Context:id]
+// CHECK: <invalid loc>:86:3: TypedefDecl=id:0:0 [Context:id]
+// CHECK: c-index-api-test.m:86:5: VarDecl=c:86:12 [Context:c]
+// CHECK: c-index-api-test.m:86:6: ObjCProtocolRef=SubP:86:12 [Context:SubP]
+// CHECK: c-index-api-test.m:86:7: ObjCProtocolRef=SubP:86:12 [Context:SubP]
+// CHECK: c-index-api-test.m:86:8: ObjCProtocolRef=SubP:86:12 [Context:SubP]
+// CHECK: c-index-api-test.m:86:9: ObjCProtocolRef=SubP:86:12 [Context:SubP]
+// CHECK: c-index-api-test.m:86:10: VarDecl=c:86:12 [Context:c]
+// CHECK: c-index-api-test.m:86:12: VarDecl=c:86:12 [Context:c]
+// CHECK: c-index-api-test.m:86:13: VarDecl=c:86:12 [Context:c]
+// CHECK: c-index-api-test.m:86:14: VarDecl=c:86:12 [Context:c]
+// CHECK: c-index-api-test.m:86:15: VarDecl=c:86:12 [Context:c]
+// CHECK: c-index-api-test.m:86:16: ObjCSelectorRef=fooC:25:1 [Context:c]
+// CHECK: c-index-api-test.m:86:17: ObjCSelectorRef=fooC:25:1 [Context:c]
+// CHECK: c-index-api-test.m:86:18: ObjCSelectorRef=fooC:25:1 [Context:c]
+// CHECK: c-index-api-test.m:86:19: ObjCSelectorRef=fooC:25:1 [Context:c]
+// CHECK: c-index-api-test.m:86:20: ObjCSelectorRef=fooC:25:1 [Context:c]
+// CHECK: c-index-api-test.m:86:21: ObjCSelectorRef=fooC:25:1 [Context:c]
+// CHECK: c-index-api-test.m:86:22: ObjCSelectorRef=fooC:25:1 [Context:c]
+// CHECK: c-index-api-test.m:86:23: ObjCSelectorRef=fooC:25:1 [Context:c]
+// CHECK: c-index-api-test.m:86:24: ObjCSelectorRef=fooC:25:1 [Context:c]
+// CHECK: c-index-api-test.m:86:25: ObjCSelectorRef=fooC:25:1 [Context:c]
+// CHECK: <invalid loc>:87:2: TypedefDecl=id:0:0 [Context:id]
+// CHECK: <invalid loc>:87:3: TypedefDecl=id:0:0 [Context:id]
+// CHECK: c-index-api-test.m:87:5: VarDecl=d:87:13 [Context:d]
+// CHECK: c-index-api-test.m:87:6: ObjCProtocolRef=Proto:87:13 [Context:Proto]
+// CHECK: c-index-api-test.m:87:7: ObjCProtocolRef=Proto:87:13 [Context:Proto]
+// CHECK: c-index-api-test.m:87:8: ObjCProtocolRef=Proto:87:13 [Context:Proto]
+// CHECK: c-index-api-test.m:87:9: ObjCProtocolRef=Proto:87:13 [Context:Proto]
+// CHECK: c-index-api-test.m:87:10: ObjCProtocolRef=Proto:87:13 [Context:Proto]
+// CHECK: c-index-api-test.m:87:11: VarDecl=d:87:13 [Context:d]
+// CHECK: c-index-api-test.m:87:13: VarDecl=d:87:13 [Context:d]
+// CHECK: c-index-api-test.m:88:2: VarRef=d:87:13 [Context:main]
+// CHECK: c-index-api-test.m:88:6: VarRef=c:86:12 [Context:main]
+// CHECK: c-index-api-test.m:89:2: ObjCSelectorRef=pMethod:41:1 [Context:main]
+// CHECK: c-index-api-test.m:89:3: VarRef=d:87:13 [Context:main]
+// CHECK: c-index-api-test.m:89:4: ObjCSelectorRef=pMethod:41:1 [Context:main]
+// CHECK: c-index-api-test.m:89:5: ObjCSelectorRef=pMethod:41:1 [Context:main]
+// CHECK: c-index-api-test.m:89:6: ObjCSelectorRef=pMethod:41:1 [Context:main]
+// CHECK: c-index-api-test.m:89:7: ObjCSelectorRef=pMethod:41:1 [Context:main]
+// CHECK: c-index-api-test.m:89:8: ObjCSelectorRef=pMethod:41:1 [Context:main]
+// CHECK: c-index-api-test.m:89:9: ObjCSelectorRef=pMethod:41:1 [Context:main]
+// CHECK: c-index-api-test.m:89:10: ObjCSelectorRef=pMethod:41:1 [Context:main]
+// CHECK: c-index-api-test.m:89:11: ObjCSelectorRef=pMethod:41:1 [Context:main]
+// CHECK: c-index-api-test.m:89:12: ObjCSelectorRef=pMethod:41:1 [Context:main]
+// CHECK: c-index-api-test.m:90:2: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-test.m:90:3: VarRef=bee:84:8 [Context:main]
+// CHECK: c-index-api-test.m:90:4: VarRef=bee:84:8 [Context:main]
+// CHECK: c-index-api-test.m:90:5: VarRef=bee:84:8 [Context:main]
+// CHECK: c-index-api-test.m:90:6: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-test.m:90:7: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-test.m:90:8: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-test.m:90:9: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-test.m:90:10: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-test.m:90:11: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-test.m:90:12: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-test.m:90:13: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-test.m:90:14: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-test.m:90:15: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-test.m:90:16: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-test.m:90:17: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-test.m:90:18: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-test.m:90:19: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-test.m:90:20: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-test.m:90:21: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-test.m:90:22: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-test.m:90:23: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-test.m:90:24: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-test.m:90:25: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-test.m:90:26: ObjCSelectorRef=floatMethod:37:1 [Context:main]
+// CHECK: c-index-api-test.m:90:27: VarRef=bee:84:8 [Context:main]
+// CHECK: c-index-api-test.m:90:28: VarRef=bee:84:8 [Context:main]
+// CHECK: c-index-api-test.m:90:29: VarRef=bee:84:8 [Context:main]
+// CHECK: c-index-api-test.m:90:30: ObjCSelectorRef=floatMethod:37:1 [Context:main]
+// CHECK: c-index-api-test.m:90:31: ObjCSelectorRef=floatMethod:37:1 [Context:main]
+// CHECK: c-index-api-test.m:90:32: ObjCSelectorRef=floatMethod:37:1 [Context:main]
+// CHECK: c-index-api-test.m:90:33: ObjCSelectorRef=floatMethod:37:1 [Context:main]
+// CHECK: c-index-api-test.m:90:34: ObjCSelectorRef=floatMethod:37:1 [Context:main]
+// CHECK: c-index-api-test.m:90:35: ObjCSelectorRef=floatMethod:37:1 [Context:main]
+// CHECK: c-index-api-test.m:90:36: ObjCSelectorRef=floatMethod:37:1 [Context:main]
+// CHECK: c-index-api-test.m:90:37: ObjCSelectorRef=floatMethod:37:1 [Context:main]
+// CHECK: c-index-api-test.m:90:38: ObjCSelectorRef=floatMethod:37:1 [Context:main]
+// CHECK: c-index-api-test.m:90:39: ObjCSelectorRef=floatMethod:37:1 [Context:main]
+// CHECK: c-index-api-test.m:90:40: ObjCSelectorRef=floatMethod:37:1 [Context:main]
+// CHECK: c-index-api-test.m:90:41: ObjCSelectorRef=floatMethod:37:1 [Context:main]
+// CHECK: c-index-api-test.m:90:42: ObjCSelectorRef=floatMethod:37:1 [Context:main]
+// CHECK: c-index-api-test.m:90:43: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-test.m:91:3: FunctionRef=main:83:5 [Context:main]
+// CHECK: c-index-api-test.m:91:4: FunctionRef=main:83:5 [Context:main]
+// CHECK: c-index-api-test.m:91:5: FunctionRef=main:83:5 [Context:main]
+// CHECK: c-index-api-test.m:91:6: FunctionRef=main:83:5 [Context:main]
+// CHECK: c-index-api-test.m:91:8: EnumConstantRef=someEnum:58:3 [Context:main]
+// CHECK: c-index-api-test.m:91:9: EnumConstantRef=someEnum:58:3 [Context:main]
+// CHECK: c-index-api-test.m:91:10: EnumConstantRef=someEnum:58:3 [Context:main]
+// CHECK: c-index-api-test.m:91:11: EnumConstantRef=someEnum:58:3 [Context:main]
+// CHECK: c-index-api-test.m:91:12: EnumConstantRef=someEnum:58:3 [Context:main]
+// CHECK: c-index-api-test.m:91:13: EnumConstantRef=someEnum:58:3 [Context:main]
+// CHECK: c-index-api-test.m:91:14: EnumConstantRef=someEnum:58:3 [Context:main]
+// CHECK: c-index-api-test.m:91:15: EnumConstantRef=someEnum:58:3 [Context:main]
+// CHECK: c-index-api-test.m:91:33: VarRef=bee:84:8 [Context:main]
+// CHECK: c-index-api-test.m:91:34: VarRef=bee:84:8 [Context:main]
+// CHECK: c-index-api-test.m:91:35: VarRef=bee:84:8 [Context:main]
diff --git a/test/Index/comments.c b/test/Index/comments.c
index 7ad8fd7..689ce88 100644
--- a/test/Index/comments.c
+++ b/test/Index/comments.c
@@ -1,15 +1,4 @@
-// RUN: clang-cc -emit-pch -o %t.ast %s &&
-// RUN: index-test %t.ast -point-at %s:22:6 | grep "starts here" &&
-// RUN: index-test %t.ast -point-at %s:22:6 | grep "block comment" &&
-// RUN: index-test %t.ast -point-at %s:28:6 | grep "BCPL" &&
-// RUN: index-test %t.ast -point-at %s:28:6 | grep "But" &&
-// RUN: index-test %t.ast -point-at %s:28:6 | grep "NOT" | count 0 &&
-// RUN: index-test %t.ast -point-at %s:30:6 | grep "member"
-
-
-
-
-
+// Run lines are sensitive to line numbers and come below the code.
//! It all starts here.
/*! It's a little odd to continue line this,
@@ -27,4 +16,19 @@ void f(int, int);
/** But there are other blocks that are part of the comment, too. */
void g(int);
-void h(int); ///< This is a member comment. \ No newline at end of file
+void h(int); ///< This is a member comment.
+
+
+// RUN: clang-cc -emit-pch -o %t.ast %s &&
+
+// RUN: index-test %t.ast -point-at %s:11:6 > %t &&
+// RUN: grep "starts here" %t &&
+// RUN: grep "block comment" %t &&
+
+// RUN: index-test %t.ast -point-at %s:17:6 > %t &&
+// RUN: grep "BCPL" %t &&
+// RUN: grep "But" %t &&
+
+// RUN: index-test %t.ast -point-at %s:19:6 > %t &&
+// RUN: grep "NOT" %t | count 0 &&
+// RUN: grep "member" %t
diff --git a/test/Index/cxx-operator-overload.cpp b/test/Index/cxx-operator-overload.cpp
new file mode 100644
index 0000000..9bda03e
--- /dev/null
+++ b/test/Index/cxx-operator-overload.cpp
@@ -0,0 +1,28 @@
+// Run lines are sensitive to line numbers and come below the code.
+// FIXME: re-enable this when we can serialize more C++ ASTs
+class Cls {
+public:
+ Cls operator +(const Cls &RHS);
+};
+
+static void bar() {
+ Cls x1, x2, x3;
+ Cls x4 = x1 + x2 + x3;
+}
+
+Cls Cls::operator +(const Cls &RHS) { while (1) {} }
+
+// RUN: clang-cc -emit-pch %s -o %t.ast
+
+// RUNx: index-test %t.ast -point-at %s:10:17 -print-decls > %t &&
+// RUNx: cat %t | count 2 &&
+// RUNx: grep ':5:9,' %t &&
+// RUNx: grep ':13:10,' %t &&
+
+// Yep, we can show references of '+' plus signs that are overloaded, w00t!
+// RUNx: index-test %t.ast -point-at %s:5:15 -print-refs > %t &&
+// RUNx: cat %t | count 2 &&
+// RUNx: grep ':10:17,' %t &&
+// RUNx: grep ':10:22,' %t &&
+
+// RUNx: index-test %t.ast -point-at %s:10:14 | grep 'DeclRefExpr x1'
diff --git a/test/Index/find-decls.c b/test/Index/find-decls.c
new file mode 100644
index 0000000..50a233d
--- /dev/null
+++ b/test/Index/find-decls.c
@@ -0,0 +1,25 @@
+// RUN: clang-cc -fblocks -emit-pch %S/t1.c -o %t1.ast &&
+// RUN: clang-cc -fblocks -emit-pch %S/t2.c -o %t2.ast &&
+
+// RUN: index-test %t1.ast %t2.ast -point-at %S/t1.c:8:7 -print-decls > %t &&
+// RUN: cat %t | count 3 &&
+// RUN: grep 'foo.h:4:6,' %t | count 2 &&
+// RUN: grep 't2.c:5:6,' %t &&
+
+// RUN: index-test %t1.ast %t2.ast -point-at %S/t1.c:5:47 -print-decls > %t &&
+// RUN: cat %t | count 1 &&
+// RUN: grep 't1.c:5:12,' %t &&
+
+// RUN: index-test %t1.ast %t2.ast -point-at %S/t1.c:6:20 -print-decls > %t &&
+// RUN: cat %t | count 1 &&
+// RUN: grep 't1.c:3:19,' %t &&
+
+// field test
+
+// RUN: index-test %t1.ast %t2.ast -point-at %S/t1.c:21:6 -print-decls > %t &&
+// RUN: cat %t | count 1 &&
+// RUN: grep 't1.c:12:7,' %t &&
+
+// RUN: index-test %t1.ast %t2.ast -point-at %S/t1.c:22:21 -print-decls > %t &&
+// RUN: cat %t | count 1 &&
+// RUN: grep 't1.c:16:7,' %t
diff --git a/test/Index/find-defs.c b/test/Index/find-defs.c
new file mode 100644
index 0000000..0e63ae7
--- /dev/null
+++ b/test/Index/find-defs.c
@@ -0,0 +1,18 @@
+// RUN: clang-cc -fblocks -emit-pch %S/t1.c -o %t1.ast &&
+// RUN: clang-cc -fblocks -emit-pch %S/t2.c -o %t2.ast &&
+
+// RUN: index-test %t1.ast %t2.ast -point-at %S/foo.h:1:14 -print-defs > %t &&
+// RUN: cat %t | count 1 &&
+// RUN: grep 't2.c:3:5,' %t &&
+
+// RUN: index-test %t1.ast %t2.ast -point-at %S/foo.h:3:9 -print-defs > %t &&
+// RUN: cat %t | count 1 &&
+// RUN: grep 't1.c:3:6,' %t &&
+
+// RUN: index-test %t1.ast %t2.ast -point-at %S/foo.h:4:9 -print-defs > %t &&
+// RUN: cat %t | count 1 &&
+// RUN: grep 't2.c:5:6,' %t &&
+
+// RUN: index-test %t1.ast %t2.ast -point-at %S/t1.c:8:7 -print-defs > %t &&
+// RUN: cat %t | count 1 &&
+// RUN: grep 't2.c:5:6,' %t
diff --git a/test/Index/find-refs.c b/test/Index/find-refs.c
new file mode 100644
index 0000000..1b58b37
--- /dev/null
+++ b/test/Index/find-refs.c
@@ -0,0 +1,47 @@
+// RUN: clang-cc -fblocks -emit-pch %S/t1.c -o %t1.ast &&
+// RUN: clang-cc -fblocks -emit-pch %S/t2.c -o %t2.ast &&
+
+// RUN: index-test %t1.ast %t2.ast -point-at %S/foo.h:1:14 -print-refs > %t &&
+// RUN: cat %t | count 4 &&
+// RUN: grep 't1.c:4:19,' %t &&
+// RUN: grep 't1.c:28:40,' %t &&
+// RUN: grep 't2.c:6:3,' %t &&
+// RUN: grep 't2.c:7:12,' %t &&
+
+// RUN: index-test %t1.ast %t2.ast -point-at %S/foo.h:3:9 -print-refs > %t &&
+// RUN: cat %t | count 1 &&
+// RUN: grep 't2.c:7:3,' %t &&
+
+// RUN: index-test %t1.ast %t2.ast -point-at %S/foo.h:4:9 -print-refs > %t &&
+// RUN: cat %t | count 1 &&
+// RUN: grep 't1.c:8:3,' %t &&
+
+// RUN: index-test %t1.ast %t2.ast -point-at %S/t1.c:3:22 -print-refs > %t &&
+// RUN: cat %t | count 1 &&
+// RUN: grep 't1.c:6:17,' %t &&
+
+// RUN: index-test %t1.ast %t2.ast -point-at %S/t1.c:4:11 -print-refs > %t &&
+// RUN: cat %t | count 1 &&
+// RUN: grep 't1.c:6:5,' %t &&
+
+// RUN: index-test %t1.ast %t2.ast -point-at %S/t1.c:5:30 -print-refs > %t &&
+// RUN: cat %t | count 3 &&
+// RUN: grep 't1.c:5:27,' %t &&
+// RUN: grep 't1.c:5:44,' %t &&
+// RUN: grep 't1.c:6:26,' %t &&
+
+// field test
+
+// FIXME: References point at the start of MemberExpr, make them point at the field instead.
+// RUN: index-test %t1.ast %t2.ast -point-at %S/t1.c:12:7 -print-refs > %t &&
+// RUN: cat %t | count 1 &&
+// RUN: grep 't1.c:21:3,' %t &&
+
+// RUN: index-test %t1.ast %t2.ast -point-at %S/t1.c:16:7 -print-refs > %t &&
+// RUN: cat %t | count 1 &&
+// RUN: grep 't1.c:22:3,' %t &&
+
+// RUN: index-test %t1.ast %t2.ast -point-at %S/foo.h:7:11 -print-refs > %t &&
+// RUN: cat %t | count 2 &&
+// RUN: grep 't1.c:25:3,' %t &&
+// RUN: grep 't2.c:10:3,' %t
diff --git a/test/Index/foo.h b/test/Index/foo.h
new file mode 100644
index 0000000..7670c00
--- /dev/null
+++ b/test/Index/foo.h
@@ -0,0 +1,8 @@
+extern int global_var;
+
+void foo_func(int param1);
+void bar_func(void);
+
+struct MyStruct {
+ int field_var;
+};
diff --git a/test/Index/multiple-redecls.c b/test/Index/multiple-redecls.c
new file mode 100644
index 0000000..6f1f75b
--- /dev/null
+++ b/test/Index/multiple-redecls.c
@@ -0,0 +1,12 @@
+// RUN: clang-cc -emit-pch %s -o %t.ast &&
+// RUN: index-test %t.ast -point-at %s:8:4 -print-decls | count 2 &&
+// RUN: index-test %t.ast -point-at %s:8:4 -print-defs | count 1
+
+static void foo(int x);
+
+static void bar(void) {
+ foo(10);
+}
+
+void foo(int x) {
+}
diff --git a/test/Index/objc-decls.m b/test/Index/objc-decls.m
new file mode 100644
index 0000000..1a8ab4b
--- /dev/null
+++ b/test/Index/objc-decls.m
@@ -0,0 +1,16 @@
+// RUN: clang-cc -emit-pch %S/t1.m -o %t1.m.ast &&
+// RUN: clang-cc -emit-pch %S/t2.m -o %t2.m.ast &&
+
+// RUN: index-test %t1.m.ast %t2.m.ast -point-at %S/t1.m:12:12 -print-decls > %t &&
+// RUN: cat %t | count 2 &&
+// RUN: grep 'objc.h:2:9,' %t | count 2 &&
+
+// RUN: index-test %t1.m.ast %t2.m.ast -point-at %S/objc.h:5:13 -print-decls > %t &&
+// RUN: cat %t | count 3 &&
+// RUN: grep 'objc.h:5:1,' %t | count 2 &&
+// RUN: grep 't1.m:15:1,' %t | count 1 &&
+
+// RUN: index-test %t1.m.ast %t2.m.ast -point-at %S/objc.h:10:13 -print-decls > %t &&
+// RUN: cat %t | count 3 &&
+// RUN: grep 'objc.h:10:1,' %t | count 2 &&
+// RUN: grep 't2.m:11:1,' %t | count 1
diff --git a/test/Index/objc-message.m b/test/Index/objc-message.m
new file mode 100644
index 0000000..45ce838
--- /dev/null
+++ b/test/Index/objc-message.m
@@ -0,0 +1,38 @@
+// RUN: clang-cc -emit-pch %S/t1.m -o %t1.m.ast &&
+// RUN: clang-cc -emit-pch %S/t2.m -o %t2.m.ast &&
+
+// RUN: index-test %t1.m.ast %t2.m.ast -point-at %S/objc.h:5:13 -print-refs > %t &&
+// RUN: cat %t | count 1 &&
+// RUN: grep 't1.m:6:3,' %t &&
+
+// RUN: index-test %t1.m.ast %t2.m.ast -point-at %S/objc.h:6:13 -print-refs > %t &&
+// RUN: cat %t | count 2 &&
+// RUN: grep 't1.m:7:3,' %t &&
+// RUN: grep 't2.m:7:3,' %t &&
+
+// RUN: index-test %t1.m.ast %t2.m.ast -point-at %S/objc.h:10:13 -print-refs > %t &&
+// RUN: cat %t | count 2 &&
+// RUN: grep 't1.m:6:3,' %t &&
+// RUN: grep 't2.m:6:3,' %t &&
+
+// RUN: index-test %t1.m.ast %t2.m.ast -point-at %S/t1.m:6:15 -print-decls > %t &&
+// RUN: cat %t | count 6 &&
+// RUN: grep 'objc.h:5:1,' %t | count 2 &&
+// RUN: grep 'objc.h:10:1,' %t | count 2 &&
+// RUN: grep 't1.m:15:1,' %t &&
+// RUN: grep 't2.m:11:1,' %t &&
+
+// RUN: index-test %t1.m.ast %t2.m.ast -point-at %S/t1.m:7:15 -print-decls > %t &&
+// RUN: cat %t | count 3 &&
+// RUN: grep 'objc.h:6:1,' %t | count 2 &&
+// RUN: grep 't1.m:18:1,' %t &&
+
+// RUN: index-test %t2.m.ast %t1.m.ast -point-at %S/t2.m:6:15 -print-decls > %t &&
+// RUN: cat %t | count 3 &&
+// RUN: grep 'objc.h:10:1,' %t | count 2 &&
+// RUN: grep 't2.m:11:1,' %t &&
+
+// RUN: index-test %t2.m.ast %t1.m.ast -point-at %S/t2.m:7:15 -print-decls > %t &&
+// RUN: cat %t | count 3 &&
+// RUN: grep 'objc.h:6:1,' %t | count 2 &&
+// RUN: grep 't1.m:18:1,' %t
diff --git a/test/Index/objc.h b/test/Index/objc.h
new file mode 100644
index 0000000..c671add
--- /dev/null
+++ b/test/Index/objc.h
@@ -0,0 +1,11 @@
+@interface Base {
+ int my_var;
+}
+-(int) my_var;
+-(void) my_method: (int)param;
++(void) my_method: (int)param;
+@end
+
+@interface Sub : Base
+-(void) my_method: (int)param;
+@end
diff --git a/test/Index/resolve-loc.c b/test/Index/resolve-loc.c
index d04b79b..cae86f3 100644
--- a/test/Index/resolve-loc.c
+++ b/test/Index/resolve-loc.c
@@ -1,16 +1,4 @@
-// RUN: clang-cc -emit-pch %s -o %t.ast &&
-// RUN: index-test %t.ast -point-at %s:15:8 | grep top_var &&
-// RUN: index-test %t.ast -point-at %s:17:15 | grep top_func_decl &&
-// RUN: index-test %t.ast -point-at %s:17:25 | grep param1 &&
-// RUN: index-test %t.ast -point-at %s:19:17 | grep top_func_def &&
-// RUN: index-test %t.ast -point-at %s:19:23 | grep param2 &&
-// RUN: index-test %t.ast -point-at %s:20:10 | grep local_var1 &&
-// RUN: index-test %t.ast -point-at %s:21:15 | grep for_var &&
-// RUN: index-test %t.ast -point-at %s:21:43 | grep top_func_def &&
-// RUN: index-test %t.ast -point-at %s:21:43 | grep '++for_var' &&
-// RUN: index-test %t.ast -point-at %s:22:9 | grep local_var2 &&
-// RUN: index-test %t.ast -point-at %s:22:30 | grep local_var2 &&
-// RUN: index-test %t.ast -point-at %s:22:30 | grep 'for_var + 1'
+// Run lines are sensitive to line numbers and come below the code.
int top_var;
@@ -22,3 +10,28 @@ void top_func_def(int param2) {
int local_var2 = for_var + 1;
}
}
+
+struct S {
+ int field_var;
+};
+
+
+// RUN: clang-cc -emit-pch %s -o %t.ast &&
+// RUN: index-test %t.ast -point-at %s:3:8 | grep top_var &&
+// RUN: index-test %t.ast -point-at %s:5:15 | grep top_func_decl &&
+// RUN: index-test %t.ast -point-at %s:5:25 | grep param1 &&
+// RUN: index-test %t.ast -point-at %s:7:17 | grep top_func_def &&
+// RUN: index-test %t.ast -point-at %s:7:23 | grep param2 &&
+// RUN: index-test %t.ast -point-at %s:8:10 | grep local_var1 &&
+// RUN: index-test %t.ast -point-at %s:9:15 | grep for_var &&
+
+// RUN: index-test %t.ast -point-at %s:9:43 > %t &&
+// RUN: grep '++for_var' %t &&
+
+// RUN: index-test %t.ast -point-at %s:10:9 | grep local_var2 &&
+
+// RUN: index-test %t.ast -point-at %s:10:30 > %t &&
+// RUN: grep 'for_var + 1' %t &&
+
+// fields test.
+// RUN: index-test %t.ast -point-at %s:15:10 | grep field_var
diff --git a/test/Index/t1.c b/test/Index/t1.c
new file mode 100644
index 0000000..45e0488
--- /dev/null
+++ b/test/Index/t1.c
@@ -0,0 +1,31 @@
+#include "foo.h"
+
+void foo_func(int param1) {
+ int local_var = global_var;
+ for (int for_var = 100; for_var < 500; ++for_var) {
+ local_var = param1 + for_var;
+ }
+ bar_func();
+}
+
+struct S1 {
+ int x;
+};
+
+struct S2 {
+ int x;
+};
+
+void field_test(void) {
+ struct S1 s1;
+ s1.x = 0;
+ ((struct S2 *)0)->x = 0;
+
+ struct MyStruct ms;
+ ms.field_var = 10;
+}
+
+int (^CP)(int) = ^(int x) { return x * global_var; };
+
+// Suppress 'no run line' failure.
+// RUN: true
diff --git a/test/Index/t1.m b/test/Index/t1.m
new file mode 100644
index 0000000..b2a7a37
--- /dev/null
+++ b/test/Index/t1.m
@@ -0,0 +1,23 @@
+#include "objc.h"
+
+static void foo() {
+ Base *base;
+ int x = [base my_var];
+ [base my_method:x];
+ [Base my_method:x];
+}
+
+@implementation Base
+-(int) my_var {
+ return my_var;
+}
+
+-(void) my_method: (int)param {
+}
+
++(void) my_method: (int)param {
+}
+@end
+
+// Suppress 'no run line' failure.
+// RUN: true
diff --git a/test/Index/t2.c b/test/Index/t2.c
new file mode 100644
index 0000000..bf52869
--- /dev/null
+++ b/test/Index/t2.c
@@ -0,0 +1,14 @@
+#include "foo.h"
+
+int global_var = 10;
+
+void bar_func(void) {
+ global_var += 100;
+ foo_func(global_var);
+
+ struct MyStruct *ms;
+ ms->field_var = 10;
+}
+
+// Suppress 'no run line' failure.
+// RUN: true
diff --git a/test/Index/t2.m b/test/Index/t2.m
new file mode 100644
index 0000000..00d2f1d
--- /dev/null
+++ b/test/Index/t2.m
@@ -0,0 +1,16 @@
+#include "objc.h"
+
+static void foo() {
+ Sub *sub;
+ int x = [sub my_var];
+ [sub my_method:x];
+ [Sub my_method:x];
+}
+
+@implementation Sub
+-(void) my_method: (int)param {
+}
+@end
+
+// Suppress 'no run line' failure.
+// RUN: true
diff --git a/test/Lexer/11-27-2007-FloatLiterals.c b/test/Lexer/11-27-2007-FloatLiterals.c
index f3ea7cb..ab3aba1 100644
--- a/test/Lexer/11-27-2007-FloatLiterals.c
+++ b/test/Lexer/11-27-2007-FloatLiterals.c
@@ -1,5 +1,9 @@
-// RUN: clang-cc %s -emit-llvm -o - | grep 0x3BFD83C940000000 | count 2 &&
-// RUN: clang-cc %s -emit-llvm -o - | grep 2.000000e+32 | count 2
+// RUN: clang-cc %s -emit-llvm -o - | FileCheck %s
+
+// CHECK: 0x3BFD83C940000000
+// CHECK: 2.000000e+{{[0]*}}32
+// CHECK: 0x3BFD83C940000000
+// CHECK: 2.000000e+{{[0]*}}32
float F = 1e-19f;
double D = 2e32;
diff --git a/test/Lexer/comment-escape.c b/test/Lexer/comment-escape.c
index c568cd6..c461457 100644
--- a/test/Lexer/comment-escape.c
+++ b/test/Lexer/comment-escape.c
@@ -2,5 +2,5 @@
// rdar://6757323
// foo \
-#define blork 32
+#define blork 32
diff --git a/test/Lexer/dollar-idents.c b/test/Lexer/dollar-idents.c
index 7635ea1..f5c33b1 100644
--- a/test/Lexer/dollar-idents.c
+++ b/test/Lexer/dollar-idents.c
@@ -1,5 +1,5 @@
// RUN: clang-cc -dump-tokens %s 2> %t &&
-// RUN: grep "identifier '\$A'" %t
+// RUN: grep "identifier '\$A'" %t &&
// RUN: clang-cc -dump-tokens -x assembler-with-cpp %s 2> %t &&
// RUN: grep "identifier 'A'" %t
// PR3808
diff --git a/test/Makefile b/test/Makefile
index 271f46f..8543d43 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -2,7 +2,14 @@ LEVEL = ../../..
include $(LEVEL)/Makefile.common
# Test in all immediate subdirectories if unset.
-TESTDIRS ?= $(shell echo $(PROJ_SRC_DIR)/*/)
+ifdef TESTSUITE
+TESTDIRS := $(TESTSUITE:%=$(PROJ_SRC_DIR)/%)
+else
+TESTDIRS ?= $(PROJ_SRC_DIR)
+endif
+
+# 'lit' wants objdir paths, so it will pick up the lit.site.cfg.
+TESTDIRS := $(TESTDIRS:$(PROJ_SRC_DIR)%=$(PROJ_OBJ_DIR)%)
ifndef TESTARGS
ifdef VERBOSE
@@ -12,9 +19,28 @@ TESTARGS = -s
endif
endif
-all::
+ifdef VG
+ VGARG="--vg"
+else
+ VGARG=
+endif
+
+all:: lit.site.cfg
@ echo '--- Running clang tests for $(TARGET_TRIPLE) ---'
- @ PATH=$(ToolDir):$(LLVM_SRC_ROOT)/test/Scripts:$$PATH VG=$(VG) ../utils/test/MultiTestRunner.py $(TESTARGS) $(TESTDIRS)
+ @ $(PYTHON) $(LLVM_SRC_ROOT)/utils/lit/lit.py \
+ $(TESTARGS) $(TESTDIRS) $(VGARG)
+
+FORCE:
+
+lit.site.cfg: FORCE
+ @echo "Making Clang 'lit.site.cfg' file..."
+ @sed -e "s#@LLVM_SOURCE_DIR@#$(LLVM_SRC_ROOT)#g" \
+ -e "s#@LLVM_BINARY_DIR@#$(LLVM_OBJ_ROOT)#g" \
+ -e "s#@LLVM_TOOLS_DIR@#$(ToolDir)#g" \
+ -e "s#@LLVM_LIBS_DIR@#$(LibDir)#g" \
+ -e "s#@CLANG_SOURCE_DIR@#$(PROJ_SRC_DIR)/..#g" \
+ -e "s#@CLANG_BINARY_DIR@#$(PROJ_OBJ_DIR)/..#g" \
+ $(PROJ_SRC_DIR)/lit.site.cfg.in > $@
clean::
@ rm -rf Output/
diff --git a/test/Misc/diag-mapping2.c b/test/Misc/diag-mapping2.c
index 7e0d774..c5fd7ff 100644
--- a/test/Misc/diag-mapping2.c
+++ b/test/Misc/diag-mapping2.c
@@ -12,7 +12,10 @@
// 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:"
+// RUN: clang-cc %s -Werror -Wno-error=#warnings 2>&1 | grep "warning:" &&
+
+// -Wno-error overrides -Werror. PR4715
+// RUN: clang-cc %s -Werror -Wno-error 2>&1 | grep "warning:"
#warning foo
diff --git a/test/PCH/cxx-method.cpp b/test/PCH/cxx-method.cpp
new file mode 100644
index 0000000..144406e
--- /dev/null
+++ b/test/PCH/cxx-method.cpp
@@ -0,0 +1,7 @@
+// RUN: clang-cc -emit-pch %s -o %t
+
+struct S {
+ void m(int x);
+};
+
+void S::m(int x) { }
diff --git a/test/PCH/libroot/usr/include/reloc.h b/test/PCH/libroot/usr/include/reloc.h
new file mode 100644
index 0000000..04eeacb
--- /dev/null
+++ b/test/PCH/libroot/usr/include/reloc.h
@@ -0,0 +1,15 @@
+#ifndef RELOC_H
+#define RELOC_H
+
+#include <reloc2.h>
+
+
+
+
+
+
+
+// Line number 13 below is important
+int x = 2;
+
+#endif // RELOC_H
diff --git a/test/PCH/libroot/usr/include/reloc2.h b/test/PCH/libroot/usr/include/reloc2.h
new file mode 100644
index 0000000..995415c
--- /dev/null
+++ b/test/PCH/libroot/usr/include/reloc2.h
@@ -0,0 +1,15 @@
+#ifndef RELOC2_H
+#define RELOC2_H
+#include <stddef.h>
+
+
+
+
+
+
+
+
+
+// Line number below is important!
+int y = 2;
+#endif // RELOC2_H
diff --git a/test/PCH/method_pool.h b/test/PCH/method_pool.h
index f7af904..8085836 100644
--- a/test/PCH/method_pool.h
+++ b/test/PCH/method_pool.h
@@ -22,8 +22,7 @@
@end
@implementation TestMethodPool1
-+ alloc {
-}
++ alloc { return 0; }
- (double)instMethod:(int)foo {
return foo;
diff --git a/test/PCH/objc_exprs.m b/test/PCH/objc_exprs.m
index eb1ae43..48966f3 100644
--- a/test/PCH/objc_exprs.m
+++ b/test/PCH/objc_exprs.m
@@ -6,7 +6,7 @@
// RUN: clang-cc -fblocks -include-pch %t -fsyntax-only -verify %s
// Expressions
-int *A1 = (objc_string)0; // expected-warning {{'struct objc_object *'}}
+int *A1 = (objc_string)0; // expected-warning {{aka 'id'}}
char A2 = (objc_encode){}; // expected-error {{not a compile-time constant}} \
expected-warning {{char [2]}}
@@ -15,8 +15,7 @@ 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 *T0 = (objc_id_protocol_ty)0; // 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> *'}}
diff --git a/test/PCH/pr4489.c b/test/PCH/pr4489.c
index 696da5b..7730819 100644
--- a/test/PCH/pr4489.c
+++ b/test/PCH/pr4489.c
@@ -1,7 +1,8 @@
// RUN: clang -x c-header -o %t.pch %s &&
// RUN: clang -include %t -x c /dev/null -emit-llvm -S -o -
// PR 4489: Crash with PCH
-
+// PR 4492: Crash with PCH (round two)
+// PR 4509: Crash with PCH (round three)
typedef struct _IO_FILE FILE;
extern int fprintf (struct _IO_FILE *__restrict __stream,
__const char *__restrict __format, ...);
@@ -17,4 +18,23 @@ int x(void)
void y(void) {
extern char z;
fprintf (0, "a");
+}
+
+struct y0 { int i; } y0[1] = {};
+
+void x0(void)
+{
+ extern char z0;
+ fprintf (0, "a");
+}
+
+void x1(void)
+{
+ fprintf (0, "asdf");
+}
+
+void y1(void)
+{
+ extern char e;
+ fprintf (0, "asdf");
} \ No newline at end of file
diff --git a/test/PCH/reloc.c b/test/PCH/reloc.c
new file mode 100644
index 0000000..b08187f
--- /dev/null
+++ b/test/PCH/reloc.c
@@ -0,0 +1,14 @@
+// RUN: clang-cc -emit-pch -o %t --relocatable-pch -isysroot %S/libroot %S/libroot/usr/include/reloc.h &&
+// RUN: clang-cc -include-pch %t -isysroot %S/libroot %s -verify &&
+// RUN: not clang-cc -include-pch %t %s
+
+#include <reloc.h>
+
+int x = 2; // expected-error{{redefinition}}
+int y = 5; // expected-error{{redefinition}}
+
+
+
+
+// expected-note{{previous definition}}
+// expected-note{{previous definition}}
diff --git a/test/Parser/CompoundStmtScope.c b/test/Parser/CompoundStmtScope.c
index 6a404aa..90e3d24 100644
--- a/test/Parser/CompoundStmtScope.c
+++ b/test/Parser/CompoundStmtScope.c
@@ -1,6 +1,6 @@
// RUN: clang-cc -fsyntax-only -verify %s
-int foo() {
+void foo() {
{
typedef float X;
}
diff --git a/test/Parser/MicrosoftExtensions.c b/test/Parser/MicrosoftExtensions.c
index 6f5622e..572ac44 100644
--- a/test/Parser/MicrosoftExtensions.c
+++ b/test/Parser/MicrosoftExtensions.c
@@ -9,22 +9,22 @@ __declspec(noalias) __declspec(restrict) void * __cdecl xxx( void * _Memory );
typedef __w64 unsigned long ULONG_PTR, *PULONG_PTR;
void * __ptr64 PtrToPtr64(const void *p)
{
- return((void * __ptr64) (unsigned __int64) (ULONG_PTR)p );
+ return((void * __ptr64) (unsigned __int64) (ULONG_PTR)p );
}
-__forceinline InterlockedBitTestAndSet (long *Base, long Bit) // expected-warning {{type specifier missing, defaults to 'int'}}
+void __forceinline InterlockedBitTestAndSet (long *Base, long Bit)
{
- __asm {
- mov eax, Bit
- mov ecx, Base
- lock bts [ecx], eax
- setc al
- };
+ __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);
+ __declspec(align(16)) int *buffer = (int *)_alloca(9);
}
typedef bool (__stdcall __stdcall *blarg)(int);
diff --git a/test/Parser/argument_redef.c b/test/Parser/argument_redef.c
index 1a43178..fd22c46 100644
--- a/test/Parser/argument_redef.c
+++ b/test/Parser/argument_redef.c
@@ -1,6 +1,6 @@
/* RUN: clang-cc -fsyntax-only -verify %s
*/
-int foo(int A) { /* expected-note {{previous definition is here}} */
+void foo(int A) { /* expected-note {{previous definition is here}} */
int A; /* expected-error {{redefinition of 'A'}} */
}
diff --git a/test/Parser/bad-control.c b/test/Parser/bad-control.c
index 6e59667..0bdd179 100644
--- a/test/Parser/bad-control.c
+++ b/test/Parser/bad-control.c
@@ -1,9 +1,9 @@
/* RUN: clang-cc -fsyntax-only -verify %s
*/
-int foo() {
+void foo() {
break; /* expected-error {{'break' statement not in loop or switch statement}} */
}
-int foo2() {
+void foo2() {
continue; /* expected-error {{'continue' statement not in loop statement}} */
}
diff --git a/test/Parser/cxx-ambig-paren-expr.cpp b/test/Parser/cxx-ambig-paren-expr.cpp
index 1712d84..324f6b5 100644
--- a/test/Parser/cxx-ambig-paren-expr.cpp
+++ b/test/Parser/cxx-ambig-paren-expr.cpp
@@ -5,9 +5,9 @@ void f() {
int x, *px;
// Type id.
- (T())x; // expected-error {{used type 'T ()'}}
- (T())+x; // expected-error {{used type 'T ()'}}
- (T())*px; // expected-error {{used type 'T ()'}}
+ (T())x; // expected-error {{cast from 'int' to 'T ()'}}
+ (T())+x; // expected-error {{cast from 'int' to 'T ()'}}
+ (T())*px; // expected-error {{cast from 'int' to 'T ()'}}
// Expression.
x = (T());
diff --git a/test/Parser/cxx-friend.cpp b/test/Parser/cxx-friend.cpp
index ea30ddc..14b31af 100644
--- a/test/Parser/cxx-friend.cpp
+++ b/test/Parser/cxx-friend.cpp
@@ -1,4 +1,4 @@
-// RUN: clang-cc -fsyntax-only %s
+// RUN: clang-cc -fsyntax-only -verify %s
class C {
friend class D;
@@ -6,12 +6,27 @@ class C {
class A {
public:
- void f();
+ void f();
+};
+
+friend int x; // expected-error {{'friend' used outside of class}}
+
+friend class D {}; // expected-error {{'friend' used outside of class}}
+
+union U {
+ int u1;
};
class B {
// 'A' here should refer to the declaration above.
friend class A;
- void f(A *a) { a->f(); }
+ friend C; // expected-error {{must specify 'class' to befriend}}
+ friend U; // expected-error {{must specify 'union' to befriend}}
+ friend int; // expected-error {{friends can only be classes or functions}}
+
+ friend void myfunc();
+
+ void f(A *a) { a->f(); }
};
+
diff --git a/test/Parser/cxx-member-initializers.cpp b/test/Parser/cxx-member-initializers.cpp
new file mode 100644
index 0000000..bebb5c5
--- /dev/null
+++ b/test/Parser/cxx-member-initializers.cpp
@@ -0,0 +1,10 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+struct x {
+ x() : a(4) ; // expected-error {{expected '{'}}
+};
+
+struct y {
+ int a;
+ y() : a(4) ; // expected-error {{expected '{'}}
+};
diff --git a/test/Parser/cxx-template-decl.cpp b/test/Parser/cxx-template-decl.cpp
index 6955018..9309b72 100644
--- a/test/Parser/cxx-template-decl.cpp
+++ b/test/Parser/cxx-template-decl.cpp
@@ -2,16 +2,17 @@
// 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 x; // expected-error {{C++ requires a type specifier for all declarations}} \
+ // expected-error {{does not refer}}
+export template x; // expected-error {{expected '<' after 'template'}}
+export template<class T> class x0; // expected-note {{exported templates are unsupported}}
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 <template X> struct Err1; // expected-error {{expected '<' after 'template'}} \
+// expected-error{{extraneous}}
+template <template <typename> > struct Err2; // expected-error {{expected 'class' before '>'}} \
+// expected-error{{extraneous}}
+template <template <typename> Foo> struct Err3; // expected-error {{expected 'class' before 'Foo'}} \
+// expected-error{{extraneous}}
// Template function declarations
template <typename T> void foo();
@@ -53,7 +54,7 @@ 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}}
+ typename T> // expected-error{{declaration of 'T' shadows template parameter}}
void shadow1();
template<typename T> // expected-note{{template parameter is declared here}}
diff --git a/test/Parser/cxx-using-declaration.cpp b/test/Parser/cxx-using-declaration.cpp
index de0e6f1..212a7d8 100644
--- a/test/Parser/cxx-using-declaration.cpp
+++ b/test/Parser/cxx-using-declaration.cpp
@@ -1,45 +1,47 @@
-// RUN: clang-cc -fsyntax-only -verify %s
-
-namespace A {
- int VA;
- void FA() {}
- struct SA { int V; };
-}
-
-using A::VA;
-using A::FA;
-using typename A::SA;
-
-void main()
-{
- VA = 1;
- FA();
- SA x; //Still needs handling.
-}
-
-struct B {
- void f(char){};
- void g(char){};
-};
-struct D : B {
- using B::f;
- void f(int);
- void g(int);
-};
-void D::f(int) { f('c'); } // calls B::f(char)
-void D::g(int) { g('c'); } // recursively calls D::g(int)
-
-namespace E {
- template <typename TYPE> int funcE(TYPE arg) { return(arg); }
-}
-
-using E::funcE<int>; // expected-error{{use of template specialization in using directive not allowed}}
-
-namespace F {
- struct X;
-}
-
-using F::X;
-// Should have some errors here. Waiting for implementation.
-void X(int);
-struct X *x;
+// FIXME: Disabled, appears to have undefined behavior, and needs to be updated to match new warnings.
+// RUN: true
+// RUNX: clang-cc -fsyntax-only -verify %s
+
+namespace A {
+ int VA;
+ void FA() {}
+ struct SA { int V; };
+}
+
+using A::VA;
+using A::FA;
+using typename A::SA;
+
+void main()
+{
+ VA = 1;
+ FA();
+ SA x; //Still needs handling.
+}
+
+struct B {
+ void f(char){};
+ void g(char){};
+};
+struct D : B {
+ using B::f;
+ void f(int);
+ void g(int);
+};
+void D::f(int) { f('c'); } // calls B::f(char)
+void D::g(int) { g('c'); } // recursively calls D::g(int)
+
+namespace E {
+ template <typename TYPE> int funcE(TYPE arg) { return(arg); }
+}
+
+using E::funcE<int>; // expected-error{{use of template specialization in using directive not allowed}}
+
+namespace F {
+ struct X;
+}
+
+using F::X;
+// Should have some errors here. Waiting for implementation.
+void X(int);
+struct X *x;
diff --git a/test/Parser/declarators.c b/test/Parser/declarators.c
index 26e8027..da8327a 100644
--- a/test/Parser/declarators.c
+++ b/test/Parser/declarators.c
@@ -18,7 +18,7 @@ int *A;
struct str;
-int test2(int *P, int A) {
+void test2(int *P, int A) {
struct str;
// Hard case for array decl, not Array[*].
@@ -26,11 +26,11 @@ int test2(int *P, int A) {
}
typedef int atype;
-int test3(x,
- atype /* expected-error {{unexpected type name 'atype': expected identifier}} */
- ) int x, atype; {}
+void 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'}} */
+void test4(x, x) int x; {} /* expected-error {{redefinition of parameter 'x'}} */
// PR3031
diff --git a/test/Parser/implicit-casts.c b/test/Parser/implicit-casts.c
index e7d2098..3e8f599 100644
--- a/test/Parser/implicit-casts.c
+++ b/test/Parser/implicit-casts.c
@@ -15,6 +15,7 @@ void test2() {
int test3() {
int a[2];
a[0] = test3; // expected-warning{{incompatible pointer to integer conversion assigning 'int ()', expected 'int'}}
+ return 0;
}
short x; void test4(char c) { x += c; }
int y; void test5(char c) { y += c; }
diff --git a/test/Parser/objc-messaging-neg-1.m b/test/Parser/objc-messaging-neg-1.m
index a1ec116..0344566 100644
--- a/test/Parser/objc-messaging-neg-1.m
+++ b/test/Parser/objc-messaging-neg-1.m
@@ -1,7 +1,6 @@
// RUN: clang-cc -fsyntax-only -verify %s
-int main()
- {
- id a;
- [a bla:0 6:7]; // expected-error {{expected ']'}}
- }
+int main() {
+ id a;
+ [a bla:0 6:7]; // expected-error {{expected ']'}}
+}
diff --git a/test/Parser/pointer_promotion.c b/test/Parser/pointer_promotion.c
index 0254828..3226eab 100644
--- a/test/Parser/pointer_promotion.c
+++ b/test/Parser/pointer_promotion.c
@@ -1,6 +1,6 @@
// RUN: clang-cc -fsyntax-only -verify %s
-int test() {
+void test() {
void *vp;
int *ip;
char *cp;
@@ -15,4 +15,3 @@ int test() {
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-weak.c b/test/Parser/pragma-weak.c
index 355a954..dca0f8d 100644
--- a/test/Parser/pragma-weak.c
+++ b/test/Parser/pragma-weak.c
@@ -10,7 +10,7 @@ int x;
extern int z;
/* expected-warning {{expected identifier in '#pragma weak'}}*/ #pragma weak z = =
/* expected-warning {{expected identifier in '#pragma weak'}}*/ #pragma weak z =
-#pragma weak z = y
+/* expected-warning {{weak identifier 'y' never declared}} */ #pragma weak z = y
extern int a;
/* expected-warning {{extra tokens at end of '#pragma weak'}}*/ #pragma weak a b
diff --git a/test/Parser/recovery.c b/test/Parser/recovery.c
index 89eac56..43d3e2d 100644
--- a/test/Parser/recovery.c
+++ b/test/Parser/recovery.c
@@ -8,10 +8,10 @@ float test2241[2] = {
// 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}}
+static void 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}}
}
@@ -20,7 +20,7 @@ static char *f (char * (*g) (char **, int), char **p, ...) {
// rdar://6094870
-int test(int a) {
+void test(int a) {
struct { int i; } x;
if (x.hello) // expected-error {{no member named 'hello'}}
@@ -61,7 +61,7 @@ struct S A = {
};
// rdar://6248081
-int test6248081() {
+void test6248081() {
[10] // expected-error {{expected expression}}
}
diff --git a/test/Parser/statements.c b/test/Parser/statements.c
index b95c23f..25e06a2 100644
--- a/test/Parser/statements.c
+++ b/test/Parser/statements.c
@@ -1,24 +1,24 @@
// RUN: clang-cc -fsyntax-only -verify %s
-int test1() {
+void test1() {
{ ; { ;;}} ;;
}
-int test2() {
+void test2() {
if (0) { if (1) {} } else { }
do { } while (0);
while (0) while(0) do ; while(0);
- for (0;0;0)
+ for ((void)0;0;(void)0)
for (;;)
- for (9;0;2)
+ for ((void)9;0;(void)2)
;
- for (int X = 0; 0; 0);
+ for (int X = 0; 0; (void)0);
}
-int test3() {
+void test3() {
switch (0) {
case 4:
@@ -30,7 +30,7 @@ int test3() {
}
}
-int test4() {
+void test4() {
if (0); // expected-warning {{if statement has empty body}}
int X; // declaration in a block.
diff --git a/test/Parser/top-level-semi-cxx0x.cpp b/test/Parser/top-level-semi-cxx0x.cpp
new file mode 100644
index 0000000..e83fd9e
--- /dev/null
+++ b/test/Parser/top-level-semi-cxx0x.cpp
@@ -0,0 +1,15 @@
+// RUN: clang-cc -fsyntax-only -pedantic -std=c++0x -verify %s
+
+void foo();
+
+void bar() { };
+
+void wibble();
+
+;
+
+namespace Blah {
+ void f() { };
+
+ void g();
+}
diff --git a/test/Preprocessor/assembler-with-cpp.c b/test/Preprocessor/assembler-with-cpp.c
index 2e84ed1..f7706ca 100644
--- a/test/Preprocessor/assembler-with-cpp.c
+++ b/test/Preprocessor/assembler-with-cpp.c
@@ -40,7 +40,7 @@
// rdar://6709206
// RUN: grep "5: expanded (" %t &&
#define M4 expanded
-#define M5() M4 ## (
+#define M5() M4 ## (
5: M5()
diff --git a/test/Preprocessor/macro-multiline.c b/test/Preprocessor/macro-multiline.c
index eb15668..ba98825 100644
--- a/test/Preprocessor/macro-multiline.c
+++ b/test/Preprocessor/macro-multiline.c
@@ -1,4 +1,4 @@
-// RUN: clang -E %s "-DX=A
+// 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
diff --git a/test/Preprocessor/macro_fn_comma_swallow.c b/test/Preprocessor/macro_fn_comma_swallow.c
index e985138..d39d4e7 100644
--- a/test/Preprocessor/macro_fn_comma_swallow.c
+++ b/test/Preprocessor/macro_fn_comma_swallow.c
@@ -1,7 +1,7 @@
// 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}'
+// RUN: clang-cc %s -E | grep '{foo}' &&
#define X(Y) foo{A, Y}
X()
diff --git a/test/Preprocessor/macro_paste_mscomment.c b/test/Preprocessor/macro_paste_mscomment.c
index b0fc571..d6ead91 100644
--- a/test/Preprocessor/macro_paste_mscomment.c
+++ b/test/Preprocessor/macro_paste_mscomment.c
@@ -1,5 +1,5 @@
-// RUN: clang-cc -P -E -fms-extensions %s | sed '/^#.\+/d' | tr -d '\n' |
-// RUN: grep '^int foo;int bar;int baz;$' | count 1
+// RUN: clang-cc -P -E -fms-extensions %s | sed '/^#.\+/d' | tr -d '\n' > %t &&
+// RUN: grep '^int foo;int bar;int baz;$' %t | count 1
// This horrible stuff should preprocess into (other than whitespace):
// int foo;
// int bar;
diff --git a/test/Preprocessor/non_fragile_feature.m b/test/Preprocessor/non_fragile_feature.m
new file mode 100644
index 0000000..cb6bc01
--- /dev/null
+++ b/test/Preprocessor/non_fragile_feature.m
@@ -0,0 +1,8 @@
+// RUN: clang-cc -fobjc-nonfragile-abi %s
+#ifndef __has_feature
+#error Should have __has_feature
+#endif
+
+#if !__has_feature(objc_nonfragile_abi)
+#error Non-fragile ABI used for compilation but feature macro not set.
+#endif
diff --git a/test/Preprocessor/non_fragile_feature1.m b/test/Preprocessor/non_fragile_feature1.m
new file mode 100644
index 0000000..59f665b
--- /dev/null
+++ b/test/Preprocessor/non_fragile_feature1.m
@@ -0,0 +1,8 @@
+// RUN: clang-cc -triple i386-unknown-unknown %s
+#ifndef __has_feature
+#error Should have __has_feature
+#endif
+
+#if __has_feature(objc_nonfragile_abi)
+#error Non-fragile ABI not used for compilation but feature macro set.
+#endif
diff --git a/test/Preprocessor/pushable-diagnostics.c b/test/Preprocessor/pushable-diagnostics.c
new file mode 100644
index 0000000..fe55122
--- /dev/null
+++ b/test/Preprocessor/pushable-diagnostics.c
@@ -0,0 +1,17 @@
+// RUN: clang-cc -fsyntax-only -verify -pedantic %s
+
+#pragma clang diagnostic pop // expected-warning{{pragma diagnostic pop could not pop, no matching push}}
+
+#pragma clang diagnostic puhs // expected-warning{{pragma diagnostic expected 'error', 'warning', 'ignored', 'fatal' 'push', or 'pop'}}
+
+char a = 'df'; // expected-warning{{multi-character character constant}}
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wmultichar"
+
+char b = 'df'; // no warning.
+#pragma clang diagnostic pop
+
+char c = 'df'; // expected-warning{{multi-character character constant}}
+
+#pragma clang diagnostic pop // expected-warning{{pragma diagnostic pop could not pop, no matching push}}
diff --git a/test/Rewriter/id-test-3.m b/test/Rewriter/id-test-3.m
index ad1e76d..7e4cc51d 100644
--- a/test/Rewriter/id-test-3.m
+++ b/test/Rewriter/id-test-3.m
@@ -10,5 +10,5 @@
@implementation INTF
- (id<P>)IMeth { return [(id<P>)self Meth: (id<P>)0]; }
-- (id<P>) Meth : (id<P>) Arg {}
+- (id<P>) Meth : (id<P>) Arg { return 0; }
@end
diff --git a/test/Rewriter/method-encoding-1.m b/test/Rewriter/method-encoding-1.m
index 25dccbf..05df602 100644
--- a/test/Rewriter/method-encoding-1.m
+++ b/test/Rewriter/method-encoding-1.m
@@ -11,8 +11,8 @@
@end
@implementation Intf
-- (char *) MyMeth : (double) arg1 : (char *[12]) arg2{}
+- (char *) MyMeth : (double) arg1 : (char *[12]) arg2{ return 0; }
- (void) MyProtoMeth : (int **) arg1 : (void*) arg2 {}
+ (void) MyProtoMeth : (int **) arg1 : (void*) arg2 {}
-- (id) address:(void *)location with:(unsigned **)arg2{}
+- (id) address:(void *)location with:(unsigned **)arg2{ return 0; }
@end
diff --git a/test/Rewriter/rewrite-foreach-4.m b/test/Rewriter/rewrite-foreach-4.m
index 774f9a0..5c831ea 100644
--- a/test/Rewriter/rewrite-foreach-4.m
+++ b/test/Rewriter/rewrite-foreach-4.m
@@ -9,7 +9,7 @@
{
return 0;
}
-- (id) allKeys {}
+- (id) allKeys { return 0; }
@end
@interface MyList (BasicTest)
diff --git a/test/Rewriter/rewrite-foreach-5.m b/test/Rewriter/rewrite-foreach-5.m
index d0d1244..d03f6ce 100644
--- a/test/Rewriter/rewrite-foreach-5.m
+++ b/test/Rewriter/rewrite-foreach-5.m
@@ -9,7 +9,7 @@
{
return 0;
}
-- (id) allKeys {}
+- (id) allKeys { return 0; }
@end
@interface MyList (BasicTest)
diff --git a/test/Sema/address_spaces.c b/test/Sema/address_spaces.c
index b79799f..d9d23ed 100644
--- a/test/Sema/address_spaces.c
+++ b/test/Sema/address_spaces.c
@@ -4,7 +4,11 @@
#define _AS2 __attribute__((address_space(2)))
#define _AS3 __attribute__((address_space(3)))
-void foo(_AS3 float *a) {
+void bar(_AS2 int a); // expected-error {{parameter may not be qualified with an address space}}
+
+void foo(_AS3 float *a,
+ _AS1 float b) // expected-error {{parameter may not be qualified with an address space}}
+{
_AS2 *x;// expected-warning {{type specifier missing, defaults to 'int'}}
_AS1 float * _AS2 *B;
@@ -15,7 +19,13 @@ void foo(_AS3 float *a) {
_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;
+ __attribute__((address_space(-1))) int *_boundsA; // expected-error {{address space is negative}}
+ __attribute__((address_space(0xFFFFFF))) int *_boundsB;
+ __attribute__((address_space(0x1000000))) int *_boundsC; // expected-error {{address space is larger than the maximum supported}}
+ // chosen specifically to overflow 32 bits and come out reasonable
+ __attribute__((address_space(4294967500))) int *_boundsD; // expected-error {{address space is larger than the maximum supported}}
+
+ *a = 5.0f + b;
}
struct _st {
@@ -27,6 +37,6 @@ struct _st {
__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 *'}}
+ expected-warning {{returning 'void __attribute__((address_space(256))) *' discards qualifiers, expected 'void *'}}
}
diff --git a/test/Sema/align-arm-apcs.c b/test/Sema/align-arm-apcs.c
new file mode 100644
index 0000000..924ba90
--- /dev/null
+++ b/test/Sema/align-arm-apcs.c
@@ -0,0 +1,4 @@
+// RUN: clang-cc -triple arm-unknown-unknown -target-abi=apcs-gnu -fsyntax-only -verify %s
+
+struct s0 { double f0; int f1; };
+char chk0[__alignof__(struct s0) == 4 ? 1 : -1];
diff --git a/test/Sema/altivec-init.c b/test/Sema/altivec-init.c
new file mode 100644
index 0000000..6185186
--- /dev/null
+++ b/test/Sema/altivec-init.c
@@ -0,0 +1,16 @@
+// RUN: clang-cc %s -faltivec -verify -pedantic -fsyntax-only -fblocks=0
+
+typedef int v4 __attribute((vector_size(16)));
+typedef short v8 __attribute((vector_size(16)));
+
+v8 foo(void) {
+ v8 a;
+ v4 b;
+ a = (v8){4, 2}; // expected-error {{too few elements in vector initialization (expected 8 elements, have 2)}}
+ b = (v4)(5, 6, 7, 8, 9); // expected-warning {{excess elements in vector initializer}}
+ b = (v4)(5, 6, 8, 8.0f);
+ return (v8){0, 1, 2, 3, 1, 2, 3, 4};
+
+ // FIXME: test that (type)(fn)(args) still works with -faltivec
+ // FIXME: test that c++ overloaded commas still work -faltivec
+}
diff --git a/test/Sema/arg-scope-c99.c b/test/Sema/arg-scope-c99.c
index b5b1c8a..1d81410 100644
--- a/test/Sema/arg-scope-c99.c
+++ b/test/Sema/arg-scope-c99.c
@@ -1,2 +1,2 @@
// RUN: clang-cc -fsyntax-only -std=c99 -verify %s
-int bb(int sz, int ar[sz][sz]) { }
+void bb(int sz, int ar[sz][sz]) { }
diff --git a/test/Sema/arg-scope.c b/test/Sema/arg-scope.c
index c1cc7e1..d5e5960 100644
--- a/test/Sema/arg-scope.c
+++ b/test/Sema/arg-scope.c
@@ -1,5 +1,5 @@
// RUN: clang-cc -fsyntax-only -verify %s
-int aa(int b, int x[sizeof b]) {}
+void 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
index 5a09e20..6407b5d 100644
--- a/test/Sema/array-constraint.c
+++ b/test/Sema/array-constraint.c
@@ -45,7 +45,7 @@ typedef int TA[I]; // expected-error {{variable length array declaration not all
void strFunc(char *);
const char staticAry[] = "test";
-int checkStaticAry() {
+void checkStaticAry() {
strFunc(staticAry); // expected-warning{{passing 'char const [5]' discards qualifiers, expected 'char *'}}
}
diff --git a/test/Sema/array-init.c b/test/Sema/array-init.c
index 50148a8..c78fd29 100644
--- a/test/Sema/array-init.c
+++ b/test/Sema/array-init.c
@@ -144,12 +144,11 @@ 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}}
+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" };
@@ -219,10 +218,10 @@ void varArray() {
}
// PR2151
-int emptyInit() {struct {} x[] = {6};} //expected-warning{{empty struct extension}} expected-error{{initializer for aggregate with no elements}}
+void 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}}
+void 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];
@@ -230,15 +229,15 @@ int noNamedImplicitCheck[sizeof(noNamedImplicit) == 3 * sizeof(*noNamedImplicit)
// ptrs are constant
struct soft_segment_descriptor {
- long ssd_base;
+ long ssd_base;
};
static int dblfault_tss;
union uniao { int ola; } xpto[1];
struct soft_segment_descriptor gdt_segs[] = {
- {(long) &dblfault_tss},
- { (long)xpto},
+ {(long) &dblfault_tss},
+ { (long)xpto},
};
static void sppp_ipv6cp_up();
diff --git a/test/Sema/attr-decl-after-definition.c b/test/Sema/attr-decl-after-definition.c
new file mode 100644
index 0000000..c1d1b53
--- /dev/null
+++ b/test/Sema/attr-decl-after-definition.c
@@ -0,0 +1,19 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+void foo();
+void foo() __attribute__((unused));
+void foo() __attribute__((unused));
+void foo(){} // expected-note {{previous definition is here}}
+void foo() __attribute__((constructor)); // expected-warning {{must precede definition}}
+void foo();
+
+int bar;
+extern int bar;
+int bar;
+int bar __attribute__((weak));
+int bar __attribute__((used));
+extern int bar __attribute__((weak));
+int bar = 0; // expected-note {{previous definition is here}}
+int bar __attribute__((weak)); // expected-warning {{must precede definition}}
+int bar;
+
diff --git a/test/Sema/attr-deprecated.c b/test/Sema/attr-deprecated.c
index 6597bad..e15381e 100644
--- a/test/Sema/attr-deprecated.c
+++ b/test/Sema/attr-deprecated.c
@@ -21,7 +21,7 @@ int a() {
// test if attributes propagate to variables
extern int var;
int w() {
- return var; // expected-warning {{'var' is deprecated}}
+ return var; // expected-warning {{'var' is deprecated}}
}
int old_fn() __attribute__ ((deprecated));
diff --git a/test/Sema/attr-format_arg.c b/test/Sema/attr-format_arg.c
index 6f95315..0830951 100644
--- a/test/Sema/attr-format_arg.c
+++ b/test/Sema/attr-format_arg.c
@@ -1,3 +1,5 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
#include <stdio.h>
const char* f(const char *s) __attribute__((format_arg(1)));
diff --git a/test/Sema/attr-malloc.c b/test/Sema/attr-malloc.c
new file mode 100644
index 0000000..1adcf07
--- /dev/null
+++ b/test/Sema/attr-malloc.c
@@ -0,0 +1,25 @@
+// RUN: clang-cc -verify -fsyntax-only %s &&
+// RUN: clang-cc -emit-llvm -o %t %s &&
+
+#include <stdlib.h>
+
+int no_vars __attribute((malloc)); // expected-warning {{functions returning a pointer type}}
+
+void returns_void (void) __attribute((malloc)); // expected-warning {{functions returning a pointer type}}
+int returns_int (void) __attribute((malloc)); // expected-warning {{functions returning a pointer type}}
+int * returns_intptr(void) __attribute((malloc)); // no-warning
+typedef int * iptr;
+iptr returns_iptr (void) __attribute((malloc)); // no-warning
+
+__attribute((malloc)) void *(*f)(); // expected-warning{{'malloc' attribute only applies to functions returning a pointer type}}
+__attribute((malloc)) int (*g)(); // expected-warning{{'malloc' attribute only applies to functions returning a pointer type}}
+
+__attribute((malloc))
+void * xalloc(unsigned n) { return malloc(n); } // no-warning
+// RUN: grep 'define noalias .* @xalloc(' %t &&
+
+#define malloc_like __attribute((__malloc__))
+void * xalloc2(unsigned) malloc_like;
+void * xalloc2(unsigned n) { return malloc(n); }
+// RUN: grep 'define noalias .* @xalloc2(' %t
+
diff --git a/test/Sema/attr-noreturn.c b/test/Sema/attr-noreturn.c
index d1417f0..b83eb94 100644
--- a/test/Sema/attr-noreturn.c
+++ b/test/Sema/attr-noreturn.c
@@ -4,7 +4,7 @@ static void (*fp0)(void) __attribute__((noreturn));
static void __attribute__((noreturn)) f0(void) {
fatal();
-}
+} // expected-warning {{function declared 'noreturn' should not return}}
// On K&R
int f1() __attribute__((noreturn));
@@ -25,3 +25,11 @@ void f4() {
return; // expected-warning {{function 'f4' declared 'noreturn' should not return}}
}
+// PR4685
+extern void f5 (unsigned long) __attribute__ ((__noreturn__));
+
+void
+f5 (unsigned long size)
+{
+
+}
diff --git a/test/Sema/attr-section.c b/test/Sema/attr-section.c
new file mode 100644
index 0000000..c61ed80
--- /dev/null
+++ b/test/Sema/attr-section.c
@@ -0,0 +1,10 @@
+// RUN: clang-cc -verify -fsyntax-only -triple x86_64-apple-darwin9 %s
+
+int x __attribute__((section(
+ 42))); // expected-error {{argument to section attribute was not a string literal}}
+
+
+// rdar://4341926
+int y __attribute__((section(
+ "sadf"))); // expected-error {{mach-o section specifier requires a segment and section separated by a comma}}
+
diff --git a/test/Sema/attr-weak.c b/test/Sema/attr-weak.c
index b79e1e7..4532ccc 100644
--- a/test/Sema/attr-weak.c
+++ b/test/Sema/attr-weak.c
@@ -5,9 +5,11 @@ 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) {
+void __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}}
+static int x __attribute__((weak)); // expected-error {{weak declaration of 'x' must be public}}
+
diff --git a/test/Sema/bitfield-promote-int-16bit.c b/test/Sema/bitfield-promote-int-16bit.c
new file mode 100644
index 0000000..12d4720
--- /dev/null
+++ b/test/Sema/bitfield-promote-int-16bit.c
@@ -0,0 +1,25 @@
+// RUN: clang-cc -fsyntax-only -verify %s -triple pic16-unknown-unknown
+
+// Check that int-sized unsigned bit-fields promote to unsigned int
+// on targets where sizeof(unsigned short) == sizeof(unsigned int)
+
+enum E { ec1, ec2, ec3 };
+struct S {
+ enum E e : 16;
+ unsigned short us : 16;
+ unsigned long ul1 : 8;
+ unsigned long ul2 : 16;
+} s;
+
+__typeof(s.e + s.e) x_e;
+unsigned x_e;
+
+__typeof(s.us + s.us) x_us;
+unsigned x_us;
+
+__typeof(s.ul1 + s.ul1) x_ul1;
+signed x_ul1;
+
+__typeof(s.ul2 + s.ul2) x_ul2;
+unsigned x_ul2;
+
diff --git a/test/Sema/bitfield-promote.c b/test/Sema/bitfield-promote.c
new file mode 100644
index 0000000..066f5d7
--- /dev/null
+++ b/test/Sema/bitfield-promote.c
@@ -0,0 +1,34 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+struct {unsigned x : 2;} x;
+__typeof__((x.x+=1)+1) y;
+__typeof__(x.x<<1) y;
+int y;
+
+
+struct { int x : 8; } x1;
+long long y1;
+__typeof__(((long long)x1.x + 1)) y1;
+
+
+// Check for extensions: variously sized unsigned bit-fields fitting
+// into a signed int promote to signed int.
+enum E { ec1, ec2, ec3 };
+struct S {
+ enum E e : 2;
+ unsigned short us : 4;
+ unsigned long long ul1 : 8;
+ unsigned long long ul2 : 50;
+} s;
+
+__typeof(s.e + s.e) x_e;
+int x_e;
+
+__typeof(s.us + s.us) x_us;
+int x_us;
+
+__typeof(s.ul1 + s.ul1) x_ul1;
+int x_ul1;
+
+__typeof(s.ul2 + s.ul2) x_ul2;
+unsigned long long x_ul2;
+
diff --git a/test/Sema/bitfield.c b/test/Sema/bitfield.c
index 655f741..581af6d 100644
--- a/test/Sema/bitfield.c
+++ b/test/Sema/bitfield.c
@@ -21,7 +21,7 @@ struct a {
int g : (_Bool)1;
// PR4017
- char : 10; // expected-error {{size of anonymous bitfield exceeds size of its type (8 bits)}}
+ char : 10; // expected-error {{size of anonymous bit-field 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'}}
};
diff --git a/test/Sema/block-args.c b/test/Sema/block-args.c
index 27bee77..3a58735 100644
--- a/test/Sema/block-args.c
+++ b/test/Sema/block-args.c
@@ -22,7 +22,7 @@ void test() {
^(int x, ...){return 5;}(arg, arg); // Explicit varargs, ok.
}
-int main(int argc) {
+int main(int argc, char** argv) {
^(int argCount) {
argCount = 3;
}(argc);
diff --git a/test/Sema/block-call.c b/test/Sema/block-call.c
index c42b642..893a8f6 100644
--- a/test/Sema/block-call.c
+++ b/test/Sema/block-call.c
@@ -5,51 +5,47 @@ 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; // OK
- PFR = II; // OK
-
- int (^IFP) () = PFR; // OK
-
+ PFR = II; // OK
- const int (^CIC) () = IFP; // expected-error {{incompatible block pointer types initializing 'int (^)()', expected 'int const (^)()'}}
+ int (^IFP) () = PFR; // OK
- const int (^CICC) () = CIC;
+ const int (^CIC) () = IFP; // expected-error {{incompatible block pointer types initializing 'int (^)()', expected 'int const (^)()'}}
- int * const (^IPCC) () = 0;
+ const int (^CICC) () = CIC;
- int * const (^IPCC1) () = IPCC;
+ int * const (^IPCC) () = 0;
- int * (^IPCC2) () = IPCC; // expected-error {{incompatible block pointer types initializing 'int *const (^)()', expected 'int *(^)()'}}
+ int * const (^IPCC1) () = IPCC;
- int (^IPCC3) (const int) = PFR;
+ 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 (^IPCC4) (int, char (^CArg) (double));
+ int (^IPCC5) (int, char (^CArg) (double)) = IPCC4;
- 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))'}}
- 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 (^)()'}}
+ 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);
+ int (^IFP) (float);
+ char (^PCP)(double, double, char);
- IFP(1.0);
- IFP (1.0, 2.0); // expected-error {{too many arguments to block call}}
+ 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}}
+ 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-literal.c b/test/Sema/block-literal.c
index 19d476f..9f5022d 100644
--- a/test/Sema/block-literal.c
+++ b/test/Sema/block-literal.c
@@ -8,40 +8,40 @@ int printf(const char*, ...);
typedef void (^T) (void);
-void takeclosure(T);
+void takeblock(T);
int takeintint(int (^C)(int)) { return C(4); }
T somefunction() {
- if (^{ })
- nothing();
+ if (^{ })
+ nothing();
- noop = ^{};
+ noop = ^{};
- noop = ^{printf("\nClosure\n"); };
+ noop = ^{printf("\nClosure\n"); };
- I(^{ });
+ I(^{ });
- return ^{printf("\nClosure\n"); };
+ return ^{printf("\nClosure\n"); };
}
void test2() {
- int x = 4;
+ int x = 4;
- takeclosure(^{ printf("%d\n", x); });
+ takeblock(^{ 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}}
- });
+ takeblock(^{
+ 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)}}
+ foo:
+ takeblock(^{ 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; });
+ takeblock(^{ y = 8; });
}
@@ -59,11 +59,11 @@ void myfunc(int (^block)(int)) {}
void myfunc3(const int *x);
void test5() {
- int a;
+ int a;
- myfunc(^(int abcd) {
- myfunc3(&a);
- return 1;
+ myfunc(^(int abcd) {
+ myfunc3(&a);
+ return 1;
});
}
@@ -86,39 +86,3 @@ 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
index 294c295..8661fd8 100644
--- a/test/Sema/block-misc.c
+++ b/test/Sema/block-misc.c
@@ -4,37 +4,37 @@ void donotwarn();
int (^IFP) ();
int (^II) (int);
int test1() {
- int (^PFR) (int) = 0; // OK
- PFR = II; // OK
+ int (^PFR) (int) = 0; // OK
+ PFR = II; // OK
- if (PFR == II) // OK
+ if (PFR == II) // OK
donotwarn();
- if (PFR == IFP) // OK
+ if (PFR == IFP) // OK
donotwarn();
if (PFR == (int (^) (int))IFP) // OK
donotwarn();
- if (PFR == 0) // OK
+ if (PFR == 0) // OK
donotwarn();
- if (PFR) // OK
+ if (PFR) // OK
donotwarn();
- if (!PFR) // OK
+ if (!PFR) // OK
donotwarn();
- return PFR != IFP; // OK
+ return PFR != IFP; // OK
}
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*)I = (void *)S; // expected-error {{assignment to cast is illegal, lvalue casts are not supported}}
void *pv = I;
- pv = S;
+ pv = S;
I(1);
@@ -44,7 +44,7 @@ int test2(double (^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() {
+void test3() {
char *^ y; // expected-error {{block pointer to non-function type is invalid}}
}
@@ -114,7 +114,7 @@ void test11(int i) {
void (^test12f)(void);
void test12() {
- test12f = ^test12f; // expected-error {{type name requires a specifier or qualifier}} expected-error {{expected expression}}
+ test12f = ^test12f; // expected-error {{type name requires a specifier or qualifier}} expected-error {{expected expression}}
}
// rdar://6808730
@@ -144,7 +144,7 @@ void foo(long (^comp)()) {
void (^test15f)(void);
void test15() {
- foo(^{ return LESS; }); // expected-error {{incompatible block pointer types passing 'int (^)(void)', expected 'long (^)()'}}
+ 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}}
@@ -185,3 +185,16 @@ void test18() {
void (^const blockA)(void) = ^{ };
blockA = ^{ }; // expected-error {{read-only variable is not assignable}}
}
+
+// rdar://7072507
+int test19() {
+ goto L0; // expected-error {{illegal goto into protected scope}}
+
+ __block int x; // expected-note {{jump bypasses setup of __block variable}}
+L0:
+ x = 0;
+ ^(){ ++x; }();
+ return x;
+}
+
+
diff --git a/test/Sema/block-printf-attribute-1.c b/test/Sema/block-printf-attribute-1.c
index ce30b8e..4941ae7 100644
--- a/test/Sema/block-printf-attribute-1.c
+++ b/test/Sema/block-printf-attribute-1.c
@@ -1,15 +1,12 @@
// 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}}
+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
+ 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-1.c b/test/Sema/block-return-1.c
new file mode 100644
index 0000000..2da8735
--- /dev/null
+++ b/test/Sema/block-return-1.c
@@ -0,0 +1,6 @@
+// RUN: clang-cc -fsyntax-only %s -verify -fblocks
+
+int j;
+void foo() {
+ ^ (void) { if (j) return 1; }(); // expected-error {{control may reach end of non-void block}}
+}
diff --git a/test/Sema/block-return-2.c b/test/Sema/block-return-2.c
new file mode 100644
index 0000000..d389f4e
--- /dev/null
+++ b/test/Sema/block-return-2.c
@@ -0,0 +1,5 @@
+// RUN: clang-cc -fsyntax-only %s -verify -fblocks
+
+void foo() {
+ ^ (void) __attribute__((noreturn)) { }(); // expected-error {{block declared 'noreturn' should not return}}
+}
diff --git a/test/Sema/block-return-3.c b/test/Sema/block-return-3.c
new file mode 100644
index 0000000..e7e9342
--- /dev/null
+++ b/test/Sema/block-return-3.c
@@ -0,0 +1,5 @@
+// RUN: clang-cc -fsyntax-only %s -verify -fblocks
+
+void foo() {
+ ^ int (void) { }(); // expected-error {{control reaches end of non-void block}}
+}
diff --git a/test/Sema/block-return.c b/test/Sema/block-return.c
index 87f4040..98a7273 100644
--- a/test/Sema/block-return.c
+++ b/test/Sema/block-return.c
@@ -31,7 +31,7 @@ CL foo() {
return (float)1.0;
else
if (2)
- return (double)2.0;
+ return (double)2.0;
return 1;
};
char *(^B)(void) = ^{
@@ -66,7 +66,7 @@ int foo3() {
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);
+ return (Boolean)(uintptr_t)INVOKE_CALLBACK2(value_equal, (uintptr_t)stack_value_or_key1, (uintptr_t)stack_value_or_key2);
};
}
@@ -91,6 +91,8 @@ bptr foo5(int j) {
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}}
+ return (^{ i=0; }); // expected-error {{returning block that lives on the local stack}}
+ return (void*)(^{ i=0; }); // expected-error {{returning block that lives on the local stack}}
}
int (*funcptr3[5])(long);
diff --git a/test/Sema/block-sentinel-attribute.c b/test/Sema/block-sentinel-attribute.c
index a7d4df1..5628a2c 100644
--- a/test/Sema/block-sentinel-attribute.c
+++ b/test/Sema/block-sentinel-attribute.c
@@ -2,24 +2,23 @@
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}}
+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}}
+ 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
+ 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", 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
+ y(1, "%s", (void*)0,3,4,5,6,7); // OK
}
diff --git a/test/Sema/builtin-prefetch.c b/test/Sema/builtin-prefetch.c
index 6b39e75..bf28277 100644
--- a/test/Sema/builtin-prefetch.c
+++ b/test/Sema/builtin-prefetch.c
@@ -1,6 +1,6 @@
// RUN: clang-cc -fsyntax-only -verify %s
-int foo() {
+void foo() {
int a;
__builtin_prefetch(&a);
__builtin_prefetch(&a, 1);
diff --git a/test/Sema/builtin-unary-fp.c b/test/Sema/builtin-unary-fp.c
new file mode 100644
index 0000000..70c7a29
--- /dev/null
+++ b/test/Sema/builtin-unary-fp.c
@@ -0,0 +1,12 @@
+// RUN: clang-cc %s -fsyntax-only -verify -pedantic
+void check(int);
+void a() {
+ check(__builtin_isfinite(1.0f));
+ check(__builtin_isinf(1.0));
+ check(__builtin_isinf_sign(1.0L));
+ check(__builtin_isnan(1.0f));
+ check(__builtin_isnormal(1.0f));
+ check(__builtin_isfinite(1)); // expected-error{{requires argument of floating point type}}
+ check(__builtin_isinf()); // expected-error{{too few arguments}}
+ check(__builtin_isnan(1,2)); // expected-error{{too many arguments}}
+}
diff --git a/test/Sema/builtins.c b/test/Sema/builtins.c
index 78b7562..e133d62 100644
--- a/test/Sema/builtins.c
+++ b/test/Sema/builtins.c
@@ -34,10 +34,40 @@ void test7() {
// atomics.
-unsigned char test9(short v) {
+void 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}}
}
+
+
+// rdar://7236819
+void test10(void) __attribute__((noreturn));
+
+void test10(void) {
+ __asm__("int3");
+ __builtin_unreachable();
+
+ // No warning about falling off the end of a noreturn function.
+}
+
+void test11(int X) {
+ switch (X) {
+ case __builtin_eh_return_data_regno(0): // constant foldable.
+ break;
+ }
+
+ __builtin_eh_return_data_regno(X); // expected-error {{not an integer constant expression}}
+}
+
+// PR5062
+void test12(void) __attribute__((__noreturn__));
+void test12(void) {
+ __builtin_trap(); // no warning because trap is noreturn.
+}
+
+void test_unknown_builtin(int a, int b) {
+ __builtin_foo(a, b); // expected-error{{use of unknown builtin}}
+}
diff --git a/test/Sema/c89-2.c b/test/Sema/c89-2.c
index 723bd7c..50c5f4e 100644
--- a/test/Sema/c89-2.c
+++ b/test/Sema/c89-2.c
@@ -1,7 +1,5 @@
-/* RUN: not clang-cc %s -std=c89 -pedantic-errors
+/* RUN: clang-cc %s -std=c89 -pedantic-errors -verify
*/
-/* We can't put expected-warning lines on #if lines. */
-
-#if 1LL /* expected-warning {{long long}} */
+#if 1LL /* expected-error {{long long}} */
#endif
diff --git a/test/Sema/c89.c b/test/Sema/c89.c
index e7585c3..fc50ebe 100644
--- a/test/Sema/c89.c
+++ b/test/Sema/c89.c
@@ -25,7 +25,7 @@ void test3(int i) {
int A[i]; /* expected-warning {{variable length array}} */
}
-int test4 = 0LL; /* expected-warning {{long long}} */
+int test4 = 0LL; /* expected-warning {{long long}} */
/* PR1999 */
void test5(register);
@@ -36,7 +36,7 @@ int *__restrict; /* expected-error {{expected identifier}} */
/* Implicit int, always ok */
-test6() {}
+test6() { return 0; }
/* PR2012 */
test7; /* expected-warning {{declaration specifier missing, defaulting to 'int'}} */
diff --git a/test/Sema/compare.c b/test/Sema/compare.c
index 51f7731..87131bb 100644
--- a/test/Sema/compare.c
+++ b/test/Sema/compare.c
@@ -3,11 +3,11 @@
int test(char *C) { // nothing here should warn.
return C != ((void*)0);
return C != (void*)0;
- return C != 0;
+ return C != 0;
+ return C != 1; // expected-warning {{comparison between pointer and integer ('char *' and 'int')}}
}
-int equal(char *a, const char *b)
-{
+int equal(char *a, const char *b) {
return a == b;
}
@@ -16,16 +16,21 @@ int arrays(char (*a)[5], char(*b)[10], char(*c)[5]) {
return a == b; // expected-warning {{comparison of distinct pointer types}}
}
-int pointers(int *a)
-{
- return a > 0; // expected-warning {{ordered comparison between pointer and integer}}
+int pointers(int *a) {
+ return a > 0; // expected-warning {{ordered comparison between pointer and zero ('int *' and 'int') is an extension}}
+ return a > 42; // expected-warning {{ordered comparison between pointer and integer ('int *' and 'int')}}
return a > (void *)0; // expected-warning {{comparison of distinct pointer types}}
}
-int function_pointers(int (*a)(int), int (*b)(int))
-{
+int function_pointers(int (*a)(int), int (*b)(int), void (*c)(int)) {
return a > b; // expected-warning {{ordered comparison of function pointers}}
return function_pointers > function_pointers; // expected-warning {{ordered comparison of function pointers}}
+ return a > c; // expected-warning {{comparison of distinct pointer types}}
return a == (void *) 0;
- return a == (void *) 1; // expected-warning {{comparison of distinct pointer types}}
+ return a == (void *) 1; // expected-warning {{equality comparison between function pointer and void pointer}}
+}
+
+int void_pointers(void* foo) {
+ return foo == (void*) 0;
+ return foo == (void*) 1;
}
diff --git a/test/Sema/complex-int.c b/test/Sema/complex-int.c
index 5977b4d..6c66089 100644
--- a/test/Sema/complex-int.c
+++ b/test/Sema/complex-int.c
@@ -44,9 +44,8 @@ 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/conditional.c b/test/Sema/conditional.c
index 1c7486a..9f48c34 100644
--- a/test/Sema/conditional.c
+++ b/test/Sema/conditional.c
@@ -4,12 +4,10 @@ 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_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'}}
+int _php_stream_free2() {
+ return (1 ? _efree(0) : free(0)); // expected-error {{incompatible type returning 'void', expected 'int'}}
}
diff --git a/test/Sema/darwin-align-cast.c b/test/Sema/darwin-align-cast.c
index 09808b5..fed8983 100644
--- a/test/Sema/darwin-align-cast.c
+++ b/test/Sema/darwin-align-cast.c
@@ -8,10 +8,10 @@ struct cmsghdr {};
#if 0
This code below comes from the following system headers:
-sys/socket.h:#define CMSG_SPACE(l) (__DARWIN_ALIGN(sizeof(struct
+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)
+i386/_param.h:#define __DARWIN_ALIGN(p) ((__darwin_size_t)((char *)(p)
+ __DARWIN_ALIGNBYTES) &~ __DARWIN_ALIGNBYTES)
#endif
@@ -19,5 +19,6 @@ 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;
+ return 0;
}
diff --git a/test/Sema/decl-type-merging.c b/test/Sema/decl-type-merging.c
index 1b789a1..1a86012 100644
--- a/test/Sema/decl-type-merging.c
+++ b/test/Sema/decl-type-merging.c
@@ -6,11 +6,11 @@ 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}}
+void 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/enum.c b/test/Sema/enum.c
index adb9375..31649e0 100644
--- a/test/Sema/enum.c
+++ b/test/Sema/enum.c
@@ -43,7 +43,7 @@ void test4() {
;
(_Bool)ve2; // expected-error {{arithmetic or pointer type is required}}
- for (; ;ve2)
+ for (; ;ve2) // expected-warning {{expression result unused}}
;
(void)ve2;
ve2; // expected-warning {{expression result unused}}
diff --git a/test/Sema/exprs.c b/test/Sema/exprs.c
index 3fd1437..69a2320 100644
--- a/test/Sema/exprs.c
+++ b/test/Sema/exprs.c
@@ -60,9 +60,9 @@ int test8(void) {
struct f { int x : 4; float y[]; };
int test9(struct f *P) {
int R;
- R = __alignof(P->x); // expected-error {{invalid application of '__alignof' to bitfield}}
+ R = __alignof(P->x); // expected-error {{invalid application of '__alignof' to bit-field}}
R = __alignof(P->y); // ok.
- R = sizeof(P->x); // expected-error {{invalid application of 'sizeof' to bitfield}}
+ R = sizeof(P->x); // expected-error {{invalid application of 'sizeof' to bit-field}}
return R;
}
@@ -94,15 +94,12 @@ void test13(
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)));
+ // Ok.
__v4hi a;
- __m64 mask = (__m64)((__v4hi)a > // expected-error {{comparison of vector types ('__v4hi' and '__v4hi') not supported yet}}
- (__v4hi)a);
+ __m64 mask = (__m64)((__v4hi)a > (__v4hi)a);
}
diff --git a/test/Sema/floating-point-compare.c b/test/Sema/floating-point-compare.c
index 763a8f4..9888105 100644
--- a/test/Sema/floating-point-compare.c
+++ b/test/Sema/floating-point-compare.c
@@ -13,11 +13,11 @@ int f3(float x) {
}
int f4(float x) {
- return x == 0.0; // no-warning {{comparing}}
+ return x == 0.0; // no-warning {{comparing}}
}
int f5(float x) {
- return x == __builtin_inf(); // no-warning
+ return x == __builtin_inf(); // no-warning
}
int f7(float x) {
diff --git a/test/Sema/format-attr-pr4470.c b/test/Sema/format-attr-pr4470.c
index cba3adf..c03c573 100644
--- a/test/Sema/format-attr-pr4470.c
+++ b/test/Sema/format-attr-pr4470.c
@@ -1,6 +1,7 @@
// RUN: clang-cc -fsyntax-only -verify -Wformat=2 %s
#include <stdio.h>
+#include <stdarg.h>
const char *foo(const char *format) __attribute__((format_arg(1)));
diff --git a/test/Sema/format-attribute-printf0.c b/test/Sema/format-attribute-printf0.c
new file mode 100644
index 0000000..fa7eafd
--- /dev/null
+++ b/test/Sema/format-attribute-printf0.c
@@ -0,0 +1,26 @@
+//RUN: clang-cc -fsyntax-only -verify %s
+
+#include <stdarg.h>
+
+// same as format(printf(...))...
+void a2(const char *a, ...) __attribute__((format(printf0, 1,2))); // no-error
+void b2(const char *a, ...) __attribute__((format(printf0, 1,1))); // expected-error {{'format' attribute parameter 3 is out of bounds}}
+void c2(const char *a, ...) __attribute__((format(printf0, 0,2))); // expected-error {{'format' attribute parameter 2 is out of bounds}}
+void d2(const char *a, int c) __attribute__((format(printf0, 1,2))); // expected-error {{format attribute requires variadic function}}
+void e2(char *str, int c, ...) __attribute__((format(printf0, 2,3))); // expected-error {{format argument not a string type}}
+
+// FreeBSD usage
+#define __printf0like(fmt,va) __attribute__((__format__(__printf0__,fmt,va)))
+void null(int i, const char *a, ...) __printf0like(2,0); // no-error
+void null(int i, const char *a, ...) {
+ if (a)
+ (void)0/* vprintf(...) would go here */;
+}
+
+void callnull(void){
+ null(0, 0); // no error
+ null(0, (char*)0); // no error
+ null(0, (void*)0); // no error
+ null(0, (int*)0); // expected-warning {{incompatible pointer types}}
+}
+
diff --git a/test/Sema/freemain.c b/test/Sema/freemain.c
new file mode 100644
index 0000000..a2364df
--- /dev/null
+++ b/test/Sema/freemain.c
@@ -0,0 +1,9 @@
+// RUN: clang-cc -fsyntax-only -verify -ffreestanding %s
+
+// Tests that -ffreestanding disables all special treatment of main().
+
+void* allocate(long size);
+
+void* main(void* context, long size) {
+ if (context) return allocate(size);
+} // expected-warning {{control may reach end of non-void function}}
diff --git a/test/Sema/function-pointer-sentinel-attribute.c b/test/Sema/function-pointer-sentinel-attribute.c
index 0de02fa..6d3fb17 100644
--- a/test/Sema/function-pointer-sentinel-attribute.c
+++ b/test/Sema/function-pointer-sentinel-attribute.c
@@ -2,22 +2,19 @@
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}}
+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}}
+ 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
+ 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
+ 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-sentinel-attr.c b/test/Sema/function-sentinel-attr.c
index 6630479..b33b4a0 100644
--- a/test/Sema/function-sentinel-attr.c
+++ b/test/Sema/function-sentinel-attr.c
@@ -18,7 +18,7 @@ int main ()
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}}
+ 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
diff --git a/test/Sema/function.c b/test/Sema/function.c
index c9d8630..e7a37f1 100644
--- a/test/Sema/function.c
+++ b/test/Sema/function.c
@@ -87,3 +87,5 @@ unknown_type t19(int* P) { // expected-error {{unknown type name 'unknown_type
P = P+1; // no warning.
}
+// missing ',' before '...'
+void t20(int i...) { } // expected-error {{requires a comma}}
diff --git a/test/Sema/heinous-extensions-on.c b/test/Sema/heinous-extensions-on.c
index 480b1b4..a56f1f6 100644
--- a/test/Sema/heinous-extensions-on.c
+++ b/test/Sema/heinous-extensions-on.c
@@ -1,10 +1,9 @@
// 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}}
+void 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/implicit-builtin-redecl.c b/test/Sema/implicit-builtin-redecl.c
index cd99b54..36513ba 100644
--- a/test/Sema/implicit-builtin-redecl.c
+++ b/test/Sema/implicit-builtin-redecl.c
@@ -12,3 +12,15 @@ void *calloc(int, int, int); // expected-warning{{incompatible redeclaration of
void f1(void) {
calloc(0, 0, 0);
}
+
+void f2() {
+ int index = 1;
+}
+
+static int index;
+
+int f3() {
+ return index << 2;
+}
+
+typedef int rindex; \ No newline at end of file
diff --git a/test/Sema/implicit-int.c b/test/Sema/implicit-int.c
index 04b27a8..5190bdb 100644
--- a/test/Sema/implicit-int.c
+++ b/test/Sema/implicit-int.c
@@ -1,6 +1,7 @@
// RUN: clang-cc -fsyntax-only %s -verify -pedantic
foo() { // expected-warning {{type specifier missing, defaults to 'int'}}
+ return 0;
}
y; // expected-warning {{type specifier missing, defaults to 'int'}}
@@ -11,19 +12,19 @@ void f((x)); // expected-warning {{type specifier missing, defaults to 'int'}}
// PR3702
#define PAD(ms10) { \
- register i; \
+ register i; \
}
-#define ILPAD() PAD((NROW - tt.tt_row) * 10) /* 1 ms per char */
+#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'}}
+ ILPAD(); // expected-warning {{type specifier missing, defaults to 'int'}}
}
struct foo {
- __extension__ __attribute__((packed)) x : 4; // expected-warning {{type specifier missing, defaults to 'int'}}
+ __extension__ __attribute__((packed)) x : 4;
};
diff --git a/test/Sema/incomplete-call.c b/test/Sema/incomplete-call.c
index aedfe50..15d9768 100644
--- a/test/Sema/incomplete-call.c
+++ b/test/Sema/incomplete-call.c
@@ -2,12 +2,12 @@
struct foo; // expected-note 3 {{forward declaration of 'struct foo'}}
-struct foo a();
+struct foo a(); // expected-note {{'a' declared here}}
void b(struct foo);
void c();
void func() {
- a(); // expected-error{{return type of called function ('struct foo') is incomplete}}
+ a(); // expected-error{{calling 'a' with incomplete return type 'struct foo'}}
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
index eb93e8e..6a6ba75 100644
--- a/test/Sema/incomplete-decl.c
+++ b/test/Sema/incomplete-decl.c
@@ -1,12 +1,13 @@
// RUN: clang-cc -fsyntax-only -verify %s
-struct foo; // expected-note 4 {{forward declaration of 'struct foo'}}
+struct foo; // expected-note 5 {{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'}}
+static struct foo g; // expected-warning {{tentative definition of variable with internal linkage has incomplete non-array type 'struct foo'}} \
+ expected-error{{tentative definition has type 'struct foo' that is never completed}}
extern void d;
extern struct foo e;
diff --git a/test/Sema/pragma-pack-4.c b/test/Sema/pragma-pack-4.c
new file mode 100644
index 0000000..f6f107d
--- /dev/null
+++ b/test/Sema/pragma-pack-4.c
@@ -0,0 +1,19 @@
+// RUN: clang-cc -triple i686-apple-darwin9 %s -fsyntax-only -verify &&
+// RUN: clang-cc -triple x86_64-apple-darwin9 %s -fsyntax-only -verify
+
+// rdar://problem/7095436
+#pragma pack(4)
+
+struct s0 {
+ long long a __attribute__((aligned(8)));
+ long long b __attribute__((aligned(8)));
+ unsigned int c __attribute__((aligned(8)));
+ int d[12];
+};
+
+struct s1 {
+ int a[15];
+ struct s0 b;
+};
+
+int arr0[((sizeof(struct s1) % 64) == 0) ? 1 : -1];
diff --git a/test/Sema/pragma-unused.c b/test/Sema/pragma-unused.c
index fe8bf86..8b94989 100644
--- a/test/Sema/pragma-unused.c
+++ b/test/Sema/pragma-unused.c
@@ -16,7 +16,7 @@ void f2(void) {
}
void f3(void) {
- #pragma unused(x) // expected-error{{use of undeclared identifier 'x'}}
+ #pragma unused(x) // expected-warning{{undeclared variable 'x' used as an argument for '#pragma unused'}}
}
void f4(void) {
@@ -26,7 +26,7 @@ void f4(void) {
int k;
void f5(void) {
- #pragma unused(k) // expected-warning{{only local variables can be arguments to '#pragma unused' - ignored}}
+ #pragma unused(k) // expected-warning{{only local variables can be arguments to '#pragma unused'}}
}
void f6(void) {
@@ -36,3 +36,8 @@ void f6(void) {
}
}
+void f7() {
+ int y;
+ #pragma unused(undeclared, undefined, y) // expected-warning{{undeclared variable 'undeclared' used as an argument for '#pragma unused'}} expected-warning{{undeclared variable 'undefined' used as an argument for '#pragma unused'}}
+}
+
diff --git a/test/Sema/predefined-function.c b/test/Sema/predefined-function.c
index e8ccb36..c8d17f0 100644
--- a/test/Sema/predefined-function.c
+++ b/test/Sema/predefined-function.c
@@ -8,31 +8,30 @@ 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 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;
+ return 0;
}
int bar() // expected-error {{redefinition of 'bar'}}
{
- return 0;
+ return 0;
}
int foobar(int); // note {{previous declaration is here}}
int foobar() // error {{conflicting types for 'foobar'}}
{
- return 0;
+ return 0;
}
int wibble(); // expected-note {{previous declaration is here}}
float wibble() // expected-error {{conflicting types for 'wibble'}}
{
- return 0.0f;
+ return 0.0f;
}
diff --git a/test/Sema/promote-int-16bit.c b/test/Sema/promote-int-16bit.c
new file mode 100644
index 0000000..fbd1215
--- /dev/null
+++ b/test/Sema/promote-int-16bit.c
@@ -0,0 +1,6 @@
+// RUN: clang-cc -fsyntax-only -verify %s -triple pic16-unknown-unknown
+
+// Check that unsigned short promotes to unsigned int on targets where
+// sizeof(unsigned short) == sizeof(unsigned int)
+__typeof(1+(unsigned short)1) x;
+unsigned x;
diff --git a/test/Sema/redefinition.c b/test/Sema/redefinition.c
index 26c90c8..9339bb9 100644
--- a/test/Sema/redefinition.c
+++ b/test/Sema/redefinition.c
@@ -1,7 +1,7 @@
// RUN: clang-cc %s -fsyntax-only -verify
-int f(int a) { } // expected-note {{previous definition is here}}
+int f(int a) { return 0; } // expected-note {{previous definition is here}}
int f(int);
-int f(int a) { } // expected-error {{redefinition of 'f'}}
+int f(int a) { return 0; } // expected-error {{redefinition of 'f'}}
// <rdar://problem/6097326>
int foo(x) {
diff --git a/test/Sema/return-noreturn.c b/test/Sema/return-noreturn.c
new file mode 100644
index 0000000..e2452f4
--- /dev/null
+++ b/test/Sema/return-noreturn.c
@@ -0,0 +1,29 @@
+// RUN: clang-cc %s -fsyntax-only -verify -fblocks -Wmissing-noreturn
+
+int j;
+void test1() { // expected-warning {{function could be attribute 'noreturn'}}
+ ^ (void) { while (1) { } }(); // expected-warning {{block could be attribute 'noreturn'}}
+ ^ (void) { if (j) while (1) { } }();
+ while (1) { }
+}
+
+void test2() {
+ if (j) while (1) { }
+}
+
+__attribute__((__noreturn__))
+void test2_positive() {
+ if (j) while (1) { }
+} // expected-warning{{function declared 'noreturn' should not return}}
+
+
+// This test case illustrates that we don't warn about the missing return
+// because the function is marked noreturn and there is an infinite loop.
+extern int foo_test_3();
+__attribute__((__noreturn__)) void* test3(int arg) {
+ while (1) foo_test_3();
+}
+
+__attribute__((__noreturn__)) void* test3_positive(int arg) {
+ while (0) foo_test_3();
+} // expected-warning{{function declared 'noreturn' should not return}}
diff --git a/test/Sema/return.c b/test/Sema/return.c
index d96cede..64def30 100644
--- a/test/Sema/return.c
+++ b/test/Sema/return.c
@@ -1,4 +1,4 @@
-// RUN: clang-cc %s -fsyntax-only -verify
+// RUN: clang-cc %s -fsyntax-only -verify -fblocks
// clang emits the following warning by default.
// With GCC, -pedantic, -Wreturn-type or -Wall are required to produce the
@@ -10,3 +10,211 @@ int t14() {
void t15() {
return 1; // expected-warning {{void function 't15' should not return a value}}
}
+
+int unknown();
+
+void test0() {
+}
+
+int test1() {
+} // expected-warning {{control reaches end of non-void function}}
+
+int test2() {
+ a: goto a;
+}
+
+int test3() {
+ goto a;
+ a: ;
+} // expected-warning {{control reaches end of non-void function}}
+
+
+void halt() {
+ a: goto a;
+}
+
+void halt2() __attribute__((noreturn));
+
+int test4() {
+ halt2();
+}
+
+int test5() {
+ halt2(), (void)1;
+}
+
+int test6() {
+ 1, halt2();
+}
+
+int j;
+int unknown_nohalt() {
+ return j;
+}
+
+int test7() {
+ unknown();
+} // expected-warning {{control reaches end of non-void function}}
+
+int test8() {
+ (void)(1 + unknown());
+} // expected-warning {{control reaches end of non-void function}}
+
+int halt3() __attribute__((noreturn));
+
+int test9() {
+ (void)(halt3() + unknown());
+}
+
+int test10() {
+ (void)(unknown() || halt3());
+} // expected-warning {{control may reach end of non-void function}}
+
+int test11() {
+ (void)(unknown() && halt3());
+} // expected-warning {{control may reach end of non-void function}}
+
+int test12() {
+ (void)(halt3() || unknown());
+}
+
+int test13() {
+ (void)(halt3() && unknown());
+}
+
+int test14() {
+ (void)(1 || unknown());
+} // expected-warning {{control reaches end of non-void function}}
+
+int test15() {
+ (void)(0 || unknown());
+} // expected-warning {{control reaches end of non-void function}}
+
+int test16() {
+ (void)(0 && unknown());
+} // expected-warning {{control reaches end of non-void function}}
+
+int test17() {
+ (void)(1 && unknown());
+} // expected-warning {{control reaches end of non-void function}}
+
+int test18() {
+ (void)(unknown_nohalt() && halt3());
+} // expected-warning {{control may reach end of non-void function}}
+
+int test19() {
+ (void)(unknown_nohalt() && unknown());
+} // expected-warning {{control reaches end of non-void function}}
+
+int test20() {
+ int i;
+ if (i)
+ return 0;
+ else if (0)
+ return 2;
+} // expected-warning {{control may reach end of non-void function}}
+
+int test21() {
+ int i;
+ if (i)
+ return 0;
+ else if (1)
+ return 2;
+}
+
+int test22() {
+ int i;
+ switch (i) default: ;
+} // expected-warning {{control reaches end of non-void function}}
+
+int test23() {
+ int i;
+ switch (i) {
+ case 0:
+ return 0;
+ case 2:
+ return 2;
+ }
+} // expected-warning {{control may reach end of non-void function}}
+
+int test24() {
+ int i;
+ switch (i) {
+ case 0:
+ return 0;
+ case 2:
+ return 2;
+ default:
+ return -1;
+ }
+}
+
+int test25() {
+ 1 ? halt3() : unknown();
+}
+
+int test26() {
+ 0 ? halt3() : unknown();
+} // expected-warning {{control reaches end of non-void function}}
+
+int j;
+void (*fptr)() __attribute__((noreturn));
+int test27() {
+ switch (j) {
+ case 1:
+ do { } while (1);
+ break;
+ case 2:
+ for (;;) ;
+ break;
+ case 3:
+ for (;1;) ;
+ for (;0;) {
+ goto done;
+ }
+ return 1;
+ case 4:
+ while (0) { goto done; }
+ return 1;
+ case 5:
+ while (1) { return 1; }
+ break;
+ case 6:
+ fptr();
+ break;
+ default:
+ return 1;
+ }
+ done: ;
+}
+
+// PR4624
+void test28() __attribute__((noreturn));
+void test28(x) { while (1) { } }
+
+void exit(int);
+int test29() {
+ exit(1);
+}
+
+#include <setjmp.h>
+jmp_buf test30_j;
+int test30() {
+ if (j)
+ longjmp(test30_j, 1);
+ else
+ _longjmp(test30_j, 1);
+}
+
+typedef void test31_t(int status);
+void test31(test31_t *callback __attribute__((noreturn)));
+
+void test32() {
+ ^ (void) { while (1) { } }();
+ ^ (void) { if (j) while (1) { } }();
+ while (1) { }
+}
+
+void test33() {
+ if (j) while (1) { }
+}
diff --git a/test/Sema/shift.c b/test/Sema/shift.c
index 5acbe12..2516d1b 100644
--- a/test/Sema/shift.c
+++ b/test/Sema/shift.c
@@ -1,6 +1,40 @@
-// RUN: clang-cc -fsyntax-only %s
+// RUN: clang-cc -Wall -fsyntax-only -verify %s
+
+#include <limits.h>
+
+enum {
+ X = 1 << 0,
+ Y = 1 << 1,
+ Z = 1 << 2
+};
void test() {
char c;
- c <<= 14;
+
+ c = 0 << 0;
+ c = 0 << 1;
+ c = 1 << 0;
+ c = 1 << -0;
+ c = 1 >> -0;
+ c = 1 << -1; // expected-warning {{shift count is negative}}
+ c = 1 >> -1; // expected-warning {{shift count is negative}}
+ c = 1 << c;
+ c <<= 0;
+ c >>= 0;
+ c <<= 1;
+ c >>= 1;
+ c <<= -1; // expected-warning {{shift count is negative}}
+ c >>= -1; // expected-warning {{shift count is negative}}
+ c <<= 999999; // expected-warning {{shift count >= width of type}}
+ c >>= 999999; // expected-warning {{shift count >= width of type}}
+ c <<= CHAR_BIT; // expected-warning {{shift count >= width of type}}
+ c >>= CHAR_BIT; // expected-warning {{shift count >= width of type}}
+ c <<= CHAR_BIT+1; // expected-warning {{shift count >= width of type}}
+ c >>= CHAR_BIT+1; // expected-warning {{shift count >= width of type}}
+ (void)((long)c << CHAR_BIT);
}
+
+#define a 0
+#define ashift 8
+enum { b = (a << ashift) };
+
diff --git a/test/Sema/static-init.c b/test/Sema/static-init.c
index cd49556..510f3ab 100644
--- a/test/Sema/static-init.c
+++ b/test/Sema/static-init.c
@@ -11,11 +11,11 @@ _Bool t = &t;
union bar {
- int i;
+ int i;
};
struct foo {
- unsigned ptr;
+ unsigned ptr;
};
union bar u[1];
diff --git a/test/Sema/struct-decl.c b/test/Sema/struct-decl.c
index 2c0945f..a5a299b 100644
--- a/test/Sema/struct-decl.c
+++ b/test/Sema/struct-decl.c
@@ -1,26 +1,26 @@
// RUN: clang-cc -fsyntax-only -verify %s
// PR3459
struct bar {
- char n[1];
+ 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}}
+ 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 v;
+ } *ts;
};
struct st;
int foo() {
- struct st *f;
- return f->v + f[0].v;
+ struct st *f;
+ return f->v + f[0].v;
}
// PR3642, PR3671
@@ -29,8 +29,8 @@ struct pppoe_tag {
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;
+ 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;
};
diff --git a/test/Sema/tentative-decls.c b/test/Sema/tentative-decls.c
index e3c893c..c94af11 100644
--- a/test/Sema/tentative-decls.c
+++ b/test/Sema/tentative-decls.c
@@ -2,7 +2,7 @@
// PR3310
struct a x1; // expected-note 2{{forward declaration of 'struct a'}}
-static struct a x2; // expected-error{{variable has incomplete type 'struct a'}}
+static struct a x2; // expected-warning{{tentative definition of variable with internal linkage has incomplete non-array 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;
diff --git a/test/Sema/transparent-union-pointer.c b/test/Sema/transparent-union-pointer.c
index ea761f1..a58bd42 100644
--- a/test/Sema/transparent-union-pointer.c
+++ b/test/Sema/transparent-union-pointer.c
@@ -1,14 +1,14 @@
// RUN: clang-cc %s -fsyntax-only -verify
typedef union {
- union wait *__uptr;
- int *__iptr;
+ 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);
+ int status = 0;
+ wait(&status);
}
diff --git a/test/Sema/type-spec-struct-union.c b/test/Sema/type-spec-struct-union.c
index 2b68b78..003efb1 100644
--- a/test/Sema/type-spec-struct-union.c
+++ b/test/Sema/type-spec-struct-union.c
@@ -57,7 +57,7 @@ struct bar_baz {
} mode;
int nowrap;
};
-int
+void
wizbiz_quxPoof(z)
z_foop z;
{
diff --git a/test/Sema/unused-expr.c b/test/Sema/unused-expr.c
index 9c231e9..acf4887 100644
--- a/test/Sema/unused-expr.c
+++ b/test/Sema/unused-expr.c
@@ -25,7 +25,7 @@ void bar(volatile int *VP, int *P, int A,
__real__ VC;
// We know this can't change errno because of -fno-math-errno.
- sqrt(A); // expected-warning {{expression result unused}}
+ sqrt(A); // expected-warning {{ignoring return value of function declared with const attribute}}
}
extern void t1();
@@ -43,4 +43,56 @@ void nowarn(unsigned char* a, unsigned char* b)
{
unsigned char c = 1;
*a |= c, *b += c;
+
+
+ // PR4633
+ int y, x;
+ ((void)0), y = x;
+}
+
+void t4(int a) {
+ int b = 0;
+
+ if (a)
+ b == 1; // expected-warning{{expression result unused}}
+ else
+ b == 2; // expected-warning{{expression result unused}}
+
+ while (1)
+ b == 3; // expected-warning{{expression result unused}}
+
+ do
+ b == 4; // expected-warning{{expression result unused}}
+ while (1);
+
+ for (;;)
+ b == 5; // expected-warning{{expression result unused}}
+
+ for (b == 1;;) {} // expected-warning{{expression result unused}}
+ for (;b == 1;) {}
+ for (;;b == 1) {} // expected-warning{{expression result unused}}
}
+
+// rdar://7186119
+int t5f(void) __attribute__((warn_unused_result));
+void t5() {
+ t5f(); // expected-warning {{ignoring return value of function declared with warn_unused_result}}
+}
+
+
+int fn1() __attribute__ ((warn_unused_result));
+int fn2() __attribute__ ((pure));
+int fn3() __attribute__ ((const));
+// rdar://6587766
+int t6() {
+ if (fn1() < 0 || fn2(2,1) < 0 || fn3(2) < 0) // no warnings
+ return -1;
+
+ fn1(); // expected-warning {{ignoring return value of function declared with warn_unused_result attribute}}
+ fn2(92, 21); // expected-warning {{ignoring return value of function declared with pure attribute}}
+ fn3(42); // expected-warning {{ignoring return value of function declared with const attribute}}
+ return 0;
+}
+
+int t7 __attribute__ ((warn_unused_result)); // expected-warning {{warning: 'warn_unused_result' attribute only applies to function types}}
+
diff --git a/test/Sema/va_arg_x86_64.c b/test/Sema/va_arg_x86_64.c
index 680abb7..61ac97b 100644
--- a/test/Sema/va_arg_x86_64.c
+++ b/test/Sema/va_arg_x86_64.c
@@ -8,9 +8,8 @@ char* foo(char *fmt, __builtin_va_list ap)
// 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));
+static void 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/vector-cast.c b/test/Sema/vector-cast.c
index 9460cac..8c607aa 100644
--- a/test/Sema/vector-cast.c
+++ b/test/Sema/vector-cast.c
@@ -20,7 +20,7 @@ void f()
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}}
+type 't1' and integer type 'short' of different size}}
long long r1 = (long long)v1;
short r2 = (short)v1; // -expected-error {{invalid conversion between vector \
diff --git a/test/Sema/warn-char-subscripts.c b/test/Sema/warn-char-subscripts.c
new file mode 100644
index 0000000..c6fd78c
--- /dev/null
+++ b/test/Sema/warn-char-subscripts.c
@@ -0,0 +1,64 @@
+// RUN: clang-cc -Wchar-subscripts -fsyntax-only -verify %s
+
+void t1() {
+ int array[1] = { 0 };
+ char subscript = 0;
+ int val = array[subscript]; // expected-warning{{array subscript is of type 'char'}}
+}
+
+void t2() {
+ int array[1] = { 0 };
+ char subscript = 0;
+ int val = subscript[array]; // expected-warning{{array subscript is of type 'char'}}
+}
+
+void t3() {
+ int *array = 0;
+ char subscript = 0;
+ int val = array[subscript]; // expected-warning{{array subscript is of type 'char'}}
+}
+
+void t4() {
+ int *array = 0;
+ char subscript = 0;
+ int val = subscript[array]; // expected-warning{{array subscript is of type 'char'}}
+}
+
+char returnsChar();
+void t5() {
+ int *array = 0;
+ int val = array[returnsChar()]; // expected-warning{{array subscript is of type 'char'}}
+}
+
+void t6() {
+ int array[1] = { 0 };
+ signed char subscript = 0;
+ int val = array[subscript]; // no warning for explicit signed char
+}
+
+void t7() {
+ int array[1] = { 0 };
+ unsigned char subscript = 0;
+ int val = array[subscript]; // no warning for unsigned char
+}
+
+typedef char CharTy;
+void t8() {
+ int array[1] = { 0 };
+ CharTy subscript = 0;
+ int val = array[subscript]; // expected-warning{{array subscript is of type 'char'}}
+}
+
+typedef signed char SignedCharTy;
+void t9() {
+ int array[1] = { 0 };
+ SignedCharTy subscript = 0;
+ int val = array[subscript]; // no warning for explicit signed char
+}
+
+typedef unsigned char UnsignedCharTy;
+void t10() {
+ int array[1] = { 0 };
+ UnsignedCharTy subscript = 0;
+ int val = array[subscript]; // no warning for unsigned char
+}
diff --git a/test/Sema/warn-unused-variables.c b/test/Sema/warn-unused-variables.c
new file mode 100644
index 0000000..fd22543
--- /dev/null
+++ b/test/Sema/warn-unused-variables.c
@@ -0,0 +1,19 @@
+// RUN: clang-cc -fsyntax-only -Wunused-variable -verify %s
+
+struct s0 {
+ unsigned int i;
+};
+
+int proto(int a, int b);
+
+void f0(void) {
+ int a __attribute__((unused)),
+ b; // expected-warning{{unused}}
+ return;
+}
+
+void f1(void) {
+ int i;
+ (void)sizeof(i);
+ return;
+}
diff --git a/test/Sema/x86-intrinsics-headers.c b/test/Sema/x86-intrinsics-headers.c
new file mode 100644
index 0000000..dd7dd5c
--- /dev/null
+++ b/test/Sema/x86-intrinsics-headers.c
@@ -0,0 +1,24 @@
+// RUN: clang -fsyntax-only %s &&
+// RUN: clang -fsyntax-only -fno-lax-vector-conversions %s &&
+// RUN: clang -fsyntax-only -x c++ %s
+
+#if defined(i386) || defined(__x86_64__)
+
+# if defined(__MMX__)
+#include <emmintrin.h>
+#include <mm_malloc.h>
+# endif
+
+# if defined(__SSE__)
+#include <xmmintrin.h>
+# endif
+
+# if defined(__SSE3__)
+#include <pmmintrin.h>
+# endif
+
+# if defined(__SSSE3__)
+#include <tmmintrin.h>
+# endif
+
+#endif
diff --git a/test/SemaCXX/PR5086-ambig-resolution-enum.cpp b/test/SemaCXX/PR5086-ambig-resolution-enum.cpp
new file mode 100644
index 0000000..838bc6f
--- /dev/null
+++ b/test/SemaCXX/PR5086-ambig-resolution-enum.cpp
@@ -0,0 +1,13 @@
+// RUN: clang-cc -fsyntax-only -verify %s -std=c++0x
+
+class C {
+public:
+ enum E { e1=0 };
+ const char * fun1(int , enum E) const;
+ int fun1(unsigned, const char *) const;
+};
+
+void foo(const C& rc) {
+ enum {BUFLEN = 128 };
+ const char *p = rc.fun1(BUFLEN - 2, C::e1);
+}
diff --git a/test/SemaCXX/abstract.cpp b/test/SemaCXX/abstract.cpp
index dc764da..e14304a 100644
--- a/test/SemaCXX/abstract.cpp
+++ b/test/SemaCXX/abstract.cpp
@@ -9,7 +9,7 @@
#endif
class C {
- virtual void f() = 0; // expected-note {{pure virtual function 'f'}}
+ virtual void f() = 0; // expected-note {{pure virtual function 'f'}}
};
static_assert(__is_abstract(C), "C has a pure virtual function");
@@ -20,7 +20,7 @@ class D : C {
static_assert(__is_abstract(D), "D inherits from an abstract class");
class E : D {
- virtual void f();
+ virtual void f();
};
static_assert(!__is_abstract(E), "E inherits from an abstract class but implements f");
@@ -38,8 +38,8 @@ struct S {
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(); // 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}}
@@ -54,17 +54,17 @@ typedef void (*Func)(C); // expected-error {{parameter type 'C' is an abstract c
void t6(Func);
class F {
- F a() { } // expected-error {{return type 'F' is an abstract class}}
+ F a() { while (1) {} } // expected-error {{return type 'F' is an abstract class}}
- class D {
- void f(F c); // expected-error {{parameter 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}}
- };
+ 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'}}
+ virtual void f() = 0; // expected-note {{pure virtual function 'f'}}
};
class Abstract;
@@ -72,50 +72,47 @@ 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}}
+ 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}}
+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'}}
+ virtual void f() = 0; // expected-note {{pure virtual function 'f'}}
};
// <rdar://problem/6854087>
class foo {
public:
- virtual foo *getFoo() = 0;
+ virtual foo *getFoo() = 0;
};
class bar : public foo {
public:
- virtual bar *getFoo();
+ virtual bar *getFoo();
};
bar x;
// <rdar://problem/6902298>
-class A
-{
+class A {
public:
- virtual void release() = 0;
- virtual void release(int count) = 0;
- virtual void retain() = 0;
+ virtual void release() = 0;
+ virtual void release(int count) = 0;
+ virtual void retain() = 0;
};
-class B : public A
-{
+class B : public A {
public:
- virtual void release();
- virtual void release(int count);
- virtual void retain();
+ virtual void release();
+ virtual void release(int count);
+ virtual void retain();
};
-void foo(void)
-{
- B b;
+void foo(void) {
+ B b;
}
struct K {
diff --git a/test/SemaCXX/access-control-check.cpp b/test/SemaCXX/access-control-check.cpp
new file mode 100644
index 0000000..fb124a9
--- /dev/null
+++ b/test/SemaCXX/access-control-check.cpp
@@ -0,0 +1,16 @@
+// RUN: clang-cc -fsyntax-only -faccess-control -verify %s
+
+class M {
+ int iM;
+};
+
+class P {
+ int iP;
+ int PPR();
+};
+
+class N : M,P {
+ N() {}
+ // FIXME. No access violation is reported in method call or member access.
+ int PR() { return iP + PPR(); }
+};
diff --git a/test/SemaCXX/addr-of-overloaded-function.cpp b/test/SemaCXX/addr-of-overloaded-function.cpp
index 9c9f0e1..80ea02b 100644
--- a/test/SemaCXX/addr-of-overloaded-function.cpp
+++ b/test/SemaCXX/addr-of-overloaded-function.cpp
@@ -23,7 +23,34 @@ int g1(char);
int g2(int);
int g2(double);
+template<typename T> T g3(T);
+int g3(int);
+int g3(char);
+
void g_test() {
g(g1);
g(g2); // expected-error{{call to 'g' is ambiguous; candidates are:}}
+ g(g3);
}
+
+template<typename T> T h1(T);
+template<typename R, typename A1> R h1(A1);
+int h1(char);
+
+void ha(int (*fp)(int));
+void hb(int (*fp)(double));
+
+void h_test() {
+ ha(h1);
+ hb(h1);
+}
+
+struct A { };
+void f(void (*)(A *));
+
+struct B
+{
+ void g() { f(d); }
+ void d(void *);
+ static void d(A *);
+};
diff --git a/test/SemaCXX/ambig-user-defined-conversions.cpp b/test/SemaCXX/ambig-user-defined-conversions.cpp
new file mode 100644
index 0000000..94598f0
--- /dev/null
+++ b/test/SemaCXX/ambig-user-defined-conversions.cpp
@@ -0,0 +1,52 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// Test1
+struct BASE {
+ operator int &(); // expected-note {{candidate function}}
+};
+struct BASE1 {
+ operator int &(); // expected-note {{candidate function}}
+};
+
+struct B : public BASE, BASE1 {
+
+};
+
+extern B f();
+
+B b1;
+void func(const int ci, const char cc); // expected-note {{candidate function}}
+void func(const char ci, const B b); // expected-note {{candidate function}}
+void func(const B b, const int ci); // expected-note {{candidate function}}
+
+const int Test1() {
+ func(b1, f()); // expected-error {{call to 'func' is ambiguous}}
+ return f(); // expected-error {{conversion from 'struct B' to 'int const' is ambiguous}}
+}
+
+
+// Test2
+struct E;
+struct A {
+ A (E&);
+};
+
+struct E {
+ operator A ();
+};
+
+struct C {
+ C (E&);
+};
+
+void f1(A); // expected-note {{candidate function}}
+void f1(C); // expected-note {{candidate function}}
+
+void Test2()
+{
+ E b;
+ f1(b); // expected-error {{call to 'f1' is ambiguous}}
+ // ambiguous because b -> C via constructor and
+ // b → A via constructor or conversion function.
+}
+
diff --git a/test/SemaCXX/ambiguous-builtin-unary-operator.cpp b/test/SemaCXX/ambiguous-builtin-unary-operator.cpp
new file mode 100644
index 0000000..042546a
--- /dev/null
+++ b/test/SemaCXX/ambiguous-builtin-unary-operator.cpp
@@ -0,0 +1,18 @@
+// RUN: clang-cc -fsyntax-only -verify %s -std=c++0x
+
+struct A {
+ operator int&();
+};
+
+struct B {
+ operator long&();
+};
+
+struct C : B, A { };
+
+void test(C c) {
+ ++c; // expected-error {{use of overloaded operator '++' is ambiguous}}\
+ // expected-note 4 {{built-in candidate operator ++ (}}
+}
+
+
diff --git a/test/SemaCXX/arrow-operator.cpp b/test/SemaCXX/arrow-operator.cpp
new file mode 100644
index 0000000..9c46e96
--- /dev/null
+++ b/test/SemaCXX/arrow-operator.cpp
@@ -0,0 +1,22 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+struct T {
+ void f();
+};
+
+struct A {
+ T* operator->(); // expected-note{{candidate function}}
+};
+
+struct B {
+ T* operator->(); // expected-note{{candidate function}}
+};
+
+struct C : A, B {
+};
+
+struct D : A { };
+
+void f(C &c, D& d) {
+ c->f(); // expected-error{{use of overloaded operator '->' is ambiguous}}
+ d->f();
+} \ No newline at end of file
diff --git a/test/SemaCXX/attr-after-definition.cpp b/test/SemaCXX/attr-after-definition.cpp
new file mode 100644
index 0000000..2ef5acf
--- /dev/null
+++ b/test/SemaCXX/attr-after-definition.cpp
@@ -0,0 +1,9 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+struct X { };
+struct Y { };
+
+bool f0(X) { return true; } // expected-note{{definition}}
+bool f1(X) { return true; }
+
+__attribute__ ((__visibility__("hidden"))) bool f0(X); // expected-warning{{attribute}}
+__attribute__ ((__visibility__("hidden"))) bool f1(Y);
diff --git a/test/SemaCXX/attr-deprecated.cpp b/test/SemaCXX/attr-deprecated.cpp
new file mode 100644
index 0000000..54f8b5b
--- /dev/null
+++ b/test/SemaCXX/attr-deprecated.cpp
@@ -0,0 +1,66 @@
+// RUN: clang-cc %s -verify -fsyntax-only
+class A {
+ void f() __attribute__((deprecated));
+ void g(A* a);
+ void h(A* a) __attribute__((deprecated));
+
+ int b __attribute__((deprecated));
+};
+
+void A::g(A* a)
+{
+ f(); // expected-warning{{'f' is deprecated}}
+ a->f(); // expected-warning{{'f' is deprecated}}
+
+ (void)b; // expected-warning{{'b' is deprecated}}
+ (void)a->b; // expected-warning{{'b' is deprecated}}
+}
+
+void A::h(A* a)
+{
+ f();
+ a->f();
+
+ (void)b;
+ (void)a->b;
+}
+
+struct B {
+ virtual void f() __attribute__((deprecated));
+ void g();
+};
+
+void B::g() {
+ f();
+ B::f(); // expected-warning{{'f' is deprecated}}
+}
+
+struct C : B {
+ virtual void f();
+ void g();
+};
+
+void C::g() {
+ f();
+ C::f();
+ B::f(); // expected-warning{{'f' is deprecated}}
+}
+
+void f(B* b, C *c) {
+ b->f();
+ b->B::f(); // expected-warning{{'f' is deprecated}}
+
+ c->f();
+ c->C::f();
+ c->B::f(); // expected-warning{{'f' is deprecated}}
+}
+
+struct D {
+ virtual void f() __attribute__((deprecated));
+};
+
+void D::f() { }
+
+void f(D* d) {
+ d->f();
+}
diff --git a/test/SemaCXX/attr-format.cpp b/test/SemaCXX/attr-format.cpp
new file mode 100644
index 0000000..369099a
--- /dev/null
+++ b/test/SemaCXX/attr-format.cpp
@@ -0,0 +1,8 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+struct S {
+ static void f(const char*, ...) __attribute__((format(printf, 1, 2)));
+
+ // GCC has a hidden 'this' argument in member functions which is why
+ // the format argument is argument 2 here.
+ void g(const char*, ...) __attribute__((format(printf, 2, 3)));
+};
diff --git a/test/SemaCXX/auto-cxx0x.cpp b/test/SemaCXX/auto-cxx0x.cpp
index 33156ef..aa92bbe 100644
--- a/test/SemaCXX/auto-cxx0x.cpp
+++ b/test/SemaCXX/auto-cxx0x.cpp
@@ -1,5 +1,5 @@
// RUN: clang-cc -fsyntax-only -verify %s -std=c++0x
void f() {
- auto int a; // expected-error{{cannot combine with previous 'auto' declaration specifier}}
+ auto int a; // expected-error{{cannot combine with previous 'auto' declaration specifier}} // expected-error{{declaration of variable 'a' with type 'auto' requires an initializer}}
int auto b; // expected-error{{cannot combine with previous 'int' declaration specifier}}
}
diff --git a/test/SemaCXX/builtin-ptrtomember-ambig.cpp b/test/SemaCXX/builtin-ptrtomember-ambig.cpp
new file mode 100644
index 0000000..7e20af3
--- /dev/null
+++ b/test/SemaCXX/builtin-ptrtomember-ambig.cpp
@@ -0,0 +1,24 @@
+// RUN: clang-cc -fsyntax-only -verify %s -std=c++0x
+
+struct A {};
+
+struct R {
+ operator const A*();
+};
+
+
+struct B : R {
+ operator A*();
+};
+
+struct C : B {
+
+};
+
+
+void foo(C c, int A::* pmf) {
+ // FIXME. Why so many built-in candidates?
+ int i = c->*pmf; // expected-error {{use of overloaded operator '->*' is ambiguous}} \
+ // expected-note 40 {{built-in candidate operator ->* ('struct A}}
+}
+
diff --git a/test/SemaCXX/builtin-ptrtomember-overload-1.cpp b/test/SemaCXX/builtin-ptrtomember-overload-1.cpp
new file mode 100644
index 0000000..27ca6dc
--- /dev/null
+++ b/test/SemaCXX/builtin-ptrtomember-overload-1.cpp
@@ -0,0 +1,46 @@
+// RUN: clang-cc -fsyntax-only -verify %s -std=c++0x
+
+struct A {};
+struct E {};
+
+struct R {
+ operator A*();
+ operator E*(); // expected-note{{candidate function}}
+};
+
+
+struct S {
+ operator A*();
+ operator E*(); // expected-note{{candidate function}}
+};
+
+struct B : R {
+ operator A*();
+};
+
+struct C : B {
+
+};
+
+void foo(C c, int A::* pmf) {
+ int i = c->*pmf;
+}
+
+struct B1 : R, S {
+ operator A*();
+};
+
+struct C1 : B1 {
+
+};
+
+void foo1(C1 c1, int A::* pmf) {
+ int i = c1->*pmf;
+ c1->*pmf = 10;
+}
+
+void foo1(C1 c1, int E::* pmf) {
+ // FIXME. Error reporting needs much improvement here.
+ int i = c1->*pmf; // expected-error {{left hand operand to ->* must be a pointer to class compatible with the right hand operand, but is 'struct C1'}} \
+ // expected-note {{because of ambiguity in conversion of 'struct C1' to 'struct E *'}}
+}
diff --git a/test/SemaCXX/builtin-ptrtomember-overload.cpp b/test/SemaCXX/builtin-ptrtomember-overload.cpp
new file mode 100644
index 0000000..718e981
--- /dev/null
+++ b/test/SemaCXX/builtin-ptrtomember-overload.cpp
@@ -0,0 +1,18 @@
+// RUN: clang-cc -fsyntax-only -verify %s -std=c++0x
+
+struct A {};
+
+struct B {
+ operator A*();
+};
+
+struct C : B {
+
+};
+
+
+void foo(C c, B b, int A::* pmf) {
+ int j = c->*pmf;
+ int i = b->*pmf;
+}
+
diff --git a/test/SemaCXX/c99.cpp b/test/SemaCXX/c99.cpp
new file mode 100644
index 0000000..b0ee056
--- /dev/null
+++ b/test/SemaCXX/c99.cpp
@@ -0,0 +1,8 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+void f0(int i) {
+ char array[i]; // expected-error{{variable length arrays}}
+}
+
+void f1(int i[static 5]) { // expected-error{{C99}}
+}
diff --git a/test/SemaCXX/cast-conversion.cpp b/test/SemaCXX/cast-conversion.cpp
new file mode 100644
index 0000000..cbc24ae
--- /dev/null
+++ b/test/SemaCXX/cast-conversion.cpp
@@ -0,0 +1,21 @@
+// RUN: clang-cc -fsyntax-only -verify %s -std=c++0x
+
+struct R {
+ R(int);
+};
+
+struct A {
+ A(R);
+};
+
+struct B {
+ B(A);
+};
+
+int main () {
+ B(10); // expected-error {{functional-style cast from 'int' to 'struct B' is not allowed}}
+ (B)10; // expected-error {{C-style cast from 'int' to 'struct B' is not allowed}}
+ static_cast<B>(10); // expected-error {{static_cast from 'int' to 'struct B' is not allowed}} \\
+ // expected-warning {{expression result unused}}
+}
+
diff --git a/test/SemaCXX/cast-explicit-ctor.cpp b/test/SemaCXX/cast-explicit-ctor.cpp
new file mode 100644
index 0000000..62134ae
--- /dev/null
+++ b/test/SemaCXX/cast-explicit-ctor.cpp
@@ -0,0 +1,6 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+struct B { explicit B(bool); };
+void f() {
+ (void)(B)true;
+ (void)B(true);
+}
diff --git a/test/SemaCXX/class-base-member-init.cpp b/test/SemaCXX/class-base-member-init.cpp
index c38c3d3..2092847 100644
--- a/test/SemaCXX/class-base-member-init.cpp
+++ b/test/SemaCXX/class-base-member-init.cpp
@@ -7,9 +7,9 @@ public:
struct D : S {
D() : b1(0), b2(1), b1(0), S(), S() {} // expected-error {{multiple initializations given for non-static member 'b1'}} \
- // expected-note {{previous initialization is here}} \
- // expected-error {{multiple initializations given for base 'class S'}} \
- // expected-note {{previous initialization is here}}
+ // expected-note {{previous initialization is here}} \
+ // expected-error {{multiple initializations given for base 'class S'}} \
+ // expected-note {{previous initialization is here}}
int b1;
int b2;
diff --git a/test/SemaCXX/class-layout.cpp b/test/SemaCXX/class-layout.cpp
new file mode 100644
index 0000000..56f41bf
--- /dev/null
+++ b/test/SemaCXX/class-layout.cpp
@@ -0,0 +1,49 @@
+// RUN: clang-cc -triple x86_64-unknown-unknown %s -fsyntax-only -verify
+
+#define SA(n, p) int a##n[(p) ? 1 : -1]
+
+struct A {
+ int a;
+ char b;
+};
+
+SA(0, sizeof(A) == 8);
+
+struct B : A {
+ char c;
+};
+
+SA(1, sizeof(B) == 12);
+
+struct C {
+// Make fields private so C won't be a POD type.
+private:
+ int a;
+ char b;
+};
+
+SA(2, sizeof(C) == 8);
+
+struct D : C {
+ char c;
+};
+
+SA(3, sizeof(D) == 8);
+
+struct __attribute__((packed)) E {
+ char b;
+ int a;
+};
+
+SA(4, sizeof(E) == 5);
+
+struct __attribute__((packed)) F : E {
+ char d;
+};
+
+SA(5, sizeof(F) == 6);
+
+struct G { G(); };
+struct H : G { };
+
+SA(6, sizeof(H) == 1);
diff --git a/test/SemaCXX/class-names.cpp b/test/SemaCXX/class-names.cpp
index a5569c0..da90145 100644
--- a/test/SemaCXX/class-names.cpp
+++ b/test/SemaCXX/class-names.cpp
@@ -5,7 +5,7 @@ C c;
void D(int);
-class D {}; // expected-note {{previous use is here}}
+class D {};
void foo()
{
@@ -13,7 +13,7 @@ void foo()
class D d;
}
-class D;
+class D; // expected-note {{previous use is here}}
enum D; // expected-error {{use of 'D' with tag type that does not match previous declaration}}
diff --git a/test/SemaCXX/composite-pointer-type.cpp b/test/SemaCXX/composite-pointer-type.cpp
index b4a5c88..ebc40c1 100644
--- a/test/SemaCXX/composite-pointer-type.cpp
+++ b/test/SemaCXX/composite-pointer-type.cpp
@@ -25,3 +25,11 @@ void f1(volatile Base *b, Derived1 *d1, const Derived2 *d2) {
if (d1 == d2) // expected-error{{comparison of distinct}}
return;
}
+
+// PR4691
+int ptrcmp1(void *a, int *b) {
+ return a < b;
+}
+int ptrcmp2(long *a, int *b) {
+ return a < b; // expected-error{{distinct}}
+} \ No newline at end of file
diff --git a/test/SemaCXX/conditional-expr.cpp b/test/SemaCXX/conditional-expr.cpp
index 3f4d715..fea3324 100644
--- a/test/SemaCXX/conditional-expr.cpp
+++ b/test/SemaCXX/conditional-expr.cpp
@@ -170,11 +170,13 @@ void test()
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}}
+ (void)(i1 ? &MixedFields::ci : &MixedFields::vi);
// Conversion of primitives does not result in an lvalue.
&(i1 ? i1 : d1); // expected-error {{address expression must be an lvalue or a function designator}}
-
+ (void)&(i1 ? flds.b1 : flds.i1); // expected-error {{address of bit-field requested}}
+ (void)&(i1 ? flds.i1 : flds.b1); // expected-error {{address of bit-field requested}}
+
// 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/constructor-initializer.cpp b/test/SemaCXX/constructor-initializer.cpp
index a180d90..b86a27d 100644
--- a/test/SemaCXX/constructor-initializer.cpp
+++ b/test/SemaCXX/constructor-initializer.cpp
@@ -1,7 +1,8 @@
-// RUN: clang-cc -fsyntax-only -verify %s
+// RUN: clang-cc -Wreorder -fsyntax-only -verify %s
class A {
int m;
A() : A::m(17) { } // expected-error {{member initializer 'm' does not name a non-static data member or base class}}
+ A(int);
};
class B : public A {
@@ -26,7 +27,7 @@ public:
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}}
+ E() : B(), D() { } // expected-error{{base class initializer 'class B' names both a direct base class and an inherited virtual base class}}
};
@@ -64,7 +65,7 @@ struct S : Y, virtual X {
};
struct Z : S {
- Z() : S(), X(), E() {} // expected-error {{type 'class E' is not a direct or virtual base of 'Z'}}
+ Z() : X(), S(), E() {} // expected-error {{type 'class E' is not a direct or virtual base of 'Z'}}
};
class U {
@@ -85,11 +86,39 @@ struct Derived : Base, Base1, virtual V {
struct Current : Derived {
int Derived;
- Current() : Derived(1), ::Derived(),
+ Current() : Derived(1), ::Derived(), // expected-warning {{member 'Derived' will be initialized after}} \
+ // expected-note {{base '::Derived'}} \
+ // expected-warning {{base class '::Derived' will be initialized after}}
::Derived::Base(), // expected-error {{type '::Derived::Base' is not a direct or virtual base of 'Current'}}
Derived::Base1(), // expected-error {{type 'Derived::Base1' is not a direct or virtual base of 'Current'}}
- Derived::V(),
+ Derived::V(), // expected-note {{base 'Derived::V'}}
::NonExisting(), // expected-error {{member initializer 'NonExisting' does not name a non-static data member or}}
INT::NonExisting() {} // expected-error {{expected a class or namespace}} \
- // expected-error {{member initializer 'NonExisting' does not name a non-static data member or}}
+ // expected-error {{member initializer 'NonExisting' does not name a non-static data member or}}
+};
+
+ // FIXME. This is bad message!
+struct M { // expected-note {{candidate function}} \
+ // expected-note {{candidate function}}
+ M(int i, int j); // expected-note {{candidate function}} \
+ // // expected-note {{candidate function}}
+};
+
+struct N : M {
+ N() : M(1), // expected-error {{no matching constructor for initialization of 'M'}}
+ m1(100) { } // expected-error {{no matching constructor for initialization of 'm1'}}
+ M m1;
+};
+
+struct P : M { // expected-error {{default constructor for 'struct M' is missing in initialization of base class}}
+ P() { }
+ M m; // expected-error {{default constructor for 'struct M' is missing in initialization of member}}
+};
+
+struct Q {
+ Q() : f1(1,2), // expected-error {{Too many arguments for member initializer 'f1'}}
+ pf(0.0) { } // expected-error {{incompatible type passing 'double', expected 'float *'}}
+ float f1;
+
+ float *pf;
};
diff --git a/test/SemaCXX/constructor.cpp b/test/SemaCXX/constructor.cpp
index 8f289a2..5ce595c 100644
--- a/test/SemaCXX/constructor.cpp
+++ b/test/SemaCXX/constructor.cpp
@@ -58,3 +58,29 @@ void y() {
a z; z.b(x);
}
}
+
+namespace A {
+ struct S {
+ S();
+ S(int);
+ void f1();
+ void f2();
+ operator int ();
+ ~S();
+ };
+}
+
+A::S::S() {}
+
+void A::S::f1() {}
+
+struct S {};
+
+A::S::S(int) {}
+
+void A::S::f2() {}
+
+A::S::operator int() { return 1; }
+
+A::S::~S() {}
+
diff --git a/test/SemaCXX/conversion-delete-expr.cpp b/test/SemaCXX/conversion-delete-expr.cpp
new file mode 100644
index 0000000..708289c
--- /dev/null
+++ b/test/SemaCXX/conversion-delete-expr.cpp
@@ -0,0 +1,109 @@
+// RUN: clang-cc -fsyntax-only -verify -std=c++0x %s
+
+// Test1
+struct B {
+ operator char *(); // expected-note {{candidate function}}
+};
+
+struct D : B {
+ operator int *(); // expected-note {{candidate function}}
+};
+
+void f (D d)
+{
+ delete d; // expected-error {{ambiguous conversion of delete expression of type 'struct D' to a pointer}}
+}
+
+// Test2
+struct B1 {
+ operator int *();
+};
+
+struct D1 : B1 {
+ operator int *();
+};
+
+void f1 (D1 d)
+{
+ delete d;
+}
+
+// Test3
+struct B2 {
+ operator const int *(); // expected-note {{candidate function}}
+};
+
+struct D2 : B2 {
+ operator int *(); // expected-note {{candidate function}}
+};
+
+void f2 (D2 d)
+{
+ delete d; // expected-error {{ambiguous conversion of delete expression of type 'struct D2' to a pointer}}
+}
+
+// Test4
+struct B3 {
+ operator const int *(); // expected-note {{candidate function}}
+};
+
+struct A3 {
+ operator const int *(); // expected-note {{candidate function}}
+};
+
+struct D3 : A3, B3 {
+};
+
+void f3 (D3 d)
+{
+ delete d; // expected-error {{mbiguous conversion of delete expression of type 'struct D3' to a pointer}}
+}
+
+// Test5
+struct X {
+ operator int();
+ operator int*();
+};
+
+void f4(X x) { delete x; delete x; }
+
+// Test6
+struct X1 {
+ operator int();
+ operator int*();
+ template<typename T> operator T*() const; // converts to any pointer!
+};
+
+void f5(X1 x) { delete x; } // OK. In selecting a conversion to pointer function, template convesions are skipped.
+
+// Test7
+struct Base {
+ operator int*();
+};
+
+struct Derived : Base {
+ // not the same function as Base's non-const operator int()
+ operator int*() const;
+};
+
+void foo6(const Derived cd, Derived d) {
+ // overload resolution selects Derived::operator int*() const;
+ delete cd;
+ delete d;
+}
+
+// Test8
+struct BB {
+ template<typename T> operator T*() const;
+};
+
+struct DD : BB {
+ template<typename T> operator T*() const; // hides base conversion
+ operator int *() const;
+};
+
+void foo7 (DD d)
+{
+ // OK. In selecting a conversion to pointer function, template convesions are skipped.
+ delete d;
+}
diff --git a/test/SemaCXX/conversion-function.cpp b/test/SemaCXX/conversion-function.cpp
index 1ca1e68..6182678 100644
--- a/test/SemaCXX/conversion-function.cpp
+++ b/test/SemaCXX/conversion-function.cpp
@@ -64,3 +64,32 @@ struct Flip {
operator Flop() const;
};
Flop flop = Flip(); // expected-error {{cannot initialize 'flop' with an rvalue of type 'struct Flip'}}
+
+// This tests that we don't add the second conversion declaration to the list of user conversions
+struct C {
+ operator const char *() const;
+};
+
+C::operator const char*() const { return 0; }
+
+void f(const C& c) {
+ const char* v = c;
+}
+
+// Test. Conversion in base class is visible in derived class.
+class XB {
+public:
+ operator int(); // expected-note {{candidate function}}
+};
+
+class Yb : public XB {
+public:
+ operator char(); // expected-note {{candidate function}}
+};
+
+void f(Yb& a) {
+ if (a) { } // expected-error {{conversion from 'class Yb' to 'bool' is ambiguous}}
+ int i = a; // OK. calls XB::operator int();
+ char ch = a; // OK. calls Yb::operator char();
+}
+
diff --git a/test/SemaCXX/copy-assignment.cpp b/test/SemaCXX/copy-assignment.cpp
index 6e5012f..413e4d1 100644
--- a/test/SemaCXX/copy-assignment.cpp
+++ b/test/SemaCXX/copy-assignment.cpp
@@ -11,7 +11,7 @@ struct ConvertibleToConstA {
};
struct B {
- B& operator=(B&);
+ B& operator=(B&); // expected-note 4 {{candidate function}}
};
struct ConvertibleToB {
diff --git a/test/SemaCXX/copy-constructor-error.cpp b/test/SemaCXX/copy-constructor-error.cpp
new file mode 100644
index 0000000..2e42fcc
--- /dev/null
+++ b/test/SemaCXX/copy-constructor-error.cpp
@@ -0,0 +1,13 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+struct S { // expected-note {{candidate function}}
+ S (S); // expected-error {{copy constructor must pass its first argument by reference}} \\
+ // expected-note {{candidate function}}
+};
+
+S f();
+
+void g() {
+ S a( f() ); // expected-error {{call to constructor of 'a' is ambiguous}}
+}
+
diff --git a/test/SemaCXX/cstyle-cast.cpp b/test/SemaCXX/cstyle-cast.cpp
new file mode 100644
index 0000000..9c47df9
--- /dev/null
+++ b/test/SemaCXX/cstyle-cast.cpp
@@ -0,0 +1,231 @@
+// RUN: clang-cc -fsyntax-only -verify -faccess-control %s
+
+struct A {};
+
+// ----------- const_cast --------------
+
+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);
+
+void t_cc()
+{
+ ccvpcvpp var = 0;
+ // Cast away deep consts and volatiles.
+ char ***var2 = (cppp)(var);
+ char ***const &var3 = var2;
+ // Const reference to reference.
+ char ***&var4 = (cpppr)(var3);
+ // Drop reference. Intentionally without qualifier change.
+ char *** var5 = (cppp)(var4);
+ const int ar[100] = {0};
+ // Array decay. Intentionally without qualifier change.
+ int *pi = (int*)(ar);
+ f fp = 0;
+ // Don't misidentify fn** as a function pointer.
+ f *fpp = (f*)(&fp);
+ int const A::* const A::*icapcap = 0;
+ int A::* A::* iapap = (int A::* A::*)(icapcap);
+}
+
+// ----------- static_cast -------------
+
+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 };
+
+struct Co1 { operator int(); };
+struct Co2 { Co2(int); };
+struct Co3 { };
+struct Co4 { Co4(Co3); operator Co3(); };
+
+// Explicit implicits
+void t_529_2()
+{
+ int i = 1;
+ (void)(float)(i);
+ double d = 1.0;
+ (void)(float)(d);
+ (void)(int)(d);
+ (void)(char)(i);
+ (void)(unsigned long)(i);
+ (void)(int)(En1);
+ (void)(double)(En1);
+ (void)(int&)(i);
+ (void)(const int&)(i);
+
+ int ar[1];
+ (void)(const int*)(ar);
+ (void)(void (*)())(t_529_2);
+
+ (void)(void*)(0);
+ (void)(void*)((int*)0);
+ (void)(volatile const void*)((const int*)0);
+ (void)(A*)((B*)0);
+ (void)(A&)(*((B*)0));
+ (void)(const B*)((C1*)0);
+ (void)(B&)(*((C1*)0));
+ (void)(A*)((D*)0);
+ (void)(const A&)(*((D*)0));
+ (void)(int B::*)((int A::*)0);
+ (void)(void (B::*)())((void (A::*)())0);
+ (void)(A*)((E*)0); // C-style cast ignores access control
+ (void)(void*)((const int*)0); // const_cast appended
+
+ (void)(int)(Co1());
+ (void)(Co2)(1);
+ (void)(Co3)((Co4)(Co3()));
+
+ // Bad code below
+ //(void)(A*)((H*)0); // {{static_cast from 'struct H *' to 'struct A *' is not allowed}}
+}
+
+// Anything to void
+void t_529_4()
+{
+ (void)(1);
+ (void)(t_529_4);
+}
+
+// Static downcasts
+void t_529_5_8()
+{
+ (void)(B*)((A*)0);
+ (void)(B&)(*((A*)0));
+ (void)(const G1*)((A*)0);
+ (void)(const G1&)(*((A*)0));
+ (void)(B*)((const A*)0); // const_cast appended
+ (void)(B&)(*((const A*)0)); // const_cast appended
+ (void)(E*)((A*)0); // access control ignored
+ (void)(E&)(*((A*)0)); // access control ignored
+
+ // Bad code below
+
+ (void)(C1*)((A*)0); // expected-error {{cannot cast 'struct A *' to 'struct C1 *' via virtual base 'struct B'}}
+ (void)(C1&)(*((A*)0)); // expected-error {{cannot cast 'struct A' to 'struct C1 &' via virtual base 'struct B'}}
+ (void)(D*)((A*)0); // expected-error {{cannot cast 'struct A *' to 'struct D *' via virtual base 'struct B'}}
+ (void)(D&)(*((A*)0)); // expected-error {{cannot cast 'struct A' to 'struct D &' via virtual base 'struct B'}}
+ (void)(H*)((A*)0); // expected-error {{ambiguous 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)(H&)(*((A*)0)); // expected-error {{ambiguous 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}}
+
+ // TODO: Test DR427. This requires user-defined conversions, though.
+}
+
+// Enum conversions
+void t_529_7()
+{
+ (void)(Enum)(1);
+ (void)(Enum)(1.0);
+ (void)(Onom)(En1);
+
+ // Bad code below
+
+ (void)(Enum)((int*)0); // expected-error {{C-style cast from 'int *' to 'enum Enum' is not allowed}}
+}
+
+// Void pointer to object pointer
+void t_529_10()
+{
+ (void)(int*)((void*)0);
+ (void)(const A*)((void*)0);
+ (void)(int*)((const void*)0); // const_cast appended
+}
+
+// Member pointer upcast.
+void t_529_9()
+{
+ (void)(int A::*)((int B::*)0);
+
+ // Bad code below
+ (void)(int A::*)((int H::*)0); // expected-error {{ambiguous conversion from pointer to member of derived class 'struct H'}}
+ (void)(int A::*)((int F::*)0); // expected-error {{conversion from pointer to member of class 'struct F'}}
+}
+
+// -------- reinterpret_cast -----------
+
+enum test { testval = 1 };
+struct structure { int m; };
+typedef void (*fnptr)();
+
+// Test conversion between pointer and integral types, as in p3 and p4.
+void integral_conversion()
+{
+ void *vp = (void*)(testval);
+ long l = (long)(vp);
+ (void)(float*)(l);
+ fnptr fnp = (fnptr)(l);
+ (void)(char)(fnp); // expected-error {{cast from pointer to smaller type 'char' loses information}}
+ (void)(long)(fnp);
+}
+
+void pointer_conversion()
+{
+ int *p1 = 0;
+ float *p2 = (float*)(p1);
+ structure *p3 = (structure*)(p2);
+ typedef int **ppint;
+ ppint *deep = (ppint*)(p3);
+ (void)(fnptr*)(deep);
+}
+
+void constness()
+{
+ int ***const ipppc = 0;
+ int const *icp = (int const*)(ipppc);
+ (void)(int*)(icp); // const_cast appended
+ int const *const **icpcpp = (int const* const**)(ipppc); // const_cast appended
+ int *ip = (int*)(icpcpp);
+ (void)(int const*)(ip);
+ (void)(int const* const* const*)(ipppc);
+}
+
+void fnptrs()
+{
+ typedef int (*fnptr2)(int);
+ fnptr fp = 0;
+ (void)(fnptr2)(fp);
+ void *vp = (void*)(fp);
+ (void)(fnptr)(vp);
+}
+
+void refs()
+{
+ long l = 0;
+ char &c = (char&)(l);
+ // Bad: from rvalue
+ (void)(int&)(&c); // expected-error {{C-style cast from rvalue to reference type 'int &'}}
+}
+
+void memptrs()
+{
+ const int structure::*psi = 0;
+ (void)(const float structure::*)(psi);
+ (void)(int structure::*)(psi); // const_cast appended
+
+ void (structure::*psf)() = 0;
+ (void)(int (structure::*)())(psf);
+
+ (void)(void (structure::*)())(psi); // expected-error {{C-style cast from 'int const struct structure::*' to 'void (struct structure::*)()' is not allowed}}
+ (void)(int structure::*)(psf); // expected-error {{C-style cast from 'void (struct structure::*)()' to 'int struct structure::*' is not allowed}}
+}
diff --git a/test/SemaCXX/dcl_ambig_res.cpp b/test/SemaCXX/dcl_ambig_res.cpp
index 57bf409..495a6e6 100644
--- a/test/SemaCXX/dcl_ambig_res.cpp
+++ b/test/SemaCXX/dcl_ambig_res.cpp
@@ -50,7 +50,7 @@ void foo5()
void foo6()
{
(void)(int(1)); //expression
- (void)(int())1; // expected-error{{used type}}
+ (void)(int())1; // expected-error{{to 'int ()'}}
}
// [dcl.ambig.res]p7:
@@ -64,3 +64,10 @@ void foo7() {
void h7(int *(C7[10])) { } // expected-note{{previous}}
void h7(int *(*_fp)(C7 _parm[10])) { } // expected-error{{redefinition}}
+
+struct S5 {
+ static bool const value = false;
+};
+int foo8() {
+ int v(int(S5::value)); // expected-warning{{disambiguated}} expected-error{{parameter declarator cannot be qualified}}
+}
diff --git a/test/SemaCXX/dcl_init_aggr.cpp b/test/SemaCXX/dcl_init_aggr.cpp
index 10c15cc..20b787a 100644
--- a/test/SemaCXX/dcl_init_aggr.cpp
+++ b/test/SemaCXX/dcl_init_aggr.cpp
@@ -40,8 +40,8 @@ char cv[4] = { 'a', 's', 'd', 'f', 0 }; // expected-error{{excess elements in ar
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 NoDefaultConstructor { // expected-note 3 {{candidate function}}
+ NoDefaultConstructor(int); // expected-note 3 {{candidate function}}
};
struct TooFewError {
int a;
@@ -53,7 +53,7 @@ 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}}
+NoDefaultConstructor too_few_error3[3] = { }; // expected-error {{no matching constructor}}
// C++ [dcl.init.aggr]p8
struct Empty { };
diff --git a/test/SemaCXX/decl-expr-ambiguity.cpp b/test/SemaCXX/decl-expr-ambiguity.cpp
index 05e25e9..8d34a9e 100644
--- a/test/SemaCXX/decl-expr-ambiguity.cpp
+++ b/test/SemaCXX/decl-expr-ambiguity.cpp
@@ -12,14 +12,14 @@ void f() {
__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;;) {}
+ for (int(a)+1;;) {} // expected-warning {{expression result unused}}
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 ()' where arithmetic or pointer type is required}}
+ (int())1; // expected-error {{C-style cast from 'int' to 'int ()' is not allowed}}
// Declarations.
int fd(T(a)); // expected-warning {{parentheses were disambiguated as a function declarator}}
diff --git a/test/SemaCXX/decl-init-ref.cpp b/test/SemaCXX/decl-init-ref.cpp
new file mode 100644
index 0000000..d7db647
--- /dev/null
+++ b/test/SemaCXX/decl-init-ref.cpp
@@ -0,0 +1,26 @@
+// RUN: clang-cc -fsyntax-only -verify -std=c++0x %s
+
+struct A {};
+
+struct BASE {
+ operator A(); // expected-note {{candidate function}}
+};
+
+struct BASE1 {
+ operator A(); // expected-note {{candidate function}}
+};
+
+class B : public BASE , public BASE1
+{
+ public:
+ B();
+} b;
+
+extern B f();
+
+const int& ri = (void)0; // expected-error {{invalid initialization of reference of type 'int const &' from expression of type 'void'}}
+
+int main() {
+ const A& rca = f(); // expected-error {{rvalue reference cannot bind to lvalue due to multiple conversion functions}}
+ A& ra = f(); // expected-error {{non-const lvalue reference to type 'struct A' cannot be initialized with a temporary of type 'class B'}}
+}
diff --git a/test/SemaCXX/decltype-crash.cpp b/test/SemaCXX/decltype-crash.cpp
new file mode 100644
index 0000000..b56a7f6
--- /dev/null
+++ b/test/SemaCXX/decltype-crash.cpp
@@ -0,0 +1,7 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+int& a();
+
+void f() {
+ decltype(a()) c; // expected-error {{no matching function for call to 'decltype'}}
+}
diff --git a/test/SemaCXX/decltype-this.cpp b/test/SemaCXX/decltype-this.cpp
new file mode 100644
index 0000000..fc00106
--- /dev/null
+++ b/test/SemaCXX/decltype-this.cpp
@@ -0,0 +1,15 @@
+// RUN: clang-cc -fsyntax-only -verify -std=c++0x %t
+template<typename T, typename U> struct is_same {
+ static const bool value = false;
+};
+
+template<typename T> struct is_same<T, T> {
+ static const bool value = true;
+};
+
+struct S {
+ void f() { static_assert(is_same<decltype(this), S*>::value, ""); }
+ void g() const { static_assert(is_same<decltype(this), const S*>::value, ""); }
+ void h() volatile { static_assert(is_same<decltype(this), volatile S*>::value, ""); }
+ void i() const volatile { static_assert(is_same<decltype(this), const volatile S*>::value, ""); }
+};
diff --git a/test/SemaCXX/default-argument-temporaries.cpp b/test/SemaCXX/default-argument-temporaries.cpp
new file mode 100644
index 0000000..232351d
--- /dev/null
+++ b/test/SemaCXX/default-argument-temporaries.cpp
@@ -0,0 +1,11 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+struct B { B(void* = 0); };
+
+struct A {
+ A(B b = B()) { }
+};
+
+void f() {
+ (void)B();
+ (void)A();
+}
diff --git a/test/SemaCXX/default-assignment-operator.cpp b/test/SemaCXX/default-assignment-operator.cpp
index 090ba3c..e627fef 100644
--- a/test/SemaCXX/default-assignment-operator.cpp
+++ b/test/SemaCXX/default-assignment-operator.cpp
@@ -26,7 +26,7 @@ Z z2;
// Test1
void f(X x, const X cx) {
- x = cx; // expected-note {{synthesized method is first required here}}
+ x = cx; // expected-note {{synthesized method is first required here}}
x = cx;
z1 = z2;
}
@@ -36,8 +36,7 @@ class T {};
T t1;
T t2;
-void g()
-{
+void g() {
t1 = t2;
}
@@ -51,8 +50,7 @@ public:
class W : V {};
W w1, w2;
-void h()
-{
+void h() {
w1 = w2;
}
@@ -67,8 +65,22 @@ public:
class D1 : B1 {};
D1 d1, d2;
-void i()
-{
- d1 = d2;
+void i() {
+ d1 = d2;
+}
+
+// Test5
+
+class E1 { // expected-error{{cannot define the implicit default assignment operator for 'class E1', because non-static const member 'a' can't use default assignment operator}}
+public:
+ const int a; // expected-note{{declared at}}
+ E1() : a(0) {}
+
+};
+
+E1 e1, e2;
+
+void j() {
+ e1 = e2; // expected-note{{synthesized method is first required here}}
}
diff --git a/test/SemaCXX/default-constructor-initializers.cpp b/test/SemaCXX/default-constructor-initializers.cpp
index 24c53839..6cbb978 100644
--- a/test/SemaCXX/default-constructor-initializers.cpp
+++ b/test/SemaCXX/default-constructor-initializers.cpp
@@ -11,16 +11,16 @@ struct X2 : X1 { // expected-note {{'struct X2' declared here}} \
struct X3 : public X2 {
};
-X3 x3; // expected-error {{cannot define the implicit default constructor for 'struct X3', because member 'struct X2' does not have any default constructor}}
+X3 x3; // expected-error {{cannot define the implicit default constructor for 'struct X3', because base class 'struct X2' does not have any default constructor}}
struct X4 {
- X2 x2;
+ X2 x2; // expected-note {{member is declared here}}
X2 & rx2; // expected-note {{declared at}}
};
-X4 x4; // expected-error {{cannot define the implicit default constructor for 'struct X4', because base class 'struct X2' does not have any default constructor}} \
- // expected-error {{cannot define the implicit default constructor for 'struct X4', because reference member rx2 cannot be default-initialized}}
+X4 x4; // expected-error {{cannot define the implicit default constructor for 'struct X4', because member's type 'struct X2' does not have any default constructor}} \
+ // expected-error {{cannot define the implicit default constructor for 'struct X4', because reference member 'rx2' cannot be default-initialized}}
struct Y1 { // has no implicit default constructor
@@ -46,11 +46,11 @@ Y4 y4;
struct Z1 {
- int& z; // expected-note {{declared at}}
- const int c1; // expected-note {{declared at}}
- volatile int v1;
+ int& z; // expected-note {{declared at}}
+ const int c1; // expected-note {{declared at}}
+ volatile int v1;
};
-Z1 z1; // expected-error {{cannot define the implicit default constructor for 'struct Z1', because reference member z cannot be default-initialized}} \
- // expected-error {{cannot define the implicit default constructor for 'struct Z1', because const member c1 cannot be default-initialized}}
+Z1 z1; // expected-error {{cannot define the implicit default constructor for 'struct Z1', because reference member 'z' cannot be default-initialized}} \
+ // expected-error {{cannot define the implicit default constructor for 'struct Z1', because const member 'c1' cannot be default-initialized}}
diff --git a/test/SemaCXX/default2.cpp b/test/SemaCXX/default2.cpp
index edbd6b3..1834520 100644
--- a/test/SemaCXX/default2.cpp
+++ b/test/SemaCXX/default2.cpp
@@ -24,20 +24,8 @@ int f1(int i, int i, int j) { // expected-error {{redefinition of parameter 'i'}
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}}
@@ -82,10 +70,6 @@ struct Y {
};
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
@@ -127,3 +111,9 @@ class C2 {
static void g(int = f()); // expected-error{{use of default argument to function 'f' that is declared later in class 'C2'}}
static int f(int = 10); // expected-note{{default argument declared here}}
};
+
+// Make sure we actually parse the default argument for an inline definition
+class XX {
+ void A(int length = -1 ) { }
+ void B() { A(); }
+};
diff --git a/test/SemaCXX/deleted-function.cpp b/test/SemaCXX/deleted-function.cpp
index 8064ed3..637b2b1 100644
--- a/test/SemaCXX/deleted-function.cpp
+++ b/test/SemaCXX/deleted-function.cpp
@@ -18,7 +18,7 @@ void ov(double) = delete; // expected-note {{candidate function has been explici
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;
+ operator int() = delete;
void operator +(int) = delete;
int i = delete; // expected-error {{only functions can have deleted definitions}}
diff --git a/test/SemaCXX/destructor.cpp b/test/SemaCXX/destructor.cpp
index f544db0..790a401 100644
--- a/test/SemaCXX/destructor.cpp
+++ b/test/SemaCXX/destructor.cpp
@@ -40,8 +40,9 @@ struct F {
~F(); // expected-error {{destructor cannot be redeclared}}
};
-~; // expected-error {{expected class name}}
-~undef(); // expected-error {{expected class name}}
+~; // expected-error {{expected the class name after '~' to name a destructor}}
+~undef(); // expected-error {{expected the class name after '~' to name a destructor}}
+~operator+(int, int); // expected-error {{expected the class name after '~' to name a destructor}}
~F(){} // expected-error {{destructor must be a non-static member function}}
struct G {
@@ -54,3 +55,9 @@ G::~G() { }
struct H {
~H(void) { }
};
+
+struct X {};
+
+struct Y {
+ ~X(); // expected-error {{expected the class name after '~' to name the enclosing class}}
+};
diff --git a/test/SemaCXX/direct-initializer.cpp b/test/SemaCXX/direct-initializer.cpp
index 149b65c..a9e2b2b 100644
--- a/test/SemaCXX/direct-initializer.cpp
+++ b/test/SemaCXX/direct-initializer.cpp
@@ -34,3 +34,17 @@ void g() {
Z z; // expected-error{{no matching constructor for initialization of 'z'}}
}
+
+struct Base {
+ operator int*() const;
+};
+
+struct Derived : Base {
+ operator int*();
+};
+
+void foo(const Derived cd, Derived d) {
+ int *pi = cd; // expected-error {{incompatible type initializing 'struct Derived const', expected 'int *'}}
+ int *ppi = d;
+
+}
diff --git a/test/SemaCXX/empty-class-layout.cpp b/test/SemaCXX/empty-class-layout.cpp
new file mode 100644
index 0000000..8b54ea1
--- /dev/null
+++ b/test/SemaCXX/empty-class-layout.cpp
@@ -0,0 +1,68 @@
+// RUN: clang-cc -triple x86_64-unknown-unknown %s -fsyntax-only -verify
+
+#define SA(n, p) int a##n[(p) ? 1 : -1]
+
+struct A { int a; };
+SA(0, sizeof(A) == 4);
+
+struct B { };
+SA(1, sizeof(B) == 1);
+
+struct C : A, B { };
+SA(2, sizeof(C) == 4);
+
+struct D { };
+struct E : D { };
+struct F : E { };
+
+struct G : E, F { };
+SA(3, sizeof(G) == 2);
+
+struct Empty { Empty(); };
+
+struct I : Empty {
+ Empty e;
+};
+SA(4, sizeof(I) == 2);
+
+struct J : Empty {
+ Empty e[2];
+};
+SA(5, sizeof(J) == 3);
+
+template<int N> struct Derived : Empty, Derived<N - 1> {
+};
+template<> struct Derived<0> : Empty { };
+
+struct S1 : virtual Derived<10> {
+ Empty e;
+};
+SA(6, sizeof(S1) == 24);
+
+struct S2 : virtual Derived<10> {
+ Empty e[2];
+};
+SA(7, sizeof(S2) == 24);
+
+struct S3 {
+ Empty e;
+};
+
+struct S4 : Empty, S3 {
+};
+SA(8, sizeof(S4) == 2);
+
+struct S5 : S3, Empty {};
+SA(9, sizeof(S5) == 2);
+
+struct S6 : S5 { };
+SA(10, sizeof(S6) == 2);
+
+struct S7 : Empty {
+ void *v;
+};
+SA(11, sizeof(S7) == 8);
+
+struct S8 : Empty, A {
+};
+SA(12, sizeof(S8) == 4);
diff --git a/test/SemaCXX/enum.cpp b/test/SemaCXX/enum.cpp
index 9668c84..db25681 100644
--- a/test/SemaCXX/enum.cpp
+++ b/test/SemaCXX/enum.cpp
@@ -14,14 +14,13 @@ void f() {
// <rdar://problem/6502934>
typedef enum Foo {
- A = 0,
- B = 1
+ A = 0,
+ B = 1
} Foo;
-
-
+
void bar() {
- Foo myvar = A;
- myvar = B;
+ Foo myvar = A;
+ myvar = B;
}
/// PR3688
@@ -32,7 +31,7 @@ struct s1 {
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}}
+ return q->bar(); // expected-error{{calling function with incomplete return type 'enum s1::e1'}}
}
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
index 5eba26e..9b2a07d 100644
--- a/test/SemaCXX/exception-spec.cpp
+++ b/test/SemaCXX/exception-spec.cpp
@@ -24,7 +24,7 @@ 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;
+struct Incomplete; // expected-note 3 {{forward declaration}}
// Exception spec must not have incomplete types, or pointers to them, except
// void.
@@ -61,3 +61,127 @@ void r7() throw(float); // expected-error {{exception specification in declarati
// Top-level const doesn't matter.
void r8() throw(int);
void r8() throw(const int);
+
+// Multiple appearances don't matter.
+void r9() throw(int, int);
+void r9() throw(int, int);
+
+struct A
+{
+};
+
+struct B1 : A
+{
+};
+
+struct B2 : A
+{
+};
+
+struct D : B1, B2
+{
+};
+
+struct P : private A
+{
+};
+
+struct Base
+{
+ virtual void f1() throw();
+ virtual void f2();
+ virtual void f3() throw(...);
+ virtual void f4() throw(int, float);
+
+ virtual void f5() throw(int, float);
+ virtual void f6() throw(A);
+ virtual void f7() throw(A, int, float);
+ virtual void f8();
+
+ virtual void g1() throw(); // expected-note {{overridden virtual function is here}}
+ virtual void g2() throw(int); // expected-note {{overridden virtual function is here}}
+ virtual void g3() throw(A); // expected-note {{overridden virtual function is here}}
+ virtual void g4() throw(B1); // expected-note {{overridden virtual function is here}}
+ virtual void g5() throw(A); // expected-note {{overridden virtual function is here}}
+};
+struct Derived : Base
+{
+ virtual void f1() throw();
+ virtual void f2() throw(...);
+ virtual void f3();
+ virtual void f4() throw(float, int);
+
+ virtual void f5() throw(float);
+ virtual void f6() throw(B1);
+ virtual void f7() throw(B1, B2, int);
+ virtual void f8() throw(B2, B2, int, float, char, double, bool);
+
+ virtual void g1() throw(int); // expected-error {{exception specification of overriding function is more lax}}
+ virtual void g2(); // expected-error {{exception specification of overriding function is more lax}}
+ virtual void g3() throw(D); // expected-error {{exception specification of overriding function is more lax}}
+ virtual void g4() throw(A); // expected-error {{exception specification of overriding function is more lax}}
+ virtual void g5() throw(P); // expected-error {{exception specification of overriding function is more lax}}
+};
+
+// Some functions to play with below.
+void s1() throw();
+void s2() throw(int);
+void s3() throw(A);
+void s4() throw(B1);
+void s5() throw(D);
+void s6();
+void s7() throw(int, float);
+void (*s8())() throw(B1); // s8 returns a pointer to function with spec
+void s9(void (*)() throw(B1)); // s9 takes pointer to function with spec
+
+void fnptrs()
+{
+ // Assignment and initialization of function pointers.
+ void (*t1)() throw() = &s1; // valid
+ t1 = &s2; // expected-error {{not superset}} expected-error {{incompatible type}}
+ t1 = &s3; // expected-error {{not superset}} expected-error {{incompatible type}}
+ void (&t2)() throw() = s2; // expected-error {{not superset}}
+ void (*t3)() throw(int) = &s2; // valid
+ void (*t4)() throw(A) = &s1; // valid
+ t4 = &s3; // valid
+ t4 = &s4; // valid
+ t4 = &s5; // expected-error {{not superset}} expected-error {{incompatible type}}
+ void (*t5)() = &s1; // valid
+ t5 = &s2; // valid
+ t5 = &s6; // valid
+ t5 = &s7; // valid
+ t1 = t3; // expected-error {{not superset}} expected-error {{incompatible type}}
+ t3 = t1; // valid
+ void (*t6)() throw(B1);
+ t6 = t4; // expected-error {{not superset}} expected-error {{incompatible type}}
+ t4 = t6; // valid
+ t5 = t1; // valid
+ t1 = t5; // expected-error {{not superset}} expected-error {{incompatible type}}
+
+ // return types and arguments must match exactly, no inheritance allowed
+ void (*(*t7)())() throw(B1) = &s8; // valid
+ void (*(*t8)())() throw(A) = &s8; // expected-error {{return types differ}} expected-error {{incompatible type}}
+ void (*(*t9)())() throw(D) = &s8; // expected-error {{return types differ}} expected-error {{incompatible type}}
+ void (*t10)(void (*)() throw(B1)) = &s9; // valid expected-warning{{disambiguated}}
+ void (*t11)(void (*)() throw(A)) = &s9; // expected-error {{argument types differ}} expected-error {{incompatible type}} expected-warning{{disambiguated}}
+ void (*t12)(void (*)() throw(D)) = &s9; // expected-error {{argument types differ}} expected-error {{incompatible type}} expected-warning{{disambiguated}}
+}
+
+// Member function stuff
+
+struct Str1 { void f() throw(int); }; // expected-note {{previous declaration}}
+void Str1::f() // expected-error {{does not match previous declaration}}
+{
+}
+
+void mfnptr()
+{
+ void (Str1::*pfn1)() throw(int) = &Str1::f; // valid
+ void (Str1::*pfn2)() = &Str1::f; // valid
+ void (Str1::*pfn3)() throw() = &Str1::f; // expected-error {{not superset}} expected-error {{incompatible type}}
+}
+
+// Don't suppress errors in template instantiation.
+template <typename T> struct TEx; // expected-note {{template is declared here}}
+
+void tf() throw(TEx<int>); // expected-error {{implicit instantiation of undefined template}}
diff --git a/test/SemaCXX/friend-class-nodecl.cpp b/test/SemaCXX/friend-class-nodecl.cpp
new file mode 100644
index 0000000..de12eaf
--- /dev/null
+++ b/test/SemaCXX/friend-class-nodecl.cpp
@@ -0,0 +1,10 @@
+// RUN: clang-cc -ast-print %s -o %t &&
+// RUN: not grep '^ *class B' %t
+
+// Tests that the tag decls in friend declarations aren't added to the
+// declaring class's decl chain.
+
+class A {
+ friend class B;
+};
+
diff --git a/test/SemaCXX/function-overloaded-redecl.cpp b/test/SemaCXX/function-overloaded-redecl.cpp
new file mode 100644
index 0000000..4d8e57c
--- /dev/null
+++ b/test/SemaCXX/function-overloaded-redecl.cpp
@@ -0,0 +1,10 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+typedef const int cInt;
+
+void f (int);
+void f (const int); // redecl
+
+void f (int) { } // expected-note {{previous definition is here}}
+void f (cInt) { } // expected-error {{redefinition of 'f'}}
+
diff --git a/test/SemaCXX/functional-cast.cpp b/test/SemaCXX/functional-cast.cpp
index 0be7ddb..142dba7 100644
--- a/test/SemaCXX/functional-cast.cpp
+++ b/test/SemaCXX/functional-cast.cpp
@@ -1,4 +1,6 @@
-// RUN: clang-cc -fsyntax-only -verify %s
+// RUN: clang-cc -fsyntax-only -verify -faccess-control %s
+
+// ------------ not interpreted as C-style cast ------------
struct SimpleValueInit {
int i;
@@ -25,3 +27,293 @@ void test_cxx_function_cast_multi() {
(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}}
}
+
+
+// ------------------ everything else --------------------
+
+struct A {};
+
+// ----------- const_cast --------------
+
+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);
+
+void t_cc()
+{
+ ccvpcvpp var = 0;
+ // Cast away deep consts and volatiles.
+ char ***var2 = cppp(var);
+ char ***const &var3 = var2;
+ // Const reference to reference.
+ char ***&var4 = cpppr(var3);
+ // Drop reference. Intentionally without qualifier change.
+ char *** var5 = cppp(var4);
+ const int ar[100] = {0};
+ // Array decay. Intentionally without qualifier change.
+ typedef int *intp;
+ int *pi = intp(ar);
+ f fp = 0;
+ // Don't misidentify fn** as a function pointer.
+ typedef f *fp_t;
+ f *fpp = fp_t(&fp);
+ int const A::* const A::*icapcap = 0;
+ typedef int A::* A::*iapap_t;
+ iapap_t iapap = iapap_t(icapcap);
+}
+
+// ----------- static_cast -------------
+
+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 };
+
+struct Co1 { operator int(); };
+struct Co2 { Co2(int); };
+struct Co3 { };
+struct Co4 { Co4(Co3); operator Co3(); };
+
+// Explicit implicits
+void t_529_2()
+{
+ int i = 1;
+ (void)float(i);
+ double d = 1.0;
+ (void)float(d);
+ (void)int(d);
+ (void)char(i);
+ typedef unsigned long ulong;
+ (void)ulong(i);
+ (void)int(En1);
+ (void)double(En1);
+ typedef int &intr;
+ (void)intr(i);
+ typedef const int &cintr;
+ (void)cintr(i);
+
+ int ar[1];
+ typedef const int *cintp;
+ (void)cintp(ar);
+ typedef void (*pfvv)();
+ (void)pfvv(t_529_2);
+
+ typedef void *voidp;
+ (void)voidp(0);
+ (void)voidp((int*)0);
+ typedef volatile const void *vcvoidp;
+ (void)vcvoidp((const int*)0);
+ typedef A *Ap;
+ (void)Ap((B*)0);
+ typedef A &Ar;
+ (void)Ar(*((B*)0));
+ typedef const B *cBp;
+ (void)cBp((C1*)0);
+ typedef B &Br;
+ (void)Br(*((C1*)0));
+ (void)Ap((D*)0);
+ typedef const A &cAr;
+ (void)cAr(*((D*)0));
+ typedef int B::*Bmp;
+ (void)Bmp((int A::*)0);
+ typedef void (B::*Bmfp)();
+ (void)Bmfp((void (A::*)())0);
+ (void)Ap((E*)0); // functional-style cast ignores access control
+ (void)voidp((const int*)0); // const_cast appended
+
+ (void)int(Co1());
+ (void)Co2(1);
+ (void)Co3((Co4)(Co3()));
+
+ // Bad code below
+ //(void)(A*)((H*)0); // {{static_cast from 'struct H *' to 'struct A *' is not allowed}}
+}
+
+// Anything to void
+void t_529_4()
+{
+ void(1);
+ (void(t_529_4));
+}
+
+// Static downcasts
+void t_529_5_8()
+{
+ typedef B *Bp;
+ (void)Bp((A*)0);
+ typedef B &Br;
+ (void)Br(*((A*)0));
+ typedef const G1 *cG1p;
+ (void)cG1p((A*)0);
+ typedef const G1 &cG1r;
+ (void)cG1r(*((A*)0));
+ (void)Bp((const A*)0); // const_cast appended
+ (void)Br(*((const A*)0)); // const_cast appended
+ typedef E *Ep;
+ (void)Ep((A*)0); // access control ignored
+ typedef E &Er;
+ (void)Er(*((A*)0)); // access control ignored
+
+ // Bad code below
+
+ typedef C1 *C1p;
+ (void)C1p((A*)0); // expected-error {{cannot cast 'struct A *' to 'C1p' (aka 'struct C1 *') via virtual base 'struct B'}}
+ typedef C1 &C1r;
+ (void)C1r(*((A*)0)); // expected-error {{cannot cast 'struct A' to 'C1r' (aka 'struct C1 &') via virtual base 'struct B'}}
+ typedef D *Dp;
+ (void)Dp((A*)0); // expected-error {{cannot cast 'struct A *' to 'Dp' (aka 'struct D *') via virtual base 'struct B'}}
+ typedef D &Dr;
+ (void)Dr(*((A*)0)); // expected-error {{cannot cast 'struct A' to 'Dr' (aka 'struct D &') via virtual base 'struct B'}}
+ typedef H *Hp;
+ (void)Hp((A*)0); // expected-error {{ambiguous 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}}
+ typedef H &Hr;
+ (void)Hr(*((A*)0)); // expected-error {{ambiguous 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}}
+
+ // TODO: Test DR427. This requires user-defined conversions, though.
+}
+
+// Enum conversions
+void t_529_7()
+{
+ (void)Enum(1);
+ (void)Enum(1.0);
+ (void)Onom(En1);
+
+ // Bad code below
+
+ (void)Enum((int*)0); // expected-error {{functional-style cast from 'int *' to 'enum Enum' is not allowed}}
+}
+
+// Void pointer to object pointer
+void t_529_10()
+{
+ typedef int *intp;
+ (void)intp((void*)0);
+ typedef const A *cAp;
+ (void)cAp((void*)0);
+ (void)intp((const void*)0); // const_cast appended
+}
+
+// Member pointer upcast.
+void t_529_9()
+{
+ typedef int A::*Amp;
+ (void)Amp((int B::*)0);
+
+ // Bad code below
+ (void)Amp((int H::*)0); // expected-error {{ambiguous conversion from pointer to member of derived class 'struct H'}}
+ (void)Amp((int F::*)0); // expected-error {{conversion from pointer to member of class 'struct F'}}
+}
+
+// -------- reinterpret_cast -----------
+
+enum test { testval = 1 };
+struct structure { int m; };
+typedef void (*fnptr)();
+
+// Test conversion between pointer and integral types, as in p3 and p4.
+void integral_conversion()
+{
+ typedef void *voidp;
+ void *vp = voidp(testval);
+ long l = long(vp);
+ typedef float *floatp;
+ (void)floatp(l);
+ fnptr fnp = fnptr(l);
+ (void)char(fnp); // expected-error {{cast from pointer to smaller type 'char' loses information}}
+ (void)long(fnp);
+}
+
+void pointer_conversion()
+{
+ int *p1 = 0;
+ typedef float *floatp;
+ float *p2 = floatp(p1);
+ typedef structure *structurep;
+ structure *p3 = structurep(p2);
+ typedef int **ppint;
+ typedef ppint *pppint;
+ ppint *deep = pppint(p3);
+ typedef fnptr fnptrp;
+ (void)fnptrp(deep);
+}
+
+void constness()
+{
+ int ***const ipppc = 0;
+ typedef int const *icp_t;
+ int const *icp = icp_t(ipppc);
+ typedef int *intp;
+ (void)intp(icp); // const_cast appended
+ typedef int const *const ** intcpcpp;
+ intcpcpp icpcpp = intcpcpp(ipppc); // const_cast appended
+ int *ip = intp(icpcpp);
+ (void)icp_t(ip);
+ typedef int const *const *const *intcpcpcp;
+ (void)intcpcpcp(ipppc);
+}
+
+void fnptrs()
+{
+ typedef int (*fnptr2)(int);
+ fnptr fp = 0;
+ (void)fnptr2(fp);
+ typedef void *voidp;
+ void *vp = voidp(fp);
+ (void)fnptr(vp);
+}
+
+void refs()
+{
+ long l = 0;
+ typedef char &charr;
+ char &c = charr(l);
+ // Bad: from rvalue
+ typedef int &intr;
+ (void)intr(&c); // expected-error {{functional-style cast from rvalue to reference type 'intr' (aka 'int &')}}
+}
+
+void memptrs()
+{
+ const int structure::*psi = 0;
+ typedef const float structure::*structurecfmp;
+ (void)structurecfmp(psi);
+ typedef int structure::*structureimp;
+ (void)structureimp(psi); // const_cast appended
+
+ void (structure::*psf)() = 0;
+ typedef int (structure::*structureimfp)();
+ (void)structureimfp(psf);
+
+ typedef void (structure::*structurevmfp)();
+ (void)structurevmfp(psi); // expected-error {{functional-style cast from 'int const struct structure::*' to 'structurevmfp' (aka 'void (struct structure::*)()') is not allowed}}
+ (void)structureimp(psf); // expected-error {{functional-style cast from 'void (struct structure::*)()' to 'structureimp' (aka 'int struct structure::*') is not allowed}}
+}
+
+// ---------------- misc ------------------
+
+void crash_on_invalid_1()
+{
+ typedef itn Typo; // expected-error {{unknown type name 'itn'}}
+ (void)Typo(1); // used to crash
+}
diff --git a/test/SemaCXX/i-c-e-cxx.cpp b/test/SemaCXX/i-c-e-cxx.cpp
index 32d04e2..785ea0e 100644
--- a/test/SemaCXX/i-c-e-cxx.cpp
+++ b/test/SemaCXX/i-c-e-cxx.cpp
@@ -4,3 +4,13 @@
const int c = 10;
int ar[c];
+
+struct X0 {
+ static const int value = static_cast<int>(4.0);
+};
+
+void f() {
+ if (const int value = 17) {
+ int array[value];
+ }
+}
diff --git a/test/SemaCXX/illegal-member-initialization.cpp b/test/SemaCXX/illegal-member-initialization.cpp
new file mode 100644
index 0000000..2d7c73d
--- /dev/null
+++ b/test/SemaCXX/illegal-member-initialization.cpp
@@ -0,0 +1,22 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+struct A {
+ A() : value(), cvalue() { } // expected-error {{cannot initialize the member to null in default constructor because reference member 'value' cannot be null-initialized}} \
+ // expected-error {{constructor for 'struct A' must explicitly initialize the reference member 'value'}}
+ int &value; // expected-note{{declared at}} {{expected-note{{declared at}}
+ const int cvalue;
+};
+
+struct B {
+};
+
+struct X {
+ X() { } // expected-error {{constructor for 'struct X' must explicitly initialize the reference member 'value'}} \
+ // expected-error {{constructor for 'struct X' must explicitly initialize the const member 'cvalue'}} \
+ // expected-error {{constructor for 'struct X' must explicitly initialize the reference member 'b'}} \
+ // expected-error {{constructor for 'struct X' must explicitly initialize the const member 'cb'}}
+ int &value; // expected-note{{declared at}}
+ const int cvalue; // expected-note{{declared at}}
+ B& b; // expected-note{{declared at}}
+ const B cb; // expected-note{{declared at}}
+};
diff --git a/test/SemaCXX/incomplete-call.cpp b/test/SemaCXX/incomplete-call.cpp
new file mode 100644
index 0000000..6134189
--- /dev/null
+++ b/test/SemaCXX/incomplete-call.cpp
@@ -0,0 +1,38 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+struct A; // expected-note 13 {{forward declaration of 'struct A'}}
+
+A f(); // expected-note {{note: 'f' declared here}}
+
+struct B {
+ A f(); // expected-note {{'f' declared here}}
+ A operator()(); // expected-note 2 {{'operator()' declared here}}
+ operator A(); // expected-note {{'operator A' declared here}}
+ A operator!(); // expected-note 2 {{'operator!' declared here}}
+ A operator++(int); // expected-note {{'operator++' declared here}}
+ A operator[](int); // expected-note {{'operator[]' declared here}}
+ A operator+(int); // expected-note {{'operator+' declared here}}
+ A operator->(); // expected-note {{'operator->' declared here}}
+};
+
+void g() {
+ f(); // expected-error {{calling 'f' with incomplete return type 'struct A'}}
+
+ typedef A (*Func)();
+ Func fp;
+ fp(); // expected-error {{calling function with incomplete return type 'struct A'}}
+ ((Func)0)(); // expected-error {{calling function with incomplete return type 'struct A'}}
+
+ B b;
+ b.f(); // expected-error {{calling 'f' with incomplete return type 'struct A'}}
+
+ b.operator()(); // expected-error {{calling 'operator()' with incomplete return type 'struct A'}}
+ b.operator A(); // expected-error {{calling 'operator A' with incomplete return type 'struct A'}}
+ b.operator!(); // expected-error {{calling 'operator!' with incomplete return type 'struct A'}}
+
+ !b; // expected-error {{calling 'operator!' with incomplete return type 'struct A'}}
+ b(); // expected-error {{calling 'operator()' with incomplete return type 'struct A'}}
+ b++; // expected-error {{calling 'operator++' with incomplete return type 'struct A'}}
+ b[0]; // expected-error {{calling 'operator[]' with incomplete return type 'struct A'}}
+ b + 1; // expected-error {{calling 'operator+' with incomplete return type 'struct A'}}
+ b->f(); // expected-error {{calling 'operator->' with incomplete return type 'struct A'}}
+}
diff --git a/test/SemaCXX/inherit.cpp b/test/SemaCXX/inherit.cpp
index eaad97cc..069e30d 100644
--- a/test/SemaCXX/inherit.cpp
+++ b/test/SemaCXX/inherit.cpp
@@ -10,7 +10,7 @@ class B3 : virtual virtual A { }; // expected-error{{duplicate 'virtual' in base
class C : public B1, private B2 { };
-class D; // expected-note {{forward declaration of 'class D'}}
+class D; // expected-note {{forward declaration of 'class D'}}
class E : public D { }; // expected-error{{base class has incomplete type}}
diff --git a/test/SemaCXX/invalid-member-expr.cpp b/test/SemaCXX/invalid-member-expr.cpp
new file mode 100644
index 0000000..90932ed
--- /dev/null
+++ b/test/SemaCXX/invalid-member-expr.cpp
@@ -0,0 +1,21 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+class X {};
+
+void test() {
+ X x;
+
+ x.int; // expected-error{{expected identifier}}
+ x.~int(); // expected-error{{expected identifier}}
+ x.operator; // expected-error{{missing type specifier after 'operator'}}
+ x.operator typedef; // expected-error{{missing type specifier after 'operator'}}
+}
+
+void test2() {
+ X *x;
+
+ x->int; // expected-error{{expected identifier}}
+ x->~int(); // expected-error{{expected identifier}}
+ x->operator; // expected-error{{missing type specifier after 'operator'}}
+ x->operator typedef; // expected-error{{missing type specifier after 'operator'}}
+}
diff --git a/test/SemaCXX/invalid-template-specifier.cpp b/test/SemaCXX/invalid-template-specifier.cpp
new file mode 100644
index 0000000..a3f081f
--- /dev/null
+++ b/test/SemaCXX/invalid-template-specifier.cpp
@@ -0,0 +1,12 @@
+// RUN: clang-cc %s -verify -fsyntax-only
+// PR4809
+// This test is primarily checking that this doesn't crash, not the particular
+// diagnostics.
+
+const template basic_istream<char>; // expected-error {{expected unqualified-id}}
+
+namespace S {}
+template <class X> class Y {
+ void x() { S::template y<char>(1); } // expected-error {{does not refer to a template}} \
+ // expected-error {{no member named 'y'}}
+};
diff --git a/test/SemaCXX/libstdcxx_is_pod_hack.cpp b/test/SemaCXX/libstdcxx_is_pod_hack.cpp
new file mode 100644
index 0000000..df064bc
--- /dev/null
+++ b/test/SemaCXX/libstdcxx_is_pod_hack.cpp
@@ -0,0 +1,7 @@
+// RUN: clang-cc -fsyntax-only %s
+
+template<typename T>
+struct __is_pod {
+};
+
+__is_pod<int> ipi;
diff --git a/test/SemaCXX/linkage-spec.cpp b/test/SemaCXX/linkage-spec.cpp
index 864953e..b4c72f5 100644
--- a/test/SemaCXX/linkage-spec.cpp
+++ b/test/SemaCXX/linkage-spec.cpp
@@ -25,3 +25,11 @@ extern "C" int const bar;
// <rdar://problem/6895431>
extern "C" struct bar d;
extern struct bar e;
+
+extern "C++" {
+ namespace N0 {
+ struct X0 {
+ int foo(int x) { return x; }
+ };
+ }
+} \ No newline at end of file
diff --git a/test/SemaCXX/member-expr-static.cpp b/test/SemaCXX/member-expr-static.cpp
index b6495a8..2fa7e07 100644
--- a/test/SemaCXX/member-expr-static.cpp
+++ b/test/SemaCXX/member-expr-static.cpp
@@ -2,20 +2,18 @@
typedef void (*thread_continue_t)();
extern "C" {
-extern void kernel_thread_start(thread_continue_t continuation);
-extern void pure_c(void);
+ extern void kernel_thread_start(thread_continue_t continuation);
+ extern void pure_c(void);
}
-class _IOConfigThread
-{
+class _IOConfigThread {
public:
- static void main( void );
+ 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);
+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-name-lookup.cpp b/test/SemaCXX/member-name-lookup.cpp
index 9fcd922..e95641b 100644
--- a/test/SemaCXX/member-name-lookup.cpp
+++ b/test/SemaCXX/member-name-lookup.cpp
@@ -146,3 +146,13 @@ struct HasAnotherMemberType : HasMemberType1, HasMemberType2 {
struct UsesAmbigMemberType : HasMemberType1, HasMemberType2 {
type t; // expected-error{{member 'type' found in multiple base classes of different types}}
};
+
+struct X0 {
+ struct Inner {
+ static const int m;
+ };
+
+ static const int n = 17;
+};
+
+const int X0::Inner::m = n;
diff --git a/test/SemaCXX/member-operator-expr.cpp b/test/SemaCXX/member-operator-expr.cpp
new file mode 100644
index 0000000..4d0e00f
--- /dev/null
+++ b/test/SemaCXX/member-operator-expr.cpp
@@ -0,0 +1,29 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+class X {
+public:
+ int operator++();
+ operator int();
+};
+
+void test() {
+ X x;
+ int i;
+
+ i = x.operator++();
+ i = x.operator int();
+ x.operator--(); // expected-error{{no member named 'operator--'}}
+ x.operator float(); // expected-error{{no member named 'operator float'}}
+ x.operator; // expected-error{{missing type specifier after 'operator'}}
+}
+
+void test2() {
+ X *x;
+ int i;
+
+ i = x->operator++();
+ i = x->operator int();
+ x->operator--(); // expected-error{{no member named 'operator--'}}
+ x->operator float(); // expected-error{{no member named 'operator float'}}
+ x->operator; // expected-error{{missing type specifier after 'operator'}}
+}
diff --git a/test/SemaCXX/member-pointer.cpp b/test/SemaCXX/member-pointer.cpp
index 3b106d5..d13b16e 100644
--- a/test/SemaCXX/member-pointer.cpp
+++ b/test/SemaCXX/member-pointer.cpp
@@ -40,6 +40,14 @@ void f() {
// Conversion to member of base.
pdi1 = pdid; // expected-error {{incompatible type assigning 'int struct D::*', expected 'int struct A::*'}}
+
+ // Comparisons
+ int (A::*pf2)(int, int);
+ int (D::*pf3)(int, int) = 0;
+ bool b1 = (pf == pf2); (void)b1;
+ bool b2 = (pf != pf2); (void)b2;
+ bool b3 = (pf == pf3); (void)b3;
+ bool b4 = (pf != 0); (void)b4;
}
struct TheBase
@@ -91,7 +99,7 @@ void h() {
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)&((&hm)->*pi);
void (HasMembers::*pf)() = &HasMembers::f;
(hm.*pf)();
diff --git a/test/SemaCXX/missing-members.cpp b/test/SemaCXX/missing-members.cpp
new file mode 100644
index 0000000..28ad9a0
--- /dev/null
+++ b/test/SemaCXX/missing-members.cpp
@@ -0,0 +1,36 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+namespace A {
+ namespace B {
+ class C { };
+ struct S { };
+ union U { };
+ }
+}
+
+void f() {
+ A::B::i; // expected-error {{no member named 'i' in namespace 'A::B'}}
+ A::B::C::i; // expected-error {{no member named 'i' in 'class A::B::C'}}
+ ::i; // expected-error {{no member named 'i' in the global namespace}}
+}
+
+namespace B {
+ class B { };
+}
+
+void g() {
+ A::B::D::E; // expected-error {{no member named 'D' in namespace 'A::B'}}
+ B::B::C::D; // expected-error {{no member named 'C' in 'class B::B'}}
+ ::C::D; // expected-error {{no member named 'C' in the global namespace}}
+}
+
+int A::B::i = 10; // expected-error {{no member named 'i' in namespace 'A::B'}}
+int A::B::C::i = 10; // expected-error {{no member named 'i' in 'class A::B::C'}}
+int A::B::S::i = 10; // expected-error {{no member named 'i' in 'struct A::B::S'}}
+int A::B::U::i = 10; // expected-error {{no member named 'i' in 'union A::B::U'}}
+
+using A::B::D; // expected-error {{no member named 'D' in namespace 'A::B'}}
+
+struct S : A::B::C {
+ using A::B::C::f; // expected-error {{no member named 'f' in 'class A::B::C'}}
+
+};
diff --git a/test/SemaCXX/namespace.cpp b/test/SemaCXX/namespace.cpp
index 696ea81..5ed6ba5 100644
--- a/test/SemaCXX/namespace.cpp
+++ b/test/SemaCXX/namespace.cpp
@@ -8,7 +8,8 @@ void f() { A = 0; } // expected-error {{unexpected namespace name 'A': expected
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}}
+class B {}; // expected-note {{previous definition is here}} \
+ // FIXME: ugly expected-note{{candidate function}}
void C(); // expected-note {{previous definition is here}}
namespace C {} // expected-error {{redefinition of 'C' as different kind of symbol}}
@@ -66,4 +67,4 @@ namespace foo {
static foo::x test1; // ok
-static foo::X test2; // typo: expected-error {{unknown type name 'X'}}
+static foo::X test2; // typo: expected-error {{no type named 'X' in}}
diff --git a/test/SemaCXX/nested-name-spec.cpp b/test/SemaCXX/nested-name-spec.cpp
index 8fff8a2..5178557 100644
--- a/test/SemaCXX/nested-name-spec.cpp
+++ b/test/SemaCXX/nested-name-spec.cpp
@@ -13,8 +13,8 @@ namespace A {
}
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'}}
+::A::ax::undef ex3; // expected-error {{no member named}}
+A::undef1::undef2 ex4; // expected-error {{no member named 'undef1'}}
int A::C::Ag1() { return 0; }
@@ -35,9 +35,9 @@ class C2 {
int x;
};
-void C2::m() const { } // expected-error{{out-of-line definition does not match any declaration in 'C2'}}
+void C2::m() const { } // expected-error{{out-of-line definition of 'm' does not match any declaration in 'class C2'}}
-void C2::f(int) { } // expected-error{{out-of-line definition does not match any declaration in 'C2'}}
+void C2::f(int) { } // expected-error{{out-of-line definition of 'f' does not match any declaration in 'class C2'}}
void C2::m() {
x = 0;
@@ -125,7 +125,7 @@ class Operators {
operator bool();
};
-Operators Operators::operator+(const Operators&) { // expected-error{{out-of-line definition does not match any declaration in 'Operators'}}
+Operators Operators::operator+(const Operators&) { // expected-error{{out-of-line definition of 'operator+' does not match any declaration in 'class Operators'}}
Operators ops;
return ops;
}
@@ -143,13 +143,13 @@ 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::f() {} // expected-error{{out-of-line definition of 'f' does not match any declaration in namespace 'A'}}
-void A::g(const int&) { } // expected-error{{out-of-line definition does not match any declaration in 'A'}}
+void A::g(const int&) { } // expected-error{{out-of-line definition of 'g' does not match any declaration in namespace 'A'}}
struct Struct { };
-void Struct::f() { } // expected-error{{out-of-line definition does not match any declaration in 'Struct'}}
+void Struct::f() { } // expected-error{{out-of-line definition of 'f' does not match any declaration in 'struct Struct'}}
void global_func(int);
void global_func2(int);
@@ -166,13 +166,16 @@ 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'}}
+ // expected-error{{no type named 'foo' in}}
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}}
-
+struct foo_S {
+ static bool value;
+};
+bool (foo_S::value);
namespace somens {
diff --git a/test/SemaCXX/new-delete.cpp b/test/SemaCXX/new-delete.cpp
index f890bf5..c67a3f6 100644
--- a/test/SemaCXX/new-delete.cpp
+++ b/test/SemaCXX/new-delete.cpp
@@ -38,10 +38,11 @@ void good_news()
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;
+ V *pv = new (ps) V;
pi = new (S(1.0f, 2)) int;
+
+ (void)new int[true];
}
struct abstract {
@@ -95,3 +96,43 @@ void bad_deletes()
delete (T*)0; // expected-warning {{deleting pointer to incomplete type}}
::S::delete (int*)0; // expected-error {{expected unqualified-id}}
}
+
+struct X0 { };
+
+struct X1 {
+ operator int*();
+ operator float();
+};
+
+struct X2 {
+ operator int*(); // expected-note {{candidate function}}
+ operator float*(); // expected-note {{candidate function}}
+};
+
+void test_delete_conv(X0 x0, X1 x1, X2 x2) {
+ delete x0; // expected-error{{cannot delete}}
+ delete x1;
+ delete x2; // expected-error{{ambiguous conversion of delete expression of type 'struct X2' to a pointer}}
+}
+
+// PR4782
+class X3 {
+public:
+ static void operator delete(void * mem, unsigned long size);
+};
+
+class X4 {
+public:
+ static void release(X3 *x);
+ static void operator delete(void * mem, unsigned long size);
+};
+
+
+void X4::release(X3 *x) {
+ delete x;
+}
+
+class X5 {
+public:
+ void Destroy() const { delete this; }
+};
diff --git a/test/SemaCXX/overload-value-dep-arg.cpp b/test/SemaCXX/overload-value-dep-arg.cpp
new file mode 100644
index 0000000..1e94d5a
--- /dev/null
+++ b/test/SemaCXX/overload-value-dep-arg.cpp
@@ -0,0 +1,13 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+class C {
+ C(void*);
+};
+
+int f(const C&);
+int f(unsigned long);
+
+template<typename T> int f(const T* t) {
+ return f(reinterpret_cast<unsigned long>(t));
+}
+
diff --git a/test/SemaCXX/overloaded-builtin-operators.cpp b/test/SemaCXX/overloaded-builtin-operators.cpp
index 2a6c24a..0284b29 100644
--- a/test/SemaCXX/overloaded-builtin-operators.cpp
+++ b/test/SemaCXX/overloaded-builtin-operators.cpp
@@ -20,11 +20,21 @@ struct Enum2 {
operator E2();
};
+
+struct X {
+ void f();
+};
+
+typedef void (X::*pmf)();
+struct Xpmf {
+ operator pmf();
+};
+
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) {
+void f(Short s, Long l, Enum1 e1, Enum2 e2, Xpmf pmf) {
// C++ [over.built]p8
int i1 = +e1;
int i2 = -e2;
@@ -37,6 +47,10 @@ void f(Short s, Long l, Enum1 e1, Enum2 e2) {
(void)static_cast<yes&>(islong(s + l));
(void)static_cast<no&>(islong(s + s));
+ // C++ [over.built]p16
+ (void)(pmf == &X::f);
+ (void)(pmf == 0);
+
// C++ [over.built]p17
(void)static_cast<yes&>(islong(s % l));
(void)static_cast<yes&>(islong(l << s));
@@ -45,7 +59,7 @@ void f(Short s, Long l, Enum1 e1, Enum2 e2) {
// FIXME: should pass (void)static_cast<no&>(islong(e1 % e2));
}
-struct ShortRef {
+struct ShortRef { // expected-note{{candidate function}}
operator short&();
};
@@ -53,7 +67,15 @@ struct LongRef {
operator volatile long&();
};
-void g(ShortRef sr, LongRef lr) {
+struct XpmfRef { // expected-note{{candidate function}}
+ operator pmf&();
+};
+
+struct E2Ref {
+ operator E2&();
+};
+
+void g(ShortRef sr, LongRef lr, E2Ref e2_ref, XpmfRef pmf_ref) {
// C++ [over.built]p3
short s1 = sr++;
@@ -64,6 +86,14 @@ void g(ShortRef sr, LongRef lr) {
short& sr1 = (sr *= lr);
volatile long& lr1 = (lr *= sr);
+ // C++ [over.built]p20:
+ E2 e2r2;
+ e2r2 = e2_ref;
+
+ pmf &pmr = (pmf_ref = &X::f); // expected-error{{no viable overloaded '='}}
+ pmf pmr2;
+ pmr2 = pmf_ref;
+
// C++ [over.built]p22
short& sr2 = (sr %= lr);
volatile long& lr2 = (lr <<= sr);
diff --git a/test/SemaCXX/overloaded-operator.cpp b/test/SemaCXX/overloaded-operator.cpp
index 916d753..8f71ad5 100644
--- a/test/SemaCXX/overloaded-operator.cpp
+++ b/test/SemaCXX/overloaded-operator.cpp
@@ -28,12 +28,12 @@ void g(Y y, Z z) {
}
struct A {
- bool operator==(Z&); // expected-note{{candidate function}}
+ bool operator==(Z&); // expected-note 2{{candidate function}}
};
A make_A();
-bool operator==(A&, Z&); // expected-note{{candidate function}}
+bool operator==(A&, Z&); // expected-note 2{{candidate function}}
void h(A a, const A ac, Z z) {
make_A() == z;
@@ -155,7 +155,7 @@ typedef INTREF Func1(FLOAT, double);
typedef float& Func2(int, double);
struct ConvertToFunc {
- operator Func1*(); // expected-note{{conversion candidate of type 'INTREF (*)(FLOAT, double)'}}
+ operator Func1*(); // expected-note{{conversion candidate of type 'INTREF (*)(float, double)'}}
operator Func2&(); // expected-note{{conversion candidate of type 'float &(&)(int, double)'}}
void operator()();
};
@@ -209,3 +209,34 @@ namespace M {
(void)(x + x);
}
}
+
+struct AA { bool operator!=(AA&); };
+struct BB : AA {};
+bool x(BB y, BB z) { return y != z; }
+
+
+struct AX {
+ AX& operator ->(); // expected-note {{declared at}}
+ int b;
+};
+
+void m() {
+ AX a;
+ a->b = 0; // expected-error {{circular pointer delegation detected}}
+}
+
+struct CircA {
+ struct CircB& operator->(); // expected-note {{declared at}}
+ int val;
+};
+struct CircB {
+ struct CircC& operator->(); // expected-note {{declared at}}
+};
+struct CircC {
+ struct CircA& operator->(); // expected-note {{declared at}}
+};
+
+void circ() {
+ CircA a;
+ a->val = 0; // expected-error {{circular pointer delegation detected}}
+}
diff --git a/test/SemaCXX/primary-base.cpp b/test/SemaCXX/primary-base.cpp
new file mode 100644
index 0000000..62f9087
--- /dev/null
+++ b/test/SemaCXX/primary-base.cpp
@@ -0,0 +1,11 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+class A { virtual void f(); };
+class B : virtual A { };
+
+class C : B { };
+
+// Since A is already a primary base class, C should be the primary base class of F.
+class F : virtual A, virtual C { };
+
+int sa[sizeof(F) == sizeof(A) ? 1 : -1];
+
diff --git a/test/SemaCXX/pseudo-destructors.cpp b/test/SemaCXX/pseudo-destructors.cpp
new file mode 100644
index 0000000..1f05e81
--- /dev/null
+++ b/test/SemaCXX/pseudo-destructors.cpp
@@ -0,0 +1,40 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+struct A {};
+
+enum Foo { F };
+typedef Foo Bar;
+
+typedef int Integer;
+
+void g();
+
+namespace N {
+ typedef Foo Wibble;
+}
+
+void f(A* a, Foo *f, int *i) {
+ a->~A();
+ a->A::~A();
+
+ a->~foo(); // expected-error{{identifier 'foo' in pseudo-destructor expression does not name a type}}
+
+ // FIXME: the type printed below isn't wonderful
+ a->~Bar(); // expected-error{{no member named}}
+
+ f->~Bar();
+ f->~Foo();
+ i->~Bar(); // expected-error{{does not match}}
+
+ g().~Bar(); // expected-error{{non-scalar}}
+
+ f->::~Bar();
+ f->N::~Wibble();
+
+ f->::~Bar(17, 42); // expected-error{{cannot have any arguments}}
+}
+
+typedef int Integer;
+
+void destroy_without_call(int *ip) {
+ ip->~Integer; // expected-error{{called immediately}}
+} \ No newline at end of file
diff --git a/test/SemaCXX/qual-id-test.cpp b/test/SemaCXX/qual-id-test.cpp
new file mode 100644
index 0000000..ecb6aa9
--- /dev/null
+++ b/test/SemaCXX/qual-id-test.cpp
@@ -0,0 +1,140 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+namespace A
+{
+ namespace B
+ {
+ struct base // expected-note{{object type}}
+ {
+ void x() {}
+ void y() {}
+ };
+ }
+
+ struct member
+ {
+ void foo();
+ };
+
+ struct middleman
+ {
+ member * operator->() { return 0; }
+ };
+
+ struct sub : B::base
+ {
+ void x() {}
+ middleman operator->() { return middleman(); }
+ };
+}
+
+struct bad
+{
+ int x();
+};
+
+namespace C
+{
+ void fun()
+ {
+ A::sub a;
+
+ a.x();
+
+ a.sub::x();
+ a.base::x();
+
+ a.B::base::x(); // expected-error{{use of undeclared identifier 'B'}}
+
+ a.A::sub::x();
+ a.A::B::base::x();
+
+ a.bad::x(); // expected-error{{type 'struct bad' is not a direct or virtual base of ''struct A::sub''}}
+
+ a->foo();
+ a->member::foo();
+ a->A::member::foo();
+ }
+
+ void fun2()
+ {
+ A::sub *a;
+
+ a->x();
+
+ a->sub::x();
+ a->base::x();
+
+ a->B::base::x(); // expected-error{{use of undeclared identifier 'B'}}
+
+ a->A::sub::x();
+ a->A::B::base::x();
+
+ a->bad::x(); // expected-error{{type 'struct bad' is not a direct or virtual base of ''struct A::sub''}}
+
+ (*a)->foo();
+ (*a)->member::foo();
+ (*a)->A::member::foo();
+ }
+
+ void fun3()
+ {
+ int i;
+ i.foo(); // expected-error{{member reference base type 'int' is not a structure or union}}
+ }
+
+ void fun4a() {
+ A::sub *a;
+
+ typedef A::member base; // expected-note{{current scope}}
+ a->base::x(); // expected-error{{ambiguous}}
+ }
+
+ void fun4b() {
+ A::sub *a;
+
+ typedef A::B::base base;
+ a->base::x();
+ }
+
+ template<typename T>
+ void fun5()
+ {
+ T a;
+ a.x();
+ a->foo();
+
+ a.A::sub::x();
+ a.A::B::base::x();
+ a->A::member::foo();
+
+ a.bad::x(); // expected-error{{direct or virtual}}
+ }
+
+ void test_fun5() {
+ fun5<A::sub>(); // expected-note{{instantiation}}
+ }
+
+ template<typename T>
+ void fun6() {
+ T a;
+ a.sub::x();
+ a.base::x();
+ a->member::foo();
+ a.B::base::x(); // expected-error{{use of undeclared identifier 'B'}}
+ }
+
+ void test_fun6() {
+ fun6<A::sub>(); // expected-note{{instantiation}}
+ }
+
+}
+
+// PR4703
+struct a {
+ int a;
+ static int sa;
+};
+
+a a;
+
+int a::sa = a.a;
diff --git a/test/SemaCXX/ref-init-ambiguous.cpp b/test/SemaCXX/ref-init-ambiguous.cpp
new file mode 100644
index 0000000..dda1ead
--- /dev/null
+++ b/test/SemaCXX/ref-init-ambiguous.cpp
@@ -0,0 +1,28 @@
+// RUN: clang-cc -fsyntax-only -verify %s -std=c++0x
+
+enum E2 { };
+
+struct A {
+ operator E2&(); // expected-note 3 {{candidate function}}
+};
+
+struct B {
+ operator E2&(); // expected-note 3 {{candidate function}}
+};
+
+struct C : B, A {
+};
+
+void test(C c) {
+ const E2 &e2 = c; // expected-error {{reference initialization of type 'enum E2 const &' with initializer of type 'struct C' is ambiguous}}
+}
+
+void foo(const E2 &);
+
+const E2 & re(C c) {
+ foo(c); // expected-error {{reference initialization of type 'enum E2 const &' with initializer of type 'struct C' is ambiguous}}
+
+ return c; // expected-error {{reference initialization of type 'enum E2 const &' with initializer of type 'struct C' is ambiguous}}
+}
+
+
diff --git a/test/SemaCXX/references.cpp b/test/SemaCXX/references.cpp
index 9067a86..e03abf4 100644
--- a/test/SemaCXX/references.cpp
+++ b/test/SemaCXX/references.cpp
@@ -87,3 +87,18 @@ void test8(int& const,// expected-error{{'const' qualifier may not be applied to
typedef intref const intref_c; // okay. FIXME: how do we verify that this is the same type as intref?
}
+
+
+class string {
+ char *Data;
+ unsigned Length;
+public:
+ string();
+ ~string();
+};
+
+string getInput();
+
+void test9() {
+ string &s = getInput(); // expected-error{{lvalue reference}}
+}
diff --git a/test/SemaCXX/return.cpp b/test/SemaCXX/return.cpp
new file mode 100644
index 0000000..03b0ddb
--- /dev/null
+++ b/test/SemaCXX/return.cpp
@@ -0,0 +1,18 @@
+// RUN: clang-cc %s -fsyntax-only -verify
+
+int test1() {
+ throw;
+}
+
+// PR5071
+template<typename T> T f() { }
+
+template<typename T>
+void g(T t) {
+ return t * 2; // okay
+}
+
+template<typename T>
+T h() {
+ return 17;
+}
diff --git a/test/SemaCXX/static-array-member.cpp b/test/SemaCXX/static-array-member.cpp
new file mode 100644
index 0000000..dac70cd
--- /dev/null
+++ b/test/SemaCXX/static-array-member.cpp
@@ -0,0 +1,18 @@
+// RUN: clang-cc -fsyntax-only %s
+
+struct X0 {
+ static int array[];
+
+ int x;
+ int y;
+};
+
+int X0::array[sizeof(X0) * 2];
+
+template<typename T, int N>
+struct X1 {
+ static T array[];
+};
+
+template<typename T, int N>
+T X1<T, N>::array[N];
diff --git a/test/SemaCXX/static-cast-complete-type.cpp b/test/SemaCXX/static-cast-complete-type.cpp
new file mode 100644
index 0000000..83583a5
--- /dev/null
+++ b/test/SemaCXX/static-cast-complete-type.cpp
@@ -0,0 +1,13 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+template<typename T> struct S {
+ S(int);
+};
+
+struct T; // expected-note{{forward declaration of 'struct T'}}
+
+void f() {
+ S<int> s0 = static_cast<S<int> >(0);
+ S<void*> s1 = static_cast<S<void*> >(00);
+
+ (void)static_cast<T>(10); // expected-error{{'struct T' is an incomplete type}}
+}
diff --git a/test/SemaCXX/static-cast.cpp b/test/SemaCXX/static-cast.cpp
index b5c515d..8db8e33 100644
--- a/test/SemaCXX/static-cast.cpp
+++ b/test/SemaCXX/static-cast.cpp
@@ -1,11 +1,11 @@
-// RUN: clang-cc -fsyntax-only -verify %s
+// RUN: clang-cc -fsyntax-only -verify -faccess-control %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 E : private A {}; // Single private base. expected-note 2 {{'private' inheritance specifier here}}
struct F : public C1 {}; // Single path to B with virtual.
struct G1 : public B {};
struct G2 : public B {};
@@ -14,6 +14,11 @@ struct H : public G1, public G2 {}; // Ambiguous path to B.
enum Enum { En1, En2 };
enum Onom { On1, On2 };
+struct Co1 { operator int(); };
+struct Co2 { Co2(int); };
+struct Co3 { };
+struct Co4 { Co4(Co3); operator Co3(); };
+
// Explicit implicits
void t_529_2()
{
@@ -45,7 +50,9 @@ void t_529_2()
(void)static_cast<int B::*>((int A::*)0);
(void)static_cast<void (B::*)()>((void (A::*)())0);
- // TODO: User-defined conversions
+ (void)static_cast<int>(Co1());
+ (void)static_cast<Co2>(1);
+ (void)static_cast<Co3>(static_cast<Co4>(Co3()));
// Bad code below
@@ -80,11 +87,10 @@ void t_529_5_8()
(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*>((A*)0); // expected-error {{cannot cast 'struct A' to 'struct E' due to inaccessible}}
+ (void)static_cast<E&>(*((A*)0)); // expected-error {{cannot cast 'struct A' to 'struct E' due to inaccessible}}
+ (void)static_cast<H*>((A*)0); // expected-error {{ambiguous 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 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'}}
diff --git a/test/SemaCXX/static-initializers.cpp b/test/SemaCXX/static-initializers.cpp
index 3d92a53..a651243 100644
--- a/test/SemaCXX/static-initializers.cpp
+++ b/test/SemaCXX/static-initializers.cpp
@@ -1,12 +1,10 @@
// RUN: clang-cc -fsyntax-only -verify %s
-int f()
-{
- return 10;
+int f() {
+ return 10;
}
-void g()
-{
- static int a = f();
+void g() {
+ static int a = f();
}
static int b = f();
diff --git a/test/SemaCXX/type-traits-incomplete.cpp b/test/SemaCXX/type-traits-incomplete.cpp
new file mode 100644
index 0000000..ac8ec45
--- /dev/null
+++ b/test/SemaCXX/type-traits-incomplete.cpp
@@ -0,0 +1,7 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+struct S; // expected-note{{forward declaration of 'struct S'}}
+
+void f() {
+ __is_pod(S); // expected-error{{incomplete type 'struct S' used in type trait expression}}
+}
diff --git a/test/SemaCXX/type-traits.cpp b/test/SemaCXX/type-traits.cpp
index 1a2e329..340c0ae 100644
--- a/test/SemaCXX/type-traits.cpp
+++ b/test/SemaCXX/type-traits.cpp
@@ -7,14 +7,23 @@ struct NonPOD { NonPOD(int); };
// PODs
enum Enum { EV };
struct POD { Enum e; int i; float f; NonPOD* p; };
+struct Empty {};
+typedef Empty EmptyAr[10];
typedef int Int;
typedef Int IntAr[10];
class Statics { static int priv; static NonPOD np; };
+union EmptyUnion {};
+union Union { int i; float f; };
+struct HasFunc { void f (); };
+struct HasOp { void operator *(); };
+struct HasConv { operator int(); };
+struct HasAssign { void operator =(int); };
// Not PODs
struct Derives : POD {};
+struct DerivesEmpty : Empty {};
struct HasCons { HasCons(int); };
-struct HasAssign { HasAssign operator =(const HasAssign&); };
+struct HasCopyAssign { HasCopyAssign operator =(const HasCopyAssign&); };
struct HasDest { ~HasDest(); };
class HasPriv { int priv; };
class HasProt { protected: int prot; };
@@ -22,6 +31,8 @@ struct HasRef { int i; int& ref; HasRef() : i(0), ref(i) {} };
struct HasNonPOD { NonPOD np; };
struct HasVirt { virtual void Virt() {}; };
typedef Derives NonPODAr[10];
+typedef HasVirt VirtAr[10];
+union NonPODUnion { int i; Derives n; };
void is_pod()
{
@@ -31,10 +42,17 @@ void is_pod()
int t04[T(__is_pod(Int))];
int t05[T(__is_pod(IntAr))];
int t06[T(__is_pod(Statics))];
+ int t07[T(__is_pod(Empty))];
+ int t08[T(__is_pod(EmptyUnion))];
+ int t09[T(__is_pod(Union))];
+ int t10[T(__is_pod(HasFunc))];
+ int t11[T(__is_pod(HasOp))];
+ int t12[T(__is_pod(HasConv))];
+ int t13[T(__is_pod(HasAssign))];
int t21[F(__is_pod(Derives))];
int t22[F(__is_pod(HasCons))];
- int t23[F(__is_pod(HasAssign))];
+ int t23[F(__is_pod(HasCopyAssign))];
int t24[F(__is_pod(HasDest))];
int t25[F(__is_pod(HasPriv))];
int t26[F(__is_pod(HasProt))];
@@ -42,9 +60,40 @@ void is_pod()
int t28[F(__is_pod(HasNonPOD))];
int t29[F(__is_pod(HasVirt))];
int t30[F(__is_pod(NonPODAr))];
+ int t31[F(__is_pod(DerivesEmpty))];
+ // int t32[F(__is_pod(NonPODUnion))];
+}
+
+typedef Empty EmptyAr[10];
+struct Bit0 { int : 0; };
+struct Bit0Cons { int : 0; Bit0Cons(); };
+struct BitOnly { int x : 3; };
+//struct DerivesVirt : virtual POD {};
+
+void is_empty()
+{
+ int t01[T(__is_empty(Empty))];
+ int t02[T(__is_empty(DerivesEmpty))];
+ int t03[T(__is_empty(HasCons))];
+ int t04[T(__is_empty(HasCopyAssign))];
+ int t05[T(__is_empty(HasDest))];
+ int t06[T(__is_empty(HasFunc))];
+ int t07[T(__is_empty(HasOp))];
+ int t08[T(__is_empty(HasConv))];
+ int t09[T(__is_empty(HasAssign))];
+ int t10[T(__is_empty(Bit0))];
+ int t11[T(__is_empty(Bit0Cons))];
+
+ int t21[F(__is_empty(Int))];
+ int t22[F(__is_empty(POD))];
+ int t23[F(__is_empty(EmptyUnion))];
+ int t24[F(__is_empty(EmptyAr))];
+ int t25[F(__is_empty(HasRef))];
+ int t26[F(__is_empty(HasVirt))];
+ int t27[F(__is_empty(BitOnly))];
+// int t27[F(__is_empty(DerivesVirt))];
}
-union Union { int i; float f; };
typedef Derives ClassType;
void is_class()
@@ -92,7 +141,7 @@ void is_enum()
int t17[F(__is_enum(ClassType))];
}
-struct Polymorph { virtual void f(); };
+typedef HasVirt Polymorph;
struct InheritPolymorph : Polymorph {};
void is_polymorphic()
@@ -109,3 +158,95 @@ void is_polymorphic()
int t17[F(__is_polymorphic(ClassType))];
int t18[F(__is_polymorphic(Enum))];
}
+
+typedef Int& IntRef;
+typedef const IntAr ConstIntAr;
+typedef ConstIntAr ConstIntArAr[4];
+
+struct HasCopy {
+ HasCopy(HasCopy& cp);
+};
+
+void has_trivial_default_constructor() {
+ int t01[T(__has_trivial_constructor(Int))];
+ int t02[T(__has_trivial_constructor(IntAr))];
+ int t03[T(__has_trivial_constructor(Union))];
+ int t04[T(__has_trivial_constructor(UnionAr))];
+ int t05[T(__has_trivial_constructor(POD))];
+ int t06[T(__has_trivial_constructor(Derives))];
+ int t07[T(__has_trivial_constructor(ConstIntAr))];
+ int t08[T(__has_trivial_constructor(ConstIntArAr))];
+ int t09[T(__has_trivial_constructor(HasDest))];
+ int t10[T(__has_trivial_constructor(HasPriv))];
+ int t11[F(__has_trivial_constructor(HasCons))];
+ int t12[F(__has_trivial_constructor(HasRef))];
+ int t13[F(__has_trivial_constructor(HasCopy))];
+ int t14[F(__has_trivial_constructor(IntRef))];
+ int t15[T(__has_trivial_constructor(HasCopyAssign))];
+ int t16[T(__has_trivial_constructor(const Int))];
+ int t17[T(__has_trivial_constructor(NonPODAr))];
+ int t18[F(__has_trivial_constructor(VirtAr))];
+}
+
+void has_trivial_copy_constructor() {
+ int t01[T(__has_trivial_copy(Int))];
+ int t02[T(__has_trivial_copy(IntAr))];
+ int t03[T(__has_trivial_copy(Union))];
+ int t04[T(__has_trivial_copy(UnionAr))];
+ int t05[T(__has_trivial_copy(POD))];
+ int t06[T(__has_trivial_copy(Derives))];
+ int t07[T(__has_trivial_copy(ConstIntAr))];
+ int t08[T(__has_trivial_copy(ConstIntArAr))];
+ int t09[T(__has_trivial_copy(HasDest))];
+ int t10[T(__has_trivial_copy(HasPriv))];
+ int t11[T(__has_trivial_copy(HasCons))];
+ int t12[T(__has_trivial_copy(HasRef))];
+ int t13[F(__has_trivial_copy(HasCopy))];
+ int t14[T(__has_trivial_copy(IntRef))];
+ int t15[T(__has_trivial_copy(HasCopyAssign))];
+ int t16[T(__has_trivial_copy(const Int))];
+ int t17[F(__has_trivial_copy(NonPODAr))];
+ int t18[F(__has_trivial_copy(VirtAr))];
+}
+
+void has_trivial_copy_assignment() {
+ int t01[T(__has_trivial_assign(Int))];
+ int t02[T(__has_trivial_assign(IntAr))];
+ int t03[T(__has_trivial_assign(Union))];
+ int t04[T(__has_trivial_assign(UnionAr))];
+ int t05[T(__has_trivial_assign(POD))];
+ int t06[T(__has_trivial_assign(Derives))];
+ int t07[F(__has_trivial_assign(ConstIntAr))];
+ int t08[F(__has_trivial_assign(ConstIntArAr))];
+ int t09[T(__has_trivial_assign(HasDest))];
+ int t10[T(__has_trivial_assign(HasPriv))];
+ int t11[T(__has_trivial_assign(HasCons))];
+ int t12[T(__has_trivial_assign(HasRef))];
+ int t13[T(__has_trivial_assign(HasCopy))];
+ int t14[F(__has_trivial_assign(IntRef))];
+ int t15[F(__has_trivial_assign(HasCopyAssign))];
+ int t16[F(__has_trivial_assign(const Int))];
+ int t17[F(__has_trivial_assign(NonPODAr))];
+ int t18[F(__has_trivial_assign(VirtAr))];
+}
+
+void has_trivial_destructor() {
+ int t01[T(__has_trivial_destructor(Int))];
+ int t02[T(__has_trivial_destructor(IntAr))];
+ int t03[T(__has_trivial_destructor(Union))];
+ int t04[T(__has_trivial_destructor(UnionAr))];
+ int t05[T(__has_trivial_destructor(POD))];
+ int t06[T(__has_trivial_destructor(Derives))];
+ int t07[T(__has_trivial_destructor(ConstIntAr))];
+ int t08[T(__has_trivial_destructor(ConstIntArAr))];
+ int t09[F(__has_trivial_destructor(HasDest))];
+ int t10[T(__has_trivial_destructor(HasPriv))];
+ int t11[T(__has_trivial_destructor(HasCons))];
+ int t12[T(__has_trivial_destructor(HasRef))];
+ int t13[T(__has_trivial_destructor(HasCopy))];
+ int t14[T(__has_trivial_destructor(IntRef))];
+ int t15[T(__has_trivial_destructor(HasCopyAssign))];
+ int t16[T(__has_trivial_destructor(const Int))];
+ int t17[T(__has_trivial_destructor(NonPODAr))];
+ int t18[T(__has_trivial_destructor(VirtAr))];
+}
diff --git a/test/SemaCXX/unknown-type-name.cpp b/test/SemaCXX/unknown-type-name.cpp
new file mode 100644
index 0000000..0542129
--- /dev/null
+++ b/test/SemaCXX/unknown-type-name.cpp
@@ -0,0 +1,29 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// PR3990
+namespace N {
+ struct Wibble {
+ };
+
+ typedef Wibble foo;
+}
+using namespace N;
+
+foo::bar x; // expected-error{{no type named 'bar' in 'struct N::Wibble'}}
+
+void f() {
+ foo::bar = 4; // expected-error{{no member named 'bar' in 'struct N::Wibble'}}
+}
+
+template<typename T>
+struct A {
+ typedef T type;
+
+ type f();
+};
+
+template<typename T>
+A<T>::type g(T t) { return t; } // expected-error{{missing 'typename'}}
+
+template<typename T>
+A<T>::type A<T>::f() { return type(); } // expected-error{{missing 'typename'}}
diff --git a/test/SemaCXX/unreachable-catch-clauses.cpp b/test/SemaCXX/unreachable-catch-clauses.cpp
new file mode 100644
index 0000000..c8b642e
--- /dev/null
+++ b/test/SemaCXX/unreachable-catch-clauses.cpp
@@ -0,0 +1,14 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+class BaseEx {};
+class Ex1: public BaseEx {};
+typedef Ex1 Ex2;
+
+void f();
+
+void test()
+try {}
+catch (BaseEx &e) { f(); }
+catch (Ex1 &e) { f(); } // expected-note {{for type class Ex1 &}}
+catch (Ex2 &e) { f(); } // expected-warning {{exception of type Ex2 & will be caught by earlier handler}}
+
diff --git a/test/SemaCXX/using-decl-1.cpp b/test/SemaCXX/using-decl-1.cpp
index 2459f25..37e101e 100644
--- a/test/SemaCXX/using-decl-1.cpp
+++ b/test/SemaCXX/using-decl-1.cpp
@@ -6,3 +6,14 @@ namespace std {
using ::f;
inline void f() { return f(true); }
}
+
+namespace M {
+ void f(float);
+}
+
+namespace N {
+ using M::f;
+ void f(int) { } // expected-note{{previous}}
+
+ void f(int) { } // expected-error{{redefinition}}
+}
diff --git a/test/SemaCXX/using-decl-templates.cpp b/test/SemaCXX/using-decl-templates.cpp
new file mode 100644
index 0000000..1a53704
--- /dev/null
+++ b/test/SemaCXX/using-decl-templates.cpp
@@ -0,0 +1,36 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T> struct A {
+ void f() { }
+ struct N { };
+};
+
+template<typename T> struct B : A<T> {
+ using A<T>::f;
+ using A<T>::N;
+
+ using A<T>::foo; // expected-error{{no member named 'foo'}}
+ using A<double>::f; // expected-error{{using declaration refers into 'A<double>::', which is not a base class of 'B'}}
+};
+
+B<int> a; // expected-note{{in instantiation of template class 'struct B<int>' requested here}}
+
+template<typename T> struct C : A<T> {
+ using A<T>::f;
+
+ void f() { };
+};
+
+template <typename T> struct D : A<T> {
+ using A<T>::f;
+
+ void f();
+};
+
+template<typename T> void D<T>::f() { }
+
+template<typename T> struct E : A<T> {
+ using A<T>::f;
+
+ void g() { f(); }
+};
diff --git a/test/SemaCXX/value-dependent-exprs.cpp b/test/SemaCXX/value-dependent-exprs.cpp
new file mode 100644
index 0000000..c70f895
--- /dev/null
+++ b/test/SemaCXX/value-dependent-exprs.cpp
@@ -0,0 +1,47 @@
+// RUN: clang-cc -verify %s
+
+template <unsigned I>
+class C0 {
+ static const int iv0 = 1 << I;
+
+ enum {
+ A = I,
+ B = I + 1
+ };
+
+ struct s0 {
+ int a : I;
+ int b[I];
+ };
+
+ // FIXME: I'm unclear where the right place to handle this is.
+#if 0
+ void f0(int *p) {
+ if (p == I) {
+ }
+ }
+#endif
+
+#if 0
+ // FIXME: Not sure whether we care about these.
+ void f1(int *a)
+ __attribute__((nonnull(1 + I)))
+ __attribute__((constructor(1 + I)))
+ __attribute__((destructor(1 + I)))
+ __attribute__((sentinel(1 + I, 2 + I))),
+ __attribute__((reqd_work_group_size(1 + I, 2 + I, 3 + I))),
+ __attribute__((format_arg(1 + I))),
+ __attribute__((aligned(1 + I))),
+ __attribute__((regparm(1 + I)));
+
+ typedef int int_a0 __attribute__((address_space(1 + B)));
+#endif
+
+#if 0
+ // FIXME: This doesn't work. PR4996.
+ int f2() {
+ return __builtin_choose_expr(I, 1, 2);
+ }
+#endif
+
+};
diff --git a/test/SemaCXX/vararg-non-pod.cpp b/test/SemaCXX/vararg-non-pod.cpp
index 1c5fe74..390f58b 100644
--- a/test/SemaCXX/vararg-non-pod.cpp
+++ b/test/SemaCXX/vararg-non-pod.cpp
@@ -51,6 +51,18 @@ void t4()
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, c); // expected-warning{{cannot pass object of non-POD type 'class C' through variadic method; call will abort at runtime}}
d(10, version);
}
+
+class E {
+ E(int, ...);
+};
+
+void t5()
+{
+ C c(10);
+
+ E e(10, c); // expected-warning{{cannot pass object of non-POD type 'class C' through variadic constructor; call will abort at runtime}}
+ (void)E(10, c); // expected-warning{{cannot pass object of non-POD type 'class C' through variadic constructor; call will abort at runtime}}
+} \ No newline at end of file
diff --git a/test/SemaCXX/vector-casts.cpp b/test/SemaCXX/vector-casts.cpp
new file mode 100644
index 0000000..5b08043
--- /dev/null
+++ b/test/SemaCXX/vector-casts.cpp
@@ -0,0 +1,40 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+typedef int __v2si __attribute__((__vector_size__(8)));
+typedef short __v4hi __attribute__((__vector_size__(8)));
+typedef short __v8hi __attribute__((__vector_size__(16)));
+
+struct S { };
+
+void f() {
+ __v2si v2si;
+ __v4hi v4hi;
+ __v8hi v8hi;
+ unsigned long long ll;
+ unsigned char c;
+ S s;
+
+ (void)reinterpret_cast<__v2si>(v4hi);
+ (void)(__v2si)v4hi;
+ (void)reinterpret_cast<__v4hi>(v2si);
+ (void)(__v4hi)v2si;
+ (void)reinterpret_cast<unsigned long long>(v2si);
+ (void)(unsigned long long)v2si;
+ (void)reinterpret_cast<__v2si>(ll);
+ (void)(__v2si)(ll);
+
+ (void)reinterpret_cast<S>(v2si); // expected-error {{reinterpret_cast from '__v2si' to 'struct S' is not allowed}}
+ (void)(S)v2si; // expected-error {{C-style cast from '__v2si' to 'struct S' is not allowed}}
+ (void)reinterpret_cast<__v2si>(s); // expected-error {{reinterpret_cast from 'struct S' to '__v2si' is not allowed}}
+ (void)(__v2si)s; // expected-error {{C-style cast from 'struct S' to '__v2si' is not allowed}}
+
+ (void)reinterpret_cast<unsigned char>(v2si); // expected-error {{reinterpret_cast from vector '__v2si' to scalar 'unsigned char' of different size}}
+ (void)(unsigned char)v2si; // expected-error {{C-style cast from vector '__v2si' to scalar 'unsigned char' of different size}}
+ (void)reinterpret_cast<__v2si>(c); // expected-error {{reinterpret_cast from scalar 'unsigned char' to vector '__v2si' of different size}}
+
+ (void)reinterpret_cast<__v8hi>(v4hi); // expected-error {{reinterpret_cast from vector '__v4hi' to vector '__v8hi' of different size}}
+ (void)(__v8hi)v4hi; // expected-error {{C-style cast from vector '__v4hi' to vector '__v8hi' of different size}}
+ (void)reinterpret_cast<__v4hi>(v8hi); // expected-error {{reinterpret_cast from vector '__v8hi' to vector '__v4hi' of different size}}
+ (void)(__v4hi)v8hi; // expected-error {{C-style cast from vector '__v8hi' to vector '__v4hi' of different size}}
+}
+
+
diff --git a/test/SemaCXX/warn-assignment-condition.cpp b/test/SemaCXX/warn-assignment-condition.cpp
new file mode 100644
index 0000000..3b9f306
--- /dev/null
+++ b/test/SemaCXX/warn-assignment-condition.cpp
@@ -0,0 +1,65 @@
+// RUN: clang-cc -fsyntax-only -Wparentheses -verify %s
+
+struct A {
+ int foo();
+ friend A operator+(const A&, const A&);
+ operator bool();
+};
+
+void test() {
+ int x, *p;
+ A a, b;
+
+ // With scalars.
+ if (x = 7) {} // expected-warning {{using the result of an assignment as a condition without parentheses}}
+ if ((x = 7)) {}
+ do {
+ } while (x = 7); // expected-warning {{using the result of an assignment as a condition without parentheses}}
+ do {
+ } while ((x = 7));
+ while (x = 7) {} // expected-warning {{using the result of an assignment as a condition without parentheses}}
+ while ((x = 7)) {}
+ for (; x = 7; ) {} // expected-warning {{using the result of an assignment as a condition without parentheses}}
+ for (; (x = 7); ) {}
+
+ if (p = p) {} // expected-warning {{using the result of an assignment as a condition without parentheses}}
+ if ((p = p)) {}
+ do {
+ } while (p = p); // expected-warning {{using the result of an assignment as a condition without parentheses}}
+ do {
+ } while ((p = p));
+ while (p = p) {} // expected-warning {{using the result of an assignment as a condition without parentheses}}
+ while ((p = p)) {}
+ for (; p = p; ) {} // expected-warning {{using the result of an assignment as a condition without parentheses}}
+ for (; (p = p); ) {}
+
+ // Initializing variables (shouldn't warn).
+ if (int y = x) {}
+ while (int y = x) {}
+ if (A y = a) {}
+ while (A y = a) {}
+
+ // With temporaries.
+ if (x = (b+b).foo()) {} // expected-warning {{using the result of an assignment as a condition without parentheses}}
+ if ((x = (b+b).foo())) {}
+ do {
+ } while (x = (b+b).foo()); // expected-warning {{using the result of an assignment as a condition without parentheses}}
+ do {
+ } while ((x = (b+b).foo()));
+ while (x = (b+b).foo()) {} // expected-warning {{using the result of an assignment as a condition without parentheses}}
+ while ((x = (b+b).foo())) {}
+ for (; x = (b+b).foo(); ) {} // expected-warning {{using the result of an assignment as a condition without parentheses}}
+ for (; (x = (b+b).foo()); ) {}
+
+ // With a user-defined operator.
+ if (a = b + b) {} // expected-warning {{using the result of an assignment as a condition without parentheses}}
+ if ((a = b + b)) {}
+ do {
+ } while (a = b + b); // expected-warning {{using the result of an assignment as a condition without parentheses}}
+ do {
+ } while ((a = b + b));
+ while (a = b + b) {} // expected-warning {{using the result of an assignment as a condition without parentheses}}
+ while ((a = b + b)) {}
+ for (; a = b + b; ) {} // expected-warning {{using the result of an assignment as a condition without parentheses}}
+ for (; (a = b + b); ) {}
+}
diff --git a/test/SemaCXX/warn-char-subscripts.cpp b/test/SemaCXX/warn-char-subscripts.cpp
new file mode 100644
index 0000000..1c06db9
--- /dev/null
+++ b/test/SemaCXX/warn-char-subscripts.cpp
@@ -0,0 +1,21 @@
+// RUN: clang-cc -Wchar-subscripts -fsyntax-only -verify %s
+
+template<typename T>
+void t1() {
+ int array[1] = { 0 };
+ T subscript = 0;
+ int val = array[subscript]; // expected-warning{{array subscript is of type 'char'}}
+}
+
+template<typename T>
+void t2() {
+ int array[1] = { 0 };
+ T subscript = 0;
+ int val = subscript[array]; // expected-warning{{array subscript is of type 'char'}}
+}
+
+void test() {
+ t1<char>(); // expected-note {{in instantiation of function template specialization 't1<char>' requested here}}
+ t2<char>(); // expected-note {{in instantiation of function template specialization 't2<char>' requested here}}
+}
+
diff --git a/test/SemaCXX/warn-for-var-in-else.cpp b/test/SemaCXX/warn-for-var-in-else.cpp
index 3368da2..f73c606 100644
--- a/test/SemaCXX/warn-for-var-in-else.cpp
+++ b/test/SemaCXX/warn-for-var-in-else.cpp
@@ -8,6 +8,7 @@ int foo() {
return X;
} else {
do_something(X); // expected-warning{{'X' is always zero in this context}}
+ return 0;
}
}
diff --git a/test/SemaCXX/warn-reorder-ctor-initialization.cpp b/test/SemaCXX/warn-reorder-ctor-initialization.cpp
new file mode 100644
index 0000000..bfce588
--- /dev/null
+++ b/test/SemaCXX/warn-reorder-ctor-initialization.cpp
@@ -0,0 +1,89 @@
+// RUN: clang-cc -fsyntax-only -Wreorder -verify %s
+
+struct BB {};
+
+struct BB1 {};
+
+class complex : public BB, BB1 {
+public:
+ complex() : s2(1), // expected-warning {{member 's2' will be initialized after}}
+ s1(1) , // expected-note {{field s1}}
+ s3(3), // expected-warning {{member 's3' will be initialized after}}
+ BB1(), // expected-note {{base 'struct BB1'}} \
+ // expected-warning {{base class 'struct BB1' will be initialized after}}
+ BB() {} // expected-note {{base 'struct BB'}}
+ int s1;
+ int s2;
+ int s3;
+};
+
+
+// testing virtual bases.
+
+
+struct V {
+ V();
+};
+
+struct A : public virtual V {
+ A();
+};
+
+struct B : public virtual V {
+ B();
+};
+
+struct Diamond : public A, public B {
+ Diamond() : A(), B() {}
+};
+
+
+struct C : public A, public B, private virtual V {
+ C() { }
+};
+
+
+struct D : public A, public B {
+ D() : A(), V() { } // expected-warning {{base class 'struct A' will be initialized after}} \
+ // expected-note {{base 'struct V'}}
+};
+
+
+struct E : public A, public B, private virtual V {
+ E() : A(), V() { } // expected-warning {{base class 'struct A' will be initialized after}} \
+ // expected-note {{base 'struct V'}}
+};
+
+
+struct A1 {
+ A1();
+};
+
+struct B1 {
+ B1();
+};
+
+struct F : public A1, public B1, private virtual V {
+ F() : A1(), V() { } // expected-warning {{base class 'struct A1' will be initialized after}} \
+ // expected-note {{base 'struct V'}}
+};
+
+struct X : public virtual A, virtual V, public virtual B {
+ X(): A(), V(), B() {} // expected-warning {{base class 'struct A' will be initialized after}} \
+ // expected-note {{base 'struct V'}}
+};
+
+class Anon {
+ int c; union {int a,b;}; int d;
+ Anon() : c(10), b(1), d(2) {}
+};
+class Anon2 {
+ int c; union {int a,b;}; int d;
+ Anon2() : c(2),
+ d(10), // expected-warning {{member 'd' will be initialized after}}
+ b(1) {} // expected-note {{field b}}
+};
+class Anon3 {
+ union {int a,b;};
+ Anon3() : b(1) {}
+};
diff --git a/test/SemaCXX/warn-unused-variables.cpp b/test/SemaCXX/warn-unused-variables.cpp
new file mode 100644
index 0000000..d8b9a00
--- /dev/null
+++ b/test/SemaCXX/warn-unused-variables.cpp
@@ -0,0 +1,6 @@
+// RUN: clang -fsyntax-only -Wunused-variable -verify %s
+
+template<typename T> void f() {
+ T t;
+ t = 17;
+}
diff --git a/test/SemaCXX/wchar_t.cpp b/test/SemaCXX/wchar_t.cpp
index fc258da..cb85bc3 100644
--- a/test/SemaCXX/wchar_t.cpp
+++ b/test/SemaCXX/wchar_t.cpp
@@ -7,3 +7,7 @@ void f(wchar_t p) {
signed wchar_t z; // expected-warning {{'wchar_t' cannot be signed or unsigned}}
++x;
}
+
+// PR4502
+wchar_t const c = L'c';
+int a[c == L'c' ? 1 : -1];
diff --git a/test/SemaObjC/access-property-getter.m b/test/SemaObjC/access-property-getter.m
index 50a3016..225d63b 100644
--- a/test/SemaObjC/access-property-getter.m
+++ b/test/SemaObjC/access-property-getter.m
@@ -31,5 +31,6 @@
- (id)harvestPredictivelyProcessedOutputFiles
{
_outputStream.release;
+ return 0;
}
@end
diff --git a/test/SemaObjC/attr-malloc.m b/test/SemaObjC/attr-malloc.m
new file mode 100644
index 0000000..6cd6be0
--- /dev/null
+++ b/test/SemaObjC/attr-malloc.m
@@ -0,0 +1,16 @@
+// RUN: clang-cc -verify -fsyntax-only -fblocks %s
+
+@interface TestAttrMallocOnMethods {}
+- (id) test1 __attribute((malloc)); // expected-warning {{functions returning a pointer type}}
+- (int) test2 __attribute((malloc)); // expected-warning {{functions returning a pointer type}}
+@end
+
+id bar(void) __attribute((malloc)); // no-warning
+
+typedef void (^bptr)(void);
+bptr baz(void) __attribute((malloc)); // no-warning
+
+__attribute((malloc)) id (*f)(); // expected-warning {{functions returning a pointer type}}
+__attribute((malloc)) bptr (*g)(); // expected-warning {{functions returning a pointer type}}
+__attribute((malloc)) void *(^h)(); // expected-warning {{functions returning a pointer type}}
+
diff --git a/test/SemaObjC/block-explicit-return-type.m b/test/SemaObjC/block-explicit-return-type.m
new file mode 100644
index 0000000..cfe72de
--- /dev/null
+++ b/test/SemaObjC/block-explicit-return-type.m
@@ -0,0 +1,77 @@
+// RUN: clang-cc -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/SemaObjC/blocks.m b/test/SemaObjC/blocks.m
index 6dab289..aecdfd1 100644
--- a/test/SemaObjC/blocks.m
+++ b/test/SemaObjC/blocks.m
@@ -44,3 +44,14 @@ void foo8() {
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}}
}
+
+
+int foo9() {
+ typedef void (^DVTOperationGroupScheduler)();
+ id _suboperationSchedulers;
+
+ for (DVTOperationGroupScheduler scheduler in _suboperationSchedulers) {
+ ;
+ }
+
+}
diff --git a/test/SemaObjC/call-super-2.m b/test/SemaObjC/call-super-2.m
index 92bec27..a481cff 100644
--- a/test/SemaObjC/call-super-2.m
+++ b/test/SemaObjC/call-super-2.m
@@ -40,8 +40,8 @@ id objc_getClass(const char *s);
{
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)}}
+ i += [(Class <Func>)self class_func0]; //
+ return i + [(Class <Func>)super class_func0]; // // expected-error {{cannot cast 'super' (it isn't an expression)}}
}
+ (int) class_func3
{
diff --git a/test/SemaObjC/category-1.m b/test/SemaObjC/category-1.m
index 6ae7758..dcbda42 100644
--- a/test/SemaObjC/category-1.m
+++ b/test/SemaObjC/category-1.m
@@ -53,4 +53,23 @@
@implementation XCRemoteComputerManager
@end
+@implementation XCRemoteComputerManager(x) // expected-note {{previous definition is here}}
+@end
+
+@implementation XCRemoteComputerManager(x) // expected-error {{reimplementation of category 'x' for class 'XCRemoteComputerManager'}}
+@end
+
+// <rdar://problem/7249233>
+
+@protocol MultipleCat_P
+-(void) im0;
+@end
+
+@interface MultipleCat_I @end
+
+@interface MultipleCat_I() @end
+@interface MultipleCat_I() <MultipleCat_P> @end
+
+@implementation MultipleCat_I // expected-warning {{incomplete implementation}}, expected-warning {{method definition for 'im0' not found}}
+@end
diff --git a/test/SemaObjC/category-method-lookup-2.m b/test/SemaObjC/category-method-lookup-2.m
index 76048cc..15da637 100644
--- a/test/SemaObjC/category-method-lookup-2.m
+++ b/test/SemaObjC/category-method-lookup-2.m
@@ -17,6 +17,7 @@ typedef struct objc_class *Class;
- instanceMethod {
[[self class] classMethod];
+ return 0;
}
@end
diff --git a/test/SemaObjC/class-bitfield.m b/test/SemaObjC/class-bitfield.m
index 01b5324..8220912 100644
--- a/test/SemaObjC/class-bitfield.m
+++ b/test/SemaObjC/class-bitfield.m
@@ -20,7 +20,7 @@
}
@end
-@interface WithBitfields: Base {
+@interface WithBitFields: Base {
void *isa; // expected-note {{previous definition is here}}
unsigned a: 5;
signed b: 4;
@@ -28,10 +28,10 @@
}
@end
-@implementation WithBitfields {
+@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}}
+ int c: 3; // expected-error {{instance variable 'c' has conflicting bit-field width}}
}
@end
diff --git a/test/SemaObjC/class-getter-using-dotsyntax.m b/test/SemaObjC/class-getter-using-dotsyntax.m
new file mode 100644
index 0000000..ba42590
--- /dev/null
+++ b/test/SemaObjC/class-getter-using-dotsyntax.m
@@ -0,0 +1,39 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+typedef struct objc_class *Class;
+
+struct objc_class {
+ Class isa;
+};
+
+typedef struct objc_object {
+ Class isa;
+} *id;
+
+@interface XCActivityLogSection
++ (unsigned)serializationFormatVersion;
++ (unsigned)sectionByDeserializingData;
++ (Class)retursClass;
+@end
+
+@implementation XCActivityLogSection
+
++ (unsigned)serializationFormatVersion
+{
+
+ return 0;
+}
++ (unsigned)sectionByDeserializingData {
+ unsigned version;
+ return self.serializationFormatVersion;
+}
+
++ (Class)retursClass {
+ Class version;
+ // FIXIT. (*version).isa does not work. Results in compiler error.
+ return version->isa;
+}
+
+@end
+
+
diff --git a/test/SemaObjC/class-impl-1.m b/test/SemaObjC/class-impl-1.m
index 5a67bef..09ad155 100644
--- a/test/SemaObjC/class-impl-1.m
+++ b/test/SemaObjC/class-impl-1.m
@@ -9,7 +9,7 @@ typedef int INTF3; // expected-note {{previous definition is here}}
@interface INTF : OBJECT
@end
-@implementation INTF @end
+@implementation INTF @end // expected-note {{previous definition is here}}
@implementation INTF // expected-error {{reimplementation of class 'INTF'}}
@end
diff --git a/test/SemaObjC/compatible-protocol-qualified-types.m b/test/SemaObjC/compatible-protocol-qualified-types.m
index 3c27b5f..71f0054 100644
--- a/test/SemaObjC/compatible-protocol-qualified-types.m
+++ b/test/SemaObjC/compatible-protocol-qualified-types.m
@@ -70,6 +70,7 @@ extern NSString * const XCActiveSelectionLevel;
- (NSTextStorage *)contents {
[_contents setDelegate:self]; // expected-warning {{incompatible type sending 'SKTText *', expected 'id<NSTextStorageDelegate>'}}
+ return 0;
}
@end
diff --git a/test/SemaObjC/comptypes-1.m b/test/SemaObjC/comptypes-1.m
index 8717bd0..df0785b 100644
--- a/test/SemaObjC/comptypes-1.m
+++ b/test/SemaObjC/comptypes-1.m
@@ -66,9 +66,7 @@ int main()
/* 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_p == obj_c) foo() ; // expected-warning {{comparison of distinct pointer types ('id<MyProtocol>' and 'MyClass *')}}
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 *')}}
diff --git a/test/SemaObjC/comptypes-3.m b/test/SemaObjC/comptypes-3.m
index 2d8f19d..0506bce 100644
--- a/test/SemaObjC/comptypes-3.m
+++ b/test/SemaObjC/comptypes-3.m
@@ -42,8 +42,8 @@ int main()
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_b) foo (); // expected-warning {{comparison of distinct pointer types ('id<MyProtocolA>' and 'id<MyProtocolB>')}}
+ if (obj_b == obj_a) foo (); // expected-warning {{comparison of distinct pointer types ('id<MyProtocolB>' and 'id<MyProtocolA>')}}
if (obj_a == obj_ab) foo (); /* Ok */
if (obj_ab == obj_a) foo (); /* Ok */
@@ -54,11 +54,11 @@ int main()
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_b == obj_ac) foo (); // expected-warning {{comparison of distinct pointer types ('id<MyProtocolB>' and 'id<MyProtocolAC>')}}
+ if (obj_ac == obj_b) foo (); // expected-warning {{comparison of distinct pointer types ('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>')}}
+ if (obj_ab == obj_ac) foo (); // expected-warning {{comparison of distinct pointer types ('id<MyProtocolAB>' and 'id<MyProtocolAC>')}}
+ if (obj_ac == obj_ab) foo (); // expected-warning {{comparison of distinct pointer types ('id<MyProtocolAC>' and 'id<MyProtocolAB>')}}
return 0;
}
diff --git a/test/SemaObjC/comptypes-5.m b/test/SemaObjC/comptypes-5.m
index afd8a49..478e8c8 100644
--- a/test/SemaObjC/comptypes-5.m
+++ b/test/SemaObjC/comptypes-5.m
@@ -26,8 +26,8 @@ int main()
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_c_cat_p = obj_id_p;
+ obj_c_super_p = obj_id_p;
obj_id_p = obj_c_cat_p; /* Ok */
obj_id_p = obj_c_super_p; /* Ok */
diff --git a/test/SemaObjC/comptypes-7.m b/test/SemaObjC/comptypes-7.m
index faca693..881fd2b 100644
--- a/test/SemaObjC/comptypes-7.m
+++ b/test/SemaObjC/comptypes-7.m
@@ -28,7 +28,7 @@ int main()
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_p = j; // expected-warning {{incompatible pointer types 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 *'}}
@@ -42,7 +42,7 @@ int main()
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_p; // expected-warning {{incompatible pointer types 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 *'}}
diff --git a/test/SemaObjC/comptypes-a.m b/test/SemaObjC/comptypes-a.m
index 936c6df..5570d56 100644
--- a/test/SemaObjC/comptypes-a.m
+++ b/test/SemaObjC/comptypes-a.m
@@ -13,6 +13,7 @@ extern NSInteger codeAssistantCaseCompareItems(id a, id b, void *context);
NSInteger codeAssistantCaseCompareItems(id<PBXCompletionItem> a, id<PBXCompletionItem> b, void *context)
{
+ return 0;
}
@interface TedWantsToVerifyObjCDoesTheRightThing
diff --git a/test/SemaObjC/conditional-expr-3.m b/test/SemaObjC/conditional-expr-3.m
index 31d4834..9f1ee68 100644
--- a/test/SemaObjC/conditional-expr-3.m
+++ b/test/SemaObjC/conditional-expr-3.m
@@ -51,15 +51,15 @@ void f7(int cond, id x, A *a) {
}
void f8(int cond, id<P0,P1> x0, id<P0,P2> x1) {
- barP0(cond ? x0 : x1);
+ barP0(cond ? x0 : x1); // expected-warning {{incompatible operand types ('id<P0,P1>' and 'id<P0,P2>')}}
}
void f9(int cond, id<P0,P1> x0, id<P0,P2> x1) {
- barP1(cond ? x0 : x1);
+ barP1(cond ? x0 : x1); // expected-warning {{incompatible operand types ('id<P0,P1>' and 'id<P0,P2>')}}
}
void f10(int cond, id<P0,P1> x0, id<P0,P2> x1) {
- barP2(cond ? x0 : x1);
+ barP2(cond ? x0 : x1); // expected-warning {{incompatible operand types ('id<P0,P1>' and 'id<P0,P2>')}}
}
int f11(int cond, A* a, B* b) {
diff --git a/test/SemaObjC/conditional-expr-4.m b/test/SemaObjC/conditional-expr-4.m
index 7d50ba6..8720958 100644
--- a/test/SemaObjC/conditional-expr-4.m
+++ b/test/SemaObjC/conditional-expr-4.m
@@ -1,5 +1,4 @@
-// RUN: clang-cc -fsyntax-only %s
-// XFAIL
+// RUN: clang-cc -fsyntax-only -verify %s
// <rdar://problem/6212771>
#define nil ((void*) 0)
@@ -26,6 +25,11 @@ A *f1_a(int cond, A *a) {
return cond ? a : nil;
}
+void *f1_const_a(int x, void *p, const A * q) {
+ void *r = x ? p : q; // expected-warning{{initializing 'void const *' discards qualifiers, expected 'void *'}}
+ return r;
+}
+
// Check interaction with qualified id
@protocol P0 @end
@@ -48,9 +52,7 @@ id f3(int cond, id<P0> a) {
@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}}
+ return (cond ? a : b).x;
}
int f5_a(int cond, A *a, A *b) {
return (cond ? a : b).x;
@@ -61,7 +63,7 @@ int f5_b(int cond, A *a, B *b) {
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}}
+ return (cond ? a : b).x; // expected-error {{member reference base type 'void *' is not a structure or union}}
}
int f7(int cond, id<P1> a) {
@@ -69,10 +71,10 @@ int f7(int cond, id<P1> a) {
}
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}}
+ return a == b; // expected-warning {{comparison of distinct pointer types ('id<P1>' and 'A *')}}
}
int f9(int cond, id<P1> a, A *b) {
- return (cond ? a : b).x; // expected-error {{incompatible operand types}}
+ return (cond ? a : b).x; // expected-warning {{incompatible operand types ('id<P1>' and 'A *')}} \
+ expected-error {{property 'x' not found on object of type 'id'}}
}
diff --git a/test/SemaObjC/conditional-expr-5.m b/test/SemaObjC/conditional-expr-5.m
new file mode 100644
index 0000000..d9c1a94
--- /dev/null
+++ b/test/SemaObjC/conditional-expr-5.m
@@ -0,0 +1,27 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface PBXBuildSettingsDictionary
+{
+ int i;
+}
+@end
+
+@interface XCConditionalBuildSettingsDictionary : PBXBuildSettingsDictionary
+{
+}
+@end
+
+@implementation PBXBuildSettingsDictionary
+
+- (XCConditionalBuildSettingsDictionary *)conditionalDictionaryForConditionSet
+{
+ return i ? self : (id)0;
+}
+
+- (XCConditionalBuildSettingsDictionary *)conditionalDictionaryForConditionSet2
+{
+ return i ? (id)0 : self;
+}
+@end
+
+
diff --git a/test/SemaObjC/conditional-expr.m b/test/SemaObjC/conditional-expr.m
index ec3613b..2043503 100644
--- a/test/SemaObjC/conditional-expr.m
+++ b/test/SemaObjC/conditional-expr.m
@@ -27,9 +27,8 @@
@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;
+ return nextOutputStream ? nextOutputStream : self; // expected-warning {{incompatible operand types ('id<DTOutputStreams>' and 'DTFilterOutputStream2 *')}}
}
@end
@@ -37,8 +36,84 @@
@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;
+ return nextOutputStream ? nextOutputStream : self; // expected-warning {{incompatible operand types ('id<DTOutputStreams>' and 'DTFilterOutputStream3 *')}}
}
@end
+
+//
+
+@protocol P0
+@property int intProp;
+@end
+@protocol P1
+@end
+@protocol P2
+@end
+
+@interface A <P0>
+@end
+
+@interface B : A
+@end
+
+@interface C
+@end
+
+@interface D
+@end
+
+void f0(id<P0> x) {
+ x.intProp = 1;
+}
+
+void f1(int cond, id<P0> x, id<P0> y) {
+ (cond ? x : y).intProp = 1;
+}
+
+void f2(int cond, id<P0> x, A *y) {
+ (cond ? x : y).intProp = 1;
+}
+
+void f3(int cond, id<P0> x, B *y) {
+ (cond ? x : y).intProp = 1;
+}
+
+void f4(int cond, id x, B *y) {
+ (cond ? x : y).intProp = 1; // expected-error {{property 'intProp' not found on object of type 'id'}}
+}
+
+void f5(int cond, id<P0> x, C *y) {
+ (cond ? x : y).intProp = 1; // expected-warning {{incompatible operand types ('id<P0>' and 'C *')}} expected-error {{property 'intProp' not found on object of type 'id'}}
+}
+
+void f6(int cond, C *x, D *y) {
+ (cond ? x : y).intProp = 1; // expected-warning {{incompatible operand types}}, expected-error {{property 'intProp' not found on object of type 'id'}}
+}
+
+id f7(int a, id<P0> x, A* p) {
+ return a ? x : p;
+}
+
+void f8(int a, A<P0> *x, A *y) {
+ [ (a ? x : y ) intProp ];
+}
+
+void f9(int a, A<P0> *x, A<P1> *y) {
+ id l0 = (a ? x : y ); // expected-warning {{incompatible operand types ('A<P0> *' and 'A<P1> *')'}}
+ A<P0> *l1 = (a ? x : y ); // expected-warning {{incompatible operand types ('A<P0> *' and 'A<P1> *')}}
+ A<P1> *l2 = (a ? x : y ); // expected-warning {{incompatible operand types ('A<P0> *' and 'A<P1> *')}}
+ [ (a ? x : y ) intProp ]; // expected-warning {{incompatible operand types ('A<P0> *' and 'A<P1> *')}}
+}
+
+void f10(int a, id<P0> x, id y) {
+ [ (a ? x : y ) intProp ];
+}
+
+void f11(int a, id<P0> x, id<P1> y) {
+ [ (a ? x : y ) intProp ]; // expected-warning {{incompatible operand types ('id<P0>' and 'id<P1>')}}
+}
+
+void f12(int a, A<P0> *x, A<P1> *y) {
+ A<P1>* l0 = (a ? x : y ); // expected-warning {{incompatible operand types ('A<P0> *' and 'A<P1> *')}}
+}
diff --git a/test/SemaObjC/crash-label.m b/test/SemaObjC/crash-label.m
new file mode 100644
index 0000000..ff40cc6
--- /dev/null
+++ b/test/SemaObjC/crash-label.m
@@ -0,0 +1,9 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+ - (NSDictionary*) _executeScript:(NSString *)source { // expected-error 2 {{expected a type}} \
+ // expected-error {{missing context for method declaration}}
+ Exit: [nilArgs release]; // expected-error {{use of undeclared identifier}}
+ }
+ - (NSDictionary *) _setupKernelStandardMode:(NSString *)source { // expected-error 2 {{expected a type}} \
+expected-error {{missing context for method declaration}}
+ Exit: if(_ciKernel && !success ) { // expected-error {{use of undeclared identifier}} // expected-error 2 {{expected}}
diff --git a/test/SemaObjC/deref-interface.m b/test/SemaObjC/deref-interface.m
new file mode 100644
index 0000000..1c85918
--- /dev/null
+++ b/test/SemaObjC/deref-interface.m
@@ -0,0 +1,12 @@
+// RUN: clang-cc -triple x86_64-apple-darwin9 -verify -fsyntax-only %s
+
+@interface NSView
+ - (id)initWithView:(id)realView;
+@end
+
+@implementation NSView
+ - (id)initWithView:(id)realView {
+ *(NSView *)self = *(NSView *)realView; // expected-error {{indirection cannot be to an interface in non-fragile ABI}}
+ }
+@end
+
diff --git a/test/SemaObjC/format-arg-attribute.m b/test/SemaObjC/format-arg-attribute.m
index 60cc7cb..dc5aa89 100644
--- a/test/SemaObjC/format-arg-attribute.m
+++ b/test/SemaObjC/format-arg-attribute.m
@@ -11,8 +11,7 @@ extern void fc3 (const NSString *) __attribute__((format_arg(1, 2))); // expecte
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" } */
+enum e1 { E1V0 } __attribute__((format_arg(1))); // expected-warning {{'format_arg' attribute only applies to function types}}
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)}}
diff --git a/test/SemaObjC/id-isa-ref.m b/test/SemaObjC/id-isa-ref.m
new file mode 100644
index 0000000..dc42f9a
--- /dev/null
+++ b/test/SemaObjC/id-isa-ref.m
@@ -0,0 +1,37 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// Failing currently due to Obj-C type representation changes. 2009-09-17
+// XFAIL
+
+typedef struct objc_object {
+ struct objc_class *isa;
+} *id;
+
+@interface NSObject {
+ struct objc_class *isa;
+}
+@end
+@interface Whatever : NSObject
++self;
+@end
+
+static void func() {
+
+ id x;
+
+ [(*x).isa self];
+ [x->isa self];
+
+ Whatever *y;
+
+ // GCC allows this, with the following warning:
+ // instance variable ‘isa’ is @protected; this will be a hard error in the future
+ //
+ // FIXME: see if we can avoid the 2 warnings that follow the error.
+ [(*y).isa self]; // expected-error {{instance variable 'isa' is protected}} \
+ expected-warning{{receiver type 'struct objc_class *' is not 'id' or interface pointer, consider casting it to 'id'}} \
+ expected-warning{{method '-self' not found (return type defaults to 'id')}}
+ [y->isa self]; // expected-error {{instance variable 'isa' is protected}} \
+ expected-warning{{receiver type 'struct objc_class *' is not 'id' or interface pointer, consider casting it to 'id'}} \
+ expected-warning{{method '-self' not found (return type defaults to 'id')}}
+}
diff --git a/test/SemaObjC/id.m b/test/SemaObjC/id.m
index 1781ce7..70d981c 100644
--- a/test/SemaObjC/id.m
+++ b/test/SemaObjC/id.m
@@ -15,6 +15,6 @@ void foo() {
}
// Test attempt to redefine 'id' in an incompatible fashion.
-typedef int id; // expected-error {{typedef redefinition with different types}}
+typedef int id; // FIXME: Decide how we want to deal with this (now that 'id' is more of a built-in type).
id b;
diff --git a/test/SemaObjC/interface-scope-2.m b/test/SemaObjC/interface-scope-2.m
index d054e71..c902590 100644
--- a/test/SemaObjC/interface-scope-2.m
+++ b/test/SemaObjC/interface-scope-2.m
@@ -83,6 +83,7 @@ typedef struct __LoreStuffNode {} LoreStuffNode;
- init {
LoreStuffNode *node;
node = &(_historyStuff[1]);
+ return 0;
}
@end
@@ -108,6 +109,7 @@ _nfttFlags;
if (self != ((void *)0)) {
(void)memset(&_nfttFlags, 0, sizeof(struct _OingoBoingoContraptionPeonFlags));
}
+ return 0;
}
@end
diff --git a/test/SemaObjC/invalid-objc-decls-1.m b/test/SemaObjC/invalid-objc-decls-1.m
index e3a94f6..4a3732e 100644
--- a/test/SemaObjC/invalid-objc-decls-1.m
+++ b/test/SemaObjC/invalid-objc-decls-1.m
@@ -32,3 +32,11 @@ Super foo( // expected-error{{interface interface type 'Super' cannot be returne
Super p1; // expected-error{{interface type cannot be statically allocated}}
return p1;
}
+
+@interface NSMutableSet @end
+
+@interface DVTDummyAnnotationProvider
+ @property(readonly) NSMutableSet annotations; // expected-error{{interface type cannot be statically allocated}}
+
+@end
+
diff --git a/test/SemaObjC/message.m b/test/SemaObjC/message.m
index 7b6a4ee..0290123 100644
--- a/test/SemaObjC/message.m
+++ b/test/SemaObjC/message.m
@@ -95,6 +95,6 @@ int test5(int X) {
void foo4() {
struct objc_object X[10];
- [X rect];
+ [X rect]; // expected-warning {{receiver type 'struct objc_object *' is not 'id' or interface pointer, consider casting it to 'id'}} expected-warning {{method '-rect' not found (return type defaults to 'id')}}
}
diff --git a/test/SemaObjC/method-arg-decay.m b/test/SemaObjC/method-arg-decay.m
index 4b04591..7fd07d2 100644
--- a/test/SemaObjC/method-arg-decay.m
+++ b/test/SemaObjC/method-arg-decay.m
@@ -87,6 +87,7 @@ extern NSMutableArray *XCFindPossibleKeyModules(PBXModule *module, BOOL useExpos
PBXModule *obj = [XCFindPossibleKeyModules(pModule, (BOOL)0) objectOfType:type matchingFunction:comparator usingData:data];
}
}
+ return 0;
}
- (BOOL)buffer:(char *)buf containsAnyPrompts:(char *[])prompts
{
diff --git a/test/SemaObjC/method-conflict.m b/test/SemaObjC/method-conflict.m
index 7a9b9f0..a4213f6 100644
--- a/test/SemaObjC/method-conflict.m
+++ b/test/SemaObjC/method-conflict.m
@@ -47,7 +47,9 @@ typedef NSUInteger XDSourceLanguage;
+ appendVisibility: (id <XDUMLNamedElement>) element withSpecification: (XDSCDisplaySpecification *) displaySpec to: (NSMutableAttributedString *) attributedString
{
+ return 0;
}
-+ (NSUInteger) compartmentsForClassifier: (id <XDSCClassifier>) classifier withSpecification: (XDSCDisplaySpecification *) displaySpec {
++ (NSUInteger) compartmentsForClassifier: (id <XDSCClassifier>) classifier withSpecification: (XDSCDisplaySpecification *) displaySpec {
+ return 0;
}
@end
diff --git a/test/SemaObjC/method-encoding-2.m b/test/SemaObjC/method-encoding-2.m
index 64a0bc4..b3ffdcd 100644
--- a/test/SemaObjC/method-encoding-2.m
+++ b/test/SemaObjC/method-encoding-2.m
@@ -7,6 +7,6 @@
@end
@implementation Intf
-- (in out bycopy id) address:(byref inout void *)location with:(out oneway unsigned **)arg2{}
-- (id) another:(void *)location with:(unsigned **)arg2 {}
+- (in out bycopy id) address:(byref inout void *)location with:(out oneway unsigned **)arg2{ return 0; }
+- (id) another:(void *)location with:(unsigned **)arg2 { return 0; }
@end
diff --git a/test/SemaObjC/method-lookup-2.m b/test/SemaObjC/method-lookup-2.m
index dd0bca9..cca7575 100644
--- a/test/SemaObjC/method-lookup-2.m
+++ b/test/SemaObjC/method-lookup-2.m
@@ -35,8 +35,8 @@ extern NSString *const NSWillBecomeMultiThreadedNotification;
@implementation SenTestTool
+ (void) initialize {}
-+(SenTestTool *) sharedInstance {}
--(int) run {}
++(SenTestTool *) sharedInstance { return 0; }
+-(int) run { return 0; }
+(int) run {
return[[self sharedInstance] run];
}
@@ -57,6 +57,7 @@ extern NSString *const NSWillBecomeMultiThreadedNotification;
- whatever {
id obj = [[XX alloc] init];
[[obj class] classMethod];
+ return 0;
}
@end
diff --git a/test/SemaObjC/method-lookup.m b/test/SemaObjC/method-lookup.m
index 917ad6b..49dc789 100644
--- a/test/SemaObjC/method-lookup.m
+++ b/test/SemaObjC/method-lookup.m
@@ -29,6 +29,7 @@ static NSMutableArray * recentCompletions = ((void *)0);
[(id)item setPriority:[item priority] / [PBXCodeAssistant factorForRecentCompletion:[item name]]];
}
}
+ return 0;
}
@end
diff --git a/test/SemaObjC/method-typecheck-1.m b/test/SemaObjC/method-typecheck-1.m
index d110c85..a53c4d9 100644
--- a/test/SemaObjC/method-typecheck-1.m
+++ b/test/SemaObjC/method-typecheck-1.m
@@ -8,8 +8,8 @@
@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 {}
+- (char) setMoo1: (int) x { return 0; } // expected-warning {{conflicting return type in implementation of 'setMoo1:': 'int' vs 'char'}}
+- (int) setOk : (int) x : (double) d { return 0; }
@end
@@ -20,7 +20,7 @@
@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'}}
+ (float) x { return 0; } // expected-warning {{conflicting parameter types in implementation of 'cMoo:': 'int' vs 'float'}}
@end
@@ -31,7 +31,6 @@
@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'}}
+(float) x { return 0; } // expected-warning {{conflicting parameter types in implementation of 'setCat:': 'int' vs 'float'}}
++ (int) cCat: (int) x { return 0; } // expected-warning {{conflicting return type in implementation of 'cCat:': 'void' vs 'int'}}
@end
-
diff --git a/test/SemaObjC/no-warn-unimpl-method.m b/test/SemaObjC/no-warn-unimpl-method.m
index 756c47b..2fcb06f 100644
--- a/test/SemaObjC/no-warn-unimpl-method.m
+++ b/test/SemaObjC/no-warn-unimpl-method.m
@@ -38,5 +38,5 @@
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
}
- - (id) init {}
+ - (id) init { return 0; }
@end
diff --git a/test/SemaObjC/nonnull.m b/test/SemaObjC/nonnull.m
new file mode 100644
index 0000000..869bbbd
--- /dev/null
+++ b/test/SemaObjC/nonnull.m
@@ -0,0 +1,42 @@
+// RUN: clang-cc -fblocks -fsyntax-only -verify %s
+
+@class NSObject;
+
+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)));
+int f6(NSObject *x) __attribute__ ((nonnull (1))); // no-warning
+int f7(NSObject *x) __attribute__ ((nonnull)); // no-warning
+
+
+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}}
+
+ // Shouldn't these emit warnings? Clang doesn't, and neither does GCC. It
+ // seems that the checking should handle Objective-C pointers.
+ func6((NSObject*) 0); // no-warning
+ func7((NSObject*) 0); // no-warning
+}
diff --git a/test/SemaObjC/nsobject-attribute.m b/test/SemaObjC/nsobject-attribute.m
index 3544cb1..c47b909 100644
--- a/test/SemaObjC/nsobject-attribute.m
+++ b/test/SemaObjC/nsobject-attribute.m
@@ -26,7 +26,7 @@ id getProperty(id self) {
@synthesize x=x;
@end
-int main(char *argc, char *argv[]) {
+int main(int argc, char *argv[]) {
HandTested *to;
to.x = tmp; // setter
if (tmp != to.x)
diff --git a/test/SemaObjC/objc2-merge-gc-attribue-decl.m b/test/SemaObjC/objc2-merge-gc-attribue-decl.m
index 9dae1ef..0da0ce8 100644
--- a/test/SemaObjC/objc2-merge-gc-attribue-decl.m
+++ b/test/SemaObjC/objc2-merge-gc-attribue-decl.m
@@ -25,6 +25,5 @@ extern __strong id p5;
extern char* __strong p6; // expected-note {{previous definition is here}}
extern char* p6; // expected-error {{redefinition of 'p6' with a different type}}
-// FIXME. We do not issue error here because we don't put the attribute on the pointer type.
-extern __strong char* p7;
-extern char* p7;
+extern __strong char* p7; // expected-note {{previous definition is here}}
+extern char* p7; // expected-error {{redefinition of 'p7' with a different type}}
diff --git a/test/SemaObjC/property-11.m b/test/SemaObjC/property-11.m
index e8e6091..bb36c27 100644
--- a/test/SemaObjC/property-11.m
+++ b/test/SemaObjC/property-11.m
@@ -29,6 +29,7 @@
o = x.foo;
[x setFoo:o];
x.foo = o;
+ return 0;
}
@end
diff --git a/test/SemaObjC/property-9-impl-method.m b/test/SemaObjC/property-9-impl-method.m
index c97f388..06cb304 100644
--- a/test/SemaObjC/property-9-impl-method.m
+++ b/test/SemaObjC/property-9-impl-method.m
@@ -55,10 +55,11 @@ NSSize minimumSize;
@implementation OrganizerTabView
@dynamic tabHeaderView, headerRect, minimumSize;
--(CGFloat) tabAreaThickness {}
+-(CGFloat) tabAreaThickness { return 0; }
-(NSRectEdge) rectEdgeForTabs {
NSRect dummy, result = {};
NSDivideRect(self.bounds, &result, &dummy, self.tabAreaThickness, self.rectEdgeForTabs);
+ return 0;
}
@end
diff --git a/test/SemaObjC/property-error-readonly-assign.m b/test/SemaObjC/property-error-readonly-assign.m
index edeff09..d5cef78 100644
--- a/test/SemaObjC/property-error-readonly-assign.m
+++ b/test/SemaObjC/property-error-readonly-assign.m
@@ -19,3 +19,26 @@ void f0(A *a, B* b) {
b.ok = 20;
}
+typedef struct {
+ int i1, i2;
+} NSRect;
+
+NSRect NSMakeRect();
+
+@interface NSWindow
+{
+ NSRect _frame;
+}
+- (NSRect)frame;
+@end
+
+@interface NSWindow (Category)
+-(void)methodToMakeClangCrash;
+@end
+
+@implementation NSWindow (Category)
+-(void)methodToMakeClangCrash
+{
+ self.frame = NSMakeRect(); // expected-error {{setter method is needed to assign to object using property assignment syntax}}
+}
+@end
diff --git a/test/SemaObjC/property-expression-error.m b/test/SemaObjC/property-expression-error.m
new file mode 100644
index 0000000..b648ee9
--- /dev/null
+++ b/test/SemaObjC/property-expression-error.m
@@ -0,0 +1,18 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface AddressMyProperties
+{
+ unsigned index;
+}
+@property unsigned index;
+@end
+
+@implementation AddressMyProperties
+@synthesize index;
+@end
+
+int main() {
+ AddressMyProperties *object;
+ &object.index; // expected-error {{address of property expression requested}}
+ return 0;
+}
diff --git a/test/SemaObjC/property-method-lookup-impl.m b/test/SemaObjC/property-method-lookup-impl.m
index ed7e9bc..295bba5 100644
--- a/test/SemaObjC/property-method-lookup-impl.m
+++ b/test/SemaObjC/property-method-lookup-impl.m
@@ -8,9 +8,7 @@
@implementation SSyncCEList
-- (id) list
-{
-}
+- (id) list { return 0; }
@end
@interface SSyncConflictList : SSyncCEList
diff --git a/test/SemaObjC/property-missing.m b/test/SemaObjC/property-missing.m
index 1aa94ce..301907a 100644
--- a/test/SemaObjC/property-missing.m
+++ b/test/SemaObjC/property-missing.m
@@ -17,6 +17,6 @@ void f2(id<NSCopying> o)
void f3(id o)
{
- o.foo; // expected-error{{member reference base type 'id' is not a structure or union}}
+ o.foo; // expected-error{{property 'foo' not found on object of type 'id'}}
}
diff --git a/test/SemaObjC/protocol-archane.m b/test/SemaObjC/protocol-archane.m
index 3e70c05..05f5103 100644
--- a/test/SemaObjC/protocol-archane.m
+++ b/test/SemaObjC/protocol-archane.m
@@ -28,8 +28,7 @@ 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}}
+Class <SomeProtocol> UnfortunateGCCExtension;
diff --git a/test/SemaObjC/protocol-attribute.m b/test/SemaObjC/protocol-attribute.m
index ae84411..6bd58dd 100644
--- a/test/SemaObjC/protocol-attribute.m
+++ b/test/SemaObjC/protocol-attribute.m
@@ -3,7 +3,7 @@
__attribute ((unavailable))
@protocol FwProto; // expected-note{{marked unavailable}}
-Class <FwProto> cFw = 0; // expected-warning {{'FwProto' is unavailable}} expected-error{{protocol qualified 'Class' is unsupported}}
+Class <FwProto> cFw = 0; // expected-warning {{'FwProto' is unavailable}}
__attribute ((deprecated)) @protocol MyProto1
@@ -31,7 +31,7 @@ __attribute ((deprecated)) @protocol MyProto1
-Class <MyProto1> clsP1 = 0; // expected-warning {{'MyProto1' is deprecated}} expected-error{{protocol qualified 'Class' is unsupported}}
+Class <MyProto1> clsP1 = 0; // expected-warning {{'MyProto1' is deprecated}}
@protocol FwProto @end // expected-note{{marked unavailable}}
diff --git a/test/SemaObjC/protocol-implementation-inherited.m b/test/SemaObjC/protocol-implementation-inherited.m
index 1aace21..55b92ae 100644
--- a/test/SemaObjC/protocol-implementation-inherited.m
+++ b/test/SemaObjC/protocol-implementation-inherited.m
@@ -26,7 +26,7 @@
@end
@implementation B1
--foo {};
+-foo { return 0; };
@end
// Interface conforms to a protocol whose methods are provided by an
diff --git a/test/SemaObjC/protocol-lookup.m b/test/SemaObjC/protocol-lookup.m
index 0f1860d..87655bd 100644
--- a/test/SemaObjC/protocol-lookup.m
+++ b/test/SemaObjC/protocol-lookup.m
@@ -44,6 +44,7 @@
[_foo release];
[_bar release];
[super dealloc];
+ return 0;
}
@end
diff --git a/test/SemaObjC/protocol-qualified-class-unsupported.m b/test/SemaObjC/protocol-qualified-class-unsupported.m
index ad1ed5d..6e344c1 100644
--- a/test/SemaObjC/protocol-qualified-class-unsupported.m
+++ b/test/SemaObjC/protocol-qualified-class-unsupported.m
@@ -23,7 +23,7 @@ id objc_getClass(const char *s);
@interface Derived2: Object <Func>
@end
-static void doSomething(Class <Func> unsupportedObjectType) { // expected-error {{protocol qualified 'Class' is unsupported}}
+static void doSomething(Class <Func> unsupportedObjectType) {
[unsupportedObjectType class_func0];
}
diff --git a/test/SemaObjC/rdr-6211479-array-property.m b/test/SemaObjC/rdr-6211479-array-property.m
index f8e4a07..1781c5a 100644
--- a/test/SemaObjC/rdr-6211479-array-property.m
+++ b/test/SemaObjC/rdr-6211479-array-property.m
@@ -1,9 +1,8 @@
// 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}}
+@property(assign) T p2; // expected-error {{property cannot have array or function type 'T' (aka 'int [2]')}}
@end
diff --git a/test/SemaObjC/return.m b/test/SemaObjC/return.m
new file mode 100644
index 0000000..9acf470
--- /dev/null
+++ b/test/SemaObjC/return.m
@@ -0,0 +1,6 @@
+// RUN: clang-cc %s -fsyntax-only -verify
+
+int test1() {
+ id a;
+ @throw a;
+}
diff --git a/test/SemaObjC/selector-1.m b/test/SemaObjC/selector-1.m
index ee77015..a969b10 100644
--- a/test/SemaObjC/selector-1.m
+++ b/test/SemaObjC/selector-1.m
@@ -8,6 +8,19 @@
@end
+@interface I
+- (id) compare: (char) arg1;
+@end
+
+@interface J
+- (id) compare: (id) arg1;
+@end
+
+SEL foo()
+{
+ return @selector(compare:); // Non warning on multiple selector found.
+}
+
int main() {
SEL s = @selector(retain);
SEL s1 = @selector(meth1:);
diff --git a/test/SemaObjC/sizeof-interface.m b/test/SemaObjC/sizeof-interface.m
index 75d7daa..140a980 100644
--- a/test/SemaObjC/sizeof-interface.m
+++ b/test/SemaObjC/sizeof-interface.m
@@ -77,3 +77,14 @@ int bar(I0 *P) {
}
@end
+
+@interface Foo @end
+
+int foo()
+{
+ Foo *f;
+
+ // Both of these crash clang nicely
+ ++f; // expected-error {{arithmetic on pointer to interface 'Foo', which is not a constant size in non-fragile ABI}}
+ --f; // expected-error {{arithmetic on pointer to interface 'Foo', which is not a constant size in non-fragile ABI}}
+}
diff --git a/test/SemaObjC/static-ivar-ref-1.m b/test/SemaObjC/static-ivar-ref-1.m
index 3c37e9e..6b1a312 100644
--- a/test/SemaObjC/static-ivar-ref-1.m
+++ b/test/SemaObjC/static-ivar-ref-1.m
@@ -1,4 +1,5 @@
-// RUN: clang-cc -ast-print %s
+// RUN: clang-cc -triple i386-unknown-unknown -ast-print %s &&
+// RUN: clang-cc -triple x86_64-apple-darwin10 -ast-print %s
@interface current
{
diff --git a/test/SemaObjC/super-cat-prot.m b/test/SemaObjC/super-cat-prot.m
index 1ab0752..6ddc31f 100644
--- a/test/SemaObjC/super-cat-prot.m
+++ b/test/SemaObjC/super-cat-prot.m
@@ -35,14 +35,16 @@ typedef struct _IBInset {} IBInset;
@interface NSView (NSView_IBViewProtocol) <IBViewProtocol> - (NSRect)layoutRect; @end
typedef enum { NSProTextFieldSquareBezel = 0, NSProTextFieldRoundedBezel = 1, NSProTextFieldDisplayBezel = 2 } MKModuleReusePolicy;
@implementation NSProBox(IBAdditions)
--(NSString *)inspectorClassName {}
+-(NSString *)inspectorClassName { return 0; }
-(IBInset)ibShadowInset {
if ([self boxType] == NSBoxSeparator) {
return [super ibShadowInset];
}
+ while (1) {}
}
-(NSSize)minimumFrameSizeFromKnobPosition:(IBKnobPosition)knobPosition {
if ([self boxType] != NSBoxSeparator)
return [super minimumFrameSizeFromKnobPosition:knobPosition];
+ while (1) {}
}
@end
diff --git a/test/SemaObjC/super.m b/test/SemaObjC/super.m
index 9afd4eb..83842af 100644
--- a/test/SemaObjC/super.m
+++ b/test/SemaObjC/super.m
@@ -21,6 +21,7 @@
+ classMethod {
[super cMethod]; // expected-warning{{method '+cMethod' not found (return type defaults to 'id')}}
+ return 0;
}
@end
diff --git a/test/SemaObjC/synchronized.m b/test/SemaObjC/synchronized.m
index 7131265..01f82c1 100644
--- a/test/SemaObjC/synchronized.m
+++ b/test/SemaObjC/synchronized.m
@@ -3,7 +3,7 @@
@interface PBXTrackableTaskManager @end
@implementation PBXTrackableTaskManager
-- (id) init {}
+- (id) init { return 0; }
- (void) unregisterTask:(id) task {
@synchronized (self) {
id taskID = [task taskIdentifier]; // expected-warning {{method '-taskIdentifier' not found (return type defaults to 'id')}}
diff --git a/test/SemaObjC/undef-superclass-1.m b/test/SemaObjC/undef-superclass-1.m
index 0d670f8..cb15dc3 100644
--- a/test/SemaObjC/undef-superclass-1.m
+++ b/test/SemaObjC/undef-superclass-1.m
@@ -24,3 +24,10 @@
[super dealloc]; // expected-error {{no super class declared in @interface for 'SUPER'}}
}
@end
+
+@interface RecursiveClass : RecursiveClass // expected-error {{trying to recursively use 'RecursiveClass' as superclass of 'RecursiveClass'}}
+@end
+
+@implementation RecursiveClass
+@end
+
diff --git a/test/SemaObjC/unused.m b/test/SemaObjC/unused.m
index 88c6f10..bbe3109 100644
--- a/test/SemaObjC/unused.m
+++ b/test/SemaObjC/unused.m
@@ -1,4 +1,4 @@
-// RUN: clang-cc %s -verify -fsyntax-only
+// RUN: clang-cc %s -verify -Wunused -fsyntax-only
#include <stdio.h>
@interface Greeter
@@ -11,8 +11,33 @@
}
@end
-int main (void) {
- [Greeter hello];
- return 0;
+
+int test1(void) {
+ [Greeter hello];
+ return 0;
+}
+
+
+
+@interface NSObject @end
+@interface NSString : NSObject
+- (int)length;
+@end
+
+void test2() {
+ @"pointless example call for test purposes".length; // expected-warning {{property access result unused - getters should not have side effects}}
}
+
+
+
+
+@interface foo
+- (int)meth: (int)x: (int)y: (int)z ;
+@end
+
+@implementation foo
+- (int) meth: (int)x:
+(int)y: // expected-warning{{unused}}
+(int) __attribute__((unused))z { return x; }
+@end
diff --git a/test/SemaObjC/warn-assign-property-nscopying.m b/test/SemaObjC/warn-assign-property-nscopying.m
new file mode 100644
index 0000000..cf1acc4
--- /dev/null
+++ b/test/SemaObjC/warn-assign-property-nscopying.m
@@ -0,0 +1,15 @@
+// RUN: clang-cc -fobjc-gc -fsyntax-only -verify %s
+
+@protocol NSCopying @end
+
+@interface NSObject <NSCopying>
+@end
+
+@interface NSDictionary : NSObject
+@end
+
+@interface INTF
+ @property NSDictionary* undoAction; // expected-warning {{no 'assign', 'retain', or 'copy' attribute is specified - 'assign' is assumed}} // expected-warning {{default assign attribute on property 'undoAction' which implements NSCopying protocol is not appropriate with}}
+ @property id okAction; // expected-warning {{no 'assign', 'retain', or 'copy' attribute is specified - 'assign' is assumed}}
+@end
+
diff --git a/test/SemaObjC/warn-superclass-method-mismatch.m b/test/SemaObjC/warn-superclass-method-mismatch.m
new file mode 100644
index 0000000..f123a3f2
--- /dev/null
+++ b/test/SemaObjC/warn-superclass-method-mismatch.m
@@ -0,0 +1,50 @@
+// RUN: clang-cc -fsyntax-only -Wsuper-class-method-mismatch -verify %s
+
+@interface Root
+-(void) method_r: (char)ch : (float*)f1 : (int*) x; // expected-note {{previous declaration is here}}
+@end
+
+@class Sub;
+
+@interface Base : Root
+-(void) method: (int*) x; // expected-note {{previous declaration is here}}
+-(void) method1: (Base*) x; // expected-note {{previous declaration is here}}
+-(void) method2: (Sub*) x;
++ method3: (int)x1 : (Base *)x2 : (float)x3; // expected-note {{previous declaration is here}}
++ mathod4: (id)x1;
+- method5: (int) x : (double) d; // expected-note {{previous declaration is here}}
+- method6: (int) x : (float) d; // expected-note {{previous declaration is here}}
+@end
+
+struct A {
+ int x,y,z;
+};
+
+@interface Sub : Base
+-(void) method: (struct A*) a; // expected-warning {{method parameter type 'struct A *' does not match super class method parameter type 'int *'}}
+-(void) method1: (Sub*) x; // expected-warning {{method parameter type 'Sub *' does not match super class method parameter type 'Base *'}}
+-(void) method2: (Base*) x; // no need to warn. At call point we warn if need be.
++ method3: (int)x1 : (Sub *)x2 : (float)x3; // expected-warning {{method parameter type 'Sub *' does not match super class method parameter type 'Base *'}}
++ mathod4: (Base*)x1;
+-(void) method_r: (char)ch : (float*)f1 : (Sub*) x; // expected-warning {{method parameter type 'Sub *' does not match super class method parameter type 'int *'}}
+- method5: (int) x : (float) d; // expected-warning {{method parameter type 'float' does not match super class method parameter type 'double'}}
+- method6: (int) x : (double) d; // expected-warning {{method parameter type 'double' does not match super class method parameter type 'float'}}
+@end
+
+void f(Base *base, Sub *sub) {
+ int x;
+ [base method:&x]; // warn. if base is actually 'Sub' it will use -[Sub method] with wrong arguments
+
+ Base *b;
+ [base method1:b]; // if base is actuall 'Sub' it will use [Sub method1] with wrong argument.
+
+ [base method2:b]; // expected-warning {{}}
+
+ Sub *s;
+ [base method2:s]; // if base is actually 'Sub' OK. Either way OK.
+
+}
+
+
+
+
diff --git a/test/SemaObjC/weak-attr-ivar.m b/test/SemaObjC/weak-attr-ivar.m
index 9e0e8cb..6af96dd 100644
--- a/test/SemaObjC/weak-attr-ivar.m
+++ b/test/SemaObjC/weak-attr-ivar.m
@@ -45,8 +45,7 @@ typedef enum { Foo_HUH_NONE } FooHUHCode;
}
@property(copy) NSString *author;
- (BOOL) isInteresting;
-@end NSString *FooHUHCodeToString(FooHUHCode HUH) {
-}
+@end NSString *FooHUHCodeToString(FooHUHCode HUH) { return 0; }
@interface FooHUHCodeToStringTransformer: NSValueTransformer {
}
@end @implementation FooPlaypenEntry @synthesize author = _author;
@@ -62,12 +61,14 @@ typedef enum { Foo_HUH_NONE } FooHUHCode;
}
}
}
+ return 0;
}
- (FooHUHCode) HUH {
if (_HUH == Foo_HUH_NONE) {
if (_mostInterestingChild)
return [_mostInterestingChild HUH];
}
+ return 0;
}
@end
diff --git a/test/SemaObjCXX/overload.mm b/test/SemaObjCXX/overload.mm
index 8ab22e1..4714100 100644
--- a/test/SemaObjCXX/overload.mm
+++ b/test/SemaObjCXX/overload.mm
@@ -1,4 +1,5 @@
// RUN: clang-cc -fsyntax-only -verify %s
+// XFAIL
@interface Foo
@end
diff --git a/test/SemaObjCXX/protocol-lookup.mm b/test/SemaObjCXX/protocol-lookup.mm
index 0f1860d..87655bd 100644
--- a/test/SemaObjCXX/protocol-lookup.mm
+++ b/test/SemaObjCXX/protocol-lookup.mm
@@ -44,6 +44,7 @@
[_foo release];
[_bar release];
[super dealloc];
+ return 0;
}
@end
diff --git a/test/SemaObjCXX/references.mm b/test/SemaObjCXX/references.mm
index 6a28ea9..82797ce 100644
--- a/test/SemaObjCXX/references.mm
+++ b/test/SemaObjCXX/references.mm
@@ -1,4 +1,6 @@
-// RUN: clang-cc -verify -emit-llvm -o %t %s
+// FIXME: This crashes, disable it until fixed.
+// RN: clang-cc -verify -emit-llvm -o - %s
+// RUN: false
// XFAIL
// Test reference binding.
diff --git a/test/SemaTemplate/ackermann.cpp b/test/SemaTemplate/ackermann.cpp
index 48fbbbb..c936889 100644
--- a/test/SemaTemplate/ackermann.cpp
+++ b/test/SemaTemplate/ackermann.cpp
@@ -1,9 +1,9 @@
-// RUN: clang-cc -fsyntax-only -ftemplate-depth=1000 -verify %s
+// RUN: clang-cc -fsyntax-only -verify %s
// template<unsigned M, unsigned N>
// struct Ackermann {
// enum {
-// value = M ? (N ? Ackermann<M-1, Ackermann<M-1, N-1> >::value
+// value = M ? (N ? Ackermann<M-1, Ackermann<M, N-1> >::value
// : Ackermann<M-1, 1>::value)
// : N + 1
// };
@@ -34,4 +34,5 @@ template<> struct Ackermann<0, 0> {
};
};
-int g0[Ackermann<3, 8>::value == 2045 ? 1 : -1];
+int g0[Ackermann<3, 4>::value == 125 ? 1 : -1];
+
diff --git a/test/SemaTemplate/ambiguous-ovl-print.cpp b/test/SemaTemplate/ambiguous-ovl-print.cpp
new file mode 100644
index 0000000..ccdeb9b
--- /dev/null
+++ b/test/SemaTemplate/ambiguous-ovl-print.cpp
@@ -0,0 +1,9 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+void f(void*, int); // expected-note{{candidate function}}
+template<typename T>
+ void f(T*, long); // expected-note{{candidate function template}}
+
+void test_f(int *ip, int i) {
+ f(ip, i); // expected-error{{ambiguous}}
+}
diff --git a/test/SemaTemplate/canonical-expr-type-0x.cpp b/test/SemaTemplate/canonical-expr-type-0x.cpp
new file mode 100644
index 0000000..2155210
--- /dev/null
+++ b/test/SemaTemplate/canonical-expr-type-0x.cpp
@@ -0,0 +1,16 @@
+// RUN: clang-cc -fsyntax-only -verify -std=c++0x %s
+
+void f();
+
+// FIXME: would like to refer to the first function parameter in these test,
+// but that won't work (yet).
+
+// Test typeof(expr) canonicalization
+template<typename T, T N>
+void f0(T x, decltype(f(N)) y) { } // expected-note{{previous}}
+
+template<typename T, T N>
+void f0(T x, decltype((f)(N)) y) { }
+
+template<typename U, U M>
+void f0(U u, decltype(f(M))) { } // expected-error{{redefinition}}
diff --git a/test/SemaTemplate/canonical-expr-type.cpp b/test/SemaTemplate/canonical-expr-type.cpp
new file mode 100644
index 0000000..0580c67
--- /dev/null
+++ b/test/SemaTemplate/canonical-expr-type.cpp
@@ -0,0 +1,53 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+void f();
+
+// Test typeof(expr) canonicalization
+template<typename T>
+void f0(T x, __typeof__(f(x)) y) { } // expected-note{{previous}}
+
+template<typename T>
+void f0(T x, __typeof__((f)(x)) y) { }
+
+template<typename U>
+void f0(U u, __typeof__(f(u))) { } // expected-error{{redefinition}}
+
+// Test insane typeof(expr) overload set canonicalization
+void f(int);
+void f(double);
+
+template<typename T, T N>
+void f0a(T x, __typeof__(f(N)) y) { } // expected-note{{previous}}
+
+void f(int);
+
+template<typename T, T N>
+void f0a(T x, __typeof__(f(N)) y) { } // expected-error{{redefinition}} \
+ // expected-note{{previous}}
+
+void f(float);
+
+template<typename T, T N>
+void f0a(T x, __typeof__(f(N)) y) { } // expected-error{{redefinition}}
+
+// Test dependently-sized array canonicalization
+template<typename T, int N, int M>
+void f1(T (&array)[N + M]) { } // expected-note{{previous}}
+
+template<typename T, int N, int M>
+void f1(T (&array)[M + N]) { }
+
+template<typename T, int M, int N>
+void f1(T (&array)[M + N]) { } // expected-error{{redefinition}}
+
+// Test dependently-sized extended vector type canonicalization
+template<typename T, int N, int M>
+struct X2 {
+ typedef T __attribute__((ext_vector_type(N))) type1;
+ typedef T __attribute__((ext_vector_type(M))) type2;
+ typedef T __attribute__((ext_vector_type(N))) type3;
+
+ void f0(type1); // expected-note{{previous}}
+ void f0(type2);
+ void f0(type3); // expected-error{{redeclared}}
+};
diff --git a/test/SemaTemplate/class-template-spec.cpp b/test/SemaTemplate/class-template-spec.cpp
index 71d8ea1..e44115c 100644
--- a/test/SemaTemplate/class-template-spec.cpp
+++ b/test/SemaTemplate/class-template-spec.cpp
@@ -1,5 +1,6 @@
// RUN: clang-cc -fsyntax-only -verify %s
-template<typename T, typename U = int> struct A; // expected-note 2{{template is declared here}}
+template<typename T, typename U = int> struct A; // expected-note {{template is declared here}} \
+ // expected-note{{explicitly specialized}}
template<> struct A<double, double>; // expected-note{{forward declaration}}
@@ -19,7 +20,8 @@ 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>'}}
+ (void)a2->x; // expected-error{{implicit instantiation of undefined template 'struct A<double, int>'}} \
+ // expected-note{{first required here}}
}
typedef float FLOAT;
@@ -49,13 +51,33 @@ struct A<char> {
A<char>::A() { }
+// Make sure we can see specializations defined before the primary template.
+namespace N{
+ template<typename T> struct A0;
+}
+
+namespace N {
+ template<>
+ struct A0<void> {
+ typedef void* pointer;
+ };
+}
+
+namespace N {
+ template<typename T>
+ struct A0 {
+ void foo(A0<void>::pointer p = 0);
+ };
+}
+
// Diagnose specialization errors
-struct A<double> { }; // expected-error{{template specialization requires 'template<>'}}
+struct A<double> { }; // expected-error{{template specialization requires 'template<>'}} \
+ // expected-error{{after instantiation}}
template<> struct ::A<double>;
namespace N {
- template<typename T> struct B; // expected-note 2{{template is declared here}}
+ template<typename T> struct B; // expected-note 2{{explicitly specialized}}
template<> struct ::N::B<char>; // okay
template<> struct ::N::B<short>; // okay
@@ -66,12 +88,12 @@ namespace N {
template<> struct N::B<int> { }; // okay
-template<> struct N::B<float> { }; // expected-error{{class template specialization of 'B' not in namespace 'N'}}
+template<> struct N::B<float> { }; // expected-error{{originally}}
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 ::A<long double>; // expected-error{{originally}}
}
template<> struct N::B<char> {
diff --git a/test/SemaTemplate/constructor-template.cpp b/test/SemaTemplate/constructor-template.cpp
new file mode 100644
index 0000000..acd845b
--- /dev/null
+++ b/test/SemaTemplate/constructor-template.cpp
@@ -0,0 +1,53 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+struct X0 { // expected-note{{candidate}}
+ X0(int); // expected-note{{candidate}}
+ template<typename T> X0(T);
+ template<typename T, typename U> X0(T*, U*);
+
+ // PR4761
+ template<typename T> X0() : f0(T::foo) {}
+ int f0;
+};
+
+void accept_X0(X0);
+
+void test_X0(int i, float f) {
+ X0 x0a(i);
+ X0 x0b(f);
+ X0 x0c = i;
+ X0 x0d = f;
+ accept_X0(i);
+ accept_X0(&i);
+ accept_X0(f);
+ accept_X0(&f);
+ X0 x0e(&i, &f);
+ X0 x0f(&f, &i);
+
+ X0 x0g(f, &i); // expected-error{{no matching constructor}}
+}
+
+template<typename T>
+struct X1 {
+ X1(const X1&);
+ template<typename U> X1(const X1<U>&);
+};
+
+template<typename T>
+struct Outer {
+ typedef X1<T> A;
+
+ A alloc;
+
+ explicit Outer(const A& a) : alloc(a) { }
+};
+
+void test_X1(X1<int> xi) {
+ Outer<int> oi(xi);
+ Outer<float> of(xi);
+}
+
+// PR4655
+template<class C> struct A {};
+template <> struct A<int>{A(const A<int>&);};
+struct B { A<int> x; B(B& a) : x(a.x) {} };
diff --git a/test/SemaTemplate/copy-ctor-assign.cpp b/test/SemaTemplate/copy-ctor-assign.cpp
new file mode 100644
index 0000000..90fb013
--- /dev/null
+++ b/test/SemaTemplate/copy-ctor-assign.cpp
@@ -0,0 +1,36 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// Make sure that copy constructors and assignment operators are properly
+// generated when there is a matching
+
+// PR5072
+template<typename T>
+struct X {
+ template<typename U>
+ X(const X<U>& other)
+ : value(other.value + 1) { } // expected-error{{binary expression}}
+
+ template<typename U>
+ X& operator=(const X<U>& other) {
+ value = other.value + 1; // expected-error{{binary expression}}
+ return *this;
+ }
+
+ T value;
+};
+
+struct Y {};
+
+X<int Y::*> test0(X<int Y::*> x) { return x; }
+X<int> test1(X<long> x) { return x; }
+
+
+X<int> test2(X<int Y::*> x) {
+ return x; // expected-note{{instantiation}}
+}
+
+void test3(X<int> &x, X<int> xi, X<long> xl, X<int Y::*> xmptr) {
+ x = xi;
+ x = xl;
+ x = xmptr; // expected-note{{instantiation}}
+} \ No newline at end of file
diff --git a/test/SemaTemplate/current-instantiation.cpp b/test/SemaTemplate/current-instantiation.cpp
index 603c140..a1d9fcb 100644
--- a/test/SemaTemplate/current-instantiation.cpp
+++ b/test/SemaTemplate/current-instantiation.cpp
@@ -69,3 +69,76 @@ struct X0 {
void g8(typename ::X0<typename X0<T_type, U>::X1::my_T_type, U_type>::X1::my_T_type&); // expected-error{{redecl}}
};
};
+
+
+template<typename T, typename U>
+struct X0<T*, U*> {
+ typedef T T_type;
+ typedef U U_type;
+ typedef T* Tptr;
+ typedef U* Uptr;
+
+ 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}}
+
+ void f4(T&); // expected-note{{previous}}
+ void f4(typename X0::U_type&);
+ void f4(typename ::X0<Tptr, Uptr>::T_type&); // expected-error{{redecl}}
+
+ void f5(X0*); // expected-note{{previous}}
+ void f5(::X0<T, U>*);
+ void f5(::X0<T*, U*>*); // expected-error{{redecl}}
+
+ struct X2 {
+ 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 X2::my_T_type&); // expected-error{{redecl}}
+
+ void g5(T&); // expected-note{{previous}}
+ void g5(typename X0::U_type&);
+ void g5(typename X0::X2::my_T_type&); // expected-error{{redecl}}
+
+ void g6(T&); // expected-note{{previous}}
+ void g6(typename X0::U_type&);
+ void g6(typename X0<T*, U*>::X2::my_T_type&); // expected-error{{redecl}}
+
+ void g7(T&); // expected-note{{previous}}
+ void g7(typename X0::U_type&);
+ void g7(typename ::X0<typename X2::my_T_type*, U_type*>::X2::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*>::X2::my_T_type*, U_type*>::X2::my_T_type&); // expected-error{{redecl}}
+ };
+};
diff --git a/test/SemaTemplate/default-arguments.cpp b/test/SemaTemplate/default-arguments.cpp
index f9bb44e..33677aa 100644
--- a/test/SemaTemplate/default-arguments.cpp
+++ b/test/SemaTemplate/default-arguments.cpp
@@ -22,3 +22,23 @@ template<class T, bool = a<T>::v> struct p { }; // expected-error {{no member na
template struct p<bool>; // expected-note {{in instantiation of default argument for 'p<bool>' required here}}
template struct p<int>;
+
+// PR5187
+template<typename T, typename U>
+struct A;
+
+template<typename T, typename U = T>
+struct A;
+
+template<typename T, typename U>
+struct A {
+ void f(A<T>);
+};
+
+template<typename T>
+struct B { };
+
+template<>
+struct B<void> {
+ typedef B<void*> type;
+};
diff --git a/test/SemaTemplate/default-expr-arguments.cpp b/test/SemaTemplate/default-expr-arguments.cpp
new file mode 100644
index 0000000..575283e
--- /dev/null
+++ b/test/SemaTemplate/default-expr-arguments.cpp
@@ -0,0 +1,86 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T>
+class C { C(int a0 = 0); };
+
+template<>
+C<char>::C(int a0);
+
+struct S { };
+
+template<typename T> void f1(T a, T b = 10) { } // expected-error{{cannot initialize 'b' with an rvalue of type 'int'}}
+
+template<typename T> void f2(T a, T b = T()) { }
+
+template<typename T> void f3(T a, T b = T() + T()); // expected-error{{invalid operands to binary expression ('struct S' and 'struct S')}}
+
+void g() {
+ f1(10);
+ f1(S()); // expected-note{{in instantiation of default function argument expression for 'f1<struct S>' required here}}
+
+ f2(10);
+ f2(S());
+
+ f3(10);
+ f3(S()); // expected-note{{in instantiation of default function argument expression for 'f3<struct S>' required here}}
+}
+
+template<typename T> struct F {
+ F(T t = 10); // expected-error{{cannot initialize 't' with an rvalue of type 'int'}}
+ void f(T t = 10); // expected-error{{cannot initialize 't' with an rvalue of type 'int'}}
+};
+
+struct FD : F<int> { };
+
+void g2() {
+ F<int> f;
+ FD fd;
+}
+
+void g3(F<int> f, F<struct S> s) {
+ f.f();
+ s.f(); // expected-note{{in instantiation of default function argument expression for 'f<struct S>' required here}}
+
+ F<int> f2;
+ F<S> s2; // expected-note{{in instantiation of default function argument expression for 'F<struct S>' required here}}
+}
+
+template<typename T> struct G {
+ G(T) {}
+};
+
+void s(G<int> flags = 10) { }
+
+// Test default arguments
+template<typename T>
+struct X0 {
+ void f(T = T()); // expected-error{{no matching}}
+};
+
+template<typename U>
+void X0<U>::f(U) { }
+
+void test_x0(X0<int> xi) {
+ xi.f();
+ xi.f(17);
+}
+
+struct NotDefaultConstructible { // expected-note{{candidate}}
+ NotDefaultConstructible(int); // expected-note{{candidate}}
+};
+
+void test_x0_not_default_constructible(X0<NotDefaultConstructible> xn) {
+ xn.f(NotDefaultConstructible(17));
+ xn.f(42);
+ xn.f(); // expected-note{{in instantiation of default function argument}}
+}
+
+template<typename T>
+struct X1 {
+ typedef T value_type;
+ X1(const value_type& value = value_type());
+};
+
+void test_X1() {
+ X1<int> x1;
+}
diff --git a/test/SemaTemplate/dependent-base-member-init.cpp b/test/SemaTemplate/dependent-base-member-init.cpp
new file mode 100644
index 0000000..b3d707b
--- /dev/null
+++ b/test/SemaTemplate/dependent-base-member-init.cpp
@@ -0,0 +1,36 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// PR4381
+template<class T> struct X {};
+template<typename T> struct Y : public X<T>::X { };
+
+// PR4621
+class A1 {
+ A1(int x) {}
+};
+template<class C> class B1 : public A1 {
+ B1(C x) : A1(x.x) {}
+};
+class A2 { A2(int x, int y); };
+template <class C> class B2 {
+ A2 x;
+ B2(C x) : x(x.x, x.y) {}
+};
+template <class C> class B3 {
+ C x;
+ B3() : x(1,2) {}
+};
+
+// PR4627
+template<typename _Container> class insert_iterator {
+ _Container* container;
+ insert_iterator(_Container& __x) : container(&__x) {}
+};
+
+// PR4763
+template<typename T> struct s0 {};
+template<typename T> struct s0_traits {};
+template<typename T> struct s1 : s0<typename s0_traits<T>::t0> {
+ s1() {}
+};
+
diff --git a/test/SemaTemplate/dependent-type-identity.cpp b/test/SemaTemplate/dependent-type-identity.cpp
index 739cb7f..b7c9040 100644
--- a/test/SemaTemplate/dependent-type-identity.cpp
+++ b/test/SemaTemplate/dependent-type-identity.cpp
@@ -59,7 +59,7 @@ struct X1 {
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> *);
diff --git a/test/SemaTemplate/destructor-template.cpp b/test/SemaTemplate/destructor-template.cpp
new file mode 100644
index 0000000..a7c8d24
--- /dev/null
+++ b/test/SemaTemplate/destructor-template.cpp
@@ -0,0 +1,12 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename A> class s0 {
+
+ template<typename B> class s1 : public s0<A> {
+ ~s1() {}
+ s0<A> ms0;
+ };
+
+};
+
+
diff --git a/test/SemaTemplate/example-dynarray.cpp b/test/SemaTemplate/example-dynarray.cpp
index 680ee04..0b8d605 100644
--- a/test/SemaTemplate/example-dynarray.cpp
+++ b/test/SemaTemplate/example-dynarray.cpp
@@ -1,4 +1,4 @@
-// RUN: clang-cc -fsyntax-only -verify %s
+// RUN: clang %s -o %t
#include <stddef.h>
#include <stdlib.h>
#include <assert.h>
@@ -24,6 +24,9 @@ public:
}
~dynarray() {
+ for (unsigned I = 0, N = size(); I != N; ++I)
+ Start[I].~T();
+
free(Start);
}
@@ -33,7 +36,9 @@ public:
for (unsigned I = 0, N = other.size(); I != N; ++I)
new (NewStart + I) T(other[I]);
- // FIXME: destroy everything in Start
+ for (unsigned I = 0, N = size(); I != N; ++I)
+ Start[I].~T();
+
free(Start);
Start = NewStart;
Last = End = NewStart + other.size();
@@ -43,33 +48,11 @@ public:
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 push_back(const T& value);
+
void pop_back() {
- // FIXME: destruct old value
--Last;
+ Last->~T();
}
T& operator[](unsigned Idx) {
@@ -108,6 +91,32 @@ public:
T* Start, *Last, *End;
};
+template<typename T>
+void dynarray<T>::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]);
+
+ for (unsigned I = 0, N = size(); I != N; ++I)
+ Start[I].~T();
+ free(Start);
+
+ Start = NewStart;
+ Last = Start + Size;
+ End = Start + NewCapacity;
+ }
+
+ new (Last) T(value);
+ ++Last;
+}
+
struct Point {
Point() { x = y = z = 0.0; }
Point(const Point& other) : x(other.x), y(other.y), z(other.z) { }
diff --git a/test/SemaTemplate/explicit-instantiation.cpp b/test/SemaTemplate/explicit-instantiation.cpp
new file mode 100644
index 0000000..b9a4ad2
--- /dev/null
+++ b/test/SemaTemplate/explicit-instantiation.cpp
@@ -0,0 +1,75 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template void *; // expected-error{{expected unqualified-id}}
+
+template typedef void f0; // expected-error{{explicit instantiation of typedef}}
+
+int v0; // expected-note{{refers here}}
+template int v0; // expected-error{{does not refer}}
+
+template<typename T>
+struct X0 {
+ static T value;
+
+ T f0(T x) {
+ return x + 1; // expected-error{{invalid operands}}
+ }
+ T* f0(T*, T*);
+
+ template<typename U>
+ T f0(T, U);
+};
+
+template int X0<int>::value;
+
+struct NotDefaultConstructible {
+ NotDefaultConstructible(int);
+};
+
+template NotDefaultConstructible X0<NotDefaultConstructible>::value;
+
+template int X0<int>::f0(int);
+template int* X0<int>::f0(int*, int*);
+template int X0<int>::f0(int, float);
+
+template int X0<int>::f0(int) const; // expected-error{{does not refer}}
+template int* X0<int>::f0(int*, float*); // expected-error{{does not refer}}
+
+struct X1 { };
+typedef int X1::*MemPtr;
+
+template MemPtr X0<MemPtr>::f0(MemPtr); // expected-note{{requested here}}
+
+struct X2 {
+ int f0(int); // expected-note{{refers here}}
+
+ template<typename T> T f1(T);
+ template<typename T> T* f1(T*);
+
+ template<typename T, typename U> void f2(T, U*); // expected-note{{candidate}}
+ template<typename T, typename U> void f2(T*, U); // expected-note{{candidate}}
+};
+
+template int X2::f0(int); // expected-error{{not an instantiation}}
+
+template int *X2::f1(int *); // okay
+
+template void X2::f2(int *, int *); // expected-error{{ambiguous}}
+
+
+template<typename T> void print_type();
+
+template void print_type<int>();
+template void print_type<float>();
+
+template<typename T> void print_type(T*);
+
+template void print_type(int*);
+template void print_type<int>(float*); // expected-error{{does not refer}}
+
+void print_type(double*);
+template void print_type<double>(double*);
+
+// PR5069
+template<int I> void foo0 (int (&)[I + 1]) { }
+template void foo0<2> (int (&)[3]);
diff --git a/test/SemaTemplate/explicit-specialization-member.cpp b/test/SemaTemplate/explicit-specialization-member.cpp
new file mode 100644
index 0000000..197dae5
--- /dev/null
+++ b/test/SemaTemplate/explicit-specialization-member.cpp
@@ -0,0 +1,11 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+template<typename T>
+struct X0 {
+ typedef T* type;
+
+ void f0(T);
+ void f1(type);
+};
+
+template<> void X0<char>::f0(char);
+template<> void X0<char>::f1(type);
diff --git a/test/SemaTemplate/ext-vector-type.cpp b/test/SemaTemplate/ext-vector-type.cpp
index d6c02bb..b6aebc1 100644
--- a/test/SemaTemplate/ext-vector-type.cpp
+++ b/test/SemaTemplate/ext-vector-type.cpp
@@ -4,7 +4,7 @@ struct make1 {
typedef T __attribute__((ext_vector_type(Length))) type;
};
-int test_make1() {
+void test_make1() {
make1<int, 5>::type x;
x.x = 4;
}
diff --git a/test/SemaTemplate/extern-templates.cpp b/test/SemaTemplate/extern-templates.cpp
new file mode 100644
index 0000000..28fda1a
--- /dev/null
+++ b/test/SemaTemplate/extern-templates.cpp
@@ -0,0 +1,66 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T>
+class X0 {
+public:
+ void f(T t);
+
+ struct Inner {
+ void g(T t);
+ };
+};
+
+template<typename T>
+void X0<T>::f(T t) {
+ t = 17; // expected-error{{incompatible}}
+}
+
+extern template class X0<int>;
+
+extern template class X0<int*>;
+
+template<typename T>
+void X0<T>::Inner::g(T t) {
+ t = 17; // expected-error{{incompatible}}
+}
+
+void test_intptr(X0<int*> xi, X0<int*>::Inner xii) {
+ xi.f(0);
+ xii.g(0);
+}
+
+// FIXME: we would like the notes to point to the explicit instantiation at the
+// bottom.
+extern template class X0<long*>; // expected-note 2{{instantiation}}
+
+void test_longptr(X0<long*> xl, X0<long*>::Inner xli) {
+ xl.f(0);
+ xli.g(0);
+}
+
+template class X0<long*>;
+
+template<typename T>
+class X1 {
+public:
+ void f(T t) { t += 2; }
+
+ void g(T t);
+};
+
+template<typename T>
+void X1<T>::g(T t) {
+ t += 2;
+}
+
+extern template class X1<void*>;
+
+void g_X1(X1<void*> x1, void *ptr) {
+ x1.g(ptr);
+}
+
+extern template void X1<const void*>::g(const void*);
+
+void g_X1_2(X1<const void *> x1, const void *ptr) {
+ x1.g(ptr);
+}
diff --git a/test/SemaTemplate/friend-template.cpp b/test/SemaTemplate/friend-template.cpp
new file mode 100644
index 0000000..761c130
--- /dev/null
+++ b/test/SemaTemplate/friend-template.cpp
@@ -0,0 +1,64 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// PR5057
+namespace std {
+ class X {
+ public:
+ template<typename T>
+ friend struct Y;
+ };
+}
+
+namespace std {
+ template<typename T>
+ struct Y
+ {
+ };
+}
+
+
+namespace N {
+ template<typename T> void f1(T) { } // expected-note{{here}}
+
+ class X {
+ template<typename T> friend void f0(T);
+ template<typename T> friend void f1(T);
+ };
+
+ template<typename T> void f0(T) { }
+ template<typename T> void f1(T) { } // expected-error{{redefinition}}
+}
+
+// PR4768
+template<typename T>
+struct X0 {
+ template<typename U> friend struct X0;
+};
+
+template<typename T>
+struct X0<T*> {
+ template<typename U> friend struct X0;
+};
+
+template<>
+struct X0<int> {
+ template<typename U> friend struct X0;
+};
+
+template<typename T>
+struct X1 {
+ template<typename U> friend void f2(U);
+ template<typename U> friend void f3(U);
+};
+
+template<typename U> void f2(U);
+
+X1<int> x1i;
+
+template<> void f2(int);
+
+// FIXME: Should this declaration of f3 be required for the specialization of
+// f3<int> (further below) to work? GCC and EDG don't require it, we do...
+template<typename U> void f3(U);
+
+template<> void f3(int);
diff --git a/test/SemaTemplate/friend.cpp b/test/SemaTemplate/friend.cpp
new file mode 100644
index 0000000..2729952
--- /dev/null
+++ b/test/SemaTemplate/friend.cpp
@@ -0,0 +1,14 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+template<typename T> struct A {
+ struct B { };
+
+ friend struct B;
+};
+
+void f() {
+ A<int>::B b;
+}
+
+struct C0 {
+ friend struct A<int>;
+};
diff --git a/test/SemaTemplate/fun-template-def.cpp b/test/SemaTemplate/fun-template-def.cpp
index 8833ef4..dee4250 100644
--- a/test/SemaTemplate/fun-template-def.cpp
+++ b/test/SemaTemplate/fun-template-def.cpp
@@ -10,8 +10,13 @@ namespace std { class type_info {}; }
struct dummy {};
+template<typename T>
+int f0(T x) {
+ return (sizeof(x) == sizeof(int))? 0 : (sizeof(x) == sizeof(double))? 1 : 2;
+}
+
template <typename T, typename U>
-T f(T t1, U u1, int i1)
+T f1(T t1, U u1, int i1)
{
T t2 = i1;
t2 = i1 + u1;
diff --git a/test/SemaTemplate/function-template-specialization.cpp b/test/SemaTemplate/function-template-specialization.cpp
new file mode 100644
index 0000000..90e38cc
--- /dev/null
+++ b/test/SemaTemplate/function-template-specialization.cpp
@@ -0,0 +1,35 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<int N> void f0(int (&array)[N]);
+
+// Simple function template specialization (using overloading)
+template<> void f0(int (&array)[1]);
+
+void test_f0() {
+ int iarr1[1];
+ f0(iarr1);
+}
+
+// Function template specialization where there are no matches
+template<> void f0(char (&array)[1]); // expected-error{{no function template matches}}
+template<> void f0<2>(int (&array)[2]) { }
+
+// Function template specialization that requires partial ordering
+template<typename T, int N> void f1(T (&array)[N]); // expected-note{{matches}}
+template<int N> void f1(int (&array)[N]); // expected-note{{matches}}
+
+template<> void f1(float (&array)[1]);
+template<> void f1(int (&array)[1]);
+
+// Function template specialization that results in an ambiguity
+template<typename T> void f1(T (&array)[17]); // expected-note{{matches}}
+template<> void f1(int (&array)[17]); // expected-error{{ambiguous}}
+
+// Resolving that ambiguity with explicitly-specified template arguments.
+template<int N> void f2(double (&array)[N]);
+template<typename T> void f2(T (&array)[42]);
+
+template<> void f2<double>(double (&array)[42]);
+template<> void f2<42>(double (&array)[42]);
+
+void f2<25>(double (&array)[25]); // expected-error{{specialization}}
diff --git a/test/SemaTemplate/implicit-instantiation-1.cpp b/test/SemaTemplate/implicit-instantiation-1.cpp
index b8f9622..d04bbd8 100644
--- a/test/SemaTemplate/implicit-instantiation-1.cpp
+++ b/test/SemaTemplate/implicit-instantiation-1.cpp
@@ -22,4 +22,4 @@ void test_add(char *cp, int i, int *ip) {
char* cp2 = add(cp, i);
add(cp, cp); // expected-note{{instantiation of}}
(void)sizeof(add(ip, ip));
-} \ No newline at end of file
+}
diff --git a/test/SemaTemplate/injected-class-name.cpp b/test/SemaTemplate/injected-class-name.cpp
index c5f826d..f9674c3 100644
--- a/test/SemaTemplate/injected-class-name.cpp
+++ b/test/SemaTemplate/injected-class-name.cpp
@@ -19,7 +19,7 @@ X<float>::X<int> xi = x;
// [temp.local]p1:
-// FIXME: test non-type and template template parameters
+// FIXME: test template template parameters
template<typename T, typename U>
struct X0 {
typedef T type;
@@ -38,3 +38,11 @@ struct X0 {
void f2(X0&);
void f2(const ::X0<type, U_type2>&); // expected-error{{redecl}}
};
+
+template<typename T, T N>
+struct X1 {
+ void f0(const X1&); // expected-note{{here}}
+ void f0(X1&);
+ void f0(const X1<T, N>&); // expected-error{{redecl}}
+};
+
diff --git a/test/SemaTemplate/instantiate-anonymous-union.cpp b/test/SemaTemplate/instantiate-anonymous-union.cpp
new file mode 100644
index 0000000..375c1da
--- /dev/null
+++ b/test/SemaTemplate/instantiate-anonymous-union.cpp
@@ -0,0 +1,31 @@
+// RUN: clang-cc -fsyntax-only %s -Wall
+
+template <typename T> class A { struct { }; };
+
+A<int> a0;
+
+template <typename T> struct B {
+ union {
+ int a;
+ void* b;
+ };
+
+ void f() {
+ a = 10;
+ b = 0;
+ }
+};
+
+B<int> b0;
+
+template <typename T> struct C {
+ union {
+ int a;
+ void* b;
+ };
+
+ C(int a) : a(a) { }
+ C(void* b) : b(b) { }
+};
+
+C<int> c0(0);
diff --git a/test/SemaTemplate/instantiate-cast.cpp b/test/SemaTemplate/instantiate-cast.cpp
index d99f3e5..6b3fc6e 100644
--- a/test/SemaTemplate/instantiate-cast.cpp
+++ b/test/SemaTemplate/instantiate-cast.cpp
@@ -1,6 +1,6 @@
// RUN: clang-cc -fsyntax-only -verify %s
-struct A { int x; };
+struct A { int x; };
class Base {
public:
@@ -23,7 +23,7 @@ struct Constructible {
template<typename T, typename U>
struct CStyleCast0 {
void f(T t) {
- (void)((U)t); // FIXME:ugly expected-error{{operand}}
+ (void)((U)t); // expected-error{{C-style cast from 'struct A' to 'int'}}
}
};
@@ -36,7 +36,7 @@ template struct CStyleCast0<A, int>; // expected-note{{instantiation}}
template<typename T, typename U>
struct StaticCast0 {
void f(T t) {
- (void)static_cast<U>(t); // expected-error{{static_cast}}
+ (void)static_cast<U>(t); // expected-error{{static_cast from 'int' to 'struct A' is not allowed}}
}
};
@@ -89,7 +89,7 @@ template struct ConstCast0<int const *, float *>; // expected-note{{instantiatio
template<typename T, typename U>
struct FunctionalCast1 {
void f(T t) {
- (void)U(t); // FIXME:ugly expected-error{{operand}}
+ (void)U(t); // expected-error{{functional-style cast from 'struct A' to 'int'}}
}
};
diff --git a/test/SemaTemplate/instantiate-deeply.cpp b/test/SemaTemplate/instantiate-deeply.cpp
new file mode 100644
index 0000000..27e430b
--- /dev/null
+++ b/test/SemaTemplate/instantiate-deeply.cpp
@@ -0,0 +1,22 @@
+// RUN: clang-cc -fsyntax-only -Wall -verify %s
+
+template<typename a> struct A {
+ template <typename b> struct B {
+ template <typename c> struct C {
+ template <typename d> struct D {
+ template <typename e> struct E {
+ e field;
+ E() : field(0) {
+ d v1 = 4;
+ c v2 = v1 * v1;
+ b v3 = 8;
+ a v4 = v3 * v3;
+ field += v2 + v4;
+ }
+ };
+ };
+ };
+ };
+};
+
+A<int>::B<int>::C<int>::D<int>::E<int> global;
diff --git a/test/SemaTemplate/instantiate-expr-2.cpp b/test/SemaTemplate/instantiate-expr-2.cpp
index 80f403e..146e63c 100644
--- a/test/SemaTemplate/instantiate-expr-2.cpp
+++ b/test/SemaTemplate/instantiate-expr-2.cpp
@@ -130,3 +130,51 @@ struct X0 {
void test_X0(X0<int> x, IntegralConstant<int, sizeof(int)> ic) {
x.f(5,ic);
}
+
+namespace N8 {
+ struct X {
+ X operator+(const X&) const;
+ };
+
+ template<typename T>
+ T test_plus(const T* xp, const T& x, const T& y) {
+ x.operator+(y);
+ return xp->operator+(y);
+ }
+
+ void test_test_plus(X x) {
+ test_plus(&x, x, x);
+ }
+}
+
+namespace N9 {
+ struct A {
+ bool operator==(int value);
+ };
+
+ template<typename T> struct B {
+ bool f(A a) {
+ return a == 1;
+ }
+ };
+
+ template struct B<int>;
+}
+
+namespace N10 {
+ template <typename T>
+ class A {
+ struct X { };
+
+ public:
+ ~A() {
+ f(reinterpret_cast<X *>(0), reinterpret_cast<X *>(0));
+ }
+
+ private:
+ void f(X *);
+ void f(X *, X *);
+ };
+
+ template class A<int>;
+}
diff --git a/test/SemaTemplate/instantiate-expr-5.cpp b/test/SemaTemplate/instantiate-expr-5.cpp
new file mode 100644
index 0000000..b42c0fb
--- /dev/null
+++ b/test/SemaTemplate/instantiate-expr-5.cpp
@@ -0,0 +1,4 @@
+// RUN: clang-cc -fsyntax-only %s
+
+template <class A> int x(A x) { return x++; }
+int y() { return x<int>(1); }
diff --git a/test/SemaTemplate/instantiate-friend-class.cpp b/test/SemaTemplate/instantiate-friend-class.cpp
new file mode 100644
index 0000000..9a4a73c
--- /dev/null
+++ b/test/SemaTemplate/instantiate-friend-class.cpp
@@ -0,0 +1,9 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+// PR4794
+
+template <class T> class X
+{
+ friend class Y;
+};
+X<int> y;
+
diff --git a/test/SemaTemplate/instantiate-function-1.cpp b/test/SemaTemplate/instantiate-function-1.cpp
index 023cc54..2749ec2 100644
--- a/test/SemaTemplate/instantiate-function-1.cpp
+++ b/test/SemaTemplate/instantiate-function-1.cpp
@@ -140,7 +140,7 @@ template<typename T> struct Member0 {
tp->f;
this->f;
- this.f; // expected-error{{member reference base type 'Member0<T> *const' is not a structure or union}}
+ this.f; // expected-error{{member reference base type 'Member0<T> *' is not a structure or union}}
}
};
diff --git a/test/SemaTemplate/instantiate-function-1.mm b/test/SemaTemplate/instantiate-function-1.mm
index aef2d9d..be995e7 100644
--- a/test/SemaTemplate/instantiate-function-1.mm
+++ b/test/SemaTemplate/instantiate-function-1.mm
@@ -1,3 +1,6 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+// XFAIL
+
template<typename T> struct Member0 {
void f(T t) {
t;
diff --git a/test/SemaTemplate/instantiate-init.cpp b/test/SemaTemplate/instantiate-init.cpp
new file mode 100644
index 0000000..870b275
--- /dev/null
+++ b/test/SemaTemplate/instantiate-init.cpp
@@ -0,0 +1,28 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+struct X0 { // expected-note 4{{candidate}}
+ X0(int*, float*); // expected-note 4{{candidate}}
+};
+
+template<typename T, typename U>
+X0 f0(T t, U u) {
+ X0 x0(t, u); // expected-error{{no matching}}
+ return X0(t, u); // expected-error{{no matching}}
+}
+
+void test_f0(int *ip, float *fp, double *dp) {
+ f0(ip, fp);
+ f0(ip, dp); // expected-note{{instantiation}}
+}
+
+template<typename Ret, typename T, typename U>
+Ret f1(Ret *retty, T t, U u) {
+ Ret r0(t, u); // expected-error{{no matching}}
+ return Ret(t, u); // expected-error{{no matching}}
+}
+
+void test_f1(X0 *x0, int *ip, float *fp, double *dp) {
+ f1(x0, ip, fp);
+ f1(x0, ip, dp); // expected-note{{instantiation}}
+}
+
diff --git a/test/SemaTemplate/instantiate-member-initializers.cpp b/test/SemaTemplate/instantiate-member-initializers.cpp
new file mode 100644
index 0000000..6fc7042
--- /dev/null
+++ b/test/SemaTemplate/instantiate-member-initializers.cpp
@@ -0,0 +1,26 @@
+// RUN: clang-cc -fsyntax-only -Wall -verify %s
+
+template<typename T> struct A {
+ A() : a(1) { } // expected-error{{incompatible type passing 'int', expected 'void *'}}
+
+ T a;
+};
+
+A<int> a0;
+A<void*> a1; // expected-note{{in instantiation of member function 'A<void *>::A' requested here}}
+
+template<typename T> struct B {
+ // FIXME: This should warn about initialization order
+ B() : b(1), a(2) { }
+
+ int a;
+ int b;
+};
+
+B<int> b0;
+
+template <class T> struct AA { AA(int); };
+template <class T> class BB : public AA<T> {
+ BB() : AA<T>(1) {}
+};
+BB<int> x;
diff --git a/test/SemaTemplate/instantiate-member-template.cpp b/test/SemaTemplate/instantiate-member-template.cpp
new file mode 100644
index 0000000..36f3b6f
--- /dev/null
+++ b/test/SemaTemplate/instantiate-member-template.cpp
@@ -0,0 +1,105 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T>
+struct X0 {
+ template<typename U> T f0(U);
+ template<typename U> U& f1(T*, U); // expected-error{{pointer to a reference}} \
+ // expected-note{{candidate}}
+};
+
+X0<int> x0i;
+X0<void> x0v;
+X0<int&> x0ir; // expected-note{{instantiation}}
+
+void test_X0(int *ip, double *dp) {
+ X0<int> xi;
+ int i1 = xi.f0(ip);
+ double *&dpr = xi.f1(ip, dp);
+ xi.f1(dp, dp); // expected-error{{no matching}}
+
+ X0<void> xv;
+ double *&dpr2 = xv.f1(ip, dp);
+}
+
+template<typename T>
+struct X1 {
+ template<typename U>
+ struct Inner0 {
+ U x;
+ T y; // expected-error{{void}}
+ };
+
+ template<typename U>
+ struct Inner1 {
+ U x; // expected-error{{void}}
+ T y;
+ };
+
+ template<typename U>
+ struct Inner2 {
+ struct SuperInner {
+ U z; // expected-error{{void}}
+ };
+ };
+
+ template<typename U>
+ struct Inner3 {
+ void f0(T t, U u) {
+ (void)(t + u); // expected-error{{invalid operands}}
+ }
+
+ template<typename V>
+ V f1(T t, U u, V) {
+ return t + u; // expected-error{{incompatible type}}
+ }
+ };
+
+ template<typename U>
+ struct Inner4;
+};
+
+template<typename T>
+template<typename U>
+struct X1<T>::Inner4 {
+ template<typename V>
+ V f2(T t, U u, V);
+
+ static U value;
+};
+
+template<typename T>
+template<typename U>
+U X1<T>::Inner4<U>::value; // expected-error{{reference variable}}
+
+template<typename T>
+template<typename U>
+template<typename V>
+V X1<T>::Inner4<U>::f2(T t, U u, V) {
+ return t + u; // expected-error{{incompatible type}}
+}
+
+void test_X1(int *ip, int i, double *dp) {
+ X1<void>::Inner0<int> *xvip; // okay
+ X1<void>::Inner0<int> xvi; // expected-note{{instantiation}}
+
+ X1<int>::Inner1<void> *xivp; // okay
+ X1<int>::Inner1<void> xiv; // expected-note{{instantiation}}
+
+ X1<int>::Inner2<void>::SuperInner *xisivp; // okay
+ X1<int>::Inner2<void>::SuperInner xisiv; // expected-note{{instantiation}}
+
+ X1<int*>::Inner3<int> id3;
+ id3.f0(ip, i);
+ id3.f0(dp, i); // expected-error{{incompatible type}}
+ id3.f1(ip, i, ip);
+ id3.f1(ip, i, dp); // expected-note{{instantiation}}
+
+ X1<int*>::Inner3<double*> id3b;
+ id3b.f0(ip, dp); // expected-note{{instantiation}}
+
+ X1<int*>::Inner4<int> id4;
+ id4.f2(ip, i, dp); // expected-note{{instantiation}}
+
+ X1<int*>::Inner4<int>::value = 17;
+ i = X1<int*>::Inner4<int&>::value; // expected-note{{instantiation}}
+}
diff --git a/test/SemaTemplate/instantiate-method.cpp b/test/SemaTemplate/instantiate-method.cpp
index daea746..f7c09ef 100644
--- a/test/SemaTemplate/instantiate-method.cpp
+++ b/test/SemaTemplate/instantiate-method.cpp
@@ -72,3 +72,12 @@ void test_converts_to(ConvertsTo<int> ci, ConvertsTo<int *> cip) {
int i = ci;
int *ip = cip;
}
+
+// PR4660
+template<class T> struct A0 { operator T*(); };
+template<class T> struct A1;
+
+int *a(A0<int> &x0, A1<int> &x1) {
+ int *y0 = x0;
+ int *y1 = x1; // expected-error{{initializing}}
+}
diff --git a/test/SemaTemplate/instantiate-static-var.cpp b/test/SemaTemplate/instantiate-static-var.cpp
index 99e6b9c..96fa34c 100644
--- a/test/SemaTemplate/instantiate-static-var.cpp
+++ b/test/SemaTemplate/instantiate-static-var.cpp
@@ -16,3 +16,25 @@ class Y {
};
Y<float> fy; // expected-note{{in instantiation of template class 'class Y<float>' requested here}}
+
+
+// out-of-line static member variables
+
+template<typename T>
+struct Z {
+ static T value;
+};
+
+template<typename T>
+T Z<T>::value; // expected-error{{no matching constructor}}
+
+struct DefCon {};
+
+struct NoDefCon {
+ NoDefCon(const NoDefCon&);
+};
+
+void test() {
+ DefCon &DC = Z<DefCon>::value;
+ NoDefCon &NDC = Z<NoDefCon>::value; // expected-note{{instantiation}}
+}
diff --git a/test/SemaTemplate/instantiate-typedef.cpp b/test/SemaTemplate/instantiate-typedef.cpp
index d30309c..e092b53 100644
--- a/test/SemaTemplate/instantiate-typedef.cpp
+++ b/test/SemaTemplate/instantiate-typedef.cpp
@@ -12,5 +12,5 @@ add_pointer<float>::type test2(int * ptr) {
}
add_pointer<int&>::type // expected-note{{in instantiation of template class 'struct add_pointer<int &>' requested here}} \
-// expected-error {{unknown type name 'type'}}
+// expected-error {{no type named 'type' in 'struct add_pointer<int &>'}}
test3();
diff --git a/test/SemaTemplate/instantiate-using-decl.cpp b/test/SemaTemplate/instantiate-using-decl.cpp
new file mode 100644
index 0000000..fd9010f
--- /dev/null
+++ b/test/SemaTemplate/instantiate-using-decl.cpp
@@ -0,0 +1,17 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T>
+struct A {
+ void f();
+};
+
+template<typename T>
+struct B : A<T> {
+ using A<T>::f;
+
+ void g() {
+ f();
+ }
+};
+
+template struct B<int>;
diff --git a/test/SemaTemplate/member-access-expr.cpp b/test/SemaTemplate/member-access-expr.cpp
new file mode 100644
index 0000000..f4922e8
--- /dev/null
+++ b/test/SemaTemplate/member-access-expr.cpp
@@ -0,0 +1,77 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+template<typename T>
+void call_f0(T x) {
+ x.Base::f0();
+}
+
+struct Base {
+ void f0();
+};
+
+struct X0 : Base {
+ typedef Base CrazyBase;
+};
+
+void test_f0(X0 x0) {
+ call_f0(x0);
+}
+
+template<typename TheBase, typename T>
+void call_f0_through_typedef(T x) {
+ typedef TheBase Base2;
+ x.Base2::f0();
+}
+
+void test_f0_through_typedef(X0 x0) {
+ call_f0_through_typedef<Base>(x0);
+}
+
+template<typename TheBase, typename T>
+void call_f0_through_typedef2(T x) {
+ typedef TheBase CrazyBase; // expected-note{{current scope}}
+ x.CrazyBase::f0(); // expected-error{{ambiguous}} \
+ // expected-error 2{{no member named}}
+}
+
+struct OtherBase { };
+
+struct X1 : Base, OtherBase {
+ typedef OtherBase CrazyBase; // expected-note{{object type}}
+};
+
+void test_f0_through_typedef2(X0 x0, X1 x1) {
+ call_f0_through_typedef2<Base>(x0);
+ call_f0_through_typedef2<OtherBase>(x1); // expected-note{{instantiation}}
+ call_f0_through_typedef2<Base>(x1); // expected-note{{instantiation}}
+}
+
+
+struct X2 {
+ operator int() const;
+};
+
+template<typename T, typename U>
+T convert(const U& value) {
+ return value.operator T(); // expected-error{{operator long}}
+}
+
+void test_convert(X2 x2) {
+ convert<int>(x2);
+ convert<long>(x2); // expected-note{{instantiation}}
+}
+
+template<typename T>
+void destruct(T* ptr) {
+ ptr->~T();
+}
+
+template<typename T>
+void destruct_intptr(int *ip) {
+ ip->~T();
+}
+
+void test_destruct(X2 *x2p, int *ip) {
+ destruct(x2p);
+ destruct(ip);
+ destruct_intptr<int>(ip);
+} \ No newline at end of file
diff --git a/test/SemaTemplate/member-function-template.cpp b/test/SemaTemplate/member-function-template.cpp
new file mode 100644
index 0000000..83bf16c
--- /dev/null
+++ b/test/SemaTemplate/member-function-template.cpp
@@ -0,0 +1,51 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+struct X {
+ template<typename T> T& f0(T);
+
+ void g0(int i, double d) {
+ int &ir = f0(i);
+ double &dr = f0(d);
+ }
+
+ template<typename T> T& f1(T);
+ template<typename T, typename U> U& f1(T, U);
+
+ void g1(int i, double d) {
+ int &ir1 = f1(i);
+ int &ir2 = f1(d, i);
+ int &ir3 = f1(i, i);
+ }
+};
+
+void test_X_f0(X x, int i, float f) {
+ int &ir = x.f0(i);
+ float &fr = x.f0(f);
+}
+
+void test_X_f1(X x, int i, float f) {
+ int &ir1 = x.f1(i);
+ int &ir2 = x.f1(f, i);
+ int &ir3 = x.f1(i, i);
+}
+
+void test_X_f0_address() {
+ int& (X::*pm1)(int) = &X::f0;
+ float& (X::*pm2)(float) = &X::f0;
+}
+
+void test_X_f1_address() {
+ int& (X::*pm1)(int) = &X::f1;
+ float& (X::*pm2)(float) = &X::f1;
+ int& (X::*pm3)(float, int) = &X::f1;
+}
+
+void test_X_f0_explicit(X x, int i, long l) {
+ int &ir1 = x.f0<int>(i);
+ int &ir2 = x.f0<>(i);
+ long &il1 = x.f0<long>(i);
+}
+
+// PR4608
+class A { template <class x> x a(x z) { return z+y; } int y; };
+
diff --git a/test/SemaTemplate/member-initializers.cpp b/test/SemaTemplate/member-initializers.cpp
new file mode 100644
index 0000000..62077fa
--- /dev/null
+++ b/test/SemaTemplate/member-initializers.cpp
@@ -0,0 +1,13 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T> struct A {
+ A() : j(10), i(10) { }
+
+ int i;
+ int j;
+};
+
+template<typename T> struct B : A<T> {
+ B() : A<T>() { }
+};
+
diff --git a/test/SemaTemplate/member-template-access-expr.cpp b/test/SemaTemplate/member-template-access-expr.cpp
new file mode 100644
index 0000000..20437ae
--- /dev/null
+++ b/test/SemaTemplate/member-template-access-expr.cpp
@@ -0,0 +1,30 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename U, typename T>
+U f0(T t) {
+ return t.template get<U>();
+}
+
+template<typename U, typename T>
+int &f1(T t) {
+ // FIXME: When we pretty-print this, we lose the "template" keyword.
+ return t.U::template get<int&>();
+}
+
+struct X {
+ template<typename T> T get();
+};
+
+void test_f0(X x) {
+ int i = f0<int>(x);
+ int &ir = f0<int&>(x);
+}
+
+struct XDerived : public X {
+};
+
+void test_f1(XDerived xd) {
+ // FIXME: Not quite functional yet.
+// int &ir = f1<X>(xd);
+}
+
diff --git a/test/SemaTemplate/metafun-apply.cpp b/test/SemaTemplate/metafun-apply.cpp
index 9261ed6..471b2ad 100644
--- a/test/SemaTemplate/metafun-apply.cpp
+++ b/test/SemaTemplate/metafun-apply.cpp
@@ -35,7 +35,8 @@ 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}}
+ 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-linkage.cpp b/test/SemaTemplate/nested-linkage.cpp
new file mode 100644
index 0000000..ffe9adc
--- /dev/null
+++ b/test/SemaTemplate/nested-linkage.cpp
@@ -0,0 +1,3 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+extern "C" { extern "C++" { template<class C> C x(); } }
diff --git a/test/SemaTemplate/nested-template.cpp b/test/SemaTemplate/nested-template.cpp
index 84b1d35..5ee2c99 100644
--- a/test/SemaTemplate/nested-template.cpp
+++ b/test/SemaTemplate/nested-template.cpp
@@ -1,5 +1,4 @@
// RUN: clang-cc -fsyntax-only -verify %s
-
class A;
class S {
@@ -14,3 +13,91 @@ public:
int i;
S::A<int>::Nested::type *ip = &i;
+template<typename T>
+struct Outer {
+ template<typename U>
+ class Inner0;
+
+ template<typename U>
+ class Inner1 {
+ struct ReallyInner;
+
+ T foo(U);
+ template<typename V> T bar(V);
+ template<typename V> T* bar(V);
+
+ static T value1;
+ static U value2;
+ };
+};
+
+template<typename X>
+template<typename Y>
+class Outer<X>::Inner0 {
+public:
+ void f(X, Y);
+};
+
+template<typename X>
+template<typename Y>
+void Outer<X>::Inner0<Y>::f(X, Y) {
+}
+
+template<typename X>
+template<typename Y>
+struct Outer<X>::Inner1<Y>::ReallyInner {
+ static Y value3;
+
+ void g(X, Y);
+};
+
+template<typename X>
+template<typename Y>
+void Outer<X>::Inner1<Y>::ReallyInner::g(X, Y) {
+}
+
+template<typename X>
+template<typename Y>
+X Outer<X>::Inner1<Y>::foo(Y) {
+ return X();
+}
+
+template<typename X>
+template<typename Y>
+template<typename Z>
+X Outer<X>::Inner1<Y>::bar(Z) {
+ return X();
+}
+
+template<typename X>
+template<typename Y>
+template<typename Z>
+X* Outer<X>::Inner1<Y>::bar(Z) {
+ return 0;
+}
+
+template<typename X>
+template<typename Y>
+X Outer<X>::Inner1<Y>::value1 = 0;
+
+template<typename X>
+template<typename Y>
+Y Outer<X>::Inner1<Y>::value2 = Y();
+
+template<typename X>
+template<typename Y>
+Y Outer<X>::Inner1<Y>::ReallyInner::value3 = Y();
+
+template<typename X>
+template<typename Y>
+Y Outer<X>::Inner1<Y*>::ReallyInner::value4; // expected-error{{Outer<X>::Inner1<Y *>::ReallyInner::}}
+
+
+template<typename T>
+struct X0 { };
+
+template<typename T>
+struct X0<T*> {
+ template<typename U>
+ void f(U u = T()) { }
+};
diff --git a/test/SemaTemplate/partial-spec-instantiate.cpp b/test/SemaTemplate/partial-spec-instantiate.cpp
new file mode 100644
index 0000000..8d1ae23
--- /dev/null
+++ b/test/SemaTemplate/partial-spec-instantiate.cpp
@@ -0,0 +1,20 @@
+// RUN: clang-cc -fsyntax-only %s
+
+// PR4607
+template <class T> struct X {};
+
+template <> struct X<char>
+{
+ static char* g();
+};
+
+template <class T> struct X2 {};
+
+template <class U>
+struct X2<U*> {
+ static void f() {
+ X<U>::g();
+ }
+};
+
+void a(char *a, char *b) {X2<char*>::f();}
diff --git a/test/SemaTemplate/qualified-id.cpp b/test/SemaTemplate/qualified-id.cpp
new file mode 100644
index 0000000..85efab2
--- /dev/null
+++ b/test/SemaTemplate/qualified-id.cpp
@@ -0,0 +1,9 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// PR5061
+namespace a {
+ template <typename T> class C {};
+}
+namespace b {
+ template<typename T> void f0(a::C<T> &a0) { }
+}
diff --git a/test/SemaTemplate/qualified-names-diag.cpp b/test/SemaTemplate/qualified-names-diag.cpp
index c875332..1d53e5c 100644
--- a/test/SemaTemplate/qualified-names-diag.cpp
+++ b/test/SemaTemplate/qualified-names-diag.cpp
@@ -1,7 +1,7 @@
// RUN: clang-cc -fsyntax-only -verify %s
namespace std {
- template<typename T> class vector { };
+ template<typename T> class vector { }; // expected-note{{candidate}}
}
typedef int INT;
diff --git a/test/SemaTemplate/temp_class_order.cpp b/test/SemaTemplate/temp_class_order.cpp
new file mode 100644
index 0000000..4687ddf
--- /dev/null
+++ b/test/SemaTemplate/temp_class_order.cpp
@@ -0,0 +1,42 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T, typename U>
+struct X1 {
+ static const int value = 0;
+};
+
+template<typename T, typename U>
+struct X1<T*, U*> {
+ static const int value = 1;
+};
+
+template<typename T>
+struct X1<T*, T*> {
+ static const int value = 2;
+};
+
+template<typename T>
+struct X1<const T*, const T*> {
+ static const int value = 3;
+};
+
+int array0[X1<int, int>::value == 0? 1 : -1];
+int array1[X1<int*, float*>::value == 1? 1 : -1];
+int array2[X1<int*, int*>::value == 2? 1 : -1];
+typedef const int* CIP;
+int array3[X1<const int*, CIP>::value == 3? 1 : -1];
+
+template<typename T, typename U>
+struct X2 { };
+
+template<typename T, typename U>
+struct X2<T*, U> { }; // expected-note{{matches}}
+
+template<typename T, typename U>
+struct X2<T, U*> { }; // expected-note{{matches}}
+
+template<typename T, typename U>
+struct X2<const T*, const U*> { };
+
+X2<int*, int*> x2a; // expected-error{{ambiguous}}
+X2<const int*, const int*> x2b;
diff --git a/test/SemaTemplate/temp_class_spec.cpp b/test/SemaTemplate/temp_class_spec.cpp
index 1a53423..dad857e 100644
--- a/test/SemaTemplate/temp_class_spec.cpp
+++ b/test/SemaTemplate/temp_class_spec.cpp
@@ -16,8 +16,7 @@ struct is_pointer<const T*> {
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}}
+int array2[is_pointer<const int*>::value? 1 : -1];
template<typename T>
struct is_lvalue_reference {
@@ -32,6 +31,38 @@ struct is_lvalue_reference<T&> {
int lvalue_ref0[is_lvalue_reference<int>::value? -1 : 1];
int lvalue_ref1[is_lvalue_reference<const int&>::value? 1 : -1];
+template<typename T>
+struct is_const {
+ static const bool value = false;
+};
+
+template<typename T>
+struct is_const<const T> {
+ static const bool value = true;
+};
+
+int is_const0[is_const<int>::value? -1 : 1];
+int is_const1[is_const<const int>::value? 1 : -1];
+int is_const2[is_const<const volatile int>::value? 1 : -1];
+int is_const3[is_const<const int [3]>::value? 1 : -1];
+int is_const4[is_const<const volatile int[3]>::value? 1 : -1];
+int is_const5[is_const<volatile int[3]>::value? -1 : 1];
+
+template<typename T>
+struct is_volatile {
+ static const bool value = false;
+};
+
+template<typename T>
+struct is_volatile<volatile T> {
+ static const bool value = true;
+};
+
+int is_volatile0[is_volatile<int>::value? -1 : 1];
+int is_volatile1[is_volatile<volatile int>::value? 1 : -1];
+int is_volatile2[is_volatile<const volatile int>::value? 1 : -1];
+int is_volatile3[is_volatile<volatile char[3]>::value? 1 : -1];
+
template<typename T, typename U>
struct is_same {
static const bool value = false;
@@ -62,7 +93,20 @@ struct remove_reference<T&> {
int remove_ref0[is_same<remove_reference<int>::type, int>::value? 1 : -1];
int remove_ref1[is_same<remove_reference<int&>::type, int>::value? 1 : -1];
-
+
+template<typename T>
+struct remove_const {
+ typedef T type;
+};
+
+template<typename T>
+struct remove_const<const T> {
+ typedef T type;
+};
+
+int remove_const0[is_same<remove_const<const int>::type, int>::value? 1 : -1];
+int remove_const1[is_same<remove_const<const int[3]>::type, int[3]>::value? 1 : -1];
+
template<typename T>
struct is_incomplete_array {
static const bool value = false;
@@ -104,6 +148,24 @@ struct get_array_size<T[N]> {
int array_size0[get_array_size<int[12]>::value == 12? 1 : -1];
template<typename T>
+struct remove_extent {
+ typedef T type;
+};
+
+template<typename T>
+struct remove_extent<T[]> {
+ typedef T type;
+};
+
+template<typename T, unsigned N>
+struct remove_extent<T[N]> {
+ typedef T type;
+};
+
+int remove_extent0[is_same<remove_extent<int[][5]>::type, int[5]>::value? 1 : -1];
+int remove_extent1[is_same<remove_extent<const int[][5]>::type, const int[5]>::value? 1 : -1];
+
+template<typename T>
struct is_unary_function {
static const bool value = false;
};
@@ -261,3 +323,10 @@ template<class T, int I> class A<T, T*, I> { }; //#2
template<class T1, class T2, int I> class A<T1*, T2, I> { }; //#3
template<class T> class A<int, T*, 5> { }; //#4
template<class T1, class T2, int I> class A<T1, T2*, I> { }; //#5
+
+// Redefinition of class template partial specializations
+template<typename T, T N, typename U> class A0;
+
+template<typename T, T N> class A0<T, N, int> { }; // expected-note{{here}}
+template<typename T, T N> class A0<T, N, int>;
+template<typename T, T N> class A0<T, N, int> { }; // expected-error{{redef}}
diff --git a/test/SemaTemplate/temp_class_spec_neg.cpp b/test/SemaTemplate/temp_class_spec_neg.cpp
index b50bd8f..a029f47 100644
--- a/test/SemaTemplate/temp_class_spec_neg.cpp
+++ b/test/SemaTemplate/temp_class_spec_neg.cpp
@@ -9,7 +9,7 @@ namespace N {
}
template<typename T>
-struct N::M::A<T*> { }; // expected-error{{not in namespace}}
+struct N::M::A<T*> { }; // expected-error{{originally}}
// C++ [temp.class.spec]p9
// bullet 1
@@ -25,7 +25,7 @@ template <class T, T* t> struct C<T*, t>; // okay
template< int X, int (*array_ptr)[X] > class A2 {}; // expected-note{{here}}
int array[5];
-template< int X > class A2<X,&array> { }; // expected-error{{specializes}}
+template< int X > class A2<X, &array> { }; // expected-error{{specializes}}
template<typename T, int N, template<typename X> class TT>
struct Test0;
diff --git a/test/SemaTemplate/temp_func_order.cpp b/test/SemaTemplate/temp_func_order.cpp
new file mode 100644
index 0000000..5fd7c8d
--- /dev/null
+++ b/test/SemaTemplate/temp_func_order.cpp
@@ -0,0 +1,95 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+template<typename T>
+int &f0(T);
+
+template<typename T>
+float &f0(T*);
+
+void test_f0(int i, int *ip) {
+ int &ir = f0(i);
+ float &fr = f0(ip);
+}
+
+template<typename T, typename U>
+int &f1(T, U);
+
+template<typename T>
+float &f1(T, T);
+
+void test_f1(int i, float f) {
+ int &ir = f1(i, f);
+ float &fr1 = f1(i, i);
+ float &fr2 = f1(f, f);
+}
+
+template<typename T, typename U>
+struct A { };
+
+template<typename T>
+int &f2(T);
+
+template<typename T, typename U>
+float &f2(A<T, U>);
+
+template<typename T>
+double &f2(A<T, T>);
+
+void test_f2(int i, A<int, float> aif, A<int, int> aii) {
+ int &ir = f2(i);
+ float &fr = f2(aif);
+ double &dr = f2(aii);
+}
+
+template<typename T, typename U>
+int &f3(T*, U); // expected-note{{candidate}}
+
+template<typename T, typename U>
+float &f3(T, U*); // expected-note{{candidate}}
+
+void test_f3(int i, int *ip, float *fp) {
+ int &ir = f3(ip, i);
+ float &fr = f3(i, fp);
+ f3(ip, ip); // expected-error{{ambiguous}}
+}
+
+template<typename T>
+int &f4(T&);
+
+template<typename T>
+float &f4(const T&);
+
+void test_f4(int i, const int ic) {
+ int &ir1 = f4(i);
+ float &fr1 = f4(ic);
+}
+
+template<typename T, typename U>
+int &f5(T&, const U&); // expected-note{{candidate}}
+
+template<typename T, typename U>
+float &f5(const T&, U&); // expected-note{{candidate}}
+
+void test_f5(int i, const int ic) {
+ f5(i, i); // expected-error{{ambiguous}}
+}
+
+template<typename T, typename U>
+int &f6(T&, U&);
+
+template<typename T, typename U>
+float &f6(const T&, U&);
+
+void test_f6(int i, const int ic) {
+ int &ir = f6(i, i);
+ float &fr = f6(ic, ic);
+}
+
+struct CrazyFun {
+ template<typename T, typename U> operator A<T, U>();
+ template<typename T> operator A<T, T>();
+};
+
+void fun(CrazyFun cf) {
+ A<int, float> aif = cf;
+ A<int, int> aii = cf;
+}
diff --git a/test/SemaTemplate/typename-specifier-4.cpp b/test/SemaTemplate/typename-specifier-4.cpp
new file mode 100644
index 0000000..c7484c1
--- /dev/null
+++ b/test/SemaTemplate/typename-specifier-4.cpp
@@ -0,0 +1,70 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+template<typename T, typename U>
+struct is_same {
+ static const bool value = false;
+};
+
+template<typename T>
+struct is_same<T, T> {
+ static const bool value = true;
+};
+
+template<typename MetaFun, typename T1, typename T2>
+struct metafun_apply2 {
+ typedef typename MetaFun::template apply<T1, T2> inner;
+ typedef typename inner::type type;
+};
+
+template<typename T, typename U> struct pair;
+
+struct make_pair {
+ template<typename T1, typename T2>
+ struct apply {
+ typedef pair<T1, T2> type;
+ };
+};
+
+int a0[is_same<metafun_apply2<make_pair, int, float>::type,
+ pair<int, float> >::value? 1 : -1];
+int a1[is_same<
+ typename make_pair::template apply<int, float>,
+ make_pair::apply<int, float>
+ >::value? 1 : -1];
+
+template<typename MetaFun>
+struct swap_and_apply2 {
+ template<typename T1, typename T2>
+ struct apply {
+ typedef typename MetaFun::template apply<T2, T1> new_metafun;
+ typedef typename new_metafun::type type;
+ };
+};
+
+int a2[is_same<swap_and_apply2<make_pair>::apply<int, float>::type,
+ pair<float, int> >::value? 1 : -1];
+
+template<typename MetaFun>
+struct swap_and_apply2b {
+ template<typename T1, typename T2>
+ struct apply {
+ typedef typename MetaFun::template apply<T2, T1>::type type;
+ };
+};
+
+int a3[is_same<swap_and_apply2b<make_pair>::apply<int, float>::type,
+ pair<float, int> >::value? 1 : -1];
+
+template<typename T>
+struct X0 {
+ template<typename U, typename V>
+ struct Inner;
+
+ void f0(X0<T>::Inner<T*, T&>); // expected-note{{here}}
+ void f0(typename X0<T>::Inner<T*, T&>); // expected-error{{redecl}}
+
+ void f1(X0<T>::Inner<T*, T&>); // expected-note{{here}}
+ void f1(typename X0<T>::template Inner<T*, T&>); // expected-error{{redecl}}
+
+ void f2(typename X0<T>::Inner<T*, T&>::type); // expected-note{{here}}
+ void f2(typename X0<T>::template Inner<T*, T&>::type); // expected-error{{redecl}}
+};
diff --git a/test/SemaTemplate/typename-specifier.cpp b/test/SemaTemplate/typename-specifier.cpp
index d3fca3e..2501b8d 100644
--- a/test/SemaTemplate/typename-specifier.cpp
+++ b/test/SemaTemplate/typename-specifier.cpp
@@ -16,7 +16,7 @@ namespace N {
int i;
typename N::A::type *ip1 = &i;
-typename N::B::type *ip2 = &i; // expected-error{{ no type named 'type' in 'B'}}
+typename N::B::type *ip2 = &i; // expected-error{{no type named 'type' in 'struct N::B'}}
typename N::C::type *ip3 = &i; // expected-error{{typename specifier refers to non-type member 'type'}}
void test(double d) {
@@ -33,7 +33,8 @@ void test(double d) {
namespace N {
template<typename T>
struct X {
- typedef typename T::type type; // expected-error 2{{no type named 'type' in 'B'}} \
+ typedef typename T::type type; // expected-error {{no type named 'type' in 'struct N::B'}} \
+ // expected-error {{no type named 'type' in 'struct 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}}
@@ -42,12 +43,12 @@ namespace N {
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'}}
+// expected-error{{no type named 'type' in}}
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'}}
+// expected-error{{no type named 'type' in}}
N::X<int>::type fail1; // expected-note{{in instantiation of template class 'struct N::X<int>' requested here}} \
-// expected-error{{unknown type name 'type'}}
+// expected-error{{no type named 'type' in}}
template<typename T>
struct Y {
@@ -69,6 +70,6 @@ struct C {
::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'}}
+// expected-error{{no type named 'type' in}}
::Y<C>::type ip9 = &i; // expected-note{{in instantiation of template class 'struct Y<struct C>' requested here}} \
-// expected-error{{unknown type name 'type'}}
+// expected-error{{no type named 'type' in}}
diff --git a/test/SemaTemplate/value-dependent-null-pointer-constant.cpp b/test/SemaTemplate/value-dependent-null-pointer-constant.cpp
new file mode 100644
index 0000000..8bde127
--- /dev/null
+++ b/test/SemaTemplate/value-dependent-null-pointer-constant.cpp
@@ -0,0 +1,29 @@
+// RUN: clang-cc -fsyntax-only %s
+
+template<typename T, int N>
+struct X0 {
+ const char *f0(bool Cond) {
+ return Cond? "honk" : N;
+ }
+
+ const char *f1(bool Cond) {
+ return Cond? N : "honk";
+ }
+
+ bool f2(const char *str) {
+ return str == N;
+ }
+};
+
+// PR4996
+template<unsigned I> int f0() {
+ return __builtin_choose_expr(I, 0, 1);
+}
+
+// PR5041
+struct A { };
+
+template <typename T> void f(T *t)
+{
+ (void)static_cast<void*>(static_cast<A*>(t));
+} \ No newline at end of file
diff --git a/test/TestRunner.sh b/test/TestRunner.sh
index bb20728..f96d3d5 100755
--- a/test/TestRunner.sh
+++ b/test/TestRunner.sh
@@ -1,134 +1,13 @@
#!/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=$?
+# TestRunner.sh - Backward compatible utility for testing an individual file.
-if [ -n "$VG" ]; then
- [ ! -s $OUTPUT.vg ]
- VG_STATUS=$?
-else
- VG_STATUS=0
-fi
+# Find where this script is.
+Dir=$(dirname $(which $0))
+AbsDir=$(cd $Dir; pwd)
-if [ $IS_XFAIL -ne 0 ]; then
- if [ $SCRIPT_STATUS -ne 0 ]; then
- SCRIPT_STATUS=0
- else
- SCRIPT_STATUS=1
- fi
-fi
+# Find 'lit', assuming standard layout.
+lit=$AbsDir/../../../utils/lit/lit.py
-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
+# Dispatch to lit.
+$lit "$@"
diff --git a/test/lit.cfg b/test/lit.cfg
new file mode 100644
index 0000000..60d8df0
--- /dev/null
+++ b/test/lit.cfg
@@ -0,0 +1,152 @@
+# -*- Python -*-
+
+import os
+import platform
+
+# Configuration file for the 'lit' test runner.
+
+# name: The name of this test suite.
+config.name = 'Clang'
+
+# testFormat: The test format to use to interpret tests.
+#
+# For now we require '&&' between commands, until they get globally killed and
+# the test runner updated.
+execute_external = platform.system() != 'Windows'
+config.test_format = lit.formats.ShTest(execute_external,
+ require_and_and = True)
+
+# suffixes: A list of file extensions to treat as test files.
+config.suffixes = ['.c', '.cpp', '.m', '.mm']
+
+# test_source_root: The root path where tests are located.
+config.test_source_root = os.path.dirname(__file__)
+
+# test_exec_root: The root path where tests should be run.
+clang_obj_root = getattr(config, 'clang_obj_root', None)
+if clang_obj_root is not None:
+ config.test_exec_root = os.path.join(clang_obj_root, 'test')
+
+# Set llvm_{src,obj}_root for use by others.
+config.llvm_src_root = getattr(config, 'llvm_src_root', None)
+config.llvm_obj_root = getattr(config, 'llvm_obj_root', None)
+
+# Tweak the PATH to include the tools dir and the scripts dir.
+if clang_obj_root is not None:
+ llvm_tools_dir = getattr(config, 'llvm_tools_dir', None)
+ if not llvm_tools_dir:
+ lit.fatal('No LLVM tools dir set!')
+ path = os.path.pathsep.join((llvm_tools_dir, config.environment['PATH']))
+ config.environment['PATH'] = path
+
+ llvm_libs_dir = getattr(config, 'llvm_libs_dir', None)
+ if not llvm_libs_dir:
+ lit.fatal('No LLVM libs dir set!')
+ path = os.path.pathsep.join((llvm_libs_dir,
+ config.environment.get('LD_LIBRARY_PATH','')))
+ config.environment['LD_LIBRARY_PATH'] = path
+
+###
+
+# Check that the object root is known.
+if config.test_exec_root is None:
+ # Otherwise, we haven't loaded the site specific configuration (the user is
+ # probably trying to run on a test file directly, and either the site
+ # configuration hasn't been created by the build system, or we are in an
+ # out-of-tree build situation).
+
+ # Try to detect the situation where we are using an out-of-tree build by
+ # looking for 'llvm-config'.
+ #
+ # FIXME: I debated (i.e., wrote and threw away) adding logic to
+ # automagically generate the lit.site.cfg if we are in some kind of fresh
+ # build situation. This means knowing how to invoke the build system
+ # though, and I decided it was too much magic.
+
+ llvm_config = lit.util.which('llvm-config', config.environment['PATH'])
+ if not llvm_config:
+ lit.fatal('No site specific configuration available!')
+
+ # Get the source and object roots.
+ llvm_src_root = lit.util.capture(['llvm-config', '--src-root']).strip()
+ llvm_obj_root = lit.util.capture(['llvm-config', '--obj-root']).strip()
+ clang_src_root = os.path.join(llvm_src_root, "tools", "clang")
+ clang_obj_root = os.path.join(llvm_obj_root, "tools", "clang")
+
+ # Validate that we got a tree which points to here, using the standard
+ # tools/clang layout.
+ this_src_root = os.path.dirname(config.test_source_root)
+ if os.path.realpath(clang_src_root) != os.path.realpath(this_src_root):
+ lit.fatal('No site specific configuration available!')
+
+ # Check that the site specific configuration exists.
+ site_cfg = os.path.join(clang_obj_root, 'test', 'lit.site.cfg')
+ if not os.path.exists(site_cfg):
+ lit.fatal('No site specific configuration available!')
+
+ # Okay, that worked. Notify the user of the automagic, and reconfigure.
+ lit.note('using out-of-tree build at %r' % clang_obj_root)
+ lit.load_config(config, site_cfg)
+ raise SystemExit
+
+###
+
+# Discover the 'clang' and 'clangcc' to use.
+
+import os
+
+def inferClang(PATH):
+ # Determine which clang to use.
+ clang = os.getenv('CLANG')
+
+ # If the user set clang in the environment, definitely use that and don't
+ # try to validate.
+ if clang:
+ return clang
+
+ # Otherwise look in the path.
+ clang = lit.util.which('clang', PATH)
+
+ if not clang:
+ lit.fatal("couldn't find 'clang' program, try setting "
+ "CLANG in your environment")
+
+ return clang
+
+def inferClangCC(clang, PATH):
+ clangcc = os.getenv('CLANGCC')
+
+ # If the user set clang in the environment, definitely use that and don't
+ # try to validate.
+ if clangcc:
+ return clangcc
+
+ # Otherwise try adding -cc since we expect to be looking in a build
+ # directory.
+ if clang.endswith('.exe'):
+ clangccName = clang[:-4] + '-cc.exe'
+ else:
+ clangccName = clang + '-cc'
+ clangcc = lit.util.which(clangccName, PATH)
+ if not clangcc:
+ # Otherwise ask clang.
+ res = lit.util.capture([clang, '-print-prog-name=clang-cc'])
+ res = res.strip()
+ if res and os.path.exists(res):
+ clangcc = res
+
+ if not clangcc:
+ lit.fatal("couldn't find 'clang-cc' program, try setting "
+ "CLANGCC in your environment")
+
+ return clangcc
+
+config.clang = inferClang(config.environment['PATH'])
+if not lit.quiet:
+ lit.note('using clang: %r' % config.clang)
+config.substitutions.append( (' clang ', ' ' + config.clang + ' ') )
+
+config.clang_cc = inferClangCC(config.clang, config.environment['PATH'])
+if not lit.quiet:
+ lit.note('using clang-cc: %r' % config.clang_cc)
+config.substitutions.append( (' clang-cc ', ' ' + config.clang_cc + ' ') )
diff --git a/test/lit.site.cfg.in b/test/lit.site.cfg.in
new file mode 100644
index 0000000..9dabafc
--- /dev/null
+++ b/test/lit.site.cfg.in
@@ -0,0 +1,10 @@
+## Autogenerated by LLVM/Clang configuration.
+# Do not edit!
+config.llvm_src_root = "@LLVM_SOURCE_DIR@"
+config.llvm_obj_root = "@LLVM_BINARY_DIR@"
+config.llvm_tools_dir = "@LLVM_TOOLS_DIR@"
+config.llvm_libs_dir = "@LLVM_LIBS_DIR@"
+config.clang_obj_root = "@CLANG_BINARY_DIR@"
+
+# Let the main config do the real work.
+lit.load_config(config, "@CLANG_SOURCE_DIR@/test/lit.cfg")
diff --git a/tools/CIndex/CIndex.cpp b/tools/CIndex/CIndex.cpp
new file mode 100644
index 0000000..9204d18
--- /dev/null
+++ b/tools/CIndex/CIndex.cpp
@@ -0,0 +1,745 @@
+//===- CIndex.cpp - Clang-C Source Indexing Library -----------------------===//
+//
+// 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-C Source Indexing library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang-c/Index.h"
+#include "clang/Index/Program.h"
+#include "clang/Index/Indexer.h"
+#include "clang/Index/ASTLocation.h"
+#include "clang/Index/Utils.h"
+#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/Decl.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Frontend/ASTUnit.h"
+#include <cstdio>
+using namespace clang;
+using namespace idx;
+
+namespace {
+
+static enum CXCursorKind TranslateDeclRefExpr(DeclRefExpr *DRE)
+{
+ NamedDecl *D = DRE->getDecl();
+ if (isa<VarDecl>(D))
+ return CXCursor_VarRef;
+ else if (isa<FunctionDecl>(D))
+ return CXCursor_FunctionRef;
+ else if (isa<EnumConstantDecl>(D))
+ return CXCursor_EnumConstantRef;
+ else
+ return CXCursor_NotImplemented;
+}
+
+#if 0
+// Will be useful one day.
+class CRefVisitor : public StmtVisitor<CRefVisitor> {
+ CXDecl CDecl;
+ CXDeclIterator Callback;
+ CXClientData CData;
+
+ void Call(enum CXCursorKind CK, Stmt *SRef) {
+ CXCursor C = { CK, CDecl, SRef };
+ Callback(CDecl, C, CData);
+ }
+
+public:
+ CRefVisitor(CXDecl C, CXDeclIterator cback, CXClientData D) :
+ CDecl(C), Callback(cback), CData(D) {}
+
+ void VisitStmt(Stmt *S) {
+ for (Stmt::child_iterator C = S->child_begin(), CEnd = S->child_end();
+ C != CEnd; ++C)
+ Visit(*C);
+ }
+ void VisitDeclRefExpr(DeclRefExpr *Node) {
+ Call(TranslateDeclRefExpr(Node), Node);
+ }
+ void VisitMemberExpr(MemberExpr *Node) {
+ Call(CXCursor_MemberRef, Node);
+ }
+ void VisitObjCMessageExpr(ObjCMessageExpr *Node) {
+ Call(CXCursor_ObjCSelectorRef, Node);
+ }
+ void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) {
+ Call(CXCursor_ObjCIvarRef, Node);
+ }
+};
+#endif
+
+// Translation Unit Visitor.
+class TUVisitor : public DeclVisitor<TUVisitor> {
+ CXTranslationUnit TUnit;
+ CXTranslationUnitIterator Callback;
+ CXClientData CData;
+
+ void Call(enum CXCursorKind CK, NamedDecl *ND) {
+ CXCursor C = { CK, ND, 0 };
+ Callback(TUnit, C, CData);
+ }
+public:
+ TUVisitor(CXTranslationUnit CTU,
+ CXTranslationUnitIterator cback, CXClientData D) :
+ TUnit(CTU), Callback(cback), CData(D) {}
+
+ void VisitTranslationUnitDecl(TranslationUnitDecl *D) {
+ VisitDeclContext(dyn_cast<DeclContext>(D));
+ }
+ void VisitDeclContext(DeclContext *DC) {
+ for (DeclContext::decl_iterator
+ I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I)
+ Visit(*I);
+ }
+ void VisitTypedefDecl(TypedefDecl *ND) {
+ Call(CXCursor_TypedefDecl, ND);
+ }
+ void VisitTagDecl(TagDecl *ND) {
+ switch (ND->getTagKind()) {
+ case TagDecl::TK_struct:
+ Call(CXCursor_StructDecl, ND);
+ break;
+ case TagDecl::TK_class:
+ Call(CXCursor_ClassDecl, ND);
+ break;
+ case TagDecl::TK_union:
+ Call(CXCursor_UnionDecl, ND);
+ break;
+ case TagDecl::TK_enum:
+ Call(CXCursor_EnumDecl, ND);
+ break;
+ }
+ }
+ void VisitVarDecl(VarDecl *ND) {
+ Call(CXCursor_VarDecl, ND);
+ }
+ void VisitFunctionDecl(FunctionDecl *ND) {
+ Call(ND->isThisDeclarationADefinition() ? CXCursor_FunctionDefn
+ : CXCursor_FunctionDecl, ND);
+ }
+ void VisitObjCInterfaceDecl(ObjCInterfaceDecl *ND) {
+ Call(CXCursor_ObjCInterfaceDecl, ND);
+ }
+ void VisitObjCCategoryDecl(ObjCCategoryDecl *ND) {
+ Call(CXCursor_ObjCCategoryDecl, ND);
+ }
+ void VisitObjCProtocolDecl(ObjCProtocolDecl *ND) {
+ Call(CXCursor_ObjCProtocolDecl, ND);
+ }
+ void VisitObjCImplementationDecl(ObjCImplementationDecl *ND) {
+ Call(CXCursor_ObjCClassDefn, ND);
+ }
+ void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *ND) {
+ Call(CXCursor_ObjCCategoryDefn, ND);
+ }
+};
+
+// Declaration visitor.
+class CDeclVisitor : public DeclVisitor<CDeclVisitor> {
+ CXDecl CDecl;
+ CXDeclIterator Callback;
+ CXClientData CData;
+
+ void Call(enum CXCursorKind CK, NamedDecl *ND) {
+ // Disable the callback when the context is equal to the visiting decl.
+ if (CDecl == ND && !clang_isReference(CK))
+ return;
+ CXCursor C = { CK, ND, 0 };
+ Callback(CDecl, C, CData);
+ }
+public:
+ CDeclVisitor(CXDecl C, CXDeclIterator cback, CXClientData D) :
+ CDecl(C), Callback(cback), CData(D) {}
+
+ void VisitObjCCategoryDecl(ObjCCategoryDecl *ND) {
+ // Issue callbacks for the containing class.
+ Call(CXCursor_ObjCClassRef, ND);
+ // FIXME: Issue callbacks for protocol refs.
+ VisitDeclContext(dyn_cast<DeclContext>(ND));
+ }
+ void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
+ // Issue callbacks for super class.
+ if (D->getSuperClass())
+ Call(CXCursor_ObjCSuperClassRef, D);
+
+ for (ObjCProtocolDecl::protocol_iterator I = D->protocol_begin(),
+ E = D->protocol_end(); I != E; ++I)
+ Call(CXCursor_ObjCProtocolRef, *I);
+ VisitDeclContext(dyn_cast<DeclContext>(D));
+ }
+ void VisitObjCProtocolDecl(ObjCProtocolDecl *PID) {
+ for (ObjCProtocolDecl::protocol_iterator I = PID->protocol_begin(),
+ E = PID->protocol_end(); I != E; ++I)
+ Call(CXCursor_ObjCProtocolRef, *I);
+
+ VisitDeclContext(dyn_cast<DeclContext>(PID));
+ }
+ void VisitTagDecl(TagDecl *D) {
+ VisitDeclContext(dyn_cast<DeclContext>(D));
+ }
+ void VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
+ VisitDeclContext(dyn_cast<DeclContext>(D));
+ }
+ void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
+ VisitDeclContext(dyn_cast<DeclContext>(D));
+ }
+ void VisitDeclContext(DeclContext *DC) {
+ for (DeclContext::decl_iterator
+ I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I)
+ Visit(*I);
+ }
+ void VisitEnumConstantDecl(EnumConstantDecl *ND) {
+ Call(CXCursor_EnumConstantDecl, ND);
+ }
+ void VisitFieldDecl(FieldDecl *ND) {
+ Call(CXCursor_FieldDecl, ND);
+ }
+ void VisitVarDecl(VarDecl *ND) {
+ Call(CXCursor_VarDecl, ND);
+ }
+ void VisitParmVarDecl(ParmVarDecl *ND) {
+ Call(CXCursor_ParmDecl, ND);
+ }
+ void VisitObjCPropertyDecl(ObjCPropertyDecl *ND) {
+ Call(CXCursor_ObjCPropertyDecl, ND);
+ }
+ void VisitObjCIvarDecl(ObjCIvarDecl *ND) {
+ Call(CXCursor_ObjCIvarDecl, ND);
+ }
+ void VisitFunctionDecl(FunctionDecl *ND) {
+ if (ND->isThisDeclarationADefinition()) {
+ VisitDeclContext(dyn_cast<DeclContext>(ND));
+#if 0
+ // Not currently needed.
+ CompoundStmt *Body = dyn_cast<CompoundStmt>(ND->getBody());
+ CRefVisitor RVisit(CDecl, Callback, CData);
+ RVisit.Visit(Body);
+#endif
+ }
+ }
+ void VisitObjCMethodDecl(ObjCMethodDecl *ND) {
+ if (ND->getBody()) {
+ Call(ND->isInstanceMethod() ? CXCursor_ObjCInstanceMethodDefn
+ : CXCursor_ObjCClassMethodDefn, ND);
+ VisitDeclContext(dyn_cast<DeclContext>(ND));
+ } else
+ Call(ND->isInstanceMethod() ? CXCursor_ObjCInstanceMethodDecl
+ : CXCursor_ObjCClassMethodDecl, ND);
+ }
+};
+
+}
+
+extern "C" {
+
+CXIndex clang_createIndex()
+{
+ // FIXME: Program is leaked.
+ return new Indexer(*new Program());
+}
+
+void clang_disposeIndex(CXIndex CIdx)
+{
+ assert(CIdx && "Passed null CXIndex");
+ delete static_cast<Indexer *>(CIdx);
+}
+
+// FIXME: need to pass back error info.
+CXTranslationUnit clang_createTranslationUnit(
+ CXIndex CIdx, const char *ast_filename)
+{
+ assert(CIdx && "Passed null CXIndex");
+ Indexer *CXXIdx = static_cast<Indexer *>(CIdx);
+ std::string astName(ast_filename);
+ std::string ErrMsg;
+
+ return ASTUnit::LoadFromPCHFile(astName, CXXIdx->getDiagnostics(),
+ CXXIdx->getFileManager(), &ErrMsg);
+}
+
+void clang_disposeTranslationUnit(
+ CXTranslationUnit CTUnit)
+{
+ assert(CTUnit && "Passed null CXTranslationUnit");
+ delete static_cast<ASTUnit *>(CTUnit);
+}
+
+const char *clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit)
+{
+ assert(CTUnit && "Passed null CXTranslationUnit");
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(CTUnit);
+ return CXXUnit->getOriginalSourceFileName().c_str();
+}
+
+void clang_loadTranslationUnit(CXTranslationUnit CTUnit,
+ CXTranslationUnitIterator callback,
+ CXClientData CData)
+{
+ assert(CTUnit && "Passed null CXTranslationUnit");
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(CTUnit);
+ ASTContext &Ctx = CXXUnit->getASTContext();
+
+ TUVisitor DVisit(CTUnit, callback, CData);
+ DVisit.Visit(Ctx.getTranslationUnitDecl());
+}
+
+void clang_loadDeclaration(CXDecl Dcl,
+ CXDeclIterator callback,
+ CXClientData CData)
+{
+ assert(Dcl && "Passed null CXDecl");
+
+ CDeclVisitor DVisit(Dcl, callback, CData);
+ DVisit.Visit(static_cast<Decl *>(Dcl));
+}
+
+// Some notes on CXEntity:
+//
+// - Since the 'ordinary' namespace includes functions, data, typedefs,
+// ObjC interfaces, thecurrent algorithm is a bit naive (resulting in one
+// entity for 2 different types). For example:
+//
+// module1.m: @interface Foo @end Foo *x;
+// module2.m: void Foo(int);
+//
+// - Since the unique name spans translation units, static data/functions
+// within a CXTranslationUnit are *not* currently represented by entities.
+// As a result, there will be no entity for the following:
+//
+// module.m: static void Foo() { }
+//
+
+
+const char *clang_getDeclarationName(CXEntity)
+{
+ return "";
+}
+const char *clang_getURI(CXEntity)
+{
+ return "";
+}
+
+CXEntity clang_getEntity(const char *URI)
+{
+ return 0;
+}
+
+//
+// CXDecl Operations.
+//
+CXEntity clang_getEntityFromDecl(CXDecl)
+{
+ return 0;
+}
+const char *clang_getDeclSpelling(CXDecl AnonDecl)
+{
+ assert(AnonDecl && "Passed null CXDecl");
+ NamedDecl *ND = static_cast<NamedDecl *>(AnonDecl);
+
+ if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(ND)) {
+ return OMD->getSelector().getAsString().c_str();
+ }
+ if (ND->getIdentifier())
+ return ND->getIdentifier()->getName();
+ else
+ return "";
+}
+
+unsigned clang_getDeclLine(CXDecl AnonDecl)
+{
+ assert(AnonDecl && "Passed null CXDecl");
+ NamedDecl *ND = static_cast<NamedDecl *>(AnonDecl);
+ SourceManager &SourceMgr = ND->getASTContext().getSourceManager();
+ return SourceMgr.getSpellingLineNumber(ND->getLocation());
+}
+
+unsigned clang_getDeclColumn(CXDecl AnonDecl)
+{
+ assert(AnonDecl && "Passed null CXDecl");
+ NamedDecl *ND = static_cast<NamedDecl *>(AnonDecl);
+ SourceManager &SourceMgr = ND->getASTContext().getSourceManager();
+ return SourceMgr.getSpellingColumnNumber(ND->getLocation());
+}
+
+const char *clang_getDeclSource(CXDecl AnonDecl)
+{
+ assert(AnonDecl && "Passed null CXDecl");
+ NamedDecl *ND = static_cast<NamedDecl *>(AnonDecl);
+ SourceManager &SourceMgr = ND->getASTContext().getSourceManager();
+ return SourceMgr.getBufferName(ND->getLocation());
+}
+
+const char *clang_getCursorSpelling(CXCursor C)
+{
+ assert(C.decl && "CXCursor has null decl");
+ NamedDecl *ND = static_cast<NamedDecl *>(C.decl);
+
+ if (clang_isReference(C.kind)) {
+ switch (C.kind) {
+ case CXCursor_ObjCSuperClassRef:
+ {
+ ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(ND);
+ assert(OID && "clang_getCursorLine(): Missing interface decl");
+ return OID->getSuperClass()->getIdentifier()->getName();
+ }
+ case CXCursor_ObjCClassRef:
+ {
+ if (ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(ND)) {
+ return OID->getIdentifier()->getName();
+ }
+ ObjCCategoryDecl *OID = dyn_cast<ObjCCategoryDecl>(ND);
+ assert(OID && "clang_getCursorLine(): Missing category decl");
+ return OID->getClassInterface()->getIdentifier()->getName();
+ }
+ case CXCursor_ObjCProtocolRef:
+ {
+ ObjCProtocolDecl *OID = dyn_cast<ObjCProtocolDecl>(ND);
+ assert(OID && "clang_getCursorLine(): Missing protocol decl");
+ return OID->getIdentifier()->getName();
+ }
+ case CXCursor_ObjCSelectorRef:
+ {
+ ObjCMessageExpr *OME = dyn_cast<ObjCMessageExpr>(
+ static_cast<Stmt *>(C.stmt));
+ assert(OME && "clang_getCursorLine(): Missing message expr");
+ return OME->getSelector().getAsString().c_str();
+ }
+ case CXCursor_VarRef:
+ case CXCursor_FunctionRef:
+ case CXCursor_EnumConstantRef:
+ {
+ DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(
+ static_cast<Stmt *>(C.stmt));
+ assert(DRE && "clang_getCursorLine(): Missing decl ref expr");
+ return DRE->getDecl()->getIdentifier()->getName();
+ }
+ default:
+ return "<not implemented>";
+ }
+ }
+ return clang_getDeclSpelling(C.decl);
+}
+
+const char *clang_getCursorKindSpelling(enum CXCursorKind Kind)
+{
+ switch (Kind) {
+ case CXCursor_FunctionDecl: return "FunctionDecl";
+ case CXCursor_TypedefDecl: return "TypedefDecl";
+ case CXCursor_EnumDecl: return "EnumDecl";
+ case CXCursor_EnumConstantDecl: return "EnumConstantDecl";
+ case CXCursor_StructDecl: return "StructDecl";
+ case CXCursor_UnionDecl: return "UnionDecl";
+ case CXCursor_ClassDecl: return "ClassDecl";
+ case CXCursor_FieldDecl: return "FieldDecl";
+ case CXCursor_VarDecl: return "VarDecl";
+ case CXCursor_ParmDecl: return "ParmDecl";
+ case CXCursor_ObjCInterfaceDecl: return "ObjCInterfaceDecl";
+ case CXCursor_ObjCCategoryDecl: return "ObjCCategoryDecl";
+ case CXCursor_ObjCProtocolDecl: return "ObjCProtocolDecl";
+ case CXCursor_ObjCPropertyDecl: return "ObjCPropertyDecl";
+ case CXCursor_ObjCIvarDecl: return "ObjCIvarDecl";
+ case CXCursor_ObjCInstanceMethodDecl: return "ObjCInstanceMethodDecl";
+ case CXCursor_ObjCClassMethodDecl: return "ObjCClassMethodDecl";
+ case CXCursor_FunctionDefn: return "FunctionDefn";
+ case CXCursor_ObjCInstanceMethodDefn: return "ObjCInstanceMethodDefn";
+ case CXCursor_ObjCClassMethodDefn: return "ObjCClassMethodDefn";
+ case CXCursor_ObjCClassDefn: return "ObjCClassDefn";
+ case CXCursor_ObjCCategoryDefn: return "ObjCCategoryDefn";
+ case CXCursor_ObjCSuperClassRef: return "ObjCSuperClassRef";
+ case CXCursor_ObjCProtocolRef: return "ObjCProtocolRef";
+ case CXCursor_ObjCClassRef: return "ObjCClassRef";
+ case CXCursor_ObjCSelectorRef: return "ObjCSelectorRef";
+
+ case CXCursor_VarRef: return "VarRef";
+ case CXCursor_FunctionRef: return "FunctionRef";
+ case CXCursor_EnumConstantRef: return "EnumConstantRef";
+ case CXCursor_MemberRef: return "MemberRef";
+
+ case CXCursor_InvalidFile: return "InvalidFile";
+ case CXCursor_NoDeclFound: return "NoDeclFound";
+ case CXCursor_NotImplemented: return "NotImplemented";
+ default: return "<not implemented>";
+ }
+}
+
+static enum CXCursorKind TranslateKind(Decl *D) {
+ switch (D->getKind()) {
+ case Decl::Function: return CXCursor_FunctionDecl;
+ case Decl::Typedef: return CXCursor_TypedefDecl;
+ case Decl::Enum: return CXCursor_EnumDecl;
+ case Decl::EnumConstant: return CXCursor_EnumConstantDecl;
+ case Decl::Record: return CXCursor_StructDecl; // FIXME: union/class
+ case Decl::Field: return CXCursor_FieldDecl;
+ case Decl::Var: return CXCursor_VarDecl;
+ case Decl::ParmVar: return CXCursor_ParmDecl;
+ case Decl::ObjCInterface: return CXCursor_ObjCInterfaceDecl;
+ case Decl::ObjCCategory: return CXCursor_ObjCCategoryDecl;
+ case Decl::ObjCProtocol: return CXCursor_ObjCProtocolDecl;
+ case Decl::ObjCMethod: {
+ ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D);
+ if (MD->isInstanceMethod())
+ return CXCursor_ObjCInstanceMethodDecl;
+ return CXCursor_ObjCClassMethodDecl;
+ }
+ default: break;
+ }
+ return CXCursor_NotImplemented;
+}
+//
+// CXCursor Operations.
+//
+CXCursor clang_getCursor(CXTranslationUnit CTUnit, const char *source_name,
+ unsigned line, unsigned column)
+{
+ assert(CTUnit && "Passed null CXTranslationUnit");
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(CTUnit);
+
+ FileManager &FMgr = CXXUnit->getFileManager();
+ const FileEntry *File = FMgr.getFile(source_name,
+ source_name+strlen(source_name));
+ if (!File) {
+ CXCursor C = { CXCursor_InvalidFile, 0, 0 };
+ return C;
+ }
+ SourceLocation SLoc =
+ CXXUnit->getSourceManager().getLocation(File, line, column);
+
+ ASTLocation ALoc = ResolveLocationInAST(CXXUnit->getASTContext(), SLoc);
+
+ Decl *Dcl = ALoc.getParentDecl();
+ if (ALoc.isNamedRef())
+ Dcl = ALoc.AsNamedRef().ND;
+ Stmt *Stm = ALoc.dyn_AsStmt();
+ if (Dcl) {
+ if (Stm) {
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Stm)) {
+ CXCursor C = { TranslateDeclRefExpr(DRE), Dcl, Stm };
+ return C;
+ } else if (ObjCMessageExpr *MExp = dyn_cast<ObjCMessageExpr>(Stm)) {
+ CXCursor C = { CXCursor_ObjCSelectorRef, Dcl, MExp };
+ return C;
+ }
+ // Fall through...treat as a decl, not a ref.
+ }
+ if (ALoc.isNamedRef()) {
+ if (isa<ObjCInterfaceDecl>(Dcl)) {
+ CXCursor C = { CXCursor_ObjCClassRef, Dcl, ALoc.getParentDecl() };
+ return C;
+ }
+ if (isa<ObjCProtocolDecl>(Dcl)) {
+ CXCursor C = { CXCursor_ObjCProtocolRef, Dcl, ALoc.getParentDecl() };
+ return C;
+ }
+ }
+ CXCursor C = { TranslateKind(Dcl), Dcl, 0 };
+ return C;
+ }
+ CXCursor C = { CXCursor_NoDeclFound, 0, 0 };
+ return C;
+}
+
+CXCursor clang_getCursorFromDecl(CXDecl AnonDecl)
+{
+ assert(AnonDecl && "Passed null CXDecl");
+ NamedDecl *ND = static_cast<NamedDecl *>(AnonDecl);
+
+ CXCursor C = { TranslateKind(ND), ND, 0 };
+ return C;
+}
+
+unsigned clang_isInvalid(enum CXCursorKind K)
+{
+ return K >= CXCursor_FirstInvalid && K <= CXCursor_LastInvalid;
+}
+
+unsigned clang_isDeclaration(enum CXCursorKind K)
+{
+ return K >= CXCursor_FirstDecl && K <= CXCursor_LastDecl;
+}
+
+unsigned clang_isReference(enum CXCursorKind K)
+{
+ return K >= CXCursor_FirstRef && K <= CXCursor_LastRef;
+}
+
+unsigned clang_isDefinition(enum CXCursorKind K)
+{
+ return K >= CXCursor_FirstDefn && K <= CXCursor_LastDefn;
+}
+
+CXCursorKind clang_getCursorKind(CXCursor C)
+{
+ return C.kind;
+}
+
+static Decl *getDeclFromExpr(Stmt *E) {
+ if (DeclRefExpr *RefExpr = dyn_cast<DeclRefExpr>(E))
+ return RefExpr->getDecl();
+ if (MemberExpr *ME = dyn_cast<MemberExpr>(E))
+ return ME->getMemberDecl();
+ if (ObjCIvarRefExpr *RE = dyn_cast<ObjCIvarRefExpr>(E))
+ return RE->getDecl();
+
+ if (CallExpr *CE = dyn_cast<CallExpr>(E))
+ return getDeclFromExpr(CE->getCallee());
+ if (CastExpr *CE = dyn_cast<CastExpr>(E))
+ return getDeclFromExpr(CE->getSubExpr());
+ if (ObjCMessageExpr *OME = dyn_cast<ObjCMessageExpr>(E))
+ return OME->getMethodDecl();
+
+ return 0;
+}
+
+CXDecl clang_getCursorDecl(CXCursor C)
+{
+ if (clang_isDeclaration(C.kind))
+ return C.decl;
+
+ if (clang_isReference(C.kind)) {
+ if (C.stmt) {
+ if (C.kind == CXCursor_ObjCClassRef ||
+ C.kind == CXCursor_ObjCProtocolRef)
+ return static_cast<Stmt *>(C.stmt);
+ else
+ return getDeclFromExpr(static_cast<Stmt *>(C.stmt));
+ } else
+ return C.decl;
+ }
+ return 0;
+}
+
+
+static SourceLocation getLocationFromCursor(CXCursor C,
+ SourceManager &SourceMgr,
+ NamedDecl *ND) {
+ if (clang_isReference(C.kind)) {
+ switch (C.kind) {
+ case CXCursor_ObjCClassRef:
+ {
+ if (isa<ObjCInterfaceDecl>(ND)) {
+ // FIXME: This is a hack (storing the parent decl in the stmt slot).
+ NamedDecl *parentDecl = static_cast<NamedDecl *>(C.stmt);
+ return parentDecl->getLocation();
+ }
+ ObjCCategoryDecl *OID = dyn_cast<ObjCCategoryDecl>(ND);
+ assert(OID && "clang_getCursorLine(): Missing category decl");
+ return OID->getClassInterface()->getLocation();
+ }
+ case CXCursor_ObjCSuperClassRef:
+ {
+ ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(ND);
+ assert(OID && "clang_getCursorLine(): Missing interface decl");
+ return OID->getSuperClassLoc();
+ }
+ case CXCursor_ObjCProtocolRef:
+ {
+ ObjCProtocolDecl *OID = dyn_cast<ObjCProtocolDecl>(ND);
+ assert(OID && "clang_getCursorLine(): Missing protocol decl");
+ return OID->getLocation();
+ }
+ case CXCursor_ObjCSelectorRef:
+ {
+ ObjCMessageExpr *OME = dyn_cast<ObjCMessageExpr>(
+ static_cast<Stmt *>(C.stmt));
+ assert(OME && "clang_getCursorLine(): Missing message expr");
+ return OME->getLeftLoc(); /* FIXME: should be a range */
+ }
+ case CXCursor_VarRef:
+ case CXCursor_FunctionRef:
+ case CXCursor_EnumConstantRef:
+ {
+ DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(
+ static_cast<Stmt *>(C.stmt));
+ assert(DRE && "clang_getCursorLine(): Missing decl ref expr");
+ return DRE->getLocation();
+ }
+ default:
+ return SourceLocation();
+ }
+ } else { // We have a declaration or a definition.
+ SourceLocation SLoc;
+ switch (ND->getKind()) {
+ case Decl::ObjCInterface:
+ {
+ SLoc = dyn_cast<ObjCInterfaceDecl>(ND)->getClassLoc();
+ break;
+ }
+ case Decl::ObjCProtocol:
+ {
+ SLoc = ND->getLocation(); /* FIXME: need to get the name location. */
+ break;
+ }
+ default:
+ {
+ SLoc = ND->getLocation();
+ break;
+ }
+ }
+ if (SLoc.isInvalid())
+ return SourceLocation();
+ return SourceMgr.getSpellingLoc(SLoc); // handles macro instantiations.
+ }
+}
+
+unsigned clang_getCursorLine(CXCursor C)
+{
+ assert(C.decl && "CXCursor has null decl");
+ NamedDecl *ND = static_cast<NamedDecl *>(C.decl);
+ SourceManager &SourceMgr = ND->getASTContext().getSourceManager();
+
+ SourceLocation SLoc = getLocationFromCursor(C, SourceMgr, ND);
+ return SourceMgr.getSpellingLineNumber(SLoc);
+}
+
+unsigned clang_getCursorColumn(CXCursor C)
+{
+ assert(C.decl && "CXCursor has null decl");
+ NamedDecl *ND = static_cast<NamedDecl *>(C.decl);
+ SourceManager &SourceMgr = ND->getASTContext().getSourceManager();
+
+ SourceLocation SLoc = getLocationFromCursor(C, SourceMgr, ND);
+ return SourceMgr.getSpellingColumnNumber(SLoc);
+}
+const char *clang_getCursorSource(CXCursor C)
+{
+ assert(C.decl && "CXCursor has null decl");
+ NamedDecl *ND = static_cast<NamedDecl *>(C.decl);
+ SourceManager &SourceMgr = ND->getASTContext().getSourceManager();
+
+ SourceLocation SLoc = getLocationFromCursor(C, SourceMgr, ND);
+ return SourceMgr.getBufferName(SLoc);
+}
+
+void clang_getDefinitionSpellingAndExtent(CXCursor C,
+ const char **startBuf,
+ const char **endBuf,
+ unsigned *startLine,
+ unsigned *startColumn,
+ unsigned *endLine,
+ unsigned *endColumn)
+{
+ assert(C.decl && "CXCursor has null decl");
+ NamedDecl *ND = static_cast<NamedDecl *>(C.decl);
+ FunctionDecl *FD = dyn_cast<FunctionDecl>(ND);
+ CompoundStmt *Body = dyn_cast<CompoundStmt>(FD->getBody());
+
+ SourceManager &SM = FD->getASTContext().getSourceManager();
+ *startBuf = SM.getCharacterData(Body->getLBracLoc());
+ *endBuf = SM.getCharacterData(Body->getRBracLoc());
+ *startLine = SM.getSpellingLineNumber(Body->getLBracLoc());
+ *startColumn = SM.getSpellingColumnNumber(Body->getLBracLoc());
+ *endLine = SM.getSpellingLineNumber(Body->getRBracLoc());
+ *endColumn = SM.getSpellingColumnNumber(Body->getRBracLoc());
+}
+
+
+} // end extern "C"
diff --git a/tools/CIndex/CIndex.exports b/tools/CIndex/CIndex.exports
new file mode 100644
index 0000000..c1ca0c7
--- /dev/null
+++ b/tools/CIndex/CIndex.exports
@@ -0,0 +1,29 @@
+_clang_createIndex
+_clang_disposeIndex
+_clang_getCursor
+_clang_getCursorColumn
+_clang_getCursorDecl
+_clang_getCursorFromDecl
+_clang_getCursorKind
+_clang_getCursorLine
+_clang_getCursorSource
+_clang_getDeclarationName
+_clang_getDeclSpelling
+_clang_getDeclLine
+_clang_getDeclColumn
+_clang_getDeclSource
+_clang_getEntity
+_clang_getEntityFromDecl
+_clang_getURI
+_clang_loadDeclaration
+_clang_loadTranslationUnit
+_clang_createTranslationUnit
+_clang_disposeTranslationUnit
+_clang_isDeclaration
+_clang_isReference
+_clang_isDefinition
+_clang_isInvalid
+_clang_getCursorSpelling
+_clang_getCursorKindSpelling
+_clang_getDefinitionSpellingAndExtent
+_clang_getTranslationUnitSpelling
diff --git a/tools/CIndex/CMakeLists.txt b/tools/CIndex/CMakeLists.txt
new file mode 100644
index 0000000..71bbde5
--- /dev/null
+++ b/tools/CIndex/CMakeLists.txt
@@ -0,0 +1,27 @@
+set(SHARED_LIBRARY TRUE)
+
+set(LLVM_NO_RTTI 1)
+
+set(LLVM_USED_LIBS
+ clangFrontend clangIndex clangSema clangAST clangLex clangBasic)
+
+set( LLVM_LINK_COMPONENTS
+ MC
+ support
+ )
+
+add_clang_library(CIndex CIndex.cpp)
+
+if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+ # FIXME: Deal with LLVM_SUBMIT_VERSION?
+
+ set_target_properties(CIndex
+ PROPERTIES
+ LINK_FLAGS "-avoid-version -Wl,-exported_symbols_list -Wl,${CMAKE_CURRENT_SOURCE_DIR}/CIndex.exports -Wl,-dead_strip -Wl,-seg1addr -Wl,0xE0000000"
+ INSTALL_NAME_DIR "@executable_path/../lib"
+ )
+endif()
+
+set_target_properties(CIndex
+ PROPERTIES
+ LINKER_LANGUAGE CXX)
diff --git a/tools/CIndex/Makefile b/tools/CIndex/Makefile
new file mode 100644
index 0000000..a9ff394
--- /dev/null
+++ b/tools/CIndex/Makefile
@@ -0,0 +1,54 @@
+##===- tools/CIndex/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 = CIndex
+
+CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
+CXXFLAGS = -fno-rtti
+
+# 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_LIBS_IN_SHARED = 1
+SHARED_LIBRARY = 1
+
+LINK_COMPONENTS := MC support
+USEDLIBS = clangFrontend.a clangIndex.a clangSema.a clangAST.a clangLex.a clangBasic.a
+
+include $(LEVEL)/Makefile.common
+
+##===----------------------------------------------------------------------===##
+# FIXME: This is copied from the 'lto' makefile. Should we share this?
+##===----------------------------------------------------------------------===##
+
+ifeq ($(HOST_OS),Darwin)
+ # set dylib internal version number to llvmCore submission number
+ ifdef LLVM_SUBMIT_VERSION
+ LLVMLibsOptions := $(LLVMLibsOptions) -Wl,-current_version \
+ -Wl,$(LLVM_SUBMIT_VERSION).$(LLVM_SUBMIT_SUBVERSION) \
+ -Wl,-compatibility_version -Wl,1
+ endif
+ # extra options to override libtool defaults
+ LLVMLibsOptions := $(LLVMLibsOptions) \
+ -avoid-version \
+ -Wl,-exported_symbols_list -Wl,$(PROJ_SRC_DIR)/CIndex.exports \
+ -Wl,-dead_strip \
+ -Wl,-seg1addr -Wl,0xE0000000
+
+ # Mac OS X 10.4 and earlier tools do not allow a second -install_name on command line
+ DARWIN_VERS := $(shell echo $(TARGET_TRIPLE) | sed 's/.*darwin\([0-9]*\).*/\1/')
+ ifneq ($(DARWIN_VERS),8)
+ LLVMLibsOptions := $(LLVMLibsOptions) \
+ -no-undefined -Wl,-install_name \
+ -Wl,"@executable_path/../lib/lib$(LIBRARYNAME)$(SHLIBEXT)"
+ endif
+endif
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index fc30fb8..cb2aa20 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -1,3 +1,12 @@
add_subdirectory(clang-cc)
add_subdirectory(driver)
add_subdirectory(index-test)
+option(CLANG_BUILD_EXPERIMENTAL "Build experimenal Clang tools" OFF)
+if (CLANG_BUILD_EXPERIMENTAL)
+ add_subdirectory(wpa)
+endif ()
+add_subdirectory(CIndex)
+if (MSVC)
+else ()
+ add_subdirectory(c-index-test)
+endif ()
diff --git a/tools/Makefile b/tools/Makefile
index 5b49cc8..0e98439 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -8,6 +8,6 @@
##===----------------------------------------------------------------------===##
LEVEL := ../../..
-DIRS := clang-cc driver index-test
+DIRS := clang-cc driver index-test CIndex c-index-test
include $(LEVEL)/Makefile.common
diff --git a/tools/c-index-test/CMakeLists.txt b/tools/c-index-test/CMakeLists.txt
new file mode 100644
index 0000000..4c72465
--- /dev/null
+++ b/tools/c-index-test/CMakeLists.txt
@@ -0,0 +1,25 @@
+set(LLVM_NO_RTTI 1)
+
+set( LLVM_USED_LIBS
+ CIndex
+ clangIndex
+ clangFrontend
+ clangSema
+ clangAST
+ clangLex
+ clangBasic
+ )
+
+set( LLVM_LINK_COMPONENTS
+ bitreader
+ mc
+ )
+
+add_clang_executable(c-index-test
+ c-index-test.c
+ )
+
+set_target_properties(c-index-test
+ PROPERTIES
+ LINKER_LANGUAGE CXX)
+
diff --git a/tools/c-index-test/Makefile b/tools/c-index-test/Makefile
new file mode 100644
index 0000000..81fee40
--- /dev/null
+++ b/tools/c-index-test/Makefile
@@ -0,0 +1,24 @@
+##===- tools/index-test/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 = c-index-test
+CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
+CXXFLAGS = -fno-rtti
+NO_INSTALL = 1
+
+# No plugins, optimize startup time.
+TOOL_NO_EXPORTS = 1
+
+include $(LEVEL)/Makefile.config
+
+LINK_COMPONENTS := bitreader mc
+USEDLIBS = CIndex.a clangIndex.a clangFrontend.a clangSema.a clangAST.a clangLex.a clangBasic.a
+
+include $(LLVM_SRC_ROOT)/Makefile.rules
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
new file mode 100644
index 0000000..c514b63
--- /dev/null
+++ b/tools/c-index-test/c-index-test.c
@@ -0,0 +1,106 @@
+/* c-index-test.c */
+
+#include "clang-c/Index.h"
+#include <stdio.h>
+#include <string.h>
+
+extern char *basename(const char *);
+
+static void PrintCursor(CXCursor Cursor) {
+ if (clang_isInvalid(Cursor.kind))
+ printf("Invalid Cursor => %s\n", clang_getCursorKindSpelling(Cursor.kind));
+ else {
+ CXDecl DeclReferenced;
+ printf("%s=%s", clang_getCursorKindSpelling(Cursor.kind),
+ clang_getCursorSpelling(Cursor));
+ DeclReferenced = clang_getCursorDecl(Cursor);
+ if (DeclReferenced)
+ printf(":%d:%d", clang_getDeclLine(DeclReferenced),
+ clang_getDeclColumn(DeclReferenced));
+ }
+}
+
+static void DeclVisitor(CXDecl Dcl, CXCursor Cursor, CXClientData Filter)
+{
+ if (!Filter || (Cursor.kind == *(enum CXCursorKind *)Filter)) {
+ printf("// CHECK: %s:%d:%d: ", basename(clang_getCursorSource(Cursor)),
+ clang_getCursorLine(Cursor),
+ clang_getCursorColumn(Cursor));
+ PrintCursor(Cursor);
+ printf(" [Context=%s]\n", clang_getDeclSpelling(Dcl));
+ }
+}
+static void TranslationUnitVisitor(CXTranslationUnit Unit, CXCursor Cursor,
+ CXClientData Filter)
+{
+ if (!Filter || (Cursor.kind == *(enum CXCursorKind *)Filter)) {
+ printf("// CHECK: %s:%d:%d: ", basename(clang_getCursorSource(Cursor)),
+ clang_getCursorLine(Cursor),
+ clang_getCursorColumn(Cursor));
+ PrintCursor(Cursor);
+ printf(" [Context=%s]\n", basename(clang_getTranslationUnitSpelling(Unit)));
+
+ clang_loadDeclaration(Cursor.decl, DeclVisitor, 0);
+
+ if (Cursor.kind == CXCursor_FunctionDefn) {
+ const char *startBuf, *endBuf;
+ unsigned startLine, startColumn, endLine, endColumn;
+ clang_getDefinitionSpellingAndExtent(Cursor, &startBuf, &endBuf,
+ &startLine, &startColumn,
+ &endLine, &endColumn);
+ {
+ /* Probe the entire body, looking for both decls and refs. */
+ unsigned curLine = startLine, curColumn = startColumn;
+ CXCursor Ref;
+
+ while (startBuf <= endBuf) {
+ if (*startBuf == '\n') {
+ startBuf++;
+ curLine++;
+ curColumn = 1;
+ } else if (*startBuf != '\t')
+ curColumn++;
+
+ Ref = clang_getCursor(Unit, clang_getCursorSource(Cursor),
+ curLine, curColumn);
+ if (Ref.kind != CXCursor_FunctionDecl) {
+ printf("// CHECK: %s:%d:%d: ", basename(clang_getCursorSource(Ref)),
+ curLine, curColumn);
+ PrintCursor(Ref);
+ printf(" [Context:%s]\n", clang_getDeclSpelling(Ref.decl));
+ }
+ startBuf++;
+ }
+ }
+ }
+ }
+}
+
+/*
+ * First sign of life:-)
+ */
+int main(int argc, char **argv) {
+ if (argc != 3) {
+ printf("Incorrect usage of c-index-test (requires 3 arguments)\n");
+ return 0;
+ }
+ {
+ CXIndex Idx = clang_createIndex();
+ CXTranslationUnit TU = clang_createTranslationUnit(Idx, argv[1]);
+ enum CXCursorKind K = CXCursor_NotImplemented;
+
+ if (!strcmp(argv[2], "all")) {
+ clang_loadTranslationUnit(TU, TranslationUnitVisitor, 0);
+ return 1;
+ }
+ /* Perform some simple filtering. */
+ if (!strcmp(argv[2], "category")) K = CXCursor_ObjCCategoryDecl;
+ else if (!strcmp(argv[2], "interface")) K = CXCursor_ObjCInterfaceDecl;
+ else if (!strcmp(argv[2], "protocol")) K = CXCursor_ObjCProtocolDecl;
+ else if (!strcmp(argv[2], "function")) K = CXCursor_FunctionDecl;
+ else if (!strcmp(argv[2], "typedef")) K = CXCursor_TypedefDecl;
+
+ clang_loadTranslationUnit(TU, TranslationUnitVisitor, &K);
+ return 1;
+ }
+}
diff --git a/tools/clang-cc/CMakeLists.txt b/tools/clang-cc/CMakeLists.txt
index e224d40..85e4c7c 100644
--- a/tools/clang-cc/CMakeLists.txt
+++ b/tools/clang-cc/CMakeLists.txt
@@ -25,3 +25,6 @@ add_clang_executable(clang-cc
clang-cc.cpp
)
add_dependencies(clang-cc clang-headers)
+
+install(TARGETS clang-cc
+ RUNTIME DESTINATION libexec)
diff --git a/tools/clang-cc/clang-cc.cpp b/tools/clang-cc/clang-cc.cpp
index 9433c17..0ad7efb 100644
--- a/tools/clang-cc/clang-cc.cpp
+++ b/tools/clang-cc/clang-cc.cpp
@@ -24,6 +24,7 @@
#include "clang/Frontend/AnalysisConsumer.h"
#include "clang/Frontend/ASTConsumers.h"
+#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompileOptions.h"
#include "clang/Frontend/FixItRewriter.h"
#include "clang/Frontend/FrontendDiagnostic.h"
@@ -37,6 +38,7 @@
#include "clang/Frontend/Utils.h"
#include "clang/Analysis/PathDiagnostic.h"
#include "clang/CodeGen/ModuleBuilder.h"
+#include "clang/Sema/CodeCompleteConsumer.h"
#include "clang/Sema/ParseAST.h"
#include "clang/Sema/SemaDiagnostic.h"
#include "clang/AST/ASTConsumer.h"
@@ -58,12 +60,13 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/Config/config.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ErrorHandling.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/Support/raw_ostream.h"
#include "llvm/System/Host.h"
#include "llvm/System/Path.h"
#include "llvm/System/Process.h"
@@ -108,14 +111,14 @@ 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",
+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",
+EmptyInputOnly("empty-input-only",
llvm::cl::desc("Force running on an empty input file"));
enum ProgActions {
@@ -128,13 +131,14 @@ enum ProgActions {
EmitAssembly, // Emit a .s file.
EmitLLVM, // Emit a .ll file.
EmitBC, // Emit a .bc file.
- EmitLLVMOnly, // Generate LLVM IR, but do not
+ 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.
+ DumpRecordLayouts, // Dump record layout information.
ParsePrintCallbacks, // Parse and print each callback.
ParseSyntaxOnly, // Parse and perform semantic analysis.
ParseNoop, // Parse with noop callbacks.
@@ -142,13 +146,13 @@ enum ProgActions {
PrintPreprocessedInput, // -E mode.
DumpTokens, // Dump out preprocessed tokens.
DumpRawTokens, // Dump out raw tokens.
- RunAnalysis, // Run one or more source code analyses.
+ 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>
+static llvm::cl::opt<ProgActions>
ProgAction(llvm::cl::desc("Choose output type:"), llvm::cl::ZeroOrMore,
llvm::cl::init(ParseSyntaxOnly),
llvm::cl::values(
@@ -180,6 +184,8 @@ ProgAction(llvm::cl::desc("Choose output type:"), llvm::cl::ZeroOrMore,
"Build ASTs and view them with GraphViz"),
clEnumValN(PrintDeclContext, "print-decl-contexts",
"Print DeclContexts and their Decls"),
+ clEnumValN(DumpRecordLayouts, "dump-record-layouts",
+ "Dump record layout information"),
clEnumValN(GeneratePTH, "emit-pth",
"Generate pre-tokenized header file"),
clEnumValN(GeneratePCH, "emit-pch",
@@ -211,6 +217,17 @@ OutputFile("o",
llvm::cl::desc("Specify output file"));
+static llvm::cl::opt<ParsedSourceLocation>
+CodeCompletionAt("code-completion-at",
+ llvm::cl::value_desc("file:line:column"),
+ llvm::cl::desc("Dump code-completion information at a location"));
+
+/// \brief Buld a new code-completion consumer that prints the results of
+/// code completion to standard output.
+static CodeCompleteConsumer *BuildPrintingCodeCompleter(Sema &S, void *) {
+ return new PrintingCodeCompleteConsumer(S, llvm::outs());
+}
+
//===----------------------------------------------------------------------===//
// PTH.
//===----------------------------------------------------------------------===//
@@ -261,13 +278,13 @@ PrintDiagnosticOption("fdiagnostics-show-option",
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"));
+ llvm::cl::desc("Format message diagnostics so that they fit "
+ "within N columns or fewer, when possible."),
+ llvm::cl::value_desc("N"));
static llvm::cl::opt<bool>
NoColorDiagnostic("fno-color-diagnostics",
- llvm::cl::desc("Don't use colors when showing diagnostics "
+ llvm::cl::desc("Don't use colors when showing diagnostics "
"(automatically turned off if output is not a "
"terminal)."));
//===----------------------------------------------------------------------===//
@@ -317,7 +334,8 @@ enum LangKind {
langkind_objc_cpp,
langkind_objcxx,
langkind_objcxx_cpp,
- langkind_ocl
+ langkind_ocl,
+ langkind_ast
};
static llvm::cl::opt<LangKind>
@@ -346,20 +364,21 @@ BaseLang("x", llvm::cl::desc("Base language to compile"),
"C++ header"),
clEnumValN(langkind_objcxx, "objective-c++-header",
"Objective-C++ header"),
+ clEnumValN(langkind_ast, "ast",
+ "Clang AST"),
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<std::string>
+ObjCConstantStringClass("fconstant-string-class",
+ llvm::cl::value_desc("class name"),
+ llvm::cl::desc("Specify the class to use for constant "
+ "Objective-C string objects."));
+
static llvm::cl::opt<bool>
ObjCEnableGC("fobjc-gc",
llvm::cl::desc("Enable Objective-C garbage collection"));
@@ -386,39 +405,23 @@ OverflowChecking("ftrapv",
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));
+AltiVec("faltivec", llvm::cl::desc("Enable AltiVec vector initializer syntax"),
+ 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 llvm::cl::opt<bool>
+PThread("pthread", llvm::cl::desc("Support POSIX threads in generated code"),
+ llvm::cl::init(false));
-static LangKind GetLanguage(const std::string &Filename) {
+static LangKind GetLanguage(llvm::StringRef 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.
+ llvm::StringRef Ext = Filename.rsplit('.').second;
+ if (Ext == "ast")
+ return langkind_ast;
+ else if (Ext == "c")
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")
+ else if (Ext == "S" || Ext == "s")
return langkind_asm_cpp;
else if (Ext == "i")
return langkind_c_cpp;
@@ -449,12 +452,12 @@ static void InitializeCOptions(LangOptions &Options) {
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:
@@ -492,25 +495,30 @@ static void InitializeLangOptions(LangOptions &Options, LangKind LK){
Options.LaxVectorConversions = 1;
break;
}
-
+
if (ObjCExclusiveGC)
Options.setGCMode(LangOptions::GCOnly);
else if (ObjCEnableGC)
Options.setGCMode(LangOptions::HybridGC);
-
+
if (ObjCEnableGCBitmapPrint)
Options.ObjCGCBitmapPrint = 1;
-
+
+ if (AltiVec)
+ Options.AltiVec = 1;
+
+ if (PThread)
+ Options.POSIXThreads = 1;
+
Options.setVisibilityMode(SymbolVisibility);
Options.OverflowChecking = OverflowChecking;
}
/// LangStds - Language standards we support.
enum LangStds {
- lang_unspecified,
+ lang_unspecified,
lang_c89, lang_c94, lang_c99,
- lang_gnu_START,
- lang_gnu89 = lang_gnu_START, lang_gnu99,
+ lang_gnu89, lang_gnu99,
lang_cxx98, lang_gnucxx98,
lang_cxx0x, lang_gnucxx0x
};
@@ -554,7 +562,7 @@ 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 "
@@ -592,6 +600,10 @@ Exceptions("fexceptions",
llvm::cl::desc("Enable support for exception handling"));
static llvm::cl::opt<bool>
+Rtti("frtti", llvm::cl::init(true),
+ llvm::cl::desc("Enable generation of rtti information"));
+
+static llvm::cl::opt<bool>
GNURuntime("fgnu-runtime",
llvm::cl::desc("Generate output compatible with the standard GNU "
"Objective-C runtime"));
@@ -622,7 +634,7 @@ static llvm::cl::opt<bool>
OptSize("Os", llvm::cl::desc("Optimize for size"));
static llvm::cl::opt<bool>
-DisableLLVMOptimizations("disable-llvm-optzns",
+DisableLLVMOptimizations("disable-llvm-optzns",
llvm::cl::desc("Don't run LLVM optimization passes"));
static llvm::cl::opt<bool>
@@ -636,17 +648,26 @@ MainFileName("main-file-name",
// FIXME: Also add an "-fno-access-control" option.
static llvm::cl::opt<bool>
-AccessControl("faccess-control",
+AccessControl("faccess-control",
llvm::cl::desc("Enable C++ access control"));
+static llvm::cl::opt<bool>
+NoElideConstructors("fno-elide-constructors",
+ llvm::cl::desc("Disable C++ copy constructor elision"));
+
+static llvm::cl::opt<std::string>
+TargetABI("target-abi",
+ llvm::cl::desc("Target a particular ABI type"));
+
+
// 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) {
+ bool parse(llvm::cl::Option &O, llvm::StringRef ArgName,
+ llvm::StringRef 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 O.error("'" + Arg + "' invalid optimization level!");
return false;
}
};
@@ -675,10 +696,11 @@ static void InitializeLanguageStandard(LangOptions &Options, LangKind LK,
// 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 langkind_ast: assert(0 && "Invalid call for AST inputs");
case lang_unspecified: assert(0 && "Unknown base language");
case langkind_ocl:
LangStd = lang_c99;
@@ -698,7 +720,7 @@ static void InitializeLanguageStandard(LangOptions &Options, LangKind LK,
break;
}
}
-
+
switch (LangStd) {
default: assert(0 && "Unknown language standard!");
@@ -729,18 +751,33 @@ static void InitializeLanguageStandard(LangOptions &Options, LangKind LK,
}
// GNUMode - Set if we're in gnu99, gnu89, gnucxx98, etc.
- Options.GNUMode = LangStd >= lang_gnu_START;
-
+ switch (LangStd) {
+ default: assert(0 && "Unknown language standard!");
+ case lang_gnucxx0x:
+ case lang_gnucxx98:
+ case lang_gnu99:
+ case lang_gnu89:
+ Options.GNUMode = 1;
+ break;
+ case lang_cxx0x:
+ case lang_cxx98:
+ case lang_c99:
+ case lang_c94:
+ case lang_c89:
+ Options.GNUMode = 0;
+ break;
+ }
+
if (Options.CPlusPlus) {
Options.C99 = 0;
- Options.HexFloats = Options.GNUMode;
+ Options.HexFloats = 0;
}
-
+
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;
@@ -753,14 +790,14 @@ static void InitializeLanguageStandard(LangOptions &Options, LangKind LK,
// 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;
if (MSExtensions.getPosition())
@@ -769,6 +806,7 @@ static void InitializeLanguageStandard(LangOptions &Options, LangKind LK,
if (NoLaxVectorConversions.getPosition())
Options.LaxVectorConversions = 0;
Options.Exceptions = Exceptions;
+ Options.Rtti = Rtti;
if (EnableBlocks.getPosition())
Options.Blocks = EnableBlocks;
if (CharIsSigned.getPosition())
@@ -778,16 +816,18 @@ static void InitializeLanguageStandard(LangOptions &Options, LangKind LK,
Options.NoBuiltin = 1;
if (Freestanding)
Options.Freestanding = Options.NoBuiltin = 1;
-
+
if (EnableHeinousExtensions)
Options.HeinousExtensions = 1;
if (AccessControl)
Options.AccessControl = 1;
-
+
+ Options.ElideConstructors = !NoElideConstructors;
+
// OpenCL and C++ both have bool, true, false keywords.
Options.Bool = Options.OpenCL | Options.CPlusPlus;
-
+
Options.MathErrno = MathErrno;
Options.InstantiationDepth = TemplateDepth;
@@ -798,18 +838,19 @@ static void InitializeLanguageStandard(LangOptions &Options, LangKind LK,
else if (GNURuntime)
Options.NeXTRuntime = 0;
+ if (!ObjCConstantStringClass.empty())
+ Options.ObjCConstantStringClass = ObjCConstantStringClass.c_str();
+
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;
@@ -818,7 +859,7 @@ static void InitializeLanguageStandard(LangOptions &Options, LangKind LK,
Options.PICLevel = PICLevel;
Options.GNUInline = !Options.C99;
- // FIXME: This is affected by other options (-fno-inline).
+ // FIXME: This is affected by other options (-fno-inline).
Options.NoInline = !OptSize && !OptLevel;
Options.Static = StaticDefine;
@@ -845,70 +886,72 @@ TargetTriple("triple",
llvm::cl::desc("Specify target triple (e.g. i686-apple-darwin9)"));
static llvm::cl::opt<std::string>
-MacOSVersionMin("mmacosx-version-min",
+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,
+static void HandleMacOSVersionMin(llvm::Triple &Triple) {
+ if (Triple.getOS() != llvm::Triple::Darwin) {
+ 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;
- }
+ fprintf(stderr,
+ "-mmacosx-version-min=%s is invalid, expected something like '10.4'.\n",
+ MacOSVersionMin.c_str());
+ exit(1);
}
- if (MacOSVersionMinIsInvalid) {
- fprintf(stderr,
- "-mmacosx-version-min=%s is invalid, expected something like '10.4'.\n",
+ unsigned VersionNum = MacOSVersionMin[3]-'0';
+
+ if (VersionNum <= 4 && Triple.getArch() == llvm::Triple::x86_64) {
+ fprintf(stderr,
+ "-mmacosx-version-min=%s is invalid with -arch x86_64.\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",
+
+
+ llvm::SmallString<16> NewDarwinString;
+ NewDarwinString += "darwin";
+
+ // Turn MacOSVersionMin into a darwin number: e.g. 10.3.9 is 3 -> darwin7.
+ VersionNum += 4;
+ if (VersionNum > 9) {
+ NewDarwinString += '1';
+ VersionNum -= 10;
+ }
+ NewDarwinString += (VersionNum+'0');
+
+ if (MacOSVersionMin.size() == 4) {
+ // "10.4" is ok.
+ } else if (MacOSVersionMin.size() == 6 &&
+ MacOSVersionMin[4] == '.' &&
+ isdigit(MacOSVersionMin[5])) { // 10.4.7 is ok.
+ // Add the period piece (.7) to the end of the triple. This gives us
+ // something like ...-darwin8.7
+ NewDarwinString += '.';
+ NewDarwinString += MacOSVersionMin[5];
+ } else { // "10.4" is ok. 10.4x is not.
+ fprintf(stderr,
+ "-mmacosx-version-min=%s is invalid, expected something like '10.4'.\n",
MacOSVersionMin.c_str());
exit(1);
}
+ Triple.setOSName(NewDarwinString.str());
}
static llvm::cl::opt<std::string>
-IPhoneOSVersionMin("miphoneos-version-min",
+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
@@ -917,68 +960,46 @@ IPhoneOSVersionMin("miphoneos-version-min",
// 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");
+static void HandleIPhoneOSVersionMin(llvm::Triple &Triple) {
+ if (Triple.getOS() != llvm::Triple::Darwin) {
+ 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",
+
+ // Validate that IPhoneOSVersionMin is a 'version number', starting with
+ // [2-9].[0-9]
+ if (IPhoneOSVersionMin.size() != 3 || !isdigit(IPhoneOSVersionMin[0]) ||
+ IPhoneOSVersionMin[1] != '.' || !isdigit(IPhoneOSVersionMin[2])) {
+ fprintf(stderr,
+ "-miphoneos-version-min=%s is invalid, expected something like '2.0'.\n",
IPhoneOSVersionMin.c_str());
exit(1);
}
+
+ // Turn IPhoneOSVersionMin into a darwin number: e.g. 2.0 is 2 -> 9.2.0
+ llvm::SmallString<16> NewDarwinString;
+ NewDarwinString += "darwin9.";
+ NewDarwinString += IPhoneOSVersionMin;
+ Triple.setOSName(NewDarwinString.str());
}
/// 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() {
+static llvm::Triple 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();
+ llvm::Triple Triple(TargetTriple);
+ if (Triple.getTriple().empty())
+ Triple = llvm::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);;
-
+ HandleIPhoneOSVersionMin(Triple);
+
return Triple;
}
@@ -994,14 +1015,14 @@ static bool InitializeSourceManager(Preprocessor &PP,
if (EmptyInputOnly) {
const char *EmptyStr = "";
- llvm::MemoryBuffer *SB =
+ 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)
+ PP.getDiagnostics().Report(FullSourceLoc(), diag::err_fe_error_reading)
<< InFile.c_str();
return true;
}
@@ -1017,7 +1038,7 @@ static bool InitializeSourceManager(Preprocessor &PP,
SourceMgr.createMainFileIDForMemBuffer(SB);
if (SourceMgr.getMainFileID().isInvalid()) {
- PP.getDiagnostics().Report(FullSourceLoc(),
+ PP.getDiagnostics().Report(FullSourceLoc(),
diag::err_fe_error_reading_stdin);
return true;
}
@@ -1057,6 +1078,10 @@ static llvm::cl::opt<std::string>
ImplicitIncludePTH("include-pth", llvm::cl::value_desc("file"),
llvm::cl::desc("Include file before parsing"));
+static llvm::cl::opt<bool>
+RelocatablePCH("relocatable-pch",
+ llvm::cl::desc("Whether to build a relocatable precompiled "
+ "header"));
//===----------------------------------------------------------------------===//
// Preprocessor include path information.
@@ -1065,7 +1090,7 @@ ImplicitIncludePTH("include-pth", llvm::cl::value_desc("file"),
// 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
//
@@ -1073,6 +1098,10 @@ ImplicitIncludePTH("include-pth", llvm::cl::value_desc("file"),
static llvm::cl::opt<bool>
nostdinc("nostdinc", llvm::cl::desc("Disable standard #include directories"));
+static llvm::cl::opt<bool>
+nostdclanginc("nostdclanginc",
+ llvm::cl::desc("Disable standard clang #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,
@@ -1108,10 +1137,37 @@ isysroot("isysroot", llvm::cl::value_desc("dir"), llvm::cl::init("/"),
// Finally, implement the code that groks the options above.
+// Add the clang headers, which are relative to the clang binary.
+void AddClangIncludePaths(const char *Argv0, InitHeaderSearch *Init) {
+ if (nostdclanginc)
+ return;
+
+ llvm::sys::Path MainExecutablePath =
+ llvm::sys::Path::GetMainExecutable(Argv0,
+ (void*)(intptr_t)AddClangIncludePaths);
+ if (MainExecutablePath.isEmpty())
+ return;
+
+ 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*/);
+}
+
/// InitializeIncludePaths - Process the -I options and set them in the
/// HeaderSearch object.
void InitializeIncludePaths(const char *Argv0, HeaderSearch &Headers,
- FileManager &FM, const LangOptions &Lang) {
+ FileManager &FM, const LangOptions &Lang,
+ llvm::Triple &triple) {
InitHeaderSearch Init(Headers, Verbose, isysroot);
// Handle -I... and -F... options, walking the lists in parallel.
@@ -1125,22 +1181,22 @@ void InitializeIncludePaths(const char *Argv0, HeaderSearch &Headers,
++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);
@@ -1158,28 +1214,28 @@ void InitializeIncludePaths(const char *Argv0, HeaderSearch &Headers,
bool iwithprefixbefore_done = iwithprefixbefore_vals.empty();
while (!iprefix_done || !iwithprefix_done || !iwithprefixbefore_done) {
if (!iprefix_done &&
- (iwithprefix_done ||
- iprefix_vals.getPosition(iprefix_idx) <
+ (iwithprefix_done ||
+ iprefix_vals.getPosition(iprefix_idx) <
iwithprefix_vals.getPosition(iwithprefix_idx)) &&
- (iwithprefixbefore_done ||
- iprefix_vals.getPosition(iprefix_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_done ||
+ iwithprefix_vals.getPosition(iwithprefix_idx) <
iwithprefixbefore_vals.getPosition(iwithprefixbefore_idx))) {
- Init.AddPath(Prefix+iwithprefix_vals[iwithprefix_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],
+ Init.AddPath(Prefix+iwithprefixbefore_vals[iwithprefixbefore_idx],
InitHeaderSearch::Angled, false, false, false);
++iwithprefixbefore_idx;
- iwithprefixbefore_done =
+ iwithprefixbefore_done =
iwithprefixbefore_idx == iwithprefixbefore_vals.size();
}
}
@@ -1187,37 +1243,18 @@ void InitializeIncludePaths(const char *Argv0, HeaderSearch &Headers,
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);
+ AddClangIncludePaths(Argv0, &Init);
+
+ if (!nostdinc)
+ Init.AddDefaultSystemIncludePaths(Lang, triple);
// 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)
-{
+void InitializePreprocessorInitOptions(PreprocessorInitOptions &InitOpts) {
// Add macros from the command line.
unsigned d = 0, D = D_macros.size();
unsigned u = 0, U = U_macros.size();
@@ -1286,17 +1323,17 @@ class VISIBILITY_HIDDEN DriverPreprocessorFactory : public PreprocessorFactory {
TargetInfo &Target;
SourceManager &SourceMgr;
HeaderSearch &HeaderInfo;
-
+
public:
DriverPreprocessorFactory(Diagnostic &diags, const LangOptions &opts,
TargetInfo &target, SourceManager &SM,
- HeaderSearch &Headers)
+ HeaderSearch &Headers)
: Diags(diags), LangInfo(opts), Target(target),
SourceMgr(SM), HeaderInfo(Headers) {}
-
-
+
+
virtual ~DriverPreprocessorFactory() {}
-
+
virtual Preprocessor* CreatePreprocessor() {
llvm::OwningPtr<PTHManager> PTHMgr;
@@ -1305,23 +1342,23 @@ public:
"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,
+ 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.
@@ -1347,7 +1384,7 @@ public:
static void ParseFile(Preprocessor &PP, MinimalAction *PA) {
Parser P(PP, *PA);
PP.EnterMainSourceFile();
-
+
// Parsing the specified input file.
P.ParseTranslationUnit();
delete PA;
@@ -1384,24 +1421,24 @@ NoImplicitFloat("no-implicit-float",
/// and feature list.
static void ComputeFeatureMap(TargetInfo *Target,
llvm::StringMap<bool> &Features) {
- assert(Features.empty() && "invalid map");
+ 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(),
+ 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",
+ 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",
+ fprintf(stderr, "error: clang-cc: invalid target feature name: %s\n",
Name + 1);
exit(1);
}
@@ -1442,7 +1479,7 @@ static void InitializeCompileOptions(CompileOptions &Opts,
Opts.CPU = TargetCPU;
Opts.Features.clear();
- for (llvm::StringMap<bool>::const_iterator it = Features.begin(),
+ 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.
@@ -1450,9 +1487,9 @@ static void InitializeCompileOptions(CompileOptions &Opts,
Name += it->first();
Opts.Features.push_back(Name);
}
-
+
Opts.NoCommon = NoCommon | LangOpts.CPlusPlus;
-
+
// Handle -ftime-report.
Opts.TimePasses = TimeReport;
@@ -1539,7 +1576,7 @@ clEnumValN(NAME, CMDFLAG, DESC),
#include "clang/Frontend/Analyses.def"
clEnumValEnd));
-static llvm::cl::opt<AnalysisStores>
+static llvm::cl::opt<AnalysisStores>
AnalysisStoreOpt("analyzer-store",
llvm::cl::desc("Source Code Analysis - Abstract Memory Store Models"),
llvm::cl::init(BasicStoreModel),
@@ -1549,7 +1586,7 @@ clEnumValN(NAME##Model, CMDFLAG, DESC),
#include "clang/Frontend/Analyses.def"
clEnumValEnd));
-static llvm::cl::opt<AnalysisConstraints>
+static llvm::cl::opt<AnalysisConstraints>
AnalysisConstraintsOpt("analyzer-constraints",
llvm::cl::desc("Source Code Analysis - Symbolic Constraint Engines"),
llvm::cl::init(RangeConstraintsModel),
@@ -1641,7 +1678,7 @@ class LoggingDiagnosticClient : public DiagnosticClient {
llvm::OwningPtr<DiagnosticClient> Chain1;
llvm::OwningPtr<DiagnosticClient> Chain2;
public:
-
+
LoggingDiagnosticClient(DiagnosticClient *Normal) {
// Output diags both where requested...
Chain1.reset(Normal);
@@ -1655,12 +1692,12 @@ public:
!NoDiagnosticsFixIt,
MessageLength));
}
-
+
virtual void setLangOptions(const LangOptions *LO) {
Chain1->setLangOptions(LO);
Chain2->setLangOptions(LO);
}
-
+
virtual bool IncludeInDiagnosticCounts() const {
return Chain1->IncludeInDiagnosticCounts();
}
@@ -1675,11 +1712,11 @@ public:
static void SetUpBuildDumpLog(unsigned argc, char **argv,
llvm::OwningPtr<DiagnosticClient> &DiagClient) {
-
+
std::string ErrorInfo;
- BuildLogFile = new llvm::raw_fd_ostream(DumpBuildInformation.c_str(), false,
+ BuildLogFile = new llvm::raw_fd_ostream(DumpBuildInformation.c_str(),
ErrorInfo);
-
+
if (!ErrorInfo.empty()) {
llvm::errs() << "error opening -dump-build-information file '"
<< DumpBuildInformation << "', option ignored!\n";
@@ -1693,7 +1730,7 @@ static void SetUpBuildDumpLog(unsigned argc, char **argv,
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()));
@@ -1705,97 +1742,77 @@ static void SetUpBuildDumpLog(unsigned argc, char **argv,
// Main driver
//===----------------------------------------------------------------------===//
-static llvm::raw_ostream* ComputeOutFile(const std::string& InFile,
- const char* Extension,
+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;
+ llvm::raw_ostream *Ret;
std::string OutFile;
- if (OutputFile == "-" || (OutputFile.empty() && InFile == "-")) {
- UseStdout = true;
- } else if (!OutputFile.empty()) {
+ if (!OutputFile.empty())
OutFile = OutputFile;
+ else if (InFile == "-") {
+ OutFile = "-";
} else if (Extension) {
llvm::sys::Path Path(InFile);
Path.eraseSuffix();
Path.appendSuffix(Extension);
- OutFile = Path.toString();
+ OutFile = Path.str();
} else {
- UseStdout = true;
+ OutFile = "-";
}
- 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;
+ std::string Error;
+ Ret = new llvm::raw_fd_ostream(OutFile.c_str(), Error,
+ (Binary ? llvm::raw_fd_ostream::F_Binary : 0));
+ if (!Error.empty()) {
+ // FIXME: Don't fail this way.
+ llvm::errs() << "ERROR: " << Error << "\n";
+ ::exit(1);
}
+ if (OutFile != "-")
+ 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::LLVMContext& Context) {
- llvm::OwningPtr<llvm::raw_ostream> OS;
- llvm::OwningPtr<ASTConsumer> Consumer;
- bool ClearSourceMgr = false;
- FixItRewriter *FixItRewrite = 0;
- bool CompleteTranslationUnit = true;
- llvm::sys::Path OutPath;
-
+static ASTConsumer *CreateConsumerAction(Preprocessor &PP,
+ const std::string &InFile,
+ ProgActions PA,
+ llvm::OwningPtr<llvm::raw_ostream> &OS,
+ llvm::sys::Path &OutPath,
+ const llvm::StringMap<bool> &Features,
+ llvm::LLVMContext& Context) {
switch (PA) {
default:
- fprintf(stderr, "Unexpected program action!\n");
- HadErrors = true;
- return;
+ return 0;
case ASTPrint:
OS.reset(ComputeOutFile(InFile, 0, false, OutPath));
- Consumer.reset(CreateASTPrinter(OS.get()));
- break;
-
+ return CreateASTPrinter(OS.get());
+
case ASTPrintXML:
OS.reset(ComputeOutFile(InFile, "xml", false, OutPath));
- Consumer.reset(CreateASTPrinterXML(OS.get()));
- break;
+ return CreateASTPrinterXML(OS.get());
case ASTDump:
- Consumer.reset(CreateASTDumper());
- break;
+ return CreateASTDumper();
case ASTView:
- Consumer.reset(CreateASTViewer());
- break;
+ return CreateASTViewer();
case PrintDeclContext:
- Consumer.reset(CreateDeclContextPrinter());
- break;
+ return CreateDeclContextPrinter();
- case EmitHTML:
- OS.reset(ComputeOutFile(InFile, 0, true, OutPath));
- Consumer.reset(CreateHTMLPrinter(OS.get(), PP.getDiagnostics(), &PP, &PPF));
- break;
+ case DumpRecordLayouts:
+ return CreateRecordLayoutDumper();
case InheritanceView:
- Consumer.reset(CreateInheritanceViewer(InheritanceViewCls));
- break;
+ return CreateInheritanceViewer(InheritanceViewCls);
case EmitAssembly:
case EmitLLVM:
- case EmitBC:
+ case EmitBC:
case EmitLLVMOnly: {
BackendAction Act;
if (ProgAction == EmitAssembly) {
@@ -1813,36 +1830,71 @@ static void ProcessInputFile(Preprocessor &PP, PreprocessorFactory &PPF,
CompileOptions Opts;
InitializeCompileOptions(Opts, PP.getLangOptions(), Features);
- Consumer.reset(CreateBackendConsumer(Act, PP.getDiagnostics(),
- PP.getLangOptions(), Opts, InFile,
- OS.get(), Context));
- break;
+ return CreateBackendConsumer(Act, PP.getDiagnostics(), PP.getLangOptions(),
+ Opts, InFile, OS.get(), Context);
}
- 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;
+ return CreateObjCRewriter(InFile, OS.get(), PP.getDiagnostics(),
+ PP.getLangOptions(), SilenceRewriteMacroWarning);
case RewriteBlocks:
- Consumer.reset(CreateBlockRewriter(InFile, PP.getDiagnostics(),
- PP.getLangOptions()));
+ return CreateBlockRewriter(InFile, PP.getDiagnostics(),
+ PP.getLangOptions());
+ }
+}
+
+/// 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::LLVMContext& Context) {
+ 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:
+ Consumer.reset(CreateConsumerAction(PP, InFile, PA, OS, OutPath,
+ Features, Context));
+
+ if (!Consumer.get()) {
+ fprintf(stderr, "Unexpected program action!\n");
+ HadErrors = true;
+ return;
+ }
+
+ break;;
+
+ case EmitHTML:
+ OS.reset(ComputeOutFile(InFile, 0, true, OutPath));
+ Consumer.reset(CreateHTMLPrinter(OS.get(), PP.getDiagnostics(), &PP, &PPF));
break;
- case RunAnalysis: {
+ case RunAnalysis:
Consumer.reset(CreateAnalysisConsumer(PP.getDiagnostics(), &PP, &PPF,
PP.getLangOptions(), OutputFile,
ReadAnalyzerOptions()));
break;
- }
+
+ case GeneratePCH:
+ if (RelocatablePCH.getValue() && !isysroot.getNumOccurrences()) {
+ PP.Diag(SourceLocation(), diag::err_relocatable_without_without_isysroot);
+ RelocatablePCH.setValue(false);
+ }
+
+ OS.reset(ComputeOutFile(InFile, 0, true, OutPath));
+ if (RelocatablePCH.getValue())
+ Consumer.reset(CreatePCHGenerator(PP, OS.get(), isysroot.c_str()));
+ else
+ Consumer.reset(CreatePCHGenerator(PP, OS.get()));
+ CompleteTranslationUnit = false;
+ break;
case DumpRawTokens: {
llvm::TimeRegion Timer(ClangFrontendTimer);
@@ -1876,28 +1928,28 @@ static void ProcessInputFile(Preprocessor &PP, PreprocessorFactory &PPF,
}
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";
+ llvm::errs() << "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));
@@ -1911,13 +1963,13 @@ static void ProcessInputFile(Preprocessor &PP, PreprocessorFactory &PPF,
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());
@@ -1943,7 +1995,7 @@ static void ProcessInputFile(Preprocessor &PP, PreprocessorFactory &PPF,
PP.getLangOptions());
bool AddedFixitLocation = false;
- for (unsigned Idx = 0, Last = FixItAtLocations.size();
+ for (unsigned Idx = 0, Last = FixItAtLocations.size();
Idx != Last; ++Idx) {
RequestedSourceLocation Requested;
if (ResolveParsedLocation(FixItAtLocations[Idx],
@@ -1973,13 +2025,19 @@ static void ProcessInputFile(Preprocessor &PP, PreprocessorFactory &PPF,
PP.getBuiltinInfo(),
/* FreeMemory = */ !DisableFree,
/* size_reserve = */0));
-
+
llvm::OwningPtr<PCHReader> Reader;
llvm::OwningPtr<ExternalASTSource> Source;
-
+
if (!ImplicitIncludePCH.empty()) {
- Reader.reset(new PCHReader(PP, ContextOwner.get()));
-
+ // If the user specified -isysroot, it will be used for relocatable PCH
+ // files.
+ const char *isysrootPCH = 0;
+ if (isysroot.getNumOccurrences() != 0)
+ isysrootPCH = isysroot.c_str();
+
+ Reader.reset(new PCHReader(PP, ContextOwner.get(), isysrootPCH));
+
// The user has asked us to include a precompiled header. Load
// the precompiled header into the AST context.
switch (Reader->ReadPCH(ImplicitIncludePCH)) {
@@ -2026,12 +2084,34 @@ static void ProcessInputFile(Preprocessor &PP, PreprocessorFactory &PPF,
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 (Consumer) {
+ CodeCompleteConsumer *(*CreateCodeCompleter)(Sema &, void *) = 0;
+ void *CreateCodeCompleterData = 0;
+
+ if (!CodeCompletionAt.FileName.empty()) {
+ // Tell the source manager to chop off the given file at a specific
+ // line and column.
+ if (const FileEntry *Entry
+ = PP.getFileManager().getFile(CodeCompletionAt.FileName)) {
+ // Truncate the named file at the given line/column.
+ PP.getSourceManager().truncateFileAt(Entry, CodeCompletionAt.Line,
+ CodeCompletionAt.Column);
+
+ // Set up the creation routine for code-completion.
+ CreateCodeCompleter = BuildPrintingCodeCompleter;
+ } else {
+ PP.getDiagnostics().Report(FullSourceLoc(),
+ diag::err_fe_invalid_code_complete_file)
+ << CodeCompletionAt.FileName;
+ }
+ }
+
+ ParseAST(PP, Consumer.get(), *ContextOwner.get(), Stats,
+ CompleteTranslationUnit,
+ CreateCodeCompleter, CreateCodeCompleterData);
+ }
if (PA == RunPreprocessorOnly) { // Just lex as fast as we can, no output.
llvm::TimeRegion Timer(ClangFrontendTimer);
@@ -2056,10 +2136,17 @@ static void ProcessInputFile(Preprocessor &PP, PreprocessorFactory &PPF,
DisableLineMarkers, DumpDefines);
ClearSourceMgr = true;
}
-
+
if (FixItRewrite)
FixItRewrite->WriteFixedFile(InFile, OutputFile);
-
+
+ // Disable the consumer prior to the context, the consumer may perform actions
+ // in its destructor which require the context.
+ if (DisableFree)
+ Consumer.take();
+ else
+ Consumer.reset();
+
// If in -disable-free mode, don't deallocate ASTContext.
if (DisableFree)
ContextOwner.take();
@@ -2079,16 +2166,71 @@ static void ProcessInputFile(Preprocessor &PP, PreprocessorFactory &PPF,
fprintf(stderr, "\n");
}
- // For a multi-file compilation, some things are ok with nuking the source
+ // 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)
+ // 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();
+ }
+}
+
+/// ProcessInputFile - Process a single AST input file with the specified state.
+///
+static void ProcessASTInputFile(const std::string &InFile, ProgActions PA,
+ const llvm::StringMap<bool> &Features,
+ Diagnostic &Diags, FileManager &FileMgr,
+ llvm::LLVMContext& Context) {
+ std::string Error;
+ llvm::OwningPtr<ASTUnit> AST(ASTUnit::LoadFromPCHFile(InFile, Diags, FileMgr,
+ &Error));
+ if (!AST) {
+ Diags.Report(FullSourceLoc(), diag::err_fe_invalid_ast_file) << Error;
+ return;
+ }
+
+ Preprocessor &PP = AST->getPreprocessor();
+
+ llvm::OwningPtr<llvm::raw_ostream> OS;
+ llvm::sys::Path OutPath;
+ llvm::OwningPtr<ASTConsumer> Consumer(CreateConsumerAction(PP, InFile, PA, OS,
+ OutPath, Features,
+ Context));
+
+ if (!Consumer.get()) {
+ Diags.Report(FullSourceLoc(), diag::err_fe_invalid_ast_action);
+ return;
+ }
+
+ // Set the main file ID to an empty file.
+ //
+ // FIXME: We probably shouldn't need this, but for now this is the simplest
+ // way to reuse the logic in ParseAST.
+ const char *EmptyStr = "";
+ llvm::MemoryBuffer *SB =
+ llvm::MemoryBuffer::getMemBuffer(EmptyStr, EmptyStr, "<dummy input>");
+ AST->getSourceManager().createMainFileIDForMemBuffer(SB);
+
+ // Stream the input AST to the consumer.
+ ParseAST(PP, Consumer.get(), AST->getASTContext(), Stats);
+
+ // Release the consumer and the AST, in that order since the consumer may
+ // perform actions in its destructor which require the context.
+ if (DisableFree) {
Consumer.take();
- else
+ AST.take();
+ } else {
Consumer.reset();
+ AST.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.
@@ -2104,23 +2246,35 @@ static void ProcessInputFile(Preprocessor &PP, PreprocessorFactory &PPF,
static llvm::cl::list<std::string>
InputFilenames(llvm::cl::Positional, llvm::cl::desc("<input files>"));
+static void LLVMErrorHandler(void *UserData, const std::string &Message) {
+ Diagnostic &Diags = *static_cast<Diagnostic*>(UserData);
+
+ Diags.Report(FullSourceLoc(), diag::err_fe_error_backend) << Message;
+
+ // We cannot recover from llvm errors.
+ exit(1);
+}
+
int main(int argc, char **argv) {
llvm::sys::PrintStackTraceOnErrorSignal();
llvm::PrettyStackTraceProgram X(argc, argv);
- llvm::LLVMContext Context;
- llvm::cl::ParseCommandLineOptions(argc, argv,
- "LLVM 'Clang' Compiler: http://clang.llvm.org\n");
-
+ llvm::LLVMContext &Context = llvm::getGlobalContext();
+
+ // Initialize targets first, so that --version shows registered targets.
llvm::InitializeAllTargets();
llvm::InitializeAllAsmPrinters();
-
+
+ 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");
-
+ llvm::errs() << "clang-cc version " CLANG_VERSION_STRING
+ << " based upon " << PACKAGE_STRING
+ << " hosted on " << llvm::sys::getHostTriple() << "\n";
+
// If no input was specified, read from stdin.
if (InputFilenames.empty())
InputFilenames.push_back("-");
@@ -2164,17 +2318,17 @@ int main(int argc, char **argv) {
} 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());
@@ -2182,30 +2336,45 @@ int main(int argc, char **argv) {
OptNoWarnings))
return 1;
+ // Set an error handler, so that any LLVM backend diagnostics go through our
+ // error handler.
+ llvm::llvm_install_error_handler(LLVMErrorHandler,
+ static_cast<void*>(&Diags));
+
// -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);
+ 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));
-
+ llvm::Triple Triple = CreateTargetTriple();
+ llvm::OwningPtr<TargetInfo>
+ Target(TargetInfo::CreateTargetInfo(Triple.getTriple()));
+
if (Target == 0) {
- Diags.Report(FullSourceLoc(), diag::err_fe_unknown_triple)
- << Triple.c_str();
+ Diags.Report(FullSourceLoc(), diag::err_fe_unknown_triple)
+ << Triple.getTriple().c_str();
return 1;
}
-
+
+ // Set the target ABI if specified.
+ if (!TargetABI.empty()) {
+ if (!Target->setABI(TargetABI)) {
+ Diags.Report(FullSourceLoc(), diag::err_fe_unknown_target_abi)
+ << TargetABI;
+ 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;
@@ -2215,35 +2384,41 @@ int main(int argc, char **argv) {
for (unsigned i = 0, e = InputFilenames.size(); i != e; ++i) {
const std::string &InFile = InputFilenames[i];
-
+
+ LangKind LK = GetLanguage(InFile);
+ // AST inputs are handled specially.
+ if (LK == langkind_ast) {
+ ProcessASTInputFile(InFile, ProgAction, Features,
+ Diags, FileMgr, Context);
+ continue;
+ }
+
/// 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);
-
+
+
+ InitializeIncludePaths(argv[0], HeaderInfo, FileMgr, LangInfo, Triple);
+
// Set up the preprocessor with these options.
DriverPreprocessorFactory PPFactory(Diags, LangInfo, *Target,
*SourceMgr.get(), HeaderInfo);
-
+
llvm::OwningPtr<Preprocessor> PP(PPFactory.CreatePreprocessor());
-
+
if (!PP)
continue;
@@ -2252,16 +2427,16 @@ int main(int argc, char **argv) {
llvm::raw_ostream *DependencyOS;
if (DependencyTargets.empty()) {
// FIXME: Use a proper diagnostic
- llvm::cerr << "-dependency-file requires at least one -MT option\n";
+ llvm::errs() << "-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);
+ new llvm::raw_fd_ostream(DependencyFile.c_str(), ErrStr);
if (!ErrStr.empty()) {
// FIXME: Use a proper diagnostic
- llvm::cerr << "unable to open dependency file: " + ErrStr;
+ llvm::errs() << "unable to open dependency file: " + ErrStr;
HadErrors = true;
continue;
}
@@ -2274,7 +2449,7 @@ int main(int argc, char **argv) {
if (ImplicitIncludePCH.empty()) {
if (InitializeSourceManager(*PP.get(), InFile))
continue;
-
+
// Initialize builtin info.
PP->getBuiltinInfo().InitializeBuiltins(PP->getIdentifierTable(),
PP->getLangOptions().NoBuiltin);
@@ -2285,7 +2460,7 @@ int main(int argc, char **argv) {
// Process the source file.
ProcessInputFile(*PP, PPFactory, InFile, ProgAction, Features, Context);
-
+
HeaderInfo.ClearFileInfo();
DiagClient->setLangOptions(0);
}
@@ -2294,7 +2469,7 @@ int main(int argc, char **argv) {
if (unsigned NumDiagnostics = Diags.getNumDiagnostics())
fprintf(stderr, "%d diagnostic%s generated.\n", NumDiagnostics,
(NumDiagnostics == 1 ? "" : "s"));
-
+
if (Stats) {
FileMgr.PrintStats();
fprintf(stderr, "\n");
@@ -2302,11 +2477,11 @@ int main(int argc, char **argv) {
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();
diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt
index f170aa2..1ad04c8 100644
--- a/tools/driver/CMakeLists.txt
+++ b/tools/driver/CMakeLists.txt
@@ -13,3 +13,5 @@ add_clang_executable(clang
add_dependencies(clang clang-cc)
+install(TARGETS clang
+ RUNTIME DESTINATION bin)
diff --git a/tools/driver/Makefile b/tools/driver/Makefile
index 8e9c291..4b2fb44 100644
--- a/tools/driver/Makefile
+++ b/tools/driver/Makefile
@@ -21,3 +21,9 @@ LINK_COMPONENTS := system support bitreader bitwriter
USEDLIBS = clangDriver.a clangBasic.a
include $(LEVEL)/Makefile.common
+
+# Translate make variable to define when building a "production" clang.
+ifdef CLANG_IS_PRODUCTION
+CPP.Defines += -DCLANG_IS_PRODUCTION
+endif
+
diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp
index 323283e..9d204ce 100644
--- a/tools/driver/driver.cpp
+++ b/tools/driver/driver.cpp
@@ -34,7 +34,7 @@ class DriverDiagnosticPrinter : public DiagnosticClient {
llvm::raw_ostream &OS;
public:
- DriverDiagnosticPrinter(const std::string _ProgName,
+ DriverDiagnosticPrinter(const std::string _ProgName,
llvm::raw_ostream &_OS)
: ProgName(_ProgName),
OS(_OS) {}
@@ -54,7 +54,7 @@ void DriverDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
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());
@@ -68,7 +68,7 @@ llvm::sys::Path GetExecutablePath(const char *Argv0) {
return llvm::sys::Path::GetMainExecutable(Argv0, P);
}
-static const char *SaveStringInSet(std::set<std::string> &SavedStrings,
+static const char *SaveStringInSet(std::set<std::string> &SavedStrings,
const std::string &S) {
return SavedStrings.insert(S).first->c_str();
}
@@ -79,6 +79,8 @@ static const char *SaveStringInSet(std::set<std::string> &SavedStrings,
/// they are applied in order to the input argument lists. Edits
/// should be one of the following forms:
///
+/// '#': Silence information about the changes to the command line arguments.
+///
/// '^': 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.
@@ -93,61 +95,74 @@ static const char *SaveStringInSet(std::set<std::string> &SavedStrings,
///
/// '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,
+///
+/// \param OS - The stream to write edit information to.
+/// \param Args - The vector of command line arguments.
+/// \param Edit - The override command to perform.
+/// \param SavedStrings - Set to use for storing string representations.
+void ApplyOneQAOverride(llvm::raw_ostream &OS,
+ 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";
- }
+ if (Edit[0] == '^') {
+ const char *Str =
+ SaveStringInSet(SavedStrings, Edit.substr(1, std::string::npos));
+ OS << "### 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));
+ OS << "### 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]) {
+ OS << "### Deleting argument " << Args[i] << '\n';
+ Args.erase(Args.begin() + i);
+ if (Edit[0] == 'X') {
+ if (i < Args.size()) {
+ OS << "### Deleting argument " << Args[i] << '\n';
+ Args.erase(Args.begin() + i);
+ } else
+ OS << "### 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'))))) {
+ OS << "### Deleting argument " << Args[i] << '\n';
+ Args.erase(Args.begin() + i);
+ } else
+ ++i;
+ }
+ OS << "### Adding argument " << Edit << " at end\n";
+ Args.push_back(SaveStringInSet(SavedStrings, '-' + Edit));
+ } else {
+ OS << "### 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";
+ llvm::raw_ostream *OS = &llvm::errs();
+
+ if (OverrideStr[0] == '#') {
+ ++OverrideStr;
+ OS = &llvm::nulls();
+ }
+
+ *OS << "### QA_OVERRIDE_GCC3_OPTIONS: " << OverrideStr << "\n";
// This does not need to be efficient.
@@ -157,7 +172,7 @@ void ApplyQAOverride(std::vector<const char*> &Args, const char *OverrideStr,
if (!End)
End = S + strlen(S);
if (End != S)
- ApplyOneQAOverride(Args, std::string(S, End), SavedStrings);
+ ApplyOneQAOverride(*OS, Args, std::string(S, End), SavedStrings);
S = End;
if (*S != '\0')
++S;
@@ -173,9 +188,14 @@ int main(int argc, const char **argv) {
Diagnostic Diags(&DiagClient);
+#ifdef CLANG_IS_PRODUCTION
+ bool IsProduction = true;
+#else
+ bool IsProduction = false;
+#endif
Driver TheDriver(Path.getBasename().c_str(), Path.getDirname().c_str(),
llvm::sys::getHostTriple().c_str(),
- "a.out", Diags);
+ "a.out", IsProduction, Diags);
llvm::OwningPtr<Compilation> C;
@@ -188,7 +208,7 @@ int main(int argc, const char **argv) {
ApplyQAOverride(StringPointers, OverrideStr, SavedStrings);
- C.reset(TheDriver.BuildCompilation(StringPointers.size(),
+ C.reset(TheDriver.BuildCompilation(StringPointers.size(),
&StringPointers[0]));
} else if (const char *Cur = ::getenv("CCC_ADD_ARGS")) {
std::vector<const char*> StringPointers;
@@ -198,7 +218,7 @@ int main(int argc, const char **argv) {
for (;;) {
const char *Next = strchr(Cur, ',');
-
+
if (Next) {
StringPointers.push_back(SaveStringInSet(SavedStrings,
std::string(Cur, Next)));
@@ -212,7 +232,7 @@ int main(int argc, const char **argv) {
StringPointers.insert(StringPointers.end(), argv + 1, argv + argc);
- C.reset(TheDriver.BuildCompilation(StringPointers.size(),
+ C.reset(TheDriver.BuildCompilation(StringPointers.size(),
&StringPointers[0]));
} else
C.reset(TheDriver.BuildCompilation(argc, argv));
diff --git a/tools/index-test/CMakeLists.txt b/tools/index-test/CMakeLists.txt
index 09f4fc1..9c9656a 100644
--- a/tools/index-test/CMakeLists.txt
+++ b/tools/index-test/CMakeLists.txt
@@ -1,6 +1,7 @@
set(LLVM_NO_RTTI 1)
set( LLVM_USED_LIBS
+ clangIndex
clangFrontend
clangSema
clangAST
@@ -10,6 +11,7 @@ set( LLVM_USED_LIBS
set( LLVM_LINK_COMPONENTS
bitreader
+ mc
)
add_clang_executable(index-test
diff --git a/tools/index-test/Makefile b/tools/index-test/Makefile
index 4fbde29..76602e1 100644
--- a/tools/index-test/Makefile
+++ b/tools/index-test/Makefile
@@ -11,13 +11,14 @@ LEVEL = ../../../..
TOOLNAME = index-test
CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
CXXFLAGS = -fno-rtti
+NO_INSTALL = 1
# No plugins, optimize startup time.
TOOL_NO_EXPORTS = 1
include $(LEVEL)/Makefile.config
-LINK_COMPONENTS := bitreader
-USEDLIBS = clangFrontend.a clangSema.a clangAST.a clangLex.a clangBasic.a
+LINK_COMPONENTS := bitreader mc
+USEDLIBS = clangIndex.a clangFrontend.a clangSema.a clangAST.a clangLex.a clangBasic.a
include $(LLVM_SRC_ROOT)/Makefile.rules
diff --git a/tools/index-test/index-test.cpp b/tools/index-test/index-test.cpp
index 552b7b0..103874c 100644
--- a/tools/index-test/index-test.cpp
+++ b/tools/index-test/index-test.cpp
@@ -17,38 +17,191 @@
//
//===----------------------------------------------------------------------===//
//
-// -point-at [file:column:line]
+// -point-at [file:line:column]
// Point at a declaration/statement/expression. If no other operation is
// specified, prints some info about it.
//
+// -print-refs
+// Print ASTLocations that reference the -point-at node
+//
+// -print-defs
+// Print ASTLocations that define the -point-at node
+//
+// -print-decls
+// Print ASTLocations that declare the -point-at node
+//
//===----------------------------------------------------------------------===//
+#include "clang/Index/Program.h"
+#include "clang/Index/Indexer.h"
+#include "clang/Index/Entity.h"
+#include "clang/Index/TranslationUnit.h"
+#include "clang/Index/ASTLocation.h"
+#include "clang/Index/DeclReferenceMap.h"
+#include "clang/Index/SelectorMap.h"
+#include "clang/Index/Handlers.h"
+#include "clang/Index/Analyzer.h"
+#include "clang/Index/Utils.h"
#include "clang/Frontend/ASTUnit.h"
-#include "clang/Frontend/Utils.h"
#include "clang/Frontend/CommandLineSourceLoc.h"
-#include "clang/AST/Decl.h"
-#include "clang/AST/Stmt.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/ExprObjC.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
-#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/System/Signals.h"
using namespace clang;
+using namespace idx;
+
+class TUnit : public TranslationUnit {
+public:
+ TUnit(ASTUnit *ast, const std::string &filename)
+ : AST(ast), Filename(filename),
+ DeclRefMap(ast->getASTContext()),
+ SelMap(ast->getASTContext()) { }
+ virtual ASTContext &getASTContext() { return AST->getASTContext(); }
+ virtual DeclReferenceMap &getDeclReferenceMap() { return DeclRefMap; }
+ virtual SelectorMap &getSelectorMap() { return SelMap; }
+
+ llvm::OwningPtr<ASTUnit> AST;
+ std::string Filename;
+ DeclReferenceMap DeclRefMap;
+ SelectorMap SelMap;
+};
static llvm::cl::list<ParsedSourceLocation>
PointAtLocation("point-at", llvm::cl::Optional,
llvm::cl::value_desc("source-location"),
llvm::cl::desc("Point at the given source location of the first AST file"));
+enum ProgActions {
+ PrintPoint, // Just print the point-at node
+ PrintRefs, // Print references of the point-at node
+ PrintDefs, // Print definitions of the point-at node
+ PrintDecls // Print declarations of the point-at node
+};
+
+static llvm::cl::opt<ProgActions>
+ProgAction(
+ llvm::cl::desc("Choose action to perform on the pointed-at AST node:"),
+ llvm::cl::ZeroOrMore,
+ llvm::cl::init(PrintPoint),
+ llvm::cl::values(
+ clEnumValN(PrintRefs, "print-refs",
+ "Print references"),
+ clEnumValN(PrintDefs, "print-defs",
+ "Print definitions"),
+ clEnumValN(PrintDecls, "print-decls",
+ "Print declarations"),
+ clEnumValEnd));
+
static llvm::cl::opt<bool>
DisableFree("disable-free",
llvm::cl::desc("Disable freeing of memory on exit"),
llvm::cl::init(false));
+static bool HadErrors = false;
+
+static void ProcessObjCMessage(ObjCMessageExpr *Msg, Indexer &Idxer) {
+ llvm::raw_ostream &OS = llvm::outs();
+ typedef Storing<TULocationHandler> ResultsTy;
+ ResultsTy Results;
+
+ Analyzer Analyz(Idxer.getProgram(), Idxer);
+
+ switch (ProgAction) {
+ default: assert(0);
+ case PrintRefs:
+ llvm::errs() << "Error: Cannot -print-refs on a ObjC message expression\n";
+ HadErrors = true;
+ return;
+
+ case PrintDecls: {
+ Analyz.FindObjCMethods(Msg, Results);
+ for (ResultsTy::iterator
+ I = Results.begin(), E = Results.end(); I != E; ++I)
+ I->print(OS);
+ break;
+ }
+
+ case PrintDefs: {
+ Analyz.FindObjCMethods(Msg, Results);
+ for (ResultsTy::iterator
+ I = Results.begin(), E = Results.end(); I != E; ++I) {
+ const ObjCMethodDecl *D = cast<ObjCMethodDecl>(I->AsDecl());
+ if (D->isThisDeclarationADefinition())
+ I->print(OS);
+ }
+ break;
+ }
+
+ }
+}
+
+static void ProcessASTLocation(ASTLocation ASTLoc, Indexer &Idxer) {
+ assert(ASTLoc.isValid());
+
+ if (ObjCMessageExpr *Msg =
+ dyn_cast_or_null<ObjCMessageExpr>(ASTLoc.dyn_AsStmt()))
+ return ProcessObjCMessage(Msg, Idxer);
+
+ Decl *D = ASTLoc.getReferencedDecl();
+ if (D == 0) {
+ llvm::errs() << "Error: Couldn't get referenced Decl for the ASTLocation\n";
+ HadErrors = true;
+ return;
+ }
+
+ llvm::raw_ostream &OS = llvm::outs();
+ typedef Storing<TULocationHandler> ResultsTy;
+ ResultsTy Results;
+
+ Analyzer Analyz(Idxer.getProgram(), Idxer);
+
+ switch (ProgAction) {
+ default: assert(0);
+ case PrintRefs: {
+ Analyz.FindReferences(D, Results);
+ for (ResultsTy::iterator
+ I = Results.begin(), E = Results.end(); I != E; ++I)
+ I->print(OS);
+ break;
+ }
+
+ case PrintDecls: {
+ Analyz.FindDeclarations(D, Results);
+ for (ResultsTy::iterator
+ I = Results.begin(), E = Results.end(); I != E; ++I)
+ I->print(OS);
+ break;
+ }
+
+ case PrintDefs: {
+ Analyz.FindDeclarations(D, Results);
+ for (ResultsTy::iterator
+ I = Results.begin(), E = Results.end(); I != E; ++I) {
+ const Decl *D = I->AsDecl();
+ bool isDef = false;
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ isDef = FD->isThisDeclarationADefinition();
+ else if (const VarDecl *VD = dyn_cast<VarDecl>(D))
+ isDef = VD->getInit() != 0;
+ else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
+ isDef = MD->isThisDeclarationADefinition();
+
+ if (isDef)
+ I->print(OS);
+ }
+ break;
+ }
+
+ }
+}
+
static llvm::cl::list<std::string>
InputFilenames(llvm::cl::Positional, llvm::cl::desc("<input AST files>"));
@@ -57,97 +210,99 @@ int main(int argc, char **argv) {
llvm::PrettyStackTraceProgram X(argc, argv);
llvm::cl::ParseCommandLineOptions(argc, argv,
"LLVM 'Clang' Indexing Test Bed: http://clang.llvm.org\n");
-
- FileManager FileMgr;
-
+
+ Program Prog;
+ Indexer Idxer(Prog);
+ llvm::SmallVector<TUnit*, 4> TUnits;
+
// If no input was specified, read from stdin.
if (InputFilenames.empty())
InputFilenames.push_back("-");
- // FIXME: Only the first AST file is used for now.
+ for (unsigned i = 0, e = InputFilenames.size(); i != e; ++i) {
+ const std::string &InFile = InputFilenames[i];
- const std::string &InFile = InputFilenames[0];
-
- std::string ErrMsg;
- llvm::OwningPtr<ASTUnit> AST;
+ std::string ErrMsg;
+ llvm::OwningPtr<ASTUnit> AST;
- AST.reset(ASTUnit::LoadFromPCHFile(InFile, FileMgr, &ErrMsg));
- if (!AST) {
- llvm::errs() << "[" << InFile << "] Error: " << ErrMsg << '\n';
- return 1;
+ AST.reset(ASTUnit::LoadFromPCHFile(InFile, Idxer.getDiagnostics(),
+ Idxer.getFileManager(), &ErrMsg));
+ if (!AST) {
+ llvm::errs() << "[" << InFile << "] Error: " << ErrMsg << '\n';
+ return 1;
+ }
+
+ TUnit *TU = new TUnit(AST.take(), InFile);
+ TUnits.push_back(TU);
+
+ Idxer.IndexAST(TU);
}
- struct ASTPoint {
- Decl *D;
- Stmt *Node;
- ASTPoint() : D(0), Node(0) {}
- };
-
- ASTPoint Point;
+ ASTLocation ASTLoc;
+ const std::string &FirstFile = TUnits[0]->Filename;
+ ASTUnit *FirstAST = TUnits[0]->AST.get();
if (!PointAtLocation.empty()) {
const std::string &Filename = PointAtLocation[0].FileName;
- const FileEntry *File = FileMgr.getFile(Filename);
+ const FileEntry *File = Idxer.getFileManager().getFile(Filename);
+ if (File == 0) {
+ llvm::errs() << "File '" << Filename << "' does not exist\n";
+ return 1;
+ }
// Safety check. Using an out-of-date AST file will only lead to crashes
// or incorrect results.
// FIXME: Check all the source files that make up the AST file.
- const FileEntry *ASTFile = FileMgr.getFile(InFile);
+ const FileEntry *ASTFile = Idxer.getFileManager().getFile(FirstFile);
if (File->getModificationTime() > ASTFile->getModificationTime()) {
- llvm::errs() << "[" << InFile << "] Error: " <<
+ llvm::errs() << "[" << FirstFile << "] Error: " <<
"Pointing at a source file which was modified after creating "
"the AST file\n";
return 1;
}
- if (File == 0) {
- llvm::errs() << "File '" << Filename << "' does not exist\n";
- return 1;
- }
unsigned Line = PointAtLocation[0].Line;
unsigned Col = PointAtLocation[0].Column;
- SourceLocation Loc = AST->getSourceManager().getLocation(File, Line, Col);
+ SourceLocation Loc =
+ FirstAST->getSourceManager().getLocation(File, Line, Col);
if (Loc.isInvalid()) {
- llvm::errs() << "[" << InFile << "] Error: " <<
+ llvm::errs() << "[" << FirstFile << "] Error: " <<
"Couldn't resolve source location (invalid location)\n";
return 1;
}
-
- llvm::tie(Point.D, Point.Node) =
- ResolveLocationInAST(AST->getASTContext(), Loc);
- if (Point.D == 0) {
- llvm::errs() << "[" << InFile << "] Error: " <<
+
+ ASTLoc = ResolveLocationInAST(FirstAST->getASTContext(), Loc);
+ if (ASTLoc.isInvalid()) {
+ llvm::errs() << "[" << FirstFile << "] Error: " <<
"Couldn't resolve source location (no declaration found)\n";
return 1;
}
}
-
- if (Point.D) {
- llvm::raw_ostream &OS = llvm::outs();
- OS << "Declaration node at point: " << Point.D->getDeclKindName() << " ";
- if (NamedDecl *ND = dyn_cast<NamedDecl>(Point.D))
- OS << ND->getNameAsString();
- OS << "\n";
-
- if (const char *Comment = AST->getASTContext().getCommentForDecl(Point.D))
- OS << "Comment associated with this declaration:\n" << Comment << "\n";
-
- if (Point.Node) {
- OS << "Statement node at point: " << Point.Node->getStmtClassName()
- << " ";
- Point.Node->printPretty(OS, AST->getASTContext(), 0,
- PrintingPolicy(AST->getASTContext().getLangOptions()));
- OS << "\n";
+
+ if (ASTLoc.isValid()) {
+ if (ProgAction == PrintPoint) {
+ llvm::raw_ostream &OS = llvm::outs();
+ ASTLoc.print(OS);
+ if (const char *Comment =
+ FirstAST->getASTContext().getCommentForDecl(ASTLoc.dyn_AsDecl()))
+ OS << "Comment associated with this declaration:\n" << Comment << "\n";
+ } else {
+ ProcessASTLocation(ASTLoc, Idxer);
}
}
- if (DisableFree)
- AST.take();
+ if (HadErrors)
+ return 1;
+
+ if (!DisableFree) {
+ for (int i=0, e=TUnits.size(); i != e; ++i)
+ delete TUnits[i];
+ }
// Managed static deconstruction. Useful for making things like
// -time-passes usable.
llvm::llvm_shutdown();
-
+
return 0;
}
diff --git a/tools/wpa/CMakeLists.txt b/tools/wpa/CMakeLists.txt
new file mode 100644
index 0000000..5553474
--- /dev/null
+++ b/tools/wpa/CMakeLists.txt
@@ -0,0 +1,20 @@
+set(LLVM_NO_RTTI 1)
+
+set( LLVM_USED_LIBS
+ clangFrontend
+ clangAnalysis
+ clangSema
+ clangAST
+ clangLex
+ clangBasic
+ clangIndex
+ )
+
+set( LLVM_LINK_COMPONENTS
+ mc
+ )
+
+add_clang_executable(clang-wpa
+ clang-wpa.cpp
+ )
+add_dependencies(clang-wpa clang-headers)
diff --git a/tools/wpa/Makefile b/tools/wpa/Makefile
new file mode 100644
index 0000000..01dbd11
--- /dev/null
+++ b/tools/wpa/Makefile
@@ -0,0 +1,16 @@
+LEVEL = ../../../..
+
+TOOLNAME = clang-wpa
+CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
+CXXFLAGS = -fno-rtti
+NO_INSTALL = 1
+
+# No plugins, optimize startup time.
+TOOL_NO_EXPORTS = 1
+
+include $(LEVEL)/Makefile.config
+
+LINK_COMPONENTS := bitreader mc
+USEDLIBS = clangFrontend.a clangSema.a clangAST.a clangLex.a clangBasic.a clangAnalysis.a clangIndex.a
+
+include $(LLVM_SRC_ROOT)/Makefile.rules
diff --git a/tools/wpa/clang-wpa.cpp b/tools/wpa/clang-wpa.cpp
new file mode 100644
index 0000000..fa2326d
--- /dev/null
+++ b/tools/wpa/clang-wpa.cpp
@@ -0,0 +1,62 @@
+//===--- clang-wpa.cpp - clang whole program analyzer ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This tool reads a sequence of precompiled AST files, and do various
+// cross translation unit analyses.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/CallGraph.h"
+
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Frontend/TextDiagnosticBuffer.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+using namespace idx;
+
+static llvm::cl::list<std::string>
+InputFilenames(llvm::cl::Positional, llvm::cl::desc("<input AST files>"));
+
+int main(int argc, char **argv) {
+ llvm::cl::ParseCommandLineOptions(argc, argv, "clang-wpa");
+ FileManager FileMgr;
+ std::vector<ASTUnit*> ASTUnits;
+
+ if (InputFilenames.empty())
+ return 0;
+
+ TextDiagnosticBuffer DiagClient;
+ Diagnostic Diags(&DiagClient);
+
+ for (unsigned i = 0, e = InputFilenames.size(); i != e; ++i) {
+ const std::string &InFile = InputFilenames[i];
+
+ std::string ErrMsg;
+ llvm::OwningPtr<ASTUnit> AST;
+
+ AST.reset(ASTUnit::LoadFromPCHFile(InFile, Diags, FileMgr, &ErrMsg));
+
+ if (!AST) {
+ llvm::errs() << "[" << InFile << "] error: " << ErrMsg << '\n';
+ return 1;
+ }
+
+ ASTUnits.push_back(AST.take());
+ }
+
+ llvm::OwningPtr<CallGraph> CG;
+ CG.reset(new CallGraph());
+
+ for (unsigned i = 0, e = ASTUnits.size(); i != e; ++i)
+ CG->addTU(*ASTUnits[i]);
+
+ CG->ViewCallGraph();
+}
diff --git a/utils/ABITest/ABITestGen.py b/utils/ABITest/ABITestGen.py
index 5598caa..63da02b 100755
--- a/utils/ABITest/ABITestGen.py
+++ b/utils/ABITest/ABITestGen.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
from pprint import pprint
import random, atexit, time
diff --git a/utils/C++Tests/LLVM-Syntax/lit.local.cfg b/utils/C++Tests/LLVM-Syntax/lit.local.cfg
new file mode 100644
index 0000000..69f010e
--- /dev/null
+++ b/utils/C++Tests/LLVM-Syntax/lit.local.cfg
@@ -0,0 +1,22 @@
+# -*- Python -*-
+
+# Configuration file for the 'lit' test runner.
+
+def getRoot(config):
+ if not config.parent:
+ return config
+ return getRoot(config.parent)
+
+root = getRoot(config)
+
+# testFormat: The test format to use to interpret tests.
+config.test_format = lit.formats.SyntaxCheckTest(compiler=root.clang,
+ dir='%s/include/llvm' % root.llvm_src_root,
+ recursive=False,
+ pattern='^(.*\\.h|[^.]*)$',
+ extra_cxx_args=['-D__STDC_LIMIT_MACROS',
+ '-D__STDC_CONSTANT_MACROS',
+ '-I%s/include' % root.llvm_src_root,
+ '-I%s/include' % root.llvm_obj_root])
+
+config.excludes = ['AbstractTypeUser.h']
diff --git a/utils/C++Tests/lit.cfg b/utils/C++Tests/lit.cfg
new file mode 100644
index 0000000..a727622
--- /dev/null
+++ b/utils/C++Tests/lit.cfg
@@ -0,0 +1,18 @@
+# -*- Python -*-
+
+# Configuration file for the 'lit' test runner.
+
+# Load the main clang test config so we can leech its clang finding logic.
+lit.load_config(config, os.path.join(os.path.dirname(__file__),
+ '..', '..', 'test', 'lit.cfg'))
+assert config.clang, "Failed to set clang!?"
+
+# name: The name of this test suite.
+config.name = 'Clang++'
+
+# suffixes: A list of file extensions to treat as test files, this is actually
+# set by on_clone().
+config.suffixes = []
+
+# Reset these from the Clang config.
+config.test_source_root = config.test_exec_root = None
diff --git a/utils/C++Tests/stdc++-Syntax/lit.local.cfg b/utils/C++Tests/stdc++-Syntax/lit.local.cfg
new file mode 100644
index 0000000..eb04866
--- /dev/null
+++ b/utils/C++Tests/stdc++-Syntax/lit.local.cfg
@@ -0,0 +1,17 @@
+# -*- Python -*-
+
+# Configuration file for the 'lit' test runner.
+
+def getRoot(config):
+ if not config.parent:
+ return config
+ return getRoot(config.parent)
+
+root = getRoot(config)
+
+# testFormat: The test format to use to interpret tests.
+config.test_format = lit.formats.SyntaxCheckTest(compiler=root.clang,
+ dir='/usr/include/c++/4.2.1',
+ recursive=False,
+ pattern='^(.*\\.h|[^.]*)$')
+
diff --git a/utils/CaptureCmd b/utils/CaptureCmd
index 3bce357..705585c 100755
--- a/utils/CaptureCmd
+++ b/utils/CaptureCmd
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
"""CaptureCmd - A generic tool for capturing information about the
invocations of another program.
diff --git a/utils/CmpDriver b/utils/CmpDriver
index 97c91a8..16b1081 100755
--- a/utils/CmpDriver
+++ b/utils/CmpDriver
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
import subprocess
@@ -33,36 +33,26 @@ def insertMinimumPadding(a, b, dist):
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]
+ def cost(a, b):
+ return sum(map(dist, a + [None] * (len(b) - len(a)), b))
+
+ # Normalize so a is shortest.
+ if len(b) < len(a):
+ b, a = insertMinimumPadding(b, a, dist)
+ return a,b
+
+ # For each None we have to insert...
+ for i in range(len(b) - len(a)):
+ # For each position we could insert it...
+ current = cost(a, b)
+ best = None
+ for j in range(len(a) + 1):
+ a_0 = a[:j] + [None] + a[j:]
+ candidate = cost(a_0, b)
+ if best is None or candidate < best[0]:
+ best = (candidate, a_0, j)
+ a = best[1]
+ return a,b
class ZipperDiff(object):
"""ZipperDiff - Simple (slow) diff only accomodating inserts."""
@@ -107,7 +97,7 @@ class CompileInfo:
ln.startswith('Configured with: ') or
ln.startswith('Thread model: ') or
ln.startswith('gcc version') or
- ln.startswith('ccc version')):
+ ln.startswith('clang version')):
pass
elif ln.strip().startswith('"'):
self.commands.append(list(splitArgs(ln)))
@@ -131,7 +121,7 @@ def main():
args = sys.argv[1:]
driverA = os.getenv('DRIVER_A') or 'gcc'
- driverB = os.getenv('DRIVER_B') or 'xcc'
+ driverB = os.getenv('DRIVER_B') or 'clang'
infoA = captureDriverInfo(driverA, args)
infoB = captureDriverInfo(driverB, args)
@@ -141,15 +131,41 @@ def main():
# Compare stdout.
if infoA.stdout != infoB.stdout:
print '-- STDOUT DIFFERS -'
- print 'A: ',infoA.stdout
- print 'B: ',infoB.stdout
+ print 'A OUTPUT: ',infoA.stdout
+ print 'B OUTPUT: ',infoB.stdout
+ print
+
+ diff = ZipperDiff(infoA.stdout.split('\n'),
+ infoB.stdout.split('\n'))
+ for i,(aElt,bElt) in enumerate(diff.getDiffs()):
+ 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 stderr.
if infoA.stderr != infoB.stderr:
print '-- STDERR DIFFERS -'
- print 'A: ',infoA.stderr
- print 'B: ',infoB.stderr
+ print 'A STDERR: ',infoA.stderr
+ print 'B STDERR: ',infoB.stderr
+ print
+
+ diff = ZipperDiff(infoA.stderr.split('\n'),
+ infoB.stderr.split('\n'))
+ for i,(aElt,bElt) in enumerate(diff.getDiffs()):
+ 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 commands.
@@ -191,4 +207,4 @@ def main():
sys.exit(1)
if __name__ == '__main__':
- main()
+ main()
diff --git a/utils/FindSpecRefs b/utils/FindSpecRefs
index c74ca3d..9097f93 100755
--- a/utils/FindSpecRefs
+++ b/utils/FindSpecRefs
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
import os
import re
diff --git a/utils/SummarizeErrors b/utils/SummarizeErrors
index 64d7824..b6e9122 100755
--- a/utils/SummarizeErrors
+++ b/utils/SummarizeErrors
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
import os, sys, re
diff --git a/utils/analyzer/CmpRuns b/utils/analyzer/CmpRuns
new file mode 100755
index 0000000..739d584
--- /dev/null
+++ b/utils/analyzer/CmpRuns
@@ -0,0 +1,230 @@
+#!/usr/bin/env python
+
+"""
+CmpRuns - A simple tool for comparing two static analyzer runs to determine
+which reports have been added, removed, or changed.
+
+This is designed to support automated testing using the static analyzer, from
+two perspectives:
+ 1. To monitor changes in the static analyzer's reports on real code bases, for
+ regression testing.
+
+ 2. For use by end users who want to integrate regular static analyzer testing
+ into a buildbot like environment.
+"""
+
+import os
+import plistlib
+
+#
+
+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)
+ def get(self, key, default=None):
+ return self.data.get(key, default)
+
+#
+
+class AnalysisReport:
+ def __init__(self, run, files):
+ self.run = run
+ self.files = files
+
+class AnalysisDiagnostic:
+ def __init__(self, data, report, htmlReport):
+ self.data = data
+ self.report = report
+ self.htmlReport = htmlReport
+
+ def getReadableName(self):
+ loc = self.data['location']
+ filename = self.report.run.getSourceName(self.report.files[loc['file']])
+ line = loc['line']
+ column = loc['col']
+
+ # FIXME: Get a report number based on this key, to 'distinguish'
+ # reports, or something.
+
+ return '%s:%d:%d' % (filename, line, column)
+
+ def getReportData(self):
+ if self.htmlReport is None:
+ return "This diagnostic does not have any report data."
+
+ return open(os.path.join(self.report.run.path,
+ self.htmlReport), "rb").read()
+
+class AnalysisRun:
+ def __init__(self, path, opts):
+ self.path = path
+ self.reports = []
+ self.diagnostics = []
+ self.opts = opts
+
+ def getSourceName(self, path):
+ if path.startswith(self.opts.root):
+ return path[len(self.opts.root):]
+ return path
+
+def loadResults(path, opts):
+ run = AnalysisRun(path, opts)
+
+ for f in os.listdir(path):
+ if (not f.startswith('report') or
+ not f.endswith('plist')):
+ continue
+
+ p = os.path.join(path, f)
+ data = plistlib.readPlist(p)
+
+ # Ignore empty reports.
+ if not data['files']:
+ continue
+
+ # Extract the HTML reports, if they exists.
+ if 'HTMLDiagnostics_files' in data['diagnostics'][0]:
+ htmlFiles = []
+ for d in data['diagnostics']:
+ # FIXME: Why is this named files, when does it have multiple
+ # files?
+ assert len(d['HTMLDiagnostics_files']) == 1
+ htmlFiles.append(d.pop('HTMLDiagnostics_files')[0])
+ else:
+ htmlFiles = [None] * len(data['diagnostics'])
+
+ report = AnalysisReport(run, data.pop('files'))
+ diagnostics = [AnalysisDiagnostic(d, report, h)
+ for d,h in zip(data.pop('diagnostics'),
+ htmlFiles)]
+
+ assert not data
+
+ run.reports.append(report)
+ run.diagnostics.extend(diagnostics)
+
+ return run
+
+def compareResults(A, B):
+ """
+ compareResults - Generate a relation from diagnostics in run A to
+ diagnostics in run B.
+
+ The result is the relation as a list of triples (a, b, confidence) where
+ each element {a,b} is None or an element from the respective run, and
+ confidence is a measure of the match quality (where 0 indicates equality,
+ and None is used if either element is None).
+ """
+
+ res = []
+
+ # Quickly eliminate equal elements.
+ neqA = []
+ neqB = []
+ eltsA = list(A.diagnostics)
+ eltsB = list(B.diagnostics)
+ eltsA.sort(key = lambda d: d.data)
+ eltsB.sort(key = lambda d: d.data)
+ while eltsA and eltsB:
+ a = eltsA.pop()
+ b = eltsB.pop()
+ if a.data == b.data:
+ res.append((a, b, 0))
+ elif a.data > b.data:
+ neqA.append(a)
+ eltsB.append(b)
+ else:
+ neqB.append(b)
+ eltsA.append(a)
+ neqA.extend(eltsA)
+ neqB.extend(eltsB)
+
+ # FIXME: Add fuzzy matching. One simple and possible effective idea would be
+ # to bin the diagnostics, print them in a normalized form (based solely on
+ # the structure of the diagnostic), compute the diff, then use that as the
+ # basis for matching. This has the nice property that we don't depend in any
+ # way on the diagnostic format.
+
+ for a in neqA:
+ res.append((a, None, None))
+ for b in neqB:
+ res.append((None, b, None))
+
+ return res
+
+def main():
+ from optparse import OptionParser
+ parser = OptionParser("usage: %prog [options] [dir A] [dir B]")
+ parser.add_option("", "--root", dest="root",
+ help="Prefix to ignore on source files",
+ action="store", type=str, default="")
+ parser.add_option("", "--verbose-log", dest="verboseLog",
+ help="Write additional information to LOG [default=None]",
+ action="store", type=str, default=None,
+ metavar="LOG")
+ (opts, args) = parser.parse_args()
+
+ if len(args) != 2:
+ parser.error("invalid number of arguments")
+
+ dirA,dirB = args
+
+ # Load the run results.
+ resultsA = loadResults(dirA, opts)
+ resultsB = loadResults(dirB, opts)
+
+ # Open the verbose log, if given.
+ if opts.verboseLog:
+ auxLog = open(opts.verboseLog, "wb")
+ else:
+ auxLog = None
+
+ diff = compareResults(resultsA, resultsB)
+ for res in diff:
+ a,b,confidence = res
+ if a is None:
+ print "ADDED: %r" % b.getReadableName()
+ if auxLog:
+ print >>auxLog, ("('ADDED', %r, %r)" % (b.getReadableName(),
+ b.getReportData()))
+ elif b is None:
+ print "REMOVED: %r" % a.getReadableName()
+ if auxLog:
+ print >>auxLog, ("('REMOVED', %r, %r)" % (a.getReadableName(),
+ a.getReportData()))
+ elif confidence:
+ print "CHANGED: %r to %r" % (a.getReadableName(),
+ b.getReadableName())
+ if auxLog:
+ print >>auxLog, ("('CHANGED', %r, %r, %r, %r)"
+ % (a.getReadableName(),
+ b.getReadableName(),
+ a.getReportData(),
+ b.getReportData()))
+ else:
+ pass
+
+ print "TOTAL REPORTS: %r" % len(resultsB.diagnostics)
+ if auxLog:
+ print >>auxLog, "('TOTAL', %r)" % len(resultsB.diagnostics)
+
+if __name__ == '__main__':
+ main()
diff --git a/utils/ccc-analyzer b/utils/ccc-analyzer
index e4bf415..ddc5030 100755
--- a/utils/ccc-analyzer
+++ b/utils/ccc-analyzer
@@ -22,6 +22,10 @@ use Text::ParseWords;
my $CC = $ENV{'CCC_CC'};
if (!defined $CC) { $CC = "gcc"; }
+
+my $ReportFailures = $ENV{'CCC_REPORT_FAILURES'};
+if (!defined $ReportFailures) { $ReportFailures = 1; }
+
my $CleanupFile;
my $ResultFile;
@@ -61,18 +65,12 @@ sub ProcessClangFailure {
$prefix = "clang_attribute_ignored";
}
- # Generate the preprocessed file with cc (i.e., gcc).
+ # Generate the preprocessed file with Clang.
my ($PPH, $PPFile) = tempfile( $prefix . "_XXXXXX",
SUFFIX => GetPPExt($Lang),
DIR => $Dir);
-
- system $CC, @$Args, "-E", "-o", $PPFile;
+ system $ClangCC, @$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";
@@ -172,6 +170,17 @@ sub Analyze {
my @PrintArgs;
my $dir;
+
+ if ($RunAnalyzer) {
+ if (defined $ResultFile) {
+ push @CmdArgs,'-o';
+ push @CmdArgs, $ResultFile;
+ }
+ elsif (defined $HtmlDir) {
+ push @CmdArgs,'-o';
+ push @CmdArgs, $HtmlDir;
+ }
+ }
if ($Verbose) {
$dir = getcwd();
@@ -190,17 +199,6 @@ sub Analyze {
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";
}
@@ -231,59 +229,61 @@ sub Analyze {
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);
+ if ($ReportFailures) {
+ if ($Result & 127 and $Cmd eq $ClangCC and defined $HtmlDir) {
+ ProcessClangFailure($ClangCC, $Lang, $file, \@CmdArgsSansAnalyses,
+ $HtmlDir, "Crash", $ofile);
}
- }
- else {
- # Check if there were any unhandled attributes.
- if (open(CHILD, $ofile)) {
- my %attributes_not_handled;
+ 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;
+ # 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/);
+ 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;
+ # 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";
+ # 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);
+ # 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);
+ # 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);
}
-
- mkpath $dir;
- open(AFILE, ">$afile");
- print AFILE "$ppfile\n";
- close(AFILE);
+ close CHILD;
}
- close CHILD;
}
}
- `rm -f $ofile`;
+ unlink($ofile);
}
##----------------------------------------------------------------------------##
@@ -378,7 +378,7 @@ if (!defined($Analyses)) { $Analyses = '-checker-cfref'; }
# Get the store model.
my $StoreModel = $ENV{'CCC_ANALYZER_STORE_MODEL'};
-if (!defined $StoreModel) { $StoreModel = "basic"; }
+if (!defined $StoreModel) { $StoreModel = "region"; }
# Get the constraints engine.
my $ConstraintsModel = $ENV{'CCC_ANALYZER_CONSTRAINTS_MODEL'};
@@ -410,7 +410,7 @@ foreach (my $i = 0; $i < scalar(@ARGV); ++$i) {
my ($ArgKey) = split /=/,$Arg,2;
# Modes ccc-analyzer supports
- if ($Arg eq '-E') { $Action = 'preprocess'; }
+ if ($Arg =~ /^-(E|MM?)$/) { $Action = 'preprocess'; }
elsif ($Arg eq '-c') { $Action = 'compile'; }
elsif ($Arg =~ /^-print-prog-name/) { exit 0; }
@@ -539,11 +539,20 @@ foreach (my $i = 0; $i < scalar(@ARGV); ++$i) {
open(IN, $ARGV[$i+1]);
while (<IN>) { s/\015?\012//; push @Files,$_; }
close(IN);
- ++$i; next;
+ ++$i;
+ next;
}
+ # Handle -Wno-. We don't care about extra warnings, but
+ # we should suppress ones that we don't want to see.
+ if ($Arg =~ /^-Wno-/) {
+ push @CompileOpts, $Arg;
+ next;
+ }
+
if (!($Arg =~ /^-/)) {
- push @Files,$Arg; next;
+ push @Files, $Arg;
+ next;
}
}
@@ -584,7 +593,7 @@ if ($Action eq 'compile' or $Action eq 'link') {
if (defined $OutputFormat) {
push @AnalyzeArgs, "-analyzer-output=" . $OutputFormat;
- if ($OutputFormat eq "plist") {
+ if ($OutputFormat =~ /plist/) {
# Change "Output" to be a file.
my ($h, $f) = tempfile("report-XXXXXX", SUFFIX => ".plist",
DIR => $HtmlDir);
diff --git a/utils/clang-completion-mode.el b/utils/clang-completion-mode.el
new file mode 100644
index 0000000..690fcda
--- /dev/null
+++ b/utils/clang-completion-mode.el
@@ -0,0 +1,257 @@
+;;; Clang Code-Completion minor mode, for use with C/Objective-C/C++.
+
+;;; Commentary:
+
+;; This minor mode uses Clang's command line interface for code
+;; completion to provide code completion results for C, Objective-C,
+;; and C++ source files. When enabled, Clang will provide
+;; code-completion results in a secondary buffer based on the code
+;; being typed. For example, after typing "struct " (triggered via the
+;; space), Clang will provide the names of all structs visible from
+;; the current scope. After typing "p->" (triggered via the ">"),
+;; Clang will provide the names of all of the members of whatever
+;; class/struct/union "p" points to. Note that this minor mode isn't
+;; meant for serious use: it is meant to help experiment with code
+;; completion based on Clang. It needs your help to make it better!
+;;
+;; To use the Clang code completion mode, first make sure that the
+;; "clang-cc" variable below refers to the "clang-cc" executable,
+;; which is typically installed in libexec/. Then, place
+;; clang-completion-mode.el somewhere in your Emacs load path. You can
+;; add a new load path to Emacs by adding some like the following to
+;; your .emacs:
+;;
+;; (setq load-path (cons "~/.emacs.d" load-path))
+;;
+;; Then, use
+;;
+;; M-x load-library
+;;
+;; to load the library in your Emacs session or add the following to
+;; your .emacs to always load this mode (not recommended):
+;;
+;; (load-library "clang-completion-mode")
+;;
+;; Finally, to try Clang-based code completion in a particular buffer,
+;; use M-x clang-completion-mode. When "Clang-CC" shows up in the mode
+;; line, Clang's code-completion is enabled.
+;;
+;; Clang's code completion is based on parsing the complete source
+;; file up to the point where the cursor is located. Therefore, Clang
+;; needs all of the various compilation flags (include paths, dialect
+;; options, etc.) to provide code-completion results. Currently, these
+;; need to be placed into the clang-cc-flags variable in a format
+;; acceptable to clang-cc. This is a hack: patches are welcome to
+;; improve the interface between this Emacs mode and Clang!
+;;
+
+;;; Code:
+;;; The clang-cc executable
+(defcustom clang-cc "clang-cc"
+ "The location of the clang-cc executable of the Clang compiler.
+This executable is typically installed into the libexec subdirectory."
+ :type 'file
+ :group 'clang-completion-mode)
+
+;;; Extra compilation flags to pass to clang-cc.
+(defcustom clang-cc-flags ""
+ "Extra flags to pass to the Clang executable.
+This variable will typically contain include paths, e.g., -I~/MyProject."
+ :type 'string
+ :group 'clang-completion-mode)
+
+;;; The prefix header to use with Clang code completion.
+(setq clang-completion-prefix-header "")
+
+;;; The substring we will use to filter completion results
+(setq clang-completion-substring "")
+
+;;; The current completion buffer
+(setq clang-completion-buffer nil)
+
+(setq clang-cc-result-string "")
+
+;;; Compute the current line in the buffer
+(defun current-line ()
+ "Return the vertical position of point..."
+ (+ (count-lines (point-min) (point))
+ (if (= (current-column) 0) 1 0)
+ -1))
+
+;;; Set the Clang prefix header
+(defun clang-prefix-header ()
+ (interactive)
+ (setq clang-completion-prefix-header
+ (read-string "Clang prefix header> " "" clang-completion-prefix-header
+ "")))
+
+;; Process "filter" that keeps track of the code-completion results
+;; produced. We store all of the results in a string, then the
+;; sentinel processes the entire string at once.
+(defun clang-completion-stash-filter (proc string)
+ (setq clang-cc-result-string (concat clang-cc-result-string string)))
+
+;; Filter the given list based on a predicate.
+(defun filter (condp lst)
+ (delq nil
+ (mapcar (lambda (x) (and (funcall condp x) x)) lst)))
+
+;; Determine whether
+(defun is-completion-line (line)
+ (or (string-match "OVERLOAD:" line)
+ (string-match (concat "COMPLETION: " clang-completion-substring) line)))
+
+(defun clang-completion-display (buffer)
+ (let* ((all-lines (split-string clang-cc-result-string "\n"))
+ (completion-lines (filter 'is-completion-line all-lines)))
+ (if (consp completion-lines)
+ (progn
+ ;; Erase the process buffer
+ (let ((cur (current-buffer)))
+ (set-buffer buffer)
+ (goto-char (point-min))
+ (erase-buffer)
+ (set-buffer cur))
+
+ ;; Display the process buffer
+ (display-buffer buffer)
+
+ ;; Insert the code-completion string into the process buffer.
+ (with-current-buffer buffer
+ (insert (mapconcat 'identity completion-lines "\n")))
+ ))))
+
+;; Process "sentinal" that, on successful code completion, replaces the
+;; contents of the code-completion buffer with the new code-completion results
+;; and ensures that the buffer is visible.
+(defun clang-completion-sentinel (proc event)
+ (let* ((all-lines (split-string clang-cc-result-string "\n"))
+ (completion-lines (filter 'is-completion-line all-lines)))
+ (if (consp completion-lines)
+ (progn
+ ;; Erase the process buffer
+ (let ((cur (current-buffer)))
+ (set-buffer (process-buffer proc))
+ (goto-char (point-min))
+ (erase-buffer)
+ (set-buffer cur))
+
+ ;; Display the process buffer
+ (display-buffer (process-buffer proc))
+
+ ;; Insert the code-completion string into the process buffer.
+ (with-current-buffer (process-buffer proc)
+ (insert (mapconcat 'identity completion-lines "\n")))
+ ))))
+
+(defun clang-complete ()
+ (let ((ccstring (concat "-code-completion-at="
+ (buffer-file-name)
+ ":"
+ (number-to-string (+ 1 (current-line)))
+ ":"
+ (number-to-string (+ 1 (current-column)))))
+ (cc-buffer-name (concat "*Clang Completion for " (buffer-name) "*")))
+ ;; Start the code-completion process
+ (if (buffer-file-name)
+ (progn
+ ;; If there is already a code-completion process, kill it first.
+ (let ((cc-proc (get-process "Clang Code-Completion")))
+ (if cc-proc
+ (delete-process cc-proc)))
+
+ (setq clang-completion-substring "")
+ (setq clang-cc-result-string "")
+ (setq clang-completion-buffer cc-buffer-name)
+
+ (let ((cc-proc
+ (if (equal clang-completion-prefix-header "")
+ (start-process "Clang Code-Completion" cc-buffer-name
+ clang-cc "-fsyntax-only" ccstring
+ (buffer-file-name))
+ (start-process "Clang Code-Completion" cc-buffer-name
+ clang-cc "-fsyntax-only" ccstring
+ "-include-pch"
+ (concat clang-completion-prefix-header ".pch")
+ (buffer-file-name)))))
+ (set-process-filter cc-proc 'clang-completion-stash-filter)
+ (set-process-sentinel cc-proc 'clang-completion-sentinel)
+ )))))
+
+;; Code-completion when one of the trigger characters is typed into
+;; the buffer, e.g., '(', ',' or '.'.
+(defun clang-complete-self-insert (arg)
+ (interactive "p")
+ (self-insert-command arg)
+ (save-buffer)
+ (clang-complete))
+
+;; When the user has typed a character that requires the filter to be
+;; updated, do so (and update the display of results).
+(defun clang-update-filter ()
+ (setq clang-completion-substring (thing-at-point 'symbol))
+ (if (get-process "Clang Code-Completion")
+ ()
+ (clang-completion-display clang-completion-buffer)
+ ))
+
+;; Invoked when the user types an alphanumeric character or "_" to
+;; update the filter for the currently-active code completion.
+(defun clang-filter-self-insert (arg)
+ (interactive "p")
+ (self-insert-command arg)
+ (clang-update-filter)
+ )
+
+;; Invoked when the user types the backspace key to update the filter
+;; for the currently-active code completion.
+(defun clang-backspace ()
+ (interactive)
+ (delete-backward-char 1)
+ (clang-update-filter))
+
+;; Invoked when the user types the delete key to update the filter
+;; for the currently-active code completion.
+(defun clang-delete ()
+ (interactive)
+ (delete-backward-char 1)
+ (clang-update-filter))
+
+;; Set up the keymap for the Clang minor mode.
+(defvar clang-completion-mode-map nil
+ "Keymap for Clang Completion Mode.")
+
+(if (null clang-completion-mode-map)
+ (fset 'clang-completion-mode-map
+ (setq clang-completion-mode-map (make-sparse-keymap))))
+
+(if (not (assq 'clang-completion-mode minor-mode-map-alist))
+ (setq minor-mode-map-alist
+ (cons (cons 'clang-completion-mode clang-completion-mode-map)
+ minor-mode-map-alist)))
+
+;; Punctuation characters trigger code completion.
+(dolist (char '("(" "," "." ">" ":" "=" ")" " "))
+ (define-key clang-completion-mode-map char 'clang-complete-self-insert))
+
+;; Alphanumeric characters (and "_") filter the results of the
+;; currently-active code completion.
+(dolist (char '("A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O"
+ "P" "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z"
+ "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o"
+ "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z"
+ "_" "0" "1" "2" "3" "4" "5" "6" "7" "8" "9"))
+ (define-key clang-completion-mode-map char 'clang-filter-self-insert))
+
+;; Delete and backspace filter the results of the currently-active
+;; code completion.
+(define-key clang-completion-mode-map [(backspace)] 'clang-backspace)
+(define-key clang-completion-mode-map [(delete)] 'clang-delete)
+
+;; Set up the Clang minor mode.
+(define-minor-mode clang-completion-mode
+ "Clang code-completion mode"
+ nil
+ " Clang-CC"
+ clang-completion-mode-map)
+
diff --git a/utils/scan-build b/utils/scan-build
index 5835628..78394b1 100755
--- a/utils/scan-build
+++ b/utils/scan-build
@@ -148,6 +148,7 @@ my %AnalysesDefaultEnabled = (
# Do not enable the missing -dealloc check by default.
# '-warn-objc-missing-dealloc' => 1,
'-warn-objc-unused-ivars' => 1,
+ '-warn-security-syntactic' => 1
);
##----------------------------------------------------------------------------##
@@ -382,32 +383,25 @@ sub ScanFile {
my $BugCategory;
my $BugPathLength = 1;
my $BugLine = 0;
- my $found = 0;
while (<IN>) {
-
- last if ($found == 5);
+ last if (/<!-- BUGMETAEND -->/);
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;
}
}
@@ -955,9 +949,14 @@ ADVANCED OPTIONS:
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.
+ the 'region' store model is used. 'region' specifies a field-
+ sensitive store model. Users can also specify 'basic', which
+ is far less precise but can more quickly analyze code.
+ 'basic' was the default store model for checker-0.221 and
+ earlier.
+
+ -no-failure-reports - Do not create a 'failures' subdirectory that includes
+ analyzer crash reports and preprocessed source files.
AVAILABLE ANALYSES (multiple analyses may be specified):
@@ -1032,7 +1031,7 @@ my $ExitStatusFoundBugs = 0; # Exit status reflects whether bugs were found
my @AnalysesToRun;
my $StoreModel;
my $ConstraintsModel;
-my $OutputFormat;
+my $OutputFormat = "html";
if (!@ARGV) {
DisplayHelp();
@@ -1166,7 +1165,17 @@ while (@ARGV) {
$OutputFormat = "plist";
next;
}
+ if ($arg eq "-plist-html") {
+ shift @ARGV;
+ $OutputFormat = "plist-html";
+ next;
+ }
+ if ($arg eq "-no-failure-reports") {
+ $ENV{"CCC_REPORT_FAILURES"} = 0;
+ next;
+ }
+
DieDiag("unrecognized option '$arg'\n") if ($arg =~ /^-/);
last;
@@ -1252,25 +1261,27 @@ if (defined $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") {
+if (defined $OutputFormat) {
+ if ($OutputFormat =~ /plist/) {
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";
+ Diag "Analysis results (plist files) deposited in '$HtmlDir'\n";
}
+ elsif ($OutputFormat =~ /html/) {
+ # 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;
+ if ($ExitStatusFoundBugs) {
+ exit 1 if ($NumBugs > 0);
+ exit 0;
+ }
}
}
diff --git a/utils/valgrind/x86_64-pc-linux-gnu_gcc-4.3.3.supp b/utils/valgrind/x86_64-pc-linux-gnu_gcc-4.3.3.supp
new file mode 100644
index 0000000..a86be6c
--- /dev/null
+++ b/utils/valgrind/x86_64-pc-linux-gnu_gcc-4.3.3.supp
@@ -0,0 +1,23 @@
+{
+ libstdcxx_overlapped_memcpy_in_stable_sort_1
+ Memcheck:Overlap
+ fun:memcpy
+ ...
+ fun:_ZSt11stable_sortIN9__gnu_cxx17__normal_iteratorIPSt4pairIPKN4llvm5ValueEjESt6vectorIS7_SaIS7_EEEEN12_GLOBAL__N_116CstSortPredicateEEvT_SF_T0_
+}
+
+{
+ libstdcxx_overlapped_memcpy_in_stable_sort_2
+ Memcheck:Overlap
+ fun:memcpy
+ ...
+ fun:_ZSt11stable_sortIN9__gnu_cxx17__normal_iteratorIPSt4pairIPKN4llvm5ValueEjESt6vectorIS7_SaIS7_EEEEN12_GLOBAL__N_116CstSortPredicateEEvT_SF_T0_
+}
+
+{
+ libstdcxx_overlapped_memcpy_in_stable_sort_3
+ Memcheck:Overlap
+ fun:memcpy
+ ...
+ fun:_ZSt11stable_sortIN9__gnu_cxx17__normal_iteratorIPSt4pairIPKN4llvm4TypeEjESt6vectorIS7_SaIS7_EEEEPFbRKS7_SE_EEvT_SH_T0_
+}
diff --git a/www/OpenProjects.html b/www/OpenProjects.html
index c0ee998..cdf3121 100644
--- a/www/OpenProjects.html
+++ b/www/OpenProjects.html
@@ -82,12 +82,10 @@ job, but there are lots of little pieces that can be picked off and implemented.
<ul>
<li>Fix bugs: there are a number of XFAIL'd test cases in Clang's repository (particularly in the CXX subdirectory). Pick a test case and fix Clang to make it work!</li>
<li>Write tests: the CXX test subdirectory in Clang's repository has placeholders for tests of every paragraph in the C++ standard. Pick a paragraph, write a few tests, and see if they work! Even if they don't we'd still like the new tests (with XFAIL'd) so that we know what to fix.</li>
- <li>Type-checking for explicit conversions: currently follows C semantics, not C++ semantics.</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>Parsing and AST representations of friend classes and functions</li>
- <li>Explicit calls to destructors and pseudo-destructor expressions (<code>x.~X()</code>).</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>
+ <li>Parsing and semantic analysis for using declarations in classes</li>
+ <li>Inherited conversion functions</li>
+ <li>Improved diagnostics for overloading failures and ambiguities</li>
+ <li>Improved template error messages, e.g., with more informative backtraces</li>
</ul>
Also, see the <a href="cxx_status.html">C++ status report page</a> to
diff --git a/www/analyzer/annotations.html b/www/analyzer/annotations.html
index e49c327..819886e 100644
--- a/www/analyzer/annotations.html
+++ b/www/analyzer/annotations.html
@@ -152,8 +152,12 @@ use 'cf_returns_retained'.</p>
<span class="command">$ cat test.m</span>
#import &lt;Foundation/Foundation.h&gt;
+#ifndef __has_feature // Optional.
+#define __has_feature(x) 0 // Compatibility with non-clang compilers.
+#endif
+
#ifndef NS_RETURNS_RETAINED
-#if __clang__
+#if __has_feature(attribute_ns_returns_retained)
<span class="code_highlight">#define NS_RETURNS_RETAINED __attribute__((ns_returns_retained))</span>
#else
#define NS_RETURNS_RETAINED
@@ -226,8 +230,12 @@ collection (<tt>-fobjc-gc-only</tt>).</p>
$ cat test.m
#import &lt;Cocoa/Cocoa.h&gt;
+#ifndef __has_feature // Optional.
+#define __has_feature(x) 0 // Compatibility with non-clang compilers.
+#endif
+
#ifndef CF_RETURNS_RETAINED
-#if __clang__
+#if __has_feature(attribute_cf_returns_retained)
<span class="code_highlight">#define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))</span>
#else
#define CF_RETURNS_RETAINED
diff --git a/www/analyzer/content.css b/www/analyzer/content.css
index 01a3af2..3f47e3b 100644
--- a/www/analyzer/content.css
+++ b/www/analyzer/content.css
@@ -1,3 +1,5 @@
+html { margin: 0px; } body { margin: 8px; }
+
html, body {
padding:0px;
font-size:small; font-family:"Lucida Grande", "Lucida Sans Unicode", Arial, Verdana, Helvetica, sans-serif; background-color: #fff; color: #222;
diff --git a/www/analyzer/latest_checker.html.incl b/www/analyzer/latest_checker.html.incl
index 4f030bb..fa287b1 100644
--- a/www/analyzer/latest_checker.html.incl
+++ b/www/analyzer/latest_checker.html.incl
@@ -1 +1 @@
-<b><a href="http://checker.minormatter.com/checker-0.212.tar.bz2">checker-0.212.tar.bz2</a></b> (built July 2, 2009)
+<b><a href="http://checker.minormatter.com/checker-224.tar.bz2">checker-224.tar.bz2</a></b> (built October 6, 2009)
diff --git a/www/analyzer/menu.css b/www/analyzer/menu.css
index 8249c14..0312f4c 100644
--- a/www/analyzer/menu.css
+++ b/www/analyzer/menu.css
@@ -4,12 +4,12 @@
[id=menu] {
position:fixed;
- width:25ex;
+ width:35ex;
}
[id=content] {
/* ***** EDIT THIS VALUE IF CONTENT OVERLAPS MENU ***** */
position:absolute;
- left:29ex;
+ left:39ex;
padding-right:4ex;
}
diff --git a/www/analyzer/menu.html.incl b/www/analyzer/menu.html.incl
index a5e7f31..b7c95f1 100644
--- a/www/analyzer/menu.html.incl
+++ b/www/analyzer/menu.html.incl
@@ -5,6 +5,11 @@
</div>
<div class="submenu">
+ <label>Events</label>
+ <a href="http://llvm.org/devmtg/2009-10">October 2, 2009 - LLVM/Clang Developers' Meeting</a>
+ </div>
+
+ <div class="submenu">
<label>Quick Links</label>
<a href="/index.html">About the Analyzer</a>
<a href="/filing_bugs.html">Filing Bugs</a>
@@ -25,4 +30,6 @@
<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>
</div>
+
+ <center><a href="http://llvm.org"><img src="http://llvm.org/img/LLVM-Logo-Derivative-3.png" style="margin-top:10px"></a></center>
</div>
diff --git a/www/comparison.html b/www/comparison.html
index f86ea7f..bba2a65 100644
--- a/www/comparison.html
+++ b/www/comparison.html
@@ -184,8 +184,7 @@
<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 doesn't support Objective-C or C++ and doesn't aim to</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
diff --git a/www/content.css b/www/content.css
index ab6983b..dca6a32 100644
--- a/www/content.css
+++ b/www/content.css
@@ -1,3 +1,5 @@
+html { margin: 0px; } body { margin: 8px; }
+
html, body {
padding:0px;
font-size:small; font-family:"Lucida Grande", "Lucida Sans Unicode", Arial, Verdana, Helvetica, sans-serif; background-color: #fff; color: #222;
diff --git a/www/cxx_status.html b/www/cxx_status.html
index 2af2b32..2c1b79e 100644
--- a/www/cxx_status.html
+++ b/www/cxx_status.html
@@ -24,7 +24,7 @@
<!--*************************************************************************-->
<h1>C++ Support in Clang</h1>
<!--*************************************************************************-->
-<p>Last updated: $Date: 2009-06-27 21:33:58 +0200 (Sat, 27 Jun 2009) $</p>
+<p>Last updated: $Date: 2009-10-13 21:41:44 +0200 (Tue, 13 Oct 2009) $</p>
<p>
This page tracks the status of C++ support in Clang.<br>
@@ -321,8 +321,21 @@ welcome!</p>
<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.5 [basic.scope.namespace]</td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td class="complete"></td>
+ <td class="na">N/A</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;3.3.6 [basic.scope.class]</td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td class="advanced"></td>
+ <td class="na">N/A</td>
+ <td>Does not check that reordering the members of a class maintains semantics.</td>
+</tr>
<tr>
<td>&nbsp;&nbsp;&nbsp;&nbsp;3.3.7 [basic.scope.hiding]</td>
<td class="na">N/A</td>
@@ -343,17 +356,17 @@ welcome!</p>
<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="advanced"></td>
<td class="na">N/A</td>
- <td>Many cases beyond simple global and function-local lookup don't work</td>
+ <td></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>
+ <td class="complete"></td>
+ <td class="na">N/A</td>
+ <td></td>
</tr>
<tr>
<td>&nbsp;&nbsp;&nbsp;&nbsp;3.4.3 [basic.lookup.qual]</td>
@@ -380,8 +393,21 @@ welcome!</p>
<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;&nbsp;&nbsp;3.4.5 [basic.lookup.classref]</td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td class="advanced"></td>
+ <td class="na">N/A</td>
+ <td>Missing ambiguity/consistency checks for paragraphs 3 (~type-name) and 7 (conversion-type-id)</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;3.4.6 [basic.lookup.udir]</td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td class="medium"></td>
+ <td class="na">N/A</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>
@@ -508,17 +534,18 @@ welcome!</p>
<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 class="complete" align="center">&#x2713;</td>
+ <td class="na">N/A</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 class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
<td></td>
- <td>template-ids are not supported, name lookup is not complete</td>
+ <td>cannot parse operator-function-ids that have explicit template argument
+ lists</td>
</tr>
<tr><td>&nbsp;&nbsp;5.2 [expr.post]</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr>
@@ -540,26 +567,26 @@ welcome!</p>
<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 class="advanced" align="center"></td>
+ <td class="advanced"></td>
+ <td></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 class="complete"></td>
+ <td class="complete"></td>
+ <td class="complete"></td>
+ <td class="complete"></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 class="complete"></td>
+ <td class="complete"></td>
+ <td></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>
@@ -588,10 +615,10 @@ welcome!</p>
<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 class="advanced" align="center"></td>
<td></td>
- <td>Some custom conversions don't work.</td>
+ <td></td>
</tr>
<tr>
<td>&nbsp;&nbsp;&nbsp;&nbsp;5.2.10 [expr.reinterpret.cast]</td>
@@ -694,10 +721,10 @@ welcome!</p>
<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 class="advanced" align="center"></td>
+ <td class="advanced"></td>
+ <td></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>
@@ -953,7 +980,7 @@ welcome!</p>
<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>
+ <td>Existence and accessibility of destructors is not tested for.</td>
</tr>
<tr>
<td>&nbsp;&nbsp;6.8 [stmt.ambig]</td>
@@ -970,7 +997,7 @@ welcome!</p>
<td class="advanced" align="center"></td>
<td class="advanced" align="center"></td>
<td></td>
- <td>No support for friend declarations.</td>
+ <td></td>
</tr>
<tr>
<td>&nbsp;&nbsp;&nbsp;&nbsp;7.1.1 [dcl.stc]</td>
@@ -998,9 +1025,9 @@ welcome!</p>
</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 class="medium"></td>
+ <td class="medium"></td>
+ <td class="medium"></td>
<td></td>
<td></td>
</tr>
@@ -1022,19 +1049,19 @@ welcome!</p>
</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 class="advanced"></td>
+ <td></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 class="advanced"></td>
<td></td>
- <td>Cannot parse template IDs.</td>
+ <td></td>
</tr>
<tr>
<td>&nbsp;&nbsp;7.2 [dcl.enum]</td>
@@ -1054,11 +1081,11 @@ welcome!</p>
</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 class="advanced"></td>
+ <td class="advanced"></td>
+ <td class="advanced"></td>
+ <td></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>
@@ -1074,7 +1101,7 @@ welcome!</p>
<td class="complete" align="center"></td>
<td class="advanced"></td>
<td></td>
- <td>The friend stuff is not supported.</td>
+ <td></td>
</tr>
<tr>
<td>&nbsp;&nbsp;&nbsp;&nbsp;7.3.2 [namespace.alias]</td>
@@ -1086,9 +1113,9 @@ welcome!</p>
</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 class="medium" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="basic" align="center"></td>
<td></td>
<td></td>
</tr>
@@ -1141,7 +1168,7 @@ welcome!</p>
<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>
+ <td></td>
</tr>
<tr>
<td>&nbsp;&nbsp;&nbsp;&nbsp;8.3.1 [dcl.ptr]</td>
@@ -1189,21 +1216,21 @@ welcome!</p>
<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>
+ <td>Partial support for default arguments of 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="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>
+ <td></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="advanced" align="center"></td>
<td class="medium" align="center"></td>
<td></td>
</tr>
@@ -1213,7 +1240,7 @@ welcome!</p>
<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>
+ <td>No CodeGen for dynamic initialization.</td>
</tr>
<tr>
<td>&nbsp;&nbsp;&nbsp;&nbsp;8.5.2[dcl.init.string]</td>
@@ -1253,7 +1280,7 @@ welcome!</p>
<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>
+ <td>Basic parser support for using declarations.</td>
</tr>
<tr>
<td>&nbsp;&nbsp;9.3 [class.mfct]</td>
@@ -1266,16 +1293,16 @@ welcome!</p>
<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="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.2 [class.this]</td>
<td class="complete" align="center"></td>
- <td class="medium" align="center"></td>
- <td class="medium" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
<td class="basic"></td>
<td></td>
</tr>
@@ -1283,7 +1310,7 @@ welcome!</p>
<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="advanced" align="center"></td>
<td class="basic"></td>
<td></td>
</tr>
@@ -1291,7 +1318,7 @@ welcome!</p>
<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="advanced" align="center"></td>
<td class="basic"></td>
<td></td>
</tr>
@@ -1299,7 +1326,7 @@ welcome!</p>
<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="advanced" align="center"></td>
<td class="basic"></td>
<td></td>
</tr>
@@ -1307,9 +1334,9 @@ welcome!</p>
<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>
+ <td class="complete"></td>
+ <td class="complete"></td>
+ <td></td>
</tr>
<tr>
<td>&nbsp;&nbsp;9.6 [class.bit]</td>
@@ -1347,7 +1374,7 @@ welcome!</p>
<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="advanced" align="center"></td>
<td class="broken" align="center"></td>
<td></td>
</tr>
@@ -1356,8 +1383,8 @@ welcome!</p>
<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>
+ <td class="basic" align="center"></td>
+ <td></td>
</tr>
<tr>
<td>&nbsp;&nbsp;10.2 [class.member.lookup]</td>
@@ -1371,9 +1398,9 @@ welcome!</p>
<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>
+ <td class="medium" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td>Basic layout of classes with virtual functions.</td>
</tr>
<tr>
<td>&nbsp;&nbsp;10.4 [class.abstract]</td>
@@ -1417,9 +1444,9 @@ welcome!</p>
</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="medium" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="medium" align="center"></td>
<td class="na" align="center">N/A</td>
<td></td>
</tr>
@@ -1460,9 +1487,9 @@ welcome!</p>
<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>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td>Most of the semantics of constructors are implemented.</td>
</tr>
<tr>
<td>&nbsp;&nbsp;12.2 [class.temporary]</td>
@@ -1476,8 +1503,8 @@ welcome!</p>
<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 class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
<td></td>
</tr>
<tr>
@@ -1485,7 +1512,7 @@ welcome!</p>
<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 class="advanced" align="center"></td>
<td></td>
</tr>
<tr>
@@ -1493,16 +1520,15 @@ welcome!</p>
<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>
+ <td class="advanced" align="center"></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>
+ <td class="medium" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td>Most of the semantics of destructors are implemented.</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>
@@ -1511,205 +1537,202 @@ welcome!</p>
<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>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td>Most of the semantics of base initializations are implemented.</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>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td>Most of the semantics of copy constructors are implemented.</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>
+ <td class="na" align="center">N/A</td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td></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 class="na" align="center">N/A</td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="na" align="center">N/A</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 class="na" align="center">N/A</td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="na" align="center">N/A</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 class="na" align="center">N/A</td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="na" align="center">N/A</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 class="na" align="center">N/A</td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="na" align="center">N/A</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 class="na" align="center">N/A</td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="na" align="center">N/A</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="na" align="center">N/A</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>
+ <td class="advanced" align="center"></td>
+ <td class="na" align="center">N/A</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="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 class="na" align="center">N/A</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 class="na" align="center">N/A</td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="na" align="center">N/A</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 class="na" align="center">N/A</td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="na" align="center">N/A</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 class="na" align="center">N/A</td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="na" align="center">N/A</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 class="na" align="center">N/A</td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="na" align="center">N/A</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 class="na" align="center">N/A</td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="na" align="center">N/A</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>
+ <td class="na" align="center">N/A</td>
+ <td class="advanced" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="na" align="center">N/A</td>
+ <td>Missing support for member pointers</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 class="na" align="center">N/A</td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="na" align="center">N/A</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 class="na" align="center">N/A</td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="na" align="center">N/A</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 class="na" align="center">N/A</td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="na" align="center">N/A</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 class="na" align="center">N/A</td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="na" align="center">N/A</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 class="na" align="center">N/A</td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="na" align="center">N/A</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 class="na" align="center">N/A</td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="na" align="center">N/A</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>
+ <td class="na" align="center">N/A</td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="na" align="center">N/A</td>
+ <td></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>
+ <td class="advanced" align="center"></td>
+ <td class="na" align="center">N/A</td>
+ <td></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 class="na" align="center">N/A</td>
<td></td>
</tr>
<tr>
@@ -1717,7 +1740,7 @@ welcome!</p>
<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 class="na" align="center">N/A</td>
<td></td>
</tr>
<tr>
@@ -1725,7 +1748,7 @@ welcome!</p>
<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 class="na" align="center">N/A</td>
<td></td>
</tr>
<tr>
@@ -1733,7 +1756,7 @@ welcome!</p>
<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 class="na" align="center">N/A</td>
<td></td>
</tr>
<tr>
@@ -1741,7 +1764,7 @@ welcome!</p>
<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 class="na" align="center">N/A</td>
<td></td>
</tr>
<tr>
@@ -1749,7 +1772,7 @@ welcome!</p>
<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 class="na" align="center">N/A</td>
<td></td>
</tr>
<tr>
@@ -1757,7 +1780,7 @@ welcome!</p>
<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 class="na" align="center">N/A</td>
<td></td>
</tr>
<tr>
@@ -1765,15 +1788,15 @@ welcome!</p>
<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
+ <td class="na" align="center">N/A</td>
+ <td>Missing support for the ->* operator (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="basic" align="center"></td>
<td class="broken" align="center"></td>
<td></td>
</tr>
@@ -1787,19 +1810,19 @@ welcome!</p>
</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="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>Cannot name function template specializations</td>
+ <td></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="complete" align="center"></td>
+ <td class="advanced" align="center"></td>
<td class="na" align="center">N/A</td>
- <td>Cannot name function template specializations</td>
+ <td></td>
</tr>
<tr>
<td>&nbsp;&nbsp;&nbsp;&nbsp;14.3.1 [temp.arg.type]</td>
@@ -1838,48 +1861,48 @@ welcome!</p>
</tr>
<tr>
<td>&nbsp;&nbsp;&nbsp;&nbsp;14.5.1 [temp.class]</td>
- <td class="medium" align="center"></td>
+ <td class="advanced" align="center"></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 class="broken" align="center"></td>
- <td>No out-of-line definitions of the members of a template.</td>
+ <td></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="advanced" align="center"></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 class="broken" align="center"></td>
- <td>No out-of-line definitions of the member functions of a class template.</td>
+ <td></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="advanced" align="center"></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 class="broken" align="center"></td>
- <td>No out-of-line definitions of the member classes of a class template.</td>
+ <td></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="advanced" align="center"></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 class="broken" align="center"></td>
- <td>No out-of-line definitions of the static data members of a class template.</td>
+ <td></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 class="advanced" 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.5.3 [temp.friend]</td>
- <td class="broken" align="center"></td>
- <td class="broken" align="center"></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>
@@ -1902,49 +1925,49 @@ welcome!</p>
</tr>
<tr>
<td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.5.4.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"></td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" 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="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" 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="medium" align="center"></td>
- <td class="medium" align="center"></td>
+ <td class="advanced" align="center"></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;&nbsp;&nbsp;14.5.5.1 [temp.over.link]</td>
<td class="na" align="center"></td>
<td class="complete" align="center"></td>
- <td class="medium" align="center"></td>
+ <td class="advanced" 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"></td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" 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="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>
@@ -2007,8 +2030,8 @@ welcome!</p>
<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="medium" align="center"></td>
+ <td class="medium" align="center"></td>
<td class="na" align="center"></td>
<td></td>
</tr>
@@ -2031,105 +2054,105 @@ welcome!</p>
<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="basic" align="center"></td>
+ <td class="basic" 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="medium" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="medium" align="center"></td>
<td class="broken" align="center"></td>
- <td>Function templates cannot be instantiated</td>
+ <td></td>
</tr>
<tr>
<td>&nbsp;&nbsp;&nbsp;&nbsp;14.7.1 [temp.inst]</td>
<td class="na" align="center">N/A</td>
+ <td class="na" align="center"></td>
+ <td class="medium" 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>
+ <td></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="advanced" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="medium" align="center"></td>
<td class="broken" align="center"></td>
- <td>Function templates cannot be instantiated</td>
+ <td></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>
+ <td class="complete" align="center">&#x2713;</td>
+ <td class="advanced" align="center"></td>
+ <td class="complete" align="center">&#x2713;</td>
+ <td class="complete" align="center"></td>
+ <td>ASTs do not carry enough information to reproduce source code accurately</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="medium" 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;14.8.1 [temp.arg.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 class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="na" align="center"></td>
<td></td>
</tr>
<tr>
<td>&nbsp;&nbsp;&nbsp;&nbsp;14.8.2 [temp.deduct]</td>
<td class="na" align="center">N/A</td>
<td class="na" align="center">N/A</td>
- <td class="medium" align="center"></td>
+ <td class="advanced" align="center"></td>
<td class="na" align="center">N/A</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="na" align="center"></td>
<td class="complete" align="center"></td>
- <td class="basic" align="center"></td>
+ <td class="advanced" align="center"></td>
<td class="na" 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 class="na" align="center">N/A</td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="na" align="center">N/A</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 class="na" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="na" align="center"></td>
<td></td>
</tr>
<tr>
<td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.8.2.4 [temp.deduct.type]</td>
<td class="na" align="center">N/A</td>
<td class="complete" align="center"></td>
- <td class="medium" align="center"></td>
+ <td class="advanced" align="center"></td>
<td class="na" align="center">N/A</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 class="na" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="na" align="center"></td>
<td></td>
</tr>
<tr>
@@ -2167,9 +2190,9 @@ welcome!</p>
<tr>
<td>&nbsp;&nbsp;15.4 [except.spec]</td>
<td class="complete" align="center"></td>
- <td></td>
- <td></td>
- <td></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="broken"></td>
<td></td>
</tr>
<tr>
diff --git a/www/diagnostics.html b/www/diagnostics.html
index 5be4db2..18f1bc7 100644
--- a/www/diagnostics.html
+++ b/www/diagnostics.html
@@ -43,7 +43,7 @@ what is wrong in a particular piece of code, an example is:</p>
$ <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
+ format-strings.c:91:13: <font color="magenta">warning:</font> '.*' specified field precision is missing a matching 'int' argument
<font color="darkgreen"> printf("%.*d");</font>
<font color="blue"> ^</font>
</pre>
@@ -64,7 +64,7 @@ nonsensical example to illustrate this:</p>
$ <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')
+ t.c:7:39: <font color="red">error:</font> 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>
@@ -89,7 +89,7 @@ one:</p>
$ <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)
+ t.c:5:11: <font color="red">error:</font> indirection requires pointer operand ('int' invalid)
<font color="darkgreen"> int y = *SomeA.X;</font>
<font color="blue"> ^~~~~~~~</font>
</pre>
@@ -112,7 +112,7 @@ example P and Q have type "int*":</p>
$ <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
+ t.c:12:8: <font color="red">error:</font> called object type 'int' is not a function or function pointer
<font color="darkgreen"> (P-Q)();</font>
<font color="blue"> ~~~~~^</font>
</pre>
@@ -134,7 +134,7 @@ a typedef in C:</p>
$ <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 *')
+ t.c:15:11: <font color="red">error:</font> 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>
@@ -148,7 +148,7 @@ is useful for the compiler to expose underlying details of a typedef:</p>
$ <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
+ t.c:13:9: <font color="red">error:</font> 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>
@@ -182,7 +182,7 @@ void addHTTPService(servers::Server const &server, ::services::WebService const
$ <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 *')
+ t.cpp:9:10: <font color="red">error:</font> invalid operands to binary expression ('servers::Server const' and '::services::WebService const *')
<font color="darkgreen">server += http;</font>
<font color="blue">~~~~~~ ^ ~~~~</font>
</pre>
@@ -193,7 +193,7 @@ void addHTTPService(servers::Server const &server, ::services::WebService const
$ <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;')
+ t.cpp:12:7: <font color="red">error:</font> 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>
@@ -210,21 +210,25 @@ 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
+ t.c:5:28: <font color="magenta">warning:</font> 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
+ t.c:5:36: <font color="magenta">warning:</font> 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>
+<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;'
+ t.cpp:9:3: <font color="red">error:</font> template specialization requires 'template&lt;&gt;'
struct iterator_traits&lt;file_iterator&gt; {
<font color="blue">^</font>
<font color="darkgreen">template&lt;&gt; </font>
@@ -244,7 +248,7 @@ Clang helps you out:</p>
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'))
+ t.c:80:3: <font color="red">error:</font> 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:
@@ -260,7 +264,7 @@ 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'
+ t.c:22:2: <font color="magenta">warning:</font> type specifier missing, defaults to 'int'
<font color="darkgreen"> ILPAD();</font>
<font color="blue"> ^</font>
t.c:17:17: note: instantiated from:
@@ -274,6 +278,45 @@ implements the "wwopen" class of APIs):</p>
<p>In practice, we've found that this is actually more useful in multiply nested
macros that in simple ones.</p>
+<h2>Quality of Implementation and Attention to Detail</h2>
+
+<p>Finally, we have put a lot of work polishing the little things, because
+little things add up over time and contribute to a great user experience. Two
+examples are:</p>
+
+<pre>
+ $ <b>gcc-4.2 t.c</b>
+ t.c: In function 'foo':
+ t.c:5: error: expected ';' before '}' token
+ $ <b>clang t.c</b>
+ t.c:4:8: <font color="red">error:</font> expected ';' after expression
+ <font color="darkgreen"> bar()</font>
+ <font color="blue"> ^</font>
+ <font color="blue"> ;</font>
+</pre>
+
+<p>This shows a trivial little tweak, where we tell you to put the semicolon at
+the end of the line that is missing it (line 4) instead of at the beginning of
+the following line (line 5). This is particularly important with fixit hints
+and caret diagnostics, because otherwise you don't get the important context.
+</p>
+
+<pre>
+ $ <b>gcc-4.2 t.c</b>
+ t.c:3: error: expected '=', ',', ';', 'asm' or '__attribute__' before '*' token
+ $ <b>clang t.c</b>
+ t.c:3:1: <font color="red">error:</font> unknown type name 'foo_t'
+ <font color="darkgreen">foo_t *P = 0;</font>
+ <font color="blue">^</font>
+</pre>
+
+<p>This shows an example of much better error recovery. The message coming out
+of GCC is completely useless for diagnosing the problem, Clang tries much harder
+and produces a much more useful diagnosis of the problem.</p>
+
+<p>While each of these details is minor, we feel that they all add up to provide
+a much more polished experience.</p>
+
</div>
</body>
</html>
diff --git a/www/features.html b/www/features.html
index 21382fd..6034ae7 100644
--- a/www/features.html
+++ b/www/features.html
@@ -232,6 +232,7 @@ Currently, clang is divided into the following libraries and tool:
<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><a href="docs/libIndex.html">libindex</a></b> - Cross-translation-unit infrastructure and indexing support.</li>
<li><b>clang</b> - A driver program, client of the libraries at various
levels.</li>
</ul>
diff --git a/www/get_started.html b/www/get_started.html
index 437cb38..86f6cef 100644
--- a/www/get_started.html
+++ b/www/get_started.html
@@ -43,30 +43,44 @@ mailing list</a>.</p>
<h2 id="build">Building Clang and Working with the Code</h2>
+<h3 id="buildNix">On Unix-like Systems</h3>
+
<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>
+ <li>Get the required tools.
+ <ul>
+ <li>See
+ <a href="http://llvm.org/docs/GettingStarted.html#requirements">
+ Getting Started with the LLVM System - Requirements</a>.</li>
+ <li>Note also that Python is needed for running the test suite.
+ Get it at: <a href="http://www.python.org/download">
+ http://www.python.org/download</a></li>
+ </ul>
+ <li>Checkout LLVM:</li>
<ul>
+ <li>Change directory to where you want the llvm directory placed.</li>
<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>
-
+ <li><tt>cd llvm/tools</tt>
+ <li><tt>svn co http://llvm.org/svn/llvm-project/cfe/trunk clang</tt></li>
+ </ul>
+ <li>Build LLVM and Clang:</li>
+ <ul>
+ <li><tt>cd ..</tt> (back to llvm)</li>
+ <li><tt>./configure</tt></li>
+ <li><tt>make</tt></li>
+ <li>This builds both LLVM and Clang for debug mode.</li>
+ <li>Note: For subsequent Clang development, you can just do make at the
+ clang directory level.</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>
@@ -74,13 +88,6 @@ follows:</p>
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>
@@ -95,7 +102,6 @@ follows:</p>
<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
@@ -120,6 +126,71 @@ 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>
+<h3 id="buildWindows">Using Visual Studio</h3>
+
+<p>The following details setting up for and building Clang on Windows using
+Visual Studio:</p>
+
+<ol>
+ <li>Get the required tools:</li>
+ <ul>
+ <li><b>Subversion</b>. Source code control program. Get it from:
+ <a href="http://subversion.tigris.org/getting.html">
+ http://subversion.tigris.org/getting.html</a></li>
+ <li><b>cmake</b>. This is used for generating Visual Studio solution and
+ project files. Get it from:
+ <a href="http://www.cmake.org/cmake/resources/software.html">
+ http://www.cmake.org/cmake/resources/software.html</a></li>
+ <li><b>Visual Studio 2005 or 2008</b></li>
+ <li><b>Python</b>. This is needed only if you will be running the tests
+ (which is essential, if you will be developing for clang).
+ Get it from:
+ <a href="http://www.python.org/download">
+ http://www.python.org/download</a></li>
+ <li><b>GnuWin32 tools</b>
+ These are also necessary for running the tests.
+ (Note that the grep from MSYS or Cygwin doesn't work with the tests
+ because of embedded double-quotes in the search strings. The GNU
+ grep does work in this case.)
+ Get them from <a href="http://getgnuwin32.sourceforge.net">
+ http://getgnuwin32.sourceforge.net</a>.</li>
+ </ul>
+
+ <li>Checkout LLVM:</li>
+ <ul>
+ <li><tt>svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm</tt></li>
+ </ul>
+ <li>Checkout Clang:</li>
+ <ul>
+ <li><tt>cd llvm\tools</tt>
+ <li><tt>svn co http://llvm.org/svn/llvm-project/cfe/trunk clang</tt></li>
+ </ul>
+ <li>Run cmake to generate the Visual Studio solution and project files:</li>
+ <ul>
+ <li><tt>cd ..</tt> (Change directory back to the llvm top.)</li>
+ <li><tt>cmake .</tt></li>
+ <li>The above, if successful, will have created an LLVM.sln file in the
+ llvm directory.
+ </ul>
+ <li>Build Clang:</li>
+ <ul>
+ <li>Open LLVM.sln in Visual Studio.</li>
+ <li>Build the "clang-cc" project for just the compiler front end.
+ Alternatively, build the "clang" project for the compiler driver
+ (note that the driver is currently broken on Windows),
+ or the "ALL_BUILD" project to build everything, including tools.</li>
+ </ul>
+ <li>Try it out (assuming you added llvm/debug/bin to your path). (See the
+ running examples from above.)</li>
+ <li>See <a href="hacking.html#testingWindows">
+ Hacking on clang - Testing using Visual Studio on Windows</a> for information
+ on running regression tests on Windows.</li>
+</ol>
+
+<p>Note that once you have checked out both llvm and clang, to synchronize
+to the latest code base, use the <tt>svn update</tt> command in both the
+llvm and llvm\tools\clang directories, as they are separate repositories.</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
diff --git a/www/hacking.html b/www/hacking.html
index db83861..a1833a2 100644
--- a/www/hacking.html
+++ b/www/hacking.html
@@ -22,6 +22,11 @@
<li><a href="#docs">Developer Documentation</a></li>
<li><a href="#debugging">Debugging</a></li>
<li><a href="#testing">Testing</a></li>
+ <ul>
+ <li><a href="#testingNonWindows">Testing on Unix-like Systems</a></li>
+ <li><a href="#testingWindows">Testing using Visual Studio on Windows</a></li>
+ </ul>
+ <li><a href="#patches">Creating Patch Files</a></li>
<li><a href="#irgen">LLVM IR Generation</a></li>
</ul>
@@ -61,22 +66,111 @@
<h2 id="testing">Testing</h2>
<!--=====================================================================-->
+ <p><i>[Note: The test running mechanism is currently under revision, so the
+ following might change shortly.]</i></p>
+
+ <!--=====================================================================-->
+ <h3 id="testingNonWindows">Testing on Unix-like Systems</h3>
+ <!--=====================================================================-->
+
<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
+ just <tt>make</tt> in the <em>test</em> sub-directory.
+ <tt>make VERBOSE=1</tt> can be used to show more detail
about what is being run.</p>
+ <p>The tests primarily consist of a test runner script running the compiler
+ under test on individual test files grouped in the directories under the
+ test directory. The individual test files include comments at the
+ beginning indicating the Clang compile options to use, to be read
+ by the test runner. Embedded comments also can do things like telling
+ the test runner that an error is expected at the current line.
+ Any output files produced by the test will be placed under
+ a created Output directory.</p>
+
+ <p>During the run of <tt>make test</tt>, the terminal output will
+ display a line similar to the following:</p>
+
+ <ul><tt>--- Running clang tests for i686-pc-linux-gnu ---</tt></ul>
+
+ <p>followed by a line continually overwritten with the current test
+ file being compiled, and an overall completion percentage.</p>
+
+ <p>After the <tt>make test</tt> run completes, the absence of any
+ <tt>Failing Tests (count):</tt> message indicates that no tests
+ failed unexpectedly. If any tests did fail, the
+ <tt>Failing Tests (count):</tt> message will be followed by a list
+ of the test source file paths that failed. For example:</p>
+
+ <tt><pre>
+ Failing Tests (3):
+ /home/john/llvm/tools/clang/test/SemaCXX/member-name-lookup.cpp
+ /home/john/llvm/tools/clang/test/SemaCXX/namespace-alias.cpp
+ /home/john/llvm/tools/clang/test/SemaCXX/using-directive.cpp
+ </pre></tt>
+
+ <p>If you used the <tt>make VERBOSE=1</tt> option, the terminal
+ output will reflect the error messages from the compiler and
+ test runner.</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
+ override LLVMGCC, as in: <tt>make LLVMGCC="clang -std=gnu89"
+ TEST=nightly report</tt> (make sure <tt>clang</tt> is in your PATH or use the
full path).</p>
+
+ <!--=====================================================================-->
+ <h3 id="testingWindows">Testing using Visual Studio on Windows</h3>
+ <!--=====================================================================-->
+
+ <p>The cmake build tool is set up to create Visual Studio project files
+ for running the tests, "clang-test" being the root.
+ Unfortunately, the test runner scripts presently don't work on Windows.
+ This will be fixed during the test runner revision in progress.</p>
+
+ <p>Note that the current and coming revised test runner is based on
+ Python, which must be installed. Find Python at:
+ <a href="http://www.python.org/download">http://www.python.org/download</a>.
+ Download the latest stable version (2.6.2 at the time of this writing).</p>
+
+ <p>The GnuWin32 tools are also necessary for running the tests.
+ (Note that the grep from MSYS or Cygwin doesn't work with the tests
+ because of embedded double-quotes in the search strings. The GNU
+ grep does work in this case.)
+ Get them from <a href="http://getgnuwin32.sourceforge.net">
+ http://getgnuwin32.sourceforge.net</a>.</p>
+
+ <!--=====================================================================-->
+ <h2 id="patches">Creating Patch Files</h2>
+ <!--=====================================================================-->
+
+ <p>To return changes to the Clang team, unless you have checkin
+ privileges, the prefered way is to send patch files to the
+ cfe-commits mailing list, with an explanation of what the patch is for.
+ Or, if you have questions, or want to have a wider discussion of what
+ you are doing, such as if you are new to Clang development, you can use
+ the cfe-dev mailing list also.
+ </p>
+
+ <p>To create these patch files, change directory
+ to the llvm/tools/clang root and run:</p>
+
+ <ul><tt>svn diff (relative path) >(patch file name)</tt></ul>
+
+ <p>For example, for getting the diffs of all of clang:</p>
+
+ <ul><tt>svn diff . >~/mypatchfile.patch</tt></ul>
+
+ <p>For example, for getting the diffs of a single file:</p>
+
+ <ul><tt>svn diff lib/Parse/ParseDeclCXX.cpp >~/ParseDeclCXX.patch</tt></ul>
+
+ <p>Note that the paths embedded in the patch depend on where you run it,
+ so changing directory to the llvm/tools/clang directory is recommended.</p>
<!--=====================================================================-->
<h2 id="irgen">LLVM IR Generation</h2>
diff --git a/www/menu.html.incl b/www/menu.html.incl
index 561969b..29ed3a3 100644
--- a/www/menu.html.incl
+++ b/www/menu.html.incl
@@ -29,20 +29,30 @@
</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>
+ <label>Communication</label>
+ <a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev">cfe-dev List</a>
+ <a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits">cfe-commit List</a>
+ <a href="irc://irc.oftc.net/llvm">IRC: irc.oftc.net#llvm</a>
<a href="http://llvm.org/bugs/">Bug Reports</a>
+ </div>
+
+ <div class="submenu">
+ <label>The Code</label>
+ <a href="/get_started.html#build">Check Out SVN</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>
+ </div>
+
+ <div class="submenu">
+ <label>Quick Links</label>
<a href="http://t1.minormatter.com/~ddunbar/clang-cov/">Testing Coverage</a>
+ <a href="http://t1.minormatter.com/~ddunbar/references.html">Spec. References</a>
</div>
<div class="submenu">
<label>Events</label>
- <a href="http://llvm.org/devmtg/">August 1, 2008 - LLVM/Clang Developer Meeting</a>
+ <a href="http://llvm.org/devmtg/2009-10/">October 2, 2009 - LLVM/Clang Developer Meeting</a>
</div>
</div>
OpenPOWER on IntegriCloud