From 4c8b24812ddcd1dedaca343a6d4e76f91f398981 Mon Sep 17 00:00:00 2001 From: Roman Divacky Date: Wed, 14 Oct 2009 18:03:49 +0000 Subject: Update clang to r84119. --- CMakeLists.txt | 47 +- INPUTS/all-std-headers.cpp | 51 + INSTALL.txt | 49 + LICENSE.TXT | 2 +- Makefile | 29 +- NOTES.txt | 4 +- README.txt | 186 +- VER | 1 + clang.xcodeproj/project.pbxproj | 268 +- docs/DriverInternals.html | 18 +- docs/InternalsManual.html | 7 +- docs/LanguageExtensions.html | 44 +- docs/UsersManual.html | 109 +- docs/libIndex.html | 267 ++ docs/tools/Makefile | 5 +- docs/tools/clang.pod | 48 +- include/clang-c/Index.h | 220 + include/clang/AST/APValue.h | 97 +- include/clang/AST/ASTConsumer.h | 12 +- include/clang/AST/ASTContext.h | 575 ++- include/clang/AST/ASTDiagnostic.h | 2 +- include/clang/AST/Attr.h | 130 +- include/clang/AST/CXXInheritance.h | 212 + include/clang/AST/CanonicalType.h | 721 +++ include/clang/AST/Decl.h | 765 ++-- include/clang/AST/DeclBase.h | 272 +- include/clang/AST/DeclCXX.h | 1089 ++++- include/clang/AST/DeclContextInternals.h | 30 +- include/clang/AST/DeclGroup.h | 38 +- include/clang/AST/DeclNodes.def | 43 +- include/clang/AST/DeclObjC.h | 570 +-- include/clang/AST/DeclTemplate.h | 724 ++- include/clang/AST/DeclarationName.h | 58 +- include/clang/AST/Expr.h | 1021 +++-- include/clang/AST/ExprCXX.h | 625 ++- include/clang/AST/ExprObjC.h | 286 +- include/clang/AST/ExternalASTSource.h | 8 +- include/clang/AST/NestedNameSpecifier.h | 46 +- include/clang/AST/ParentMap.h | 10 +- include/clang/AST/PrettyPrinter.h | 26 +- include/clang/AST/RecordLayout.h | 180 +- include/clang/AST/Redeclarable.h | 162 + include/clang/AST/Stmt.h | 484 +- include/clang/AST/StmtCXX.h | 5 +- include/clang/AST/StmtGraphTraits.h | 28 +- include/clang/AST/StmtIterator.h | 64 +- include/clang/AST/StmtNodes.def | 14 +- include/clang/AST/StmtObjC.h | 190 +- include/clang/AST/StmtVisitor.h | 20 +- include/clang/AST/TemplateName.h | 70 +- include/clang/AST/Type.h | 1871 ++++++-- include/clang/AST/TypeLoc.h | 538 +++ include/clang/AST/TypeLocNodes.def | 55 + include/clang/AST/TypeLocVisitor.h | 58 + include/clang/AST/TypeNodes.def | 23 +- include/clang/AST/TypeOrdering.h | 6 +- include/clang/AST/TypeVisitor.h | 12 +- include/clang/Analysis/Analyses/LiveVariables.h | 42 +- .../clang/Analysis/Analyses/UninitializedValues.h | 24 +- include/clang/Analysis/AnalysisDiagnostic.h | 2 +- include/clang/Analysis/CFG.h | 451 ++ include/clang/Analysis/CallGraph.h | 147 + .../clang/Analysis/FlowSensitive/DataflowSolver.h | 129 +- .../clang/Analysis/FlowSensitive/DataflowValues.h | 58 +- include/clang/Analysis/LocalCheckers.h | 32 +- include/clang/Analysis/PathDiagnostic.h | 232 +- .../clang/Analysis/PathSensitive/AnalysisContext.h | 167 + .../clang/Analysis/PathSensitive/AnalysisManager.h | 140 + .../Analysis/PathSensitive/BasicValueFactory.h | 91 +- include/clang/Analysis/PathSensitive/BugReporter.h | 287 +- include/clang/Analysis/PathSensitive/Checker.h | 122 + .../Analysis/PathSensitive/CheckerVisitor.def | 18 + .../clang/Analysis/PathSensitive/CheckerVisitor.h | 59 + .../Analysis/PathSensitive/ConstraintManager.h | 18 +- include/clang/Analysis/PathSensitive/Environment.h | 111 +- .../clang/Analysis/PathSensitive/ExplodedGraph.h | 594 +-- include/clang/Analysis/PathSensitive/GRAuditor.h | 20 +- .../clang/Analysis/PathSensitive/GRBlockCounter.h | 16 +- .../clang/Analysis/PathSensitive/GRCoreEngine.h | 770 ++-- .../clang/Analysis/PathSensitive/GRExprEngine.h | 567 +-- .../Analysis/PathSensitive/GRExprEngineBuilders.h | 55 +- .../Analysis/PathSensitive/GRSimpleAPICheck.h | 10 +- include/clang/Analysis/PathSensitive/GRState.h | 450 +- .../clang/Analysis/PathSensitive/GRStateTrait.h | 82 +- include/clang/Analysis/PathSensitive/GRSubEngine.h | 68 + .../clang/Analysis/PathSensitive/GRTransferFuncs.h | 60 +- include/clang/Analysis/PathSensitive/GRWorkList.h | 36 +- include/clang/Analysis/PathSensitive/MemRegion.h | 496 +- include/clang/Analysis/PathSensitive/SVals.h | 259 +- include/clang/Analysis/PathSensitive/SValuator.h | 54 +- include/clang/Analysis/PathSensitive/Store.h | 122 +- .../clang/Analysis/PathSensitive/SymbolManager.h | 179 +- .../clang/Analysis/PathSensitive/ValueManager.h | 108 +- include/clang/Analysis/ProgramPoint.h | 321 +- .../clang/Analysis/Support/BlkExprDeclBitVector.h | 128 +- include/clang/Analysis/Support/BumpVector.h | 215 + include/clang/Analysis/Support/Optional.h | 55 + include/clang/Analysis/Support/SaveAndRestore.h | 44 + .../Analysis/Visitors/CFGRecStmtDeclVisitor.h | 14 +- .../clang/Analysis/Visitors/CFGRecStmtVisitor.h | 4 +- include/clang/Analysis/Visitors/CFGStmtVisitor.h | 62 +- .../clang/Analysis/Visitors/CFGVarDeclVisitor.h | 21 +- include/clang/Basic/Builtins.def | 173 +- include/clang/Basic/Builtins.h | 23 +- include/clang/Basic/ConvertUTF.h | 82 +- include/clang/Basic/Diagnostic.h | 194 +- include/clang/Basic/DiagnosticCommonKinds.td | 3 +- include/clang/Basic/DiagnosticDriverKinds.td | 10 + include/clang/Basic/DiagnosticFrontendKinds.td | 22 +- include/clang/Basic/DiagnosticGroups.td | 21 +- include/clang/Basic/DiagnosticLexKinds.td | 12 +- include/clang/Basic/DiagnosticParseKinds.td | 17 +- include/clang/Basic/DiagnosticSemaKinds.td | 483 +- include/clang/Basic/FileManager.h | 46 +- include/clang/Basic/IdentifierTable.h | 127 +- include/clang/Basic/LangOptions.h | 46 +- include/clang/Basic/Makefile | 4 +- include/clang/Basic/OnDiskHashTable.h | 88 +- include/clang/Basic/PartialDiagnostic.h | 155 + include/clang/Basic/SourceLocation.h | 90 +- include/clang/Basic/SourceManager.h | 242 +- include/clang/Basic/SourceManagerInternals.h | 24 +- include/clang/Basic/TargetInfo.h | 176 +- include/clang/Basic/TokenKinds.def | 1 + include/clang/Basic/TokenKinds.h | 2 +- include/clang/Basic/Version.h | 30 +- include/clang/CodeGen/ModuleBuilder.h | 6 +- include/clang/Driver/Action.h | 38 +- include/clang/Driver/Arg.h | 46 +- include/clang/Driver/ArgList.h | 55 +- include/clang/Driver/Compilation.h | 18 +- include/clang/Driver/Driver.h | 37 +- include/clang/Driver/DriverDiagnostic.h | 2 +- include/clang/Driver/HostInfo.h | 55 +- include/clang/Driver/Job.h | 22 +- include/clang/Driver/Option.h | 88 +- include/clang/Driver/Options.def | 23 +- include/clang/Driver/Options.h | 4 +- include/clang/Driver/Tool.h | 8 +- include/clang/Driver/ToolChain.h | 15 +- include/clang/Driver/Types.def | 5 +- include/clang/Frontend/ASTConsumers.h | 24 +- include/clang/Frontend/ASTUnit.h | 39 +- include/clang/Frontend/Analyses.def | 9 + include/clang/Frontend/CommandLineSourceLoc.h | 29 +- include/clang/Frontend/CompileOptions.h | 2 +- include/clang/Frontend/DeclXML.def | 8 +- include/clang/Frontend/DocumentXML.h | 60 +- include/clang/Frontend/FixItRewriter.h | 4 +- include/clang/Frontend/FrontendDiagnostic.h | 2 +- include/clang/Frontend/InitHeaderSearch.h | 22 +- include/clang/Frontend/ManagerRegistry.h | 2 +- include/clang/Frontend/PCHBitCodes.h | 93 +- include/clang/Frontend/PCHReader.h | 155 +- include/clang/Frontend/PCHWriter.h | 69 +- include/clang/Frontend/PathDiagnosticClients.h | 36 +- include/clang/Frontend/StmtXML.def | 3 + include/clang/Frontend/TextDiagnosticPrinter.h | 8 +- include/clang/Frontend/TypeXML.def | 21 +- include/clang/Frontend/Utils.h | 31 +- include/clang/Index/ASTLocation.h | 174 + include/clang/Index/Analyzer.h | 56 + include/clang/Index/DeclReferenceMap.h | 50 + include/clang/Index/Entity.h | 143 + include/clang/Index/GlobalSelector.h | 99 + include/clang/Index/Handlers.h | 81 + include/clang/Index/IndexProvider.h | 38 + include/clang/Index/Indexer.h | 75 + include/clang/Index/Program.h | 45 + include/clang/Index/STLExtras.h | 63 + include/clang/Index/SelectorMap.h | 57 + include/clang/Index/TranslationUnit.h | 37 + include/clang/Index/Utils.h | 35 + include/clang/Lex/DirectoryLookup.h | 40 +- include/clang/Lex/HeaderMap.h | 14 +- include/clang/Lex/HeaderSearch.h | 50 +- include/clang/Lex/LexDiagnostic.h | 2 +- include/clang/Lex/Lexer.h | 100 +- include/clang/Lex/LiteralSupport.h | 46 +- include/clang/Lex/MacroInfo.h | 54 +- include/clang/Lex/MultipleIncludeOpt.h | 22 +- include/clang/Lex/PPCallbacks.h | 28 +- include/clang/Lex/PTHLexer.h | 32 +- include/clang/Lex/PTHManager.h | 44 +- include/clang/Lex/Pragma.h | 14 +- include/clang/Lex/Preprocessor.h | 201 +- include/clang/Lex/PreprocessorLexer.h | 58 +- include/clang/Lex/ScratchBuffer.h | 4 +- include/clang/Lex/Token.h | 70 +- include/clang/Lex/TokenConcatenation.h | 16 +- include/clang/Lex/TokenLexer.h | 40 +- include/clang/Parse/Action.h | 909 +++- include/clang/Parse/AttributeList.h | 55 +- include/clang/Parse/DeclSpec.h | 338 +- include/clang/Parse/Designator.h | 44 +- include/clang/Parse/Ownership.h | 68 +- include/clang/Parse/ParseDiagnostic.h | 2 +- include/clang/Parse/Parser.h | 290 +- include/clang/Parse/Scope.h | 46 +- include/clang/Rewrite/DeltaTree.h | 8 +- include/clang/Rewrite/HTMLRewrite.h | 20 +- include/clang/Rewrite/RewriteRope.h | 62 +- include/clang/Rewrite/Rewriter.h | 111 +- include/clang/Rewrite/TokenRewriter.h | 24 +- include/clang/Sema/CodeCompleteConsumer.h | 332 ++ include/clang/Sema/ExternalSemaSource.h | 8 +- include/clang/Sema/ParseAST.h | 10 +- include/clang/Sema/SemaConsumer.h | 4 +- include/clang/Sema/SemaDiagnostic.h | 2 +- lib/AST/APValue.cpp | 16 +- lib/AST/ASTContext.cpp | 2766 ++++++----- lib/AST/CMakeLists.txt | 11 +- lib/AST/CXXInheritance.cpp | 244 + lib/AST/Decl.cpp | 509 ++- lib/AST/DeclBase.cpp | 164 +- lib/AST/DeclCXX.cpp | 610 ++- lib/AST/DeclObjC.cpp | 440 +- lib/AST/DeclPrinter.cpp | 244 +- lib/AST/DeclTemplate.cpp | 206 +- lib/AST/DeclarationName.cpp | 44 +- lib/AST/Expr.cpp | 797 ++-- lib/AST/ExprCXX.cpp | 274 +- lib/AST/ExprConstant.cpp | 284 +- lib/AST/InheritViz.cpp | 10 +- lib/AST/NestedNameSpecifier.cpp | 61 +- lib/AST/ParentMap.cpp | 10 +- lib/AST/RecordLayoutBuilder.cpp | 674 +++ lib/AST/RecordLayoutBuilder.h | 146 + lib/AST/Stmt.cpp | 80 +- lib/AST/StmtDumper.cpp | 143 +- lib/AST/StmtIterator.cpp | 40 +- lib/AST/StmtPrinter.cpp | 191 +- lib/AST/StmtProfile.cpp | 720 +++ lib/AST/StmtViz.cpp | 17 +- lib/AST/TemplateName.cpp | 42 +- lib/AST/Type.cpp | 987 ++-- lib/AST/TypeLoc.cpp | 370 ++ lib/Analysis/AnalysisContext.cpp | 138 + lib/Analysis/AnalysisManager.cpp | 35 + lib/Analysis/BasicConstraintManager.cpp | 62 +- lib/Analysis/BasicObjCFoundationChecks.cpp | 329 +- lib/Analysis/BasicObjCFoundationChecks.h | 21 +- lib/Analysis/BasicStore.cpp | 380 +- lib/Analysis/BasicValueFactory.cpp | 138 +- lib/Analysis/BugReporter.cpp | 994 ++-- lib/Analysis/BugReporterVisitors.cpp | 349 ++ lib/Analysis/CFG.cpp | 2084 +++++++++ lib/Analysis/CFRefCount.cpp | 1882 ++++---- lib/Analysis/CMakeLists.txt | 10 +- lib/Analysis/CallGraph.cpp | 150 + lib/Analysis/CallInliner.cpp | 75 + lib/Analysis/CheckDeadStores.cpp | 99 +- lib/Analysis/CheckNSError.cpp | 166 +- lib/Analysis/CheckObjCDealloc.cpp | 134 +- lib/Analysis/CheckObjCInstMethSignature.cpp | 47 +- lib/Analysis/CheckObjCUnusedIVars.cpp | 64 +- lib/Analysis/CheckSecuritySyntaxOnly.cpp | 409 ++ lib/Analysis/Environment.cpp | 141 +- lib/Analysis/ExplodedGraph.cpp | 200 +- lib/Analysis/GRBlockCounter.cpp | 2 +- lib/Analysis/GRCoreEngine.cpp | 439 +- lib/Analysis/GRExprEngine.cpp | 2541 +++++----- lib/Analysis/GRExprEngineInternalChecks.cpp | 844 ++-- lib/Analysis/GRState.cpp | 158 +- lib/Analysis/LiveVariables.cpp | 122 +- lib/Analysis/MemRegion.cpp | 212 +- lib/Analysis/PathDiagnostic.cpp | 96 +- lib/Analysis/RangeConstraintManager.cpp | 60 +- lib/Analysis/RegionStore.cpp | 1811 +++++--- lib/Analysis/SVals.cpp | 163 +- lib/Analysis/SValuator.cpp | 160 + lib/Analysis/SimpleConstraintManager.cpp | 64 +- lib/Analysis/SimpleConstraintManager.h | 24 +- lib/Analysis/SimpleSValuator.cpp | 158 +- lib/Analysis/Store.cpp | 246 +- lib/Analysis/SymbolManager.cpp | 139 +- lib/Analysis/UninitializedValues.cpp | 84 +- lib/Analysis/ValueManager.cpp | 114 +- lib/Basic/Builtins.cpp | 18 +- lib/Basic/CMakeLists.txt | 11 + lib/Basic/ConvertUTF.c | 606 +-- lib/Basic/Diagnostic.cpp | 121 +- lib/Basic/FileManager.cpp | 88 +- lib/Basic/IdentifierTable.cpp | 58 +- lib/Basic/Makefile | 11 + lib/Basic/SourceLocation.cpp | 4 +- lib/Basic/SourceManager.cpp | 302 +- lib/Basic/TargetInfo.cpp | 57 +- lib/Basic/Targets.cpp | 1092 +++-- lib/Basic/Version.cpp | 49 + lib/CMakeLists.txt | 1 + lib/CodeGen/ABIInfo.h | 22 +- lib/CodeGen/CGBlocks.cpp | 196 +- lib/CodeGen/CGBlocks.h | 40 +- lib/CodeGen/CGBuiltin.cpp | 255 +- lib/CodeGen/CGCXX.cpp | 1639 ++++++- lib/CodeGen/CGCXX.h | 2 +- lib/CodeGen/CGCXXClass.cpp | 176 + lib/CodeGen/CGCXXExpr.cpp | 304 ++ lib/CodeGen/CGCXXTemp.cpp | 102 +- lib/CodeGen/CGCall.cpp | 268 +- lib/CodeGen/CGCall.h | 33 +- lib/CodeGen/CGDebugInfo.cpp | 686 ++- lib/CodeGen/CGDebugInfo.h | 56 +- lib/CodeGen/CGDecl.cpp | 291 +- lib/CodeGen/CGExpr.cpp | 889 ++-- lib/CodeGen/CGExprAgg.cpp | 251 +- lib/CodeGen/CGExprComplex.cpp | 177 +- lib/CodeGen/CGExprConstant.cpp | 868 +++- lib/CodeGen/CGExprScalar.cpp | 684 +-- lib/CodeGen/CGObjC.cpp | 259 +- lib/CodeGen/CGObjCGNU.cpp | 999 ++-- lib/CodeGen/CGObjCMac.cpp | 2817 ++++++------ lib/CodeGen/CGObjCRuntime.h | 49 +- lib/CodeGen/CGRecordLayoutBuilder.cpp | 386 ++ lib/CodeGen/CGRecordLayoutBuilder.h | 134 + lib/CodeGen/CGRtti.cpp | 47 + lib/CodeGen/CGStmt.cpp | 330 +- lib/CodeGen/CGValue.h | 124 +- lib/CodeGen/CGVtable.cpp | 557 +++ lib/CodeGen/CGVtable.h | 61 + lib/CodeGen/CMakeLists.txt | 11 +- lib/CodeGen/CodeGenFunction.cpp | 437 +- lib/CodeGen/CodeGenFunction.h | 291 +- lib/CodeGen/CodeGenModule.cpp | 846 ++-- lib/CodeGen/CodeGenModule.h | 132 +- lib/CodeGen/CodeGenTypes.cpp | 376 +- lib/CodeGen/CodeGenTypes.h | 124 +- lib/CodeGen/Makefile | 3 + lib/CodeGen/Mangle.cpp | 1098 ++++- lib/CodeGen/Mangle.h | 48 +- lib/CodeGen/ModuleBuilder.cpp | 16 +- lib/CodeGen/README.txt | 18 - lib/CodeGen/TargetABIInfo.cpp | 647 ++- lib/Driver/Action.cpp | 12 +- lib/Driver/Arg.cpp | 23 +- lib/Driver/ArgList.cpp | 54 +- lib/Driver/Compilation.cpp | 46 +- lib/Driver/Driver.cpp | 580 ++- lib/Driver/HostInfo.cpp | 257 +- lib/Driver/Job.cpp | 6 +- lib/Driver/Makefile | 16 +- lib/Driver/OptTable.cpp | 18 +- lib/Driver/Option.cpp | 57 +- lib/Driver/Tool.cpp | 2 +- lib/Driver/ToolChain.cpp | 12 +- lib/Driver/ToolChains.cpp | 392 +- lib/Driver/ToolChains.h | 138 +- lib/Driver/Tools.cpp | 1082 +++-- lib/Driver/Tools.h | 174 +- lib/Driver/Types.cpp | 48 +- lib/Frontend/ASTConsumers.cpp | 209 +- lib/Frontend/ASTUnit.cpp | 63 +- lib/Frontend/AnalysisConsumer.cpp | 536 +-- lib/Frontend/Backend.cpp | 85 +- lib/Frontend/CMakeLists.txt | 11 +- lib/Frontend/CacheTokens.cpp | 189 +- lib/Frontend/DeclXML.cpp | 74 +- lib/Frontend/DependencyFile.cpp | 16 +- lib/Frontend/DiagChecker.cpp | 32 +- lib/Frontend/DocumentXML.cpp | 157 +- lib/Frontend/FixItRewriter.cpp | 44 +- lib/Frontend/GeneratePCH.cpp | 21 +- lib/Frontend/HTMLDiagnostics.cpp | 371 +- lib/Frontend/HTMLPrint.cpp | 10 +- lib/Frontend/InitHeaderSearch.cpp | 459 +- lib/Frontend/InitPreprocessor.cpp | 111 +- lib/Frontend/PCHReader.cpp | 612 ++- lib/Frontend/PCHReaderDecl.cpp | 174 +- lib/Frontend/PCHReaderStmt.cpp | 127 +- lib/Frontend/PCHWriter.cpp | 547 ++- lib/Frontend/PCHWriterDecl.cpp | 221 +- lib/Frontend/PCHWriterStmt.cpp | 101 +- lib/Frontend/PlistDiagnostics.cpp | 148 +- lib/Frontend/PrintParserCallbacks.cpp | 85 +- lib/Frontend/PrintPreprocessedOutput.cpp | 96 +- lib/Frontend/RewriteBlocks.cpp | 311 +- lib/Frontend/RewriteMacros.cpp | 49 +- lib/Frontend/RewriteObjC.cpp | 1306 +++--- lib/Frontend/RewriteTest.cpp | 4 +- lib/Frontend/StmtXML.cpp | 78 +- lib/Frontend/TextDiagnosticBuffer.cpp | 2 +- lib/Frontend/TextDiagnosticPrinter.cpp | 138 +- lib/Frontend/TypeXML.cpp | 72 +- lib/Frontend/Warnings.cpp | 16 +- lib/Headers/CMakeLists.txt | 7 +- lib/Headers/Makefile | 8 +- lib/Headers/emmintrin.h | 34 +- lib/Headers/mmintrin.h | 12 +- lib/Headers/stdarg.h | 2 +- lib/Index/ASTLocation.cpp | 117 + lib/Index/ASTVisitor.h | 144 + lib/Index/Analyzer.cpp | 438 ++ lib/Index/CMakeLists.txt | 15 + lib/Index/DeclReferenceMap.cpp | 91 + lib/Index/Entity.cpp | 225 + lib/Index/EntityImpl.h | 70 + lib/Index/GlobalSelector.cpp | 73 + lib/Index/Handlers.cpp | 22 + lib/Index/IndexProvider.cpp | 20 + lib/Index/Indexer.cpp | 104 + lib/Index/Makefile | 28 + lib/Index/Program.cpp | 50 + lib/Index/ProgramImpl.h | 56 + lib/Index/ResolveLocation.cpp | 505 ++ lib/Index/SelectorMap.cpp | 85 + lib/Lex/CMakeLists.txt | 4 +- lib/Lex/HeaderMap.cpp | 44 +- lib/Lex/HeaderSearch.cpp | 112 +- lib/Lex/Lexer.cpp | 436 +- lib/Lex/LiteralSupport.cpp | 267 +- lib/Lex/MacroArgs.cpp | 34 +- lib/Lex/MacroArgs.h | 26 +- lib/Lex/MacroInfo.cpp | 12 +- lib/Lex/PPCaching.cpp | 5 +- lib/Lex/PPDirectives.cpp | 352 +- lib/Lex/PPExpressions.cpp | 100 +- lib/Lex/PPLexerChange.cpp | 68 +- lib/Lex/PPMacroExpansion.cpp | 169 +- lib/Lex/PTHLexer.cpp | 220 +- lib/Lex/Pragma.cpp | 170 +- lib/Lex/Preprocessor.cpp | 134 +- lib/Lex/PreprocessorLexer.cpp | 4 +- lib/Lex/ScratchBuffer.cpp | 10 +- lib/Lex/TokenConcatenation.cpp | 42 +- lib/Lex/TokenLexer.cpp | 120 +- lib/Makefile | 2 +- lib/Parse/AttributeList.cpp | 20 +- lib/Parse/CMakeLists.txt | 4 +- lib/Parse/DeclSpec.cpp | 186 +- lib/Parse/ExtensionRAIIObject.h | 2 +- lib/Parse/MinimalAction.cpp | 70 +- lib/Parse/ParseCXXInlineMethods.cpp | 44 +- lib/Parse/ParseDecl.cpp | 858 ++-- lib/Parse/ParseDeclCXX.cpp | 533 ++- lib/Parse/ParseExpr.cpp | 255 +- lib/Parse/ParseExprCXX.cpp | 220 +- lib/Parse/ParseInit.cpp | 40 +- lib/Parse/ParseObjc.cpp | 301 +- lib/Parse/ParsePragma.cpp | 65 +- lib/Parse/ParsePragma.h | 18 +- lib/Parse/ParseStmt.cpp | 109 +- lib/Parse/ParseTemplate.cpp | 221 +- lib/Parse/ParseTentative.cpp | 24 +- lib/Parse/Parser.cpp | 137 +- lib/Rewrite/CMakeLists.txt | 2 +- lib/Rewrite/DeltaTree.cpp | 106 +- lib/Rewrite/HTMLRewrite.cpp | 227 +- lib/Rewrite/RewriteRope.cpp | 184 +- lib/Rewrite/Rewriter.cpp | 74 +- lib/Rewrite/TokenRewriter.cpp | 20 +- lib/Sema/CMakeLists.txt | 12 +- lib/Sema/CodeCompleteConsumer.cpp | 184 + lib/Sema/IdentifierResolver.cpp | 18 +- lib/Sema/IdentifierResolver.h | 10 +- lib/Sema/JumpDiagnostics.cpp | 62 +- lib/Sema/ParseAST.cpp | 37 +- lib/Sema/Sema.cpp | 329 +- lib/Sema/Sema.h | 1874 +++++--- lib/Sema/SemaAccess.cpp | 89 +- lib/Sema/SemaAttr.cpp | 84 +- lib/Sema/SemaCXXCast.cpp | 1128 +++++ lib/Sema/SemaCXXScopeSpec.cpp | 381 +- lib/Sema/SemaChecking.cpp | 530 ++- lib/Sema/SemaCodeComplete.cpp | 1432 ++++++ lib/Sema/SemaDecl.cpp | 2593 +++++++---- lib/Sema/SemaDeclAttr.cpp | 544 ++- lib/Sema/SemaDeclCXX.cpp | 2665 ++++++++--- lib/Sema/SemaDeclObjC.cpp | 832 ++-- lib/Sema/SemaExceptionSpec.cpp | 320 ++ lib/Sema/SemaExpr.cpp | 2812 +++++++----- lib/Sema/SemaExprCXX.cpp | 1129 +++-- lib/Sema/SemaExprObjC.cpp | 446 +- lib/Sema/SemaInit.cpp | 462 +- lib/Sema/SemaLookup.cpp | 1482 +++--- lib/Sema/SemaOverload.cpp | 2271 +++++---- lib/Sema/SemaOverload.h | 37 +- lib/Sema/SemaStmt.cpp | 405 +- lib/Sema/SemaTemplate.cpp | 2545 ++++++++--- lib/Sema/SemaTemplate.h | 104 + lib/Sema/SemaTemplateDeduction.cpp | 1931 ++++++-- lib/Sema/SemaTemplateInstantiate.cpp | 1238 +++-- lib/Sema/SemaTemplateInstantiateDecl.cpp | 1342 ++++-- lib/Sema/SemaType.cpp | 797 ++-- lib/Sema/TreeTransform.h | 4829 ++++++++++++++++++++ test/Analysis/CFDateGC.m | 8 +- test/Analysis/CheckNSError.m | 4 +- test/Analysis/NSPanel.m | 2 +- test/Analysis/NSString.m | 15 +- test/Analysis/PR2978.m | 1 + test/Analysis/PR3991.m | 1 + test/Analysis/array-struct.c | 6 +- test/Analysis/casts.c | 19 +- test/Analysis/cfref_rdar6080742.c | 18 +- test/Analysis/complex.c | 2 +- test/Analysis/dead-stores.c | 171 +- test/Analysis/dead-stores.cpp | 19 + test/Analysis/exercise-ps.c | 2 +- test/Analysis/misc-ps-basic-store.m | 14 + test/Analysis/misc-ps-region-store-i386.m | 14 + test/Analysis/misc-ps-region-store-x86_64.m | 14 + test/Analysis/misc-ps-region-store.m | 243 +- test/Analysis/misc-ps.m | 410 +- ...il-receiver-undefined-larger-than-voidptr-ret.m | 3 +- test/Analysis/no-outofbounds.c | 12 + test/Analysis/null-deref-ps.c | 39 +- test/Analysis/outofbound.c | 1 + test/Analysis/pr4209.m | 3 +- test/Analysis/rdar-6442306-1.m | 1 + test/Analysis/rdar-6540084.m | 1 + test/Analysis/rdar-6541136-region.c | 7 +- test/Analysis/rdar-6562655.m | 6 +- ...dar-6600344-nil-receiver-undefined-struct-ret.m | 3 +- test/Analysis/rdar-7168531.m | 19 + test/Analysis/region-1.m | 1 + test/Analysis/region-only-test.c | 2 +- test/Analysis/retain-release-gc-only.m | 186 +- test/Analysis/retain-release-region-store.m | 24 + test/Analysis/retain-release.m | 439 +- test/Analysis/security-syntax-checks.m | 91 + test/Analysis/uninit-vals-ps-region.c | 18 + test/Analysis/uninit-vals-ps.c | 50 +- test/Analysis/uninit-vals.c | 2 +- test/Analysis/unions-region.m | 41 + test/Analysis/unused-ivars.m | 45 +- test/CMakeLists.txt | 73 +- .../basic.lookup.argdep/p2-template-id.cpp | 27 + .../basic/basic.lookup/basic.lookup.argdep/p2.cpp | 73 + .../basic/basic.lookup/basic.lookup.argdep/p4.cpp | 42 + .../basic.lookup/basic.lookup.elab/templateid.cpp | 18 + .../basic.lookup.qual/namespace.qual/p2.cpp | 65 + .../basic.lookup.qual/namespace.qual/p3.cpp | 41 + .../basic.lookup.qual/namespace.qual/p4.cpp | 25 + .../basic.lookup.qual/namespace.qual/p5.cpp | 35 + .../basic/basic.lookup/basic.lookup.unqual/p3.cpp | 4 +- .../CXX/basic/basic.start/basic.start.main/p2a.cpp | 8 + .../CXX/basic/basic.start/basic.start.main/p2b.cpp | 8 + .../CXX/basic/basic.start/basic.start.main/p2c.cpp | 4 + .../CXX/basic/basic.start/basic.start.main/p2d.cpp | 4 + .../CXX/basic/basic.start/basic.start.main/p2e.cpp | 4 + .../CXX/basic/basic.start/basic.start.main/p2f.cpp | 7 + .../CXX/basic/basic.start/basic.start.main/p2g.cpp | 4 + .../basic/basic.stc/basic.stc.dynamic/p2-nodef.cpp | 7 + test/CXX/basic/basic.stc/basic.stc.dynamic/p2.cpp | 25 + test/CXX/class.derived/class.virtual/p12.cpp | 19 + test/CXX/class/class.friend/p1-ambiguous.cpp | 37 + test/CXX/class/class.friend/p1.cpp | 76 + test/CXX/class/class.friend/p2.cpp | 10 + test/CXX/class/class.friend/p6.cpp | 10 + test/CXX/class/class.local/p3.cpp | 2 +- test/CXX/class/class.local/p4.cpp | 2 +- test/CXX/class/class.nest/p1.cpp | 14 + test/CXX/class/class.nested.type/p1.cpp | 4 +- test/CXX/class/class.union/p1.cpp | 105 + .../namespace.def/namespace.memdef/p3.cpp | 15 + .../basic.namespace/namespace.udecl/p3-cxx0x.cpp | 20 + .../basic.namespace/namespace.udecl/p5-cxx0x.cpp | 12 + .../basic.namespace/namespace.udecl/p6-cxx0x.cpp | 8 + .../basic.namespace/namespace.udecl/p8-cxx0x.cpp | 15 + test/CXX/dcl.dcl/dcl.spec/dcl.stc/p9.cpp | 4 +- .../dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp | 10 + .../dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp | 13 + .../dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp | 60 + .../dcl.decl/dcl.meaning/dcl.fct.default/p10.cpp | 16 + .../dcl.decl/dcl.meaning/dcl.fct.default/p2.cpp | 9 + .../dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp | 13 + .../dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp | 55 + .../dcl.decl/dcl.meaning/dcl.fct.default/p5.cpp | 18 + .../dcl.decl/dcl.meaning/dcl.fct.default/p6.cpp | 32 + .../dcl.decl/dcl.meaning/dcl.fct.default/p7.cpp | 7 + .../dcl.decl/dcl.meaning/dcl.fct.default/p8.cpp | 4 + test/CXX/dcl.decl/dcl.meaning/dcl.fct/p3.cpp | 3 + test/CXX/dcl.decl/dcl.meaning/dcl.mptr/p3.cpp | 26 + test/CXX/expr/p3.cpp | 15 + test/CXX/expr/p8.cpp | 18 + test/CXX/expr/p9.cpp | 50 + test/CXX/lex/lex.trigraph/p1.cpp | 19 + test/CXX/lex/lex.trigraph/p2.cpp | 3 + test/CXX/lex/lex.trigraph/p3.cpp | 8 + test/CXX/over/over.match/over.match.best/p1.cpp | 16 + test/CXX/over/over.over/p1.cpp | 94 + test/CXX/over/over.over/p2.cpp | 10 + test/CXX/over/over.over/p4.cpp | 23 + test/CXX/temp/temp.decls/temp.class.spec/p6.cpp | 20 + .../temp.class.spec/temp.class.order/p2.cpp | 16 + .../temp.class.spec.mfunc/p1-neg.cpp | 25 + .../temp.class.spec/temp.class.spec.mfunc/p1.cpp | 26 + .../temp.decls/temp.class/temp.mem.class/p1.cpp | 27 + .../temp.class/temp.mem.func/p1-retmem.cpp | 28 + .../temp.decls/temp.class/temp.mem.func/p1.cpp | 68 + .../temp.decls/temp.class/temp.mem.func/p1inst.cpp | 17 + .../temp.decls/temp.class/temp.mem.func/pr5056.cpp | 17 + .../temp.decls/temp.class/temp.static/p1-inst.cpp | 28 + .../temp/temp.decls/temp.class/temp.static/p1.cpp | 26 + .../temp.decls/temp.fct/temp.func.order/p4.cpp | 23 + .../temp.decls/temp.fct/temp.func.order/p5.cpp | 12 + .../temp.decls/temp.fct/temp.over.link/p4-neg.cpp | 6 +- .../temp/temp.decls/temp.fct/temp.over.link/p6.cpp | 16 + test/CXX/temp/temp.decls/temp.friend/p1.cpp | 56 + test/CXX/temp/temp.decls/temp.friend/p3.cpp | 13 + test/CXX/temp/temp.decls/temp.friend/p5.cpp | 11 + test/CXX/temp/temp.decls/temp.mem/p1.cpp | 16 + .../temp/temp.fct.spec/temp.arg.explicit/p3.cpp | 2 +- .../temp.deduct/temp.deduct.call/p3.cpp | 32 +- .../temp.deduct/temp.deduct.conv/p2.cpp | 36 + .../temp.deduct/temp.deduct.conv/p3.cpp | 30 + .../temp.deduct/temp.deduct.conv/p4.cpp | 44 + .../temp.deduct/temp.deduct.funcaddr/p1.cpp | 22 + .../temp.deduct/temp.deduct.partial/p11.cpp | 22 + test/CXX/temp/temp.param/p1.cpp | 3 + test/CXX/temp/temp.res/temp.dep/p3.cpp | 43 + test/CXX/temp/temp.spec/temp.expl.spec/p1.cpp | 99 + test/CXX/temp/temp.spec/temp.expl.spec/p10.cpp | 7 + test/CXX/temp/temp.spec/temp.expl.spec/p11.cpp | 8 + test/CXX/temp/temp.spec/temp.expl.spec/p13.cpp | 6 + test/CXX/temp/temp.spec/temp.expl.spec/p14.cpp | 42 + test/CXX/temp/temp.spec/temp.expl.spec/p15.cpp | 22 + test/CXX/temp/temp.spec/temp.expl.spec/p16.cpp | 26 + test/CXX/temp/temp.spec/temp.expl.spec/p17.cpp | 12 + test/CXX/temp/temp.spec/temp.expl.spec/p18.cpp | 20 + test/CXX/temp/temp.spec/temp.expl.spec/p19.cpp | 30 + test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp | 239 + test/CXX/temp/temp.spec/temp.expl.spec/p20.cpp | 14 + test/CXX/temp/temp.spec/temp.expl.spec/p21.cpp | 30 + test/CXX/temp/temp.spec/temp.expl.spec/p3.cpp | 14 + test/CXX/temp/temp.spec/temp.expl.spec/p4.cpp | 59 + test/CXX/temp/temp.spec/temp.expl.spec/p5.cpp | 61 + test/CXX/temp/temp.spec/temp.expl.spec/p6.cpp | 56 + test/CXX/temp/temp.spec/temp.expl.spec/p9.cpp | 14 + test/CodeCompletion/call.cpp | 28 + test/CodeCompletion/enum-switch-case-qualified.cpp | 33 + test/CodeCompletion/enum-switch-case.c | 29 + test/CodeCompletion/enum-switch-case.cpp | 29 + test/CodeCompletion/function-templates.cpp | 15 + test/CodeCompletion/functions.cpp | 9 + test/CodeCompletion/member-access.c | 13 + test/CodeCompletion/member-access.cpp | 43 + test/CodeCompletion/namespace-alias.cpp | 21 + test/CodeCompletion/namespace.cpp | 15 + test/CodeCompletion/nested-name-specifier.cpp | 18 + test/CodeCompletion/operator.cpp | 18 + test/CodeCompletion/ordinary-name.c | 12 + test/CodeCompletion/property.m | 29 + test/CodeCompletion/tag.c | 13 + test/CodeCompletion/tag.cpp | 26 + test/CodeCompletion/templates.cpp | 17 + test/CodeCompletion/truncation.c | 12 + test/CodeCompletion/truncation.c.h | 5 + test/CodeCompletion/using-namespace.cpp | 21 + test/CodeCompletion/using.cpp | 25 + test/CodeGen/2008-07-17-no-emit-on-error.c | 4 +- ...2008-07-22-bitfield-init-after-zero-len-array.c | 5 +- test/CodeGen/2008-07-29-override-alias-decl.c | 2 +- test/CodeGen/2009-01-21-invalid-debug-info.m | 2 +- test/CodeGen/2009-04-23-dbg.c | 2 +- test/CodeGen/2009-06-01-addrofknr.c | 12 +- test/CodeGen/2009-07-31-DbgDeclare.c | 5 + test/CodeGen/2009-08-14-vararray-crash.c | 11 + test/CodeGen/PR3613-static-decl.c | 2 +- test/CodeGen/PR4611-bitfield-layout.c | 6 + test/CodeGen/PR5060-align.c | 13 + test/CodeGen/address-space-compound-literal.c | 5 + test/CodeGen/address-space-field1.c | 39 + test/CodeGen/address-space-field2.c | 50 + test/CodeGen/address-space-field3.c | 46 + test/CodeGen/address-space-field4.c | 61 + test/CodeGen/arm-arguments.c | 94 + test/CodeGen/arm_asm_clobber.c | 21 + test/CodeGen/array.c | 4 +- test/CodeGen/asm-inout.c | 18 + test/CodeGen/asm.c | 13 +- test/CodeGen/attr-cleanup.c | 2 +- test/CodeGen/attributes.c | 100 +- test/CodeGen/blocks-2.c | 3 +- test/CodeGen/blocks-aligned-byref-variable.c | 19 + test/CodeGen/blocks-seq.c | 20 +- test/CodeGen/boolassign.c | 5 +- test/CodeGen/builtin-attributes.c | 12 + test/CodeGen/builtins-ffs_parity_popcount.c | 4 +- test/CodeGen/builtins-powi.c | 4 +- test/CodeGen/builtins.c | 2 + test/CodeGen/cast-to-union.c | 8 +- test/CodeGen/conditional.c | 21 +- test/CodeGen/const-init.c | 61 +- test/CodeGen/darwin-string-literals.c | 16 +- test/CodeGen/debug-info.c | 6 +- test/CodeGen/designated-initializers.c | 5 +- test/CodeGen/exprs.c | 8 +- test/CodeGen/ext-vector-shuffle.c | 4 +- test/CodeGen/ext-vector.c | 19 +- test/CodeGen/function-attributes.c | 2 +- test/CodeGen/functions.c | 5 +- test/CodeGen/global-decls.c | 2 +- test/CodeGen/global-init.c | 25 +- test/CodeGen/global-with-initialiser.c | 6 +- test/CodeGen/globalinit.c | 2 +- test/CodeGen/init-with-member-expr.c | 2 +- test/CodeGen/inline.c | 16 +- test/CodeGen/inline2.c | 62 + test/CodeGen/packed-union.c | 16 + test/CodeGen/parameter-passing.c | 2 +- test/CodeGen/pragma-pack-1.c | 7 + test/CodeGen/pragma-pack-2.c | 23 + test/CodeGen/pragma-pack-3.c | 19 + test/CodeGen/pragma-weak.c | 165 + test/CodeGen/predefined-expr.c | 45 + test/CodeGen/regparm.c | 5 +- test/CodeGen/stack-protector.c | 3 +- test/CodeGen/statements.c | 22 + test/CodeGen/staticinit.c | 6 +- test/CodeGen/stdcall-fastcall.c | 2 +- test/CodeGen/string-init.c | 2 +- test/CodeGen/struct-init.c | 4 +- test/CodeGen/struct-x86-darwin.c | 20 +- test/CodeGen/struct.c | 43 +- test/CodeGen/union-init.c | 28 +- test/CodeGen/union-init2.c | 4 + test/CodeGen/unreachable.c | 37 + test/CodeGen/unwind-attr.c | 1 + test/CodeGen/vector.c | 10 +- test/CodeGen/visibility.c | 2 +- test/CodeGen/volatile.c | 2 +- test/CodeGen/x86.c | 2 +- test/CodeGen/x86_32-arguments.c | 127 +- test/CodeGen/x86_64-arguments.c | 28 +- test/CodeGenCXX/PR4827-cast.cpp | 5 + test/CodeGenCXX/PR4890-debug-info-dtor.cpp | 6 + test/CodeGenCXX/PR4983-constructor-conversion.cpp | 16 + test/CodeGenCXX/PR5050-constructor-conversion.cpp | 19 + test/CodeGenCXX/PR5093-static-member-function.cpp | 9 + test/CodeGenCXX/anonymous-namespaces.cpp | 22 + .../anonymous-union-member-initializer.cpp | 12 + test/CodeGenCXX/array-pointer-decay.cpp | 7 + test/CodeGenCXX/attr.cpp | 36 + test/CodeGenCXX/cast-conversion.cpp | 33 + test/CodeGenCXX/class-layout.cpp | 5 + test/CodeGenCXX/conditional-expr-lvalue.cpp | 7 + test/CodeGenCXX/constructor-conversion.cpp | 55 + test/CodeGenCXX/constructor-default-arg.cpp | 40 + test/CodeGenCXX/constructor-for-array-members.cpp | 44 + test/CodeGenCXX/constructor-init-reference.cpp | 9 + test/CodeGenCXX/constructor-init.cpp | 61 + test/CodeGenCXX/constructor-template.cpp | 56 + test/CodeGenCXX/conversion-function.cpp | 115 + test/CodeGenCXX/convert-to-fptr.cpp | 47 + test/CodeGenCXX/copy-assign-synthesis-1.cpp | 109 + test/CodeGenCXX/copy-assign-synthesis.cpp | 79 + test/CodeGenCXX/copy-constructor-elim.cpp | 43 + test/CodeGenCXX/copy-constructor-synthesis.cpp | 110 + test/CodeGenCXX/decl-ref-init.cpp | 31 + test/CodeGenCXX/default-arg-temps.cpp | 14 +- .../CodeGenCXX/default-constructor-for-members.cpp | 24 + test/CodeGenCXX/default-destructor-synthesis.cpp | 60 + test/CodeGenCXX/delete.cpp | 37 + test/CodeGenCXX/derived-to-base.cpp | 16 + test/CodeGenCXX/destructor-calls.cpp | 41 + test/CodeGenCXX/destructors.cpp | 30 + .../devirtualize-virtual-function-calls.cpp | 47 + test/CodeGenCXX/explicit-instantiation.cpp | 13 +- .../function-template-specialization.cpp | 15 +- test/CodeGenCXX/global-init.cpp | 16 + test/CodeGenCXX/mangle-extreme.cpp | 47 + test/CodeGenCXX/mangle-subst-std.cpp | 39 + test/CodeGenCXX/mangle-subst.cpp | 56 + test/CodeGenCXX/mangle.cpp | 190 +- test/CodeGenCXX/member-function-pointers.cpp | 73 + test/CodeGenCXX/member-functions.cpp | 2 +- test/CodeGenCXX/member-pointers-zero-init.cpp | 34 + test/CodeGenCXX/namespace-aliases.cpp | 3 + test/CodeGenCXX/nested-base-member-access.cpp | 52 + test/CodeGenCXX/new.cpp | 23 +- test/CodeGenCXX/nullptr.cpp | 7 + test/CodeGenCXX/overload-binop-implicitconvert.cpp | 22 + test/CodeGenCXX/predefined-expr-sizeof.cpp | 30 + test/CodeGenCXX/predefined-expr.cpp | 226 + test/CodeGenCXX/references.cpp | 13 + test/CodeGenCXX/reinterpret-cast.cpp | 12 + test/CodeGenCXX/static-data-member.cpp | 8 + test/CodeGenCXX/static-init.cpp | 13 + test/CodeGenCXX/temp-1.cpp | 83 + ...template-anonymous-union-member-initializer.cpp | 10 + test/CodeGenCXX/trivial-constructor-init.cpp | 21 + test/CodeGenCXX/virt.cpp | 1024 +++++ test/CodeGenCXX/virtual-base-cast.cpp | 9 + test/CodeGenCXX/virtual-function-calls.cpp | 11 + test/CodeGenCXX/vtable-cast-crash.cpp | 21 + test/CodeGenCXX/x86_64-arguments.cpp | 10 + test/CodeGenObjC/PR4541.m | 19 + test/CodeGenObjC/PR4894-recursive-debug-crash.m | 40 + test/CodeGenObjC/constant-strings.m | 4 +- test/CodeGenObjC/debug-info-linkagename.m | 17 + test/CodeGenObjC/for-in.m | 44 + test/CodeGenObjC/ivar-layout-64-bitfields.m | 40 + test/CodeGenObjC/ivar-layout-no-optimize.m | 18 + test/CodeGenObjC/messages.m | 4 +- test/CodeGenObjC/objc-assign-ivar.m | 53 + test/CodeGenObjC/objc-gc-aggr-assign.m | 46 + test/CodeGenObjC/objc-read-weak-byref.m | 26 + test/CodeGenObjC/objc2-assign-global.m | 83 +- test/CodeGenObjC/objc2-ivar-assign.m | 41 + test/CodeGenObjC/objc2-new-gc-api-strongcast.m | 26 + test/CodeGenObjC/objc2-weak-assign.m | 4 + test/CodeGenObjC/objc2-weak-ivar-debug.m | 15 + test/CodeGenObjC/objc2-write-barrier-2.m | 80 + test/CodeGenObjC/objc2-write-barrier-3.m | 47 + test/CodeGenObjC/objc2-write-barrier-4.m | 28 + test/CodeGenObjC/objc2-write-barrier-5.m | 27 + test/CodeGenObjC/objc2-write-barrier.m | 114 + test/CodeGenObjC/object-incr-decr-1.m | 19 + test/CodeGenObjC/overloadable.m | 4 +- test/CodeGenObjC/predefined-expr.m | 90 + test/CodeGenObjC/property-agrr-getter.m | 23 +- test/CodeGenObjC/property-setter-attr.m | 2 +- test/CodeGenObjC/protocol-in-extended-class.m | 29 + test/CodeGenObjC/protocols-lazy.m | 4 +- test/CodeGenObjC/protocols.m | 50 + test/CodeGenObjC/variadic-sends.m | 41 + test/Coverage/targets.c | 27 +- test/Driver/arm-darwin-builtin.c | 14 + test/Driver/ast.c | 26 + test/Driver/bindings.c | 6 +- test/Driver/clang-translation.c | 8 +- test/Driver/darwin-arm.c | 4 + test/Driver/darwin-as.c | 10 + test/Driver/darwin-cc.c | 1 - test/Driver/darwin-ld.c | 7 +- test/Driver/default-toolchain.c | 6 +- test/Driver/dragonfly.c | 10 +- test/Driver/freebsd.c | 10 +- test/Driver/openbsd.c | 8 +- test/Driver/pth.c | 8 +- test/Driver/qa_override.c | 3 +- test/Driver/redzone.c | 6 +- test/Frontend/ast-codegen.c | 12 + test/Frontend/ast-main.c | 8 + test/Frontend/dependency-gen.c | 2 +- test/Frontend/stdin.c | 2 +- test/Index/c-index-api-test.m | 224 + test/Index/comments.c | 30 +- test/Index/cxx-operator-overload.cpp | 28 + test/Index/find-decls.c | 25 + test/Index/find-defs.c | 18 + test/Index/find-refs.c | 47 + test/Index/foo.h | 8 + test/Index/multiple-redecls.c | 12 + test/Index/objc-decls.m | 16 + test/Index/objc-message.m | 38 + test/Index/objc.h | 11 + test/Index/resolve-loc.c | 39 +- test/Index/t1.c | 31 + test/Index/t1.m | 23 + test/Index/t2.c | 14 + test/Index/t2.m | 16 + test/Lexer/11-27-2007-FloatLiterals.c | 8 +- test/Lexer/comment-escape.c | 2 +- test/Lexer/dollar-idents.c | 2 +- test/Makefile | 32 +- test/Misc/diag-mapping2.c | 5 +- test/PCH/cxx-method.cpp | 7 + test/PCH/libroot/usr/include/reloc.h | 15 + test/PCH/libroot/usr/include/reloc2.h | 15 + test/PCH/method_pool.h | 3 +- test/PCH/objc_exprs.m | 5 +- test/PCH/pr4489.c | 22 +- test/PCH/reloc.c | 14 + test/Parser/CompoundStmtScope.c | 2 +- test/Parser/MicrosoftExtensions.c | 18 +- test/Parser/argument_redef.c | 2 +- test/Parser/bad-control.c | 4 +- test/Parser/cxx-ambig-paren-expr.cpp | 6 +- test/Parser/cxx-friend.cpp | 21 +- test/Parser/cxx-member-initializers.cpp | 10 + test/Parser/cxx-template-decl.cpp | 21 +- test/Parser/cxx-using-declaration.cpp | 92 +- test/Parser/declarators.c | 10 +- test/Parser/implicit-casts.c | 1 + test/Parser/objc-messaging-neg-1.m | 9 +- test/Parser/pointer_promotion.c | 3 +- test/Parser/pragma-weak.c | 2 +- test/Parser/recovery.c | 12 +- test/Parser/statements.c | 14 +- test/Parser/top-level-semi-cxx0x.cpp | 15 + test/Preprocessor/assembler-with-cpp.c | 2 +- test/Preprocessor/macro-multiline.c | 2 +- test/Preprocessor/macro_fn_comma_swallow.c | 2 +- test/Preprocessor/macro_paste_mscomment.c | 4 +- test/Preprocessor/non_fragile_feature.m | 8 + test/Preprocessor/non_fragile_feature1.m | 8 + test/Preprocessor/pushable-diagnostics.c | 17 + test/Rewriter/id-test-3.m | 2 +- test/Rewriter/method-encoding-1.m | 4 +- test/Rewriter/rewrite-foreach-4.m | 2 +- test/Rewriter/rewrite-foreach-5.m | 2 +- test/Sema/address_spaces.c | 16 +- test/Sema/align-arm-apcs.c | 4 + test/Sema/altivec-init.c | 16 + test/Sema/arg-scope-c99.c | 2 +- test/Sema/arg-scope.c | 2 +- test/Sema/array-constraint.c | 2 +- test/Sema/array-init.c | 23 +- test/Sema/attr-decl-after-definition.c | 19 + test/Sema/attr-deprecated.c | 2 +- test/Sema/attr-format_arg.c | 2 + test/Sema/attr-malloc.c | 25 + test/Sema/attr-noreturn.c | 10 +- test/Sema/attr-section.c | 10 + test/Sema/attr-weak.c | 4 +- test/Sema/bitfield-promote-int-16bit.c | 25 + test/Sema/bitfield-promote.c | 34 + test/Sema/bitfield.c | 2 +- test/Sema/block-args.c | 2 +- test/Sema/block-call.c | 52 +- test/Sema/block-literal.c | 82 +- test/Sema/block-misc.c | 39 +- test/Sema/block-printf-attribute-1.c | 17 +- test/Sema/block-return-1.c | 6 + test/Sema/block-return-2.c | 5 + test/Sema/block-return-3.c | 5 + test/Sema/block-return.c | 6 +- test/Sema/block-sentinel-attribute.c | 25 +- test/Sema/builtin-prefetch.c | 2 +- test/Sema/builtin-unary-fp.c | 12 + test/Sema/builtins.c | 32 +- test/Sema/c89-2.c | 6 +- test/Sema/c89.c | 4 +- test/Sema/compare.c | 23 +- test/Sema/complex-int.c | 5 +- test/Sema/conditional.c | 10 +- test/Sema/darwin-align-cast.c | 5 +- test/Sema/decl-type-merging.c | 10 +- test/Sema/enum.c | 2 +- test/Sema/exprs.c | 11 +- test/Sema/floating-point-compare.c | 4 +- test/Sema/format-attr-pr4470.c | 1 + test/Sema/format-attribute-printf0.c | 26 + test/Sema/freemain.c | 9 + test/Sema/function-pointer-sentinel-attribute.c | 23 +- test/Sema/function-sentinel-attr.c | 2 +- test/Sema/function.c | 2 + test/Sema/heinous-extensions-on.c | 13 +- test/Sema/implicit-builtin-redecl.c | 12 + test/Sema/implicit-int.c | 9 +- test/Sema/incomplete-call.c | 4 +- test/Sema/incomplete-decl.c | 5 +- test/Sema/pragma-pack-4.c | 19 + test/Sema/pragma-unused.c | 9 +- test/Sema/predefined-function.c | 17 +- test/Sema/promote-int-16bit.c | 6 + test/Sema/redefinition.c | 4 +- test/Sema/return-noreturn.c | 29 + test/Sema/return.c | 210 +- test/Sema/shift.c | 38 +- test/Sema/static-init.c | 4 +- test/Sema/struct-decl.c | 20 +- test/Sema/tentative-decls.c | 2 +- test/Sema/transparent-union-pointer.c | 8 +- test/Sema/type-spec-struct-union.c | 2 +- test/Sema/unused-expr.c | 54 +- test/Sema/va_arg_x86_64.c | 9 +- test/Sema/vector-cast.c | 2 +- test/Sema/warn-char-subscripts.c | 64 + test/Sema/warn-unused-variables.c | 19 + test/Sema/x86-intrinsics-headers.c | 24 + test/SemaCXX/PR5086-ambig-resolution-enum.cpp | 13 + test/SemaCXX/abstract.cpp | 57 +- test/SemaCXX/access-control-check.cpp | 16 + test/SemaCXX/addr-of-overloaded-function.cpp | 27 + test/SemaCXX/ambig-user-defined-conversions.cpp | 52 + test/SemaCXX/ambiguous-builtin-unary-operator.cpp | 18 + test/SemaCXX/arrow-operator.cpp | 22 + test/SemaCXX/attr-after-definition.cpp | 9 + test/SemaCXX/attr-deprecated.cpp | 66 + test/SemaCXX/attr-format.cpp | 8 + test/SemaCXX/auto-cxx0x.cpp | 2 +- test/SemaCXX/builtin-ptrtomember-ambig.cpp | 24 + test/SemaCXX/builtin-ptrtomember-overload-1.cpp | 46 + test/SemaCXX/builtin-ptrtomember-overload.cpp | 18 + test/SemaCXX/c99.cpp | 8 + test/SemaCXX/cast-conversion.cpp | 21 + test/SemaCXX/cast-explicit-ctor.cpp | 6 + test/SemaCXX/class-base-member-init.cpp | 6 +- test/SemaCXX/class-layout.cpp | 49 + test/SemaCXX/class-names.cpp | 4 +- test/SemaCXX/composite-pointer-type.cpp | 8 + test/SemaCXX/conditional-expr.cpp | 6 +- test/SemaCXX/constructor-initializer.cpp | 41 +- test/SemaCXX/constructor.cpp | 26 + test/SemaCXX/conversion-delete-expr.cpp | 109 + test/SemaCXX/conversion-function.cpp | 29 + test/SemaCXX/copy-assignment.cpp | 2 +- test/SemaCXX/copy-constructor-error.cpp | 13 + test/SemaCXX/cstyle-cast.cpp | 231 + test/SemaCXX/dcl_ambig_res.cpp | 9 +- test/SemaCXX/dcl_init_aggr.cpp | 6 +- test/SemaCXX/decl-expr-ambiguity.cpp | 4 +- test/SemaCXX/decl-init-ref.cpp | 26 + test/SemaCXX/decltype-crash.cpp | 7 + test/SemaCXX/decltype-this.cpp | 15 + test/SemaCXX/default-argument-temporaries.cpp | 11 + test/SemaCXX/default-assignment-operator.cpp | 28 +- test/SemaCXX/default-constructor-initializers.cpp | 18 +- test/SemaCXX/default2.cpp | 22 +- test/SemaCXX/deleted-function.cpp | 2 +- test/SemaCXX/destructor.cpp | 11 +- test/SemaCXX/direct-initializer.cpp | 14 + test/SemaCXX/empty-class-layout.cpp | 68 + test/SemaCXX/enum.cpp | 13 +- test/SemaCXX/exception-spec.cpp | 126 +- test/SemaCXX/friend-class-nodecl.cpp | 10 + test/SemaCXX/function-overloaded-redecl.cpp | 10 + test/SemaCXX/functional-cast.cpp | 294 +- test/SemaCXX/i-c-e-cxx.cpp | 10 + test/SemaCXX/illegal-member-initialization.cpp | 22 + test/SemaCXX/incomplete-call.cpp | 38 + test/SemaCXX/inherit.cpp | 2 +- test/SemaCXX/invalid-member-expr.cpp | 21 + test/SemaCXX/invalid-template-specifier.cpp | 12 + test/SemaCXX/libstdcxx_is_pod_hack.cpp | 7 + test/SemaCXX/linkage-spec.cpp | 8 + test/SemaCXX/member-expr-static.cpp | 18 +- test/SemaCXX/member-name-lookup.cpp | 10 + test/SemaCXX/member-operator-expr.cpp | 29 + test/SemaCXX/member-pointer.cpp | 10 +- test/SemaCXX/missing-members.cpp | 36 + test/SemaCXX/namespace.cpp | 5 +- test/SemaCXX/nested-name-spec.cpp | 23 +- test/SemaCXX/new-delete.cpp | 45 +- test/SemaCXX/overload-value-dep-arg.cpp | 13 + test/SemaCXX/overloaded-builtin-operators.cpp | 36 +- test/SemaCXX/overloaded-operator.cpp | 37 +- test/SemaCXX/primary-base.cpp | 11 + test/SemaCXX/pseudo-destructors.cpp | 40 + test/SemaCXX/qual-id-test.cpp | 140 + test/SemaCXX/ref-init-ambiguous.cpp | 28 + test/SemaCXX/references.cpp | 15 + test/SemaCXX/return.cpp | 18 + test/SemaCXX/static-array-member.cpp | 18 + test/SemaCXX/static-cast-complete-type.cpp | 13 + test/SemaCXX/static-cast.cpp | 22 +- test/SemaCXX/static-initializers.cpp | 10 +- test/SemaCXX/type-traits-incomplete.cpp | 7 + test/SemaCXX/type-traits.cpp | 149 +- test/SemaCXX/unknown-type-name.cpp | 29 + test/SemaCXX/unreachable-catch-clauses.cpp | 14 + test/SemaCXX/using-decl-1.cpp | 11 + test/SemaCXX/using-decl-templates.cpp | 36 + test/SemaCXX/value-dependent-exprs.cpp | 47 + test/SemaCXX/vararg-non-pod.cpp | 14 +- test/SemaCXX/vector-casts.cpp | 40 + test/SemaCXX/warn-assignment-condition.cpp | 65 + test/SemaCXX/warn-char-subscripts.cpp | 21 + test/SemaCXX/warn-for-var-in-else.cpp | 1 + test/SemaCXX/warn-reorder-ctor-initialization.cpp | 89 + test/SemaCXX/warn-unused-variables.cpp | 6 + test/SemaCXX/wchar_t.cpp | 4 + test/SemaObjC/access-property-getter.m | 1 + test/SemaObjC/attr-malloc.m | 16 + test/SemaObjC/block-explicit-return-type.m | 77 + test/SemaObjC/blocks.m | 11 + test/SemaObjC/call-super-2.m | 4 +- test/SemaObjC/category-1.m | 19 + test/SemaObjC/category-method-lookup-2.m | 1 + test/SemaObjC/class-bitfield.m | 6 +- test/SemaObjC/class-getter-using-dotsyntax.m | 39 + test/SemaObjC/class-impl-1.m | 2 +- .../SemaObjC/compatible-protocol-qualified-types.m | 1 + test/SemaObjC/comptypes-1.m | 4 +- test/SemaObjC/comptypes-3.m | 12 +- test/SemaObjC/comptypes-5.m | 4 +- test/SemaObjC/comptypes-7.m | 4 +- test/SemaObjC/comptypes-a.m | 1 + test/SemaObjC/conditional-expr-3.m | 6 +- test/SemaObjC/conditional-expr-4.m | 20 +- test/SemaObjC/conditional-expr-5.m | 27 + test/SemaObjC/conditional-expr.m | 83 +- test/SemaObjC/crash-label.m | 9 + test/SemaObjC/deref-interface.m | 12 + test/SemaObjC/format-arg-attribute.m | 3 +- test/SemaObjC/id-isa-ref.m | 37 + test/SemaObjC/id.m | 2 +- test/SemaObjC/interface-scope-2.m | 2 + test/SemaObjC/invalid-objc-decls-1.m | 8 + test/SemaObjC/message.m | 2 +- test/SemaObjC/method-arg-decay.m | 1 + test/SemaObjC/method-conflict.m | 4 +- test/SemaObjC/method-encoding-2.m | 4 +- test/SemaObjC/method-lookup-2.m | 5 +- test/SemaObjC/method-lookup.m | 1 + test/SemaObjC/method-typecheck-1.m | 11 +- test/SemaObjC/no-warn-unimpl-method.m | 2 +- test/SemaObjC/nonnull.m | 42 + test/SemaObjC/nsobject-attribute.m | 2 +- test/SemaObjC/objc2-merge-gc-attribue-decl.m | 5 +- test/SemaObjC/property-11.m | 1 + test/SemaObjC/property-9-impl-method.m | 3 +- test/SemaObjC/property-error-readonly-assign.m | 23 + test/SemaObjC/property-expression-error.m | 18 + test/SemaObjC/property-method-lookup-impl.m | 4 +- test/SemaObjC/property-missing.m | 2 +- test/SemaObjC/protocol-archane.m | 3 +- test/SemaObjC/protocol-attribute.m | 4 +- test/SemaObjC/protocol-implementation-inherited.m | 2 +- test/SemaObjC/protocol-lookup.m | 1 + .../protocol-qualified-class-unsupported.m | 2 +- test/SemaObjC/rdr-6211479-array-property.m | 3 +- test/SemaObjC/return.m | 6 + test/SemaObjC/selector-1.m | 13 + test/SemaObjC/sizeof-interface.m | 11 + test/SemaObjC/static-ivar-ref-1.m | 3 +- test/SemaObjC/super-cat-prot.m | 4 +- test/SemaObjC/super.m | 1 + test/SemaObjC/synchronized.m | 2 +- test/SemaObjC/undef-superclass-1.m | 7 + test/SemaObjC/unused.m | 33 +- test/SemaObjC/warn-assign-property-nscopying.m | 15 + test/SemaObjC/warn-superclass-method-mismatch.m | 50 + test/SemaObjC/weak-attr-ivar.m | 5 +- test/SemaObjCXX/overload.mm | 1 + test/SemaObjCXX/protocol-lookup.mm | 1 + test/SemaObjCXX/references.mm | 4 +- test/SemaTemplate/ackermann.cpp | 7 +- test/SemaTemplate/ambiguous-ovl-print.cpp | 9 + test/SemaTemplate/canonical-expr-type-0x.cpp | 16 + test/SemaTemplate/canonical-expr-type.cpp | 53 + test/SemaTemplate/class-template-spec.cpp | 34 +- test/SemaTemplate/constructor-template.cpp | 53 + test/SemaTemplate/copy-ctor-assign.cpp | 36 + test/SemaTemplate/current-instantiation.cpp | 73 + test/SemaTemplate/default-arguments.cpp | 20 + test/SemaTemplate/default-expr-arguments.cpp | 86 + test/SemaTemplate/dependent-base-member-init.cpp | 36 + test/SemaTemplate/dependent-type-identity.cpp | 2 +- test/SemaTemplate/destructor-template.cpp | 12 + test/SemaTemplate/example-dynarray.cpp | 63 +- test/SemaTemplate/explicit-instantiation.cpp | 75 + .../explicit-specialization-member.cpp | 11 + test/SemaTemplate/ext-vector-type.cpp | 2 +- test/SemaTemplate/extern-templates.cpp | 66 + test/SemaTemplate/friend-template.cpp | 64 + test/SemaTemplate/friend.cpp | 14 + test/SemaTemplate/fun-template-def.cpp | 7 +- .../function-template-specialization.cpp | 35 + test/SemaTemplate/implicit-instantiation-1.cpp | 2 +- test/SemaTemplate/injected-class-name.cpp | 10 +- test/SemaTemplate/instantiate-anonymous-union.cpp | 31 + test/SemaTemplate/instantiate-cast.cpp | 8 +- test/SemaTemplate/instantiate-deeply.cpp | 22 + test/SemaTemplate/instantiate-expr-2.cpp | 48 + test/SemaTemplate/instantiate-expr-5.cpp | 4 + test/SemaTemplate/instantiate-friend-class.cpp | 9 + test/SemaTemplate/instantiate-function-1.cpp | 2 +- test/SemaTemplate/instantiate-function-1.mm | 3 + test/SemaTemplate/instantiate-init.cpp | 28 + .../instantiate-member-initializers.cpp | 26 + test/SemaTemplate/instantiate-member-template.cpp | 105 + test/SemaTemplate/instantiate-method.cpp | 9 + test/SemaTemplate/instantiate-static-var.cpp | 22 + test/SemaTemplate/instantiate-typedef.cpp | 2 +- test/SemaTemplate/instantiate-using-decl.cpp | 17 + test/SemaTemplate/member-access-expr.cpp | 77 + test/SemaTemplate/member-function-template.cpp | 51 + test/SemaTemplate/member-initializers.cpp | 13 + test/SemaTemplate/member-template-access-expr.cpp | 30 + test/SemaTemplate/metafun-apply.cpp | 3 +- test/SemaTemplate/nested-linkage.cpp | 3 + test/SemaTemplate/nested-template.cpp | 89 +- test/SemaTemplate/partial-spec-instantiate.cpp | 20 + test/SemaTemplate/qualified-id.cpp | 9 + test/SemaTemplate/qualified-names-diag.cpp | 2 +- test/SemaTemplate/temp_class_order.cpp | 42 + test/SemaTemplate/temp_class_spec.cpp | 75 +- test/SemaTemplate/temp_class_spec_neg.cpp | 4 +- test/SemaTemplate/temp_func_order.cpp | 95 + test/SemaTemplate/typename-specifier-4.cpp | 70 + test/SemaTemplate/typename-specifier.cpp | 15 +- .../value-dependent-null-pointer-constant.cpp | 29 + test/TestRunner.sh | 137 +- test/lit.cfg | 152 + test/lit.site.cfg.in | 10 + tools/CIndex/CIndex.cpp | 745 +++ tools/CIndex/CIndex.exports | 29 + tools/CIndex/CMakeLists.txt | 27 + tools/CIndex/Makefile | 54 + tools/CMakeLists.txt | 9 + tools/Makefile | 2 +- tools/c-index-test/CMakeLists.txt | 25 + tools/c-index-test/Makefile | 24 + tools/c-index-test/c-index-test.c | 106 + tools/clang-cc/CMakeLists.txt | 3 + tools/clang-cc/clang-cc.cpp | 907 ++-- tools/driver/CMakeLists.txt | 2 + tools/driver/Makefile | 6 + tools/driver/driver.cpp | 126 +- tools/index-test/CMakeLists.txt | 2 + tools/index-test/Makefile | 5 +- tools/index-test/index-test.cpp | 271 +- tools/wpa/CMakeLists.txt | 20 + tools/wpa/Makefile | 16 + tools/wpa/clang-wpa.cpp | 62 + utils/ABITest/ABITestGen.py | 2 +- utils/C++Tests/LLVM-Syntax/lit.local.cfg | 22 + utils/C++Tests/lit.cfg | 18 + utils/C++Tests/stdc++-Syntax/lit.local.cfg | 17 + utils/CaptureCmd | 2 +- utils/CmpDriver | 92 +- utils/FindSpecRefs | 2 +- utils/SummarizeErrors | 2 +- utils/analyzer/CmpRuns | 230 + utils/ccc-analyzer | 139 +- utils/clang-completion-mode.el | 257 ++ utils/scan-build | 67 +- utils/valgrind/x86_64-pc-linux-gnu_gcc-4.3.3.supp | 23 + www/OpenProjects.html | 10 +- www/analyzer/annotations.html | 12 +- www/analyzer/content.css | 2 + www/analyzer/latest_checker.html.incl | 2 +- www/analyzer/menu.css | 4 +- www/analyzer/menu.html.incl | 7 + www/comparison.html | 3 +- www/content.css | 2 + www/cxx_status.html | 587 +-- www/diagnostics.html | 71 +- www/features.html | 1 + www/get_started.html | 107 +- www/hacking.html | 104 +- www/menu.html.incl | 20 +- 1226 files changed, 105980 insertions(+), 41087 deletions(-) create mode 100644 INPUTS/all-std-headers.cpp create mode 100644 INSTALL.txt create mode 100644 VER create mode 100644 docs/libIndex.html create mode 100644 include/clang-c/Index.h create mode 100644 include/clang/AST/CXXInheritance.h create mode 100644 include/clang/AST/CanonicalType.h create mode 100644 include/clang/AST/Redeclarable.h create mode 100644 include/clang/AST/TypeLoc.h create mode 100644 include/clang/AST/TypeLocNodes.def create mode 100644 include/clang/AST/TypeLocVisitor.h create mode 100644 include/clang/Analysis/CFG.h create mode 100644 include/clang/Analysis/CallGraph.h create mode 100644 include/clang/Analysis/PathSensitive/AnalysisContext.h create mode 100644 include/clang/Analysis/PathSensitive/AnalysisManager.h create mode 100644 include/clang/Analysis/PathSensitive/Checker.h create mode 100644 include/clang/Analysis/PathSensitive/CheckerVisitor.def create mode 100644 include/clang/Analysis/PathSensitive/CheckerVisitor.h create mode 100644 include/clang/Analysis/PathSensitive/GRSubEngine.h create mode 100644 include/clang/Analysis/Support/BumpVector.h create mode 100644 include/clang/Analysis/Support/Optional.h create mode 100644 include/clang/Analysis/Support/SaveAndRestore.h create mode 100644 include/clang/Basic/PartialDiagnostic.h create mode 100644 include/clang/Index/ASTLocation.h create mode 100644 include/clang/Index/Analyzer.h create mode 100644 include/clang/Index/DeclReferenceMap.h create mode 100644 include/clang/Index/Entity.h create mode 100644 include/clang/Index/GlobalSelector.h create mode 100644 include/clang/Index/Handlers.h create mode 100644 include/clang/Index/IndexProvider.h create mode 100644 include/clang/Index/Indexer.h create mode 100644 include/clang/Index/Program.h create mode 100644 include/clang/Index/STLExtras.h create mode 100644 include/clang/Index/SelectorMap.h create mode 100644 include/clang/Index/TranslationUnit.h create mode 100644 include/clang/Index/Utils.h create mode 100644 include/clang/Sema/CodeCompleteConsumer.h create mode 100644 lib/AST/CXXInheritance.cpp create mode 100644 lib/AST/RecordLayoutBuilder.cpp create mode 100644 lib/AST/RecordLayoutBuilder.h create mode 100644 lib/AST/StmtProfile.cpp create mode 100644 lib/AST/TypeLoc.cpp create mode 100644 lib/Analysis/AnalysisContext.cpp create mode 100644 lib/Analysis/AnalysisManager.cpp create mode 100644 lib/Analysis/BugReporterVisitors.cpp create mode 100644 lib/Analysis/CFG.cpp create mode 100644 lib/Analysis/CallGraph.cpp create mode 100644 lib/Analysis/CallInliner.cpp create mode 100644 lib/Analysis/CheckSecuritySyntaxOnly.cpp create mode 100644 lib/Analysis/SValuator.cpp create mode 100644 lib/Basic/Version.cpp create mode 100644 lib/CodeGen/CGCXXClass.cpp create mode 100644 lib/CodeGen/CGCXXExpr.cpp create mode 100644 lib/CodeGen/CGRecordLayoutBuilder.cpp create mode 100644 lib/CodeGen/CGRecordLayoutBuilder.h create mode 100644 lib/CodeGen/CGRtti.cpp create mode 100644 lib/CodeGen/CGVtable.cpp create mode 100644 lib/CodeGen/CGVtable.h create mode 100644 lib/Index/ASTLocation.cpp create mode 100644 lib/Index/ASTVisitor.h create mode 100644 lib/Index/Analyzer.cpp create mode 100644 lib/Index/CMakeLists.txt create mode 100644 lib/Index/DeclReferenceMap.cpp create mode 100644 lib/Index/Entity.cpp create mode 100644 lib/Index/EntityImpl.h create mode 100644 lib/Index/GlobalSelector.cpp create mode 100644 lib/Index/Handlers.cpp create mode 100644 lib/Index/IndexProvider.cpp create mode 100644 lib/Index/Indexer.cpp create mode 100644 lib/Index/Makefile create mode 100644 lib/Index/Program.cpp create mode 100644 lib/Index/ProgramImpl.h create mode 100644 lib/Index/ResolveLocation.cpp create mode 100644 lib/Index/SelectorMap.cpp create mode 100644 lib/Sema/CodeCompleteConsumer.cpp create mode 100644 lib/Sema/SemaCXXCast.cpp create mode 100644 lib/Sema/SemaCodeComplete.cpp create mode 100644 lib/Sema/SemaExceptionSpec.cpp create mode 100644 lib/Sema/SemaTemplate.h create mode 100644 lib/Sema/TreeTransform.h create mode 100644 test/Analysis/dead-stores.cpp create mode 100644 test/Analysis/misc-ps-region-store-i386.m create mode 100644 test/Analysis/misc-ps-region-store-x86_64.m create mode 100644 test/Analysis/no-outofbounds.c create mode 100644 test/Analysis/rdar-7168531.m create mode 100644 test/Analysis/security-syntax-checks.m create mode 100644 test/Analysis/unions-region.m create mode 100644 test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-template-id.cpp create mode 100644 test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp create mode 100644 test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp create mode 100644 test/CXX/basic/basic.lookup/basic.lookup.elab/templateid.cpp create mode 100644 test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p2.cpp create mode 100644 test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p3.cpp create mode 100644 test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p4.cpp create mode 100644 test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p5.cpp create mode 100644 test/CXX/basic/basic.start/basic.start.main/p2a.cpp create mode 100644 test/CXX/basic/basic.start/basic.start.main/p2b.cpp create mode 100644 test/CXX/basic/basic.start/basic.start.main/p2c.cpp create mode 100644 test/CXX/basic/basic.start/basic.start.main/p2d.cpp create mode 100644 test/CXX/basic/basic.start/basic.start.main/p2e.cpp create mode 100644 test/CXX/basic/basic.start/basic.start.main/p2f.cpp create mode 100644 test/CXX/basic/basic.start/basic.start.main/p2g.cpp create mode 100644 test/CXX/basic/basic.stc/basic.stc.dynamic/p2-nodef.cpp create mode 100644 test/CXX/basic/basic.stc/basic.stc.dynamic/p2.cpp create mode 100644 test/CXX/class.derived/class.virtual/p12.cpp create mode 100644 test/CXX/class/class.friend/p1-ambiguous.cpp create mode 100644 test/CXX/class/class.friend/p1.cpp create mode 100644 test/CXX/class/class.friend/p2.cpp create mode 100644 test/CXX/class/class.friend/p6.cpp create mode 100644 test/CXX/class/class.nest/p1.cpp create mode 100644 test/CXX/class/class.union/p1.cpp create mode 100644 test/CXX/dcl.dcl/basic.namespace/namespace.def/namespace.memdef/p3.cpp create mode 100644 test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3-cxx0x.cpp create mode 100644 test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p5-cxx0x.cpp create mode 100644 test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p6-cxx0x.cpp create mode 100644 test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8-cxx0x.cpp create mode 100644 test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp create mode 100644 test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp create mode 100644 test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp create mode 100644 test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p10.cpp create mode 100644 test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p2.cpp create mode 100644 test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp create mode 100644 test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp create mode 100644 test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p5.cpp create mode 100644 test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p6.cpp create mode 100644 test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p7.cpp create mode 100644 test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p8.cpp create mode 100644 test/CXX/dcl.decl/dcl.meaning/dcl.fct/p3.cpp create mode 100644 test/CXX/dcl.decl/dcl.meaning/dcl.mptr/p3.cpp create mode 100644 test/CXX/expr/p3.cpp create mode 100644 test/CXX/expr/p8.cpp create mode 100644 test/CXX/expr/p9.cpp create mode 100644 test/CXX/lex/lex.trigraph/p1.cpp create mode 100644 test/CXX/lex/lex.trigraph/p2.cpp create mode 100644 test/CXX/lex/lex.trigraph/p3.cpp create mode 100644 test/CXX/over/over.match/over.match.best/p1.cpp create mode 100644 test/CXX/over/over.over/p1.cpp create mode 100644 test/CXX/over/over.over/p2.cpp create mode 100644 test/CXX/over/over.over/p4.cpp create mode 100644 test/CXX/temp/temp.decls/temp.class.spec/p6.cpp create mode 100644 test/CXX/temp/temp.decls/temp.class.spec/temp.class.order/p2.cpp create mode 100644 test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1-neg.cpp create mode 100644 test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1.cpp create mode 100644 test/CXX/temp/temp.decls/temp.class/temp.mem.class/p1.cpp create mode 100644 test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1-retmem.cpp create mode 100644 test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1.cpp create mode 100644 test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1inst.cpp create mode 100644 test/CXX/temp/temp.decls/temp.class/temp.mem.func/pr5056.cpp create mode 100644 test/CXX/temp/temp.decls/temp.class/temp.static/p1-inst.cpp create mode 100644 test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp create mode 100644 test/CXX/temp/temp.decls/temp.fct/temp.func.order/p4.cpp create mode 100644 test/CXX/temp/temp.decls/temp.fct/temp.func.order/p5.cpp create mode 100644 test/CXX/temp/temp.decls/temp.fct/temp.over.link/p6.cpp create mode 100644 test/CXX/temp/temp.decls/temp.friend/p1.cpp create mode 100644 test/CXX/temp/temp.decls/temp.friend/p3.cpp create mode 100644 test/CXX/temp/temp.decls/temp.friend/p5.cpp create mode 100644 test/CXX/temp/temp.decls/temp.mem/p1.cpp create mode 100644 test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p2.cpp create mode 100644 test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p3.cpp create mode 100644 test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p4.cpp create mode 100644 test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.funcaddr/p1.cpp create mode 100644 test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.partial/p11.cpp create mode 100644 test/CXX/temp/temp.res/temp.dep/p3.cpp create mode 100644 test/CXX/temp/temp.spec/temp.expl.spec/p1.cpp create mode 100644 test/CXX/temp/temp.spec/temp.expl.spec/p10.cpp create mode 100644 test/CXX/temp/temp.spec/temp.expl.spec/p11.cpp create mode 100644 test/CXX/temp/temp.spec/temp.expl.spec/p13.cpp create mode 100644 test/CXX/temp/temp.spec/temp.expl.spec/p14.cpp create mode 100644 test/CXX/temp/temp.spec/temp.expl.spec/p15.cpp create mode 100644 test/CXX/temp/temp.spec/temp.expl.spec/p16.cpp create mode 100644 test/CXX/temp/temp.spec/temp.expl.spec/p17.cpp create mode 100644 test/CXX/temp/temp.spec/temp.expl.spec/p18.cpp create mode 100644 test/CXX/temp/temp.spec/temp.expl.spec/p19.cpp create mode 100644 test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp create mode 100644 test/CXX/temp/temp.spec/temp.expl.spec/p20.cpp create mode 100644 test/CXX/temp/temp.spec/temp.expl.spec/p21.cpp create mode 100644 test/CXX/temp/temp.spec/temp.expl.spec/p3.cpp create mode 100644 test/CXX/temp/temp.spec/temp.expl.spec/p4.cpp create mode 100644 test/CXX/temp/temp.spec/temp.expl.spec/p5.cpp create mode 100644 test/CXX/temp/temp.spec/temp.expl.spec/p6.cpp create mode 100644 test/CXX/temp/temp.spec/temp.expl.spec/p9.cpp create mode 100644 test/CodeCompletion/call.cpp create mode 100644 test/CodeCompletion/enum-switch-case-qualified.cpp create mode 100644 test/CodeCompletion/enum-switch-case.c create mode 100644 test/CodeCompletion/enum-switch-case.cpp create mode 100644 test/CodeCompletion/function-templates.cpp create mode 100644 test/CodeCompletion/functions.cpp create mode 100644 test/CodeCompletion/member-access.c create mode 100644 test/CodeCompletion/member-access.cpp create mode 100644 test/CodeCompletion/namespace-alias.cpp create mode 100644 test/CodeCompletion/namespace.cpp create mode 100644 test/CodeCompletion/nested-name-specifier.cpp create mode 100644 test/CodeCompletion/operator.cpp create mode 100644 test/CodeCompletion/ordinary-name.c create mode 100644 test/CodeCompletion/property.m create mode 100644 test/CodeCompletion/tag.c create mode 100644 test/CodeCompletion/tag.cpp create mode 100644 test/CodeCompletion/templates.cpp create mode 100644 test/CodeCompletion/truncation.c create mode 100644 test/CodeCompletion/truncation.c.h create mode 100644 test/CodeCompletion/using-namespace.cpp create mode 100644 test/CodeCompletion/using.cpp create mode 100644 test/CodeGen/2009-07-31-DbgDeclare.c create mode 100644 test/CodeGen/2009-08-14-vararray-crash.c create mode 100644 test/CodeGen/PR4611-bitfield-layout.c create mode 100644 test/CodeGen/PR5060-align.c create mode 100644 test/CodeGen/address-space-compound-literal.c create mode 100644 test/CodeGen/address-space-field1.c create mode 100644 test/CodeGen/address-space-field2.c create mode 100644 test/CodeGen/address-space-field3.c create mode 100644 test/CodeGen/address-space-field4.c create mode 100644 test/CodeGen/arm-arguments.c create mode 100644 test/CodeGen/arm_asm_clobber.c create mode 100644 test/CodeGen/asm-inout.c create mode 100644 test/CodeGen/blocks-aligned-byref-variable.c create mode 100644 test/CodeGen/builtin-attributes.c create mode 100644 test/CodeGen/inline2.c create mode 100644 test/CodeGen/packed-union.c create mode 100644 test/CodeGen/pragma-pack-1.c create mode 100644 test/CodeGen/pragma-pack-2.c create mode 100644 test/CodeGen/pragma-pack-3.c create mode 100644 test/CodeGen/pragma-weak.c create mode 100644 test/CodeGen/predefined-expr.c create mode 100644 test/CodeGen/union-init2.c create mode 100644 test/CodeGen/unreachable.c create mode 100644 test/CodeGenCXX/PR4827-cast.cpp create mode 100644 test/CodeGenCXX/PR4890-debug-info-dtor.cpp create mode 100644 test/CodeGenCXX/PR4983-constructor-conversion.cpp create mode 100644 test/CodeGenCXX/PR5050-constructor-conversion.cpp create mode 100644 test/CodeGenCXX/PR5093-static-member-function.cpp create mode 100644 test/CodeGenCXX/anonymous-namespaces.cpp create mode 100644 test/CodeGenCXX/anonymous-union-member-initializer.cpp create mode 100644 test/CodeGenCXX/array-pointer-decay.cpp create mode 100644 test/CodeGenCXX/attr.cpp create mode 100644 test/CodeGenCXX/cast-conversion.cpp create mode 100644 test/CodeGenCXX/class-layout.cpp create mode 100644 test/CodeGenCXX/conditional-expr-lvalue.cpp create mode 100644 test/CodeGenCXX/constructor-conversion.cpp create mode 100644 test/CodeGenCXX/constructor-default-arg.cpp create mode 100644 test/CodeGenCXX/constructor-for-array-members.cpp create mode 100644 test/CodeGenCXX/constructor-init-reference.cpp create mode 100644 test/CodeGenCXX/constructor-init.cpp create mode 100644 test/CodeGenCXX/constructor-template.cpp create mode 100644 test/CodeGenCXX/conversion-function.cpp create mode 100644 test/CodeGenCXX/convert-to-fptr.cpp create mode 100644 test/CodeGenCXX/copy-assign-synthesis-1.cpp create mode 100644 test/CodeGenCXX/copy-assign-synthesis.cpp create mode 100644 test/CodeGenCXX/copy-constructor-elim.cpp create mode 100644 test/CodeGenCXX/copy-constructor-synthesis.cpp create mode 100644 test/CodeGenCXX/decl-ref-init.cpp create mode 100644 test/CodeGenCXX/default-constructor-for-members.cpp create mode 100644 test/CodeGenCXX/default-destructor-synthesis.cpp create mode 100644 test/CodeGenCXX/delete.cpp create mode 100644 test/CodeGenCXX/derived-to-base.cpp create mode 100644 test/CodeGenCXX/destructor-calls.cpp create mode 100644 test/CodeGenCXX/destructors.cpp create mode 100644 test/CodeGenCXX/devirtualize-virtual-function-calls.cpp create mode 100644 test/CodeGenCXX/global-init.cpp create mode 100644 test/CodeGenCXX/mangle-extreme.cpp create mode 100644 test/CodeGenCXX/mangle-subst-std.cpp create mode 100644 test/CodeGenCXX/mangle-subst.cpp create mode 100644 test/CodeGenCXX/member-function-pointers.cpp create mode 100644 test/CodeGenCXX/member-pointers-zero-init.cpp create mode 100644 test/CodeGenCXX/namespace-aliases.cpp create mode 100644 test/CodeGenCXX/nested-base-member-access.cpp create mode 100644 test/CodeGenCXX/nullptr.cpp create mode 100644 test/CodeGenCXX/overload-binop-implicitconvert.cpp create mode 100644 test/CodeGenCXX/predefined-expr-sizeof.cpp create mode 100644 test/CodeGenCXX/predefined-expr.cpp create mode 100644 test/CodeGenCXX/reinterpret-cast.cpp create mode 100644 test/CodeGenCXX/static-data-member.cpp create mode 100644 test/CodeGenCXX/static-init.cpp create mode 100644 test/CodeGenCXX/temp-1.cpp create mode 100644 test/CodeGenCXX/template-anonymous-union-member-initializer.cpp create mode 100644 test/CodeGenCXX/trivial-constructor-init.cpp create mode 100644 test/CodeGenCXX/virt.cpp create mode 100644 test/CodeGenCXX/virtual-base-cast.cpp create mode 100644 test/CodeGenCXX/virtual-function-calls.cpp create mode 100644 test/CodeGenCXX/vtable-cast-crash.cpp create mode 100644 test/CodeGenCXX/x86_64-arguments.cpp create mode 100644 test/CodeGenObjC/PR4541.m create mode 100644 test/CodeGenObjC/PR4894-recursive-debug-crash.m create mode 100644 test/CodeGenObjC/debug-info-linkagename.m create mode 100644 test/CodeGenObjC/for-in.m create mode 100644 test/CodeGenObjC/ivar-layout-64-bitfields.m create mode 100644 test/CodeGenObjC/ivar-layout-no-optimize.m create mode 100644 test/CodeGenObjC/objc-assign-ivar.m create mode 100644 test/CodeGenObjC/objc-gc-aggr-assign.m create mode 100644 test/CodeGenObjC/objc-read-weak-byref.m create mode 100644 test/CodeGenObjC/objc2-ivar-assign.m create mode 100644 test/CodeGenObjC/objc2-new-gc-api-strongcast.m create mode 100644 test/CodeGenObjC/objc2-weak-ivar-debug.m create mode 100644 test/CodeGenObjC/objc2-write-barrier-2.m create mode 100644 test/CodeGenObjC/objc2-write-barrier-3.m create mode 100644 test/CodeGenObjC/objc2-write-barrier-4.m create mode 100644 test/CodeGenObjC/objc2-write-barrier-5.m create mode 100644 test/CodeGenObjC/objc2-write-barrier.m create mode 100644 test/CodeGenObjC/object-incr-decr-1.m create mode 100644 test/CodeGenObjC/predefined-expr.m create mode 100644 test/CodeGenObjC/protocol-in-extended-class.m create mode 100644 test/CodeGenObjC/protocols.m create mode 100644 test/CodeGenObjC/variadic-sends.m create mode 100644 test/Driver/arm-darwin-builtin.c create mode 100644 test/Driver/ast.c create mode 100644 test/Driver/darwin-arm.c create mode 100644 test/Driver/darwin-as.c create mode 100644 test/Frontend/ast-codegen.c create mode 100644 test/Frontend/ast-main.c create mode 100644 test/Index/c-index-api-test.m create mode 100644 test/Index/cxx-operator-overload.cpp create mode 100644 test/Index/find-decls.c create mode 100644 test/Index/find-defs.c create mode 100644 test/Index/find-refs.c create mode 100644 test/Index/foo.h create mode 100644 test/Index/multiple-redecls.c create mode 100644 test/Index/objc-decls.m create mode 100644 test/Index/objc-message.m create mode 100644 test/Index/objc.h create mode 100644 test/Index/t1.c create mode 100644 test/Index/t1.m create mode 100644 test/Index/t2.c create mode 100644 test/Index/t2.m create mode 100644 test/PCH/cxx-method.cpp create mode 100644 test/PCH/libroot/usr/include/reloc.h create mode 100644 test/PCH/libroot/usr/include/reloc2.h create mode 100644 test/PCH/reloc.c create mode 100644 test/Parser/cxx-member-initializers.cpp create mode 100644 test/Parser/top-level-semi-cxx0x.cpp create mode 100644 test/Preprocessor/non_fragile_feature.m create mode 100644 test/Preprocessor/non_fragile_feature1.m create mode 100644 test/Preprocessor/pushable-diagnostics.c create mode 100644 test/Sema/align-arm-apcs.c create mode 100644 test/Sema/altivec-init.c create mode 100644 test/Sema/attr-decl-after-definition.c create mode 100644 test/Sema/attr-malloc.c create mode 100644 test/Sema/attr-section.c create mode 100644 test/Sema/bitfield-promote-int-16bit.c create mode 100644 test/Sema/bitfield-promote.c create mode 100644 test/Sema/block-return-1.c create mode 100644 test/Sema/block-return-2.c create mode 100644 test/Sema/block-return-3.c create mode 100644 test/Sema/builtin-unary-fp.c create mode 100644 test/Sema/format-attribute-printf0.c create mode 100644 test/Sema/freemain.c create mode 100644 test/Sema/pragma-pack-4.c create mode 100644 test/Sema/promote-int-16bit.c create mode 100644 test/Sema/return-noreturn.c create mode 100644 test/Sema/warn-char-subscripts.c create mode 100644 test/Sema/warn-unused-variables.c create mode 100644 test/Sema/x86-intrinsics-headers.c create mode 100644 test/SemaCXX/PR5086-ambig-resolution-enum.cpp create mode 100644 test/SemaCXX/access-control-check.cpp create mode 100644 test/SemaCXX/ambig-user-defined-conversions.cpp create mode 100644 test/SemaCXX/ambiguous-builtin-unary-operator.cpp create mode 100644 test/SemaCXX/arrow-operator.cpp create mode 100644 test/SemaCXX/attr-after-definition.cpp create mode 100644 test/SemaCXX/attr-deprecated.cpp create mode 100644 test/SemaCXX/attr-format.cpp create mode 100644 test/SemaCXX/builtin-ptrtomember-ambig.cpp create mode 100644 test/SemaCXX/builtin-ptrtomember-overload-1.cpp create mode 100644 test/SemaCXX/builtin-ptrtomember-overload.cpp create mode 100644 test/SemaCXX/c99.cpp create mode 100644 test/SemaCXX/cast-conversion.cpp create mode 100644 test/SemaCXX/cast-explicit-ctor.cpp create mode 100644 test/SemaCXX/class-layout.cpp create mode 100644 test/SemaCXX/conversion-delete-expr.cpp create mode 100644 test/SemaCXX/copy-constructor-error.cpp create mode 100644 test/SemaCXX/cstyle-cast.cpp create mode 100644 test/SemaCXX/decl-init-ref.cpp create mode 100644 test/SemaCXX/decltype-crash.cpp create mode 100644 test/SemaCXX/decltype-this.cpp create mode 100644 test/SemaCXX/default-argument-temporaries.cpp create mode 100644 test/SemaCXX/empty-class-layout.cpp create mode 100644 test/SemaCXX/friend-class-nodecl.cpp create mode 100644 test/SemaCXX/function-overloaded-redecl.cpp create mode 100644 test/SemaCXX/illegal-member-initialization.cpp create mode 100644 test/SemaCXX/incomplete-call.cpp create mode 100644 test/SemaCXX/invalid-member-expr.cpp create mode 100644 test/SemaCXX/invalid-template-specifier.cpp create mode 100644 test/SemaCXX/libstdcxx_is_pod_hack.cpp create mode 100644 test/SemaCXX/member-operator-expr.cpp create mode 100644 test/SemaCXX/missing-members.cpp create mode 100644 test/SemaCXX/overload-value-dep-arg.cpp create mode 100644 test/SemaCXX/primary-base.cpp create mode 100644 test/SemaCXX/pseudo-destructors.cpp create mode 100644 test/SemaCXX/qual-id-test.cpp create mode 100644 test/SemaCXX/ref-init-ambiguous.cpp create mode 100644 test/SemaCXX/return.cpp create mode 100644 test/SemaCXX/static-array-member.cpp create mode 100644 test/SemaCXX/static-cast-complete-type.cpp create mode 100644 test/SemaCXX/type-traits-incomplete.cpp create mode 100644 test/SemaCXX/unknown-type-name.cpp create mode 100644 test/SemaCXX/unreachable-catch-clauses.cpp create mode 100644 test/SemaCXX/using-decl-templates.cpp create mode 100644 test/SemaCXX/value-dependent-exprs.cpp create mode 100644 test/SemaCXX/vector-casts.cpp create mode 100644 test/SemaCXX/warn-assignment-condition.cpp create mode 100644 test/SemaCXX/warn-char-subscripts.cpp create mode 100644 test/SemaCXX/warn-reorder-ctor-initialization.cpp create mode 100644 test/SemaCXX/warn-unused-variables.cpp create mode 100644 test/SemaObjC/attr-malloc.m create mode 100644 test/SemaObjC/block-explicit-return-type.m create mode 100644 test/SemaObjC/class-getter-using-dotsyntax.m create mode 100644 test/SemaObjC/conditional-expr-5.m create mode 100644 test/SemaObjC/crash-label.m create mode 100644 test/SemaObjC/deref-interface.m create mode 100644 test/SemaObjC/id-isa-ref.m create mode 100644 test/SemaObjC/nonnull.m create mode 100644 test/SemaObjC/property-expression-error.m create mode 100644 test/SemaObjC/return.m create mode 100644 test/SemaObjC/warn-assign-property-nscopying.m create mode 100644 test/SemaObjC/warn-superclass-method-mismatch.m create mode 100644 test/SemaTemplate/ambiguous-ovl-print.cpp create mode 100644 test/SemaTemplate/canonical-expr-type-0x.cpp create mode 100644 test/SemaTemplate/canonical-expr-type.cpp create mode 100644 test/SemaTemplate/constructor-template.cpp create mode 100644 test/SemaTemplate/copy-ctor-assign.cpp create mode 100644 test/SemaTemplate/default-expr-arguments.cpp create mode 100644 test/SemaTemplate/dependent-base-member-init.cpp create mode 100644 test/SemaTemplate/destructor-template.cpp create mode 100644 test/SemaTemplate/explicit-instantiation.cpp create mode 100644 test/SemaTemplate/explicit-specialization-member.cpp create mode 100644 test/SemaTemplate/extern-templates.cpp create mode 100644 test/SemaTemplate/friend-template.cpp create mode 100644 test/SemaTemplate/friend.cpp create mode 100644 test/SemaTemplate/function-template-specialization.cpp create mode 100644 test/SemaTemplate/instantiate-anonymous-union.cpp create mode 100644 test/SemaTemplate/instantiate-deeply.cpp create mode 100644 test/SemaTemplate/instantiate-expr-5.cpp create mode 100644 test/SemaTemplate/instantiate-friend-class.cpp create mode 100644 test/SemaTemplate/instantiate-init.cpp create mode 100644 test/SemaTemplate/instantiate-member-initializers.cpp create mode 100644 test/SemaTemplate/instantiate-member-template.cpp create mode 100644 test/SemaTemplate/instantiate-using-decl.cpp create mode 100644 test/SemaTemplate/member-access-expr.cpp create mode 100644 test/SemaTemplate/member-function-template.cpp create mode 100644 test/SemaTemplate/member-initializers.cpp create mode 100644 test/SemaTemplate/member-template-access-expr.cpp create mode 100644 test/SemaTemplate/nested-linkage.cpp create mode 100644 test/SemaTemplate/partial-spec-instantiate.cpp create mode 100644 test/SemaTemplate/qualified-id.cpp create mode 100644 test/SemaTemplate/temp_class_order.cpp create mode 100644 test/SemaTemplate/temp_func_order.cpp create mode 100644 test/SemaTemplate/typename-specifier-4.cpp create mode 100644 test/SemaTemplate/value-dependent-null-pointer-constant.cpp create mode 100644 test/lit.cfg create mode 100644 test/lit.site.cfg.in create mode 100644 tools/CIndex/CIndex.cpp create mode 100644 tools/CIndex/CIndex.exports create mode 100644 tools/CIndex/CMakeLists.txt create mode 100644 tools/CIndex/Makefile create mode 100644 tools/c-index-test/CMakeLists.txt create mode 100644 tools/c-index-test/Makefile create mode 100644 tools/c-index-test/c-index-test.c create mode 100644 tools/wpa/CMakeLists.txt create mode 100644 tools/wpa/Makefile create mode 100644 tools/wpa/clang-wpa.cpp create mode 100644 utils/C++Tests/LLVM-Syntax/lit.local.cfg create mode 100644 utils/C++Tests/lit.cfg create mode 100644 utils/C++Tests/stdc++-Syntax/lit.local.cfg create mode 100755 utils/analyzer/CmpRuns create mode 100644 utils/clang-completion-mode.el create mode 100644 utils/valgrind/x86_64-pc-linux-gnu_gcc-4.3.3.supp diff --git a/CMakeLists.txt b/CMakeLists.txt index bb128d68f2bdb..0cd52d0d946b5 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 0000000000000..bddf4ec163c40 --- /dev/null +++ b/INPUTS/all-std-headers.cpp @@ -0,0 +1,51 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/INSTALL.txt b/INSTALL.txt new file mode 100644 index 0000000000000..e8e320962bb4f --- /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 21cb5c7ac589d..72faf418f2879 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 00e38d26de469..22fe214705cd9 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 3b5ad16e3e10b..c658fe96bdfb3 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 611dc9d2c01c1..924ecc416c3a3 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 0000000000000..9459d4ba2a0d3 --- /dev/null +++ b/VER @@ -0,0 +1 @@ +1.1 diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj index 26be7bb0b7199..24e1ac360f72b 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 = ""; tabWidth = 2; }; 1A2193CD0F45EEB700C0713D /* Mangle.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Mangle.h; path = lib/CodeGen/Mangle.h; sourceTree = ""; tabWidth = 2; }; 1A2A54A40FD1DD1C00F4CE45 /* AnalysisConsumer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AnalysisConsumer.cpp; path = lib/Frontend/AnalysisConsumer.cpp; sourceTree = ""; }; - 1A2A54A50FD1DD1C00F4CE45 /* ASTConsumers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ASTConsumers.cpp; path = lib/Frontend/ASTConsumers.cpp; sourceTree = ""; }; + 1A2A54A50FD1DD1C00F4CE45 /* ASTConsumers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ASTConsumers.cpp; path = lib/Frontend/ASTConsumers.cpp; sourceTree = ""; tabWidth = 2; }; 1A2A54A60FD1DD1C00F4CE45 /* Backend.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Backend.cpp; path = lib/Frontend/Backend.cpp; sourceTree = ""; }; 1A2A54A70FD1DD1C00F4CE45 /* CacheTokens.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CacheTokens.cpp; path = lib/Frontend/CacheTokens.cpp; sourceTree = ""; }; 1A2A54A80FD1DD1C00F4CE45 /* DependencyFile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DependencyFile.cpp; path = lib/Frontend/DependencyFile.cpp; sourceTree = ""; }; @@ -336,19 +356,25 @@ 1A2A54AE0FD1DD1C00F4CE45 /* PrintPreprocessedOutput.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PrintPreprocessedOutput.cpp; path = lib/Frontend/PrintPreprocessedOutput.cpp; sourceTree = ""; }; 1A2A54AF0FD1DD1C00F4CE45 /* RewriteBlocks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RewriteBlocks.cpp; path = lib/Frontend/RewriteBlocks.cpp; sourceTree = ""; }; 1A2A54B00FD1DD1C00F4CE45 /* RewriteMacros.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RewriteMacros.cpp; path = lib/Frontend/RewriteMacros.cpp; sourceTree = ""; }; - 1A2A54B10FD1DD1C00F4CE45 /* RewriteObjC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RewriteObjC.cpp; path = lib/Frontend/RewriteObjC.cpp; sourceTree = ""; }; + 1A2A54B10FD1DD1C00F4CE45 /* RewriteObjC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = RewriteObjC.cpp; path = lib/Frontend/RewriteObjC.cpp; sourceTree = ""; tabWidth = 2; }; 1A2A54B20FD1DD1C00F4CE45 /* RewriteTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RewriteTest.cpp; path = lib/Frontend/RewriteTest.cpp; sourceTree = ""; }; 1A2A54B30FD1DD1C00F4CE45 /* StmtXML.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StmtXML.cpp; path = lib/Frontend/StmtXML.cpp; sourceTree = ""; }; 1A2A54B40FD1DD1C00F4CE45 /* Warnings.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Warnings.cpp; path = lib/Frontend/Warnings.cpp; sourceTree = ""; }; 1A30A9E80B93A4C800201A91 /* ExprCXX.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ExprCXX.h; path = clang/AST/ExprCXX.h; sourceTree = ""; tabWidth = 2; }; 1A32C17E0E1C87AD00A6B483 /* ExprConstant.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ExprConstant.cpp; path = lib/AST/ExprConstant.cpp; sourceTree = ""; tabWidth = 2; }; 1A376A2C0D4AED9B002A1C52 /* CGExprConstant.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGExprConstant.cpp; path = lib/CodeGen/CGExprConstant.cpp; sourceTree = ""; tabWidth = 2; }; - 1A410F840FBCE51100351440 /* SemaTemplateInstantiateExpr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaTemplateInstantiateExpr.cpp; path = lib/Sema/SemaTemplateInstantiateExpr.cpp; sourceTree = ""; tabWidth = 2; }; 1A471AB40F437BC500753CE8 /* CGBlocks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGBlocks.cpp; path = lib/CodeGen/CGBlocks.cpp; sourceTree = ""; tabWidth = 2; }; - 1A5119C30FBDF71000A1FF22 /* SemaTemplateInstantiateStmt.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaTemplateInstantiateStmt.cpp; path = lib/Sema/SemaTemplateInstantiateStmt.cpp; sourceTree = ""; tabWidth = 2; }; + 1A4C41BE105B4C0B0047B5E7 /* CGCXXClass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGCXXClass.cpp; path = lib/CodeGen/CGCXXClass.cpp; sourceTree = ""; tabWidth = 2; }; + 1A535ED8107BC45E000C3AE7 /* CXXInheritance.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CXXInheritance.cpp; path = lib/AST/CXXInheritance.cpp; sourceTree = ""; }; + 1A535EDB107BC47B000C3AE7 /* CanonicalType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CanonicalType.h; path = clang/AST/CanonicalType.h; sourceTree = ""; }; 1A5D5E570E5E81010023C059 /* CGCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGCXX.cpp; path = lib/CodeGen/CGCXX.cpp; sourceTree = ""; tabWidth = 2; }; 1A649E1D0F9599D9005B965E /* CGBlocks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CGBlocks.h; path = lib/CodeGen/CGBlocks.h; sourceTree = ""; }; - 1A649E1E0F9599DA005B965E /* CGCXX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CGCXX.h; path = lib/CodeGen/CGCXX.h; sourceTree = ""; }; + 1A649E1E0F9599DA005B965E /* CGCXX.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CGCXX.h; path = lib/CodeGen/CGCXX.h; sourceTree = ""; tabWidth = 2; }; + 1A6B6CD110693FC900BB4A8F /* CodeCompleteConsumer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CodeCompleteConsumer.cpp; path = lib/Sema/CodeCompleteConsumer.cpp; sourceTree = ""; tabWidth = 2; }; + 1A6B6CD210693FC900BB4A8F /* SemaCodeComplete.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaCodeComplete.cpp; path = lib/Sema/SemaCodeComplete.cpp; sourceTree = ""; tabWidth = 2; }; + 1A6B6CD310693FC900BB4A8F /* SemaTemplate.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = SemaTemplate.h; path = lib/Sema/SemaTemplate.h; sourceTree = ""; tabWidth = 2; }; + 1A6B6E991069833600BB4A8F /* CGCXXExpr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGCXXExpr.cpp; path = lib/CodeGen/CGCXXExpr.cpp; sourceTree = ""; tabWidth = 2; }; + 1A6C01F6108128710072DEE4 /* CGRtti.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGRtti.cpp; path = lib/CodeGen/CGRtti.cpp; sourceTree = ""; tabWidth = 2; }; 1A6FE7080FD6F85800E00CA9 /* CGCXXTemp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGCXXTemp.cpp; path = lib/CodeGen/CGCXXTemp.cpp; sourceTree = ""; tabWidth = 2; }; 1A7019E90F79BC1100FEC4D1 /* DiagnosticAnalysisKinds.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DiagnosticAnalysisKinds.td; sourceTree = ""; }; 1A7019EA0F79BC1100FEC4D1 /* DiagnosticASTKinds.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DiagnosticASTKinds.td; sourceTree = ""; }; @@ -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 = ""; tabWidth = 2; }; 1A72BEAC0D641E9400B085E9 /* Attr.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Attr.h; path = clang/AST/Attr.h; sourceTree = ""; tabWidth = 2; }; 1A7342470C7B57D500122F56 /* CGObjC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGObjC.cpp; path = lib/CodeGen/CGObjC.cpp; sourceTree = ""; tabWidth = 2; }; + 1A81AA18108144F40094E50B /* CGVtable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGVtable.cpp; path = lib/CodeGen/CGVtable.cpp; sourceTree = ""; tabWidth = 2; }; + 1A81AA5D108278A20094E50B /* CGVtable.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CGVtable.h; path = lib/CodeGen/CGVtable.h; sourceTree = ""; tabWidth = 2; }; 1A869A6E0BA2164C008DA07A /* LiteralSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LiteralSupport.h; sourceTree = ""; }; 1A869AA70BA21ABA008DA07A /* LiteralSupport.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = LiteralSupport.cpp; sourceTree = ""; }; + 1AA1D91610125DE30078DEBC /* RecordLayoutBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = RecordLayoutBuilder.cpp; path = lib/AST/RecordLayoutBuilder.cpp; sourceTree = ""; tabWidth = 2; }; + 1AA1D91710125DE30078DEBC /* RecordLayoutBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = RecordLayoutBuilder.h; path = lib/AST/RecordLayoutBuilder.h; sourceTree = ""; tabWidth = 2; }; + 1AB290021045858B00FE33D8 /* PartialDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = PartialDiagnostic.h; sourceTree = ""; tabWidth = 2; }; 1ABC36930C7A4BDC006DB0AB /* CGBuiltin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGBuiltin.cpp; path = lib/CodeGen/CGBuiltin.cpp; sourceTree = ""; tabWidth = 2; }; 1ADF47AE0F782C3200E48A8A /* SemaTemplateInstantiateDecl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaTemplateInstantiateDecl.cpp; path = lib/Sema/SemaTemplateInstantiateDecl.cpp; sourceTree = ""; tabWidth = 2; }; + 1AE4EE3B103B89CA00888A23 /* TreeTransform.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = TreeTransform.h; path = lib/Sema/TreeTransform.h; sourceTree = ""; tabWidth = 2; }; + 1AE4EE3D103B89ED00888A23 /* StmtProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = StmtProfile.cpp; path = lib/AST/StmtProfile.cpp; sourceTree = ""; tabWidth = 2; }; + 1AE4EE3F103B8A0A00888A23 /* TargetABIInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = TargetABIInfo.cpp; path = lib/CodeGen/TargetABIInfo.cpp; sourceTree = ""; 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 = ""; tabWidth = 2; }; + 1AFF8AE11012BFC900D248DA /* CGRecordLayoutBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGRecordLayoutBuilder.cpp; path = lib/CodeGen/CGRecordLayoutBuilder.cpp; sourceTree = ""; tabWidth = 2; }; + 1AFF8AE21012BFC900D248DA /* CGRecordLayoutBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CGRecordLayoutBuilder.h; path = lib/CodeGen/CGRecordLayoutBuilder.h; sourceTree = ""; tabWidth = 2; }; 3507E4C10E27FE2D00FB7B57 /* CheckObjCInstMethSignature.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CheckObjCInstMethSignature.cpp; path = lib/Analysis/CheckObjCInstMethSignature.cpp; sourceTree = ""; }; 352246E10F5C6BE000D0D279 /* HTMLDiagnostics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = HTMLDiagnostics.cpp; path = lib/Frontend/HTMLDiagnostics.cpp; sourceTree = ""; }; 352246E20F5C6BE000D0D279 /* InitHeaderSearch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = InitHeaderSearch.cpp; path = lib/Frontend/InitHeaderSearch.cpp; sourceTree = ""; }; @@ -406,7 +442,6 @@ 35544B870F5C7FD700D92AA9 /* SimpleConstraintManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SimpleConstraintManager.h; path = lib/Analysis/SimpleConstraintManager.h; sourceTree = ""; }; 35544B8B0F5C803200D92AA9 /* SemaTemplateInstantiate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaTemplateInstantiate.cpp; path = lib/Sema/SemaTemplateInstantiate.cpp; sourceTree = ""; tabWidth = 2; }; 3557D1A80EB136B100C59739 /* InheritViz.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = InheritViz.cpp; path = lib/AST/InheritViz.cpp; sourceTree = ""; tabWidth = 2; }; - 3557D1EF0EB13BB700C59739 /* SemaInherit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaInherit.cpp; path = lib/Sema/SemaInherit.cpp; sourceTree = ""; tabWidth = 2; }; 35585DBD0EAFBC4500D0A97A /* CXXFieldCollector.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CXXFieldCollector.h; path = lib/Sema/CXXFieldCollector.h; sourceTree = ""; tabWidth = 2; }; 35585DBE0EAFBC4500D0A97A /* SemaOverload.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaOverload.cpp; path = lib/Sema/SemaOverload.cpp; sourceTree = ""; tabWidth = 2; }; 35585DBF0EAFBC4500D0A97A /* SemaOverload.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = SemaOverload.h; path = lib/Sema/SemaOverload.h; sourceTree = ""; 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 = ""; }; 35D55B290D81D8E50092E734 /* BasicValueFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BasicValueFactory.h; path = clang/Analysis/PathSensitive/BasicValueFactory.h; sourceTree = ""; }; 35E194670ECB82FB00F21733 /* SemaCXXScopeSpec.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaCXXScopeSpec.cpp; path = lib/Sema/SemaCXXScopeSpec.cpp; sourceTree = ""; tabWidth = 2; }; - 35E194680ECB82FB00F21733 /* SemaNamedCast.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaNamedCast.cpp; path = lib/Sema/SemaNamedCast.cpp; sourceTree = ""; tabWidth = 2; }; + 35E194680ECB82FB00F21733 /* SemaCXXCast.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaCXXCast.cpp; path = lib/Sema/SemaCXXCast.cpp; sourceTree = ""; tabWidth = 2; }; 35E1946C0ECB83C100F21733 /* PTHLexer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PTHLexer.cpp; sourceTree = ""; }; 35EE48AD0E0C4CB200715C54 /* DeclCXX.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclCXX.h; path = clang/AST/DeclCXX.h; sourceTree = ""; tabWidth = 2; }; 35EE48AE0E0C4CB200715C54 /* ParentMap.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ParentMap.h; path = clang/AST/ParentMap.h; sourceTree = ""; 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 = ""; }; 35FE6BCE0DF6EE1F00739712 /* DeclBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = DeclBase.cpp; path = lib/AST/DeclBase.cpp; sourceTree = ""; tabWidth = 2; }; 72D16C1E0D9975C400E6DA4A /* HTMLRewrite.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = HTMLRewrite.cpp; path = lib/Rewrite/HTMLRewrite.cpp; sourceTree = ""; }; + 7F270AFE107A90010031B377 /* CodeCompleteConsumer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CodeCompleteConsumer.h; path = clang/Sema/CodeCompleteConsumer.h; sourceTree = ""; }; 84AF36A00CB17A3B00C820A5 /* DeclObjC.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclObjC.h; path = clang/AST/DeclObjC.h; sourceTree = ""; tabWidth = 2; }; 84D9A8870C1A57E100AC7ABC /* AttributeList.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = AttributeList.cpp; path = lib/Parse/AttributeList.cpp; sourceTree = ""; tabWidth = 2; }; 84D9A88B0C1A581300AC7ABC /* AttributeList.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = AttributeList.h; path = clang/Parse/AttributeList.h; sourceTree = ""; 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 = ""; }; + 9012911C1048068D0083456D /* ASTUnit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ASTUnit.cpp; path = lib/Frontend/ASTUnit.cpp; sourceTree = ""; }; + 9012911F104812F90083456D /* CIndex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CIndex.cpp; path = tools/CIndex/CIndex.cpp; sourceTree = ""; }; + 90129120104812F90083456D /* CIndex.exports */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = CIndex.exports; path = tools/CIndex/CIndex.exports; sourceTree = ""; }; 9063F2210F9E8BDF002F7251 /* ExternalSemaSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ExternalSemaSource.h; path = clang/Sema/ExternalSemaSource.h; sourceTree = ""; }; 9063F2220F9E8BDF002F7251 /* SemaConsumer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SemaConsumer.h; path = clang/Sema/SemaConsumer.h; sourceTree = ""; }; 9063F2280F9E911F002F7251 /* OnDiskHashTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OnDiskHashTable.h; sourceTree = ""; }; @@ -482,9 +522,50 @@ 9063F22A0F9E911F002F7251 /* TemplateKinds.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TemplateKinds.h; sourceTree = ""; }; 906BF4AE0F83BA16001071FA /* ConvertUTF.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConvertUTF.h; sourceTree = ""; }; 906BF4AF0F83BA2E001071FA /* ConvertUTF.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ConvertUTF.c; sourceTree = ""; }; + 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 = ""; }; 90FB99DE0F98FB1D008F9415 /* DeclContextInternals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DeclContextInternals.h; path = clang/AST/DeclContextInternals.h; sourceTree = ""; }; 90FB99DF0F98FB1D008F9415 /* DeclVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DeclVisitor.h; path = clang/AST/DeclVisitor.h; sourceTree = ""; }; 90FB99E00F98FB1D008F9415 /* ExternalASTSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ExternalASTSource.h; path = clang/AST/ExternalASTSource.h; sourceTree = ""; }; + 90FD6D5F103C3D21005F5B73 /* Analyzer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Analyzer.h; path = clang/Index/Analyzer.h; sourceTree = ""; }; + 90FD6D60103C3D21005F5B73 /* ASTLocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTLocation.h; path = clang/Index/ASTLocation.h; sourceTree = ""; }; + 90FD6D61103C3D21005F5B73 /* DeclReferenceMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DeclReferenceMap.h; path = clang/Index/DeclReferenceMap.h; sourceTree = ""; }; + 90FD6D62103C3D21005F5B73 /* Entity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Entity.h; path = clang/Index/Entity.h; sourceTree = ""; }; + 90FD6D63103C3D21005F5B73 /* GlobalSelector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GlobalSelector.h; path = clang/Index/GlobalSelector.h; sourceTree = ""; }; + 90FD6D64103C3D21005F5B73 /* Handlers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Handlers.h; path = clang/Index/Handlers.h; sourceTree = ""; }; + 90FD6D65103C3D21005F5B73 /* Indexer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Indexer.h; path = clang/Index/Indexer.h; sourceTree = ""; }; + 90FD6D66103C3D21005F5B73 /* IndexProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IndexProvider.h; path = clang/Index/IndexProvider.h; sourceTree = ""; }; + 90FD6D67103C3D21005F5B73 /* Program.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Program.h; path = clang/Index/Program.h; sourceTree = ""; }; + 90FD6D68103C3D21005F5B73 /* SelectorMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SelectorMap.h; path = clang/Index/SelectorMap.h; sourceTree = ""; }; + 90FD6D69103C3D21005F5B73 /* STLExtras.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = STLExtras.h; path = clang/Index/STLExtras.h; sourceTree = ""; }; + 90FD6D6A103C3D21005F5B73 /* TranslationUnit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TranslationUnit.h; path = clang/Index/TranslationUnit.h; sourceTree = ""; }; + 90FD6D6B103C3D21005F5B73 /* Utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Utils.h; path = clang/Index/Utils.h; sourceTree = ""; }; + 90FD6D6D103C3D49005F5B73 /* Analyzer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Analyzer.cpp; path = lib/Index/Analyzer.cpp; sourceTree = ""; }; + 90FD6D6E103C3D49005F5B73 /* ASTLocation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ASTLocation.cpp; path = lib/Index/ASTLocation.cpp; sourceTree = ""; }; + 90FD6D6F103C3D49005F5B73 /* ASTVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTVisitor.h; path = lib/Index/ASTVisitor.h; sourceTree = ""; }; + 90FD6D70103C3D49005F5B73 /* DeclReferenceMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DeclReferenceMap.cpp; path = lib/Index/DeclReferenceMap.cpp; sourceTree = ""; }; + 90FD6D71103C3D49005F5B73 /* Entity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Entity.cpp; path = lib/Index/Entity.cpp; sourceTree = ""; }; + 90FD6D72103C3D49005F5B73 /* EntityImpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EntityImpl.h; path = lib/Index/EntityImpl.h; sourceTree = ""; }; + 90FD6D73103C3D49005F5B73 /* GlobalSelector.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GlobalSelector.cpp; path = lib/Index/GlobalSelector.cpp; sourceTree = ""; }; + 90FD6D74103C3D49005F5B73 /* Handlers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Handlers.cpp; path = lib/Index/Handlers.cpp; sourceTree = ""; }; + 90FD6D75103C3D49005F5B73 /* Indexer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Indexer.cpp; path = lib/Index/Indexer.cpp; sourceTree = ""; }; + 90FD6D76103C3D49005F5B73 /* IndexProvider.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = IndexProvider.cpp; path = lib/Index/IndexProvider.cpp; sourceTree = ""; }; + 90FD6D77103C3D49005F5B73 /* Program.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Program.cpp; path = lib/Index/Program.cpp; sourceTree = ""; }; + 90FD6D78103C3D49005F5B73 /* ProgramImpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProgramImpl.h; path = lib/Index/ProgramImpl.h; sourceTree = ""; }; + 90FD6D79103C3D49005F5B73 /* ResolveLocation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ResolveLocation.cpp; path = lib/Index/ResolveLocation.cpp; sourceTree = ""; }; + 90FD6D7A103C3D49005F5B73 /* SelectorMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SelectorMap.cpp; path = lib/Index/SelectorMap.cpp; sourceTree = ""; }; + 90FD6D86103C3D80005F5B73 /* Analyses.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Analyses.def; path = clang/Frontend/Analyses.def; sourceTree = ""; }; + 90FD6D87103C3D80005F5B73 /* AnalysisConsumer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AnalysisConsumer.h; path = clang/Frontend/AnalysisConsumer.h; sourceTree = ""; }; + 90FD6D88103C3D80005F5B73 /* ASTConsumers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTConsumers.h; path = clang/Frontend/ASTConsumers.h; sourceTree = ""; }; + 90FD6D89103C3D80005F5B73 /* ASTUnit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTUnit.h; path = clang/Frontend/ASTUnit.h; sourceTree = ""; }; + 90FD6D8A103C3D80005F5B73 /* CommandLineSourceLoc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandLineSourceLoc.h; path = clang/Frontend/CommandLineSourceLoc.h; sourceTree = ""; }; + 90FD6D8B103C3D80005F5B73 /* DeclContextXML.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = DeclContextXML.def; path = clang/Frontend/DeclContextXML.def; sourceTree = ""; }; + 90FD6D8C103C3D80005F5B73 /* DeclXML.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = DeclXML.def; path = clang/Frontend/DeclXML.def; sourceTree = ""; }; + 90FD6D8D103C3D80005F5B73 /* DocumentXML.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = DocumentXML.def; path = clang/Frontend/DocumentXML.def; sourceTree = ""; }; + 90FD6D8E103C3D80005F5B73 /* DocumentXML.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DocumentXML.h; path = clang/Frontend/DocumentXML.h; sourceTree = ""; }; + 90FD6D8F103C3D80005F5B73 /* StmtXML.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = StmtXML.def; path = clang/Frontend/StmtXML.def; sourceTree = ""; }; + 90FD6D90103C3D80005F5B73 /* TypeXML.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = TypeXML.def; path = clang/Frontend/TypeXML.def; sourceTree = ""; }; + 90FD6D91103C3D80005F5B73 /* Utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Utils.h; path = clang/Frontend/Utils.h; sourceTree = ""; }; + 90FD6DB5103D977E005F5B73 /* index-test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "index-test.cpp"; path = "tools/index-test/index-test.cpp"; sourceTree = ""; }; BDF87CF60FD746F300BBF872 /* SemaTemplateDeduction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaTemplateDeduction.cpp; path = lib/Sema/SemaTemplateDeduction.cpp; sourceTree = ""; tabWidth = 2; }; DE01DA480B12ADA300AC22CE /* PPCallbacks.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PPCallbacks.h; sourceTree = ""; }; DE06756B0C051CFE00EBBFD8 /* ParseExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ParseExprCXX.cpp; path = lib/Parse/ParseExprCXX.cpp; sourceTree = ""; tabWidth = 2; }; @@ -530,7 +611,6 @@ DE3986EF0CB8D4B300223765 /* IdentifierTable.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = IdentifierTable.h; sourceTree = ""; tabWidth = 2; }; DE3986F30CB8D50C00223765 /* IdentifierTable.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = IdentifierTable.cpp; sourceTree = ""; tabWidth = 2; }; DE3B90DE0EAC5EF200D01046 /* ExtensionRAIIObject.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ExtensionRAIIObject.h; path = lib/Parse/ExtensionRAIIObject.h; sourceTree = ""; tabWidth = 2; }; - DE3B921C0EB1A81400D01046 /* SemaInherit.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = SemaInherit.h; path = lib/Sema/SemaInherit.h; sourceTree = ""; tabWidth = 2; }; DE3B92230EB5152000D01046 /* Designator.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Designator.h; path = clang/Parse/Designator.h; sourceTree = ""; tabWidth = 2; }; DE41211D0D7F1BBE0080F80A /* GRWorkList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GRWorkList.h; path = clang/Analysis/PathSensitive/GRWorkList.h; sourceTree = ""; }; DE41211E0D7F1BBE0080F80A /* SymbolManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SymbolManager.h; path = clang/Analysis/PathSensitive/SymbolManager.h; sourceTree = ""; }; @@ -603,8 +683,6 @@ DEB077980F44F97800F5A2BE /* TokenConcatenation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TokenConcatenation.cpp; sourceTree = ""; }; DEB07AC70F4A427E00F5A2BE /* SemaAttr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaAttr.cpp; path = lib/Sema/SemaAttr.cpp; sourceTree = ""; tabWidth = 2; }; DEB089EE0F12F1D900522C07 /* TypeTraits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TypeTraits.h; sourceTree = ""; }; - DEC63B190C7B940200DBF169 /* CFG.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CFG.cpp; path = lib/AST/CFG.cpp; sourceTree = ""; tabWidth = 2; }; - DEC63B1B0C7B940600DBF169 /* CFG.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CFG.h; path = clang/AST/CFG.h; sourceTree = ""; tabWidth = 2; }; DEC8D9900A9433CD00353FCA /* Decl.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Decl.h; path = clang/AST/Decl.h; sourceTree = ""; tabWidth = 2; }; DEC8D9A30A94346E00353FCA /* AST.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = AST.h; path = clang/AST/AST.h; sourceTree = ""; tabWidth = 2; }; DECAB0CF0DB3C84200E13CCB /* RewriteRope.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RewriteRope.cpp; path = lib/Rewrite/RewriteRope.cpp; sourceTree = ""; }; @@ -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 = ""; }; + 9012911210470FAF0083456D /* clang-c */ = { + isa = PBXGroup; + children = ( + 9012911510470FCE0083456D /* Index.h */, + ); + name = "clang-c"; + sourceTree = ""; + }; + 9012911E104812DA0083456D /* CIndex */ = { + isa = PBXGroup; + children = ( + 9012911F104812F90083456D /* CIndex.cpp */, + 90129120104812F90083456D /* CIndex.exports */, + ); + name = CIndex; + sourceTree = ""; + }; + 90F9EFA8104ABDC400D09A15 /* c-index-test */ = { + isa = PBXGroup; + children = ( + 90F9EFA9104ABDED00D09A15 /* c-index-test.c */, + ); + name = "c-index-test"; + sourceTree = ""; + }; + 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 = ""; + }; + 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 = ""; + }; + 90FD6DB4103D9763005F5B73 /* index-test */ = { + isa = PBXGroup; + children = ( + 90FD6DB5103D977E005F5B73 /* index-test.cpp */, + ); + name = "index-test"; + sourceTree = ""; + }; 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 = ""; @@ -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 = ""; @@ -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 = ""; @@ -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 a99d72cd4eb2c..a7d2da37711e9 100644 --- a/docs/DriverInternals.html +++ b/docs/DriverInternals.html @@ -240,7 +240,7 @@

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 @@

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.

@@ -409,7 +409,7 @@

Unified Parsing & Pipelining

-

Parsing and pipeling both occur without reference to a +

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

-

For example, on Darwin -gfull gets translated into - two separate arguments, -g - and -fno-eliminate-unused-debug-symbols. Trying to - write Tool logic to do something with -gfull will not - work, because at Tools run after the arguments have been +

For example, on Darwin -gfull gets translated into two + separate arguments, -g + and -fno-eliminate-unused-debug-symbols. Trying to write Tool + logic to do something with -gfull will not work, because Tool + argument translation is done after the arguments have been translated.

A long term goal is to remove this tool chain specific diff --git a/docs/InternalsManual.html b/docs/InternalsManual.html index a4d5a057ebaa6..f39224f47dc56 100644 --- a/docs/InternalsManual.html +++ b/docs/InternalsManual.html @@ -67,6 +67,7 @@ td {

  • Constant Folding in the Clang AST
  • +
  • The Index Library
  • @@ -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).

    -

    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.

    -

    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 c855a5057a62d..9ac35e1dc2dc2 100644 --- a/docs/LanguageExtensions.html +++ b/docs/LanguageExtensions.html @@ -27,6 +27,7 @@ td {

  • Builtin Functions
  • Target-Specific Extensions @@ -264,7 +265,7 @@ builtins that we need to implement.

    __builtin_shufflevector

    -

    __builtin_shufflevector is used to expression generic vector +

    __builtin_shufflevector is used to express generic vector permutation/shuffle/swizzle operations. This builtin is also very important for the implementation of various target-specific header files like <xmmintrin.h>. @@ -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.

    +

    Query for this feature with __has_builtin(__builtin_shufflevector).

    + + +

    __builtin_unreachable

    + + +

    __builtin_unreachable is used to indicate that a specific point in +the program cannot be reached, even if the compiler might otherwise think it +can. This is useful to improve optimization and eliminates certain warnings. +For example, without the __builtin_unreachable in the example below, +the compiler assumes that the inline asm can fall through and prints a "function +declared 'noreturn' should not return" warning. +

    + +

    Syntax:

    + +
    +__builtin_unreachable()
    +
    + +

    Example of Use:

    + +
    +void myabort(void) __attribute__((noreturn));
    +void myabort(void) {
    +    asm("int3");
    +    __builtin_unreachable();
    +}
    +
    + +

    Description:

    + +

    The __builtin_unreachable() builtin has completely undefined behavior. Since +it has undefined behavior, it is a statement that it is never reached and the +optimizer can take advantage of this to produce better code. This builtin takes +no arguments and produces a void result. +

    + +

    Query for this feature with __has_builtin(__builtin_unreachable).

    + +

    Target-Specific Extensions

    diff --git a/docs/UsersManual.html b/docs/UsersManual.html index 65415eea48d5a..20fdda72dced9 100644 --- a/docs/UsersManual.html +++ b/docs/UsersManual.html @@ -33,6 +33,12 @@ td {
  • Language and Target-Independent Features
  • @@ -362,7 +368,7 @@ by commenting them out.

    Clang provides a number of ways to control which code constructs cause it to emit errors and warning messages, and how they are displayed to the console.

    -

    Controlling How Clang Displays Diagnostics

    +

    Controlling How Clang Displays Diagnostics

    When Clang emits a diagnostic, it includes rich information in the output, and gives you fine-grain control over which information is printed. Clang has @@ -394,18 +400,64 @@ it:

    For more information please see Formatting of Diagnostics.

    -

    Controlling Which Diagnostics Clang Generates

    +

    Diagnostic Mappings

    -

    mappings: ignore, note, warning, error, fatal

    +

    All diagnostics are mapped into one of these 5 classes:

    -The two major classes are control from the command line and control via pragmas -in your code.

    +
      +
    • Ignored
    • +
    • Note
    • +
    • Warning
    • +
    • Error
    • +
    • Fatal
    • +

    +

    Controlling Diagnostics via Command Line Flags

    -W flags, -pedantic, etc

    -

    pragma GCC diagnostic

    +

    Controlling Diagnostics via Pragmas

    + +

    Clang can also control what diagnostics are enabled through the use of +pragmas in the source code. This is useful for turning off specific warnings +in a section of source code. Clang supports GCC's pragma for compatibility +with existing source code, as well as several extensions.

    + +

    The pragma may control any warning that can be used from the command line. +Warnings may be set to ignored, warning, error, or fatal. The following +example code will tell Clang or GCC to ignore the -Wall warnings:

    + +
    +#pragma GCC diagnostic ignored "-Wall"
    +
    + +

    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.

    + +

    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.

    + +
    +#pragma clang diagnostic push
    +#pragma clang diagnostic ignored "-Wmultichar"
    +
    +char b = 'df'; // no warning.
    +
    +#pragma clang diagnostic pop
    +
    + +

    The push and pop pragmas will save and restore the full diagnostic state of +the compiler, regardless of how it was set. That means that it is possible to +use push and pop around GCC compatible diagnostics and Clang will push and pop +them appropriately, while GCC will ignore the pushes and pops as unknown +pragmas. It should be noted that while Clang supports the GCC pragma, Clang and +GCC do not support the exact same set of warnings, so even when using GCC +compatible #pragmas there is no guarantee that they will have identical behaviour +on both compilers.

    Precompiled Headers

    @@ -465,6 +517,50 @@ for headers that are directly included within a source file. For example:

    test.h since test.h was included directly in the source file and not specified on the command line using -include.

    +

    Relocatable PCH Files

    +

    It is sometimes necessary to build a precompiled header from headers that +are not yet in their final, installed locations. For example, one might build a +precompiled header within the build tree that is then meant to be installed +alongside the headers. Clang permits the creation of "relocatable" precompiled +headers, which are built with a given path (into the build directory) and can +later be used from an installed location.

    + +

    To build a relocatable precompiled header, place your headers into a +subdirectory whose structure mimics the installed location. For example, if you +want to build a precompiled header for the header mylib.h that +will be installed into /usr/include, create a subdirectory +build/usr/include and place the header mylib.h into +that subdirectory. If mylib.h depends on other headers, then +they can be stored within build/usr/include in a way that mimics +the installed location.

    + +

    Building a relocatable precompiled header requires two additional arguments. +First, pass the --relocatable-pch flag to indicate that the +resulting PCH file should be relocatable. Second, pass +-isysroot /path/to/build, which makes all includes for your +library relative to the build directory. For example:

    + +
    +  # clang -x c-header --relocatable-pch -isysroot /path/to/build /path/to/build/mylib.h mylib.h.pch
    +
    + +

    When loading the relocatable PCH file, the various headers used in the PCH +file are found from the system header root. For example, mylib.h +can be found in /usr/include/mylib.h. If the headers are installed +in some other system root, the -isysroot option can be used provide +a different system root from which the headers will be based. For example, +-isysroot /Developer/SDKs/MacOSX10.4u.sdk will look for +mylib.h in +/Developer/SDKs/MacOSX10.4u.sdk/usr/include/mylib.h.

    + +

    Relocatable precompiled headers are intended to be used in a limited number +of cases where the compilation environment is tightly controlled and the +precompiled header cannot be generated after headers have been installed. +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, +stat() caching, to be disabled. However, this change is only +likely to affect PCH files that reference a large number of headers.

    C Language Features

    @@ -500,7 +596,6 @@ variants "__asm__" and "__typeof__" are recognized in all modes.
  • The Apple "blocks" extension is recognized by default in gnu* modes on some platforms; it can be enabled in any mode with the "-fblocks" option.
  • -
  • Some warnings are different.
  • Differences between *89 and *99 modes:

    diff --git a/docs/libIndex.html b/docs/libIndex.html new file mode 100644 index 0000000000000..5693de80a8685 --- /dev/null +++ b/docs/libIndex.html @@ -0,0 +1,267 @@ + + + The Index Library + + + + + + + + + +
    + +

    The Index Library

    + +

    Table of Contents

    + + +

    Design Philosophy

    + +

    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.

    + +

    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.

    + +

    Classes

    + +

    Entity

    + +

    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:

    + +

    +t1.c: +

    +void foo(void);
    +void bar(void);
    +
    +

    + +

    +t2.c: +

    +void foo(void) {
    +}
    +
    +

    + +

    +Translation unit t1.c contains 2 Entities foo and bar, while t2.c contains 1 Entity foo. +Entities are uniqued in such a way that the Entity* pointer for t1.c/foo is the same as the Entity* pointer for t2.c/foo. +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: +

    +

    +t3.c: +

    +static void foo(void);
    +
    +

    +

    +there can be no Entity (if you ask for the Entity* of the static function foo you'll get a null pointer). +This is for 2 reasons: +

      +
    • To preserve the invariant that the same Entity* pointers refer to the same semantic Decls. + In the above example t1.c/foo and t2.c/foo are the same, while t3.c/foo is different.
    • +
    • 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.
    • +
    +

    + +

    ASTLocation

    + +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 foo in the form of ASTLocations, +"pointing" at the expressions that reference foo. + +

    DeclReferenceMap

    + +Accepts an ASTContext and creates a mapping from NamedDecls to the ASTLocations that reference them (in the same ASTContext). + +

    Functions

    + +

    ResolveLocationInAST

    + +A function that accepts an ASTContext and a SourceLocation which it resolves into an ASTLocation. + +

    AST Files

    + +The precompiled headers implementation of clang (PCH) 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. + +

    index-test tool

    + +

    Usage

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

    +

    +   -point-at  [file:line:column]
    +
    +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. +

    + +

    +

    +   -print-refs
    +
    +Prints the ASTLocations that reference the declaration that was resolved out of the [file:line:column] triplet +

    + +

    +

    +   -print-defs
    +
    +Prints the ASTLocations that define the resolved declaration +

    + +

    +

    +   -print-decls
    +
    +Prints the ASTLocations that declare the resolved declaration +

    + +

    Examples

    + +

    +Here's an example of using index-test: +

    + +

    +We have 3 files, +

    + +

    +foo.h: +

    +extern int global_var;
    +
    +void foo_func(int param1);
    +void bar_func(void);
    +
    + +t1.c: +
    +#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();
    +}
    +
    + +t2.c: +
    +#include "foo.h"
    +
    +int global_var = 10;
    +
    +void bar_func(void) {
    +  global_var += 100;
    +  foo_func(global_var);
    +}
    +
    +

    + +

    +You first get AST files out of t1.c and t2.c: + +

    +$ clang-cc -emit-pch t1.c -o t1.ast
    +$ clang-cc -emit-pch t2.c -o t2.ast
    +
    +

    + +

    +Find the ASTLocation under this position of t1.c: +

    +[...]
    +void foo_func(int param1) {
    +  int local_var = global_var;
    +                      ^
    +[...]
    +
    + +
    +$ index-test t1.ast -point-at t1.c:4:23
    +> [Decl: Var local_var | Stmt: DeclRefExpr global_var] <t1.c:4:19, t1.c:4:19>
    +
    +

    + +

    +Find the declaration: + +

    +$ index-test t1.ast -point-at t1.c:4:23 -print-decls
    +> [Decl: Var global_var] <foo.h:1:12, foo.h:1:12>
    +
    +

    + +

    +Find the references: + +

    +$ index-test t1.ast t2.ast -point-at t1.c:4:23 -print-refs
    +> [Decl: Var local_var | Stmt: DeclRefExpr global_var] <t1.c:4:19, t1.c:4:19>
    +> [Decl: Function bar_func | Stmt: DeclRefExpr global_var] <t2.c:6:3, t2.c:6:3>
    +> [Decl: Function bar_func | Stmt: DeclRefExpr global_var] <t2.c:7:12, t2.c:7:12>
    +
    +

    + +

    +Find definitions: + +

    +$ index-test t1.ast t2.ast -point-at t1.c:4:23 -print-defs
    +> [Decl: Var global_var] <t2.c:3:5, t2.c:3:18>
    +
    +

    + +
    + + + diff --git a/docs/tools/Makefile b/docs/tools/Makefile index 90eb7768f531b..12696ef0b659b 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 c520f93997e53..daa7387989309 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 -=item B<-iquote>I -=item B<-isystem>I -=item B<-iprefix>I -=item B<-iwithprefix>I -=item B<-iwithprefixbefore>I -=item B<-isysroot> +#=item B<-idirafter>I +#=item B<-iquote>I +#=item B<-isystem>I +#=item B<-iprefix>I +#=item B<-iwithprefix>I +#=item B<-iwithprefixbefore>I +#=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 0000000000000..3178017e45be8 --- /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 -o ". + + 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 5d5abfe011d4f..94d258d9e4e6d 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(this)->getInt(); } - + APFloat &getFloat() { assert(isFloat() && "Invalid accessor"); - return *(APFloat*)(void*)Data; + return *(APFloat*)(char*)Data; } const APFloat &getFloat() const { return const_cast(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(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(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(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(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 6dc7e13d8f70c..af6bf30b6882d 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 041a0f33ad4d7..63f909146e927 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 Types; - llvm::FoldingSet ExtQualTypes; + llvm::FoldingSet ExtQualNodes; llvm::FoldingSet ComplexTypes; llvm::FoldingSet PointerTypes; llvm::FoldingSet BlockPointerTypes; @@ -70,17 +73,21 @@ class ASTContext { llvm::FoldingSet ConstantArrayTypes; llvm::FoldingSet IncompleteArrayTypes; std::vector VariableArrayTypes; - std::vector DependentSizedArrayTypes; - std::vector DependentSizedExtVectorTypes; + llvm::FoldingSet DependentSizedArrayTypes; + llvm::FoldingSet DependentSizedExtVectorTypes; llvm::FoldingSet VectorTypes; llvm::FoldingSet FunctionNoProtoTypes; llvm::FoldingSet FunctionProtoTypes; + llvm::FoldingSet DependentTypeOfExprTypes; + llvm::FoldingSet DependentDecltypeTypes; llvm::FoldingSet TemplateTypeParmTypes; llvm::FoldingSet TemplateSpecializationTypes; llvm::FoldingSet QualifiedNameTypes; llvm::FoldingSet TypenameTypes; - llvm::FoldingSet ObjCQualifiedInterfaceTypes; + llvm::FoldingSet ObjCInterfaceTypes; llvm::FoldingSet ObjCObjectPointerTypes; + llvm::FoldingSet ObjCProtocolListTypes; + llvm::FoldingSet ElaboratedTypes; llvm::FoldingSet QualifiedTemplateNames; llvm::FoldingSet DependentTemplateNames; @@ -97,46 +104,109 @@ class ASTContext { llvm::DenseMap ASTRecordLayouts; llvm::DenseMap ObjCLayouts; + /// \brief Mapping from ObjCContainers to their ObjCImplementations. + llvm::DenseMap ObjCImpls; + llvm::DenseMap SignedFixedWidthIntTypes; llvm::DenseMap 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 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 + /// struct X { + /// static T value; + /// }; + /// + /// template + /// T X::value = T(17); + /// + /// int *x = &X::value; + /// \endcode + /// + /// This mapping will contain an entry that maps from the VarDecl for + /// X::value to the corresponding VarDecl for X::value (within the + /// class template X) and will be marked TSK_ImplicitInstantiation. + llvm::DenseMap + InstantiatedFromStaticDataMember; + + /// \brief Keeps track of the UnresolvedUsingDecls from which UsingDecls + /// where created during instantiation. + /// + /// For example: + /// \code + /// template + /// struct A { + /// void f(); + /// }; + /// + /// template + /// struct B : A { + /// using A::f; + /// }; + /// + /// template struct B; + /// \endcode + /// + /// This mapping will contain an entry that maps from the UsingDecl in + /// B to the UnresolvedUsingDecl in B. + llvm::DenseMap + InstantiatedFromUnresolvedUsingDecl; + + llvm::DenseMap 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 DeclComments; - -public: + +public: TargetInfo &Target; IdentifierTable &Idents; SelectorTable &Selectors; @@ -163,41 +233,73 @@ public: llvm::OwningPtr 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 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 . 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 . 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 + GE_None, //< No error + GE_Missing_stdio, //< Missing a type from + GE_Missing_setjmp //< Missing a type from }; - + /// 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

    (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 getTypeInfo(const Type *T); std::pair 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(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(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::iterator type_iterator; typedef std::vector::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 e9f150574b050..abd36f7e5f0fa 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 7d3009b011293..6a5e3666a92c4 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 #include #include @@ -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 const T *getNext() const { + for (const Attr *attr = getNext(); attr; attr = attr->getNext()) + if (const T *V = dyn_cast(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 0000000000000..a57bcc184a936 --- /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 +#include +#include + +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 { + /// \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 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, 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::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 0000000000000..d7ac76dd32e42 --- /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 + +namespace clang { + +template class CanProxy; +template 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 will be of that +/// type (or some subclass of that type). The typedef @c CanQualType is just +/// a shorthand for @c CanQual. +/// +/// An instance of @c CanQual can be implicitly converted to a +/// @c CanQual when T is derived from U, which essentially provides an +/// implicit upcast. For example, @c CanQual can be +/// converted to @c CanQual. Note that any @c CanQual type can +/// be implicitly converted to a QualType, but the reverse operation requires +/// a call to ASTContext::getCanonicalType(). +/// +/// +template +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 + CanQual(const CanQual& Other, + typename llvm::enable_if, 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 Ptr = T->getAs()) { ... } + /// @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(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 T) { + /// if (CanQual Ptr = T->getAs()) { + /// // 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 CanProxy getAs() const; + + /// \brief Overloaded arrow operator that produces a canonical type + /// proxy. + CanProxy 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 getUnqualifiedType() const; + + CanQual getQualifiedType(unsigned TQs) const { + return CanQual::CreateUnsafe(QualType(getTypePtr(), TQs)); + } + + /// \brief Determines whether this canonical type is more qualified than + /// the @p Other canonical type. + bool isMoreQualifiedThan(CanQual 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 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 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 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 CreateUnsafe(QualType Other); +}; + +template +inline bool operator==(CanQual x, CanQual y) { + return x.getAsOpaquePtr() == y.getAsOpaquePtr(); +} + +template +inline bool operator!=(CanQual x, CanQual y) { + return x.getAsOpaquePtr() != y.getAsOpaquePtr(); +} + +/// \brief Represents a canonical, potentially-qualified type. +typedef CanQual 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 +class CanProxyBase { +protected: + CanQual 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 Ptr = T->getAs()) { ... } + /// @endcode + operator const T*() const { return this->Stored.getTypePtr(); } + + /// \brief Try to convert the given canonical type to a specific structural + /// type. + template CanProxy getAs() const { + return this->Stored.template getAs(); + } + + 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 *operator->() const { + return static_cast *>(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 +struct CanProxyAdaptor : CanProxyBase { }; + +/// \brief Canonical proxy type returned when retrieving the members of a +/// canonical type or as the result of the @c CanQual::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 +class CanProxy : public CanProxyAdaptor { +public: + /// \brief Build a NULL proxy. + CanProxy() { } + + /// \brief Build a proxy to the given canonical type. + CanProxy(CanQual Stored) { this->Stored = Stored; } + + /// \brief Implicit conversion to the stored canonical type. + operator CanQual() const { return this->Stored; } +}; + +} // end namespace clang + +namespace llvm { + +/// Implement simplify_type for CanQual, so that we can dyn_cast from +/// CanQual to a specific Type class. We're prefer isa/dyn_cast/cast/etc. +/// to return smart pointer (proxies?). +template +struct simplify_type > { + typedef T* SimpleType; + static SimpleType getSimplifiedValue(const ::clang::CanQual &Val) { + return Val.getTypePtr(); + } +}; +template +struct simplify_type< ::clang::CanQual > +: public simplify_type > {}; + +// Teach SmallPtrSet that CanQual is "basically a pointer". +template +class PointerLikeTypeTraits > { +public: + static inline void *getAsVoidPointer(clang::CanQual P) { + return P.getAsOpaquePtr(); + } + static inline clang::CanQual getFromVoidPointer(void *P) { + return clang::CanQual::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 +class CanTypeIterator { + InputIterator Iter; + +public: + typedef CanQualType value_type; + typedef value_type reference; + typedef CanProxy pointer; + typedef typename std::iterator_traits::difference_type + difference_type; + typedef typename std::iterator_traits::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 : public CanProxyBase { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) +}; + +template<> +struct CanProxyAdaptor : public CanProxyBase { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType) +}; + +template<> +struct CanProxyAdaptor + : public CanProxyBase { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType) +}; + +template<> +struct CanProxyAdaptor : public CanProxyBase { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType) +}; + +template<> +struct CanProxyAdaptor + : public CanProxyBase { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType) +}; + +template<> +struct CanProxyAdaptor + : public CanProxyBase { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType) +}; + +template<> +struct CanProxyAdaptor + : public CanProxyBase { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const Type *, getClass) +}; + +template<> +struct CanProxyAdaptor : public CanProxyBase { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(ArrayType::ArraySizeModifier, + getSizeModifier) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Qualifiers, getIndexTypeQualifiers) +}; + +template<> +struct CanProxyAdaptor + : public CanProxyBase { + 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 + : public CanProxyBase { + 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 + : public CanProxyBase { + 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 + : public CanProxyBase { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(ArrayType::ArraySizeModifier, + getSizeModifier) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Qualifiers, getIndexTypeQualifiers) +}; + +template<> +struct CanProxyAdaptor + : public CanProxyBase { + 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 + : public CanProxyBase { + 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 + : public CanProxyBase { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const Expr *, getSizeExpr) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getAttributeLoc) +}; + +template<> +struct CanProxyAdaptor : public CanProxyBase { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getNumElements) +}; + +template<> +struct CanProxyAdaptor : public CanProxyBase { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getNumElements) +}; + +template<> +struct CanProxyAdaptor : public CanProxyBase { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getResultType) +}; + +template<> +struct CanProxyAdaptor + : public CanProxyBase { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getResultType) +}; + +template<> +struct CanProxyAdaptor + : public CanProxyBase { + 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 + 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 : public CanProxyBase { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getUnderlyingType) +}; + +template<> +struct CanProxyAdaptor : public CanProxyBase { + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Expr *, getUnderlyingExpr) + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getUnderlyingType) +}; + +template<> +struct CanProxyAdaptor : public CanProxyBase { + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(TagDecl *, getDecl) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBeingDefined) +}; + +template<> +struct CanProxyAdaptor : public CanProxyBase { + 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 : public CanProxyBase { + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(EnumDecl *, getDecl) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBeingDefined) +}; + +template<> +struct CanProxyAdaptor + : public CanProxyBase { + 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 + : public CanProxyBase { + 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 +inline CanQual CanQual::getUnqualifiedType() const { + return CanQual::CreateUnsafe(Stored.getUnqualifiedType()); +} + +template +inline CanQual CanQual::getNonReferenceType() const { + if (CanQual RefType = getAs()) + return RefType->getPointeeType(); + else + return *this; +} + +template +CanQual CanQual::getFromOpaquePtr(void *Ptr) { + CanQual Result; + Result.Stored.setFromOpaqueValue(Ptr); + assert((!Result || Result.Stored.isCanonical()) + && "Type is not canonical!"); + return Result; +} + +template +CanQual CanQual::CreateUnsafe(QualType Other) { + assert((Other.isNull() || Other->isCanonical()) && "Type is not canonical!"); + assert((Other.isNull() || isa(Other.getTypePtr())) && + "Dynamic type does not meet the static type's requires"); + CanQual Result; + Result.Stored = Other; + return Result; +} + +template +template +CanProxy CanQual::getAs() const { + if (Stored.isNull()) + return CanProxy(); + + if (isa(Stored.getTypePtr())) + return CanQual::CreateUnsafe(Stored); + + return CanProxy(); +} + +template +CanProxy CanQual::operator->() const { + return CanProxy(*this); +} + +template +typename CanTypeIterator::pointer +CanTypeIterator::operator->() const { + return CanProxy(*this); +} + +} + + +#endif // LLVM_CLANG_AST_CANONICAL_TYPE_H diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 69a52869d8188..7c326dee338c5 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(&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(const_cast(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(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 { 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 InitType; + + /// \brief The initializer for this variable or, for a ParmVarDecl, the + /// C++ default argument. + mutable InitType Init; + private: - mutable llvm::PointerUnion 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 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(); - if (!S) - S = Init.get()->Value; - - return (const Expr*) S; + if (!S) { + if (EvaluatedStmt *ES = Init.dyn_cast()) + S = ES->Value; + } + return (const Expr*) S; } - Expr *getInit() { + Expr *getInit() { if (Init.isNull()) return 0; Stmt *S = Init.dyn_cast(); - if (!S) - S = Init.get()->Value; + if (!S) { + if (EvaluatedStmt *ES = Init.dyn_cast()) + S = ES->Value; + } - return (Expr*) S; + return (Expr*) S; } /// \brief Retrieve the address of the initializer expression. Stmt **getInitAddress() { - if (Init.is()) - return reinterpret_cast(&Init); // FIXME: ugly hack - return &Init.get()->Value; + if (EvaluatedStmt *ES = Init.dyn_cast()) + 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()->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(Ctx) || isa(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 (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(defarg); + } + + /// \brief Retrieve the source range that covers the entire default + /// argument. + SourceRange getDefaultArgRange() const; + void setUninstantiatedDefaultArg(Expr *arg) { + Init = reinterpret_cast(arg); + } + Expr *getUninstantiatedDefaultArg() { + return (Expr *)Init.get(); + } + const Expr *getUninstantiatedDefaultArg() const { + return (const Expr *)Init.get(); } - 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(-1); + return Init.is(); + } + + bool hasUninstantiatedDefaultArg() const { + return Init.is(); } /// 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(-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 { 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 + llvm::PointerUnion3 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 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()->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::A. When a complete definition of /// X::A is required, it will be instantiated from the /// declaration returned by getInstantiatedFromMemberFunction(). - FunctionDecl *getInstantiatedFromMemberFunction() const { - return TemplateOrSpecialization.dyn_cast(); - } + 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(); + } + /// \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 { 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 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(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 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(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(const_cast(D)); } diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index 0bce2f84c7ba7..9e88871565f1f 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(); } - + /// 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(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 bool hasAttr() const { return getAttr() != 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(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(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(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(this)->getLexicalParent(); - } + } + DeclContext *getLookupParent(); + + const DeclContext *getLookupParent() const { + return const_cast(this)->getLookupParent(); + } + ASTContext &getParentASTContext() const { return cast(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(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_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 c523e96e03b06..c858c5c0df787 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 { typedef ::clang::NamedDecl* SimpleType; @@ -63,26 +68,26 @@ namespace llvm { }; template<> struct simplify_type< ::clang::AnyFunctionDecl> : public simplify_type {}; - + // 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(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 + /// MemberSpecializationInfo referring to the member class that was + /// instantiated or specialized. + llvm::PointerUnion TemplateOrInstantiation; - + + void getNestedVisibleConversionFunctions(CXXRecordDecl *RD, + const llvm::SmallPtrSet &TopConversionsTypeSet, + const llvm::SmallPtrSet &HiddenConversionTypes); + void collectConversionFunctions( + llvm::SmallPtrSet& 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 + reverse_base_class_iterator; + + /// reverse_base_class_iterator = Iterator that traverses the base classes + /// of a class in reverse order. + typedef std::reverse_iterator + reverse_base_class_const_iterator; + + virtual CXXRecordDecl *getCanonicalDecl() { + return cast(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 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 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(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(getTypeForDecl())->isBeingDefined()) && + "getConversionFunctions() called on incomplete type"); + return &Conversions; } - const OverloadedFunctionDecl *getConversionFunctions() const { - return &Conversions; + const OverloadedFunctionDecl *getConversionFunctions() const { + assert((this->isDefinition() || + cast(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::A. When a complete definition of /// X::A is required, it will be instantiated from the /// declaration returned by getInstantiatedFromMemberClass(). - CXXRecordDecl *getInstantiatedFromMemberClass() const { - return TemplateOrInstantiation.dyn_cast(); - } - + 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(getDeclContext())) return RD->isLocalClass(); - + return dyn_cast(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(const_cast(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(FunctionDecl::getCanonicalDecl()); + } + CXXMethodDecl *getCanonicalDecl() { + return cast(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(FunctionDecl::getParent()); + const CXXRecordDecl *getParent() const { + return cast(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( cast(FunctionDecl::getParent())); } @@ -557,11 +950,11 @@ public: QualType getThisType(ASTContext &C) const; unsigned getTypeQualifiers() const { - return getType()->getAsFunctionProtoType()->getTypeQuals(); + return getType()->getAs()->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 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(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(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(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(BaseOrMember); + return reinterpret_cast(BaseOrMember); else return 0; } + void setMember(FieldDecl * anonUnionField) { + BaseOrMember = reinterpret_cast(anonUnionField); + } + + FieldDecl *getAnonUnionMember() const { + return CtorOrAnonUnion.dyn_cast(); + } + void setAnonUnionMember(FieldDecl *anonMember) { + CtorOrAnonUnion = anonMember; + } + + const CXXConstructorDecl *getConstructor() const { + return CtorOrAnonUnion.dyn_cast(); + } + 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(Base & ~0x03); + return 0; + } + /// getMemberToDestroy - Get the member for the given object. + FieldDecl *getMemberToDestroy(uintptr_t Member) const { + if (isMemberToDestroy(Member)) + return reinterpret_cast(Member); + return 0; + } + /// getVbaseClassToDestroy - Get the virtual base. + Type *getVbaseClassToDestroy(uintptr_t Vbase) const { + if (isVbaseToDestroy(Vbase)) + return reinterpret_cast(Vbase & ~0x01); + return 0; + } + /// getDirectNonVBaseClassToDestroy - Get the virtual base. + Type *getDirectNonVBaseClassToDestroy(uintptr_t Base) const { + if (isDirectNonVBaseToDestroy(Base)) + return reinterpret_cast(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()->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 class A { +/// friend int foo(T); +/// friend class B; +/// friend T; // only in C++0x +/// template friend class C; +/// template 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 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(); + } + + /// If this friend declaration doesn't name an unelaborated + /// type, return the inner declaration. + NamedDecl *getFriendDecl() const { + return Friend.dyn_cast(); + } + + /// 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(Namespace); } - + const NamespaceDecl *getNamespace() const { return const_cast(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 6c1231c0a73d5..d9e40d4789073 100644 --- a/include/clang/AST/DeclContextInternals.h +++ b/include/clang/AST/DeclContextInternals.h @@ -57,13 +57,13 @@ public: Data = reinterpret_cast(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(OldD)); Data = reinterpret_cast(VT) | DK_Decl_Vector; } - + VectorTy &Vec = *getAsVector(); if (isa(D) || D->getIdentifierNamespace() == Decl::IDNS_Tag) @@ -217,4 +217,4 @@ typedef llvm::DenseMap StoredDeclsMap; } // end namespace clang -#endif +#endif diff --git a/include/clang/AST/DeclGroup.h b/include/clang/AST/DeclGroup.h index 15a8adef8e57b..790ea3ca06624 100644 --- a/include/clang/AST/DeclGroup.h +++ b/include/clang/AST/DeclGroup.h @@ -18,7 +18,7 @@ #include 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(D) & Mask); - } - -public: + } + +public: DeclGroupRef() : D(0) {} - + explicit DeclGroupRef(Decl* d) : D(d) {} explicit DeclGroupRef(DeclGroup* dg) : D((Decl*) (reinterpret_cast(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(this)->getSingleDecl(); } - + DeclGroup &getDeclGroup() { assert(isDeclGroup() && "Isn't a declgroup"); return *((DeclGroup*)(reinterpret_cast(D) & ~Mask)); @@ -96,7 +96,7 @@ public: const DeclGroup &getDeclGroup() const { return const_cast(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 1e4440357b655..79a0d368288c0 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 2fcdaa3e2959d..2b12bb5c1b6d2 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(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 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(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::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 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 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 + typedef filtered_decl_iterator 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 + typedef filtered_decl_iterator 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 /// { // 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 ReferencedProtocols; - + /// Instance variables in the interface. ObjCList 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 &getReferencedProtocols() const { - return ReferencedProtocols; + const ObjCList &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::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 @@ -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 anyObjectThatImplementsNSDraggingInfo; @@ -605,78 +653,83 @@ public: class ObjCProtocolDecl : public ObjCContainerDecl { /// Referenced protocols ObjCList 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 &getReferencedProtocols() const { + + const ObjCList &getReferencedProtocols() const { return ReferencedProtocols; } typedef ObjCList::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 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::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 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::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 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 &getReferencedProtocols() const { + + const ObjCList &getReferencedProtocols() const { return ReferencedProtocols; } - + typedef ObjCList::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 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 - 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 - 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(const_cast(D)); - } - static ObjCCategoryImplDecl *castFromDeclContext(const DeclContext *DC) { - return static_cast(const_cast(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 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(const_cast(D)); - } - static ObjCImplementationDecl *castFromDeclContext(const DeclContext *DC) { - return static_cast(const_cast(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 5d0fe158e054f..8d44676124fbc 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(this + 1); } + iterator begin() { return reinterpret_cast(this + 1); } const_iterator begin() const { - return reinterpret_cast(this + 1); + return reinterpret_cast(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(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(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(TypeOrValue)); + + return QualType::getFromOpaquePtr(reinterpret_cast(TypeOrValue)); } - + /// \brief Retrieve the template argument as a declaration. Decl *getAsDecl() const { if (Kind != Declaration) return 0; return reinterpret_cast(TypeOrValue); } - + /// \brief Retrieve the template argument as an integral value. llvm::APSInt *getAsIntegral() { if (Kind != Integral) return 0; return reinterpret_cast(&Integer.Value[0]); } - + const llvm::APSInt *getAsIntegral() const { return const_cast(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(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 FlatArguments; - + /// \brief The number of template arguments in this template /// argument list. unsigned NumFlatArguments; - + llvm::PointerIntPair 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 Template; - + /// The two bits are contain the top 4 values of TemplateSpecializationKind. + llvm::PointerIntPair 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 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 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 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 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(TemplatedDecl); @@ -585,7 +663,7 @@ public: llvm::FoldingSet &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(); } - + /// \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 + /// struct X { + /// template void f(); + /// }; + /// \endcode + /// + /// X::A is a CXXMethodDecl (whose parent is X, a + /// ClassTemplateSpecializationDecl) for which getPrimaryTemplate() will + /// return X::f, a FunctionTemplateDecl (whose parent is again + /// X) for which getInstantiatedFromMemberTemplate() will return + /// X::f, a FunctionTemplateDecl (whose parent is X, 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::f is a + /// member specialization. + /// + /// \code + /// template + /// struct X { + /// template void f(T, U); + /// }; + /// + /// template<> template + /// void X::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 class array; -/// -/// template<> +/// +/// template<> /// class array { }; // class template specialization array /// \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 + 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 + getInstantiatedFrom() const { + if (getSpecializationKind() != TSK_ImplicitInstantiation && + getSpecializationKind() != TSK_ExplicitInstantiationDefinition && + getSpecializationKind() != TSK_ExplicitInstantiationDeclaration) + return (ClassTemplateDecl*)0; + + if (SpecializedPartialSpecialization *PartialSpec + = SpecializedTemplate.dyn_cast()) + return PartialSpec->PartialSpecialization; + + return const_cast( + SpecializedTemplate.get()); + } + + /// \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()) + 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 Specializations; /// \brief The class template partial specializations for this class /// template. - llvm::FoldingSet + llvm::FoldingSet 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 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 + /// struct X { + /// template struct A {}; + /// }; + /// \endcode + /// + /// X::A is a ClassTemplateSpecializationDecl (whose parent + /// is X, also a CTSD) for which getSpecializedTemplate() will + /// return X::A, a TemplateClassDecl (whose parent is again + /// X) for which getInstantiatedFromMemberTemplate() will return + /// X::A, a TemplateClassDecl (whose parent is X, 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::Inner is a + /// member specialization. + /// + /// \code + /// template + /// struct X { + /// template struct Inner; + /// }; + /// + /// template<> template + /// struct X::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 class A { +/// friend class MyVector; // not a friend template +/// template friend class B; // friend template +/// template friend class Foo::Nested; // friend template +class FriendTemplateDecl : public Decl { +public: + typedef llvm::PointerUnion 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(); + } + + /// 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(); + } + + /// 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 db140999b0454..ed4ac6b5d4e74 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 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(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(Name)) { + DeclarationName(CXXSpecialName *Name) + : Ptr(reinterpret_cast(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(Name)) { + DeclarationName(CXXOperatorIdName *Name) + : Ptr(reinterpret_cast(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(II)) { + DeclarationName(const IdentifierInfo *II) + : Ptr(reinterpret_cast(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(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(Ptr); return 0; @@ -195,12 +197,18 @@ public: /// an opaque pointer. void *getAsOpaquePtr() const { return reinterpret_cast(Ptr); } + static DeclarationName getFromOpaquePtr(void *P) { + DeclarationName N; + N.Ptr = reinterpret_cast (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 { 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 6a1046e6d03fe..d5dff5065d49e 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 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 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 + /// template /// 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(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(this)->IgnoreParens(); } @@ -280,18 +306,18 @@ public: const Expr *IgnoreParenNoopCasts(ASTContext &Ctx) const { return const_cast(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(Val); } Expr *getSubExpr() { return cast(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(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(SubExprs[RHS]); } const Expr *getRHS() const { return cast(SubExprs[RHS]); } void setRHS(Expr *E) { SubExprs[RHS] = E; } - - Expr *getBase() { + + Expr *getBase() { return cast(getRHS()->getType()->isIntegerType() ? getLHS():getRHS()); } - - const Expr *getBase() const { + + const Expr *getBase() const { return cast(getRHS()->getType()->isIntegerType() ? getLHS():getRHS()); } - - Expr *getIdx() { + + Expr *getIdx() { return cast(getRHS()->getType()->isIntegerType() ? getRHS():getLHS()); } - + const Expr *getIdx() const { return cast(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(SubExprs[FN]); } Expr *getCallee() { return cast(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(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(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 "" in "sort". +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 (this + 1); + } + + /// \brief Retrieve the template arguments + const TemplateArgument *getTemplateArgs() const { + return reinterpret_cast (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. 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 (this + 1); + } + + /// \brief Retrieve the qualifier that preceded the member name, if any. + const NameQualifier *getMemberQualifier() const { + return const_cast(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(this + 1); + + return reinterpret_cast( + getMemberQualifier() + 1); + } + + /// \brief Retrieve the explicit template argument list that followed the + /// member template name, if any. + const ExplicitTemplateArgumentList *getExplicitTemplateArgumentList() const { + return const_cast(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(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. + 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(Op); } const Expr *getSubExpr() const { return cast(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(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(SubExprs[RHS]); } - + Expr *getLHS() const { return cast_or_null(SubExprs[LHS]); } void setLHS(Expr *E) { SubExprs[LHS] = E; } Expr *getRHS() const { return cast(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(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 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(InitExprs[Init]); } - - Expr* getInit(unsigned Init) { + + Expr* getInit(unsigned Init) { assert(Init < getNumInits() && "Initializer access out of range!"); return cast_or_null(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::iterator iterator; typedef std::vector::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(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(*const_cast(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(Exprs[Init]); + } + + Expr* getExpr(unsigned Init) { + assert(Init < getNumExprs() && "Initializer access out of range!"); + return cast_or_null(Exprs[Init]); + } + + Expr **getExprs() { return reinterpret_cast(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 &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 7d76a49d1267b..3f66b1f40bfcb 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(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(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(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(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(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(Args[Arg]); + } + const Expr *getArg(unsigned Arg) const { + assert(Arg < NumArgs && "Arg access out of range!"); + return cast(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(getDecl()); } const VarDecl *getVarDecl() const { return cast(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()->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 +/// 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(Base)), IsArrow(isArrow), + OperatorLoc(OperatorLoc), Qualifier(Qualifier), + QualifierRange(QualifierRange), DestroyedType(DestroyedType), + DestroyedTypeLoc(DestroyedTypeLoc) { } + + void setBase(Expr *E) { Base = E; } + Expr *getBase() const { return cast(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. +/// \brief An expression that refers to a C++ template-id, such as +/// @c isa. class TemplateIdRefExpr : public Expr { /// \brief If this template-id was qualified-id, e.g., @c std::sort, /// this nested name specifier contains the @c std::. NestedNameSpecifier *Qualifier; - + /// \brief If this template-id was a qualified-id, e.g., @c std::sort, /// 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, 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; 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. 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(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(SubExpr); } const Expr *getSubExpr() const { return cast(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(this + 1); + } + + /// \brief Retrieve the explicit template argument list that followed the + /// member template name, if any. + const ExplicitTemplateArgumentList *getExplicitTemplateArgumentList() const { + return const_cast(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. + 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 e00833b5820e5..0613f4c095f8e 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(String); } const StringLiteral *getString() const { return cast(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(Base); } Expr *getBase() { return cast(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(Base); } Expr *getBase() { return cast(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(Base); } Expr *getBase() { return cast_or_null(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(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 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(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 6f862a55d4bad..0670d1a620945 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 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 &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(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((Source->*Get)(Ptr >> 1)); } diff --git a/include/clang/AST/NestedNameSpecifier.h b/include/clang/AST/NestedNameSpecifier.h index b304cc8e8a042..1594b090fea5d 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(NNS), + Diagnostic::ak_nestednamespec); + return DB; +} + } #endif diff --git a/include/clang/AST/ParentMap.h b/include/clang/AST/ParentMap.h index c669991ccc088..f826e1117b66c 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(S)); } - + const Stmt *getParentIgnoreParens(const Stmt *S) const { return getParentIgnoreParens(const_cast(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(E)); } }; - + } // end clang namespace #endif diff --git a/include/clang/AST/PrettyPrinter.h b/include/clang/AST/PrettyPrinter.h index 6ad3a6bcc2763..0635ec5dcd51e 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 ab184563da23d..7490b1d66b3ea 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 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 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 *bases, + unsigned numbases, + const std::pair *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 0000000000000..458af1f14423d --- /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 +class Redeclarable { + +protected: + struct DeclLink : public llvm::PointerIntPair { + DeclLink(decl_type *D, bool isLatest) + : llvm::PointerIntPair(D, isLatest) { } + + typedef llvm::PointerIntPair 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); // + /// #2 int f(int x = 0, int y); // + /// #3 int f(int x, int y) { return x + y; } // + /// + /// If there is only one declaration, it is + DeclLink RedeclLink; + +public: + Redeclarable() : RedeclLink(LatestDeclLink(static_cast(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( + static_cast(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(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(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(this); + } + + // First one will point to this one as latest. + First->RedeclLink = LatestDeclLink(static_cast(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( + static_cast(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 0a64dafd4e2c8..411f215e912e1 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 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 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(this)->child_begin()); } - + const_child_iterator child_end() const { return const_child_iterator(const_cast(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(lhs); @@ -454,32 +498,32 @@ public: Expr *getRHS() { return reinterpret_cast(SubExprs[RHS]); } Stmt *getSubStmt() { return SubExprs[SUBSTMT]; } - const Expr *getLHS() const { - return reinterpret_cast(SubExprs[LHS]); + const Expr *getLHS() const { + return reinterpret_cast(SubExprs[LHS]); } - const Expr *getRHS() const { - return reinterpret_cast(SubExprs[RHS]); + const Expr *getRHS() const { + return reinterpret_cast(SubExprs[RHS]); } const Stmt *getSubStmt() const { return SubExprs[SUBSTMT]; } void setSubStmt(Stmt *S) { SubExprs[SUBSTMT] = S; } void setLHS(Expr *Val) { SubExprs[LHS] = reinterpret_cast(Val); } void setRHS(Expr *Val) { SubExprs[RHS] = reinterpret_cast(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(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(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(SubExprs[COND]);} void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast(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(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(cond); SubExprs[BODY] = body; - } + } /// \brief Build an empty do-while statement. explicit DoStmt(EmptyShell Empty) : Stmt(DoStmtClass, Empty) { } - + Expr *getCond() { return reinterpret_cast(SubExprs[COND]); } const Expr *getCond() const { return reinterpret_cast(SubExprs[COND]);} void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast(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(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(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 Names; llvm::SmallVector Constraints; llvm::SmallVector Exprs; llvm::SmallVector 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 &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(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(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 2338f1457a84d..28fe348c45913 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 1bfac6a9587e8..25d015287b757 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 struct GraphTraits; @@ -28,23 +28,23 @@ template <> struct GraphTraits { typedef clang::Stmt NodeType; typedef clang::Stmt::child_iterator ChildIteratorType; typedef llvm::df_iterator 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 { typedef const clang::Stmt NodeType; typedef clang::Stmt::const_child_iterator ChildIteratorType; typedef llvm::df_iterator 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 35bd5ada0256c..2d523fffce740 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 +#include 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(RawVAPtr & ~Flags); } - + void setVAPtr(VariableArrayType* P) { - assert (inDecl() || inDeclGroup() || inSizeOfTypeVA()); + assert (inDecl() || inDeclGroup() || inSizeOfTypeVA()); RawVAPtr = reinterpret_cast(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 -class StmtIteratorImpl : public StmtIteratorBase, +class StmtIteratorImpl : public StmtIteratorBase, public std::iterator { + 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(*this); } - + DERIVED operator++(int) { DERIVED tmp = static_cast(*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 { explicit StmtIterator() : StmtIteratorImpl() {} StmtIterator(Stmt** S) : StmtIteratorImpl(S) {} - StmtIterator(Decl** dgi, Decl** dge) + StmtIterator(Decl** dgi, Decl** dge) : StmtIteratorImpl(dgi, dge) {} StmtIterator(VariableArrayType* t):StmtIteratorImpl(t) {} @@ -133,10 +133,10 @@ struct StmtIterator : public StmtIteratorImpl { struct ConstStmtIterator : public StmtIteratorImpl { - explicit ConstStmtIterator() : + explicit ConstStmtIterator() : StmtIteratorImpl() {} - - ConstStmtIterator(const StmtIterator& RHS) : + + ConstStmtIterator(const StmtIterator& RHS) : StmtIteratorImpl(RHS) {} }; diff --git a/include/clang/AST/StmtNodes.def b/include/clang/AST/StmtNodes.def index a95a627311860..8d7e4b5fc0a3f 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 8ae707174403a..3fd8f1672deb2 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(SubExprs[COLLECTION]); + Expr *getCollection() { + return reinterpret_cast(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(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(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(SubExprs[NEXT_CATCH]); } - ObjCAtCatchStmt *getNextCatchStmt() { + ObjCAtCatchStmt *getNextCatchStmt() { return static_cast(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(SubStmts[CATCH]); + + const ObjCAtCatchStmt *getCatchStmts() const { + return dyn_cast_or_null(SubStmts[CATCH]); } - ObjCAtCatchStmt *getCatchStmts() { - return dyn_cast_or_null(SubStmts[CATCH]); + ObjCAtCatchStmt *getCatchStmts() { + return dyn_cast_or_null(SubStmts[CATCH]); } void setCatchStmts(Stmt *S) { SubStmts[CATCH] = S; } - - const ObjCAtFinallyStmt *getFinallyStmt() const { - return dyn_cast_or_null(SubStmts[FINALLY]); + + const ObjCAtFinallyStmt *getFinallyStmt() const { + return dyn_cast_or_null(SubStmts[FINALLY]); } - ObjCAtFinallyStmt *getFinallyStmt() { - return dyn_cast_or_null(SubStmts[FINALLY]); + ObjCAtFinallyStmt *getFinallyStmt() { + return dyn_cast_or_null(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(SubStmts[SYNC_BODY]); } - CompoundStmt *getSynchBody() { - return reinterpret_cast(SubStmts[SYNC_BODY]); + CompoundStmt *getSynchBody() { + return reinterpret_cast(SubStmts[SYNC_BODY]); } void setSynchBody(Stmt *S) { SubStmts[SYNC_BODY] = S; } - - const Expr *getSynchExpr() const { - return reinterpret_cast(SubStmts[SYNC_EXPR]); + + const Expr *getSynchExpr() const { + return reinterpret_cast(SubStmts[SYNC_EXPR]); } - Expr *getSynchExpr() { - return reinterpret_cast(SubStmts[SYNC_EXPR]); + Expr *getSynchExpr() { + return reinterpret_cast(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(Throw); } Expr *getThrowExpr() { return reinterpret_cast(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 4f4066ab86022..3a525507dad33 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(this)->Visit ## NAME(static_cast(S)) - + /// StmtVisitor - This class implements a simple visitor for Stmt subclasses. /// Since Expr derives from Stmt, this also includes support for visiting Exprs. template 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 511934c1dbf54..66ff34cf1e318 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 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 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(Template)) { } + + QualifiedTemplateName(NestedNameSpecifier *NNS, bool TemplateKeyword, + OverloadedFunctionDecl *Template) + : Qualifier(NNS, TemplateKeyword? 1 : 0), + Template(reinterpret_cast(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 a00c0c4ff1c4a..89776b91fe4a8 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 @@ -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 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, + Qualifiers::FastWidth> Value; + + bool hasExtQuals() const { + return Value.getPointer().is(); + } + + const ExtQuals *getExtQualsUnsafe() const { + return Value.getPointer().get(); + } + + const Type *getTypePtrUnsafe() const { + return Value.getPointer().get(); + } + + friend class QualifierCollector; +public: QualType() {} - + QualType(const Type *Ptr, unsigned Quals) - : Value(const_cast(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(getExtQualsUnsafe()->getBaseType()); + return const_cast(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; + } + + // Retrieves the CVR qualifiers of this type. + unsigned getCVRQualifiers() const { + unsigned CVR = getFastQualifiers(); + if (isVolatileQualified()) CVR |= Qualifiers::Volatile; + return CVR; + } + + bool isConstant(ASTContext& Ctx) const { + return QualType::isConstant(*this, Ctx); + } + + // 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); } - bool isConstant(ASTContext& Ctx) const; - - /// addConst/addVolatile/addRestrict - add the specified type qual to this - /// QualType. - void addConst() { Value.setInt(Value.getInt() | Const); } - void addVolatile() { Value.setInt(Value.getInt() | Volatile); } - void addRestrict() { Value.setInt(Value.getInt() | Restrict); } + void addFastQualifiers(unsigned TQs) { + assert(!(TQs & ~Qualifiers::FastMask) + && "non-fast qualifier bits set in mask!"); + Value.setInt(Value.getInt() | TQs); + } - void removeConst() { Value.setInt(Value.getInt() & ~Const); } - void removeVolatile() { Value.setInt(Value.getInt() & ~Volatile); } - void removeRestrict() { Value.setInt(Value.getInt() & ~Restrict); } + void removeConst(); + void removeVolatile(); + void removeRestrict(); + void removeCVRQualifiers(unsigned Mask); - QualType getQualifiedType(unsigned TQs) const { - return QualType(getTypePtr(), TQs); + 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; } - QualType getWithAdditionalQualifiers(unsigned TQs) const { - return QualType(getTypePtr(), TQs|getCVRQualifiers()); + + // 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 { }; template<> struct simplify_type< ::clang::QualType> : public simplify_type {}; - + // Teach SmallPtrSet that QualType is "basically a pointer". template<> class PointerLikeTypeTraits { @@ -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(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(); } + bool isFunctionProtoType() const { return getAs(); } 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 bool isObjCQualifiedInterfaceType() const; // NSString bool isObjCQualifiedIdType() const; // id + bool isObjCQualifiedClassType() const; // Class + 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'. This scheme will eventually + // replace the specific getAsXXXX methods above. + // + // There are some specializations of this member template listed + // immediately following this class. + template 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(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(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(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 +/// template /// 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; } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, Context, getElementType(), getSizeExpr()); } - static bool classof(const DependentSizedExtVectorType *) { return true; } + + 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(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(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(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(D), QualType()) { } friend class ASTContext; // ASTContext creates these. public: - + RecordDecl *getDecl() const { return reinterpret_cast(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(T) && classof(cast(T)); @@ -1453,11 +2091,14 @@ class EnumType : public TagType { : TagType(Enum, reinterpret_cast(D), QualType()) { } friend class ASTContext; // ASTContext creates these. public: - + EnumDecl *getDecl() const { return reinterpret_cast(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(T) && classof(cast(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 will refer to -/// a tag type for the instantiation +/// a tag type for the instantiation /// @c std::vector>. /// /// 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(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 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 *getIdentifier() const { + return Name.dyn_cast(); } /// \brief Retrieve the type named by the typename specifier as a @@ -1693,7 +2419,11 @@ public: return Name.dyn_cast(); } - 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". +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 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::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

    ', /// and 'Interface

    *'. /// /// 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 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(); + } + /// 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

    ". - bool isObjCQualifiedIdType() const { return Decl == 0 && Protocols.size(); } - + bool isObjCQualifiedIdType() const { + return getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCId) && + Protocols.size(); + } + /// isObjCQualifiedClassType - true for "Class

    ". + 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::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". 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::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. +/// \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 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::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(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(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(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(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(CT)) return AT->getElementType().getAddressSpace(); if (const RecordType *RT = dyn_cast(CT)) return RT->getAddressSpace(); - if (const ExtQualType *EXTQT = dyn_cast(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(CT)) return AT->getElementType().getObjCGCAttr(); - if (const ExtQualType *EXTQT = dyn_cast(CT)) - return EXTQT->getObjCGCAttr(); - if (const PointerType *PT = CT->getAsPointerType()) - return PT->getPointeeType().getObjCGCAttr(); - return GCNone; + if (const ObjCObjectPointerType *PT = CT->getAs()) + return PT->getPointeeType().getObjCGCAttr(); + // We most look at all pointer types, not just pointer to interface types. + if (const PointerType *PT = CT->getAs()) + 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()) { + if (const FunctionType *FT = PT->getPointeeType()->getAs()) + return FT->getNoReturnAttr(); + } else if (const FunctionType *FT = getTypePtr()->getAs()) + 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()) return RefType->getPointeeType(); else return *this; } -inline const TypedefType* Type::getAsTypedefType() const { - return dyn_cast(this); -} inline const ObjCInterfaceType *Type::getAsPointerToObjCInterfaceType() const { - if (const PointerType *PT = getAsPointerType()) - return PT->getPointeeType()->getAsObjCInterfaceType(); + if (const PointerType *PT = getAs()) + return PT->getPointeeType()->getAs(); return 0; } - + // NOTE: All of these methods use "getUnqualifiedType" to strip off address // space qualifiers if present. inline bool Type::isFunctionType() const { return isa(CanonicalType.getUnqualifiedType()); } inline bool Type::isPointerType() const { - return isa(CanonicalType.getUnqualifiedType()); + return isa(CanonicalType.getUnqualifiedType()); +} +inline bool Type::isAnyPointerType() const { + return isPointerType() || isObjCObjectPointerType(); } inline bool Type::isBlockPointerType() const { - return isa(CanonicalType.getUnqualifiedType()); + return isa(CanonicalType.getUnqualifiedType()); } inline bool Type::isReferenceType() const { return isa(CanonicalType.getUnqualifiedType()); @@ -1961,7 +2811,7 @@ inline bool Type::isRValueReferenceType() const { return isa(CanonicalType.getUnqualifiedType()); } inline bool Type::isFunctionPointerType() const { - if (const PointerType* T = getAsPointerType()) + if (const PointerType* T = getAs()) return T->getPointeeType()->isFunctionType(); else return false; @@ -1970,7 +2820,7 @@ inline bool Type::isMemberPointerType() const { return isa(CanonicalType.getUnqualifiedType()); } inline bool Type::isMemberFunctionPointerType() const { - if (const MemberPointerType* T = getAsMemberPointerType()) + if (const MemberPointerType* T = getAs()) return T->getPointeeType()->isFunctionType(); else return false; @@ -2008,21 +2858,35 @@ inline bool Type::isObjCObjectPointerType() const { inline bool Type::isObjCInterfaceType() const { return isa(CanonicalType.getUnqualifiedType()); } -inline bool Type::isObjCQualifiedInterfaceType() const { - return isa(CanonicalType.getUnqualifiedType()); -} inline bool Type::isObjCQualifiedIdType() const { - if (const ObjCObjectPointerType *OPT = getAsObjCObjectPointerType()) { + if (const ObjCObjectPointerType *OPT = getAs()) return OPT->isObjCQualifiedIdType(); - } return false; } +inline bool Type::isObjCQualifiedClassType() const { + if (const ObjCObjectPointerType *OPT = getAs()) + return OPT->isObjCQualifiedClassType(); + return false; +} +inline bool Type::isObjCIdType() const { + if (const ObjCObjectPointerType *OPT = getAs()) + return OPT->isObjCIdType(); + return false; +} +inline bool Type::isObjCClassType() const { + if (const ObjCObjectPointerType *OPT = getAs()) + return OPT->isObjCClassType(); + return false; +} +inline bool Type::isObjCBuiltinType() const { + return isObjCIdType() || isObjCClassType(); +} inline bool Type::isTemplateTypeParmType() const { return isa(CanonicalType.getUnqualifiedType()); } inline bool Type::isSpecificBuiltinType(unsigned K) const { - if (const BuiltinType *BT = getAsBuiltinType()) + if (const BuiltinType *BT = getAs()) 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'. +template const T *Type::getAs() const { + // If this is directly a T type, return it. + if (const T *Ty = dyn_cast(this)) + return Ty; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa(CanonicalType)) + return 0; + + // If this is a typedef for the type, strip the typedef off without + // losing all typedef information. + return cast(getUnqualifiedDesugaredType()); +} + } // end namespace clang #endif diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h new file mode 100644 index 0000000000000..a6184375e0957 --- /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(Data)->StartLoc; + } + void setStartLoc(SourceLocation Loc) { + static_cast(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(Data)->NameLoc; + } + void setNameLoc(SourceLocation Loc) { + static_cast(Data)->NameLoc = Loc; + } + SourceRange getSourceRange() const { + return SourceRange(getNameLoc(), getNameLoc()); + } + + TypedefDecl *getTypedefDecl() const { + return cast(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(Data)->NameLoc; + } + void setNameLoc(SourceLocation Loc) { + static_cast(Data)->NameLoc = Loc; + } + SourceRange getSourceRange() const { + return SourceRange(getNameLoc(), getNameLoc()); + } + + ObjCInterfaceDecl *getIFaceDecl() const { + return cast(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(static_cast(Data) + 1); + } + +public: + SourceLocation getLAngleLoc() const { + return static_cast(Data)->LAngleLoc; + } + void setLAngleLoc(SourceLocation Loc) { + static_cast(Data)->LAngleLoc = Loc; + } + + SourceLocation getRAngleLoc() const { + return static_cast(Data)->RAngleLoc; + } + void setRAngleLoc(SourceLocation Loc) { + static_cast(Data)->RAngleLoc = Loc; + } + + unsigned getNumProtocols() const { + return cast(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(Ty)->qual_begin() + i); + } + + TypeLoc getBaseTypeLoc() const { + void *Next = static_cast(Data) + getLocalDataSize(); + return TypeLoc(cast(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(Data)->StarLoc; + } + void setStarLoc(SourceLocation Loc) { + static_cast(Data)->StarLoc = Loc; + } + + TypeLoc getPointeeLoc() const { + void *Next = static_cast(Data) + getLocalDataSize(); + return TypeLoc(cast(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(Data)->CaretLoc; + } + void setCaretLoc(SourceLocation Loc) { + static_cast(Data)->CaretLoc = Loc; + } + + TypeLoc getPointeeLoc() const { + void *Next = static_cast(Data) + getLocalDataSize(); + return TypeLoc(cast(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(Data)->StarLoc; + } + void setStarLoc(SourceLocation Loc) { + static_cast(Data)->StarLoc = Loc; + } + + TypeLoc getPointeeLoc() const { + void *Next = static_cast(Data) + getLocalDataSize(); + return TypeLoc(cast(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(Data)->AmpLoc; + } + void setAmpLoc(SourceLocation Loc) { + static_cast(Data)->AmpLoc = Loc; + } + + TypeLoc getPointeeLoc() const { + void *Next = static_cast(Data) + getLocalDataSize(); + return TypeLoc(cast(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(static_cast(Data) + 1); + } + +public: + SourceLocation getLParenLoc() const { + return static_cast(Data)->LParenLoc; + } + void setLParenLoc(SourceLocation Loc) { + static_cast(Data)->LParenLoc = Loc; + } + + SourceLocation getRParenLoc() const { + return static_cast(Data)->RParenLoc; + } + void setRParenLoc(SourceLocation Loc) { + static_cast(Data)->RParenLoc = Loc; + } + + unsigned getNumArgs() const { + if (isa(Ty)) + return 0; + return cast(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(Data) + getLocalDataSize(); + return TypeLoc(cast(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(Data)->LBracketLoc; + } + void setLBracketLoc(SourceLocation Loc) { + static_cast(Data)->LBracketLoc = Loc; + } + + SourceLocation getRBracketLoc() const { + return static_cast(Data)->RBracketLoc; + } + void setRBracketLoc(SourceLocation Loc) { + static_cast(Data)->RBracketLoc = Loc; + } + + Expr *getSizeExpr() const { + return static_cast(Data)->Size; + } + void setSizeExpr(Expr *Size) { + static_cast(Data)->Size = Size; + } + + TypeLoc getElementLoc() const { + void *Next = static_cast(Data) + getLocalDataSize(); + return TypeLoc(cast(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 0000000000000..107ea85479f9f --- /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 0000000000000..df386cab6f423 --- /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(this)->Visit ## CLASS(cast(TyLoc)) + +template +class TypeLocVisitor { + class TypeDispatch : public TypeVisitor { + 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(TyLoc)); \ + } +#include "clang/AST/TypeLocNodes.def" + }; + +public: + RetTy Visit(TypeLoc TyLoc) { + TypeDispatch TD(static_cast(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 64a09d8002707..6c6bd20e85283 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 4f60273d68095..652f4f70bd16d 100644 --- a/include/clang/AST/TypeOrdering.h +++ b/include/clang/AST/TypeOrdering.h @@ -37,7 +37,7 @@ namespace llvm { template<> struct DenseMapInfo { 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(-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 a02e39b3f34e5..19f7f42a897a8 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(this)->Visit ## CLASS(static_cast(T)) - + template 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 b41cd684e951c..17f772da0c6da 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 { - - + + 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 7a9da03e4bd28..8a967c3f6edce 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 { +class UninitializedValues : + public DataflowValues { 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 3ee733518595b..114ae74b0c061 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 0000000000000..e6f4cf961be07 --- /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 + +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 ImplTy; + ImplTy Impl; + public: + StatementList(BumpVectorContext &C) : Impl(C, 4) {} + + typedef std::reverse_iterator iterator; + typedef std::reverse_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 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(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 CFGBlockListTy; + typedef CFGBlockListTy::iterator iterator; + typedef CFGBlockListTy::const_iterator const_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_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 + 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 { + 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 { + 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 > { + typedef const clang::CFGBlock NodeType; + typedef clang::CFGBlock::const_pred_iterator ChildIteratorType; + + static NodeType *getEntryNode(Inverse 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 + : public GraphTraits { + + 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 > + : public GraphTraits > { + + 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 0000000000000..fabeea38d597a --- /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 +#include + +namespace clang { + +class CallGraphNode { + idx::Entity F; + typedef std::pair CallRecord; + std::vector CalledFunctions; + +public: + CallGraphNode(idx::Entity f) : F(f) {} + + typedef std::vector::iterator iterator; + typedef std::vector::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 FunctionMapTy; + + /// FunctionMap owns all CallGraphNodes. + FunctionMapTy FunctionMap; + + /// CallerCtx maps a caller to its ASTContext. + llvm::DenseMap 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 { + typedef clang::CallGraph GraphType; + typedef clang::CallGraphNode NodeType; + + typedef std::pair CGNPairTy; + typedef std::pointer_to_unary_function CGNDerefFun; + + typedef mapped_iterator 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 PairTy; + typedef std::pointer_to_unary_function DerefFun; + + typedef mapped_iterator 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 38612593368b6..f505bca9519cf 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 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 { 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 { 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 { //===----------------------------------------------------------------------===// /// DataflowSolverTy - Generic dataflow solver. //===----------------------------------------------------------------------===// - + template 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(B)); + + TF.VisitTerminator(const_cast(B)); } - + void ProcessBlock(const CFGBlock* B, bool recordStmtValues, dataflow::backward_analysis_tag) { - + TF.VisitTerminator(const_cast(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(S)); + TF.BlockStmt_Visit(const_cast(S)); } - + void ProcessStmt(const Stmt* S, bool record, dataflow::backward_analysis_tag){ TF.BlockStmt_Visit(const_cast(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 d6427a5cab474..648fe33ab0d49 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 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 EdgeDataMapTy; typedef llvm::DenseMap 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(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(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(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(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 9ff3f52f89aac..1da15fbae6c4c 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 994b35e5efdac..a08afe2bb90be 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 #include @@ -24,12 +25,17 @@ #include 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 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 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::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::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 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::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::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 path; unsigned Size; std::string BugType; std::string Desc; std::string Category; std::deque 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::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::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::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 reverse_iterator; typedef std::reverse_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 0000000000000..ffe282d3caa39 --- /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 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 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 0000000000000..e97f80576a8bd --- /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 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 b694e9b299408..12f0ce2d50b7c 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 L; public: - CompoundValData(QualType t, llvm::ImmutableList l) + CompoundValData(QualType t, llvm::ImmutableList l) : T(t), L(l) {} typedef llvm::ImmutableList::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 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 > APSIntSetTy; @@ -56,44 +74,54 @@ class BasicValueFactory { llvm::ImmutableList::Factory SValListFactory; llvm::FoldingSet CompoundValDataSet; + llvm::FoldingSet 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 Vals); - + + const LazyCompoundValData *getLazyCompoundValData(const GRState *state, + const TypedRegion *region); + llvm::ImmutableList getEmptySValList() { return SValListFactory.GetEmptyList(); } - + llvm::ImmutableList consVals(SVal X, llvm::ImmutableList 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& getPersistentSValWithData(const SVal& V, uintptr_t Data); - + const std::pair& - 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 90fd9d8ebf45e..1434fce811d15 100644 --- a/include/clang/Analysis/PathSensitive/BugReporter.h +++ b/include/clang/Analysis/PathSensitive/BugReporter.h @@ -27,7 +27,7 @@ #include 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* N, - const ExplodedNode* 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 *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* - getOriginalNode(const ExplodedNode* N) = 0; + virtual const ExplodedNode* + getOriginalNode(const ExplodedNode* N) = 0; }; - - BugReport(BugType& bt, const char* desc, const ExplodedNode *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 *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* 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 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* 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* N, - const ExplodedNode* PrevN, + virtual PathDiagnosticPiece* VisitNode(const ExplodedNode* N, + const ExplodedNode* PrevN, BugReporterContext& BR); - + virtual void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N) {} + const ExplodedNode* N) {} }; //===----------------------------------------------------------------------===// // BugTypes (collections of related reports). //===----------------------------------------------------------------------===// - + class BugReportEquivClass : public llvm::FoldingSetNode { // List of *owned* BugReport objects. std::list 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::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 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::iterator iterator; iterator begin() { return EQClasses.begin(); } iterator end() { return EQClasses.end(); } - + typedef llvm::FoldingSet::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 Ranges; public: - RangedBugReport(BugType& D, const char* description, ExplodedNode *n) + RangedBugReport(BugType& D, const char* description, ExplodedNode *n) : BugReport(D, description, n) {} - + RangedBugReport(BugType& D, const char *shortDescription, - const char *description, ExplodedNode *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 > 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 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& 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 Callbacks; public: BugReporterContext(GRBugReporter& br) : BR(br) {} virtual ~BugReporterContext(); - + void addVisitor(BugReporterVisitor* visitor) { if (visitor) Callbacks.push_back(visitor); } - + typedef std::vector::iterator visitor_iterator; visitor_iterator visitor_begin() { return Callbacks.begin(); } - visitor_iterator visitor_end() { return Callbacks.end(); } - - GRBugReporter& getBugReporter() { return BR; } - - ExplodedGraph& 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::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 0000000000000..4e00d69cdba1c --- /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 OldSink; + SaveAndRestore OldTag; + SaveAndRestore 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 0000000000000..ff6528dae8f56 --- /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 0000000000000..e74f49c9a761f --- /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 +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(this)->PreVisitBinaryOperator(C, + static_cast(S)); + break; +#define PREVISIT(NAME) \ +case Stmt::NAME ## Class:\ +static_cast(this)->PreVisit ## NAME(C,static_cast(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 689bebb450f44..37a14083ac558 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 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 6f8a126427699..6d5c5678e59b1 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 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(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& 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& RegionRoots); }; - + } // end clang namespace #endif diff --git a/include/clang/Analysis/PathSensitive/ExplodedGraph.h b/include/clang/Analysis/PathSensitive/ExplodedGraph.h index 8494d935650d0..a7bbdf939f877 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(P & ~Mask); } - ExplodedNodeImpl* getNode() const { - return reinterpret_cast(getPtr()); + ExplodedNode *getNode() const { + return reinterpret_cast(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 - const T* getLocationAs() const { return llvm::dyn_cast(&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 -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 -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(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 + const T* getLocationAs() const { return llvm::dyn_cast(&Location); } + + static void Profile(llvm::FoldingSetNodeID &ID, + const ProgramPoint& Loc, const GRState* state) { ID.Add(Loc); - GRTrait::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(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(this)->pred_begin(); - } + } const_pred_iterator pred_end() const { return const_cast(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(this)->succ_begin(); @@ -219,23 +185,40 @@ public: const_succ_iterator succ_end() const { return const_cast(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 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 RootsTy; - typedef llvm::SmallVector EndNodesTy; - + typedef llvm::SmallVector RootsTy; + typedef llvm::SmallVector 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 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(&CodeDecl); - } - - typedef llvm::DenseMap NodeMap; - - ExplodedGraphImpl* Trim(const ExplodedNodeImpl* const * NBeg, - const ExplodedNodeImpl* const * NEnd, - InterExplodedGraphMapImpl *M, - llvm::DenseMap *InverseMap) - const; -}; - -class InterExplodedGraphMapImpl { - llvm::DenseMap 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 -class InterExplodedGraphMap : public InterExplodedGraphMapImpl { -public: - InterExplodedGraphMap() {}; - ~InterExplodedGraphMap() {}; - ExplodedNode* getMappedNode(const ExplodedNode* N) const { - return static_cast*>(getMappedImplNode(N)); - } -}; - -template -class ExplodedGraph : public ExplodedGraphImpl { -public: - typedef STATE StateTy; - typedef ExplodedNode NodeTy; - typedef llvm::FoldingSet 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(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(); - 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 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.begin()); - } - - roots_iterator roots_end() { - return reinterpret_cast(Roots.end()); - } - - const_roots_iterator roots_begin() const { - return const_cast(this)->roots_begin(); - } - - const_roots_iterator roots_end() const { - return const_cast(this)->roots_end(); - } + node_iterator nodes_begin() { return Nodes.begin(); } - eop_iterator eop_begin() { - return reinterpret_cast(EndNodes.begin()); - } - - eop_iterator eop_end() { - return reinterpret_cast(EndNodes.end()); - } - - const_eop_iterator eop_begin() const { - return const_cast(this)->eop_begin(); - } - - const_eop_iterator eop_end() const { - return const_cast(this)->eop_end(); - } - - std::pair*> + 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 NodeMap; + + std::pair Trim(const NodeTy* const* NBeg, const NodeTy* const* NEnd, - llvm::DenseMap *InverseMap = 0) const { - - if (NBeg == NEnd) - return std::make_pair((ExplodedGraph*) 0, - (InterExplodedGraphMap*) 0); - - assert (NBeg < NEnd); - - const ExplodedNodeImpl* const* NBegImpl = - (const ExplodedNodeImpl* const*) NBeg; - const ExplodedNodeImpl* const* NEndImpl = - (const ExplodedNodeImpl* const*) NEnd; - - llvm::OwningPtr > - M(new InterExplodedGraphMap()); - - ExplodedGraphImpl* G = ExplodedGraphImpl::Trim(NBegImpl, NEndImpl, M.get(), - InverseMap); - - return std::make_pair(static_cast(G), M.take()); - } + llvm::DenseMap *InverseMap = 0) const; + + ExplodedGraph* TrimInternal(const ExplodedNode* const * NBeg, + const ExplodedNode* const * NEnd, + InterExplodedGraphMap *M, + llvm::DenseMap *InverseMap) const; }; -template class ExplodedNodeSet { - - typedef ExplodedNode NodeTy; - typedef llvm::SmallPtrSet ImplTy; + typedef llvm::SmallPtrSet ImplTy; ImplTy Impl; - + public: - ExplodedNodeSet(NodeTy* N) { - assert (N && !static_cast(N)->isSink()); + ExplodedNodeSet(ExplodedNode* N) { + assert (N && !static_cast(N)->isSink()); Impl.insert(N); } - + ExplodedNodeSet() {} - - inline void Add(NodeTy* N) { - if (N && !static_cast(N)->isSink()) Impl.insert(N); + + inline void Add(ExplodedNode* N) { + if (N && !static_cast(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 - struct GraphTraits*> { - typedef clang::ExplodedNode NodeType; - typedef typename NodeType::succ_iterator ChildIteratorType; + template<> struct GraphTraits { + typedef clang::ExplodedNode NodeType; + typedef NodeType::succ_iterator ChildIteratorType; typedef llvm::df_iterator 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 - struct GraphTraits*> { - typedef const clang::ExplodedNode NodeType; - typedef typename NodeType::succ_iterator ChildIteratorType; + + template<> struct GraphTraits { + typedef const clang::ExplodedNode NodeType; + typedef NodeType::const_succ_iterator ChildIteratorType; typedef llvm::df_iterator 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 eca591d4af0ec..015c82e80bb59 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 + +class ExplodedNode; +class GRStateManager; + class GRAuditor { public: - typedef ExplodedNode 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 b4fd2704b81a6..67ed9532db02b 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 0fbdbde55bd5c..02e0b0275e4e0 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 G; - + llvm::OwningPtr 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 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 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 -class GRStmtNodeBuilder { -public: - typedef STATE StateTy; - typedef typename StateTy::ManagerTy StateManagerTy; - typedef ExplodedNode NodeTy; - -private: - GRStmtNodeBuilderImpl& NB; - StateManagerTy& Mgr; - const StateTy* CleanedState; - GRAuditor* 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* A) { - Auditor = A; - } - - NodeTy* getLastNode() const { - return static_cast(NB.getLastNode()); - } - - NodeTy* generateNode(PostStmt PP, const StateTy* St, NodeTy* Pred) { - HasGeneratedNode = true; - return static_cast(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(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(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& 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& 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& 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 DeferredTy; + typedef llvm::SmallVector 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 -class GRBranchNodeBuilder { - typedef STATE StateTy; - typedef ExplodedGraph GraphTy; - typedef typename GraphTy::NodeTy NodeTy; - - GRBranchNodeBuilderImpl& NB; - -public: - GRBranchNodeBuilder(GRBranchNodeBuilderImpl& nb) : NB(nb) {} - - const GraphTy& getGraph() const { - return static_cast(NB.getGraph()); - } - - NodeTy* getPredecessor() const { - return static_cast(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(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((*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 -class GRIndirectGotoNodeBuilder { - typedef STATE StateTy; - typedef ExplodedGraph 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(NB.generateNodeImpl(I, St, isSink)); - } - - const StateTy* getState() const { - return static_cast(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((*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 -class GRSwitchNodeBuilder { - typedef STATE StateTy; - typedef ExplodedGraph 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(NB.generateCaseStmtNodeImpl(I, St)); - } - - NodeTy* generateDefaultCaseNode(const StateTy* St, bool isSink = false) { - return static_cast(NB.generateDefaultCaseNodeImpl(St, isSink)); - } - - const StateTy* getState() const { - return static_cast(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 -class GREndPathNodeBuilder { - typedef STATE StateTy; - typedef ExplodedNode NodeTy; - - GREndPathNodeBuilderImpl& NB; - -public: - GREndPathNodeBuilder(GREndPathNodeBuilderImpl& nb) : NB(nb) {} - - NodeTy* getPredecessor() const { - return static_cast(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(NB.generateNodeImpl(St, tag)); + return Eng.WList->getBlockCounter(); } - - NodeTy *generateNode(const StateTy *St, NodeTy *Pred, const void *tag = 0) { - return static_cast(NB.generateNodeImpl(St, tag, Pred)); - } -}; - -template -class GRCoreEngine : public GRCoreEngineImpl { -public: - typedef SUBENGINE SubEngineTy; - typedef typename SubEngineTy::StateTy StateTy; - typedef typename StateTy::ManagerTy StateManagerTy; - typedef ExplodedGraph GraphTy; - typedef typename GraphTy::NodeTy NodeTy; - -protected: - SubEngineTy& SubEngine; - - virtual const void* getInitialState() { - return SubEngine.getInitialState(); - } - - virtual void ProcessEndPath(GREndPathNodeBuilderImpl& BuilderImpl) { - GREndPathNodeBuilder Builder(BuilderImpl); - SubEngine.ProcessEndPath(Builder); - } - - virtual void ProcessStmt(Stmt* S, GRStmtNodeBuilderImpl& BuilderImpl) { - GRStmtNodeBuilder Builder(BuilderImpl,SubEngine.getStateManager()); - SubEngine.ProcessStmt(S, Builder); - } - - virtual bool ProcessBlockEntrance(CFGBlock* Blk, const void* State, - GRBlockCounter BC) { - return SubEngine.ProcessBlockEntrance(Blk, - static_cast(State), - BC); + unsigned getCurrentBlockCount() const { + return getBlockCounter().getNumVisited(B.getBlockID()); } - virtual void ProcessBranch(Stmt* Condition, Stmt* Terminator, - GRBranchNodeBuilderImpl& BuilderImpl) { - GRBranchNodeBuilder Builder(BuilderImpl); - SubEngine.ProcessBranch(Condition, Terminator, Builder); - } - - virtual void ProcessIndirectGoto(GRIndirectGotoNodeBuilderImpl& BuilderImpl) { - GRIndirectGotoNodeBuilder Builder(BuilderImpl); - SubEngine.ProcessIndirectGoto(Builder); - } - - virtual void ProcessSwitch(GRSwitchNodeBuilderImpl& BuilderImpl) { - GRSwitchNodeBuilder 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(G.get()); - } - - /// takeGraph - Returns the exploded graph. Ownership of the graph is - /// transfered to the caller. - GraphTy* takeGraph() { - return static_cast(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 f05bc680a7e25..e5c61e68c77c1 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 GraphTy; - typedef GraphTy::NodeTy NodeTy; - - // Builders. - typedef GRStmtNodeBuilder StmtNodeBuilder; - typedef GRBranchNodeBuilder BranchNodeBuilder; - typedef GRIndirectGotoNodeBuilder IndirectGotoNodeBuilder; - typedef GRSwitchNodeBuilder SwitchNodeBuilder; - typedef GREndPathNodeBuilder EndPathNodeBuilder; - typedef ExplodedNodeSet NodeSet; - -protected: - GRCoreEngine 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 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 BatchAuditor; + std::vector 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 ErrorNodes; - typedef llvm::DenseMap UndefArgsTy; - + typedef llvm::SmallPtrSet ErrorNodes; + typedef llvm::DenseMap 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(N)) != 0; - } - - bool isUndefControlFlow(const NodeTy* N) const { - return N->isSink() && UndefBranches.count(const_cast(N)) != 0; + + void registerCheck(Checker *check) { + Checkers.push_back(check); } - - bool isUndefStore(const NodeTy* N) const { - return N->isSink() && UndefStores.count(const_cast(N)) != 0; + + bool isRetStackAddr(const ExplodedNode* N) const { + return N->isSink() && RetsStackAddr.count(const_cast(N)) != 0; } - - bool isImplicitNullDeref(const NodeTy* N) const { - return N->isSink() && ImplicitNullDeref.count(const_cast(N)) != 0; + + bool isUndefControlFlow(const ExplodedNode* N) const { + return N->isSink() && UndefBranches.count(const_cast(N)) != 0; } - - bool isExplicitNullDeref(const NodeTy* N) const { - return N->isSink() && ExplicitNullDeref.count(const_cast(N)) != 0; + + bool isUndefStore(const ExplodedNode* N) const { + return N->isSink() && UndefStores.count(const_cast(N)) != 0; } - - bool isUndefDeref(const NodeTy* N) const { - return N->isSink() && UndefDeref.count(const_cast(N)) != 0; + + bool isImplicitNullDeref(const ExplodedNode* N) const { + return N->isSink() && ImplicitNullDeref.count(const_cast(N)) != 0; } - - bool isImplicitBadDivide(const NodeTy* N) const { - return N->isSink() && ImplicitBadDivides.count(const_cast(N)) != 0; + + bool isExplicitNullDeref(const ExplodedNode* N) const { + return N->isSink() && ExplicitNullDeref.count(const_cast(N)) != 0; } - - bool isExplicitBadDivide(const NodeTy* N) const { - return N->isSink() && ExplicitBadDivides.count(const_cast(N)) != 0; + + bool isUndefDeref(const ExplodedNode* N) const { + return N->isSink() && UndefDeref.count(const_cast(N)) != 0; } - - bool isNoReturnCall(const NodeTy* N) const { - return N->isSink() && NoReturnCalls.count(const_cast(N)) != 0; + + bool isNoReturnCall(const ExplodedNode* N) const { + return N->isSink() && NoReturnCalls.count(const_cast(N)) != 0; } - - bool isUndefResult(const NodeTy* N) const { - return N->isSink() && UndefResults.count(const_cast(N)) != 0; + + bool isUndefResult(const ExplodedNode* N) const { + return N->isSink() && UndefResults.count(const_cast(N)) != 0; } - - bool isBadCall(const NodeTy* N) const { - return N->isSink() && BadCalls.count(const_cast(N)) != 0; + + bool isBadCall(const ExplodedNode* N) const { + return N->isSink() && BadCalls.count(const_cast(N)) != 0; } - - bool isUndefArg(const NodeTy* N) const { + + bool isUndefArg(const ExplodedNode* N) const { return N->isSink() && - (UndefArgs.find(const_cast(N)) != UndefArgs.end() || - MsgExprUndefArgs.find(const_cast(N)) != MsgExprUndefArgs.end()); + (UndefArgs.find(const_cast(N)) != UndefArgs.end() || + MsgExprUndefArgs.find(const_cast(N)) != MsgExprUndefArgs.end()); } - - bool isUndefReceiver(const NodeTy* N) const { - return N->isSink() && UndefReceivers.count(const_cast(N)) != 0; + + bool isUndefReceiver(const ExplodedNode* N) const { + return N->isSink() && UndefReceivers.count(const_cast(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(X)) - return SVator->EvalCast(cast(X), CastT); - else - return SVator->EvalCast(cast(X), CastT); - } - + void EvalEagerlyAssume(ExplodedNodeSet& Dst, ExplodedNodeSet& Src, Expr *Ex); + SVal EvalMinus(SVal X) { - return X.isValid() ? SVator->EvalMinus(cast(X)) : X; + return X.isValid() ? SVator.EvalMinus(cast(X)) : X; } - + SVal EvalComplement(SVal X) { - return X.isValid() ? SVator->EvalComplement(cast(X)) : X; + return X.isValid() ? SVator.EvalComplement(cast(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(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(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 0f3a1372a0f04..60db406cd13df 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 -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), 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), Pred, state); - } + + ExplodedNode* MakeNode(const GRState* state) { + return B.MakeNode(Dst, const_cast(stmt), Pred, state); + } }; } // end clang namespace diff --git a/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h b/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h index e54b31dfe883b..978ff0889e64c 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 class ExplodedGraph; - - -class GRSimpleAPICheck : public GRAuditor { +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 0da8f5243e9c3..d8b9d560ccd85 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 struct GRStatePartialTrait; template 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 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 IntSetTy; - typedef llvm::ImmutableMap GenericDataMap; - - typedef GRStateManager ManagerTy; - + typedef llvm::ImmutableMap 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 CB scanReachableSymbols(SVal val) const; - + //==---------------------------------------------------------------------==// // Accessing the Generic Data Map (GDM). //==---------------------------------------------------------------------==// void* const* FindGDM(void* K) const; - + template const GRState *add(typename GRStateTrait::key_type K) const; @@ -285,31 +280,31 @@ public: get() const { return GRStateTrait::MakeData(FindGDM(GRStateTrait::GDMIndex())); } - + template typename GRStateTrait::lookup_type get(typename GRStateTrait::key_type key) const { void* const* d = FindGDM(GRStateTrait::GDMIndex()); return GRStateTrait::Lookup(GRStateTrait::MakeData(d), key); } - + template typename GRStateTrait::context_type get_context() const; - - + + template const GRState *remove(typename GRStateTrait::key_type K) const; template const GRState *remove(typename GRStateTrait::key_type K, typename GRStateTrait::context_type C) const; - + template const GRState *set(typename GRStateTrait::data_type D) const; - + template const GRState *set(typename GRStateTrait::key_type K, - typename GRStateTrait::value_type E) const; + typename GRStateTrait::value_type E) const; template const GRState *set(typename GRStateTrait::key_type K, @@ -321,7 +316,7 @@ public: void* const* d = FindGDM(GRStateTrait::GDMIndex()); return GRStateTrait::Contains(GRStateTrait::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 { - 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 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 StoreMgr; llvm::OwningPtr ConstraintMgr; - GRState::IntSetTy::Factory ISetFactory; - + GRState::GenericDataMap::Factory GDMFactory; - + typedef llvm::DenseMap > GDMContextsTy; GDMContextsTy GDMContexts; - + /// Printers - A set of printer objects used for pretty-printing a GRState. /// GRStateManager owns these objects. std::vector Printers; - + /// StateSet - FoldingSet containing all the states created for analyzing /// a particular function. This is used to unique states. llvm::FoldingSet 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 class // to resolve keys into the GDM and to return data values to clients. // - - // Trait based GDM dispatch. + + // Trait based GDM dispatch. template const GRState* set(const GRState* st, typename GRStateTrait::data_type D) { return addGDM(st, GRStateTrait::GDMIndex(), GRStateTrait::MakeVoidPtr(D)); } - + template const GRState* set(const GRState* st, typename GRStateTrait::key_type K, typename GRStateTrait::value_type V, typename GRStateTrait::context_type C) { - - return addGDM(st, GRStateTrait::GDMIndex(), + + return addGDM(st, GRStateTrait::GDMIndex(), GRStateTrait::MakeVoidPtr(GRStateTrait::Set(st->get(), K, V, C))); } @@ -575,22 +535,22 @@ public: const GRState* remove(const GRState* st, typename GRStateTrait::key_type K, typename GRStateTrait::context_type C) { - - return addGDM(st, GRStateTrait::GDMIndex(), + + return addGDM(st, GRStateTrait::GDMIndex(), GRStateTrait::MakeVoidPtr(GRStateTrait::Remove(st->get(), K, C))); } - + void* FindGDMContext(void* index, void* (*CreateContext)(llvm::BumpPtrAllocator&), void (*DeleteContext)(void*)); - + template typename GRStateTrait::context_type get_context() { void* p = FindGDMContext(GRStateTrait::GDMIndex(), GRStateTrait::CreateContext, GRStateTrait::DeleteContext); - + return GRStateTrait::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(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(Idx), + cast(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(LV) ? this : bindLoc(cast(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 const GRState *GRState::add(typename GRStateTrait::key_type K) const { - return Mgr->add(this, K, get_context()); + return getStateManager().add(this, K, get_context()); } - + template typename GRStateTrait::context_type GRState::get_context() const { - return Mgr->get_context(); + return getStateManager().get_context(); } - + template const GRState *GRState::remove(typename GRStateTrait::key_type K) const { - return Mgr->remove(this, K, get_context()); + return getStateManager().remove(this, K, get_context()); } template const GRState *GRState::remove(typename GRStateTrait::key_type K, typename GRStateTrait::context_type C) const { - return Mgr->remove(this, K, C); + return getStateManager().remove(this, K, C); } - + template const GRState *GRState::set(typename GRStateTrait::data_type D) const { - return Mgr->set(this, D); + return getStateManager().set(this, D); } - + template const GRState *GRState::set(typename GRStateTrait::key_type K, typename GRStateTrait::value_type E) const { - return Mgr->set(this, K, E, get_context()); + return getStateManager().set(this, K, E, get_context()); } - + template const GRState *GRState::set(typename GRStateTrait::key_type K, typename GRStateTrait::value_type E, typename GRStateTrait::context_type C) const { - return Mgr->set(this, K, E, C); + return getStateManager().set(this, K, E, C); } - + template 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 ce43cda31e9e5..5189a1f5aa7e8 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 struct GRStatePartialTrait; - + // Partial-specialization for ImmutableMap. - + template struct GRStatePartialTrait< llvm::ImmutableMap > { typedef llvm::ImmutableMap 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 struct GRStatePartialTrait< llvm::ImmutableSet > { typedef llvm::ImmutableSet 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 struct GRStatePartialTrait< llvm::ImmutableList > { typedef llvm::ImmutableList 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*) *p) + return p ? data_type((const llvm::ImmutableListImpl*) *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 0000000000000..62e36f9e641e4 --- /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 db23f81e2d670..5f7b2cb0e327e 100644 --- a/include/clang/Analysis/PathSensitive/GRTransferFuncs.h +++ b/include/clang/Analysis/PathSensitive/GRTransferFuncs.h @@ -21,66 +21,68 @@ #include namespace clang { - + class GRExprEngine; class BugReporter; class ObjCMessageExpr; class GRStmtNodeBuilderRef; - + class GRTransferFuncs { public: GRTransferFuncs() {} virtual ~GRTransferFuncs() {} - + virtual void RegisterPrinters(std::vector& Printers) {} virtual void RegisterChecks(BugReporter& BR) {} - + // Calls. - - virtual void EvalCall(ExplodedNodeSet& Dst, + + virtual void EvalCall(ExplodedNodeSet& Dst, GRExprEngine& Engine, - GRStmtNodeBuilder& Builder, + GRStmtNodeBuilder& Builder, CallExpr* CE, SVal L, - ExplodedNode* Pred) {} - - virtual void EvalObjCMessageExpr(ExplodedNodeSet& Dst, + ExplodedNode* Pred) {} + + virtual void EvalObjCMessageExpr(ExplodedNodeSet& Dst, GRExprEngine& Engine, - GRStmtNodeBuilder& Builder, + GRStmtNodeBuilder& Builder, ObjCMessageExpr* ME, - ExplodedNode* 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& Builder) {} - - - virtual void EvalDeadSymbols(ExplodedNodeSet& Dst, + GREndPathNodeBuilder& Builder) {} + + + virtual void EvalDeadSymbols(ExplodedNodeSet& Dst, GRExprEngine& Engine, - GRStmtNodeBuilder& Builder, - ExplodedNode* Pred, + GRStmtNodeBuilder& Builder, + ExplodedNode* Pred, Stmt* S, const GRState* state, SymbolReaper& SymReaper) {} - - // Return statements. - virtual void EvalReturn(ExplodedNodeSet& Dst, + + // Return statements. + virtual void EvalReturn(ExplodedNodeSet& Dst, GRExprEngine& Engine, - GRStmtNodeBuilder& Builder, + GRStmtNodeBuilder& Builder, ReturnStmt* S, - ExplodedNode* 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 c76532294c1f8..17b83fdf9fdc3 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 5926229e517c3..0e487691a8912 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 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 { +private: + friend class ElementRegion; + + RegionRawOffset(const MemRegion* reg, int64_t offset = 0) + : std::pair(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(Data); + const FunctionDecl *getDecl() const { + return FD; } - - SymbolRef getSymbol() const { - assert(codekind == Symbolic); - return const_cast(static_cast(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(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(D); } - - QualType getValueType(ASTContext& C) const { + + void Profile(llvm::FoldingSetNodeID& ID) const; + +public: + const VarDecl *getDecl() const { return cast(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(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(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(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(&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 const RegionTy* MemRegion::getAs() const { - const MemRegion *R = this; - - do { - if (const RegionTy* RT = dyn_cast(R)) - return RT; - - if (const TypedViewRegion *TR = dyn_cast(R)) { - R = TR->getSuperRegion(); - continue; - } - - break; - } - while (R); - - return 0; + if (const RegionTy* RT = dyn_cast(this)) + return RT; + + return NULL; } //===----------------------------------------------------------------------===// @@ -592,7 +562,7 @@ class MemRegionManager { ASTContext &C; llvm::BumpPtrAllocator& A; llvm::FoldingSet 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 RegionTy* getRegion(const A1 a1); - + template - RegionTy* getRegion(const A1 a1, const MemRegion* superRegion); - + RegionTy* getSubRegion(const A1 a1, const MemRegion* superRegion); + template 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 struct MemRegionManagerTrait; - + template RegionTy* MemRegionManager::getRegion(const A1 a1) { const typename MemRegionManagerTrait::SuperRegionTy *superRegion = MemRegionManagerTrait::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(Regions.FindNodeOrInsertPos(ID, InsertPos)); - + if (!R) { R = (RegionTy*) A.Allocate(); new (R) RegionTy(a1, superRegion); Regions.InsertNode(R, InsertPos); } - + return R; } template -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(Regions.FindNodeOrInsertPos(ID, InsertPos)); - + if (!R) { R = (RegionTy*) A.Allocate(); new (R) RegionTy(a1, superRegion); Regions.InsertNode(R, InsertPos); } - + return R; } - + template RegionTy* MemRegionManager::getRegion(const A1 a1, const A2 a2) { - + const typename MemRegionManagerTrait::SuperRegionTy *superRegion = MemRegionManagerTrait::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(Regions.FindNodeOrInsertPos(ID, InsertPos)); - + if (!R) { R = (RegionTy*) A.Allocate(); new (R) RegionTy(a1, a2, superRegion); Regions.InsertNode(R, InsertPos); } - + return R; } - + //===----------------------------------------------------------------------===// // Traits for constructing regions. //===----------------------------------------------------------------------===// @@ -776,18 +754,18 @@ template <> struct MemRegionManagerTrait { const Expr *, unsigned) { return MRMgr.getStackRegion(); } -}; - +}; + template <> struct MemRegionManagerTrait { 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 { typedef MemSpaceRegion SuperRegionTy; static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr, @@ -795,20 +773,24 @@ template <> struct MemRegionManagerTrait { return MRMgr.getGlobalsRegion(); } }; - + template <> struct MemRegionManagerTrait { typedef MemRegion SuperRegionTy; - static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr, - const VarDecl *d) { - if (d->hasLocalStorage()) { - return isa(d) || isa(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(D) || isa(D) ? MRMgr.getStackArgumentsRegion() : MRMgr.getStackRegion(); } - + return MRMgr.getGlobalsRegion(); } }; - + template <> struct MemRegionManagerTrait { typedef MemRegion SuperRegionTy; static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr, @@ -820,7 +802,7 @@ template <> struct MemRegionManagerTrait { template<> struct MemRegionManagerTrait { 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 { return MRMgr.getCodeRegion(); } }; - + } // end clang namespace //===----------------------------------------------------------------------===// @@ -836,10 +818,10 @@ template<> struct MemRegionManagerTrait { //===----------------------------------------------------------------------===// 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 4bc5e27aacf05..4ba3c7396822e 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(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 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(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 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 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 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 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(D), true, SubKind) {} + : DefinedSVal(const_cast(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 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(SE)) {} @@ -236,12 +281,12 @@ public: const SymExpr *getSymbolicExpression() const { return reinterpret_cast(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(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 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(data.first)); } - + public: - + Loc getLoc() const { return cast(((std::pair*) Data)->first); } - + const Loc& getPersistentLoc() const { const SVal& V = ((std::pair*) Data)->first; return cast(V); - } - + } + unsigned getNumBits() const { return ((std::pair*) Data)->second; } - + // Implement isa 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(Data); } - + typedef llvm::ImmutableList::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(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(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(Data); } - + + const MemRegion* getBaseRegion() const; + template const REGION* getRegionAs() const { return llvm::dyn_cast(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 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(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 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 490c04e5978e9..e63eb12cf8ea8 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 + class GenericCastResult : public std::pair { + public: + const GRState *getState() const { return this->first; } + T getSVal() const { return this->second; } + GenericCastResult(const GRState *s, T v) + : std::pair(s, v) {} + }; - virtual SVal EvalCast(NonLoc val, QualType castTy) = 0; + class CastResult : public GenericCastResult { + public: + CastResult(const GRState *s, SVal v) : GenericCastResult(s, v) {} + }; + + class DefinedOrUnknownCastResult : + public GenericCastResult { + public: + DefinedOrUnknownCastResult(const GRState *s, DefinedOrUnknownSVal v) + : GenericCastResult(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 5aa53507fd141..3ff253d0abf30 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& 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 f32a7e3481dd2..d3996c6330a2a 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 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 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 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 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 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 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 support. static inline bool classof(const SymExpr* SE) { return SE->getKind() == SymSymKind; - } + } }; class SymbolManager { typedef llvm::FoldingSet 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 SetTy; - typedef SetTy::Factory FactoryTy; - - FactoryTy F; + typedef llvm::DenseSet 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 36d1df2150df9..8d162a681c446 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 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 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 d2b536ca1cb2f..666e45b847cf0 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 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 Data; + std::pair 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(P), - (uintptr_t) k), Tag(tag) {} - - ProgramPoint(const void* P1, const void* P2, const void *tag = 0) - : Data(reinterpret_cast(P1) | TwoPointers, - reinterpret_cast(P2)), Tag(tag) {} - - ProgramPoint(const void* P1, const void* P2, bool, const void *tag = 0) - : Data(reinterpret_cast(P1) | Custom, - reinterpret_cast(P2)), Tag(tag) {} protected: - void* getData1NoMask() const { - Kind k = getKind(); k = k; - assert(k == BlockEntranceKind || k == BlockExitKind); - return reinterpret_cast(Data.first); - } - - void* getData1() const { - Kind k = getKind(); k = k; - assert(k == BlockEdgeKind ||(k >= MinPostStmtKind && k <= MaxPostStmtKind)); - return reinterpret_cast(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(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(Data.first)); - ID.AddPointer(reinterpret_cast(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(Data.first)); - if (getKind() != PostStmtCustomKind) - ID.AddPointer(reinterpret_cast(Data.second)); - else { - const std::pair *P = - reinterpret_cast*>(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(getData1NoMask()); + return const_cast(reinterpret_cast(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(getData1NoMask()); + return const_cast(reinterpret_cast(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 + const T* getStmtAs() const { return llvm::dyn_cast(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 - T* getStmtAs() const { return llvm::dyn_cast(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* TaggedData) - : PostStmt(S, TaggedData, true) { - assert(getKind() == PostStmtCustomKind); - } + const std::pair* TaggedData,\ + const LocationContext *L) + : PostStmt(S, TaggedData, PostStmtCustomKind, L) {} const std::pair& getTaggedPair() const { - return *reinterpret_cast*>(getData2()); + return + *reinterpret_cast*>(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(getData1()); + return const_cast(static_cast(getData1())); } - + CFGBlock* getDst() const { - return static_cast(getData2()); + return const_cast(static_cast(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 { static inline clang::ProgramPoint getEmptyKey() { uintptr_t x = - reinterpret_cast(DenseMapInfo::getEmptyKey()) & ~0x7; - return clang::BlockEntrance(reinterpret_cast(x)); + reinterpret_cast(DenseMapInfo::getEmptyKey()) & ~0x7; + return clang::BlockEntrance(reinterpret_cast(x), 0); } static inline clang::ProgramPoint getTombstoneKey() { uintptr_t x = - reinterpret_cast(DenseMapInfo::getTombstoneKey()) & ~0x7; - return clang::BlockEntrance(reinterpret_cast(x)); + reinterpret_cast(DenseMapInfo::getTombstoneKey()) & ~0x7; + return clang::BlockEntrance(reinterpret_cast(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 a592be815419e..27ecc66e66e3b 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 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(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(X); } - + static inline const ParentTy& ParentRef(const ValTy& X) { return static_cast(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(*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(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 0000000000000..a5e11a100665c --- /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 + +namespace clang { + +class BumpVectorContext { + llvm::PointerIntPair 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 +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::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_reverse_iterator; + typedef std::reverse_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::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 +void BumpVector::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(NewCapacity); + + // Copy the elements over. + if (llvm::is_class::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 0000000000000..3940007bb574f --- /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 +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 +struct simplify_type > { + typedef const T* SimpleType; + static SimpleType getSimplifiedValue(const ::clang::Optional &Val) { + return Val.getPointer(); + } +}; + +template +struct simplify_type< ::clang::Optional > + : public simplify_type > {}; +} // 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 0000000000000..4720c22d990ef --- /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 +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 ee79c517030f9..3826d3a3acd6e 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(this)->VisitVarDecl(D); } - + namespace clang { template class CFGRecStmtDeclVisitor : public CFGRecStmtVisitor { -public: +public: void VisitDeclRefExpr(DeclRefExpr* DR) { - static_cast(this)->VisitDecl(DR->getDecl()); + static_cast(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(this)->VisitDecl(D); + static_cast(this)->VisitDecl(D); // Visit the initializer. if (VarDecl* VD = dyn_cast(D)) if (Expr* I = VD->getInit()) static_cast(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 4d3201962250d..83700a3a346d9 100644 --- a/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h +++ b/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h @@ -20,12 +20,12 @@ namespace clang { template class CFGRecStmtVisitor : public CFGStmtVisitor { -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(this)->BlockStmt_Visit(S);} }; diff --git a/include/clang/Analysis/Visitors/CFGStmtVisitor.h b/include/clang/Analysis/Visitors/CFGStmtVisitor.h index f42bbde8f1489..426b9ccd8a23a 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(this)->BlockStmt_Visit ## CLASS(static_cast(S)); +static_cast(this)->BlockStmt_Visit ## CLASS(static_cast(S)); #define DEFAULT_BLOCKSTMT_VISIT(CLASS) RetTy BlockStmt_Visit ## CLASS(CLASS *S)\ { return\ @@ -36,40 +36,40 @@ class CFGStmtVisitor : public StmtVisitor { 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(this)->getCFG().isBlkExpr(S)) return StmtVisitor::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(S); if (B->isLogicalOp()) @@ -78,40 +78,40 @@ public: return static_cast(this)->BlockStmt_VisitComma(B); // Fall through. } - + default: if (isa(S)) - return + return static_cast(this)->BlockStmt_VisitExpr(cast(S)); else - return static_cast(this)->BlockStmt_VisitStmt(S); + return static_cast(this)->BlockStmt_VisitStmt(S); } } DEFAULT_BLOCKSTMT_VISIT(StmtExpr) DEFAULT_BLOCKSTMT_VISIT(ConditionalOperator) - + RetTy BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) { return static_cast(this)->BlockStmt_VisitStmt(S); } - + RetTy BlockStmt_VisitImplicitControlFlowExpr(Expr* E) { return static_cast(this)->BlockStmt_VisitExpr(E); } - + RetTy BlockStmt_VisitExpr(Expr* E) { return static_cast(this)->BlockStmt_VisitStmt(E); } - + RetTy BlockStmt_VisitStmt(Stmt* S) { return static_cast(this)->Visit(S); } RetTy BlockStmt_VisitLogicalOp(BinaryOperator* B) { - return + return static_cast(this)->BlockStmt_VisitImplicitControlFlowExpr(B); } - + RetTy BlockStmt_VisitComma(BinaryOperator* B) { return static_cast(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(S)->getSubStmt(); if (CS->body_empty()) return; static_cast(this)->Visit(CS->body_back()); return; } - + case Stmt::BinaryOperatorClass: { BinaryOperator* B = cast(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(this)->Visit(*I); + if (*I) static_cast(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 25101235ddd2d..1bc798f4e79e1 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 class CFGVarDeclVisitor : public CFGStmtVisitor { const CFG& cfg; -public: +public: CFGVarDeclVisitor(const CFG& c) : cfg(c) {} - + void VisitStmt(Stmt* S) { static_cast(this)->VisitChildren(S); } - + void VisitDeclRefExpr(DeclRefExpr* DR) { static_cast(this)->VisitDeclChain(DR->getDecl()); } - + void VisitDeclStmt(DeclStmt* DS) { static_cast(this)->VisitDeclChain(DS->getDecl()); } - - void VisitDeclChain(ScopedDecl* D) { + + void VisitDeclChain(ScopedDecl* D) { for (; D != NULL ; D = D->getNextDeclarator()) static_cast(this)->VisitScopedDecl(D); } - + void VisitScopedDecl(ScopedDecl* D) { if (VarDecl* V = dyn_cast(D)) static_cast(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(this)->BlockStmt_Visit(const_cast(*SI)); + static_cast(this)->BlockStmt_Visit(const_cast(*SI)); } }; diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def index c2f4061c5d789..27997858c00c8 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 f770c5089eec5..07f091a58a4e2 100644 --- a/include/clang/Basic/Builtins.h +++ b/include/clang/Basic/Builtins.h @@ -17,6 +17,10 @@ #include +// VC++ defines 'alloca' as an object-like macro, which interferes with our +// builtins. +#undef alloca + namespace llvm { template class SmallVectorImpl; } @@ -63,35 +67,40 @@ public: /// \brief Popular the vector with the names of all of the builtins. void GetBuiltinNames(llvm::SmallVectorImpl &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 73e2fcd12fee2..4da2ad7572235 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 207710bdff31e..380192e9dae65 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 +#include #include 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 DiagMappings; + mutable std::vector 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 ¤tMappings = 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 +inline +typename llvm::enable_if, + const DiagnosticBuilder &>::type +operator<<(const DiagnosticBuilder &DB, T *DC) { + DB.AddTaggedVal(reinterpret_cast(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(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(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 &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 e059d5e605203..cbf9cdbc1599a 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; 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 a8dbd68df10ff..dfdf0ff2e733d 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 815ae8d700034..e5c73270fdfce 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 2896f7988c016..c34bdc111c90f 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 6ca50db50a8a7..3f132c0dabfa2 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>; def pp_macro_not_used : Warning<"macro is not used">, DefaultIgnore, InGroup>; 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; -def warn_pragma_diagnostic_invalid : +def warn_pragma_diagnostic_gcc_invalid : ExtWarn<"pragma diagnostic expected 'error', 'warning', 'ignored', or" " 'fatal'">, InGroup; +def warn_pragma_diagnostic_clang_invalid : + ExtWarn<"pragma diagnostic expected 'error', 'warning', 'ignored', 'fatal'" + " 'push', or 'pop'">, + InGroup; +def warn_pragma_diagnostic_clang_cannot_ppp : + ExtWarn<"pragma diagnostic pop could not pop, no matching push">, + InGroup; def warn_pragma_diagnostic_invalid_option : ExtWarn<"pragma diagnostic expected option name (e.g. \"-Wundef\")">, InGroup; diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index d65a97eb7067b..6971df50cb551 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 b1a73d05a45fc..b03676d877e26 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, DefaultIgnore; +def warn_unused_variable : Warning<"unused variable %0">, + InGroup, 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, 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; +def warn_falloff_nonvoid_function : Warning< + "control reaches end of non-void function">, + InGroup; +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>, DefaultIgnore; +def warn_suggest_noreturn_block : Warning< + "block could be attribute 'noreturn'">, + InGroup>, 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 ">; +def err_implicit_decl_requires_setjmp : Error< + "implicit declaration of '%0' requires inclusion of the header ">; 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{||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{||specialized|instantiated|instantiated}0 " + "declaration is here">; +def err_template_spec_decl_function_scope : Error< + "explicit %select{||specialization|instantiation|" + "instantiation}0 of %1 in function scope">; +def err_template_spec_decl_class_scope : Error< + "explicit %select{||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; def ext_sizeof_void_type : Extension< - "invalid application of '%0' to a void type">; + "invalid application of '%0' to a void type">, InGroup; // 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>, 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, 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; 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; 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; + 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; +def warn_unused_property_expr : Warning< + "property access result unused - getters should not have side effects">, + InGroup; +def warn_unused_call : Warning< + "ignoring return value of function declared with %0 attribute">, + InGroup; +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, DefaultIgnore; +def warn_base_initialized : Warning< + "base class %0 will be initialized after">, + InGroup, 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>; +def warn_falloff_noreturn_function : Warning< + "function declared 'noreturn' should not return">, + InGroup>; 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, DefaultIgnore; } diff --git a/include/clang/Basic/FileManager.h b/include/clang/Basic/FileManager.h index d6a0cf34d9fa1..7c9113c497ef1 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 -#include -#include // FIXME: Enhance libsystem to support inode and other fields in stat. #include #include 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 StatResult; - /// \brief The set of stat() calls that have been + /// \brief The set of stat() calls that have been llvm::StringMap StatCalls; typedef llvm::StringMap::const_iterator iterator; - + iterator begin() const { return StatCalls.begin(); } iterator end() const { return StatCalls.end(); } @@ -126,22 +124,22 @@ class FileManager { /// llvm::StringMap DirEntries; llvm::StringMap FileEntries; - + /// NextFileUID - Each FileEntry we create is assigned a unique ID #. /// unsigned NextFileUID; - + // Statistics. unsigned NumDirLookups, NumFileLookups; unsigned NumDirCacheMisses, NumFileCacheMisses; - + // Caching. llvm::OwningPtr 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 57cd311631446..84c2fc910d11b 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 -#include +#include +#include namespace llvm { template struct DenseMapInfo; @@ -38,21 +38,21 @@ namespace clang { /// IdentifierLocPair - A simple pair of identifier info and location. typedef std::pair 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 *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 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, where internal pointer // points to the external string data. return ((std::pair*) 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, where internal pointer // points to the external string data. const char* p = ((std::pair*) 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 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 &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 &Entry = HashTable.GetOrCreateValue(NameStart, NameEnd); - + IdentifierInfo *II = Entry.getValue(); assert(!II && "IdentifierInfo already exists"); - + // Lookups failed, make a new IdentifierInfo. void *Mem = getAllocator().Allocate(); 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(II); assert((InfoPtr & ArgFlags) == 0 &&"Insufficiently aligned IdentifierInfo"); @@ -383,7 +378,7 @@ class Selector { InfoPtr = reinterpret_cast(SI); assert((InfoPtr & ArgFlags) == 0 &&"Insufficiently aligned IdentifierInfo"); } - + IdentifierInfo *getAsIdentifierInfo() const { if (getIdentifierInfoFlag()) return reinterpret_cast(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 { 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 { public: static inline void *getAsVoidPointer(clang::IdentifierInfo* P) { - return P; + return P; } static inline clang::IdentifierInfo *getFromVoidPointer(void *P) { return static_cast(P); @@ -549,7 +544,7 @@ template<> class PointerLikeTypeTraits { 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(P); diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h index 26688bf567284..d4d3fe50eba06 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 b08d61457b751..6ed5fefb7e646 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 f54d67042c472..65245167d8d56 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(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& Len = + const std::pair& 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& L = Info::ReadKeyDataLength(Items); + const std::pair& 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(buckets) & 0x3) == 0 && "buckets should be 4-byte aligned."); - + unsigned numBuckets = ReadLE32(buckets); unsigned numEntries = ReadLE32(buckets); return new OnDiskChainedHashTable(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 0000000000000..e8cc564c8a204 --- /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(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 2405c2fe7db72..28cf2db9bc25f 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 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 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 249ca89f717de..7eb988f005ec0 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(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 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 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 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 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 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 getImmediateInstantiationRange(SourceLocation Loc) const; - + /// getInstantiationRange - Given a SourceLocation object, return the /// range of tokens covered by the instantiation in the ultimate file. std::pair 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_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::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 getDecomposedInstantiationLocSlowCase(const SrcMgr::SLocEntry *E, - unsigned Offset) const; + unsigned Offset) const; std::pair getDecomposedSpellingLocSlowCase(const SrcMgr::SLocEntry *E, unsigned Offset) const; diff --git a/include/clang/Basic/SourceManagerInternals.h b/include/clang/Basic/SourceManagerInternals.h index 0bcb68e4601dd..258989cb7787e 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 FilenameIDs; std::vector*> 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 > 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 537d553bc2d1a..a1e0a17c882ef 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 #include #include -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 &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 &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 e711996cf26da..239712c08caff 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 62a9e428bf210..85dc0671de629 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 f0e1aa7db233e..120d5a4210d01 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 12b74d51473e2..1871c8f206f3d 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 ceef189f7b7ef..679704c395872 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 6bed2b8cbdef3..ebf40d45de4cb 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 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 a9c890b0b8994..dcb60381a4674 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 +#include + +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 6414ef13692b0..56786a7ae2a39 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 TCArgs; + llvm::DenseMap, + 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 c0def2bcca29f..c0327a2f1d1c2 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 #include #include +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 CCCClangArchs; + std::set CCCClangArchs; /// Certain options suppress the 'no input files' warning. bool SuppressMissingInputWarning : 1; - + std::list TempFiles; std::list 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 705c3422cda39..d4a9da7b6d802 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 b5e80b0c3bfe6..bf67c343f3266 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 a23babdbb31a5..906d73128b7dc 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 c59faef897aee..c70b6482167b1 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 af108a85ebdd9..4084be6c0b42b 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 8b959d369c0e1..7fcaf3f497bef 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 d8b37e9ead88c..8a89f01e0f4b0 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 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 c9d0ef197dae5..b7630d8afdb87 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 8d24e5013fb05..e01a04c67ae1f 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 be45202625586..f59a0a7d481e6 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 -#include 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 68c06f5dcee61..89eb3b8821ca0 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 @@ -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 SourceMgr; - llvm::OwningPtr DiagClient; - llvm::OwningPtr Diags; + Diagnostic &Diags; + SourceManager SourceMgr; llvm::OwningPtr HeaderInfo; llvm::OwningPtr Target; llvm::OwningPtr PP; llvm::OwningPtr 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 ad799c3a8b25b..d5e408020a987 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 1eaa958995f54..59f70ede9129d 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 + class parser : public basic_parser { 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:: - 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 75dec00f747f3..508af537b1fa1 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 956d9719f9f40..36323c260c9a3 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()->getResultType()) + ATTRIBUTE_XML(getType()->getAs(), "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()->getResultType()) + ATTRIBUTE_XML(getType()->getAs(), "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 4ed11e153ce36..6693ddbac57d5 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 struct IdMap : llvm::DenseMap {}; @@ -47,9 +46,8 @@ namespace XML struct IdMap : std::map {}; } -//--------------------------------------------------------- -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 - void addAttribute(const char* pName, const T* value) - { + void addAttribute(const char* pName, const T* value) { addPtrAttribute(pName, value); } template - void addAttribute(const char* pName, T* value) - { + void addAttribute(const char* pName, T* value) { addPtrAttribute(pName, value); } template void addAttribute(const char* pName, const T& value); - + template 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 -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 -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 7fcd682bf66c1..fac87afadef24 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 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 079abae3eee1c..a044586a8c0a1 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 51516661c99ef..a90b4eaf9e2b5 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 #include -#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 ecab67a3b6769..f05cfe6df6b8d 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 80aa248a78e6f..716780e68a528 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, , 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 8291f4697a8ea..1230e3753e04d 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 #include #include #include @@ -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 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 TypesLoaded; + std::vector 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 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 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 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 PendingIdentifierInfos; + /// \brief FIXME: document! llvm::SmallVector 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 &Record); PCHReadResult ReadSourceManagerBlock(); PCHReadResult ReadSLocEntryRecord(unsigned ID); - + bool ParseLanguageOptions(const llvm::SmallVectorImpl &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 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 &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 + virtual std::pair ReadMethodPool(Selector Sel); void SetIdentifierInfo(unsigned ID, IdentifierInfo *II); + void SetGloballyVisibleDecls(IdentifierInfo *II, + const llvm::SmallVectorImpl &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 c663442e64d8c..a807cd7c4d1fa 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(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 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 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 TypesToEmit; + std::queue 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 IdentifierIDs; - + /// \brief Offsets of each of the identifier IDs into the identifier /// table. std::vector IdentifierOffsets; /// \brief Map that provides the ID numbers of each Selector. llvm::DenseMap SelectorIDs; - + /// \brief Offset of each selector within the method pool/selector /// table, indexed by the Selector ID (-1). std::vector SelectorOffsets; /// \brief A vector of all Selectors (ordered by ID). std::vector 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 SwitchCaseIDs; - + /// \brief Mapping from LabelStmt statements to IDs. std::map 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 028cd8549272d..8cb6898d75984 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 #include +#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 *FilesMade) = 0; +}; + +PathDiagnosticClient* +CreateHTMLDiagnosticClient(const std::string& prefix, Preprocessor* PP = 0, + PreprocessorFactory* PPF = 0, + llvm::SmallVectorImpl* 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 26430f740d91d..fd79cf0c6ccbd 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 f8408bdbd742e..0fd8d44f72bc1 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 2a78fd9f75b12..6aca15a75427c 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 77df60cd7210a..9cbcf8e3e93e8 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 pair. -/// Pointing at '++foo' will return a pair. -/// -std::pair 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 0000000000000..9620ec5dbd4fd --- /dev/null +++ b/include/clang/Index/ASTLocation.h @@ -0,0 +1,174 @@ +//===--- ASTLocation.h - A 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 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(d), N_Decl), D(const_cast(d)) { } + + ASTLocation(const Decl *parentDecl, const Stmt *stm) + : ParentDecl(const_cast(parentDecl), N_Stmt), + Stm(const_cast(stm)) { + if (!stm) ParentDecl.setPointer(0); + } + + ASTLocation(const Decl *parentDecl, NamedDecl *ndRef, SourceLocation loc) + : ParentDecl(const_cast(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(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(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 0000000000000..f6b5465148e68 --- /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 0000000000000..73f2fe50b3b64 --- /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 + +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 MapTy; + typedef pair_value_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 0000000000000..4533a1a0ac082 --- /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 + +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 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(); + } + + /// \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(); + } + + 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::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::getFromOpaqueValue((void*)-1); + return Ent; + } + static Entity getTombstoneMarker() { + Entity Ent; + Ent.Val = + llvm::PointerUnion::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 { + 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 0000000000000..51f98267f3562 --- /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 + +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 { + 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 0000000000000..655aef901cd16 --- /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 TURes; +/// IndexProvider.GetTranslationUnitsFor(Entity, TURes); +/// for (Storing::iterator +/// I = TURes.begin(), E = TURes.end(); I != E; ++I) { .... +/// @endcode +template +class Storing : public handler_type { + typedef typename handler_type::receiving_type receiving_type; + typedef llvm::SmallVector 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 0000000000000..187dd9393cbb9 --- /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 0000000000000..8b1d2dd38bff8 --- /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 + +namespace clang { + class ASTContext; + +namespace idx { + class Program; + class TranslationUnit; + +/// \brief Maps information to TranslationUnits. +class Indexer : public IndexProvider { +public: + typedef llvm::SmallPtrSet TUSetTy; + typedef llvm::DenseMap CtxTUMapTy; + typedef std::map MapTy; + typedef std::map 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 0000000000000..8039192512d62 --- /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 0000000000000..a3693c6c79a62 --- /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 +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 0000000000000..be01702fcbdbe --- /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 + +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 SelMethMapTy; + typedef std::multimap SelRefMapTy; + + typedef pair_value_iterator method_iterator; + typedef pair_value_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 0000000000000..bf9e78f72892c --- /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 0000000000000..e78ef8a155630 --- /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 618de39233db7..c94a990224155 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 d8033093bd8e7..6bb7c25947d7c 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 f21aab1b40152..7517440983b12 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 search the current dir first, then each @@ -81,7 +81,7 @@ class HeaderSearch { std::vector 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 > LookupFileCache; - - + + /// FrameworkMap - This is a collection mapping a framework or subframework /// name like "Carbon" to the Carbon.framework directory. llvm::StringMap 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 > 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 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::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 03d9b7b3bbb84..a470aa0924fbc 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 3a73147152afc..c2db4d357c517 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 &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 8ee8ecf7359fe..97656f7d39d61 100644 --- a/include/clang/Lex/LiteralSupport.h +++ b/include/clang/Lex/LiteralSupport.h @@ -17,6 +17,7 @@ #include #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 ccd13c80d3546..5887041c46b9f 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 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(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::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 94d4677f9d29c..5d5d673290596 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 e5cbeebd22aa0..dd24fb7d7ba25 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 369b818a1fc9e..e96a8c514e6eb 100644 --- a/include/clang/Lex/PTHLexer.h +++ b/include/clang/Lex/PTHLexer.h @@ -18,42 +18,42 @@ #include 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 507576473f60e..ff1a17259e8a6 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 136dc6fabfb67..ef367feb84db9 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 6d5ed72455b90..0765ac391be3f 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 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 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 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 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 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 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 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 Macros; - + /// MICache - A "freelist" of MacroInfo objects that can be reused for quick /// allocation. std::vector 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 CachedTokensTy; + typedef llvm::SmallVector 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::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 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 f98b5599658fd..85c44c5a0b808 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 - + 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 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 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 6506f9262947c..f03515ffc1428 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 2c8f2ad3f2b62..8acdb30cc705a 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 dfc05f4074e0a..d759e47e57fcd 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 c0a61cf93ee55..3f13e9cc1268e 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 d969562977ea3..1ee14701fa2d7 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(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 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::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 A; + /// template class B { + /// friend class A::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 &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() + /// \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(). + /// + /// \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", 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: + /// + /// \code + /// template 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". /// /// \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 &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::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 50ca88acbce93..9fcc845cb0064 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 300602e5147cc..51970f1867d96 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" and protocol-qualified id // "id". 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 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 026286d318fb8..255af59018192 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 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 987edfa96dd1b..9bd69c5fdb687 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 T* getAs() const { return llvm::PointerLikeTypeTraits::getFromVoidPointer(Ptr); } - + template T getAsVal() const { return llvm::PointerLikeTypeTraits::getFromVoidPointer(Ptr); } - + void *get() const { return Ptr; } - + template static OpaquePtr make(T P) { OpaquePtr R; R.set(P); return R; } - + template void set(T P) { Ptr = llvm::PointerLikeTypeTraits::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::value> @@ -252,7 +252,7 @@ namespace clang { uintptr_t PtrWithInvalid; typedef llvm::PointerLikeTypeTraits PtrTraits; public: - ActionResult(bool Invalid = false) + ActionResult(bool Invalid = false) : PtrWithInvalid(static_cast(Invalid)) { } template @@ -262,17 +262,17 @@ namespace clang { PtrWithInvalid = reinterpret_cast(VP); assert((PtrWithInvalid & 0x01) == 0 && "Badly aligned pointer"); } - + ActionResult(PtrTy V) { void *VP = PtrTraits::getAsVoidPointer(V); PtrWithInvalid = reinterpret_cast(VP); assert((PtrWithInvalid & 0x01) == 0 && "Badly aligned pointer"); } - + ActionResult(const DiagnosticBuilder &) : PtrWithInvalid(0x01) { } PtrTy get() const { - void *VP = reinterpret_cast(PtrWithInvalid & ~0x01); + void *VP = reinterpret_cast(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 - class ASTResultMover - { + class ASTResultMover { ASTOwningResult &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 - class ASTMultiMover - { + class ASTMultiMover { ASTMultiPtr &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 - class ASTOwningPtr - { + class ASTOwningPtr { void *Node; public: @@ -400,8 +397,7 @@ namespace clang { #if !defined(DISABLE_SMART_POINTERS) template - class ASTOwningResult - { + class ASTOwningResult { llvm::PointerIntPair ActionInv; void *Ptr; @@ -505,8 +501,7 @@ namespace clang { }; #else template - class ASTOwningResult - { + class ASTOwningResult { public: typedef ActionBase::ActionResult::UID> DumbResult; @@ -522,8 +517,7 @@ namespace clang { ASTOwningResult(const ASTOwningPtr &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 - 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 & source) { return (ASTMultiPtr*)source.operator->(); - } + } #endif ASTMultiPtr(ASTMultiPtr&); // DO NOT IMPLEMENT @@ -608,7 +601,7 @@ namespace clang { /// Move constructor ASTMultiPtr(moving::ASTMultiMover 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 inline ASTOwningPtr::ASTOwningPtr(const ASTOwningResult &o) - : Node(o.get()) - {} + : Node(o.get()) { } // These versions are hopefully no-ops. template inline diff --git a/include/clang/Parse/ParseDiagnostic.h b/include/clang/Parse/ParseDiagnostic.h index fa600ddadfab4..c702e2fe65b86 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 e2380542ae6f6..9cb4677f66370 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 UnusedHandler; llvm::OwningPtr WeakHandler; llvm::OwningPtr 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 >IO, 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 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 &P, - bool WarnOnDeclarations, + llvm::SmallVectorImpl &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 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 &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 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 84cc5d5c3461a..480b94f73f621 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 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(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(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 7bf9305e28775..7e0796524c6d9 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 f49d49e710c9a..f77e0c61c54ce 100644 --- a/include/clang/Rewrite/HTMLRewrite.h +++ b/include/clang/Rewrite/HTMLRewrite.h @@ -19,36 +19,36 @@ #include 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 7faa451290e40..c0bd741d55465 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 #include +#include 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 { + public std::iterator { /// 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 c3ee0175c36fd..29e78fa27958b 100644 --- a/include/clang/Rewrite/Rewriter.h +++ b/include/clang/Rewrite/Rewriter.h @@ -22,13 +22,14 @@ #include #include #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 c8fd0f532c25a..62ea12af1f17c 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::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 TokenAtLoc; - + /// ScratchBuf - This is the buffer that we create scratch tokens from. /// llvm::OwningPtr 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::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 0000000000000..d2f509df7b2cc --- /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 +#include + +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 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 Chunks; + + CodeCompletionString(const CodeCompletionString &); // DO NOT IMPLEMENT + CodeCompletionString &operator=(const CodeCompletionString &); // DITTO + +public: + CodeCompletionString() { } + ~CodeCompletionString(); + + typedef llvm::SmallVector::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 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 0f0d375e9c30a..05c56451b2188 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 - ReadMethodPool(Selector Sel) { + virtual std::pair + ReadMethodPool(Selector Sel) { return std::pair(); } - + // 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 bdce5e95effb5..8a245d03cdaa3 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 e821947035c4c..b213daf8a39ea 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 de92844f4d6ad..d026339b5caf9 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 4df7671c5a955..772a884c90d36 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 2877cc3b7fe77..85b4fd6d6cc03 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() { @@ -52,6 +58,13 @@ ASTContext::~ASTContext() { Types.pop_back(); } + { + llvm::FoldingSet::iterator + I = ExtQualNodes.begin(), E = ExtQualNodes.end(); + while (I != E) + Deallocate(&*I++); + } + { llvm::DenseMap::iterator I = ASTRecordLayouts.begin(), E = ASTRecordLayouts.end(); @@ -73,8 +86,8 @@ ASTContext::~ASTContext() { // Destroy nested-name-specifiers. for (llvm::FoldingSet::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 &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::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::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::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 { 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::iterator Pos + llvm::DenseMap::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 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::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 DeclStartDecomp + std::pair 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(D) && !isa(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 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::iterator FirstComment = LastComment; while (FirstComment != Comments.begin()) { @@ -357,31 +445,31 @@ const char *ASTContext::getCommentForDecl(const Decl *D) { --FirstComment; std::pair 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(); 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(D)) { QualType T = VD->getType(); - if (const ReferenceType* RT = T->getAsReferenceType()) { + if (const ReferenceType* RT = T->getAs()) { 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 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(T)->getElementType()); break; + case Type::ConstantArrayWithExpr: + case Type::ConstantArrayWithoutExpr: case Type::ConstantArray: { const ConstantArrayType *CAT = cast(T); - + std::pair 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 EltInfo = + std::pair EltInfo = getTypeInfo(cast(T)->getElementType()); Width = EltInfo.first*cast(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(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(T)->getPointeeType(); - std::pair PtrDiffInfo = + std::pair 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 EltInfo = + std::pair EltInfo = getTypeInfo(cast(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(TT)) return getTypeInfo(ET->getDecl()->getIntegerType()); @@ -648,6 +749,10 @@ ASTContext::getTypeInfo(const Type *T) { break; } + case Type::Elaborated: { + return getTypeInfo(cast(T)->getUnderlyingType().getTypePtr()); + } + case Type::Typedef: { const TypedefDecl *Typedef = cast(T)->getDecl(); if (const AlignedAttr *Aligned = Typedef->getAttr()) { @@ -671,16 +776,16 @@ ASTContext::getTypeInfo(const Type *T) { case Type::QualifiedName: return getTypeInfo(cast(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()) 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()) - 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 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()) - 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 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()) - 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 &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::iterator + I = ObjCImpls.find(D); + if (I != ObjCImpls.end()) + return cast(I->second); + return 0; +} +/// \brief Get the implementation of ObjCCategoryDecl, or NULL if none exists. +ObjCCategoryImplDecl *ASTContext::getObjCImplementation(ObjCCategoryDecl *D) { + llvm::DenseMap::iterator + I = ObjCImpls.find(D); + if (I != ObjCImpls.end()) + return cast(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()) - StructPacking = PA->getAlignment(); - - if (const AlignedAttr *AA = D->getAttr()) - NewEntry->SetAlignment(std::max(NewEntry->getAlignment(), - AA->getAlignment())); - - // Layout each ivar sequentially. - unsigned i = 0; - llvm::SmallVector 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()) - StructPacking = PA->getAlignment(); - - if (const AlignedAttr *AA = D->getAttr()) - 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(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()->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(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()->getPointeeType(); + ResultType = getNoReturnType(Pointee); + ResultType = getPointerType(ResultType); + } else if (T->isBlockPointerType()) { + QualType Pointee = T->getAs()->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()) { + ResultType = getFunctionNoProtoType(FNPT->getResultType(), true); + } else { + const FunctionProtoType *F = T->getAs(); + 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(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(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(Decl)) return getTypedefType(Typedef); else if (isa(Decl)) { assert(false && "Template type parameter types are always available."); - } else if (ObjCInterfaceDecl *ObjCInterface = dyn_cast(Decl)) + } else if (ObjCInterfaceDecl *ObjCInterface + = dyn_cast(Decl)) return getObjCInterfaceType(ObjCInterface); if (RecordDecl *Record = dyn_cast(Decl)) { if (PrevDecl) Decl->TypeForDecl = PrevDecl->TypeForDecl; else - Decl->TypeForDecl = new (*this,8) RecordType(Record); - } - else if (EnumDecl *Enum = dyn_cast(Decl)) { + Decl->TypeForDecl = new (*this, TypeAlignment) RecordType(Record); + } else if (EnumDecl *Enum = dyn_cast(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(Decl); - Decl->TypeForDecl = new(*this,8) ObjCInterfaceType(Type::ObjCInterface, OID); + 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 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(); 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(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" 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" 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(e)) { @@ -1881,39 +2083,63 @@ static QualType getDecltypeForExpr(const Expr *e, ASTContext &Context) { // return type of that function. if (const CallExpr *CE = dyn_cast(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" 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(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 . +/// 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 . 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 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. + // 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(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(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(AT)) - return getIncompleteArrayType(NewEltTy, IAT->getSizeModifier(), - IAT->getIndexTypeQualifier()); - + return CanQualType::CreateUnsafe( + getIncompleteArrayType(NewEltTy, IAT->getSizeModifier(), + IAT->getIndexTypeCVRQualifiers())); + if (DependentSizedArrayType *DSAT = dyn_cast(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(AT); - return getVariableArrayType(NewEltTy, VAT->getSizeExpr(), - VAT->getSizeModifier(), - VAT->getIndexTypeQualifier()); -} - -Decl *ASTContext::getCanonicalDecl(Decl *D) { - if (!D) - return 0; - - if (TagDecl *Tag = dyn_cast(D)) { - QualType T = getTagDeclType(Tag); - return cast(cast(T.getTypePtr()->CanonicalType) - ->getDecl()); - } - - if (ClassTemplateDecl *Template = dyn_cast(D)) { - while (Template->getPreviousDeclaration()) - Template = Template->getPreviousDeclaration(); - return Template; - } - - if (const FunctionDecl *Function = dyn_cast(D)) { - while (Function->getPreviousDeclaration()) - Function = Function->getPreviousDeclaration(); - return const_cast(Function); - } - - if (FunctionTemplateDecl *FunTmpl = dyn_cast(D)) { - while (FunTmpl->getPreviousDeclaration()) - FunTmpl = FunTmpl->getPreviousDeclaration(); - return FunTmpl; - } - - if (const VarDecl *Var = dyn_cast(D)) { - while (Var->getPreviousDeclaration()) - Var = Var->getPreviousDeclaration(); - return const_cast(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(getCanonicalDecl(Template))); + return TemplateName(cast(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(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(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(CType) && - !isa(CType.getUnqualifiedType())) + if (!isa(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(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(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(ATy)) return cast(getConstantArrayType(NewEltTy, CAT->getSize(), CAT->getSizeModifier(), - CAT->getIndexTypeQualifier())); + CAT->getIndexTypeCVRQualifiers())); if (const IncompleteArrayType *IAT = dyn_cast(ATy)) return cast(getIncompleteArrayType(NewEltTy, IAT->getSizeModifier(), - IAT->getIndexTypeQualifier())); + IAT->getIndexTypeCVRQualifiers())); - if (const DependentSizedArrayType *DSAT + if (const DependentSizedArrayType *DSAT = dyn_cast(ATy)) return cast( - getDependentSizedArrayType(NewEltTy, - DSAT->getSizeExpr(), + getDependentSizedArrayType(NewEltTy, + DSAT->getSizeExpr() ? + DSAT->getSizeExpr()->Retain() : 0, DSAT->getSizeModifier(), - DSAT->getIndexTypeQualifier())); - + DSAT->getIndexTypeCVRQualifiers(), + DSAT->getBracketsRange())); + const VariableArrayType *VAT = cast(ATy); - return cast(getVariableArrayType(NewEltTy, VAT->getSizeExpr(), + return cast(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(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()) return getFloatingRank(CT->getElementType()); - assert(T->getAsBuiltinType() && "getFloatingRank(): not a floating type"); - switch (T->getAsBuiltinType()->getKind()) { + assert(T->getAs() && "getFloatingRank(): not a floating type"); + switch (T->getAs()->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(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(); 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(); assert(Rec && "Invalid ObjCFAstEnumerationStateType"); ObjCFastEnumerationStateTypeDecl = Rec->getDecl(); } @@ -2399,7 +2725,7 @@ static bool isTypeTypedefedAsBOOL(QualType T) { if (const TypedefType *TT = dyn_cast(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(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(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(PointeeTy.getTypePtr())) { - if (const BuiltinType *BT = PointeeTy->getAsBuiltinType()) { + if (isa(PointeeTy.getTypePtr())) { + if (const BuiltinType *BT = PointeeTy->getAs()) { if (BT->getKind() == BuiltinType::ULong && ((const_cast(this))->getIntWidth(PointeeTy) == 32)) PointeeTy = UnsignedIntTy; - else + else if (BT->getKind() == BuiltinType::Long && ((const_cast(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(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(this))->getIntWidth(T) == 32 ? 'l' : 'q'; + if (const BuiltinType *BT = T->getAs()) { + 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(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(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()) { 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()) { 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(T.getTypePtr())) { + // Also, do not emit the 'r' for anything but the outermost type! + if (isa(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()) + P = P->getAs()->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(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()) { + // 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(T->getCanonicalTypeInternal())) { + return; + } + + if (const ArrayType *AT = + // Ignore type qualifiers etc. + dyn_cast(T->getCanonicalTypeInternal())) { if (isa(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(AT)) S += llvm::utostr(CAT->getSize().getZExtValue()); else { @@ -2792,14 +3079,20 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, assert(isa(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()) { S += '?'; - } else if (const RecordType *RTy = T->getAsRecordType()) { + return; + } + + if (const RecordType *RTy = T->getAs()) { 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()) { // @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()) { + 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(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(); if (!TT) return; TypedefDecl *TD = TT->getDecl(); // typedef struct objc_selector *SEL; - const PointerType *ptr = TD->getUnderlyingType()->getAsPointerType(); + const PointerType *ptr = TD->getUnderlyingType()->getAs(); 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(Ty)) { @@ -3036,68 +3384,30 @@ bool ASTContext::isObjCNSObjectType(QualType Ty) const { if (TD->getAttr()) 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

    (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(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()->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 with id +/// 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 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(); + + 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

    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

    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

    *", + // 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

    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"); + + 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

    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

    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(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(RHS)) + if (RHS->getNumProtocols() == 0) return true; // FIXME: should return false! - - // Finally, we must have two protocol-qualified interfaces. - const ObjCQualifiedInterfaceType *LHSP =cast(LHS); - const ObjCQualifiedInterfaceType *RHSP =cast(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(); + const ObjCObjectPointerType *RHSOPT = RHS->getAs(); + + 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(); + const FunctionType *rbase = rhs->getAs(); const FunctionProtoType *lproto = dyn_cast(lbase); const FunctionProtoType *rproto = dyn_cast(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()) LHS = RT->getPointeeType(); - if (const ReferenceType *RT = RHS->getAsReferenceType()) + if (const ReferenceType *RT = RHS->getAs()) 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(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(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()) { if (ETy->getDecl()->getIntegerType() == RHSCan.getUnqualifiedType()) return RHS; } - if (const EnumType* ETy = RHS->getAsEnumType()) { + if (const EnumType* ETy = RHS->getAs()) { 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()->getPointeeType(); + QualType RHSPointee = RHS->getAs()->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()->getPointeeType(); + QualType RHSPointee = RHS->getAs()->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(), RHS->getAs())) 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(); + const ObjCInterfaceType* RHSIface = RHS->getAs(); 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(), + RHS->getAs())) + 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(LHSCan); - ExtQualType* RQual = cast(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()) T = ETy->getDecl()->getIntegerType(); - const BuiltinType* BTy = T->getAsBuiltinType(); + const BuiltinType* BTy = T->getAs(); 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(*Lookup.first)) { - Type = Context.getTypeDeclType(cast(*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 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 ac4cbb2d296e3..20e1150b22c2e 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 0000000000000..4a46eab2e6038 --- /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 +#include + +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 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& 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& 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(); + 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(BaseSpec->getType()->getAs() + ->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()->getDecl() + ->getCanonicalDecl() == BaseRecord; +} + +bool CXXRecordDecl::FindTagMember(CXXBaseSpecifier *Specifier, + CXXBasePath &Path, + void *Name) { + RecordDecl *BaseRecord = Specifier->getType()->getAs()->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()->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()->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(*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 3d02150b65bff..429729ea3b0e2 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 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(this)) return PVD->OriginalType; return getType(); } -void VarDecl::setInit(ASTContext &C, Expr *I) { - if (EvaluatedStmt *Eval = Init.dyn_cast()) { - 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()) { + 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(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()) 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 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(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(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(this)->getNominatedNamespace() == cast(OldD)->getNominatedNamespace(); } - + if (const FunctionDecl *FD = dyn_cast(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(OldD)) return FunctionTemplate->getTemplatedDecl() ->declarationReplaces(OldFunctionTemplate->getTemplatedDecl()); - + // For method declarations, we keep track of redeclarations. if (isa(this)) return false; - + + if (isa(this) && isa(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. @@ -309,14 +331,24 @@ 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(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(); + if (FTSInfo) + C.Deallocate(FTSInfo); + + MemberSpecializationInfo *MSInfo + = TemplateOrSpecialization.dyn_cast(); + 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(); - for (const DeclContext *DC = getDeclContext(); !DC->isTranslationUnit(); + for (const DeclContext *DC = getDeclContext(); !DC->isTranslationUnit(); DC = DC->getParent()) { if (const LinkageSpecDecl *Linkage = dyn_cast(DC)) { if (Linkage->getLanguage() == LinkageSpecDecl::lang_c) - return getStorageClass() != Static && + return getStorageClass() != Static && !getAttr(); 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(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(getDeclContext()) && - cast(getDeclContext())->getLanguage() + cast(getDeclContext())->getLanguage() == LinkageSpecDecl::lang_c && !getAttr()) 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(); if (isa(FT)) return 0; return cast(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()) +/// \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()) { + // 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()) - 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()) - 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(Info->getInstantiatedFrom()); + + return 0; +} + +MemberSpecializationInfo *FunctionDecl::getMemberSpecializationInfo() const { + return TemplateOrSpecialization.dyn_cast(); +} + +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()) { return Info->Template.getPointer(); @@ -589,79 +736,151 @@ FunctionTemplateDecl *FunctionDecl::getPrimaryTemplate() const { const TemplateArgumentList * FunctionDecl::getTemplateSpecializationArgs() const { - if (FunctionTemplateSpecializationInfo *Info - = TemplateOrSpecialization - .dyn_cast()) { + if (FunctionTemplateSpecializationInfo *Info + = TemplateOrSpecialization + .dyn_cast()) { 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(); 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(); - if (!Info) - return false; + if (FTSInfo) + return FTSInfo->getTemplateSpecializationKind(); + + MemberSpecializationInfo *MSInfo + = TemplateOrSpecialization.dyn_cast(); + 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()) + 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(); - 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(TypeForDecl->getAsTagType()); - TagT->decl.setPointer(this); - TagT->getAsTagType()->decl.setInt(1); + if (TagType *TagT = const_cast(TypeForDecl->getAs())) { + 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(TypeForDecl->getAsTagType()); - TagT->decl.setPointer(this); - TagT->decl.setInt(0); + if (TagType *TagT = const_cast(TypeForDecl->getAs())) { + 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(this)); - TagDecl* D = cast(T->getAsTagType()->getDecl()); - return D->isDefinition() ? D : 0; + if (isDefinition()) + return const_cast(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(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(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 96ba19b9a6b99..224bf877ad249 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(this)) return TTP->isParameterPack(); - + return false; } bool Decl::isFunctionOrFunctionTemplate() const { if (const UsingDecl *UD = dyn_cast(this)) return UD->getTargetDecl()->isFunctionOrFunctionTemplate(); - + return isa(this) || isa(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(DC)) + if (ND->isAnonymousNamespace()) + return true; + } while ((DC = DC->getParent())); + + return false; +} + TranslationUnitDecl *Decl::getTranslationUnitDecl() { if (TranslationUnitDecl *TUD = dyn_cast(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(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(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(this) || - !isa(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(this) || + !isa(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(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(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(this)->TypeForDecl->getAsTagType()) - if (TagT->isBeingDefined() || + if (const TagType *TagT =cast(this)->TypeForDecl->getAs()) + 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 Decls; - if (Source->ReadDeclsLexicallyInContext(const_cast(this), + if (Source->ReadDeclsLexicallyInContext(const_cast(this), Decls)) return; @@ -537,7 +582,7 @@ DeclContext::LoadLexicalDeclsFromExternalStorage() const { LastDecl = PrevDecl; } -void +void DeclContext::LoadVisibleDeclsFromExternalStorage() const { DeclContext *This = const_cast(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(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(*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(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(Result.first), diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index b8b29528066d4..457f4c85a0471 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 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(BaseType->getAs()->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(QT->getAs()->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(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(*Con)->isCopyConstructor(Context, + // C++ [class.copy]p2: + // A non-template constructor for class X is a copy constructor if [...] + if (isa(*Con)) + continue; + + if (cast(*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(*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(this))); DeclarationName OpName =Context.DeclarationNames.getCXXOperatorName(OO_Equal); @@ -110,16 +192,17 @@ bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context) const { const CXXMethodDecl* Method = cast(*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(); 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()) { 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(); 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()) 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& 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(TopConv)) + TConvType = + getASTContext().getCanonicalType( + TConversionTemplate->getTemplatedDecl()->getResultType()); + else + TConvType = + getASTContext().getCanonicalType( + cast(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 &TopConversionsTypeSet, + const llvm::SmallPtrSet &HiddenConversionTypes) +{ + bool inTopClass = (RD == this); + QualType ClassType = getASTContext().getTypeDeclType(this); + if (const RecordType *Record = ClassType->getAs()) { + OverloadedFunctionDecl *Conversions + = cast(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(Conv)) + ConvType = + getASTContext().getCanonicalType( + ConversionTemplate->getTemplatedDecl()->getResultType()); + else + ConvType = + getASTContext().getCanonicalType( + cast(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(Conv)) + RD->addVisibleConversionFunction(ConversionTemplate); + else + RD->addVisibleConversionFunction(cast(Conv)); + } + } + } + + if (getNumBases() == 0 && getNumVBases() == 0) + return; + + llvm::SmallPtrSet ConversionFunctions; + if (!inTopClass) + collectConversionFunctions(ConversionFunctions); + + for (CXXRecordDecl::base_class_iterator VBase = vbases_begin(), + E = vbases_end(); VBase != E; ++VBase) { + CXXRecordDecl *VBaseClassDecl + = cast(VBase->getType()->getAs()->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(Base->getType()->getAs()->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 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(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(ConvDecl->getTemplatedDecl()) && + "Function template is not a conversion function template"); + Conversions.addOverload(ConvDecl); +} + +CXXRecordDecl *CXXRecordDecl::getInstantiatedFromMemberClass() const { + if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) + return cast(MSInfo->getInstantiatedFrom()); + + return 0; +} + +MemberSpecializationInfo *CXXRecordDecl::getMemberSpecializationInfo() const { + return TemplateOrInstantiation.dyn_cast(); +} + +void +CXXRecordDecl::setInstantiationOfMemberClass(CXXRecordDecl *RD, + TemplateSpecializationKind TSK) { + assert(TemplateOrInstantiation.isNull() && + "Previous template or instantiation?"); + assert(!isa(this)); + TemplateOrInstantiation + = new (getASTContext()) MemberSpecializationInfo(RD, TSK); +} + +TemplateSpecializationKind CXXRecordDecl::getTemplateSpecializationKind() { + if (ClassTemplateSpecializationDecl *Spec + = dyn_cast(this)) + return Spec->getSpecializationKind(); + + if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) + return MSInfo->getTemplateSpecializationKind(); + + return TSK_Undeclared; +} + +void +CXXRecordDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) { + if (ClassTemplateSpecializationDecl *Spec + = dyn_cast(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(*Con)) + continue; + CXXConstructorDecl *Constructor = cast(*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(*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(*R.first)) + if (FD->getNumParams() == 1) + return false; + } + + return true; +} -typedef llvm::DenseMap *> +typedef llvm::DenseMap *> 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 *&Methods = (*OverriddenMethods)[this]; if (!Methods) Methods = new std::vector; - + 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(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(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(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(); 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(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()->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(ND) || isa(ND)) + D = ND; + else if (OverloadedFunctionDecl *Ovl = dyn_cast(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(D)) + return FD; + + if (FunctionTemplateDecl *FTD = dyn_cast(D)) + return FTD; + + assert(isa(D)); + return *Iter; +} + +OverloadIterator &OverloadIterator::operator++() { + if (isa(D) || isa(D)) { + D = 0; + return *this; + } + + if (++Iter == cast(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(D) || Iter == Other.Iter; +} + +FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + FriendUnion Friend, + SourceLocation FriendL) { +#ifndef NDEBUG + if (Friend.is()) { + NamedDecl *D = Friend.get(); + assert(isa(D) || + isa(D) || + isa(D) || + isa(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 54f13e14ba652..7f38ac1d9ad0a 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(*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(*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(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(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 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 &Protocols = ClassDecl->getReferencedProtocols(); for (ObjCList::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 &Protocols = - CatDecl->getReferencedProtocols(); - for (ObjCList::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 &Protocols = CatDecl->getReferencedProtocols(); for (ObjCList::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(getDeclContext()); + + if (ObjCInterfaceDecl *IFD = dyn_cast(CtxD)) { + if (ObjCImplementationDecl *ImplD = Ctx.getObjCImplementation(IFD)) + Redecl = ImplD->getMethod(getSelector(), isInstanceMethod()); + + } else if (ObjCCategoryDecl *CD = dyn_cast(CtxD)) { + if (ObjCCategoryImplDecl *ImplD = Ctx.getObjCImplementation(CD)) + Redecl = ImplD->getMethod(getSelector(), isInstanceMethod()); + + } else if (ObjCImplementationDecl *ImplD = + dyn_cast(CtxD)) { + if (ObjCInterfaceDecl *IFD = ImplD->getClassInterface()) + Redecl = IFD->getMethod(getSelector(), isInstanceMethod()); + + } else if (ObjCCategoryImplDecl *CImplD = + dyn_cast(CtxD)) { + if (ObjCCategoryDecl *CatD = CImplD->getCategoryClass()) + Redecl = CatD->getMethod(getSelector(), isInstanceMethod()); + } + + return Redecl ? Redecl : this; +} + +ObjCMethodDecl *ObjCMethodDecl::getCanonicalDecl() { + Decl *CtxD = cast(getDeclContext()); + + if (ObjCImplementationDecl *ImplD = dyn_cast(CtxD)) { + if (ObjCInterfaceDecl *IFD = ImplD->getClassInterface()) + if (ObjCMethodDecl *MD = IFD->getMethod(getSelector(), + isInstanceMethod())) + return MD; + + } else if (ObjCCategoryImplDecl *CImplD = + dyn_cast(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(getDeclContext())) - length += CID->getNameAsString().size()+1; - length += getSelector().getAsString().size(); // selector name - return length; -} - ObjCInterfaceDecl *ObjCMethodDecl::getClassInterface() { if (ObjCInterfaceDecl *ID = dyn_cast(getDeclContext())) return ID; if (ObjCCategoryDecl *CD = dyn_cast(getDeclContext())) return CD->getClassInterface(); - if (ObjCImplementationDecl *IMD = - dyn_cast(getDeclContext())) + if (ObjCImplDecl *IMD = dyn_cast(getDeclContext())) return IMD->getClassInterface(); - if (ObjCCategoryImplDecl *CID = - dyn_cast(getDeclContext())) - return CID->getClassInterface(); + + assert(!isa(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(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 &Protocols = + IDecl->getReferencedProtocols(); + + for (ObjCList::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(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(this)) { + if (IFace) + Ctx.setObjCImplementation(IFace, ImplD); + + } else if (ObjCCategoryImplDecl *ImplD = + dyn_cast_or_null(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(*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(*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 12e89cd80d197..9d0d836cf62b9 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& 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(this)); } static QualType GetBaseType(QualType T) { @@ -90,13 +93,13 @@ static QualType GetBaseType(QualType T) { while (!BaseType->isSpecifierType()) { if (isa(BaseType)) break; - else if (const PointerType* PTy = BaseType->getAsPointerType()) + else if (const PointerType* PTy = BaseType->getAs()) BaseType = PTy->getPointeeType(); else if (const ArrayType* ATy = dyn_cast(BaseType)) BaseType = ATy->getElementType(); - else if (const FunctionType* FTy = BaseType->getAsFunctionType()) + else if (const FunctionType* FTy = BaseType->getAs()) BaseType = FTy->getResultType(); - else if (const VectorType *VTy = BaseType->getAsVectorType()) + else if (const VectorType *VTy = BaseType->getAs()) 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& 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(DC); + AccessSpecifier CurAS = AS_none; + llvm::SmallVector 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(*D) && + if (isa(*D) && cast(*D)->isThisDeclarationADefinition()) Terminator = 0; else if (isa(*D) && cast(*D)->getBody()) Terminator = 0; else if (isa(*D) || isa(*D) || - isa(*D) || + isa(*D) || isa(*D) || isa(*D) || isa(*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(D->getType().getTypePtr())) { - const FunctionType *AFT = D->getType()->getAsFunctionType(); + const FunctionType *AFT = D->getType()->getAs(); 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()) + Proto += " __attribute((noreturn))"; + if (CXXConstructorDecl *CDecl = dyn_cast(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()) { + const CXXRecordDecl *BaseDecl = + cast(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(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()) { + const CXXRecordDecl *BaseDecl = + cast(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(Param)) { - - QualType ParamType = + + QualType ParamType = Context.getTypeDeclType(const_cast(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(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 &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 f1bd1b67d21e9..7836b3f827ce7 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::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(this)->end(), + iterator Param = const_cast(this)->end(), ParamBegin = const_cast(this)->begin(); while (Param != ParamBegin) { --Param; - + if (!(*Param)->isTemplateParameterPack() && - !(isa(*Param) && + !(isa(*Param) && cast(*Param)->hasDefaultArgument()) && !(isa(*Param) && cast(*Param)->hasDefaultArgument()) && !(isa(*Param) && cast(*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::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 TemplateArgs; - llvm::SmallVector 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(*Param)) { QualType ParamType = Context.getTypeDeclType(cast(*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(*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(*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()) + 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()) + return PartialSpec->PartialSpecialization->getSpecializedTemplate(); + return SpecializedTemplate.get(); +} + //===----------------------------------------------------------------------===// // 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 a17abde777303..101ddd2509336 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()) 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()) 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()) 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(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 *SpecialNames + llvm::FoldingSet *SpecialNames = static_cast*>(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:: getHashValue(clang::DeclarationName N) { return DenseMapInfo::getHashValue(N.getAsOpaquePtr()); diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 482e1062d88cb..0e4a29f916fa3 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 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(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(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(Val)) - ClonedVal = IntLit->Clone(C); - else - ClonedVal = cast(Val)->Clone(C); - return new (C) ImaginaryLiteral(ClonedVal, getType()); -} + std::string Proto = FD->getQualifiedNameAsString(Policy); + + const FunctionType *AFT = FD->getType()->getAs(); + const FunctionProtoType *FT = 0; + if (FD->hasWrittenPrototype()) + FT = dyn_cast(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(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(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(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 *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(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(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(CEE)) + return dyn_cast(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(getCallee()); if (!ICE) // FIXME: deal with more complex calls (e.g. (func)(), (*func)()). return 0; - + const DeclRefExpr *DRE = dyn_cast(ICE->getSubExpr()); if (!DRE) return 0; - + const FunctionDecl *FDecl = dyn_cast(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()) CalleeType = FnTypePtr->getPointeeType(); - else if (const BlockPointerType *BPT = CalleeType->getAsBlockPointerType()) + else if (const BlockPointerType *BPT = CalleeType->getAs()) CalleeType = BPT->getPointeeType(); - - const FunctionType *FnType = CalleeType->getAsFunctionType(); + + const FunctionType *FnType = CalleeType->getAs(); 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()); + 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(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()-> + getPointeeType()->getAs(); } -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(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(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(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(this); - const Expr *CalleeExpr = CE->getCallee()->IgnoreParenCasts(); - if (const DeclRefExpr *CalleeDRE = dyn_cast(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(CalleeDRE->getDecl())) - if (FD->getAttr() || - FD->getAttr() || FD->getAttr()) { - 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() || + FD->getAttr() || FD->getAttr()) { + 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(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(CS->body_back())) return E->isUnusedResultAWarning(Loc, R1, R2); - + Loc = cast(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(this)->getSubExpr() - ->isUnusedResultAWarning(Loc, R1, R2); + return false; Loc = cast(this)->getLParenLoc(); R1 = cast(this)->getSubExpr()->getSourceRange(); return true; @@ -602,7 +761,7 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, Loc = cast(this)->getTypeBeginLoc(); R1 = cast(this)->getSubExpr()->getSourceRange(); return true; - + case ImplicitCastExprClass: // Check the operand, since implicit casts are inserted by Sema return cast(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(this) + ->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2); case CXXExprWithTemporariesClass: return cast(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(Decl)) return NTTParm->getType()->isReferenceType(); return isa(Decl) || isa(Decl) || // C++ 3.10p2: An lvalue refers to an object or function. (Ctx.getLangOptions().CPlusPlus && - (isa(Decl) || isa(Decl))); + (isa(Decl) || isa(Decl) || + isa(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(this)->getBase()->getType()->isVectorType()) return cast(this)->getBase()->isLvalue(Ctx); return LV_Valid; - case DeclRefExprClass: + case DeclRefExprClass: case QualifiedDeclRefExprClass: { // C99 6.5.1p2 const NamedDecl *RefdDecl = cast(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(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(this)->isLvalueCast()? LV_Valid + return cast(this)->isLvalueCast()? LV_Valid : LV_InvalidExpression; case ParenExprClass: // C99 6.5.1p5 return cast(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(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(this)) { - const BlockDeclRefExpr *BDR = cast(this); + if (const BlockDeclRefExpr *BDR = dyn_cast(this)) { if (!BDR->isByRef() && isa(BDR->getDecl())) return MLV_NotBlockQualified; } + // Assigning to an 'implicit' property? + if (const ObjCImplicitSetterGetterRefExpr* Expr = + dyn_cast(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()) { + if (r->hasConstFields()) return MLV_ConstQualified; } - - // Assigning to an 'implicit' property? - else if (isa(this)) { - const ObjCKVCRefExpr* KVCExpr = cast(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(this)->getSubExpr()->hasGlobalStorage(); - case ImplicitCastExprClass: - return cast(this)->getSubExpr()->hasGlobalStorage(); - case CompoundLiteralExprClass: - return cast(this)->isFileScope(); - case DeclRefExprClass: - case QualifiedDeclRefExprClass: { - const Decl *D = cast(this)->getDecl(); - if (const VarDecl *VD = dyn_cast(D)) - return VD->hasGlobalStorage(); - if (isa(D)) - return true; - return false; - } - case MemberExprClass: { - const MemberExpr *M = cast(this); - return !M->isArrow() && M->getBase()->hasGlobalStorage(); - } - case ArraySubscriptExprClass: - return cast(this)->getBase()->hasGlobalStorage(); - case PredefinedExprClass: - return true; - case CXXDefaultArgExprClass: - return cast(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(E)) E = P->getSubExpr(); - + return E; } @@ -1037,17 +1175,17 @@ Expr *Expr::IgnoreParenNoopCasts(ASTContext &Ctx) { E = P->getSubExpr(); continue; } - + if (CastExpr *P = dyn_cast(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(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(this)->getSubExpr()->isConstantInitializer(Ctx); - } case UnaryOperatorClass: { const UnaryOperator* Exp = cast(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(this); + if (Exp->getOpcode() == BinaryOperator::Sub && + isa(Exp->getLHS()->IgnoreParenNoopCasts(Ctx)) && + isa(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(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(this)->getSubExpr()->getType()->isIntegerType()) + return cast(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(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(E); if (CE->isBuiltinCall(Ctx)) @@ -1213,7 +1424,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { if (isa(cast(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(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(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(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(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(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(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()) { 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(this)) { // Ignore the ImplicitCastExpr type entirely. - return ICE->getSubExpr()->isNullPointerConstant(Ctx); + return ICE->getSubExpr()->isNullPointerConstant(Ctx, NPC); } else if (const ParenExpr *PE = dyn_cast(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(this)) { // See through default argument expressions - return DefaultArg->getExpr()->isNullPointerConstant(Ctx); + return DefaultArg->getExpr()->isNullPointerConstant(Ctx, NPC); } else if (isa(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(E)) if (FieldDecl *Field = dyn_cast(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()) 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(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(static_cast(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(static_cast(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 399c30255a8f2..cba0e220952e0 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 (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()) { 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()) { // Type traits are only parsed in C++, so we've got CXXRecords. return cast(Record->getDecl())->isPolymorphic(); } return false; case UTT_IsAbstract: - if (const RecordType *RT = QueriedType->getAsRecordType()) + if (const RecordType *RT = QueriedType->getAs()) return cast(RT->getDecl())->isAbstract(); return false; + case UTT_IsEmpty: + if (const RecordType *Record = QueriedType->getAs()) { + return !Record->getDecl()->isUnion() + && cast(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()) return cast(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()) + return cast(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()) + return cast(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()) return cast(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(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()); + 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 eb6b5b725ff59..94d22998ebbed 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 { 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(E->getDecl())) { return APValue(E, 0); } else if (VarDecl* VD = dyn_cast(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()->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()->getDecl(); const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD); FieldDecl *FD = dyn_cast(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 { 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()->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(); 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 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(E->getInitializer())); } -APValue +APValue VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) { - const VectorType *VT = E->getType()->getAsVectorType(); + const VectorType *VT = E->getType()->getAs(); unsigned NumInits = E->getNumInits(); unsigned NumElements = VT->getNumElements(); - + QualType EltTy = VT->getElementType(); llvm::SmallVector 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(); 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(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(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()->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(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(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 { 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()->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()) { 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(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 dd2fc14ab2a4c..c47a9dadbadd0 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(Type->getAsRecordType()->getDecl()); + const CXXRecordDecl *Decl + = static_cast(Type->getAs()->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 90ec4d33fdfee..d969776aa0ee7 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(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::template Inner), + // the type requires its own nested-name-specifier for uniqueness, so we + // suppress that nested-name-specifier during printing. + assert(!isa(T) && + "Qualified name type in nested-name-specifier"); + if (const TemplateSpecializationType *SpecType + = dyn_cast(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 9d87daa0bfd86..48251d52fd2a8 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(P) || isa(P))) { DirectChild = P; P = getParent(P); } - + if (!P) return false; - + switch (P->getStmtClass()) { default: return isa(P); @@ -78,7 +78,7 @@ bool ParentMap::isConsumedExpr(Expr* E) const { case Stmt::ForStmtClass: return DirectChild == cast(P)->getCond(); case Stmt::WhileStmtClass: - return DirectChild == cast(P)->getCond(); + return DirectChild == cast(P)->getCond(); case Stmt::DoStmtClass: return DirectChild == cast(P)->getCond(); case Stmt::IfStmtClass: diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp new file mode 100644 index 0000000000000..c79cc3c1dbb1a --- /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 +#include + +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(i->getType()->getAs()->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(i->getType()->getAs()->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(i->getType()->getAs()->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(i->getType()->getAs()->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(i->getType()->getAs()->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 &mark, + llvm::SmallSet &IndirectPrimary) { + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); i != e; ++i) { + const CXXRecordDecl *Base = + cast(i->getType()->getAs()->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(I->getType()->getAs()->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()) { + if (const CXXRecordDecl *RD = dyn_cast(RT->getDecl())) + return canPlaceRecordAtOffset(RD, Offset); + } + + if (const ConstantArrayType *AT = Ctx.getAsConstantArrayType(T)) { + QualType ElemTy = Ctx.getBaseElementType(AT); + const RecordType *RT = ElemTy->getAs(); + if (!RT) + return true; + const CXXRecordDecl *RD = dyn_cast(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(I->getType()->getAs()->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()) { + if (const CXXRecordDecl *RD = dyn_cast(RT->getDecl())) { + UpdateEmptyClassOffsets(RD, Offset); + return; + } + } + + if (const ConstantArrayType *AT = Ctx.getAsConstantArrayType(T)) { + QualType ElemTy = Ctx.getBaseElementType(AT); + const RecordType *RT = ElemTy->getAs(); + if (!RT) + return; + const CXXRecordDecl *RD = dyn_cast(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(); + + // The #pragma pack attribute specifies the maximum field alignment. + if (const PragmaPackAttr *PPA = D->getAttr()) + MaxFieldAlignment = PPA->getAlignment(); + + if (const AlignedAttr *AA = D->getAttr()) + UpdateAlignment(AA->getAlignment()); + + // If this is a C++ class, lay out the vtable and the non-virtual bases. + const CXXRecordDecl *RD = dyn_cast(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 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(); + + // The #pragma pack attribute specifies the maximum field alignment. + if (const PragmaPackAttr *PPA = D->getAttr()) + MaxFieldAlignment = PPA->getAlignment(); + + if (const AlignedAttr *AA = D->getAttr()) + UpdateAlignment(AA->getAlignment()); + + // Layout each ivar sequentially. + llvm::SmallVector 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(); + + 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 FieldInfo = Ctx.getTypeInfo(D->getType()); + uint64_t TypeSize = FieldInfo.first; + + FieldAlign = FieldInfo.second; + + if (FieldPacked) + FieldAlign = 1; + if (const AlignedAttr *AA = D->getAttr()) + 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()) { + unsigned AS = RT->getPointeeType().getAddressSpace(); + FieldSize = Ctx.Target.getPointerWidth(AS); + FieldAlign = Ctx.Target.getPointerAlign(AS); + } else { + std::pair FieldInfo = Ctx.getTypeInfo(D->getType()); + FieldSize = FieldInfo.first; + FieldAlign = FieldInfo.second; + } + + if (FieldPacked) + FieldAlign = 8; + if (const AlignedAttr *AA = D->getAttr()) + 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(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(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 0000000000000..6e4cdd2fe2ee5 --- /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 + +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 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, 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 IndirectPrimaryBases; + + /// EmptyClassOffsets - A map from offsets to empty record decls. + typedef std::multimap 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 &mark, + llvm::SmallSet &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 17577910d2a36..3a838fadafa41 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 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&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&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&Pieces, Pieces.push_back(AsmStringPiece(CurStringPiece)); return 0; } - + char CurChar = *CurPtr++; if (CurChar == '$') { CurStringPiece += "$$"; @@ -278,48 +274,48 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl&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&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&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 bc096bf0d9f39..0465999a94cc4 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(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(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, ""); 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, ">"); - + // } @@ -220,15 +223,15 @@ void StmtDumper::DumpDeclarator(Decl *D) { // Emit storage class for vardecls. if (VarDecl *V = dyn_cast(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(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 5c22e28894f9e..4f62b66e257df 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(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(decl)) + if (VarDecl* VD = dyn_cast(decl)) if (VD->Init) return; - + NextDecl(); } else if (inDeclGroup()) { - if (VarDecl* VD = dyn_cast(*DGI)) + if (VarDecl* VD = dyn_cast(*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(D)) { + + if (VarDecl* VD = dyn_cast(D)) { if (VariableArrayType* VAPtr = FindVA(VD->getType().getTypePtr())) { setVAPtr(VAPtr); return true; } - + if (VD->getInit()) return true; } else if (TypedefDecl* TD = dyn_cast(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(*DGI); return *VD->getInitAddress(); } - + assert (inDecl()); if (VarDecl* VD = dyn_cast(decl)) { diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index fec17fb22352b..05d0c26835456 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 << ""; } - + 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::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 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(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(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(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(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(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(Node->getCatchStmts()); - catchStmt; - catchStmt = + catchStmt; + catchStmt = static_cast(catchStmt->getNextCatchStmt())) { Indent() << "@catch("; if (catchStmt->getCatchParamDecl()) { @@ -401,19 +400,18 @@ void StmtPrinter::VisitObjCAtTryStmt(ObjCAtTryStmt *Node) { PrintRawDecl(DS); } OS << ")"; - if (CompoundStmt *CS = dyn_cast(catchStmt->getCatchBody())) - { - PrintRawCompoundStmt(CS); - OS << "\n"; - } + if (CompoundStmt *CS = dyn_cast(catchStmt->getCatchBody())) { + PrintRawCompoundStmt(CS); + OS << "\n"; + } } - - if (ObjCAtFinallyStmt *FS =static_cast( - Node->getFinallyStmt())) { + + if (ObjCAtFinallyStmt *FS = static_cast( + Node->getFinallyStmt())) { Indent() << "@finally"; PrintRawCompoundStmt(dyn_cast(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()->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(AFT)) { OS << "()"; } else if (!BD->param_empty() || cast(AFT)->isVariadic()) { @@ -1209,7 +1258,7 @@ void StmtPrinter::VisitBlockExpr(BlockExpr *Node) { (*AI)->getType().getAsStringInternal(ParamStr, Policy); OS << ParamStr; } - + const FunctionProtoType *FT = cast(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(this)); } diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp new file mode 100644 index 0000000000000..c4d42f6be2280 --- /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 { + 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(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(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(D)) { + ID.AddInteger(NTTP->getDepth()); + ID.AddInteger(NTTP->getIndex()); + VisitType(NTTP->getType()); + return; + } + + if (ParmVarDecl *Parm = dyn_cast(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(D)) { + ID.AddInteger(TTP->getDepth()); + ID.AddInteger(TTP->getIndex()); + return; + } + + if (OverloadedFunctionDecl *Ovl = dyn_cast(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 96b5218ba2f0b..61fd750ccc83f 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 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 : 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 << ""; - - 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 5b671c111fbfd..24588bc5f11f9 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()) return Template; - + if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) return QTN->getTemplateDecl(); return 0; } +OverloadedFunctionDecl *TemplateName::getAsOverloadedFunctionDecl() const { + if (OverloadedFunctionDecl *Ovl + = Storage.dyn_cast()) + 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(Template); + return isa(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()) OS << Template->getIdentifier()->getName(); + else if (OverloadedFunctionDecl *Ovl + = Storage.dyn_cast()) + 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(Template); +} + +OverloadedFunctionDecl * +QualifiedTemplateName::getOverloadedFunctionDecl() const { + return dyn_cast(Template); +} + diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 4e061a9fbe625..0293862baedb4 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(this)) return ATy->getElementType().getTypePtr(); - + // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers - if (ArrayType *AT = dyn_cast(CanonicalType.getUnqualifiedType())) - return AT->getElementType().getTypePtr(); + if (!isa(CanonicalType)) return 0; - } - + // If this is a typedef for an array type, strip the typedef off without // losing all typedef information. - return cast(getDesugaredType())->getElementType().getTypePtr(); + return cast(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(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(this)) - return TDT->LookThroughTypedefs().getDesugaredType(); - if (const TypeOfExprType *TOE = dyn_cast(this)) - return TOE->getUnderlyingExpr()->getType().getDesugaredType(); - if (const TypeOfType *TOT = dyn_cast(this)) - return TOT->getUnderlyingType().getDesugaredType(); - if (const DecltypeType *DTT = dyn_cast(this)) - return DTT->getUnderlyingExpr()->getType().getDesugaredType(); - if (const TemplateSpecializationType *Spec - = dyn_cast(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(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(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(CanonicalType)) return BT->getKind() == BuiltinType::Void; - if (const ExtQualType *AS = dyn_cast(CanonicalType)) - return AS->getBaseType()->isVoidType(); return false; } @@ -151,18 +169,16 @@ bool Type::isObjectType() const { if (isa(CanonicalType) || isa(CanonicalType) || isa(CanonicalType) || isVoidType()) return false; - if (const ExtQualType *AS = dyn_cast(CanonicalType)) - return AS->getBaseType()->isObjectType(); return true; } bool Type::isDerivedType() const { switch (CanonicalType->getTypeClass()) { - case ExtQual: - return cast(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()) return RT->getDecl()->isClass(); return false; } bool Type::isStructureType() const { - if (const RecordType *RT = getAsRecordType()) + if (const RecordType *RT = getAs()) return RT->getDecl()->isStruct(); return false; } bool Type::isVoidPointerType() const { - if (const PointerType *PT = getAsPointerType()) + if (const PointerType *PT = getAs()) return PT->getPointeeType()->isVoidType(); return false; } bool Type::isUnionType() const { - if (const RecordType *RT = getAsRecordType()) + if (const RecordType *RT = getAs()) return RT->getDecl()->isUnion(); return false; } @@ -200,192 +216,29 @@ bool Type::isUnionType() const { bool Type::isComplexType() const { if (const ComplexType *CT = dyn_cast(CanonicalType)) return CT->getElementType()->isFloatingType(); - if (const ExtQualType *AS = dyn_cast(CanonicalType)) - return AS->getBaseType()->isComplexType(); return false; } bool Type::isComplexIntegerType() const { // Check for GCC complex integer extension. - if (const ComplexType *CT = dyn_cast(CanonicalType)) - return CT->getElementType()->isIntegerType(); - if (const ExtQualType *AS = dyn_cast(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(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(CanonicalType)) { - // Look through type qualifiers (e.g. ExtQualType's). - if (isa(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(getDesugaredType()); -} - -const BuiltinType *Type::getAsBuiltinType() const { - // If this is directly a builtin type, return it. - if (const BuiltinType *BTy = dyn_cast(this)) - return BTy; - - // If the canonical form of this type isn't a builtin type, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers (e.g. ExtQualType's). - if (isa(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(getDesugaredType()); -} - -const FunctionType *Type::getAsFunctionType() const { - // If this is directly a function type, return it. - if (const FunctionType *FTy = dyn_cast(this)) - return FTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers - if (isa(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(getDesugaredType()); -} - -const FunctionNoProtoType *Type::getAsFunctionNoProtoType() const { - return dyn_cast_or_null(getAsFunctionType()); -} - -const FunctionProtoType *Type::getAsFunctionProtoType() const { - return dyn_cast_or_null(getAsFunctionType()); -} - - -const PointerType *Type::getAsPointerType() const { - // If this is directly a pointer type, return it. - if (const PointerType *PTy = dyn_cast(this)) - return PTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers - if (isa(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(getDesugaredType()); -} - -const BlockPointerType *Type::getAsBlockPointerType() const { - // If this is directly a block pointer type, return it. - if (const BlockPointerType *PTy = dyn_cast(this)) - return PTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers - if (isa(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(getDesugaredType()); -} - -const ReferenceType *Type::getAsReferenceType() const { - // If this is directly a reference type, return it. - if (const ReferenceType *RTy = dyn_cast(this)) - return RTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers - if (isa(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(getDesugaredType()); -} - -const LValueReferenceType *Type::getAsLValueReferenceType() const { - // If this is directly an lvalue reference type, return it. - if (const LValueReferenceType *RTy = dyn_cast(this)) - return RTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers - if (isa(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(getDesugaredType()); -} - -const RValueReferenceType *Type::getAsRValueReferenceType() const { - // If this is directly an rvalue reference type, return it. - if (const RValueReferenceType *RTy = dyn_cast(this)) - return RTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers - if (isa(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(getDesugaredType()); + if (const ComplexType *Complex = getAs()) + 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(this)) - return MTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers - if (isa(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(getDesugaredType()); +QualType Type::getPointeeType() const { + if (const PointerType *PT = getAs()) + return PT->getPointeeType(); + if (const ObjCObjectPointerType *OPT = getAs()) + return OPT->getPointeeType(); + if (const BlockPointerType *BPT = getAs()) + 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()) return PT->getPointeeType()->isVariablyModifiedType(); - if (const ReferenceType *RT = getAsReferenceType()) + if (const ReferenceType *RT = getAs()) return RT->getPointeeType()->isVariablyModifiedType(); - if (const MemberPointerType *PT = getAsMemberPointerType()) + if (const MemberPointerType *PT = getAs()) 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()) 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(this)) - return RTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers - if (isa(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(getDesugaredType()); -} - -const TagType *Type::getAsTagType() const { - // If this is directly a tag type, return it. - if (const TagType *TagTy = dyn_cast(this)) - return TagTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers - if (isa(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(getDesugaredType()); -} - const RecordType *Type::getAsStructureType() const { // If this is directly a structure type, return it. if (const RecordType *RT = dyn_cast(this)) { @@ -468,24 +285,21 @@ const RecordType *Type::getAsStructureType() const { if (const RecordType *RT = dyn_cast(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(getDesugaredType()); + return cast(getUnqualifiedDesugaredType()); } - // Look through type qualifiers - if (isa(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(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(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(getDesugaredType()); - } - - // Look through type qualifiers - if (isa(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(CanonicalType.getUnqualifiedType()); -} - -const ComplexType *Type::getAsComplexType() const { - // Are we directly a complex type? - if (const ComplexType *CTy = dyn_cast(this)) - return CTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers - if (isa(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(getDesugaredType()); -} - -const VectorType *Type::getAsVectorType() const { - // Are we directly a vector type? - if (const VectorType *VTy = dyn_cast(this)) - return VTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers - if (isa(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsVectorType(); - return 0; + return cast(getUnqualifiedDesugaredType()); } - // If this is a typedef for a vector type, strip the typedef off without - // losing all typedef information. - return cast(getDesugaredType()); -} - -const ExtVectorType *Type::getAsExtVectorType() const { - // Are we directly an OpenCU vector type? - if (const ExtVectorType *VTy = dyn_cast(this)) - return VTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers - if (isa(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(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(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(CanonicalType.getUnqualifiedType()); + if (const ObjCInterfaceType *OIT = getAs()) + 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(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()) { 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(CanonicalType); +const ObjCObjectPointerType *Type::getAsObjCInterfacePointerType() const { + if (const ObjCObjectPointerType *OPT = getAs()) { + 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(CanonicalType); +const CXXRecordDecl *Type::getCXXRecordDeclForPointerType() const { + if (const PointerType *PT = getAs()) + if (const RecordType *RT = PT->getPointeeType()->getAs()) + return dyn_cast(RT->getDecl()); + return 0; } bool Type::isIntegerType() const { @@ -620,8 +365,6 @@ bool Type::isIntegerType() const { return true; if (const VectorType *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isIntegerType(); - if (const ExtQualType *EXTQT = dyn_cast(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(CanonicalType)) return true; - if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) - return EXTQT->getBaseType()->isIntegralType(); return false; } bool Type::isEnumeralType() const { if (const TagType *TT = dyn_cast(CanonicalType)) return TT->getDecl()->isEnum(); - if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) - return EXTQT->getBaseType()->isEnumeralType(); return false; } bool Type::isBooleanType() const { if (const BuiltinType *BT = dyn_cast(CanonicalType)) return BT->getKind() == BuiltinType::Bool; - if (const ExtQualType *EXTQT = dyn_cast(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(CanonicalType)) - return EXTQT->getBaseType()->isCharType(); return false; } bool Type::isWideCharType() const { if (const BuiltinType *BT = dyn_cast(CanonicalType)) return BT->getKind() == BuiltinType::WChar; - if (const ExtQualType *EXTQT = dyn_cast(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(CanonicalType)) return ET->getDecl()->getIntegerType()->isSignedIntegerType(); - + if (const FixedWidthIntType *FWIT = dyn_cast(CanonicalType)) return FWIT->isSigned(); - + if (const VectorType *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isSignedIntegerType(); - if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) - return EXTQT->getBaseType()->isSignedIntegerType(); return false; } @@ -718,8 +449,6 @@ bool Type::isUnsignedIntegerType() const { if (const VectorType *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isUnsignedIntegerType(); - if (const ExtQualType *EXTQT = dyn_cast(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(CanonicalType)) return VT->getElementType()->isFloatingType(); - if (const ExtQualType *EXTQT = dyn_cast(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(CanonicalType)) return VT->getElementType()->isRealFloatingType(); - if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) - return EXTQT->getBaseType()->isRealFloatingType(); return false; } @@ -757,8 +482,6 @@ bool Type::isRealType() const { return true; if (const VectorType *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isRealType(); - if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) - return EXTQT->getBaseType()->isRealType(); return false; } @@ -772,8 +495,6 @@ bool Type::isArithmeticType() const { return ET->getDecl()->isDefinition(); if (isa(CanonicalType)) return true; - if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) - return EXTQT->getBaseType()->isArithmeticType(); return isa(CanonicalType) || isa(CanonicalType); } @@ -787,8 +508,6 @@ bool Type::isScalarType() const { return true; return false; } - if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) - return EXTQT->getBaseType()->isScalarType(); if (isa(CanonicalType)) return true; return isa(CanonicalType) || @@ -815,8 +534,6 @@ bool Type::isAggregateType() const { return true; } - if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) - return EXTQT->getBaseType()->isAggregateType(); return isa(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(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(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(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(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(cast(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()) 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()) 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 ""; case Dependent: return ""; - case UndeducedAuto: return ""; + 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(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(CurType); - if (TDT == 0) - return QualType(CurType.getTypePtr(), TypeQuals); - } + do { + CurType = TDT->getDecl()->getUnderlyingType(); + TDT = dyn_cast(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(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(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(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(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(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(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(DC)) { if (NS->getIdentifier()) MyPart = NS->getNameAsString(); - } else if (ClassTemplateSpecializationDecl *Spec + } else if (ClassTemplateSpecializationDecl *Spec = dyn_cast(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 0000000000000..c24477ae81c5f --- /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 { +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(this)) + return DL->getTypeSpecLoc(); + return cast(*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 { +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 { +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 { +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 { +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 { +public: + bool VisitDeclaratorLoc(DeclaratorLoc TyLoc) { return true; } +}; + +} + +bool DeclaratorLoc::classof(const TypeLoc *TL) { + return DeclaratorLocChecker().Visit(*TL); +} + +//===----------------------------------------------------------------------===// +// DefaultTypeSpecLoc Implementation +//===----------------------------------------------------------------------===// + +namespace { + +class DefaultTypeSpecLocChecker : + public TypeLocVisitor { +public: + bool VisitDefaultTypeSpecLoc(DefaultTypeSpecLoc TyLoc) { return true; } +}; + +} + +bool DefaultTypeSpecLoc::classof(const TypeLoc *TL) { + return DefaultTypeSpecLocChecker().Visit(*TL); +} + +//===----------------------------------------------------------------------===// +// TypedefLoc Implementation +//===----------------------------------------------------------------------===// + +namespace { + +class TypedefLocChecker : public TypeLocVisitor { +public: + bool VisitTypedefLoc(TypedefLoc TyLoc) { return true; } +}; + +} + +bool TypedefLoc::classof(const TypeLoc *TL) { + return TypedefLocChecker().Visit(*TL); +} + +//===----------------------------------------------------------------------===// +// ObjCInterfaceLoc Implementation +//===----------------------------------------------------------------------===// + +namespace { + +class ObjCInterfaceLocChecker : + public TypeLocVisitor { +public: + bool VisitObjCInterfaceLoc(ObjCInterfaceLoc TyLoc) { return true; } +}; + +} + +bool ObjCInterfaceLoc::classof(const TypeLoc *TL) { + return ObjCInterfaceLocChecker().Visit(*TL); +} + +//===----------------------------------------------------------------------===// +// ObjCProtocolListLoc Implementation +//===----------------------------------------------------------------------===// + +namespace { + +class ObjCProtocolListLocChecker : + public TypeLocVisitor { +public: + bool VisitObjCProtocolListLoc(ObjCProtocolListLoc TyLoc) { return true; } +}; + +} + +bool ObjCProtocolListLoc::classof(const TypeLoc *TL) { + return ObjCProtocolListLocChecker().Visit(*TL); +} + +//===----------------------------------------------------------------------===// +// PointerLoc Implementation +//===----------------------------------------------------------------------===// + +namespace { + +class PointerLocChecker : public TypeLocVisitor { +public: + bool VisitPointerLoc(PointerLoc TyLoc) { return true; } +}; + +} + +bool PointerLoc::classof(const TypeLoc *TL) { + return PointerLocChecker().Visit(*TL); +} + +//===----------------------------------------------------------------------===// +// BlockPointerLoc Implementation +//===----------------------------------------------------------------------===// + +namespace { + +class BlockPointerLocChecker : + public TypeLocVisitor { +public: + bool VisitBlockPointerLoc(BlockPointerLoc TyLoc) { return true; } +}; + +} + +bool BlockPointerLoc::classof(const TypeLoc *TL) { + return BlockPointerLocChecker().Visit(*TL); +} + +//===----------------------------------------------------------------------===// +// MemberPointerLoc Implementation +//===----------------------------------------------------------------------===// + +namespace { + +class MemberPointerLocChecker : + public TypeLocVisitor { +public: + bool VisitMemberPointerLoc(MemberPointerLoc TyLoc) { return true; } +}; + +} + +bool MemberPointerLoc::classof(const TypeLoc *TL) { + return MemberPointerLocChecker().Visit(*TL); +} + +//===----------------------------------------------------------------------===// +// ReferenceLoc Implementation +//===----------------------------------------------------------------------===// + +namespace { + +class ReferenceLocChecker : public TypeLocVisitor { +public: + bool VisitReferenceLoc(ReferenceLoc TyLoc) { return true; } +}; + +} + +bool ReferenceLoc::classof(const TypeLoc *TL) { + return ReferenceLocChecker().Visit(*TL); +} + +//===----------------------------------------------------------------------===// +// FunctionLoc Implementation +//===----------------------------------------------------------------------===// + +namespace { + +class FunctionLocChecker : public TypeLocVisitor { +public: + bool VisitFunctionLoc(FunctionLoc TyLoc) { return true; } +}; + +} + +bool FunctionLoc::classof(const TypeLoc *TL) { + return FunctionLocChecker().Visit(*TL); +} + +//===----------------------------------------------------------------------===// +// ArrayLoc Implementation +//===----------------------------------------------------------------------===// + +namespace { + +class ArrayLocChecker : public TypeLocVisitor { +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 0000000000000..a4cb66be04b30 --- /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(D)) + return FD->getBody(); + else if (const ObjCMethodDecl *MD = dyn_cast(D)) + return MD->getBody(); + + llvm::llvm_unreachable("unknown code decl"); +} + +const ImplicitParamDecl *AnalysisContext::getSelfDecl() const { + if (const ObjCMethodDecl *MD = dyn_cast(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(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(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 0000000000000..c2733faa683cc --- /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(D) || isa(D)) { + const NamedDecl *ND = cast(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 cb89d30651079..d0b8289528542 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 ConstNotEqTy; typedef llvm::ImmutableMap ConstEqTy; - + static int ConstEqIndex = 0; static int ConstNotEqIndex = 0; namespace clang { template<> struct GRStateTrait : public GRStatePartialTrait { - static inline void* GDMIndex() { return &ConstNotEqIndex; } + static inline void* GDMIndex() { return &ConstNotEqIndex; } }; template<> struct GRStateTrait : public GRStatePartialTrait { - 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(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(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(); 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(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(); - + 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 aa85769157e7a..af300f36fa721 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(T->getPointeeType().getTypePtr()); - } - // FIXME: Support ObjCQualifiedIdType? + if (const ObjCObjectPointerType *PT = + Receiver->getType()->getAs()) + 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* 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* N, +bool BasicObjCFoundationChecks::Audit(ExplodedNode* N, GRStateManager&) { - - ObjCMessageExpr* ME = + + const ObjCMessageExpr* ME = cast(cast(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* N, } static inline bool isNil(SVal X) { - return isa(X); + return isa(X); } //===----------------------------------------------------------------------===// // Error reporting. //===----------------------------------------------------------------------===// -bool BasicObjCFoundationChecks::CheckNilArg(NodeTy* N, unsigned Arg) { - ObjCMessageExpr* ME = +bool BasicObjCFoundationChecks::CheckNilArg(ExplodedNode* N, unsigned Arg) { + const ObjCMessageExpr* ME = cast(cast(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* N, GRStateManager&); - + + bool Audit(ExplodedNode* N, GRStateManager&); + private: - void AddError(const TypedRegion* R, Expr* Ex, ExplodedNode *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 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 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(); } - + 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* N,GRStateManager&){ - CallExpr* CE = cast(cast(N->getLocation()).getStmt()); - Expr* Callee = CE->getCallee(); - SVal CallV = N->getState()->getSVal(Callee); +bool AuditCFNumberCreate::Audit(ExplodedNode* N,GRStateManager&){ + const CallExpr* CE = + cast(cast(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(&TheTypeVal); - + if (!V) return false; - + uint64_t NumberKind = V->getValue().getLimitedValue(); Optional 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(&TheValueExpr); if (!LV) return false; - - const TypedRegion* R = dyn_cast(LV->getRegion()); - if (!R) return false; - - while (const TypedViewRegion* ATR = dyn_cast(R)) { - R = dyn_cast(ATR->getSuperRegion()); - if (!R) return false; - } - + + const TypedRegion* R = dyn_cast(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 *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(cast(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 5c9701ecdd36f..1271ae4ab1c04 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 19d641ee9753a..a4f451f364906 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 BindingsTy; +typedef llvm::ImmutableMap 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& RegionRoots); + /// It updatees the GRState object in place with the values removed. + void RemoveDeadBindings(GRState &state, Stmt* Loc, SymbolReaper& SymReaper, + llvm::SmallVectorImpl& 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(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(BaseL)) { const MemRegion *BaseR = cast(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(Base); + + Loc BaseL = cast(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(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(Base); + + Loc BaseL = cast(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(BaseL).getRegion(); - + if (isa(R)) { // int x; // char* y = (char*) &x; @@ -215,12 +206,12 @@ SVal BasicStoreManager::getLValueElement(const GRState *state, // y[0] = 'a'; return Base; } - + if (isa(R) || isa(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(); 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(loc)) - return UnknownVal(); - - assert (!isa(loc)); - + return SValuator::CastResult(state, UnknownVal()); + + assert(!isa(loc)); + switch (loc.getSubKind()) { case loc::MemRegionKind: { const MemRegion* R = cast(loc).getRegion(); - + if (const ElementRegion *ER = dyn_cast(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(R) || isa(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(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)) return store; const MemRegion* R = cast(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(R)) { // FIXME: Should check for index 0. QualType T = ER->getLocationType(C); - + if (isHigherOrderRawPtr(T, C)) R = ER->getSuperRegion(); - } - + } + if (!(isa(R) || isa(R))) return store; - - // We only track bindings to self.ivar. - if (const ObjCIvarRegion *IVR = dyn_cast(R)) - if (IVR->getSuperRegion() != SelfRegion) - return store; - + + const TypedRegion *TyR = cast(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(&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(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).getRegion(); - + if (!(isa(R) || isa(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& RegionRoots) + llvm::SmallVectorImpl& 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(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 Marked; - + while (!RegionRoots.empty()) { const MemRegion* MR = RegionRoots.back(); RegionRoots.pop_back(); - + while (MR) { if (const SymbolicRegion* SymR = dyn_cast(MR)) { SymReaper.markLive(SymR->getSymbol()); @@ -421,17 +415,17 @@ BasicStoreManager::RemoveDeadBindings(const GRState *state, Stmt* Loc, else if (isa(MR) || isa(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(X)) break; - + const loc::MemRegionVal& LVD = cast(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(*CI)) { @@ -473,25 +469,25 @@ Store BasicStoreManager::scanForIvars(Stmt *B, const Decl* SelfDecl, Store St) { if (const DeclRefExpr *DR = dyn_cast(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(ND)) { - const Decl& CD = StateMgr.getCodeDecl(); + const Decl& CD = *InitLoc->getDecl(); if (const ObjCMethodDecl* MD = dyn_cast(&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(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(R) || isa(R))) + return state; + + QualType T = cast(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 72ad0a5ed8f1d..b33c277f86f90 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 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 SValData; typedef std::pair SValPair; @@ -33,7 +40,7 @@ template<> struct FoldingSetTrait { ID.AddPointer( (void*) X.second); } }; - + template<> struct FoldingSetTrait { 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 FoldNodeTy; - + X.Profile(ID); FoldNodeTy* P = APSIntSet.FindNodeOrInsertPos(ID, InsertPos); - - if (!P) { + + if (!P) { P = (FoldNodeTy*) BPAlloc.Allocate(); 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 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(); + 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& 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 FoldNodeTy; FoldNodeTy* P = Map.FindNodeOrInsertPos(ID, InsertPos); - - if (!P) { + + if (!P) { P = (FoldNodeTy*) BPAlloc.Allocate(); 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& 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 FoldNodeTy; FoldNodeTy* P = Map.FindNodeOrInsertPos(ID, InsertPos); - - if (!P) { + + if (!P) { P = (FoldNodeTy*) BPAlloc.Allocate(); 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 3db96ca9eacba..8235f4acb179a 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(&P)) - return PS->getStmt(); +static inline const Stmt* GetStmt(ProgramPoint P) { + if (const StmtPoint* SP = dyn_cast(&P)) + return SP->getStmt(); else if (const BlockEdge* BE = dyn_cast(&P)) return BE->getSrc()->getTerminator(); - + return 0; } -static inline const ExplodedNode* -GetPredecessorNode(const ExplodedNode* N) { +static inline const ExplodedNode* +GetPredecessorNode(const ExplodedNode* N) { return N->pred_empty() ? NULL : *(N->pred_begin()); } -static inline const ExplodedNode* -GetSuccessorNode(const ExplodedNode* N) { +static inline const ExplodedNode* +GetSuccessorNode(const ExplodedNode* N) { return N->succ_empty() ? NULL : *(N->succ_begin()); } -static Stmt* GetPreviousStmt(const ExplodedNode* 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* 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* N) { default: break; } + + // Some expressions don't have locations. + if (S->getLocStart().isInvalid()) + continue; + return S; } - + return 0; } -static inline Stmt* GetCurrentOrPreviousStmt(const ExplodedNode* 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* 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* N) { // PathDiagnosticBuilder and its associated routines and helper objects. //===----------------------------------------------------------------------===// -typedef llvm::DenseMap*, -const ExplodedNode*> NodeBackMap; +typedef llvm::DenseMap 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* getOriginalNode(const ExplodedNode* 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 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* N); - + + PathDiagnosticLocation ExecutionContinues(const ExplodedNode* N); + PathDiagnosticLocation ExecutionContinues(llvm::raw_string_ostream& os, - const ExplodedNode* 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* 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* 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(getCodeDecl()) ? "method" : "function") << '.'; - + << (isa(N->getLocationContext()->getDecl()) ? + "method" : "function") << '.'; + return Loc; } static bool IsNested(const Stmt *S, ParentMap &PM) { if (isa(S) && PM.isConsumedExpr(cast(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(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(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(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(Parent)->getBody() == S) - return PathDiagnosticLocation(S, SMgr); - break; + return PathDiagnosticLocation(S, SMgr); + break; case Stmt::IfStmtClass: if (cast(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(S)) { // Special case: the binary operator represents the initialization @@ -320,86 +326,86 @@ PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) { //===----------------------------------------------------------------------===// static const VarDecl* -GetMostRecentVarDeclBinding(const ExplodedNode* 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(P)) continue; - - DeclRefExpr* DR = dyn_cast(cast(P).getStmt()); - + + const DeclRefExpr* DR = dyn_cast(cast(P).getStmt()); + if (!DR) continue; - + SVal Y = N->getState()->getSVal(DR); - + if (X != Y) continue; - - VarDecl* VD = dyn_cast(DR->getDecl()); - + + const VarDecl* VD = dyn_cast(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* Pred; - PathDiagnostic& PD; + const ExplodedNode* Pred; + PathDiagnostic& PD; BugReporter& BR; - + public: - + NotableSymbolHandler(SymbolRef sym, const GRState* prevst, const Stmt* s, - GRStateManager& vmgr, const ExplodedNode* 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(S)) { if (!B->isAssignmentOp()) return true; - + // What variable did we assign to? DeclRefExpr* DR = dyn_cast(B->getLHS()->IgnoreParenCasts()); - + if (!DR) return true; - + VD = dyn_cast(DR->getDecl()); } else if (const DeclStmt* DS = dyn_cast(S)) { @@ -408,42 +414,42 @@ public: // holds by contruction in the CFG. VD = dyn_cast(*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* N, +static void HandleNotableSymbol(const ExplodedNode* N, const Stmt* S, SymbolRef Sym, BugReporter& BR, PathDiagnostic& PD) { - - const ExplodedNode* Pred = N->pred_empty() ? 0 : *N->pred_begin(); + + const 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(BR).getStateManager(); @@ -454,34 +460,34 @@ static void HandleNotableSymbol(const ExplodedNode* N, namespace { class VISIBILITY_HIDDEN ScanNotableSymbols : public StoreManager::BindingsHandler { - + llvm::SmallSet AlreadyProcessed; - const ExplodedNode* N; - Stmt* S; + const ExplodedNode* N; + const Stmt* S; GRBugReporter& BR; PathDiagnostic& PD; - + public: - ScanNotableSymbols(const ExplodedNode* 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 *N) { + const ExplodedNode *N) { SourceManager& SMgr = PDB.getSourceManager(); - const ExplodedNode* 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(&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(S); + os << "Control jumps to 'case "; + CaseStmt* Case = cast(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(LHS)) { // FIXME: Maybe this should be an assertion. Are there cases // were it is not an EnumConstantDecl? EnumConstantDecl* D = dyn_cast(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(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(&P)) { + + if (const PostStmt* PS = dyn_cast(&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(S); - + if (!E) return false; - - E = E->IgnoreParenCasts(); - + + E = E->IgnoreParenCasts(); + if (isa(E)) return true; - + if (const BinaryOperator *B = dyn_cast(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 CLocs; typedef std::vector::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(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(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 *N) { - - + const ExplodedNode *N) { + + EdgeBuilder EB(PD, PDB); - const ExplodedNode* 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(&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(Loop)) CS = dyn_cast(FS->getBody()); else if (const WhileStmt *WS = dyn_cast(Loop)) - CS = dyn_cast(WS->getBody()); + CS = dyn_cast(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(&P)) { + if (const BlockEntrance *BE = dyn_cast(&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(&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* 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(getStmt(BR))) { +void BugReport::getRanges(const SourceRange*& beg, const SourceRange*& end) { + if (const Expr* E = dyn_cast_or_null(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(S)) + if (const MemberExpr *ME = dyn_cast(S)) return ME->getMemberLoc(); + // For binary operators, return the location of the operator. + if (const BinaryOperator *B = dyn_cast(S)) + return B->getOperatorLoc(); return S->getLocStart(); } @@ -1261,8 +1280,8 @@ SourceLocation BugReport::getLocation() const { return FullSourceLoc(); } -PathDiagnosticPiece* BugReport::VisitNode(const ExplodedNode* N, - const ExplodedNode* 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& -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*, NodeBackMap*>, - std::pair*, unsigned> > -MakeReportGraph(const ExplodedGraph* G, - const ExplodedNode** NStart, - const ExplodedNode** NEnd) { - +static std::pair, + std::pair > +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* GTrim; - InterExplodedGraphMap* NMap; + ExplodedGraph* GTrim; + InterExplodedGraphMap* NMap; llvm::DenseMap 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 > AutoReleaseGTrim(GTrim); - llvm::OwningPtr > AutoReleaseNMap(NMap); - + llvm::OwningPtr AutoReleaseGTrim(GTrim); + llvm::OwningPtr 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*> WS; - typedef llvm::DenseMap*,unsigned> IndexMapTy; + std::queue WS; + typedef llvm::DenseMap IndexMapTy; IndexMapTy IndexMap; - for (const ExplodedNode** I = NStart; I != NEnd; ++I) - if (const ExplodedNode *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 *GNew = - new ExplodedGraph(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 Visited; - + unsigned cnt = 0; - const ExplodedNode* Root = 0; - + const ExplodedNode* Root = 0; + while (!WS.empty()) { - const ExplodedNode* Node = WS.front(); + const ExplodedNode* Node = WS.front(); WS.pop(); - + if (Visited.find(Node) != Visited.end()) continue; - + Visited[Node] = cnt++; - + if (Node->pred_empty()) { Root = Node; break; } - - for (ExplodedNode::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 *Last = 0, *First = 0; + ExplodedNode *Last = 0, *First = 0; NodeBackMap *BM = new NodeBackMap(); unsigned NodeIndex = 0; - - for ( const ExplodedNode *N = Root ;;) { + + for ( const ExplodedNode *N = Root ;;) { // Lookup the number associated with the current node. llvm::DenseMap::iterator I = Visited.find(N); assert(I != Visited.end()); - + // Create the equivalent node in the new graph with the same state // and location. - ExplodedNode* NewN = - GNew->getNode(N->getLocation(), N->getState()); - + ExplodedNode* NewN = GNew->getNode(N->getLocation(), N->getState()); + // Store the mapping to the original node. llvm::DenseMap::iterator IMitr=InverseMap.find(N); assert(IMitr != InverseMap.end() && "No mapping to original node."); - (*BM)[NewN] = (const ExplodedNode*) 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*)(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::const_succ_iterator SI = N->succ_begin(); - ExplodedNode::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* G, static void CompactPathDiagnostic(PathDiagnostic &PD, const SourceManager& SM) { typedef std::vector > MacroStackTy; - + typedef std::vector 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(*I)) if (!MP->containsEvent()) { delete MP; continue; } - + PD.push_back(*I); } } void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD, BugReportEquivClass& EQ) { - - std::vector*> Nodes; - + + std::vector Nodes; + for (BugReportEquivClass::iterator I=EQ.begin(), E=EQ.end(); I!=E; ++I) { - const ExplodedNode* 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*, NodeBackMap*>, - std::pair*, unsigned> >& + // node to a root. + const std::pair, + std::pair >& 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 > ReportGraph(GPair.first.first); + + llvm::OwningPtr ReportGraph(GPair.first.first); llvm::OwningPtr BackMap(GPair.first.second); - const ExplodedNode *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 DFSWorkList; + llvm::DenseMap 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 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 - 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 Meta = R.getExtraDescriptiveText(); - for (const char** s = Meta.first; s != Meta.second; ++s) D->addMeta(*s); + std::pair 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 0000000000000..89c9ca10ec570 --- /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()->getStmt(); + + if (const UnaryOperator *U = dyn_cast(S)) { + if (U->getOpcode() == UnaryOperator::Deref) + return U->getSubExpr()->IgnoreParenCasts(); + } + else if (const MemberExpr *ME = dyn_cast(S)) { + return ME->getBase()->IgnoreParenCasts(); + } + else if (const ArraySubscriptExpr *AE = dyn_cast(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()->getStmt(); + if (const ObjCMessageExpr *ME = dyn_cast(S)) + return ME->getReceiver(); + return NULL; +} + +const Stmt* +clang::bugreporter::GetDenomExpr(const ExplodedNode *N) { + const Stmt *S = N->getLocationAs()->getStmt(); + if (const BinaryOperator *BE = dyn_cast(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()->getStmt(); + if (const CallExpr *CE = dyn_cast(S)) + return CE->getCallee(); + return NULL; +} + +const Stmt* +clang::bugreporter::GetRetValExpr(const ExplodedNode *N) { + const Stmt *S = N->getLocationAs()->getStmt(); + if (const ReturnStmt *RS = dyn_cast(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(R)) { + if (const PostStmt *P = Node->getLocationAs()) + if (const DeclStmt *DS = P->getStmtAs()) + 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()) { + if (const DeclStmt *DS = PS->getStmtAs()) { + + if (const VarRegion *VR = dyn_cast(R)) { + os << "Variable '" << VR->getDecl()->getNameAsString() << "' "; + } + else + return NULL; + + if (isa(V)) { + bool b = false; + ASTContext &C = BRC.getASTContext(); + if (R->isBoundable()) { + if (const TypedRegion *TR = dyn_cast(R)) { + if (TR->getValueType(C)->isObjCObjectPointerType()) { + os << "initialized to nil"; + b = true; + } + } + } + + if (!b) + os << "initialized to a null pointer value"; + } + else if (isa(V)) { + os << "initialized to " << cast(V).getValue(); + } + else if (V.isUndef()) { + if (isa(R)) { + const VarDecl *VD = cast(DS->getSingleDecl()); + if (VD->getInit()) + os << "initialized to a garbage value"; + else + os << "declared without an initial value"; + } + } + } + } + + if (os.str().empty()) { + if (isa(V)) { + bool b = false; + ASTContext &C = BRC.getASTContext(); + if (R->isBoundable()) { + if (const TypedRegion *TR = dyn_cast(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(V)) { + os << "The value " << cast(V).getValue() + << " is assigned to "; + } + else + return NULL; + + if (const VarRegion *VR = dyn_cast(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(&P)) { + CFGBlock *BSrc = BE->getSrc(); + S = BSrc->getTerminatorCondition(); + } + else if (PostStmt *PS = dyn_cast(&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(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(&P)) { + CFGBlock *BSrc = BE->getSrc(); + S = BSrc->getTerminatorCondition(); + } + else if (PostStmt *PS = dyn_cast(&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(data); + + if (!S) + return; + + GRStateManager &StateMgr = BRC.getStateManager(); + const GRState *state = N->getState(); + + if (const DeclRefExpr *DR = dyn_cast(S)) { + if (const VarDecl *VD = dyn_cast(DR->getDecl())) { + const VarRegion *R = + StateMgr.getRegionManager().getVarRegion(VD, N->getLocationContext()); + + // What did we load? + SVal V = state->getSVal(S); + + if (isa(V) || isa(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(&V)) { + const SubRegion *R = cast(L->getRegion()); + while (R && !isa(R)) { + R = dyn_cast(R->getSuperRegion()); + } + + if (R) { + assert(isa(R)); + registerTrackConstraint(BRC, loc::MemRegionVal(R), false); + } + } +} diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp new file mode 100644 index 0000000000000..7b1d50cb3aeea --- /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(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 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 BackpatchBlocksTy; + BackpatchBlocksTy BackpatchBlocks; + + // A list of labels whose address has been taken (for indirect gotos). + typedef llvm::SmallPtrSet 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(t)) { + if (VariableArrayType* vat = dyn_cast(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(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(S), alwaysAdd); + + case Stmt::BinaryOperatorClass: + return VisitBinaryOperator(cast(S), alwaysAdd); + + case Stmt::BlockExprClass: + return VisitBlockExpr(cast(S), alwaysAdd); + + case Stmt::BlockDeclRefExprClass: + return VisitBlockDeclRefExpr(cast(S), alwaysAdd); + + case Stmt::BreakStmtClass: + return VisitBreakStmt(cast(S)); + + case Stmt::CallExprClass: + return VisitCallExpr(cast(S), alwaysAdd); + + case Stmt::CaseStmtClass: + return VisitCaseStmt(cast(S)); + + case Stmt::ChooseExprClass: + return VisitChooseExpr(cast(S)); + + case Stmt::CompoundStmtClass: + return VisitCompoundStmt(cast(S)); + + case Stmt::ConditionalOperatorClass: + return VisitConditionalOperator(cast(S)); + + case Stmt::ContinueStmtClass: + return VisitContinueStmt(cast(S)); + + case Stmt::DeclStmtClass: + return VisitDeclStmt(cast(S)); + + case Stmt::DefaultStmtClass: + return VisitDefaultStmt(cast(S)); + + case Stmt::DoStmtClass: + return VisitDoStmt(cast(S)); + + case Stmt::ForStmtClass: + return VisitForStmt(cast(S)); + + case Stmt::GotoStmtClass: + return VisitGotoStmt(cast(S)); + + case Stmt::IfStmtClass: + return VisitIfStmt(cast(S)); + + case Stmt::IndirectGotoStmtClass: + return VisitIndirectGotoStmt(cast(S)); + + case Stmt::LabelStmtClass: + return VisitLabelStmt(cast(S)); + + case Stmt::ObjCAtCatchStmtClass: + return VisitObjCAtCatchStmt(cast(S)); + + case Stmt::CXXThrowExprClass: + return VisitCXXThrowExpr(cast(S)); + + case Stmt::ObjCAtSynchronizedStmtClass: + return VisitObjCAtSynchronizedStmt(cast(S)); + + case Stmt::ObjCAtThrowStmtClass: + return VisitObjCAtThrowStmt(cast(S)); + + case Stmt::ObjCAtTryStmtClass: + return VisitObjCAtTryStmt(cast(S)); + + case Stmt::ObjCForCollectionStmtClass: + return VisitObjCForCollectionStmt(cast(S)); + + case Stmt::ParenExprClass: + S = cast(S)->getSubExpr(); + goto tryAgain; + + case Stmt::NullStmtClass: + return Block; + + case Stmt::ReturnStmtClass: + return VisitReturnStmt(cast(S)); + + case Stmt::SizeOfAlignOfExprClass: + return VisitSizeOfAlignOfExpr(cast(S), alwaysAdd); + + case Stmt::StmtExprClass: + return VisitStmtExpr(cast(S), alwaysAdd); + + case Stmt::SwitchStmtClass: + return VisitSwitchStmt(cast(S)); + + case Stmt::WhileStmtClass: + return VisitWhileStmt(cast(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()) + 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 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::Alignment < 8 + ? 8 : llvm::AlignOf::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(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 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 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 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 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 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 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 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(); + 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 BlkExprMapTy; +} + +static void FindSubExprAssignments(Stmt* Terminator, llvm::SmallPtrSet& 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(*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 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(*BI)) { + + if (BinaryOperator* B = dyn_cast(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(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(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(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(BlkExprMap)->size(); + } +} + +//===----------------------------------------------------------------------===// +// Cleanup: CFG dstor. +//===----------------------------------------------------------------------===// + +CFG::~CFG() { + delete reinterpret_cast(BlkExprMap); +} + +//===----------------------------------------------------------------------===// +// CFG pretty printing +//===----------------------------------------------------------------------===// + +namespace { + +class VISIBILITY_HIDDEN StmtPrinterHelper : public PrinterHelper { + + typedef llvm::DenseMap > 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 { + + 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(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(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(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(B.getLabel())) { + + if (print_edges) + OS << " "; + + if (LabelStmt* L = dyn_cast(Terminator)) + OS << L->getName(); + else if (CaseStmt* C = dyn_cast(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(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(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(getTerminator())); +} + +Stmt* CFGBlock::getTerminatorCondition() { + + if (!Terminator) + return NULL; + + Expr* E = NULL; + + switch (Terminator->getStmtClass()) { + default: + break; + + case Stmt::ForStmtClass: + E = cast(Terminator)->getCond(); + break; + + case Stmt::WhileStmtClass: + E = cast(Terminator)->getCond(); + break; + + case Stmt::DoStmtClass: + E = cast(Terminator)->getCond(); + break; + + case Stmt::IfStmtClass: + E = cast(Terminator)->getCond(); + break; + + case Stmt::ChooseExprClass: + E = cast(Terminator)->getCond(); + break; + + case Stmt::IndirectGotoStmtClass: + E = cast(Terminator)->getTarget(); + break; + + case Stmt::SwitchStmtClass: + E = cast(Terminator)->getCond(); + break; + + case Stmt::ConditionalOperatorClass: + E = cast(Terminator)->getCond(); + break; + + case Stmt::BinaryOperatorClass: // '&&' and '||' + E = cast(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 : 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 3cca482633caf..9b6125705d9aa 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(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 *SNB; + GRStmtNodeBuilder *SNB; Stmt *S; const void *tag; - GREndPathNodeBuilder *ENB; + GREndPathNodeBuilder *ENB; public: - GenericNodeBuilder(GRStmtNodeBuilder &snb, Stmt *s, + GenericNodeBuilder(GRStmtNodeBuilder &snb, Stmt *s, const void *t) : SNB(&snb), S(s), tag(t), ENB(0) {} - GenericNodeBuilder(GREndPathNodeBuilder &enb) + + GenericNodeBuilder(GREndPathNodeBuilder &enb) : SNB(0), S(0), tag(0), ENB(&enb) {} - - ExplodedNode *MakeNode(const GRState *state, - ExplodedNode *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(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(); if (!(PT->getPointeeType().getUnqualifiedType() == Ctx->VoidTy)) return false; @@ -281,14 +282,14 @@ typedef llvm::ImmutableMap 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 { return ObjCSummaryKey(DenseMapInfo::getEmptyKey(), DenseMapInfo::getEmptyKey()); } - + static inline ObjCSummaryKey getTombstoneKey() { return ObjCSummaryKey(DenseMapInfo::getTombstoneKey(), - DenseMapInfo::getTombstoneKey()); + DenseMapInfo::getTombstoneKey()); } - + static unsigned getHashValue(const ObjCSummaryKey &V) { return (DenseMapInfo::getHashValue(V.getIdentifier()) - & 0x88888888) + & 0x88888888) | (DenseMapInfo::getHashValue(V.getSelector()) & 0x55555555); } - + static bool isEqual(const ObjCSummaryKey& LHS, const ObjCSummaryKey& RHS) { return DenseMapInfo::isEqual(LHS.getIdentifier(), RHS.getIdentifier()) && DenseMapInfo::isEqual(LHS.getSelector(), RHS.getSelector()); } - + static bool isPod() { return DenseMapInfo::isPod() && DenseMapInfo::isPod(); } }; } // end llvm namespace - + namespace { class VISIBILITY_HIDDEN ObjCSummaryCache { typedef llvm::DenseMap 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(PT->getPointeeType()); - if (!OI) return 0; - - return OI ? OI->getDecl() : 0; + + const ObjCInterfaceDecl* getReceiverDecl(Expr* E) { + if (const ObjCObjectPointerType* PT = + E->getType()->getAs()) + 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 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(); 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 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(); 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(); 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(); + + // 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' to strip away any typedefs on the // function's type. - const FunctionType* FT = FD->getType()->getAsFunctionType(); + const FunctionType* FT = FD->getType()->getAs(); 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: . 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 . (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 . (IOKit) @@ -1017,13 +1021,13 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { DoNothing, DoNothing); } break; - + case 26: if (!memcmp(FName, "IOOpenFirmwarePathMatching", 26)) { // Part of . (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 . // 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: + // 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 . // 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: + // 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(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()) { @@ -1254,7 +1283,7 @@ RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ, Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true)); } } - else if (RetTy->getAsPointerType()) { + else if (RetTy->getAs()) { if (FD->getAttr()) { 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()) { Summ.setRetEffect(ObjCAllocRetE); + return; } - else if (MD->getAttr()) { - Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true)); - } + + isTrackedLoc = true; } + + if (!isTrackedLoc) + isTrackedLoc = MD->getResultType()->getAs() != NULL; + + if (isTrackedLoc && MD->getAttr()) + 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 RefBindings; static int RefBIndex = 0; namespace clang { template<> struct GRStateTrait : public GRStatePartialTrait { - 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 : public GRStatePartialTrait { - static inline void* GDMIndex() { return &AutoRBIndex; } + static inline void* GDMIndex() { return &AutoRBIndex; } }; template<> struct GRStateTrait : public GRStatePartialTrait { - 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(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(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 - SummaryLogTy; + typedef llvm::DenseMap + 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& Dst, - GRStmtNodeBuilder& Builder, + void ProcessNonLeakError(ExplodedNodeSet& Dst, + GRStmtNodeBuilder& Builder, Expr* NodeExpr, Expr* ErrorExpr, - ExplodedNode* Pred, + ExplodedNode* Pred, const GRState* St, RefVal::Kind hasErr, SymbolRef Sym); - + const GRState * HandleSymbolDeath(const GRState * state, SymbolRef sid, RefVal V, llvm::SmallVectorImpl &Leaked); - - ExplodedNode* ProcessLeaks(const GRState * state, + + ExplodedNode* ProcessLeaks(const GRState * state, llvm::SmallVectorImpl &Leaked, GenericNodeBuilder &Builder, GRExprEngine &Eng, - ExplodedNode *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& Printers) { Printers.push_back(new BindingsPrinter()); } - + bool isGCEnabled() const { return Summaries.isGCEnabled(); } const LangOptions& getLangOptions() const { return LOpts; } - - const RetainSummary *getSummaryOfNode(const ExplodedNode *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& Dst, + void EvalSummary(ExplodedNodeSet& Dst, GRExprEngine& Eng, - GRStmtNodeBuilder& Builder, + GRStmtNodeBuilder& Builder, Expr* Ex, Expr* Receiver, const RetainSummary& Summ, ExprIterator arg_beg, ExprIterator arg_end, - ExplodedNode* Pred); - - virtual void EvalCall(ExplodedNodeSet& Dst, + ExplodedNode* Pred); + + virtual void EvalCall(ExplodedNodeSet& Dst, GRExprEngine& Eng, - GRStmtNodeBuilder& Builder, + GRStmtNodeBuilder& Builder, CallExpr* CE, SVal L, - ExplodedNode* Pred); - - - virtual void EvalObjCMessageExpr(ExplodedNodeSet& Dst, + ExplodedNode* Pred); + + + virtual void EvalObjCMessageExpr(ExplodedNodeSet& Dst, GRExprEngine& Engine, - GRStmtNodeBuilder& Builder, + GRStmtNodeBuilder& Builder, ObjCMessageExpr* ME, - ExplodedNode* Pred); - - bool EvalObjCMessageExprAux(ExplodedNodeSet& Dst, + ExplodedNode* Pred); + + bool EvalObjCMessageExprAux(ExplodedNodeSet& Dst, GRExprEngine& Engine, - GRStmtNodeBuilder& Builder, + GRStmtNodeBuilder& Builder, ObjCMessageExpr* ME, - ExplodedNode* Pred); + ExplodedNode* Pred); - // Stores. + // Stores. virtual void EvalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val); // End-of-path. - + virtual void EvalEndPath(GRExprEngine& Engine, - GREndPathNodeBuilder& Builder); - - virtual void EvalDeadSymbols(ExplodedNodeSet& Dst, + GREndPathNodeBuilder& Builder); + + virtual void EvalDeadSymbols(ExplodedNodeSet& Dst, GRExprEngine& Engine, - GRStmtNodeBuilder& Builder, - ExplodedNode* Pred, + GRStmtNodeBuilder& Builder, + ExplodedNode* Pred, Stmt* S, const GRState* state, SymbolReaper& SymReaper); - - std::pair*, const GRState *> + + std::pair HandleAutoreleaseCounts(const GRState * state, GenericNodeBuilder Bd, - ExplodedNode* Pred, GRExprEngine &Eng, + ExplodedNode* Pred, GRExprEngine &Eng, SymbolRef Sym, RefVal V, bool &stop); // Return statements. - - virtual void EvalReturn(ExplodedNodeSet& Dst, + + virtual void EvalReturn(ExplodedNodeSet& Dst, GRExprEngine& Engine, - GRStmtNodeBuilder& Builder, + GRStmtNodeBuilder& Builder, ReturnStmt* S, - ExplodedNode* Pred); + ExplodedNode* Pred); // Assumptions. @@ -1965,34 +2006,34 @@ static void PrintPool(llvm::raw_ostream &Out, SymbolRef Sym, else Out << ""; Out << ":{"; - + // Get the contents of the pool. if (const ARCounts *cnts = state->get(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(); - + 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(); - + 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 *n, SymbolRef sym) + ExplodedNode *n, SymbolRef sym) : RangedBugReport(D, D.getDescription(), n), Sym(sym), TF(tf) {} CFRefReport(CFRefBug& D, const CFRefCount &tf, - ExplodedNode *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* N); - + const ExplodedNode* N); + std::pair getExtraDescriptiveText(); - - PathDiagnosticPiece* VisitNode(const ExplodedNode* N, - const ExplodedNode* 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 *n, SymbolRef sym, + ExplodedNode *n, SymbolRef sym, GRExprEngine& Eng); - + PathDiagnosticPiece* getEndPath(BugReporterContext& BRC, - const ExplodedNode* 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 CFRefReport::getExtraDescriptiveText() { CFRefCount& TF = static_cast(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& V, for (llvm::SmallVectorImpl::const_iterator I=V.begin(), E=V.end(); I!=E; ++I) if (*I == X) return true; - + return false; } -PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N, - const ExplodedNode* PrevN, +PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N, + const ExplodedNode* PrevN, BugReporterContext& BRC) { - + if (!isa(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(Sym); + + const RefVal* CurrT = CurrSt->get(Sym); if (!CurrT) return NULL; - + const RefVal &CurrV = *CurrT; const RefVal *PrevT = PrevSt->get(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(N->getLocation()).getStmt(); - - if (CallExpr *CE = dyn_cast(S)) { + const Stmt* S = cast(N->getLocation()).getStmt(); + + if (const CallExpr *CE = dyn_cast(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(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* 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(getBugType()).getTF().isGCEnabled()) { assert(CurrV.getObjKind() == RetEffect::CF); os << " " @@ -2333,51 +2376,51 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* 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 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(N->getLocation()).getStmt(); - - if (CallExpr *CE = dyn_cast(S)) { + const Stmt* S = cast(N->getLocation()).getStmt(); + + if (const CallExpr *CE = dyn_cast(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(S)) { - if (Expr *receiver = ME->getReceiver()) + else if (const ObjCMessageExpr *ME = dyn_cast(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* N, break; } } - + // Specially handle CFMakeCollectable and friends. if (contains(AEffects, MakeCollectable)) { // Get the name of the function. - Stmt* S = cast(N->getLocation()).getStmt(); + const Stmt* S = cast(N->getLocation()).getStmt(); SVal X = CurrSt->getSValAsScalarOrLoc(cast(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* 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::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* N, continue; } } - } while(0); - + } while (0); + if (os.str().empty()) return 0; // We have nothing to say! - Stmt* S = cast(N->getLocation()).getStmt(); + const Stmt* S = cast(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(*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(*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 MemRegion*> -GetAllocationSite(GRStateManager& StateMgr, const ExplodedNode* N, +static std::pair +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* 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(); - + 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* 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* 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* 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(AllocNode->getLocation()).getStmt(); - + const Stmt* FirstStmt = cast(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* LeakN = EndN; + const ExplodedNode* LeakN = EndN; PathDiagnosticLocation L; - + while (LeakN) { ProgramPoint P = LeakN->getLocation(); - + if (const PostStmt *PS = dyn_cast(&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(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(BRC.getCodeDecl()); + ObjCMethodDecl& MD = cast(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(BRC.getCodeDecl()); + ObjCMethodDecl& MD = cast(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 *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* 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(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(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(RetE)) + if (const ObjCObjectPointerType *PT = RetTy->getAs()) + 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& Dst, +void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, GRExprEngine& Eng, - GRStmtNodeBuilder& Builder, + GRStmtNodeBuilder& Builder, Expr* Ex, Expr* Receiver, const RetainSummary& Summ, ExprIterator arg_beg, ExprIterator arg_end, - ExplodedNode* 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& Dst, ErrorExpr = *I; ErrorSym = Sym; break; - } + } continue; } + tryAgain: if (isa(V)) { if (loc::MemRegionVal* MR = dyn_cast(&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(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(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(superReg) || isa(superReg) || - isa(superReg)) - R = cast(superReg); - } - - // FIXME: What about layers of ElementRegions? - } - - // Is the invalidated variable something that we were tracking? - SymbolRef Sym = state->getSValAsScalarOrLoc(R).getAsLocSymbol(); - - // Remove any existing reference-count binding. - if (Sym) state = state->remove(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()); - } + 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(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(superReg) || isa(superReg) || + isa(superReg)) + R = cast(superReg); } + // FIXME: What about layers of ElementRegions? } - else if (isa(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); - } - 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(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(V)); } } - else if (isa(V)) - state = state->unbindLoc(cast(V).getLoc()); - } - - // Evaluate the effect on the message receiver. + else if (isa(V)) { + // If we are passing a location wrapped as an integer, unwrap it and + // invalidate the values referred by the location. + V = cast(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& 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& 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(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& 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(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& Dst, +void CFRefCount::EvalCall(ExplodedNodeSet& Dst, GRExprEngine& Eng, - GRStmtNodeBuilder& Builder, + GRStmtNodeBuilder& Builder, CallExpr* CE, SVal L, - ExplodedNode* Pred) { + ExplodedNode* Pred) { const FunctionDecl* FD = L.getAsFunctionDecl(); - RetainSummary* Summ = !FD ? Summaries.getDefaultSummary() + RetainSummary* Summ = !FD ? Summaries.getDefaultSummary() : Summaries.getSummary(const_cast(FD)); - + assert(Summ); EvalSummary(Dst, Eng, Builder, CE, 0, *Summ, CE->arg_begin(), CE->arg_end(), Pred); } -void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst, +void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst, GRExprEngine& Eng, - GRStmtNodeBuilder& Builder, + GRStmtNodeBuilder& Builder, ObjCMessageExpr* ME, - ExplodedNode* 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& Dst, SVal V = St->getSValAsScalarOrLoc(Receiver); SymbolRef Sym = V.getAsLocSymbol(); + if (Sym) { if (const RefVal* T = St->get(Sym)) { - QualType Ty = T->getType(); - - if (const PointerType* PT = Ty->getAsPointerType()) { - QualType PointeeTy = PT->getPointeeType(); - - if (ObjCInterfaceType* IT = dyn_cast(PointeeTy)) - ID = IT->getDecl(); - } + if (const ObjCObjectPointerType* PT = + T->getType()->getAs()) + 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()) + ID = PT->getInterfaceDecl(); } // FIXME: The receiver could be a reference to a class, meaning that @@ -3101,16 +3061,22 @@ void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& 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(&Eng.getGraph().getCodeDecl())) { + if (isa(Pred->getLocationContext()->getDecl())) { if (Expr* Receiver = ME->getReceiver()) { SVal X = St->getSValAsScalarOrLoc(Receiver); - if (loc::MemRegionVal* L = dyn_cast(&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(&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(location)) @@ -3156,7 +3122,7 @@ void CFRefCount::EvalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val) { else { const MemRegion* R = cast(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& Dst, +void CFRefCount::EvalReturn(ExplodedNodeSet& Dst, GRExprEngine& Eng, - GRStmtNodeBuilder& Builder, + GRStmtNodeBuilder& Builder, ReturnStmt* S, - ExplodedNode* 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(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& Dst, } break; } - - default: + + default: return; } - + // Update the binding. state = state->set(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(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(CD)) { + Decl const *CD = &Pred->getCodeDecl(); + if (const ObjCMethodDecl* MD = dyn_cast(CD)) { const RetainSummary &Summ = *Summaries.getMethodSummary(MD); RetEffect RE = Summ.getRetEffect(); bool hasError = false; @@ -3267,25 +3233,26 @@ void CFRefCount::EvalReturn(ExplodedNodeSet& 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(Sym, X); - ExplodedNode *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(leakAtReturn), *this, @@ -3293,21 +3260,22 @@ void CFRefCount::EvalReturn(ExplodedNodeSet& 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(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(Sym, X ^ RefVal::ErrorReturnedNotOwned); - if (ExplodedNode *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(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(); - + if (B.isEmpty()) return state; - - bool changed = false; + + bool changed = false; RefBindings::Factory& RefBFactory = state->get_context(); - 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(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(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(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(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(sym, V); @@ -3485,27 +3453,27 @@ const GRState * CFRefCount::Update(const GRState * state, SymbolRef sym, // Handle dead symbols and end-of-path. //===----------------------------------------------------------------------===// -std::pair*, const GRState *> +std::pair CFRefCount::HandleAutoreleaseCounts(const GRState * state, GenericNodeBuilder Bd, - ExplodedNode* 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(Sym, V); - ExplodedNode *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(Sym, V); - if (ExplodedNode *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(overAutorelease), *this, N, Sym, os.str().c_str()); BR->EmitReport(report); } - - return std::make_pair((ExplodedNode*)0, state); + + return std::make_pair((ExplodedNode*)0, state); } const GRState * CFRefCount::HandleSymbolDeath(const GRState * state, SymbolRef sid, RefVal V, llvm::SmallVectorImpl &Leaked) { - - bool hasLeak = V.isOwned() || + + bool hasLeak = V.isOwned() || ((V.isNotOwned() || V.isReturnedOwned()) && V.getCount() > 0); - + if (!hasLeak) return state->remove(sid); - + Leaked.push_back(sid); return state->set(sid, V ^ RefVal::ErrorLeak); } -ExplodedNode* +ExplodedNode* CFRefCount::ProcessLeaks(const GRState * state, llvm::SmallVectorImpl &Leaked, GenericNodeBuilder &Builder, GRExprEngine& Eng, - ExplodedNode *Pred) { - + ExplodedNode *Pred) { + if (Leaked.empty()) return Pred; - + // Generate an intermediate node representing the leak point. - ExplodedNode *N = Builder.MakeNode(state, Pred); - + ExplodedNode *N = Builder.MakeNode(state, Pred); + if (N) { for (llvm::SmallVectorImpl::iterator I = Leaked.begin(), E = Leaked.end(); I != E; ++I) { - - CFRefBug *BT = static_cast(Pred ? leakWithinFunction + + CFRefBug *BT = static_cast(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& Builder) { - + GREndPathNodeBuilder& Builder) { + const GRState *state = Builder.getState(); GenericNodeBuilder Bd(Builder); - RefBindings B = state->get(); - ExplodedNode *Pred = 0; + RefBindings B = state->get(); + 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(); - llvm::SmallVector Leaked; - + + B = state->get(); + llvm::SmallVector 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& Dst, +void CFRefCount::EvalDeadSymbols(ExplodedNodeSet& Dst, GRExprEngine& Eng, - GRStmtNodeBuilder& Builder, - ExplodedNode* Pred, + GRStmtNodeBuilder& Builder, + ExplodedNode* Pred, Stmt* S, const GRState* state, SymbolReaper& SymReaper) { RefBindings B = state->get(); - + // 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& Dst, return; } } - + B = state->get(); llvm::SmallVector 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(); - + for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(), E = SymReaper.dead_end(); I!=E; ++I) B = F.Remove(B, *I); - + state = state->set(B); Builder.MakeNode(Dst, S, Pred, state); } -void CFRefCount::ProcessNonLeakError(ExplodedNodeSet& Dst, - GRStmtNodeBuilder& Builder, - Expr* NodeExpr, Expr* ErrorExpr, - ExplodedNode* 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(useAfterRelease); - break; + break; case RefVal::ErrorReleaseNotOwned: BT = static_cast(releaseNotOwned); break; @@ -3709,7 +3677,7 @@ void CFRefCount::ProcessNonLeakError(ExplodedNodeSet& Dst, BT = static_cast(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& 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 7d6a619736e0f..89c1783cc2f55 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 0000000000000..ae8845db63ae7 --- /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 { + + 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(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(*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 : 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 0000000000000..cca8584a61faf --- /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 69433d6396a5b..d5cb7ca7fdd30 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 Escaped; - + enum DeadStoreKind { Standard, Enclosing, DeadIncrement, DeadInit }; - + public: DeadStoreObs(ASTContext &ctx, BugReporter& br, ParentMap& parents, llvm::SmallPtrSet &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()) 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(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(RHS); - + if (!BRHS) return false; - + DeclRefExpr *DR; - + if ((DR = dyn_cast(BRHS->getLHS()->IgnoreParenCasts()))) if (DR->getDecl() == VD) return true; - + if ((DR = dyn_cast(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(S)) { + + if (BinaryOperator* B = dyn_cast(S)) { if (!B->isAssignmentOp()) return; // Skip non-assignments. - + if (DeclRefExpr* DR = dyn_cast(B->getLHS())) if (VarDecl *VD = dyn_cast(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(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(RHS)) if (VD == dyn_cast(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(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(Ex)) CheckDeclRef(DR, U, DeadIncrement, AD, Live); - } + } else if (DeclStmt* DS = dyn_cast(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(*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(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{ CFG *cfg; public: FindEscaped(CFG *c) : cfg(c) {} - + CFG& getCFG() { return *cfg; } - + llvm::SmallPtrSet 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 c91442b5e8291..8086da588264b 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& ErrorParams); - - void CheckSignature(FunctionDecl& MD, QualType& ResultTy, + + void CheckSignature(const FunctionDecl& MD, QualType& ResultTy, llvm::SmallVectorImpl& 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 ErrorParams; - if (ObjCMethodDecl* MD = dyn_cast(&CodeDecl)) + if (const ObjCMethodDecl* MD = dyn_cast(&CodeDecl)) CheckSignature(*MD, ResultTy, ErrorParams); - else if (FunctionDecl* FD = dyn_cast(&CodeDecl)) + else if (const FunctionDecl* FD = dyn_cast(&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::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(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& 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& 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(); + if (!PPT) + return false; + + const ObjCObjectPointerType* PT = + PPT->getPointeeType()->getAs(); + + 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(); if (!PPT) return false; - - const TypedefType* TT = PPT->getPointeeType()->getAsTypedefType(); + + const TypedefType* TT = PPT->getPointeeType()->getAs(); 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(ParamL).getRegionAs(); 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(); + const SVal* X = state->get(); 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 a14ae265128b9..92e3e112d9f1a 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(S)) if (ME->getSelector() == Dealloc) - if(ME->getReceiver()) + if (ME->getReceiver()) if (Expr* Receiver = ME->getReceiver()->IgnoreParenCasts()) return isa(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(S)) if (ME->getSelector() == Release) - if(ME->getReceiver()) + if (ME->getReceiver()) if (Expr* Receiver = ME->getReceiver()->IgnoreParenCasts()) if (ObjCIvarRefExpr* E = dyn_cast(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(S)) - if(ME->getReceiver()) + if (ME->getReceiver()) if (Expr* Receiver = ME->getReceiver()->IgnoreParenCasts()) if (DeclRefExpr* E = dyn_cast(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(S)) if (BO->isAssignmentOp()) - if(ObjCPropertyRefExpr* PRE = + if (ObjCPropertyRefExpr* PRE = dyn_cast(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()) // 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 28814867bd589..8c0d39629d503 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 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 0063c40482a0e..1a900f8976783 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 IvarUsageMap; +typedef llvm::DenseMap IvarUsageMap; -static void Scan(IvarUsageMap& M, Stmt* S) { +static void Scan(IvarUsageMap& M, const Stmt* S) { if (!S) return; - - if (ObjCIvarRefExpr* Ex = dyn_cast(S)) { - ObjCIvarDecl* D = Ex->getDecl(); + + if (const ObjCIvarRefExpr *Ex = dyn_cast(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(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()) 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 0000000000000..9f0d059cb66e9 --- /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 { + 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(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: +// 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(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(expr)) { + const NamedDecl *ND = DR->getDecl(); + return ND == x || ND == y ? DR : NULL; + } + + if (const UnaryOperator *U = dyn_cast(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(condition); + + if (!B) + return; + + // Is this a comparison? + if (!(B->isRelationalOp() || B->isEqualityOp())) + return; + + // Are we comparing variables? + const DeclRefExpr *drLHS = dyn_cast(B->getLHS()->IgnoreParens()); + const DeclRefExpr *drRHS = dyn_cast(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(drLHS->getDecl()) : NULL; + const VarDecl *vdRHS = drRHS ? dyn_cast(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 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: +// 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(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(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: +// 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(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(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: +//===----------------------------------------------------------------------===// + +void WalkAST::CheckCall_random(const CallExpr *CE, const FunctionDecl *FD) { + if (FD->getIdentifier() != GetIdentifier(II_random, "random")) + return; + + const FunctionProtoType *FTP = dyn_cast(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: +//===----------------------------------------------------------------------===// + +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(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 3f8f14dcb0b4e..1610ad4d271d9 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(E)); - + // ParenExprs are no-ops. - - case Stmt::ParenExprClass: + + case Stmt::ParenExprClass: E = cast(E)->getSubExpr(); continue; - + case Stmt::CharacterLiteralClass: { const CharacterLiteral* C = cast(E); return ValMgr.makeIntVal(C->getValue(), C->getType()); } - + case Stmt::IntegerLiteralClass: { return ValMgr.makeIntVal(cast(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(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(E)->getSubExpr(); - continue; - - case Stmt::CharacterLiteralClass: { - const CharacterLiteral* C = cast(E); - return ValMgr.makeIntVal(C->getValue(), C->getType()); - } - - case Stmt::IntegerLiteralClass: { - return ValMgr.makeIntVal(cast(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& DRoots) { - - // Drop bindings for subexpressions. - Env = RemoveSubExprBindings(Env); +Environment +EnvironmentManager::RemoveDeadBindings(Environment Env, const Stmt *S, + SymbolReaper &SymReaper, + const GRState *ST, + llvm::SmallVectorImpl &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(X)) { const MemRegion* R = cast(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(R)) { + if (const SubRegion *SR = dyn_cast(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(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(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 20de6c48c387e..0dc81a4225a8b 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& getVector(void* P) { - return *reinterpret_cast*>(P); +static inline BumpVector& getVector(void* P) { + return *reinterpret_cast*>(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(N) & Mask) == 0x0); - assert (!getFlag()); - +void ExplodedNode::NodeGroup::addNode(ExplodedNode* N, ExplodedGraph &G) { + assert((reinterpret_cast(N) & Mask) == 0x0); + assert(!getFlag()); + if (getKind() == Size1) { - if (ExplodedNodeImpl* NOld = getNode()) { - std::vector* V = new std::vector(); - assert ((reinterpret_cast(V) & Mask) == 0x0); - V->push_back(NOld); - V->push_back(N); + if (ExplodedNode* NOld = getNode()) { + BumpVectorContext &Ctx = G.getNodeAllocator(); + BumpVector *V = + G.getAllocator().Allocate >(); + new (V) BumpVector(Ctx, 4); + + assert((reinterpret_cast(V) & Mask) == 0x0); + V->push_back(NOld, Ctx); + V->push_back(N, Ctx); P = reinterpret_cast(V) | SizeOther; - assert (getPtr() == (void*) V); - assert (getKind() == SizeOther); + assert(getPtr() == (void*) V); + assert(getKind() == SizeOther); } else { P = reinterpret_cast(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(&*(getVector(getPtr()).begin())); + return const_cast(&*(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(&getVector(getPtr()).back()) + 1; + return const_cast(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(); + 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::Trim(const NodeTy* const* NBeg, const NodeTy* const* NEnd, + llvm::DenseMap *InverseMap) const { + + if (NBeg == NEnd) + return std::make_pair((ExplodedGraph*) 0, + (InterExplodedGraphMap*) 0); + + assert (NBeg < NEnd); + + llvm::OwningPtr M(new InterExplodedGraphMap()); + + ExplodedGraph* G = TrimInternal(NBeg, NEnd, M.get(), InverseMap); + + return std::make_pair(static_cast(G), M.take()); } -ExplodedGraphImpl* -ExplodedGraphImpl::Trim(const ExplodedNodeImpl* const* BeginSources, - const ExplodedNodeImpl* const* EndSources, - InterExplodedGraphMapImpl* M, - llvm::DenseMap *InverseMap) -const { - - typedef llvm::DenseSet Pass1Ty; +ExplodedGraph* +ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources, + const ExplodedNode* const* EndSources, + InterExplodedGraphMap* M, + llvm::DenseMap *InverseMap) const { + + typedef llvm::DenseSet Pass1Ty; Pass1Ty Pass1; - - typedef llvm::DenseMap Pass2Ty; + + typedef llvm::DenseMap Pass2Ty; Pass2Ty& Pass2 = M->M; - - llvm::SmallVector WL1, WL2; + + llvm::SmallVector 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::iterator I = +ExplodedNode* +InterExplodedGraphMap::getMappedNode(const ExplodedNode* N) const { + llvm::DenseMap::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 f69a16da401c3..4f4103ac45b4a 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 ff7b548bc054f..87472472fdeeb 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 Stack; public: virtual bool hasWork() const { @@ -47,27 +48,27 @@ public: return U; } }; - + class VISIBILITY_HIDDEN BFS : public GRWorkList { std::queue 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(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(Node->getLocation()), Node); break; - + case ProgramPoint::BlockEntranceKind: HandleBlockEntrance(cast(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(Node->getLocation())); HandlePostStmt(cast(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(Term)->getLHS(), Term, B, Pred); return; - + case Stmt::ConditionalOperatorClass: HandleBranch(cast(Term)->getCond(), Term, B, Pred); return; - + // FIXME: Use constant-folding in CFG construction to simplify this // case. - + case Stmt::ChooseExprClass: HandleBranch(cast(Term)->getCond(), Term, B, Pred); return; - + case Stmt::DoStmtClass: HandleBranch(cast(Term)->getCond(), Term, B, Pred); return; - + case Stmt::ForStmtClass: HandleBranch(cast(Term)->getCond(), Term, B, Pred); return; - + case Stmt::ContinueStmtClass: case Stmt::BreakStmtClass: - case Stmt::GotoStmtClass: + case Stmt::GotoStmtClass: break; - + case Stmt::IfStmtClass: HandleBranch(cast(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(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(Term)->getCond(), - this); - + GRSwitchNodeBuilder builder(Pred, B, cast(Term)->getCond(), + this); + ProcessSwitch(builder); return; } - + case Stmt::WhileStmtClass: HandleBranch(cast(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 d9117f5930e61..5079acef54b45 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 Checks; typedef llvm::DenseMap 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 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,33 +75,68 @@ 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(N->getLocation()).getStmt(); + const Stmt* S = cast(N->getLocation()).getStmt(); void* key = reinterpret_cast((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::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::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(&StateMgr.getCodeDecl())) + const Decl *D = InitLoc->getDecl(); + + if (const FunctionDecl *FD = dyn_cast(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(&Constraint_untested)) { + if (const GRState *newState = state->Assume(*Constraint, true)) + state = newState; + } } } + } + else if (const ObjCMethodDecl *MD = dyn_cast(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(&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 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(S), Pred, Dst, false); break; - + case Stmt::AsmStmtClass: VisitAsmStmt(cast(S), Pred, Dst); break; - + case Stmt::BinaryOperatorClass: { BinaryOperator* B = cast(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(S), Pred, Tmp); - EvalEagerlyAssume(Dst, Tmp, cast(S)); + EvalEagerlyAssume(Dst, Tmp, cast(S)); } else VisitBinaryOperator(cast(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(S); VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst); break; } - + case Stmt::CompoundAssignOperatorClass: VisitBinaryOperator(cast(S), Pred, Dst); break; @@ -346,22 +401,22 @@ void GRExprEngine::Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst) { case Stmt::CompoundLiteralExprClass: VisitCompoundLiteralExpr(cast(S), Pred, Dst, false); break; - + case Stmt::ConditionalOperatorClass: { // '?' operator ConditionalOperator* C = cast(S); VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst); break; } - + case Stmt::DeclRefExprClass: case Stmt::QualifiedDeclRefExprClass: VisitDeclRefExpr(cast(S), Pred, Dst, false); break; - + case Stmt::DeclStmtClass: VisitDeclStmt(cast(S), Pred, Dst); break; - + case Stmt::ImplicitCastExprClass: case Stmt::CStyleCastExprClass: { CastExpr* C = cast(S); @@ -372,11 +427,11 @@ void GRExprEngine::Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst) { case Stmt::InitListExprClass: VisitInitListExpr(cast(S), Pred, Dst); break; - + case Stmt::MemberExprClass: VisitMemberExpr(cast(S), Pred, Dst, false); break; - + case Stmt::ObjCIvarRefExprClass: VisitObjCIvarRefExpr(cast(S), Pred, Dst, false); break; @@ -384,12 +439,12 @@ void GRExprEngine::Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst) { case Stmt::ObjCForCollectionStmtClass: VisitObjCForCollectionStmt(cast(S), Pred, Dst); break; - + case Stmt::ObjCMessageExprClass: { VisitObjCMessageExpr(cast(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(S)->getSubExpr()->IgnoreParens(), Pred, Dst); break; - + case Stmt::ReturnStmtClass: VisitReturnStmt(cast(S), Pred, Dst); break; - + case Stmt::SizeOfAlignOfExprClass: VisitSizeOfAlignOfExpr(cast(S), Pred, Dst); break; - + case Stmt::StmtExprClass: { StmtExpr* SE = cast(S); @@ -421,25 +476,25 @@ void GRExprEngine::Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst) { Dst.Add(Pred); break; } - + if (Expr* LastExpr = dyn_cast(*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(S), Pred, Dst); break; - + case Stmt::UnaryOperatorClass: { UnaryOperator *U = cast(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(Ex), Pred, Dst, true); return; - + case Stmt::DeclRefExprClass: case Stmt::QualifiedDeclRefExprClass: VisitDeclRefExpr(cast(Ex), Pred, Dst, true); return; - + case Stmt::ObjCIvarRefExprClass: VisitObjCIvarRefExpr(cast(Ex), Pred, Dst, true); return; - + case Stmt::UnaryOperatorClass: VisitUnaryOperator(cast(Ex), Pred, Dst, true); return; - + case Stmt::MemberExprClass: VisitMemberExpr(cast(Ex), Pred, Dst, true); return; - + case Stmt::CompoundLiteralExprClass: VisitCompoundLiteralExpr(cast(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(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 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(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(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(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(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(&X); - case SVal::UnknownKind: { - if (Expr *Ex = dyn_cast(Condition)) { + if (!V) { + if (X.isUnknown()) { + if (const Expr *Ex = dyn_cast(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(V)) { LabelStmt* L = cast(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(V) || isa(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(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(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(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(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(X).getData(); - + + const Expr *Ex = (const Expr*) cast(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(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(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(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(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 OldSPointKind(Builder->PointKind); SaveAndRestore 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(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 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(location); - + + Loc LV = cast(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(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(LV)) { const MemRegion* R = cast(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& Dst, +static bool EvalOSAtomicCompareAndSwap(ExplodedNodeSet& Dst, GRExprEngine& Engine, - GRStmtNodeBuilder& Builder, - CallExpr* CE, SVal L, - ExplodedNode* 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(); + // 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 Tmp; + ExplodedNodeSet Tmp; SVal location = state->getSVal(theValueExpr); Engine.EvalLoad(Tmp, theValueExpr, Pred, state, location, OSAtomicLoadTag); - for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); + for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) { - - ExplodedNode *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(theValueVal_untested); + DefinedOrUnknownSVal oldValueVal = + cast(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 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(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::iterator I2 = TmpStore.begin(), + for (ExplodedNodeSet::iterator I2 = TmpStore.begin(), E2 = TmpStore.end(); I2 != E2; ++I2) { - ExplodedNode *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& Dst, +static bool EvalOSAtomic(ExplodedNodeSet& Dst, GRExprEngine& Engine, - GRStmtNodeBuilder& Builder, + GRStmtNodeBuilder& Builder, CallExpr* CE, SVal L, - ExplodedNode* 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& Dst, //===----------------------------------------------------------------------===// // Transfer function: Function calls. //===----------------------------------------------------------------------===// +static void MarkNoReturnFunction(const FunctionDecl *FD, CallExpr *CE, + const GRState *state, + GRStmtNodeBuilder *Builder) { + if (!FD) + return; + + if (FD->getAttr() || + FD->getAttr()) + 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(&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()) + Proto = FnTypePtr->getPointeeType()->getAs(); 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(L)) { - NodeTy* N = Builder->generateNode(CE, state, *DI); - - if (N) { - N->markAsSink(); - BadCalls.insert(N); - } - - continue; - } - + // Check for the "noreturn" attribute. - + SaveAndRestore OldSink(Builder->BuildSinks); const FunctionDecl* FD = L.getAsFunctionDecl(); - if (FD) { - if (FD->getAttr() || - FD->getAttr()) - 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(&X); - if (CI && CI->getValue() != 0) - Builder->BuildSinks = true; - } - } - break; + MarkNoReturnFunction(FD, CE, state, Builder); - case 6: - if (!memcmp(s, "Assert", 6)) { - Builder->BuildSinks = true; - break; - } - - // FIXME: This is just a wrapper around throwing an exception. - // Eventually inter-procedural analysis should handle this easily. - if (!memcmp(s, "ziperr", 6)) Builder->BuildSinks = true; - - break; - - case 7: - if (!memcmp(s, "assfail", 7)) Builder->BuildSinks = true; - break; - - case 8: - if (!memcmp(s ,"db_error", 8) || - !memcmp(s, "__assert", 8)) - Builder->BuildSinks = true; - break; - - case 12: - if (!memcmp(s, "__assert_rtn", 12)) Builder->BuildSinks = true; - break; - - case 13: - if (!memcmp(s, "__assert_fail", 13)) Builder->BuildSinks = true; - break; - - case 14: - if (!memcmp(s, "dtrace_assfail", 14) || - !memcmp(s, "yy_fatal_error", 14)) - Builder->BuildSinks = true; - break; - - case 26: - if (!memcmp(s, "_XCAssertionFailureHandler", 26) || - !memcmp(s, "_DTAssertionFailureHandler", 26) || - !memcmp(s, "_TSAssertionFailureHandler", 26)) - Builder->BuildSinks = true; - - break; - } - - } - } - // Evaluate the call. + if (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 EagerlyAssumeTag = std::pair(&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(P) || cast(P).getStmt() != Ex) { - Dst.Add(Pred); + Dst.Add(Pred); continue; - } + } - const GRState* state = Pred->getState(); - SVal V = state->getSVal(Ex); - if (isa(V)) { + const GRState* state = Pred->getState(); + SVal V = state->getSVal(Ex); + if (nonloc::SymExprVal *SEV = dyn_cast(&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(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(elem)) { VarDecl* ElemD = cast(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(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(&ElementV)) if (const TypedRegion* R = dyn_cast(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(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 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 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(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(&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(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(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(&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(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(D)) return; - - const VarDecl* VD = dyn_cast(D); + + const VarDecl* VD = dyn_cast(D); Expr* InitEx = const_cast(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(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(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 Vals; - GRExprEngine::NodeTy* N; + ExplodedNode* N; InitListExpr::reverse_iterator Itr; - - InitListWLItem(GRExprEngine::NodeTy* n, llvm::ImmutableList vals, - InitListExpr::reverse_iterator itr) + + InitListWLItem(ExplodedNode* n, llvm::ImmutableList 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 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 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(*X.Itr)); - + // Construct the new list of values by prepending the new value to // the already constructed list. llvm::ImmutableList 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(V))); - break; - + state = state->BindExpr(U, EvalComplement(cast(V))); + break; + case UnaryOperator::Minus: // FIXME: Do we need to handle promotions? - state = state->bindExpr(U, EvalMinus(cast(V))); - break; - - case UnaryOperator::LNot: - + state = state->BindExpr(U, EvalMinus(cast(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(V)) { Loc X = ValMgr.makeNull(); Result = EvalBinOp(state, BinaryOperator::EQ, cast(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(V), X, + Result = EvalBinOp(state, BinaryOperator::EQ, cast(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(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(X)); // Should be an Lval, or unknown, undef. - + if (isa(X)) state = state->bindLoc(cast(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 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(X)) { // Determine if the value is on the stack. const MemRegion* R = cast(&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(LHS)) { - Visit(RHS, Pred, Dst); + + // FIXME: Add proper support for ObjCImplicitSetterGetterRefExpr. + if (isa(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(B)->getComputationResultType(); + QualType CTy = + cast(B)->getComputationResultType(); CTy = getContext().getCanonicalType(CTy); - QualType CLHSTy = cast(B)->getComputationLHSType(); - CLHSTy = getContext().getCanonicalType(CTy); + QualType CLHSTy = + cast(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,70 +2911,37 @@ 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(L)) { - if (isa(R)) - return SVator->EvalBinOpLL(Op, cast(L), cast(R), T); - else - return SVator->EvalBinOpLN(state, Op, cast(L), cast(R), T); - } - - if (isa(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(R), cast(L), T); - } - else - return SVator->EvalBinOpNN(Op, cast(L), cast(R), T); -} - //===----------------------------------------------------------------------===// // Visualization. //===----------------------------------------------------------------------===// @@ -3105,67 +2952,65 @@ static SourceManager* GraphPrintSourceManager; namespace llvm { template<> -struct VISIBILITY_HIDDEN DOTGraphTraits : +struct VISIBILITY_HIDDEN DOTGraphTraits : 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(Loc).getBlock()->getBlockID(); break; - + case ProgramPoint::BlockExitKind: assert (false); break; - + default: { - if (isa(Loc)) { - const PostStmt& L = cast(Loc); - Stmt* S = L.getStmt(); + if (StmtPoint *L = dyn_cast(&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(Loc)) + + if (isa(Loc)) + Out << "\\lPreStmt\\l;"; + else if (isa(Loc)) Out << "\\lPostLoad\\l;"; else if (isa(Loc)) Out << "\\lPostStore\\l"; @@ -3175,7 +3020,7 @@ struct VISIBILITY_HIDDEN DOTGraphTraits : Out << "\\lPostLocationChecksSucceed\\l"; else if (isa(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 : 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 : Out << "\\|Call to NULL/Undefined."; else if (GraphPrintCheckerState->isUndefArg(N)) Out << "\\|Argument in call is undefined"; - + break; } const BlockEdge& E = cast(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(T)) { Stmt* Label = E.getDst()->getLabel(); - - if (Label) { + + if (Label) { if (CaseStmt* C = dyn_cast(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 : Out << "\\ldefault:"; } } - else + else Out << "\\l(implicit) default:"; } else if (isa(T)) { @@ -3251,46 +3092,45 @@ struct VISIBILITY_HIDDEN DOTGraphTraits : 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 -GRExprEngine::NodeTy* GetGraphNode(ITERATOR I) { return *I; } +ExplodedNode* GetGraphNode(ITERATOR I) { return *I; } -template <> -GRExprEngine::NodeTy* -GetGraphNode::iterator> - (llvm::DenseMap::iterator I) { +template <> ExplodedNode* +GetGraphNode::iterator> + (llvm::DenseMap::iterator I) { return I->first; } #endif void GRExprEngine::ViewGraph(bool trim) { -#ifndef NDEBUG +#ifndef NDEBUG if (trim) { - std::vector Src; + std::vector 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(R.getEndNode()); + ExplodedNode *N = const_cast(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 TrimmedG(G.Trim(Beg, End).first); + + std::auto_ptr 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 a2ce79a2f390d..cc1ec4b77e48f 100644 --- a/lib/Analysis/GRExprEngineInternalChecks.cpp +++ b/lib/Analysis/GRExprEngineInternalChecks.cpp @@ -14,41 +14,29 @@ #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 inline -ExplodedNode* GetNode(ITERATOR I) { +ExplodedNode* GetNode(ITERATOR I) { return *I; } template <> inline -ExplodedNode* 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 *N); -static const Stmt *GetReceiverExpr(const ExplodedNode *N); -static const Stmt *GetDenomExpr(const ExplodedNode *N); -static const Stmt *GetCalleeExpr(const ExplodedNode *N); -static const Stmt *GetRetValExpr(const ExplodedNode *N); - -static void registerTrackNullOrUndefValue(BugReporterContext& BRC, - const Stmt *ValExpr, - const ExplodedNode* N); - //===----------------------------------------------------------------------===// // Bug Descriptions. //===----------------------------------------------------------------------===// @@ -58,17 +46,17 @@ namespace { class VISIBILITY_HIDDEN BuiltinBugReport : public RangedBugReport { public: BuiltinBugReport(BugType& bt, const char* desc, - ExplodedNode *n) + ExplodedNode *n) : RangedBugReport(bt, desc, n) {} - + BuiltinBugReport(BugType& bt, const char *shortDesc, const char *desc, - ExplodedNode *n) - : RangedBugReport(bt, shortDesc, desc, n) {} - + ExplodedNode *n) + : RangedBugReport(bt, shortDesc, desc, n) {} + void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* 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* N, + const ExplodedNode* N, BuiltinBugReport *R) {} - + template void Emit(BugReporter& BR, ITER I, ITER E); }; - - + + template 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* N) { + const ExplodedNode* N) { static_cast(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* 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((*I)->getLocation()); - ObjCMessageExpr *ME = cast(P.getStmt()); + const ObjCMessageExpr *ME = cast(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* 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((*I)->getLocation()); - ObjCMessageExpr *ME = cast(P.getStmt()); + const ObjCMessageExpr *ME = cast(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* 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* 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* 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()->getStmt(); + BuiltinBugReport *report = NULL; + + if (const BinaryOperator *B = dyn_cast(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()->getStmt(); + const Stmt *X = S; + + if (const BinaryOperator *B = dyn_cast(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* 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 *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 *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* N, + const ExplodedNode* N, BuiltinBugReport *R) { registerTrackNullOrUndefValue(BRC, static_cast(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* N = *I; - Stmt *S = cast(N->getLocation()).getStmt(); - Expr* E = cast(S)->getReceiver(); + ExplodedNode* N = *I; + const Stmt *S = cast(N->getLocation()).getStmt(); + const Expr* E = cast(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* 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* N = *I; - Stmt *S = cast(N->getLocation()).getStmt(); - Expr* E = cast(S)->getRetValue(); - assert (E && "Return expression cannot be NULL"); - + ExplodedNode* N = *I; + const Stmt *S = cast(N->getLocation()).getStmt(); + const Expr* E = cast(S)->getRetValue(); + assert(E && "Return expression cannot be NULL"); + // Get the value associated with E. loc::MemRegionVal V = cast(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(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(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* 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(*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 *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* N, + const ExplodedNode* N, BuiltinBugReport *R) { registerTrackNullOrUndefValue(BRC, static_cast(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(N->getLocation()); - DeclStmt *DS = cast(PS.getStmt()); + ExplodedNode* N = *I; + PostStmt PS = cast(N->getLocation()); + const DeclStmt *DS = cast(PS.getStmt()); VarDecl* VD = cast(*DS->decl_begin()); QualType T = Eng.getContext().getCanonicalType(VD->getType()); VariableArrayType* VT = cast(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* N, + const ExplodedNode* N, BuiltinBugReport *R) { registerTrackNullOrUndefValue(BRC, static_cast(R)->getArg(), N); @@ -549,370 +586,217 @@ public: //===----------------------------------------------------------------------===// // __attribute__(nonnull) checking -class VISIBILITY_HIDDEN CheckAttrNonNull : public GRSimpleAPICheck { +class VISIBILITY_HIDDEN CheckAttrNonNull : + public CheckerVisitor { + BugType *BT; - BugReporter &BR; - + public: - CheckAttrNonNull(BugReporter &br) : BT(0), BR(br) {} + CheckAttrNonNull() : BT(0) {} + ~CheckAttrNonNull() {} - virtual bool Audit(ExplodedNode* N, GRStateManager& VMgr) { - CallExpr* CE = cast(cast(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(); - 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(&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 { -static const Stmt *GetDerefExpr(const ExplodedNode *N) { - // Pattern match for a few useful cases (do something smarter later): - // a[0], p->f, *p - const Stmt *S = N->getLocationAs()->getStmt(); + BadArg *BT; - if (const UnaryOperator *U = dyn_cast(S)) { - if (U->getOpcode() == UnaryOperator::Deref) - return U->getSubExpr()->IgnoreParenCasts(); - } - else if (const MemberExpr *ME = dyn_cast(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(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 *N) { - const Stmt *S = N->getLocationAs()->getStmt(); - if (const ObjCMessageExpr *ME = dyn_cast(S)) - return ME->getReceiver(); - return NULL; -} - -static const Stmt *GetDenomExpr(const ExplodedNode *N) { - const Stmt *S = N->getLocationAs()->getStmt(); - if (const BinaryOperator *BE = dyn_cast(S)) - return BE->getRHS(); - return NULL; -} - -static const Stmt *GetCalleeExpr(const ExplodedNode *N) { - const Stmt *S = N->getLocationAs()->getStmt(); - if (const CallExpr *CE = dyn_cast(S)) - return CE->getCallee(); - return NULL; -} - -static const Stmt *GetRetValExpr(const ExplodedNode *N) { - const Stmt *S = N->getLocationAs()->getStmt(); - if (const ReturnStmt *RS = dyn_cast(S)) - return RS->getRetValue(); - return NULL; -} +class VISIBILITY_HIDDEN CheckBadCall : public CheckerVisitor { + BadCall *BT; -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(R)) { - if (const PostStmt *P = Node->getLocationAs()) - if (const DeclStmt *DS = P->getStmtAs()) - 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()) { - if (const DeclStmt *DS = PS->getStmtAs()) { - - if (const VarRegion *VR = dyn_cast(R)) { - os << "Variable '" << VR->getDecl()->getNameAsString() << "' "; - } - else - return NULL; - - if (isa(V)) { - bool b = false; - ASTContext &C = BRC.getASTContext(); - if (R->isBoundable()) { - if (const TypedRegion *TR = dyn_cast(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(V)) { - os << "initialized to " << cast(V).getValue(); - } - else if (V.isUndef()) { - if (isa(R)) { - const VarDecl *VD = cast(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(V)) { - bool b = false; - ASTContext &C = BRC.getASTContext(); - if (R->isBoundable()) { - if (const TypedRegion *TR = dyn_cast(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(R)) { - os << '\'' << VR->getDecl()->getNameAsString() << '\''; - } - else - return NULL; + if (L.isUndef() || isa(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(&P)) { - CFGBlock *BSrc = BE->getSrc(); - S = BSrc->getTerminatorCondition(); - } - else if (PostStmt *PS = dyn_cast(&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 { + DivZero *BT; public: - TrackConstraintBRVisitor(SVal 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)) { + 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(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(&P)) { - CFGBlock *BSrc = BE->getSrc(); - S = BSrc->getTerminatorCondition(); - } - else if (PostStmt *PS = dyn_cast(&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* 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(S)) { - if (const VarDecl *VD = dyn_cast(DR->getDecl())) { - const VarRegion *R = - StateMgr.getRegionManager().getVarRegion(VD); - - // What did we load? - SVal V = state->getSVal(S); - - if (isa(V) || isa(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(&V)) { - const SubRegion *R = cast(L->getRegion()); - while (R && !isa(R)) { - R = dyn_cast(R->getSuperRegion()); - } - - if (R) { - assert(isa(R)); - registerTrackConstraint(BRC, loc::MemRegionVal(R), false); + SVal Denom = C.getState()->getSVal(B->getRHS()); + const DefinedSVal *DV = dyn_cast(&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 54c0afbff33ee..f269824d5477c 100644 --- a/lib/Analysis/GRState.cpp +++ b/lib/Analysis/GRState.cpp @@ -27,7 +27,7 @@ GRStateManager::~GRStateManager() { for (std::vector::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 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(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(); - 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::iterator I = Mgr->Printers.begin(), - E = Mgr->Printers.end(); I != E; ++I) { + for (std::vector::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& 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 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(&val)) return scan(X->getRegion()); if (SymbolRef Sym = val.getAsSymbol()) return visitor.VisitSymbol(Sym); - + if (nonloc::CompoundVal *X = dyn_cast(&val)) return scan(*X); - + return true; } - + bool ScanReachableSymbols::scan(const MemRegion *R) { if (isa(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(R)) if (!visitor.VisitSymbol(SR->getSymbol())) return false; - + // If this is a subregion, also visit the parent regions. if (const SubRegion *SR = dyn_cast(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(&V)) return X->getValue() == Y; if (nonloc::ConcreteInt* X = dyn_cast(&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 aead7f43ad8f6..4d96c8f8f4015 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 { - + LiveVariables::AnalysisDataTy& AD; - + typedef llvm::SmallVector 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::Visit(S); } else if (!getCFG().isBlkExpr(S)) { - + if (AD.Observer) AD.Observer->ObserveStmt(S,AD,LiveState); - + StmtVisitor::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(DR->getDecl())) + if (VarDecl* V = dyn_cast(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(Element)) VD = cast(DS->getSingleDecl()); else { - Expr* ElemExpr = cast(Element)->IgnoreParens(); + Expr* ElemExpr = cast(Element)->IgnoreParens(); if ((DR = dyn_cast(ElemExpr))) VD = cast(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(E->IgnoreParens())) + if (DeclRefExpr* DR = dyn_cast(E->IgnoreParens())) if (VarDecl* VD = dyn_cast(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(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(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 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 45305403585a8..353e63240294b 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 << ""; } -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(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(); new (region) MemSpaceRegion(this); } @@ -251,8 +247,16 @@ StringRegion* MemRegionManager::getStringRegion(const StringLiteral* Str) { return getRegion(Str); } -VarRegion* MemRegionManager::getVarRegion(const VarDecl* d) { - return getRegion(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(LC)) + LC = LC->getParent(); + + return getRegion(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(fd, t); -} - -CodeTextRegion* MemRegionManager::getCodeTextRegion(SymbolRef sym, QualType t) { - return getRegion(sym, t); +CodeTextRegion *MemRegionManager::getCodeTextRegion(const FunctionDecl *FD) { + return getRegion(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(d, superRegion); + return getSubRegion(d, superRegion); } ObjCIvarRegion* MemRegionManager::getObjCIvarRegion(const ObjCIvarDecl* d, const MemRegion* superRegion) { - return getRegion(d, superRegion); + return getSubRegion(d, superRegion); } ObjCObjectRegion* MemRegionManager::getObjCObjectRegion(const ObjCInterfaceDecl* d, const MemRegion* superRegion) { - return getRegion(d, superRegion); -} - -TypedViewRegion* -MemRegionManager::getTypedViewRegion(QualType t, const MemRegion* superRegion) { - return getRegion(t, superRegion); + return getSubRegion(d, superRegion); } AllocaRegion* MemRegionManager::getAllocaRegion(const Expr* E, unsigned cnt) { return getRegion(E, cnt); } - const MemSpaceRegion *MemRegion::getMemorySpace() const { const MemRegion *R = this; const SubRegion* SR = dyn_cast(this); - + while (SR) { R = SR->getSuperRegion(); SR = dyn_cast(R); } - + return dyn_cast(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(SR)) { - R = SR->getSuperRegion(); - SR = dyn_cast(R); +const MemRegion *MemRegion::getBaseRegion() const { + const MemRegion *R = this; + while (true) { + if (const ElementRegion *ER = dyn_cast(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(&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()) { + 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(&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(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 a608ce0d5884c..800496a161429 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(*I)) return true; - + if (PathDiagnosticMacroPiece *MP = dyn_cast(*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(*SM)); } - + return FullSourceLoc(R.getBegin(), const_cast(*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(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 079462e8d19f4..73b445e6ab36b 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 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 : public GRStatePartialTrait { - 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(); 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(CR); } @@ -310,11 +310,11 @@ RangeSet RangeConstraintManager::GetRange(const GRState *state, SymbolRef sym) { if (ConstraintRangeTy::data_type* V = state->get(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(); - + 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 23e8b738b601f..3844d6a6149cc 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 RegionBindingsTy; +typedef llvm::ImmutableMap RegionBindings; //===----------------------------------------------------------------------===// // Fine-grained control of RegionStoreManager. @@ -36,56 +87,26 @@ typedef llvm::ImmutableMap 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 RegionViews; -namespace { class VISIBILITY_HIDDEN RegionViewMap {}; } -static int RegionViewMapIndex = 0; -namespace clang { - template<> struct GRStateTrait - : public GRStatePartialTrait > { - - 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 - : public GRStatePartialTrait > { - 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 - : public GRStatePartialTrait > { - 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 > Map; - - llvm::ImmutableSet::Factory F; + typedef llvm::ImmutableSet SetTy; + typedef llvm::DenseMap 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 &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 S = I->second; for (llvm::ImmutableSet::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 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 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(&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 getBinding(RegionBindings B, const MemRegion *R); + Optional getDirectBinding(RegionBindings B, const MemRegion *R); + /// getDefaultBinding - Returns an SVal* representing an optional default + /// binding associated with a region and its subregions. + Optional 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 getLValueElement(const GRState *state, QualType elementType, - SVal Base, SVal Offset); + SVal getLValueField(const FieldDecl* D, SVal Base); + + 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(&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 *BindDeclWithNoInit(const GRState *state, const VarDecl* VD) { + const GRState *BindDecl(const GRState *ST, const VarDecl *VD, + const LocationContext *LC, SVal InitVal); + + 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 RetrieveElement(const GRState* state, const ElementRegion* R); + SVal RetrieveObjCIvar(const GRState *state, const ObjCIvarRegion *R); - SVal RetrieveField(const GRState* state, const FieldRegion* R); + SVal RetrieveVar(const GRState *state, const VarRegion *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 + 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& 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(store)); + static inline RegionBindings GetRegionBindings(Store store) { + return RegionBindings(static_cast(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 &WL, + const SubRegion *R) { + const MemRegion *superR = R->getSuperRegion(); + if (add(superR, R)) + if (const SubRegion *sr = dyn_cast(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(I.getKey())) - M->add(R->getSuperRegion(), R); + + llvm::SmallVector WL; + + for (RegionBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) + if (const SubRegion *R = dyn_cast(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 + SubRegions(getRegionStoreSubRegionMap(state->getStore())); + + RegionBindings B = GetRegionBindings(state->getStore()); + + llvm::DenseMap Visited; + llvm::SmallVector 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 V = getDirectBinding(B, R)) { + if (const MemRegion *RV = V->getAsRegion()) + WorkList.push_back(RV); + } + + // Handle region. + if (isa(R) || isa(R) || + isa(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(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(R)||isa(R)||isa(R)) + && Visited[cast(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(D)) @@ -455,9 +624,8 @@ SVal RegionStoreManager::getLValueFieldOrIvar(const GRState *St, SVal Base, return loc::MemRegionVal(MRMgr.getFieldRegion(cast(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(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(&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(BaseIdx)) return UnknownVal(); - + const llvm::APSInt& BaseIdxI = cast(BaseIdx).getValue(); const llvm::APSInt& OffI = cast(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(R)) { - // Get the type of the variable. - QualType T = VR->getDesugaredValueType(getContext()); + const MemRegion *R) { - // FIXME: Handle variable-length arrays. - if (isa(T)) + switch (R->getKind()) { + case MemRegion::MemSpaceRegionKind: + assert(0 && "Cannot index into a MemSpace"); return UnknownVal(); - - if (const ConstantArrayType* CAT = dyn_cast(T)) { - // return the size as signed integer. - return ValMgr.makeIntVal(CAT->getSize(), false); - } - const QualType* CastTy = state->get(VR); - - // If the VarRegion is cast to other type, compute the size with respect to - // that type. - if (CastTy) { - QualType EleTy =cast(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(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(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(R)) { - // FIXME: Unsupported yet. - FR = 0; - return UnknownVal(); - } + case MemRegion::VarRegionKind: { + const VarRegion* VR = cast(R); + // Get the type of the variable. + QualType T = VR->getDesugaredValueType(getContext()); - if (isa(R)) { - return UnknownVal(); - } + // FIXME: Handle variable-length arrays. + if (isa(T)) + return UnknownVal(); - if (isa(R)) { - return UnknownVal(); - } + if (const ConstantArrayType* CAT = dyn_cast(T)) { + // return the size as signed integer. + return ValMgr.makeIntVal(CAT->getSize(), false); + } - if (isa(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(Array)) return UnknownVal(); - + const MemRegion* R = cast(&Array)->getRegion(); const TypedRegion* ArrayR = dyn_cast(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(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(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(ToTy.getTypePtr())->getPointeeType(); - - // Process region cast according to the kind of the region being cast. - - // FIXME: Need to handle arbitrary downcasts. - if (isa(R) || isa(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(R) || isa(R) || isa(R) - || isa(R) || isa(R)) { - // If the pointee type is incomplete, do not compute its size, and return - // the original region. - if (const RecordType *RT = dyn_cast(PointeeTy.getTypePtr())) { - const RecordDecl *D = RT->getDecl(); - if (!D->getDefinition(getContext())) - return CastResult(state, R); - } - - QualType ObjTy = cast(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(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(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(MR)) { - QualType T; - // If the SymbolicRegion was cast to another type, use that type. - if (const QualType *t = state->get(SR)) { - T = *t; - } else { - // Otherwise use the symbol's type. + switch (MR->getKind()) { + case MemRegion::SymbolicRegionKind: { + const SymbolicRegion *SR = cast(MR); SymbolRef Sym = SR->getSymbol(); - T = Sym->getType(getContext()); + QualType T = Sym->getType(getContext()); + QualType EleTy; + + if (const PointerType *PT = T->getAs()) + EleTy = PT->getPointeeType(); + else + EleTy = T->getAs()->getPointeeType(); + + SVal ZeroIdx = ValMgr.makeZeroArrayIndex(); + ER = MRMgr.getElementRegion(EleTy, ZeroIdx, SR, getContext()); + break; + } + case MemRegion::AllocaRegionKind: { + const AllocaRegion *AR = cast(MR); + QualType T = getContext().CharTy; // Create an ElementRegion of bytes. + QualType EleTy = T->getAs()->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(MR)) { - // Get the alloca region's current cast type. + case MemRegion::ElementRegionKind: { + ER = cast(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::lookup_type T = state->get(AR); - assert(T && "alloca region has no type."); - QualType EleTy = cast(T->getTypePtr())->getPointeeType(); - SVal ZeroIdx = ValMgr.makeZeroArrayIndex(); - ER = MRMgr.getElementRegion(EleTy, ZeroIdx, AR, getContext()); - } - else if (isa(MR)) { - // Not track pointer arithmetic on struct fields. - return UnknownVal(); - } - else { - ER = cast(MR); - } + case MemRegion::CodeTextRegionKind: + // Technically this can happen if people do funny things with casts. + return UnknownVal(); - SVal Idx = ER->getIndex(); + 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(&Idx); - nonloc::ConcreteInt* Offset = dyn_cast(&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(&R)) { + // FIXME: Should use SValuator here. + SVal NewIdx = + Base->evalBinOp(ValMgr, Op, + cast(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 RegionStoreManager::getDirectBinding(RegionBindings B, + const MemRegion *R) { + if (const BindingVal *BV = B.lookup(R)) + return Optional::create(BV->getDirectValue()); + + return Optional(); +} + +Optional RegionStoreManager::getDefaultBinding(RegionBindings B, + const MemRegion *R) { + + if (R->isBoundable()) + if (const TypedRegion *TR = dyn_cast(R)) + if (TR->getValueType(getContext())->isUnionType()) + return UnknownVal(); + + if (BindingVal const *V = B.lookup(R)) + return Optional::create(V->getDefaultValue()); + + return Optional(); +} + +Optional RegionStoreManager::getBinding(RegionBindings B, + const MemRegion *R) { + if (const BindingVal *BV = B.lookup(R)) + return Optional::create(BV->getValue()); + + return Optional(); +} + +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(); + const PointerType *PUsedTy = UsedTy->getAs(); + + 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(L) && "location unknown"); assert(!isa(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(L)) - return UndefinedVal(); + return SValuator::CastResult(state, UndefinedVal()); const MemRegion *MR = cast(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(MR) || isa(MR)) - return UnknownVal(); + if (isa(MR)) + return SValuator::CastResult(state, UnknownVal()); + + if (const SymbolicRegion *SR = dyn_cast(MR)) + MR = GetElementZeroRegion(SR, T); + + if (isa(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(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(R)) - return RetrieveField(state, FR); + return CastRetrievedVal(RetrieveField(state, FR), state, FR, T); if (const ElementRegion* ER = dyn_cast(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(R)) + return CastRetrievedVal(RetrieveObjCIvar(state, IVR), state, IVR, T); - if (const ObjCIvarRegion *IVR = dyn_cast(R)) { - const MemRegion *SR = IVR->getSuperRegion(); + if (const VarRegion *VR = dyn_cast(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(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 +RegionStoreManager::GetLazyBinding(RegionBindings B, const MemRegion *R) { + if (Optional OV = getDirectBinding(B, R)) + if (const nonloc::LazyCompoundVal *V = + dyn_cast(OV.getPointer())) + return std::make_pair(V->getState(), V->getRegion()); + + if (const ElementRegion *ER = dyn_cast(R)) { + const std::pair &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(R)) { + const std::pair &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(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 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(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()->getElementType(); + if (T != Ctx.getCanonicalType(R->getElementType())) + return UnknownVal(); + const StringLiteral *Str = StrR->getStringLiteral(); SVal Idx = R->getIndex(); if (nonloc::ConcreteInt *CI = dyn_cast(&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(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(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 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(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 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 &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(superR) || isa(superR)) { + superR = cast(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(R)) + return RetrieveElement(lazyBindingState, + cast(lazyBindingRegion)); + + return RetrieveField(lazyBindingState, + cast(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(superR)) { - if (typedSuperR->getValueType(getContext())->isVectorType()) - return UnknownVal(); + + if (isa(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(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(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 V = getDirectBinding(B, R)) + return *V; + + const MemRegion *superR = R->getSuperRegion(); + + // Check if the super region has a binding. + if (Optional 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 V = getDirectBinding(B, R)) return *V; - const MemRegion* superR = R->getSuperRegion(); - if (const SVal* D = state->get(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(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 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(T.getTypePtr()); llvm::ImmutableList 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(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(L)) R = cast(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(L).getRegion(); - + const MemRegion *R = cast(L).getRegion(); + // Check if the region is a struct region. if (const TypedRegion* TR = dyn_cast(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(R)) { + if (ER->getIndex().isZeroConstant()) { + if (const TypedRegion *superR = + dyn_cast(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(R)) { + // Binding directly to a symbolic region should be treated as binding + // to element 0. + QualType T = SR->getSymbol()->getType(getContext()); + T = T->getAs()->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(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(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(&Init)) + return CopyLazyBindings(*LCV, state, R); + + // Remaining case: explicit compound values. nonloc::CompoundVal& CV = cast(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(); RecordDecl* RD = RT->getDecl(); if (!RD->isDefinition()) return state; + // Handle lazy compound values. + if (const nonloc::LazyCompoundVal *LCV=dyn_cast(&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(V)) - return KillStruct(state, R); + return state->makeWithStore(KillStruct(state->getStore(), R)); nonloc::CompoundVal& CV = cast(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 + SubRegions(getRegionStoreSubRegionMap(store)); + RemoveSubRegionBindings(B, R, *SubRegions); // Set the default value of the struct region to "unknown". - state = state->set(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(R)) - if (subRegion->isSubRegionOf(R)) - store = Remove(store, ValMgr.makeLoc(subRegion)); - } - - return state->makeWithStore(store); -} - -//===----------------------------------------------------------------------===// -// Region views. -//===----------------------------------------------------------------------===// + B = RBFactory.Add(B, R, BindingVal(UnknownVal(), BindingVal::Default)); -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(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(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(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(Base, RVFactory.Remove(*d, View)); -} + llvm::OwningPtr + SubRegions(getRegionStoreSubRegionMap(state->getStore())); -const GRState *RegionStoreManager::setCastType(const GRState *state, - const MemRegion* R, QualType T) { - return state->set(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(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(&X)) { - const MemRegion *R = XR->getRegion(); - - while (R) { - if (const SymbolicRegion *SR = dyn_cast(R)) { - SymReaper.markLive(SR->getSymbol()); - return; - } - - if (const SubRegion *SR = dyn_cast(R)) { - R = SR->getSuperRegion(); - continue; - } - - break; - } - - return; - } +namespace { +class VISIBILITY_HIDDEN RBDNode + : public std::pair { +public: + RBDNode(const GRState *st, const MemRegion *r) + : std::pair(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& RegionRoots) -{ - Store store = state->getStore(); - RegionBindingsTy B = GetRegionBindings(store); - - // Lazily constructed backmap from MemRegions to SubRegions. - typedef llvm::ImmutableSet SubRegionsTy; - typedef llvm::ImmutableMap 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& RegionRoots) +{ + Store store = state.getStore(); + RegionBindings B = GetRegionBindings(store); + // The backmap from regions to subregions. - SubRegionsMapTy SubRegMap = SubRegMapF.GetEmptyMap(); + llvm::OwningPtr + 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 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 WorkList; + llvm::DenseMap 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(R)) { - if (SymReaper.isLive(Loc, VR->getDecl())) { - RegionRoots.push_back(VR); // This is a live "root". - } - } - else if (const SymbolicRegion* SR = dyn_cast(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(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(superR)) - IntermediateRoots.push_back(superR); + + if (const SymbolicRegion* SR = dyn_cast(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(cast(R)->getSuperRegion())) + IntermediateRoots.push_back(superR); + } + + // Enqueue the RegionRoots onto WorkList. + for (llvm::SmallVectorImpl::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 Marked; + // Process the worklist. + typedef llvm::DenseMap, 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(); - // Check if we have already processed this region. - if (Marked.count(R)) continue; + // Have we visited this node before? + VisitFlag &VF = Visited[N]; + if (VF >= N.getVisitFlag()) + continue; - // Mark this region as processed. This is needed for termination in case - // a region is referenced more than once. - Marked.insert(R); + const MemRegion *R = N.getRegion(); + const GRState *state_N = N.getState(); + // 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(R)) { + const MemRegion *superR = SR->getSuperRegion(); + if (!isa(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(R) || isa(R) || isa(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(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 V = getBinding(B_N, R); + + if (V) { + // Check for lazy bindings. + if (const nonloc::LazyCompoundVal *LCV = + dyn_cast(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(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(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(frame->getDecl()); + CallExpr const *CE = cast(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 d711ce0a225e3..688b7ff6e1e34 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(sym)) return true; - } else if (const CodeTextRegion *CTR = dyn_cast(R)) { - if (CTR->isSymbolic()) { - SymbolRef sym = CTR->getSymbol(); - if (isa(sym)) - return true; - } } } return false; } -const FunctionDecl* SVal::getAsFunctionDecl() const { +const FunctionDecl *SVal::getAsFunctionDecl() const { if (const loc::MemRegionVal* X = dyn_cast(this)) { const MemRegion* R = X->getRegion(); - if (const CodeTextRegion* CTR = R->getAs()) { - if (CTR->isDeclared()) - return CTR->getDecl(); - } + if (const CodeTextRegion *CTR = R->getAs()) + 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(this)) { - const MemRegion *R = X->getRegion(); - - while (R) { - // Blast through region views. - if (const TypedViewRegion *View = dyn_cast(R)) { - R = View->getSuperRegion(); - continue; - } - - if (const SymbolicRegion *SymR = dyn_cast(R)) - return SymR->getSymbol(); - - break; - } + const MemRegion *R = X->getBaseRegion(); + if (const SymbolicRegion *SymR = dyn_cast(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(this)) return X->getSymbol(); - + if (const nonloc::SymExprVal *X = dyn_cast(this)) if (SymbolRef Y = dyn_cast(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(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(itr.back())) expand(); + while (!isa(itr.back())) expand(); } SVal::symbol_iterator& SVal::symbol_iterator::operator++() { assert(!itr.empty() && "attempting to iterate on an 'end' iterator"); assert(isa(itr.back())); - itr.pop_back(); + itr.pop_back(); if (!itr.empty()) while (!isa(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(SE)) { itr.push_back(SIE->getLHS()); return; - } + } else if (const SymSymExpr *SSE = dyn_cast(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(Data)->getState(); +} + +const TypedRegion *nonloc::LazyCompoundVal::getRegion() const { + return static_cast(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(this)->print(Out); break; - + cast(this)->dumpToStream(os); + break; case LocKind: - cast(this)->print(Out); break; - + cast(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(this)->getValue().getZExtValue(); - + os << cast(this)->getValue().getZExtValue(); if (cast(this)->getValue().isUnsigned()) - Out << 'U'; - + os << 'U'; break; - case nonloc::SymbolValKind: - Out << '$' << cast(this)->getSymbol(); + os << '$' << cast(this)->getSymbol(); break; - case nonloc::SymExprValKind: { const nonloc::SymExprVal& C = *cast(this); const SymExpr *SE = C.getSymbolicExpression(); - Out << SE; + os << SE; break; } - case nonloc::LocAsIntegerKind: { const nonloc::LocAsInteger& C = *cast(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(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(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(this)->getValue().getZExtValue() - << " (Loc)"; + os << cast(this)->getValue().getZExtValue() << " (Loc)"; break; - case loc::GotoLabelKind: - Out << "&&" - << cast(this)->getLabel()->getID()->getName(); + os << "&&" << cast(this)->getLabel()->getID()->getName(); break; - case loc::MemRegionKind: - Out << '&' << cast(this)->getRegion()->getString(); + os << '&' << cast(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 0000000000000..573cac315b3a5 --- /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(L)) { + if (isa(R)) + return EvalBinOpLL(Op, cast(L), cast(R), T); + + return EvalBinOpLN(ST, Op, cast(L), cast(R), T); + } + + if (isa(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(R), cast(L), T); + } + + return EvalBinOpNN(ST, Op, cast(L), cast(R), T); +} + +DefinedOrUnknownSVal SValuator::EvalEQ(const GRState *ST, + DefinedOrUnknownSVal L, + DefinedOrUnknownSVal R) { + return cast(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(val), castTy)); + + // Check for casts from integers to pointers. + if (Loc::IsLocType(castTy) && originalTy->isIntegerType()) { + if (nonloc::LocAsInteger *LV = dyn_cast(&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(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(originalTy)->getElementType(); + // QualType pointerTy = C.getPointerType(elemTy); + return CastResult(state, EvalCastL(cast(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(val) ? EvalCastL(cast(val), castTy) + : EvalCastNL(cast(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(X.getSVal())); +} diff --git a/lib/Analysis/SimpleConstraintManager.cpp b/lib/Analysis/SimpleConstraintManager.cpp index 82801eb05d383..015db76080dfb 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(&X)) { const SymExpr *SE = SymVal->getSymbolicExpression(); - + if (isa(SE)) return true; - + if (const SymIntExpr *SIE = dyn_cast(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(Cond)) return Assume(state, cast(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(Cond).getRegion(); const SubRegion *SubR = dyn_cast(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(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(SubR->getSuperRegion()); } - + // FALL-THROUGH. } - + case loc::GotoLabelKind: return Assumption ? state : NULL; case loc::ConcreteIntKind: { - bool b = cast(Cond).getValue() != 0; + bool b = cast(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(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(Cond); - if (const SymIntExpr *SE = dyn_cast(V.getSymbolicExpression())) - return AssumeSymInt(state, Assumption, SE); - + if (const SymIntExpr *SE = dyn_cast(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(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(Idx) && isa(UpperBound))) diff --git a/lib/Analysis/SimpleConstraintManager.h b/lib/Analysis/SimpleConstraintManager.h index 1e1a10da030fc..0c58440ac0b6d 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 76a8bc782eb57..636ce15c33264 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(&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(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(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(val)) return ValMgr.makeLocAsInteger(val, BitWidth); - + llvm::APSInt i = cast(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(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(lhs).getValue(), resultTy); break; - } + } case loc::MemRegionKind: { if (SymbolRef lSym = lhs.getAsLocSymbol()) { if (isa(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(lhs).getLoc(); + Loc lhsL = cast(lhs).getLoc(); switch (rhs.getSubKind()) { case nonloc::LocAsIntegerKind: return EvalBinOpLL(op, lhsL, cast(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(lhs).getSymbolicExpression(); - + // Only handle ($sym op constant) for now. if (const SymIntExpr *symIntExpr = dyn_cast(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(rhs)) { const nonloc::ConcreteInt& lhsInt = cast(lhs); return lhsInt.evalBinOp(ValMgr, op, cast(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(&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(&rhs)){ + BasicValueFactory &BVF = ValMgr.getBasicValueFactory(); + lhs = nonloc::ConcreteInt(BVF.Convert(rhs_I->getValue(), + *Constant)); + continue; + } + } + if (isa(rhs)) { - return ValMgr.makeNonLoc(cast(lhs).getSymbol(), op, + return ValMgr.makeNonLoc(slhs->getSymbol(), op, cast(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 cb099862f0551..4b4ae6580820f 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()) { + 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(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(R) || isa(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(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(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()->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(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(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(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(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(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(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(R) || isa(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 275f30a2963e0..22e1101929562 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(SE)->getSymbolID(); - return; - case SymExpr::SymIntKind: - print(os, cast(SE)); - return; - case SymExpr::SymSymKind: - print(os, cast(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(); - new (SD) SymbolRegionValue(SymbolCounter, R, T); + new (SD) SymbolRegionValue(SymbolCounter, R, T); DataSet.InsertNode(SD, InsertPos); ++SymbolCounter; } - + return cast(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(); - 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(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(); + new (SD) SymbolDerived(SymbolCounter, parentSymbol, R); + DataSet.InsertNode(SD, InsertPos); + ++SymbolCounter; + } + + return cast(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(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(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(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(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(sym); diff --git a/lib/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp index 014ea8255e680..8e7b15862d665 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 { + : public CFGRecStmtDeclVisitor { 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 { - + 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(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(E->IgnoreParenCasts())) - if (VarDecl* VD = dyn_cast(DR->getDecl())) + if (VarDecl* VD = dyn_cast(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(*I); if (VD && VD->isBlockVarDecl()) { - if (Stmt* I = VD->getInit()) + if (Stmt* I = VD->getInit()) V(VD,AD) = AD.FullUninitTaint ? V(cast(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(S))) return V(static_cast(S),AD); else return static_cast*>(this)->Visit(S); } bool TransferFuncs::BlockStmt_VisitExpr(Expr* E) { - bool x = static_cast*>(this)->Visit(E); + bool x = static_cast*>(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 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 724a2e92d7448..fe670e79b3b53 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(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(&V)) { + const llvm::APSInt& I = CI->getValue(); + if (I.getBitWidth() == ArrayIndexWidth && I.isSigned()) + return V; } - return UnknownVal(); + return SVator->EvalCastNL(cast(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(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 6cb5dab53df24..1a3293775ed61 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 &Names, bool NoBuiltins) { // Final all target-independent names @@ -65,18 +65,18 @@ Builtin::Context::GetBuiltinNames(llvm::SmallVectorImpl &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 e0e9a10e51958..527ebf965934b 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 e5dd3e6bf5706..124e386c55265 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 78b8b0a855977..4a29997a2ccc3 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 DiagInfo; std::map 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::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 &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 &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 &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 &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 &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 &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 &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 &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 &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 cc25d33051586..df86f9d04702e 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 +#include +#include 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 UniqueDirs; + llvm::StringMap 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, DirectoryEntry> UniqueDirs; + std::map, 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 &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 &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 3810c49f71f31..93c260fdbe17a 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::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::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(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(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(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(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()); new (SI) MultiKeywordSelector(nKeys, IIV); SelTabImpl.Table.InsertNode(SI, InsertPos); diff --git a/lib/Basic/Makefile b/lib/Basic/Makefile index 3fd6c2c153842..5bd4314f45cdc 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 f21ec8b1e9d7e..578a4eb34bab5 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 << ""; 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 << " -#include 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(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 &Entry = + llvm::StringMapEntry &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 &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 &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 &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 &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 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(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 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(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(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::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 SourceManager::getInstantiationRange(SourceLocation Loc) const { if (Loc.isFileID()) return std::make_pair(Loc, Loc); - + std::pair 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 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 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(LineOffsets.size()); @@ -718,7 +772,7 @@ unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos) const { else Content = const_cast(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 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 ""; - + 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 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 LOffs = getDecomposedLoc(LHS); std::pair 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::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::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 ba7f190408b29..9cd12493e7a49 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 3f7d9a31c61e9..1d4d1235c9634 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 &Buf, const char *Macro, - const char *Val = "1") { +static void Define(std::vector &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 &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 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 &Defines) const=0; public: OSTargetInfo(const std::string& triple) : TgtInfo(triple) {} virtual void getTargetDefines(const LangOptions &Opts, std::vector &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 &Defs, const LangOptions &Opts) { Define(Defs, "__APPLE_CC__", "5621"); @@ -156,81 +102,94 @@ static void getDarwinDefines(std::vector &Defs, const LangOptions &Opts) { Define(Defs, "__STATIC__"); else Define(Defs, "__DYNAMIC__"); + + if (Opts.POSIXThreads) + Define(Defs, "_REENTRANT", "1"); } -static void getDarwinOSXDefines(std::vector &Defs, const char *Triple) { +static void getDarwinOSXDefines(std::vector &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 &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 class DarwinTargetInfo : public OSTargetInfo { protected: - virtual void getOSDefines(const LangOptions &Opts, const char *Triple, + virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, std::vector &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 class DragonFlyBSDTargetInfo : public OSTargetInfo { protected: - virtual void getOSDefines(const LangOptions &Opts, const char *Triple, + virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, std::vector &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(triple) {} }; @@ -278,11 +234,13 @@ public: template class FreeBSDTargetInfo : public OSTargetInfo { protected: - virtual void getOSDefines(const LangOptions &Opts, const char *Triple, + virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, std::vector &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(triple) {} + FreeBSDTargetInfo(const std::string &triple) + : OSTargetInfo(triple) { + this->UserLabelPrefix = ""; + } }; // Linux target template class LinuxTargetInfo : public OSTargetInfo { protected: - virtual void getOSDefines(const LangOptions &Opts, const char *Triple, + virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, std::vector &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(triple) { this->UserLabelPrefix = ""; } }; +// NetBSD Target +template +class NetBSDTargetInfo : public OSTargetInfo { +protected: + virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + std::vector &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(triple) { + this->UserLabelPrefix = ""; + } +}; + // OpenBSD Target template class OpenBSDTargetInfo : public OSTargetInfo { protected: - virtual void getOSDefines(const LangOptions &Opts, const char *Triple, + virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, std::vector &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(triple) {} }; @@ -340,7 +324,7 @@ public: template class SolarisTargetInfo : public OSTargetInfo { protected: - virtual void getOSDefines(const LangOptions &Opts, const char *Triple, + virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, std::vector &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(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 &Features, const std::string &Name, bool Enabled) const; - virtual void getDefaultFeatures(const std::string &CPU, + virtual void getDefaultFeatures(const std::string &CPU, llvm::StringMap &Features) const; virtual void HandleTargetFeatures(const llvm::StringMap &Features); }; -void X86TargetInfo::getDefaultFeatures(const std::string &CPU, +void X86TargetInfo::getDefaultFeatures(const std::string &CPU, llvm::StringMap &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 &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 &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 &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 { +public: + OpenBSDI386TargetInfo(const std::string& triple) : + OpenBSDTargetInfo(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 &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 &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 &Defines) const { + X86_32TargetInfo::getTargetDefines(Opts, Defines); + Define(Defines, "__CYGWIN__"); + Define(Defines, "__CYGWIN32__"); + DefineStd(Defines, "unix", Opts); } }; } // end anonymous namespace @@ -963,47 +1049,183 @@ 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 &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 &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 &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 { public: - DarwinX86_64TargetInfo(const std::string& triple) + DarwinX86_64TargetInfo(const std::string& triple) : DarwinTargetInfo(triple) { Int64Type = SignedLongLong; } }; } // end anonymous namespace +namespace { +class OpenBSDX86_64TargetInfo : public OpenBSDTargetInfo { +public: + OpenBSDX86_64TargetInfo(const std::string& triple) + : OpenBSDTargetInfo(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 &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 { protected: - virtual void getOSDefines(const LangOptions &Opts, const char *Triple, + virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, std::vector &Defines) const { getDarwinDefines(Defines, Opts); getDarwinIPhoneOSDefines(Defines, Triple); } public: - DarwinARMTargetInfo(const std::string& triple) + DarwinARMTargetInfo(const std::string& triple) : DarwinTargetInfo(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 &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 &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 &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 &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(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(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(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(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(T); - if (isOpenBSD) - return new OpenBSDTargetInfo(T); - if (isFreeBSD) - return new FreeBSDTargetInfo(T); - if (isSolaris) - return new SolarisTargetInfo(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(T); - if (isDragonFly) + case llvm::Triple::DragonFly: return new DragonFlyBSDTargetInfo(T); - if (isOpenBSD) - return new OpenBSDTargetInfo(T); - if (isFreeBSD) + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo(T); + case llvm::Triple::OpenBSD: + return new OpenBSDI386TargetInfo(T); + case llvm::Triple::FreeBSD: return new FreeBSDTargetInfo(T); - if (isSolaris) + case llvm::Triple::Solaris: return new SolarisTargetInfo(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(T); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo(T); + case llvm::Triple::OpenBSD: + return new OpenBSDX86_64TargetInfo(T); + case llvm::Triple::FreeBSD: + return new FreeBSDTargetInfo(T); + case llvm::Triple::Solaris: + return new SolarisTargetInfo(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 0000000000000..30383f6251f64 --- /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 +#include +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 e3da531011eeb..2bfaa445e5686 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 58e5a778cf33c..1ab2f55295fa0 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 d5f803ba98bfd..736425e01276c 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 +#include + 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 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(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(); 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(), 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()->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(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(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(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(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 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 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 5d46ac78f693e..3a860c0d3c369 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 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 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 a919dfa2e32cf..987cd24e2c8b5 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 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 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 5f3acea767d5c..3960cf51868f8 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 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()) { + CXXRecordDecl *RD = cast(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(MD)) + if (Destructor->isTrivial()) + return RValue::get(0); + + const FunctionProtoType *FPT = MD->getType()->getAs(); + 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()->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(Base)) { + if (const VarDecl *VD = dyn_cast(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(Base)) + return true; + + // And calls on bound temporaries. + if (isa(Base)) + return true; + + // Check if this is a call expr that returns a record type. + if (const CallExpr *CE = dyn_cast(Base)) + return CE->getCallReturnType()->isRecordType(); + + // We can't devirtualize the call. + return false; +} + RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE) { + if (isa(CE->getCallee())) + return EmitCXXMemberPointerCallExpr(CE); + const MemberExpr *ME = cast(CE->getCallee()); const CXXMethodDecl *MD = cast(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(); + + 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(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(E->getCallee()); + const Expr *BaseExpr = BO->getLHS(); + const Expr *MemFnExpr = BO->getRHS(); + const MemberPointerType *MPT = + MemFnExpr->getType()->getAs(); + const FunctionProtoType *FPT = + MPT->getPointeeType()->getAs(); + const CXXRecordDecl *RD = + cast(cast(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()->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(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(); + 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(CurFuncDecl) && + assert(isa(CurFuncDecl) && "Must be in a C++ member function decl to load 'this'"); assert(cast(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(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(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(E->getType()->getAsRecordType()->getDecl()); + + const CXXRecordDecl *RD = + cast(E->getType()->getAs()->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( 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( 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()->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()->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(); + 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(); + 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(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()->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(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(); + 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()->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()->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(); + 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()->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(Base->getType()->getAs()->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()) { + CXXRecordDecl *FieldClassDecl + = cast(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(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(Base->getType()->getAs()->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()) { + CXXRecordDecl *FieldClassDecl + = cast(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(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(BaseType->getAs()->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()) { + 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(Base->getType()->getAs()->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() || Field->isAnonymousStructOrUnion()) + continue; + const RecordType *ClassRec = FieldType->getAs(); + CXXRecordDecl *MemberClassDecl = + dyn_cast(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(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(); + CXXRecordDecl *FieldClassDecl = cast(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(); + CXXRecordDecl *BaseClassDecl = cast(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 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()) { + CXXRecordDecl *FieldClassDecl = cast(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(); + CXXRecordDecl *FieldClassDecl = cast(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 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(Base->getType()->getAs()->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 6051d9133c026..1e6adb05a0d92 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 0000000000000..56a28fc9a007a --- /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(BS->getType()->getAs()->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(ClassDecl)-> + isDerivedFrom(const_cast(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(ClassDecl)-> + isDerivedFrom(const_cast(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(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(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 0000000000000..2d62df6c58a44 --- /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(); + if (!RT) + return 0; + + const CXXRecordDecl *RD = dyn_cast(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(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(); + + 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(Arg)) { + if (ICE->getCastKind() != CastExpr::CK_UserDefinedConversion && + ICE->getType()->isVoidPointerType()) + Arg = ICE->getSubExpr(); + else + break; + } + + QualType DeleteTy = Arg->getType()->getAs()->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()) { + if (CXXRecordDecl *RD = dyn_cast(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(); + + 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 a6e6d11505b63..4768556f6bcac 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 97391bc620be7..bad166f01ef5d 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()); + // FIXME: Set calling convention correctly, it needs to be associated with the + // type somehow. + return getFunctionInfo(FTNP->getResultType(), + llvm::SmallVector(), 0); } -const +const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionProtoType *FTP) { llvm::SmallVector 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()) + return llvm::CallingConv::X86_StdCall; + + if (D->hasAttr()) + return llvm::CallingConv::X86_FastCall; + + return llvm::CallingConv::C; +} + +const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXRecordDecl *RD, + const FunctionProtoType *FTP) { + llvm::SmallVector 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(); 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(FD)) if (MD->isInstance()) return getFunctionInfo(MD); + + unsigned CallingConvention = getCallingConventionForDecl(FD); + const FunctionType *FTy = FD->getType()->getAs(); + if (const FunctionNoProtoType *FNTP = dyn_cast(FTy)) + return getFunctionInfo(FNTP->getResultType(), + llvm::SmallVector(), + CallingConvention); - const FunctionType *FTy = FD->getType()->getAsFunctionType(); - if (const FunctionProtoType *FTP = dyn_cast(FTy)) - return getFunctionInfo(FTP); - return getFunctionInfo(cast(FTy)); + const FunctionProtoType *FPT = cast(FTy); + llvm::SmallVector 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 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 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 &ArgTys) { + const llvm::SmallVector &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 &ArgTys) { +CGFunctionInfo::CGFunctionInfo(unsigned _CallingConvention, + QualType ResTy, + const llvm::SmallVector &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 &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 &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(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(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()) @@ -385,6 +437,8 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, FuncAttrs |= llvm::Attribute::ReadNone; else if (TargetDecl->hasAttr()) FuncAttrs |= llvm::Attribute::ReadOnly; + if (TargetDecl->hasAttr()) + 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()) 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 Tys; + std::vector 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(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(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(Callee->stripPointerCasts())) - CS.setCallingConv(F->getCallingConv()); + CS.setCallingConv(static_cast(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 daf6f00045012..ebf801dcaad1e 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, + typedef llvm::SmallVector, 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 &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 - 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 2bf8a222a2531..4c624205b4cac 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(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 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 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 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(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(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(EltTy))) { uint64_t Upper = 0; if (const ConstantArrayType *CAT = dyn_cast(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::iterator it = + TypeCache.find(Ty.getAsOpaquePtr()); + if (it != TypeCache.end()) { + // Verify that the debug info still exists. + if (&*it->second) + return llvm::DIType(cast(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

    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(Ty), Unit); - case Type::Builtin: return Slot = CreateType(cast(Ty), Unit); - case Type::Complex: return Slot = CreateType(cast(Ty), Unit); - case Type::Pointer: return Slot = CreateType(cast(Ty), Unit); + case Type::ObjCObjectPointer: + return CreateType(cast(Ty), Unit); + case Type::ObjCInterface: + return CreateType(cast(Ty), Unit); + case Type::Builtin: return CreateType(cast(Ty), Unit); + case Type::Complex: return CreateType(cast(Ty), Unit); + case Type::Pointer: return CreateType(cast(Ty), Unit); case Type::BlockPointer: - return Slot = CreateType(cast(Ty), Unit); - case Type::Typedef: return Slot = CreateType(cast(Ty), Unit); + return CreateType(cast(Ty), Unit); + case Type::Typedef: return CreateType(cast(Ty), Unit); case Type::Record: case Type::Enum: - return Slot = CreateType(cast(Ty), Unit); + return CreateType(cast(Ty), Unit); case Type::FunctionProto: case Type::FunctionNoProto: - return Slot = CreateType(cast(Ty), Unit); - + return CreateType(cast(Ty), Unit); + case Type::Elaborated: + return getOrCreateType(cast(Ty)->getUnderlyingType(), + Unit); + case Type::ConstantArray: + case Type::ConstantArrayWithExpr: + case Type::ConstantArrayWithoutExpr: case Type::VariableArray: case Type::IncompleteArray: - return Slot = CreateType(cast(Ty), Unit); + return CreateType(cast(Ty), Unit); case Type::TypeOfExpr: - return Slot = getOrCreateType(cast(Ty)->getUnderlyingExpr() - ->getType(), Unit); + return getOrCreateType(cast(Ty)->getUnderlyingExpr() + ->getType(), Unit); case Type::TypeOf: - return Slot = getOrCreateType(cast(Ty)->getUnderlyingType(), - Unit); + return getOrCreateType(cast(Ty)->getUnderlyingType(), Unit); case Type::Decltype: - return Slot = getOrCreateType(cast(Ty)->getUnderlyingExpr() - ->getType(), Unit); + return getOrCreateType(cast(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()) { + llvm::DICompileUnit DefUnit; + unsigned Tag = llvm::dwarf::DW_TAG_structure_type; + + llvm::SmallVector 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()) { + llvm::DICompileUnit DefUnit; + unsigned Tag = llvm::dwarf::DW_TAG_structure_type; + + llvm::SmallVector 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 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 de655800fa080..0a617b999240e 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 #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 TypeCache; - + std::map 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 2ae7e225ebbf0..7feff83dee6bb 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(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(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()) 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(CurFuncDecl)) ContextName = CGM.getMangledName(FD); else if (isa(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()) { 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()) GV->setSection(SA->getName()); - + if (D.hasAttr()) CGM.AddUsedGlobal(GV); @@ -202,7 +201,13 @@ void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D) { DI->EmitGlobalVariable(static_cast(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 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 &Info = ByRefValueInfo[D]; + if (Info.first) + return Info.first; + + QualType Ty = D->getType(); + + std::vector 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(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(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(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()) + DtorTy = Array->getElementType(); + if (const RecordType *RT = DtorTy->getAs()) + if (CXXRecordDecl *ClassDecl = dyn_cast(RT->getDecl())) { + if (!ClassDecl->hasTrivialDestructor()) { + const CXXDestructorDecl *D = ClassDecl->getDestructor(getContext()); + assert(D && "EmitLocalBlockVarDecl - destructor is nul"); + assert(!Ty->getAs() && "FIXME - destruction of arrays NYI"); + + CleanupScope scope(*this); + EmitCXXDestructorCall(D, Dtor_Complete, DeclPtr); + } + } + // Handle the cleanup attribute if (const CleanupAttr *CA = D.getAttr()) { 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(D) || isa(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 0951019f01087..2834dfeb780a6 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()) { + if (CXXRecordDecl *ClassDecl = dyn_cast(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(Elts)) return 0; - + return cast(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()) { 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(E)); - case Expr::CallExprClass: + case Expr::CallExprClass: + case Expr::CXXMemberCallExprClass: case Expr::CXXOperatorCallExprClass: return EmitCallExprLValue(cast(E)); case Expr::VAArgExprClass: return EmitVAArgExprLValue(cast(E)); - case Expr::DeclRefExprClass: + case Expr::DeclRefExprClass: case Expr::QualifiedDeclRefExprClass: return EmitDeclRefLValue(cast(E)); case Expr::ParenExprClass:return EmitLValue(cast(E)->getSubExpr()); @@ -184,7 +207,7 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { case Expr::ObjCEncodeExprClass: return EmitObjCEncodeExprLValue(cast(E)); - case Expr::BlockDeclRefExprClass: + case Expr::BlockDeclRefExprClass: return EmitBlockDeclRefLValue(cast(E)); case Expr::CXXConditionDeclExprClass: @@ -194,31 +217,34 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { return EmitCXXConstructLValue(cast(E)); case Expr::CXXBindTemporaryExprClass: return EmitCXXBindTemporaryLValue(cast(E)); + case Expr::CXXExprWithTemporariesClass: + return EmitCXXExprWithTemporariesLValue(cast(E)); case Expr::ObjCMessageExprClass: return EmitObjCMessageExprLValue(cast(E)); - case Expr::ObjCIvarRefExprClass: + case Expr::ObjCIvarRefExprClass: return EmitObjCIvarRefLValue(cast(E)); case Expr::ObjCPropertyRefExprClass: return EmitObjCPropertyRefLValue(cast(E)); - case Expr::ObjCKVCRefExprClass: - return EmitObjCKVCRefLValue(cast(E)); + case Expr::ObjCImplicitSetterGetterRefExprClass: + return EmitObjCKVCRefLValue(cast(E)); case Expr::ObjCSuperExprClass: return EmitObjCSuperExprLValue(cast(E)); case Expr::StmtExprClass: return EmitStmtExprLValue(cast(E)); - case Expr::UnaryOperatorClass: + case Expr::UnaryOperatorClass: return EmitUnaryOpLValue(cast(E)); case Expr::ArraySubscriptExprClass: return EmitArraySubscriptExpr(cast(E)); case Expr::ExtVectorElementExprClass: return EmitExtVectorElementExpr(cast(E)); - case Expr::MemberExprClass: return EmitMemberExpr(cast(E)); + case Expr::MemberExprClass: + return EmitMemberExpr(cast(E)); case Expr::CompoundLiteralExprClass: return EmitCompoundLiteralLValue(cast(E)); case Expr::ConditionalOperatorClass: - return EmitConditionalOperator(cast(E)); + return EmitConditionalOperatorLValue(cast(E)); case Expr::ChooseExprClass: return EmitLValue(cast(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(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(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(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(); 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 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(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()) { unsigned NumSrcElts = VTy->getNumElements(); unsigned NumDstElts = cast(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 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 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 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(E)) { + LV.SetObjCIvar(LV, true); + ObjCIvarRefExpr *Exp = cast(const_cast(E)); + LV.setBaseIvarExp(Exp->getBase()); + LV.SetObjCArray(LV, E->getType()->isArrayType()); + return; + } + if (const DeclRefExpr *Exp = dyn_cast(E)) { + if (const VarDecl *VD = dyn_cast(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(E)) + setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV); + else if (const ParenExpr *Exp = dyn_cast(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()->getPointeeType(); + if (ExpTy->isRecordType()) + LV.SetObjCIvar(LV, false); + } + } + else if (const ImplicitCastExpr *Exp = dyn_cast(E)) + setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV); + else if (const CStyleCastExpr *Exp = dyn_cast(E)) + setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV); + else if (const ArraySubscriptExpr *Exp = dyn_cast(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(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(E->getDecl()); - + if (VD && (VD->isBlockVarDecl() || isa(VD) || isa(VD))) { LValue LV; - bool NonGCable = VD->hasLocalStorage() && + bool NonGCable = VD->hasLocalStorage() && !VD->hasAttr(); 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()) { - 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(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()) { // 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(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(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(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(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 &Elts) { +static +llvm::Constant *GenerateConstantVector(llvm::LLVMContext &VMContext, + llvm::SmallVector &Elts) { llvm::SmallVector 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(); 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(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(); if (PTy->getPointeeType()->isUnionType()) isUnion = true; - CVRQualifiers = PTy->getPointeeType().getCVRQualifiers(); - } else if (isa(BaseExpr) || - isa(BaseExpr)) { + BaseQuals = PTy->getPointeeType().getQualifiers(); + } else if (isa(BaseExpr->IgnoreParens()) || + isa( + 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(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(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(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(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(); + CXXRecordDecl *DerivedClassDecl = + cast(DerivedClassTy->getDecl()); + + const RecordType *BaseClassTy = E->getType()->getAs(); + CXXRecordDecl *BaseClassDecl = cast(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(E)) return EmitCXXMemberCallExpr(CE); - + const Decl *TargetDecl = 0; if (const ImplicitCastExpr *CE = dyn_cast(E->getCallee())) { if (const DeclRefExpr *DRE = dyn_cast(CE->getSubExpr())) { TargetDecl = DRE->getDecl(); if (const FunctionDecl *FD = dyn_cast(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(E)) if (const CXXMethodDecl *MD = dyn_cast_or_null(TargetDecl)) return EmitCXXOperatorMemberCallExpr(CE, MD); - + + if (isa(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()->getPointeeType(); + QualType ResultType = FnType->getAs()->getResultType(); CallArgList Args; - EmitCallArgs(Args, FnType->getAsFunctionProtoType(), ArgBeg, ArgEnd); - - return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), + EmitCallArgs(Args, FnType->getAs(), 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(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 412a06594f532..0866ff893c4e3 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 { 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(SrcType->getAs()-> + getClass()->getAs()->getDecl()); + const CXXRecordDecl *DstDecl = + cast(E->getType()->getAs()-> + getClass()->getAs()->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(); + assert(MPT->getPointeeType()->isFunctionProtoType() && + "Unexpected member pointer type!"); + + const QualifiedDeclRefExpr *DRE = cast(E->getSubExpr()); + const CXXMethodDecl *MD = cast(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()) + 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(DestPtr->getType()); const llvm::ArrayType *AType = cast(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()->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(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 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 3555c8c9b6917..9e81e4fbeabee 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()->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()->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()->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()->getElementType(); + DestType = DestType->getAs()->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()->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(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()->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()->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()->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()->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(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 37c9c366fee64..7f540c3c06885 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 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(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(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 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()->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 { 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()) { + QualType T = MPT->getPointeeType(); + if (T->isFunctionProtoType()) { + QualifiedDeclRefExpr *DRE = cast(E->getSubExpr()); + + return EmitMemberFunctionPointer(cast(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(E->getLHS()->IgnoreParenNoopCasts(CGM.getContext())) || + !isa(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 Elts; + std::vector 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(); + const MemberPointerType *DestTy = + E->getType()->getAs(); + + const CXXRecordDecl *BaseClass = + cast(cast(SrcTy->getClass())->getDecl()); + const CXXRecordDecl *DerivedClass = + cast(cast(DestTy->getClass())->getDecl()); + + if (SrcTy->getPointeeType()->isFunctionProtoType()) { + llvm::Constant *C = + CGM.EmitConstantExpr(SubExpr, SubExpr->getType(), CGF); + if (!C) + return 0; + + llvm::ConstantStruct *CS = cast(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(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(ILE->getInit(0)) || isa(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 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& 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(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(ConvertType(ILE->getType())); - RecordDecl *RD = ILE->getType()->getAsRecordType()->getDecl(); - std::vector 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 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 Elts; - std::vector 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 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(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(E)->getDecl(); if (const FunctionDecl *FD = dyn_cast(Decl)) - return CGM.GetAddrOfFunction(GlobalDecl(FD)); + return CGM.GetAddrOfFunction(FD); if (const VarDecl* VD = dyn_cast(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(E)->getIdentType() == + if (cast(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(E)->getLabel()); - llvm::Constant *C = llvm::ConstantInt::get(llvm::Type::Int32Ty, id); + unsigned id = + CGF->GetIDForAddrOfLabel(cast(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(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(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 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(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()) + 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 Array(NumElements); + for (uint64_t i = 0; i != NumElements; ++i) + Array[i] = Element; + + const llvm::ArrayType *ATy = + cast(getTypes().ConvertTypeForMem(T)); + return llvm::ConstantArray::get(ATy, Array); + } + } + + if (const RecordType *RT = T->getAs()) { + 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 2af0639f5ce38..cc81256032afb 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(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(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(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(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(DstTy)) { // The source value may be an integer, or a pointer. if (isa(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(Src->getType())) { // Must be an ptr to int cast. assert(isa(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(SrcType)) { + if (DstType->isExtVectorType() && !SrcType->isVectorType()) { // Cast the scalar to element type - QualType EltTy = DstType->getAsExtVectorType()->getElementType(); + QualType EltTy = DstType->getAs()->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 Args; unsigned NumElements = cast(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(Src->getType()) || isa(DstTy)) return Builder.CreateBitCast(Src, DstTy, "conv"); - + // Finally, we have the arithmetic types: real int/float. if (isa(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(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()->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(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(V->getType()) && "Expected pointer"); assert(isa(cast(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(DestTy)) - V = Builder.CreateBitCast(V, DestTy, "ptrconv"); + const llvm::Type *DestLTy = ConvertType(DestTy); + if (V->getType() != DestLTy) { + if (isa(DestLTy)) + V = Builder.CreateBitCast(V, DestLTy, "ptrconv"); else { - assert(isa(DestTy) && "Unknown array decay"); - V = Builder.CreatePtrToInt(V, DestTy, "ptrconv"); + assert(isa(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()->getPointeeType()->getAs(); + CXXRecordDecl *DerivedClassDecl = + cast(DerivedClassTy->getDecl()); + + const RecordType *BaseClassTy = + DestTy->getAs()->getPointeeType()->getAs(); + CXXRecordDecl *BaseClassDecl = cast(BaseClassTy->getDecl()); + + Value *Src = Visit(const_cast(E)); - return EmitCastExpr(Op, E->getType()); -} + bool NullCheckValue = true; + + if (isa(E)) { + // We always assume that 'this' is never null. + NullCheckValue = false; + } else if (const ImplicitCastExpr *ICE = dyn_cast(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(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(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(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()->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(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(PT->getElementType())) { - NextVal = Builder.CreateGEP(InVal, Inc, "ptrincdec"); + QualType PTEE = ValTy->getPointeeType(); + if (const ObjCInterfaceType *OIT = + dyn_cast(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(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(AmountVal))); - else if (InVal->getType() == llvm::Type::DoubleTy) - NextVal = - llvm::ConstantFP::get(llvm::APFloat(static_cast(AmountVal))); + if (InVal->getType()->isFloatTy()) + NextVal = + llvm::ConstantFP::get(VMContext, + llvm::APFloat(static_cast(AmountVal))); + else if (InVal->getType()->isDoubleTy()) + NextVal = + llvm::ConstantFP::get(VMContext, + llvm::APFloat(static_cast(AmountVal))); else { llvm::APFloat F(static_cast(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 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(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()->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(); + const ObjCObjectPointerType *OPT = + Ops.E->getLHS()->getType()->getAs(); + 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(); + OPT = Ops.E->getRHS()->getType()->getAs(); + 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(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()->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(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(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()->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(E)) return isCheapEnoughToEvaluateUnconditionally(PE->getSubExpr()); - + // TODO: Allow anything we can constant fold to an integer or fp constant. if (isa(E) || isa(E) || isa(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(E)) if (const VarDecl *VD = dyn_cast(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(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(V1->getType())->getNumElements(); - + va_list va; va_start(va, V2); - + llvm::SmallVector 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 33cb5bca3869b..cadba328bf12a 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(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(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()) + if (CGM.getDebugInfo() && !OMD->hasAttr()) 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, // , ). // 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(CurFuncDecl); ImplicitParamDecl *selfDecl = OMD->getSelfDecl(); - const PointerType *PTy = - cast(getContext().getCanonicalType(selfDecl->getType())); + const ObjCObjectPointerType *PTy = cast( + 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(CurFuncDecl); bool isClassMessage = OMD->isClassMethod(); bool isCategoryImpl = isa(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(Exp)) { Selector S = E->getProperty()->getGetterName(); if (isa(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(Exp); + } else { + const ObjCImplicitSetterGetterRefExpr *KE = + cast(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(KE->getBase())) + } else if (isa(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(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(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(Exp)) { + } else if (const ObjCImplicitSetterGetterRefExpr *E = + dyn_cast(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(E->getBase())) { + } else if (isa(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(D)->getType(); - DeclAddress = LocalDeclMap[D]; + DeclAddress = LocalDeclMap[D]; } else { ElementTy = cast(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 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(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(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 6554da9cf98c9..f348bfffcb869 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 &IvarNames, @@ -77,12 +81,19 @@ private: const llvm::SmallVectorImpl &IvarOffsets); llvm::Constant *GenerateMethodList(const std::string &ClassName, const std::string &CategoryName, - const llvm::SmallVectorImpl &MethodSels, - const llvm::SmallVectorImpl &MethodTypes, + const llvm::SmallVectorImpl &MethodSels, + const llvm::SmallVectorImpl &MethodTypes, bool isClassMethodList); llvm::Constant *GenerateEmptyProtocol(const std::string &ProtocolName); + llvm::Constant *GeneratePropertyList(const ObjCImplementationDecl *OID, + llvm::SmallVectorImpl &InstanceMethodSels, + llvm::SmallVectorImpl &InstanceMethodTypes); llvm::Constant *GenerateProtocolList( const llvm::SmallVectorImpl &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 &MethodNames, const llvm::SmallVectorImpl &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 &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 &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( CGM.getTypes().ConvertType(CGM.getContext().IntTy)); LongTy = cast( 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( CGM.getTypes().ConvertType(CGM.getContext().getObjCSelType())); PtrToIntTy = llvm::PointerType::getUnqual(IntTy); PtrTy = PtrToInt8Ty; - + // Object type - IdTy = cast( - CGM.getTypes().ConvertType(CGM.getContext().getObjCIdType())); - + ASTIdTy = CGM.getContext().getObjCIdType(); + IdTy = cast(CGM.getTypes().ConvertType(ASTIdTy)); + // IMP type std::vector 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 &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 &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 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 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(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 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 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(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(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 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 &MethodSels, - const llvm::SmallVectorImpl &MethodTypes, + const std::string &CategoryName, + const llvm::SmallVectorImpl &MethodSels, + const llvm::SmallVectorImpl &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 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 &IvarNames, const llvm::SmallVectorImpl &IvarTypes, const llvm::SmallVectorImpl &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 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 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 &MethodNames, const llvm::SmallVectorImpl &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 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 &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 Elements; + std::vector 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 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 Elements; + std::vector 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 InstanceMethodNames; llvm::SmallVector InstanceMethodTypes; + llvm::SmallVector OptionalInstanceMethodNames; + llvm::SmallVector 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 ClassMethodNames; llvm::SmallVector ClassMethodTypes; - for (ObjCProtocolDecl::classmeth_iterator + llvm::SmallVector OptionalClassMethodNames; + llvm::SmallVector 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 Properties; + std::vector 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 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 Elements; + std::vector 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 MethodSels; + llvm::SmallVector MethodTypes; + + std::vector 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 ProtocolElements; + for (llvm::StringMapIterator 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 ClassMethodSels; llvm::SmallVector 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 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 &InstanceMethodSels, + llvm::SmallVectorImpl &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 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 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 IvarNames; llvm::SmallVector IvarTypes; llvm::SmallVector IvarOffsets; - - int superInstanceSize = !SuperClassDecl ? 0 : + + std::vector 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 InstanceMethodSels; llvm::SmallVector 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 ClassMethodSels; llvm::SmallVector 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 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 &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( 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::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 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(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 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(CGM.CreateRuntimeFunction(FTy, - "objc_getProperty")); + std::vector 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(CGM.CreateRuntimeFunction(FTy, + "objc_getProperty")); } llvm::Function *CGObjCGNU::GetPropertySetFunction() { - std::vector 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(CGM.CreateRuntimeFunction(FTy, - "objc_setProperty")); + std::vector 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(CGM.CreateRuntimeFunction(FTy, + "objc_setProperty")); } -llvm::Function *CGObjCGNU::EnumerationMutationFunction() { - std::vector Params(1, IdTy); - return cast(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 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 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(S); @@ -1271,9 +1615,9 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, if (!isTry) { std::vector 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(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(S).getTryBody() + CGF.EmitStmt(isTry ? cast(S).getTryBody() : cast(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(); + assert(OPT && "Invalid @catch type."); + const ObjCInterfaceType *IT = + OPT->getPointeeType()->getAs(); 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(S).getFinallyStmt()) CGF.EmitStmt(FinallyStmt->getFinallyBody()); } else { @@ -1446,9 +1787,9 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, // @synchronized. std::vector 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(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 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()->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 c3354574c7753..4485ed5aee757 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 +#include 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 ConstantVector; +typedef std::vector 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 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 Args; - Args.push_back(ObjectPtrTy); - llvm::FunctionType *FTy = - llvm::FunctionType::get(llvm::Type::VoidTy, Args, false); + llvm::SmallVector 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 SkipIvars; llvm::SmallVector IvarsInfo; - + /// LazySymbols - Symbols to generate a lazy reference for. See /// DefinedSymbols and FinishModule(). - std::set LazySymbols; - + llvm::SetVector 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 DefinedSymbols; - + llvm::SetVector DefinedSymbols; + /// ClassNames - uniqued class names. llvm::DenseMap ClassNames; - + /// MethodVarNames - uniqued method variable names. llvm::DenseMap MethodVarNames; - + /// MethodVarTypes - uniqued method type signatures. We have to use /// a StringMap here because have no other unique reference. llvm::StringMap MethodVarTypes; - + /// MethodDefinitions - map of methods which have been defined in /// this translation unit. llvm::DenseMap MethodDefinitions; - + /// PropertyNames - uniqued method variable names. llvm::DenseMap PropertyNames; - + /// ClassReferences - uniqued class references. llvm::DenseMap ClassReferences; - + /// SelectorReferences - uniqued selector references. llvm::DenseMap 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 Protocols; - + /// DefinedProtocols - Protocols which have actually been /// defined. We should not need this, see FIXME in GenerateProtocol. llvm::DenseSet DefinedProtocols; - + /// DefinedClasses - List of defined classes. std::vector DefinedClasses; /// DefinedNonLazyClasses - List of defined "non-lazy" classes. std::vector DefinedNonLazyClasses; - + /// DefinedCategories - List of defined categories. std::vector DefinedCategories; - + /// DefinedNonLazyCategories - List of defined "non-lazy" categories. std::vector DefinedNonLazyCategories; - - /// UsedGlobals - List of globals to pack into the llvm.used metadata - /// to prevent them from being clobbered. - std::vector 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 &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 SuperClassReferences; - + /// MetaClassReferences - uniqued meta class references. llvm::DenseMap MetaClassReferences; /// EHTypeReferences - uniqued class ehtype references. llvm::DenseMap EHTypeReferences; - + /// NonLegacyDispatchMethods - List of methods for which we do *not* generate /// legacy messaging dispatch. llvm::DenseSet 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()) 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::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 InstanceMethods, ClassMethods; std::vector 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 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 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 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 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 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 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 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; // - 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; // + 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 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 () - 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 () + 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(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 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 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 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 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(ID->getClassInterface()); - + llvm::SmallVector 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 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: - - - 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); } + This framework differs slightly from the one gcc uses, in that gcc + uses _rethrow to determine if objc_exception_try_exit should be called + and if the object should be rethrown. This breaks in the face of + throwing nil and introduces unnecessary branches. + + We specialize this framework for a few particular circumstances: + + - If there are no catch blocks, then we avoid emitting the second + exception handling context. + + - If there is a catch-all catch block (i.e. @catch(...) or @catch(id + e)) we avoid emitting the code to rethrow an uncaught exception. + + - FIXME: If there is no @finally block we can do a few more + simplifications. + + Rethrows and Jumps-Through-Finally + -- + + Support for implicit rethrows and jumping through the finally block is + handled by storing the current exception-handling context in + ObjCEHStack. + + In order to implement proper @finally semantics, we support one basic + mechanism for jumping through the finally block to an arbitrary + destination. Constructs which generate exits from a @try or @catch + block use this mechanism to implement the proper semantics by chaining + jumps, as necessary. + + This mechanism works like the one used for indirect goto: we + arbitrarily assign an ID to each destination and store the ID for the + destination in a variable prior to entering the finally block. At the + end of the finally block we simply create a switch to the proper + destination. + + Code gen for @synchronized(expr) stmt; + Effectively generating code for: + objc_sync_enter(expr); + @try stmt @finally { objc_sync_exit(expr); } */ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, @@ -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(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(S).getTryBody() - : cast(S).getSynchBody()); + CGF.EmitStmt(isTry ? cast(S).getTryBody() + : cast(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(S).getCatchStmts()) - { + } else if (const ObjCAtCatchStmt* CatchStmt = + cast(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(); + + // catch(id e) always matches. // FIXME: For the time being we also match id; 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(); 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(S).getFinallyStmt()) + if (const ObjCAtFinallyStmt* FinallyStmt = + cast(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(AddrWeakObj->getType())->getElementType(); - AddrWeakObj = CGF.Builder.CreateBitCast(AddrWeakObj, ObjCTypes.PtrObjectPtrTy); + cast(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(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(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(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(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 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()->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 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. 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; igetIdentifier()); 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()) 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 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(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 &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(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(), BytePos + FieldOffset, ForStrongLayout, HasUnion); continue; } - + if (const ArrayType *Array = CGM.getContext().getAsArrayType(FQT)) { - const ConstantArrayType *CArray = + const ConstantArrayType *CArray = dyn_cast_or_null(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(); 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 RecFields; const ObjCInterfaceDecl *OI = OMD->getClassInterface(); CGM.getContext().CollectObjCIvars(OI, RecFields); - + // Add this implementations synthesized ivars. llvm::SmallVector Ivars; CGM.getContext().CollectSynthesizedIvars(OI, Ivars); for (unsigned k = 0, e = Ivars.size(); k != e; ++k) RecFields.push_back(cast(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 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(D->getDeclContext())) { NameOut += '('; NameOut += CID->getNameAsString(); @@ -3418,64 +3470,55 @@ void CGObjCCommonMac::GetNameForMethod(const ObjCMethodDecl *D, NameOut += ']'; } -void CGObjCCommonMac::MergeMetadataGlobals( - std::vector &UsedArray) { - llvm::Type *i8PTy = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); - for (std::vector::iterator i = UsedGlobals.begin(), - e = UsedGlobals.end(); i != e; ++i) { - UsedArray.push_back(llvm::ConstantExpr::getBitCast(cast(*i), - i8PTy)); - } -} - void CGObjCMac::FinishModule() { EmitModuleInfo(); // Emit the dummy bodies for any protocols which were referenced but // never defined. - for (llvm::DenseMap::iterator - i = Protocols.begin(), e = Protocols.end(); i != e; ++i) { - if (i->second->hasInitializer()) + for (llvm::DenseMap::iterator + I = Protocols.begin(), e = Protocols.end(); I != e; ++I) { + if (I->second->hasInitializer()) continue; std::vector 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::iterator i = LazySymbols.begin(), - e = LazySymbols.end(); i != e; ++i) { - s << "\t.lazy_reference .objc_class_name_" << (*i)->getName() << "\n"; - } - for (std::set::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::iterator I = LazySymbols.begin(), + e = LazySymbols.end(); I != e; ++I) + OS << "\t.lazy_reference .objc_class_name_" << (*I)->getName() << "\n"; + for (llvm::SetVector::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(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(ProtocolTyHolder.get())->refineAbstractTypeTo(T); ProtocolListTy = cast(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(ClassTyHolder.get())->refineAbstractTypeTo(T); - + ClassTy = cast(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(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 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(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(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 - &Container, +void CGObjCNonFragileABIMac::AddModuleClassList(const + std::vector + &Container, const char *SymbolName, const char *SectionName) { unsigned NumClasses = Container.size(); - + if (!NumClasses) return; - + std::vector Symbols(NumClasses); for (unsigned i=0; igetType(), 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 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 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 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 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 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 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 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 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 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 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 InstanceMethods, ClassMethods; std::vector 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 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 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 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 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()->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()); + const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, + llvm::SmallVector()); 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 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(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(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 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(AddrWeakObj->getType())->getElementType(); - AddrWeakObj = CGF.Builder.CreateBitCast(AddrWeakObj, ObjCTypes.PtrObjectPtrTy); + cast(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(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(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(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(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(S).getTryBody() - : cast(S).getSynchBody()); + CGF.EmitStmt(isTry ? cast(S).getTryBody() + : cast(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(); + 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 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(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 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 0f9cf0606d36e..6b4556239723d 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 &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 0000000000000..7baf69d87689f --- /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(); + + 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()) + 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()) { + const RecordDecl *RD = cast(RT->getDecl()); + if (const PragmaPackAttr *PPA = RD->getAttr()) { + 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(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 0000000000000..d1a13aa29711e --- /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 + +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 FieldTypes; + + /// LLVMFieldInfo - Holds a field and its corresponding LLVM field number. + typedef std::pair LLVMFieldInfo; + llvm::SmallVector 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 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 0000000000000..7bc774fce75bc --- /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 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 b67996c676307..f58b579267873 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(*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(S)) { - EmitAnyExpr(E, 0, false, true); - } else { + if (!isa(S)) ErrorUnsupported(S, "statement"); + + EmitAnyExpr(cast(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(*S)); break; case Stmt::IfStmtClass: EmitIfStmt(cast(*S)); break; case Stmt::WhileStmtClass: EmitWhileStmt(cast(*S)); break; case Stmt::DoStmtClass: EmitDoStmt(cast(*S)); break; case Stmt::ForStmtClass: EmitForStmt(cast(*S)); break; - + case Stmt::ReturnStmtClass: EmitReturnStmt(cast(*S)); break; - case Stmt::DeclStmtClass: EmitDeclStmt(cast(*S)); break; case Stmt::SwitchStmtClass: EmitSwitchStmt(cast(*S)); break; case Stmt::AsmStmtClass: EmitAsmStmt(cast(*S)); break; case Stmt::ObjCAtTryStmtClass: EmitObjCAtTryStmt(cast(*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(*S)); break; - case Stmt::ObjCForCollectionStmtClass: + case Stmt::ObjCForCollectionStmtClass: EmitObjCForCollectionStmt(cast(*S)); break; + + case Stmt::CXXTryStmtClass: + EmitCXXTryStmt(cast(*S)); + break; } } @@ -103,6 +126,7 @@ bool CodeGenFunction::EmitSimpleStmt(const Stmt *S) { default: return false; case Stmt::NullStmtClass: break; case Stmt::CompoundStmtClass: EmitCompoundStmt(cast(*S)); break; + case Stmt::DeclStmtClass: EmitDeclStmt(cast(*S)); break; case Stmt::LabelStmtClass: EmitLabelStmt(cast(*S)); break; case Stmt::GotoStmtClass: EmitGotoStmt(cast(*S)); break; case Stmt::BreakStmtClass: EmitBreakStmt(cast(*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(LastStmt), AggLoc); } DidCallStackSave = OldDidCallStackSave; - + EmitCleanupBlocks(CleanupStackDepth); - + return RV; } void CodeGenFunction::SimplifyForwardingBlocks(llvm::BasicBlock *BB) { llvm::BranchInst *BI = dyn_cast(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(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(BoolCondVal)) + if (llvm::ConstantInt *C = dyn_cast(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(BoolCondVal)) + if (llvm::ConstantInt *C = dyn_cast(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(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 *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 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 OutputConstraintInfos; llvm::SmallVector 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 ResultRegDests; std::vector ResultRegQualTys; std::vector ResultRegTypes; @@ -826,16 +879,16 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { std::vector InOutArgs; std::vector 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(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 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(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 820e1bd6c3ec5..2a06f51f6685d 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 getComplexVal() const { return std::pair(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 0000000000000..41f7eefbe82be --- /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 &methods; + std::vector 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 IndirectPrimary; + llvm::SmallSet 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 Index; + llvm::DenseMap VCall; + llvm::DenseMap VCallOffset; + llvm::DenseMap VBIndex; + typedef std::pair CallOffset; + typedef llvm::DenseMap Thunks_t; + Thunks_t Thunks; + typedef llvm::DenseMap, + CanQualType> > CovariantThunks_t; + CovariantThunks_t CovariantThunks; + std::vector 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 &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 &getIndex() { return Index; } + llvm::DenseMap &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 &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(i->getType()->getAs()->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()->getPointeeType(); + qB = qB->getAs()->getPointeeType(); + CXXRecordDecl *D = cast(qD->getAs()->getDecl()); + CXXRecordDecl *B = cast(qB->getAs()->getDecl()); + if (D != Class) + return VBlookup(D, B); + llvm::DenseMap::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()->getResultType(); + CanQualType oret = CGM.getContext().getCanonicalType(nc_oret); + QualType nc_ret = MD->getType()->getAs()->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 > *Path, bool MorallyVirtual) { + for (std::vector >::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(MD)) + m = wrap(CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete)); + else { + const FunctionProtoType *FPT = + MD->getType()->getAs(); + 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(MD)) + m = wrap(CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete)); + else { + const FunctionProtoType *FPT = MD->getType()->getAs(); + 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(i->getType()->getAs()->getDecl()); + if (Base != PrimaryBase || PrimaryBaseWasVirtual) { + uint64_t o = Offset + Layout.getBaseClassOffset(Base); + StartNewTable(); + std::vector > S; + S.push_back(std::make_pair(RD, Offset)); + GenerateVtableForBase(Base, MorallyVirtual, o, false, &S); + } + } + } + + Index_t end(const CXXRecordDecl *RD, std::vector &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::reverse_iterator i = offsets.rbegin(), + e = offsets.rend(); i != e; ++i) + methods.push_back(*i); + } + + // The vcalls come first... + for (std::vector::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::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 > *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 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 > *Path = 0) { + bool alloc = false; + if (Path == 0) { + alloc = true; + Path = new std::vector >; + } + // 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(i->getType()->getAs()->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 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 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::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 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 0000000000000..69fb1f1005996 --- /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 MethodVtableIndicesTy; + MethodVtableIndicesTy MethodVtableIndices; + + typedef std::pair ClassPairTy; + + /// VirtualBaseClassIndicies - Contains the index into the vtable where the + /// offsets for virtual bases of a class are stored. + typedef llvm::DenseMap 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 c206a3bdd2088..2f46313c9c207 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 c3f9364e7ae44..5206f447f8d0d 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(*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(D)) { - DI->EmitFunctionStart(CGM.getMangledName(FD), RetTy, CurFn, Builder); + if (isa(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(GD.getDecl()); + // Check if we should generate debug info for this function. - if (CGM.getDebugInfo() && !FD->hasAttr()) + if (CGM.getDebugInfo() && !FD->hasAttr()) DebugInfo = CGM.getDebugInfo(); - + FunctionArgList Args; - + if (const CXXMethodDecl *MD = dyn_cast(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(); 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(FD); + llvm::BasicBlock *DtorEpilogue = 0; + if (DD) { + DtorEpilogue = createBasicBlock("dtor.epilogue"); + + PushCleanupBlock(DtorEpilogue); + } + + if (const CXXConstructorDecl *CD = dyn_cast(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(FD->getDeclContext()); + (void) ClassDecl; + if (const CXXConstructorDecl *CD = dyn_cast(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(FD)) { + assert(!ClassDecl->hasUserDeclaredDestructor() && + "Cannot synthesize a non-implicit destructor"); + SynthesizeDefaultDestructor(CD, GD.getDtorType(), Fn, Args); + } else if (const CXXMethodDecl *MD = dyn_cast(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(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(S) && !IgnoreCaseStmts) return true; - + // If this is a switch statement, we want to ignore cases below it. if (isa(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(Cond)) return EmitBranchOnBoolExpr(PE->getSubExpr(), TrueBlock, FalseBlock); - + if (const BinaryOperator *CondBOp = dyn_cast(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(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(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 AddrTakenLabelsByID; + AddrTakenLabelsByID.resize(LabelIDs.size()); + + for (std::map::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::iterator i = IndirectSwitches.begin(), - e = IndirectSwitches.end(); i != e; ++i) { - llvm::SwitchInst *I = *i; - - I->setSuccessor(0, Default); - for (std::map::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(Ty)) { + } + + if (const ArrayType *AT = dyn_cast(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(); + 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 Blocks; std::swap(Blocks, CE.Blocks); - + std::vector 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 72c4aa4a658ab..722d002c19f57 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 +#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 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 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 VLASizeMap; + llvm::DenseMap 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 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 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 > 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 &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 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 d88a37a45b233..36ad7f514ec81 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(D)) if (VD->getStorageClass() == VarDecl::PrivateExtern) @@ -105,7 +110,7 @@ CodeGenModule::getDeclVisibilityMode(const Decl *D) const { if (const VisibilityAttr *attr = D->getAttr()) { 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(GD.getDecl()); + if (const CXXConstructorDecl *D = dyn_cast(ND)) return getMangledCXXCtorName(D, GD.getCtorType()); if (const CXXDestructorDecl *D = dyn_cast(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(), 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 Ctors; for (CtorList::const_iterator I = Fns.begin(), E = Fns.end(); I != E; ++I) { std::vector 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(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()) { + // 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()) - F->setCallingConv(llvm::CallingConv::X86_FastCall); - - if (D->hasAttr()) - F->setCallingConv(llvm::CallingConv::X86_StdCall); + AttributeList.size())); + F->setCallingConv(static_cast(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()) F->addFnAttr(llvm::Attribute::AlwaysInline); - - if (D->hasAttr()) + + if (D->hasAttr()) F->addFnAttr(llvm::Attribute::NoInline); + + if (const AlignedAttr *AA = D->getAttr()) + F->setAlignment(AA->getAlignment()/8); + // C++ ABI requires 2-byte alignment for member functions. + if (F->getAlignment() < 2 && isa(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()) { F->setLinkage(llvm::Function::DLLImportLinkage); - } else if (FD->hasAttr() || + } else if (FD->hasAttr() || FD->hasAttr()) { // "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()) @@ -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 UsedArray; UsedArray.resize(LLVMUsed.size()); for (unsigned i = 0, e = LLVMUsed.size(); i != e; ++i) { - UsedArray[i] = - llvm::ConstantExpr::getBitCast(cast(&*LLVMUsed[i]), i8PTy); + UsedArray[i] = + llvm::ConstantExpr::getBitCast(cast(&*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(Global)) { // Constructors and destructors should never be deferred. - if (FD->hasAttr() || + if (FD->hasAttr() || FD->hasAttr()) 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(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()) { + if (const CXXRecordDecl *RD = dyn_cast(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(GD.getDecl()); + // If this is an alias definition (which otherwise looks like a declaration) // emit it now. if (Global->hasAttr()) @@ -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(GD.getDecl()); + if (const CXXConstructorDecl *CD = dyn_cast(D)) EmitCXXConstructor(CD, GD.getCtorType()); else if (const CXXDestructorDecl *DD = dyn_cast(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::iterator DDI = + llvm::DenseMap::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(FD)) { + const CXXRecordDecl *ClassDecl = + cast(CD->getDeclContext()); + if (CD->isCopyConstructor(getContext())) + DeferredCopyConstructorToEmit(D); + else if (!ClassDecl->hasUserDeclaredConstructor()) + DeferredDeclsToEmit.push_back(D); + } + else if (isa(FD)) + DeferredDestructorToEmit(D); + else if (const CXXMethodDecl *MD = dyn_cast(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(Ty)) { - Ty = llvm::FunctionType::get(llvm::Type::VoidTy, + Ty = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), std::vector(), false); IsIncompleteFunction = true; } - llvm::Function *F = llvm::Function::Create(cast(Ty), + llvm::Function *F = llvm::Function::Create(cast(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(CopyCtorDecl.getDecl()); + const CXXRecordDecl *ClassDecl = cast(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(Base->getType()->getAs()->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()) { + if ((*Field)->isAnonymousStructOrUnion()) + continue; + CXXRecordDecl *FieldClassDecl + = cast(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(CopyAssignDecl.getDecl()); + const CXXRecordDecl *ClassDecl = cast(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(Base->getType()->getAs()->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()) { + if ((*Field)->isAnonymousStructOrUnion()) + continue; + CXXRecordDecl *FieldClassDecl + = cast(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(DtorDecl.getDecl()); + const CXXRecordDecl *ClassDecl = cast(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(Base->getType()->getAs()->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()) { + if ((*Field)->isAnonymousStructOrUnion()) + continue; + CXXRecordDecl *FieldClassDecl + = cast(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(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::iterator DDI = + llvm::DenseMap::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() || + if (D->hasAttr() || D->hasAttr()) 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(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(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(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()) GV->setLinkage(llvm::Function::DLLImportLinkage); else if (D->hasAttr()) GV->setLinkage(llvm::Function::DLLExportLinkage); - else if (D->hasAttr()) - GV->setLinkage(llvm::GlobalVariable::WeakAnyLinkage); - else if (!CompileOpts.NoCommon && - (!D->hasExternalStorage() && !D->getInit())) + else if (D->hasAttr()) { + if (GV->isConstant()) + GV->setLinkage(llvm::GlobalVariable::WeakODRLinkage); + else + GV->setLinkage(llvm::GlobalVariable::WeakAnyLinkage); + } else if (!CompileOpts.NoCommon && + !D->hasExternalStorage() && !D->getInit() && + !D->getAttr()) { 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(Old); if (OldFn == 0) return; - + const llvm::Type *NewRetTy = NewFn->getReturnType(); llvm::SmallVector ArgList; @@ -914,7 +1076,7 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old, unsigned OpNo = UI.getOperandNo(); llvm::CallInst *CI = dyn_cast(*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(GD.getDecl()); - + if (const CXXMethodDecl *MD = dyn_cast(D)) { - bool isVariadic = D->getType()->getAsFunctionProtoType()->isVariadic(); - + bool isVariadic = D->getType()->getAs()->isVariadic(); + Ty = getTypes().GetFunctionType(getTypes().getFunctionInfo(MD), isVariadic); } else { Ty = cast(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 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(Entry)) { assert(CE->getOpcode() == llvm::Instruction::BitCast); Entry = CE->getOperand(0); } - - + + if (cast(Entry)->getType()->getElementType() != Ty) { llvm::GlobalValue *OldFn = cast(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(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(Entry); CodeGenFunction(*this).GenerateCode(D, Fn); SetFunctionDefinitionAttributes(D, Fn); SetLLVMFunctionAttributesForDefinition(D, Fn); - + if (const ConstructorAttr *CA = D->getAttr()) AddGlobalCtor(Fn, CA->getPriority()); if (const DestructorAttr *DA = D->getAttr()) @@ -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() || + } else if (D->hasAttr() || D->hasAttr()) { 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(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& 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 & +GetConstantCFStringEntry(llvm::StringMap &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 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 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 &Entry = - CFConstantStringMap.GetOrCreateValue(&str[0], &str[str.length()]); - + llvm::StringMapEntry &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(getTypes().ConvertType(CFTy)); - std::vector Fields; - RecordDecl::field_iterator Field = CFRD->field_begin(); + std::vector 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 &Entry = - ConstantStringMap.GetOrCreateValue(&str[0], &str[str.length()]); + + llvm::StringMapEntry &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(D)->getDescribedFunctionTemplate()) return; + + EmitGlobal(cast(D)); + break; - // Fall through - case Decl::Var: - EmitGlobal(GlobalDecl(cast(D))); + EmitGlobal(cast(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(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(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(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 ba9f1b28a07d3..2e58337ee52db 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 +#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 Value; + llvm::PointerIntPair Value; + + void Init(const Decl *D) { + assert(!isa(D) && "Use other ctor with ctor decls!"); + assert(!isa(D) && "Use other ctor with dtor decls!"); + + Value.setPointer(D); + } public: GlobalDecl() {} - - explicit GlobalDecl(const ValueDecl *VD) : Value(VD, 0) { - assert(!isa(VD) && "Use other ctor with ctor decls!"); - assert(!isa(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(getDecl()) && "Decl is not a ctor!"); return static_cast(Value.getInt()); } - + CXXDtorType getDtorType() const { assert(isa(getDecl()) && "Decl is not a dtor!"); return static_cast(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 > CtorList; + typedef std::vector > 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 CFConstantStringMap; llvm::StringMap ConstantStringMap; + /// CXXGlobalInits - Variables with global initializers that need to run + /// before main. + std::vector 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 1a30ea37fbbc3..dedf824ef9fd4 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 &getPaddingFields() { - return PaddingFields; - } - - private: - CodeGenTypes &CGT; - const RecordDecl& RD; - llvm::Type *STy; - llvm::SmallSet 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::iterator - I = CGRecordLayouts.begin(), E = CGRecordLayouts.end(); + for (llvm::DenseMap::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::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(T); - if (const TagType* TT = FT->getResultType()->getAsTagType()) + if (const TagType* TT = FT->getResultType()->getAs()) if (!TT->getDecl()->isDefinition()) return TT; if (const FunctionProtoType *FPT = dyn_cast(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()) 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(TD)).getTypePtr(); - llvm::DenseMap::iterator TDTI = + const Type *Key = Context.getTagDeclType(TD).getTypePtr(); + llvm::DenseMap::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(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(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(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(T)->getWidth()); + return llvm::IntegerType::get(getLLVMContext(), + cast(T)->getWidth()); case Type::Complex: { - const llvm::Type *EltTy = + const llvm::Type *EltTy = ConvertTypeRecursive(cast(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(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(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(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(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(&Ty); return GetFunctionType(getFunctionInfo(FNPT), true); } - - case Type::ExtQual: - return - ConvertTypeRecursive(QualType(cast(Ty).getBaseType(), 0)); - - case Type::ObjCQualifiedInterface: { - // Lower foo just like foo. - ObjCInterfaceDecl *ID = cast(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(&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(Ty).getPointeeType()); + return llvm::PointerType::getUnqual(T); + } case Type::Record: case Type::Enum: { const TagDecl *TD = cast(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(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(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(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(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(i->getType()->getAs()->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(TD)).getTypePtr(); - llvm::DenseMap::iterator TDTI = + const Type *Key = + Context.getTagDeclType(TD).getTypePtr(); + llvm::DenseMap::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(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(TD); - // There isn't any extra information for empty structures/unions. - if (RD->field_empty()) { - ResultType = llvm::StructType::get(std::vector()); - } 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(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(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::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(TD)).getTypePtr(); + const Type *Key = + Context.getTagDeclType(TD).getTypePtr(); llvm::DenseMap::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 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 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 b72d8e92013ae..a92a019b988ec 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 @@ -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 &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 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, 8> PointersToResolve; @@ -98,9 +109,9 @@ class CodeGenTypes { /// types are never refined. llvm::DenseMap 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 CGRecordLayouts; @@ -112,13 +123,15 @@ class CodeGenTypes { llvm::FoldingSet 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 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 - &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 &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 e716fe78bc609..108490b71d48e 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 8018b4f45a84d..fd772748dbda3 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 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(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(DC)) + if (const LinkageSpecDecl *Linkage = dyn_cast(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()) { // 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(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()) { // 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; } - + // ::= _Z // ::= // ::= @@ -125,43 +165,54 @@ bool CXXNameMangler::mangle(const NamedDecl *D) { // FIXME: Actually use a visitor to decode these? if (const FunctionDecl *FD = dyn_cast(D)) return mangleFunctionDecl(FD); - + if (const VarDecl *VD = dyn_cast(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) -{ - // ::= GV # Guard variable for one-time - // # initialization +void CXXNameMangler::mangleCXXVtable(const CXXRecordDecl *RD) { + // ::= TV # virtual table + Out << "_ZTV"; + mangleName(RD); +} + +void CXXNameMangler::mangleCXXRtti(const CXXRecordDecl *RD) { + // ::= TI # typeinfo structure + Out << "_ZTI"; + mangleName(RD); +} + +void CXXNameMangler::mangleGuardVariable(const VarDecl *D) { + // ::= GV # 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) { // ::= 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(FD) || isa(FD) || - isa(FD))) - MangleReturnType = true; - mangleBareFunctionType(FD->getType()->getAsFunctionType(), MangleReturnType); + if (FunctionTemplateDecl *PrimaryTemplate = FD->getPrimaryTemplate()) { + if (!(isa(FD) || isa(FD) || + isa(FD))) + MangleReturnType = true; + + // Mangle the type of the primary template. + FD = PrimaryTemplate->getTemplatedDecl(); + } + + mangleBareFunctionType(FD->getType()->getAs(), MangleReturnType); } static bool isStdNamespace(const DeclContext *DC) { @@ -200,37 +256,196 @@ static bool isStdNamespace(const DeclContext *DC) { return false; const NamespaceDecl *NS = cast(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(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(ND)) { + TemplateArgs = &Spec->getTemplateArgs(); + return Spec->getSpecializedTemplate(); + } + + return 0; } void CXXNameMangler::mangleName(const NamedDecl *ND) { // ::= // ::= // ::= - // ::= # See Scope Encoding below + // ::= // + const DeclContext *DC = ND->getDeclContext(); + while (isa(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(DC)) { + mangleLocalName(ND); + return; + } + + mangleNestedName(ND); +} +void CXXNameMangler::mangleName(const TemplateDecl *TD, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs) { + const DeclContext *DC = TD->getDeclContext(); + while (isa(DC)) { + assert(cast(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) { // ::= // ::= St # ::std:: - if (ND->getDeclContext()->isTranslationUnit()) - mangleUnqualifiedName(ND); - else if (isStdNamespace(ND->getDeclContext())) { + if (isStdNamespace(ND->getDeclContext())) Out << "St"; - mangleUnqualifiedName(ND); - } else if (isa(ND->getDeclContext())) - mangleLocalName(ND); - else - mangleNestedName(ND); + + mangleUnqualifiedName(ND); +} + +void CXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *ND) { + // ::= + // ::= + if (mangleSubstitution(ND)) + return; + + mangleUnscopedName(ND->getTemplatedDecl()); + addSubstitution(ND); +} + +void CXXNameMangler::mangleCalloffset(int64_t nv, int64_t v) { + // ::= h _ + // ::= v _ + // ::= # non-virtual base override + // ::= _ + // # 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) { + // ::= T + // # 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) { + // ::= Tc + // # 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) { // ::= - // ::= - // ::= + // ::= + // ::= DeclarationName Name = ND->getDeclName(); switch (Name.getNameKind()) { - case DeclarationName::Identifier: - mangleSourceName(Name.getAsIdentifierInfo()); + case DeclarationName::Identifier: { + if (const NamespaceDecl *NS = dyn_cast(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(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] $_ + // 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(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(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: - // ::= cv # (cast) + // ::= cv # (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(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) { // ::= N [] E // ::= N [] E - // FIXME: no template support + Out << 'N'; if (const CXXMethodDecl *Method = dyn_cast(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) { + // ::= N [] E + + Out << 'N'; + + mangleTemplatePrefix(TD); + mangleTemplateArgs(TemplateArgs, NumTemplateArgs); + Out << 'E'; } void CXXNameMangler::mangleLocalName(const NamedDecl *ND) { // := Z E [] // := Z E s [] - // := _ + // := _ Out << 'Z'; mangleFunctionEncoding(cast(ND->getDeclContext())); Out << 'E'; @@ -319,21 +549,46 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC) { // ::= # empty // ::= // 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(DC)) - mangleSourceName(Namespace->getIdentifier()); - else if (const RecordDecl *Record = dyn_cast(DC)) { - if (const ClassTemplateSpecializationDecl *D = - dyn_cast(Record)) { - mangleType(QualType(D->getTypeForDecl(), 0)); - } else - mangleSourceName(Record->getIdentifier()); + while (isa(DC)) + DC = DC->getParent(); + + if (DC->isTranslationUnit()) + return; + + if (mangleSubstitution(cast(DC))) + return; + + // Check if we have a template. + const TemplateArgumentList *TemplateArgs = 0; + if (const TemplateDecl *TD = isTemplate(cast(DC), TemplateArgs)) { + mangleTemplatePrefix(TD); + mangleTemplateArgumentList(*TemplateArgs); + } else { + manglePrefix(DC->getParent()); + mangleUnqualifiedName(cast(DC)); } + + addSubstitution(cast(DC)); +} + +void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND) { + // ::=