From 180abc3db9ae3b4fc63cd65b15697e6ffcc8a657 Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Sun, 17 Jul 2011 15:40:56 +0000 Subject: Vendor import of clang trunk r135360: http://llvm.org/svn/llvm-project/cfe/trunk@135360 --- CMakeLists.txt | 13 +- INPUTS/cfg-big-switch.c | 27 + INPUTS/cfg-long-chain1.c | 20 + INPUTS/cfg-long-chain2.c | 20 + INPUTS/cfg-long-chain3.c | 21 + INPUTS/cfg-nested-switches.c | 36 + LICENSE.TXT | 2 +- bindings/python/clang/cindex.py | 22 +- bindings/python/tests/cindex/test_cursor_kind.py | 8 +- .../python/tests/cindex/test_translation_unit.py | 15 +- clang.xcodeproj/project.pbxproj | 43 +- docs/AutomaticReferenceCounting.html | 1857 +++++++++++++ docs/Block-ABI-Apple.txt | 4 +- docs/BlockLanguageSpec.txt | 2 +- docs/DriverInternals.html | 2 +- docs/InternalsManual.html | 9 +- docs/LanguageExtensions.html | 119 +- docs/UsersManual.html | 18 +- docs/index.html | 4 - include/clang-c/Index.h | 255 +- include/clang/ARCMigrate/ARCMT.h | 94 + include/clang/ARCMigrate/ARCMTActions.h | 47 + include/clang/ARCMigrate/FileRemapper.h | 76 + include/clang/AST/ASTContext.h | 40 +- include/clang/AST/ASTDiagnostic.h | 22 +- include/clang/AST/CanonicalType.h | 2 +- include/clang/AST/Decl.h | 34 +- include/clang/AST/DeclBase.h | 19 +- include/clang/AST/DeclCXX.h | 1 - include/clang/AST/DeclObjC.h | 43 +- include/clang/AST/DeclTemplate.h | 8 + include/clang/AST/DeclarationName.h | 3 + include/clang/AST/Expr.h | 211 +- include/clang/AST/ExprCXX.h | 170 +- include/clang/AST/ExprObjC.h | 149 +- include/clang/AST/ExternalASTSource.h | 24 +- include/clang/AST/GlobalDecl.h | 124 + include/clang/AST/NestedNameSpecifier.h | 12 + include/clang/AST/OperationKinds.h | 30 +- include/clang/AST/ParentMap.h | 1 + include/clang/AST/PrettyPrinter.h | 6 +- include/clang/AST/RecursiveASTVisitor.h | 7 + include/clang/AST/Stmt.h | 29 +- include/clang/AST/StmtObjC.h | 33 + include/clang/AST/TemplateBase.h | 7 +- include/clang/AST/TemplateName.h | 110 +- include/clang/AST/Type.h | 420 ++- .../clang/Analysis/Analyses/UninitializedValues.h | 10 +- include/clang/Analysis/AnalysisContext.h | 5 + .../Analysis/DomainSpecific/CocoaConventions.h | 25 +- include/clang/Basic/Attr.td | 9 + include/clang/Basic/Builtins.def | 6 + include/clang/Basic/Builtins.h | 1 - include/clang/Basic/BuiltinsX86.def | 82 +- include/clang/Basic/DelayedCleanupPool.h | 109 + include/clang/Basic/Diagnostic.h | 53 +- include/clang/Basic/DiagnosticCategories.h | 26 + include/clang/Basic/DiagnosticCommonKinds.td | 1 + include/clang/Basic/DiagnosticDriverKinds.td | 6 + include/clang/Basic/DiagnosticFrontendKinds.td | 3 + include/clang/Basic/DiagnosticGroups.td | 22 +- include/clang/Basic/DiagnosticIDs.h | 4 + include/clang/Basic/DiagnosticLexKinds.td | 2 +- include/clang/Basic/DiagnosticParseKinds.td | 5 + include/clang/Basic/DiagnosticSemaKinds.td | 338 ++- include/clang/Basic/FileManager.h | 5 +- include/clang/Basic/IdentifierTable.h | 20 +- include/clang/Basic/LangOptions.h | 13 +- include/clang/Basic/SourceManager.h | 144 +- include/clang/Basic/SourceManagerInternals.h | 2 +- include/clang/Basic/Specifiers.h | 2 +- include/clang/Basic/StmtNodes.td | 7 + include/clang/Basic/TargetInfo.h | 24 + include/clang/Basic/TokenKinds.def | 7 + include/clang/Basic/arm_neon.td | 4 +- include/clang/CodeGen/BackendUtil.h | 4 +- include/clang/Driver/CC1Options.td | 40 +- include/clang/Driver/Compilation.h | 1 - include/clang/Driver/Driver.h | 2 + include/clang/Driver/ObjCRuntime.h | 46 + include/clang/Driver/Option.h | 7 +- include/clang/Driver/Options.td | 20 +- include/clang/Driver/ToolChain.h | 10 +- include/clang/Frontend/ASTUnit.h | 14 +- include/clang/Frontend/CodeGenOptions.h | 13 + include/clang/Frontend/DependencyOutputOptions.h | 2 + include/clang/Frontend/DiagnosticOptions.h | 3 +- include/clang/Frontend/FrontendAction.h | 39 + include/clang/Frontend/FrontendActions.h | 6 - include/clang/Frontend/FrontendOptions.h | 11 +- include/clang/Frontend/HeaderSearchOptions.h | 27 +- include/clang/Frontend/PreprocessorOptions.h | 27 +- include/clang/Frontend/TextDiagnosticPrinter.h | 19 +- include/clang/Frontend/Utils.h | 1 + include/clang/Lex/Lexer.h | 22 +- include/clang/Lex/LiteralSupport.h | 4 +- include/clang/Lex/MacroInfo.h | 16 + include/clang/Lex/PPCallbacks.h | 37 + include/clang/Lex/PreprocessingRecord.h | 34 +- include/clang/Lex/Preprocessor.h | 55 +- include/clang/Lex/Token.h | 4 +- include/clang/Lex/TokenLexer.h | 33 +- include/clang/Parse/Parser.h | 72 +- include/clang/Rewrite/FixItRewriter.h | 1 - include/clang/Rewrite/Rewriter.h | 5 +- include/clang/Sema/AnalysisBasedWarnings.h | 38 +- include/clang/Sema/AttributeList.h | 48 +- include/clang/Sema/CodeCompleteConsumer.h | 30 +- include/clang/Sema/DeclSpec.h | 59 +- include/clang/Sema/DelayedDiagnostic.h | 41 +- include/clang/Sema/ExternalSemaSource.h | 5 + include/clang/Sema/Initialization.h | 107 +- include/clang/Sema/LocInfoType.h | 63 + include/clang/Sema/Overload.h | 18 +- include/clang/Sema/Scope.h | 8 +- include/clang/Sema/Sema.h | 332 ++- include/clang/Sema/TypoCorrection.h | 105 + include/clang/Serialization/ASTBitCodes.h | 40 +- include/clang/Serialization/ASTReader.h | 10 +- include/clang/Serialization/ASTWriter.h | 2 +- .../clang/Serialization/ChainedIncludesSource.h | 2 +- .../Core/PathSensitive/GRStateTrait.h | 4 + lib/ARCMigrate/ARCMT.cpp | 541 ++++ lib/ARCMigrate/ARCMTActions.cpp | 53 + lib/ARCMigrate/CMakeLists.txt | 24 + lib/ARCMigrate/FileRemapper.cpp | 291 ++ lib/ARCMigrate/Internals.h | 148 ++ lib/ARCMigrate/Makefile | 18 + lib/ARCMigrate/TransARCAssign.cpp | 75 + lib/ARCMigrate/TransAutoreleasePool.cpp | 436 +++ lib/ARCMigrate/TransBlockObjCVariable.cpp | 143 + lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp | 211 ++ lib/ARCMigrate/TransProperties.cpp | 364 +++ lib/ARCMigrate/TransRetainReleaseDealloc.cpp | 219 ++ lib/ARCMigrate/TransUnbridgedCasts.cpp | 203 ++ lib/ARCMigrate/TransUnusedInitDelegate.cpp | 74 + lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp | 198 ++ lib/ARCMigrate/TransformActions.cpp | 699 +++++ lib/ARCMigrate/Transforms.cpp | 296 +++ lib/ARCMigrate/Transforms.h | 92 + lib/AST/ASTContext.cpp | 293 +- lib/AST/ASTDiagnostic.cpp | 74 +- lib/AST/ASTImporter.cpp | 20 +- lib/AST/Decl.cpp | 110 +- lib/AST/DeclBase.cpp | 35 +- lib/AST/DeclCXX.cpp | 54 +- lib/AST/DeclObjC.cpp | 58 +- lib/AST/DeclPrinter.cpp | 5 + lib/AST/DeclarationName.cpp | 22 + lib/AST/Expr.cpp | 256 +- lib/AST/ExprCXX.cpp | 60 +- lib/AST/ExprClassification.cpp | 15 +- lib/AST/ExprConstant.cpp | 68 +- lib/AST/ExternalASTSource.cpp | 4 +- lib/AST/ItaniumMangle.cpp | 447 +++- lib/AST/NestedNameSpecifier.cpp | 22 + lib/AST/ParentMap.cpp | 9 + lib/AST/RecordLayoutBuilder.cpp | 9 +- lib/AST/Stmt.cpp | 33 +- lib/AST/StmtPrinter.cpp | 26 + lib/AST/StmtProfile.cpp | 308 ++- lib/AST/TemplateBase.cpp | 43 +- lib/AST/TemplateName.cpp | 40 +- lib/AST/Type.cpp | 547 +++- lib/AST/TypePrinter.cpp | 117 +- lib/Analysis/CFG.cpp | 6 +- lib/Analysis/CocoaConventions.cpp | 65 +- lib/Analysis/FormatString.cpp | 3 +- lib/Analysis/ReachableCode.cpp | 6 + lib/Analysis/UninitializedValues.cpp | 46 +- lib/Basic/Builtins.cpp | 22 +- lib/Basic/Diagnostic.cpp | 16 +- lib/Basic/DiagnosticIDs.cpp | 81 +- lib/Basic/IdentifierTable.cpp | 9 +- lib/Basic/SourceManager.cpp | 121 +- lib/Basic/TargetInfo.cpp | 39 +- lib/Basic/Targets.cpp | 348 ++- lib/CMakeLists.txt | 1 + lib/CodeGen/ABIInfo.h | 12 +- lib/CodeGen/BackendUtil.cpp | 46 +- lib/CodeGen/CGBlocks.cpp | 316 ++- lib/CodeGen/CGBlocks.h | 3 +- lib/CodeGen/CGBuiltin.cpp | 348 +-- lib/CodeGen/CGCXXABI.cpp | 2 +- lib/CodeGen/CGCXXABI.h | 2 +- lib/CodeGen/CGCall.cpp | 555 +++- lib/CodeGen/CGCall.h | 47 +- lib/CodeGen/CGClass.cpp | 390 ++- lib/CodeGen/CGCleanup.cpp | 35 +- lib/CodeGen/CGDebugInfo.cpp | 51 +- lib/CodeGen/CGDebugInfo.h | 8 +- lib/CodeGen/CGDecl.cpp | 770 +++++- lib/CodeGen/CGDeclCXX.cpp | 162 +- lib/CodeGen/CGException.cpp | 212 +- lib/CodeGen/CGExpr.cpp | 450 +++- lib/CodeGen/CGExprAgg.cpp | 319 ++- lib/CodeGen/CGExprCXX.cpp | 147 +- lib/CodeGen/CGExprComplex.cpp | 93 +- lib/CodeGen/CGExprConstant.cpp | 42 +- lib/CodeGen/CGExprScalar.cpp | 494 ++-- lib/CodeGen/CGObjC.cpp | 1255 ++++++++- lib/CodeGen/CGObjCGNU.cpp | 224 +- lib/CodeGen/CGObjCMac.cpp | 791 +++--- lib/CodeGen/CGObjCRuntime.cpp | 28 +- lib/CodeGen/CGObjCRuntime.h | 8 +- lib/CodeGen/CGRTTI.cpp | 4 +- lib/CodeGen/CGRecordLayout.h | 16 +- lib/CodeGen/CGRecordLayoutBuilder.cpp | 69 +- lib/CodeGen/CGStmt.cpp | 32 +- lib/CodeGen/CGTemporaries.cpp | 9 +- lib/CodeGen/CGVTT.cpp | 3 +- lib/CodeGen/CGVTables.cpp | 5 +- lib/CodeGen/CGVTables.h | 2 +- lib/CodeGen/CGValue.h | 81 +- lib/CodeGen/CodeGenAction.cpp | 12 +- lib/CodeGen/CodeGenFunction.cpp | 262 +- lib/CodeGen/CodeGenFunction.h | 414 ++- lib/CodeGen/CodeGenModule.cpp | 58 +- lib/CodeGen/CodeGenModule.h | 125 +- lib/CodeGen/CodeGenTypes.cpp | 617 +++-- lib/CodeGen/CodeGenTypes.h | 130 +- lib/CodeGen/GlobalDecl.h | 127 - lib/CodeGen/ItaniumCXXABI.cpp | 123 +- lib/CodeGen/TargetInfo.cpp | 274 +- lib/CodeGen/TargetInfo.h | 20 +- lib/Driver/Arg.cpp | 2 +- lib/Driver/ArgList.cpp | 4 +- lib/Driver/Driver.cpp | 41 +- lib/Driver/Option.cpp | 16 +- lib/Driver/ToolChain.cpp | 34 +- lib/Driver/ToolChains.cpp | 161 +- lib/Driver/ToolChains.h | 26 +- lib/Driver/Tools.cpp | 267 +- lib/Driver/Tools.h | 2 +- lib/Frontend/ASTUnit.cpp | 85 +- lib/Frontend/BoostConAction.cpp | 39 - lib/Frontend/CMakeLists.txt | 1 - lib/Frontend/CacheTokens.cpp | 7 +- lib/Frontend/CompilerInstance.cpp | 3 +- lib/Frontend/CompilerInvocation.cpp | 123 +- lib/Frontend/DependencyFile.cpp | 55 +- lib/Frontend/FrontendAction.cpp | 46 + lib/Frontend/InitHeaderSearch.cpp | 217 +- lib/Frontend/InitPreprocessor.cpp | 170 +- lib/Frontend/PrintPreprocessedOutput.cpp | 48 +- lib/Frontend/TextDiagnosticPrinter.cpp | 115 +- lib/FrontendTool/CMakeLists.txt | 3 +- lib/FrontendTool/ExecuteCompilerInvocation.cpp | 17 +- lib/Headers/float.h | 42 + lib/Headers/stdarg.h | 2 +- lib/Lex/HeaderSearch.cpp | 6 +- lib/Lex/Lexer.cpp | 84 +- lib/Lex/MacroArgs.cpp | 11 +- lib/Lex/MacroArgs.h | 7 +- lib/Lex/MacroInfo.cpp | 32 + lib/Lex/PPDirectives.cpp | 22 +- lib/Lex/PPLexerChange.cpp | 4 + lib/Lex/PPMacroExpansion.cpp | 72 +- lib/Lex/Pragma.cpp | 30 +- lib/Lex/PreprocessingRecord.cpp | 11 +- lib/Lex/Preprocessor.cpp | 18 +- lib/Lex/TokenLexer.cpp | 182 +- lib/Makefile | 4 +- lib/Parse/ParseAST.cpp | 9 +- lib/Parse/ParseDecl.cpp | 498 ++-- lib/Parse/ParseDeclCXX.cpp | 37 +- lib/Parse/ParseExpr.cpp | 156 +- lib/Parse/ParseExprCXX.cpp | 49 +- lib/Parse/ParseObjc.cpp | 46 +- lib/Parse/ParseStmt.cpp | 23 +- lib/Parse/ParseTemplate.cpp | 4 +- lib/Parse/ParseTentative.cpp | 3 +- lib/Parse/Parser.cpp | 26 +- lib/Rewrite/FixItRewriter.cpp | 3 +- lib/Rewrite/HTMLRewrite.cpp | 2 +- lib/Rewrite/RewriteObjC.cpp | 20 +- lib/Rewrite/Rewriter.cpp | 73 +- lib/Sema/AnalysisBasedWarnings.cpp | 84 +- lib/Sema/AttributeList.cpp | 6 + lib/Sema/CMakeLists.txt | 1 + lib/Sema/CodeCompleteConsumer.cpp | 8 +- lib/Sema/DeclSpec.cpp | 80 +- lib/Sema/DelayedDiagnostic.cpp | 3 + lib/Sema/JumpDiagnostics.cpp | 224 +- lib/Sema/Sema.cpp | 59 +- lib/Sema/SemaCXXCast.cpp | 162 +- lib/Sema/SemaCXXScopeSpec.cpp | 58 +- lib/Sema/SemaChecking.cpp | 541 +++- lib/Sema/SemaCodeComplete.cpp | 154 +- lib/Sema/SemaDecl.cpp | 444 +++- lib/Sema/SemaDeclAttr.cpp | 1115 ++++---- lib/Sema/SemaDeclCXX.cpp | 575 ++-- lib/Sema/SemaDeclObjC.cpp | 540 +++- lib/Sema/SemaExpr.cpp | 2797 ++++++-------------- lib/Sema/SemaExprCXX.cpp | 439 ++- lib/Sema/SemaExprMember.cpp | 1594 +++++++++++ lib/Sema/SemaExprObjC.cpp | 627 ++++- lib/Sema/SemaInit.cpp | 410 ++- lib/Sema/SemaLookup.cpp | 990 ++++--- lib/Sema/SemaObjCProperty.cpp | 432 ++- lib/Sema/SemaOverload.cpp | 367 ++- lib/Sema/SemaStmt.cpp | 77 +- lib/Sema/SemaTemplate.cpp | 134 +- lib/Sema/SemaTemplateDeduction.cpp | 328 ++- lib/Sema/SemaTemplateInstantiate.cpp | 151 +- lib/Sema/SemaTemplateInstantiateDecl.cpp | 42 +- lib/Sema/SemaTemplateVariadic.cpp | 16 +- lib/Sema/SemaType.cpp | 848 ++++-- lib/Sema/TreeTransform.h | 175 +- lib/Sema/TypeLocBuilder.h | 27 +- lib/Serialization/ASTReader.cpp | 77 +- lib/Serialization/ASTReaderDecl.cpp | 1 + lib/Serialization/ASTReaderStmt.cpp | 263 +- lib/Serialization/ASTWriter.cpp | 63 +- lib/Serialization/ASTWriterDecl.cpp | 22 +- lib/Serialization/ASTWriterStmt.cpp | 228 +- lib/Serialization/ChainedIncludesSource.cpp | 3 +- .../Checkers/BasicObjCFoundationChecks.cpp | 2 +- lib/StaticAnalyzer/Checkers/CStringChecker.cpp | 756 ++++-- .../Checkers/CallAndMessageChecker.cpp | 2 +- lib/StaticAnalyzer/Checkers/Checkers.td | 8 +- lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp | 6 +- lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp | 27 +- lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp | 79 +- .../Checkers/StackAddrEscapeChecker.cpp | 20 +- lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp | 110 +- lib/StaticAnalyzer/Core/CFRefCount.cpp | 142 +- lib/StaticAnalyzer/Core/Environment.cpp | 3 + lib/StaticAnalyzer/Core/ExprEngine.cpp | 78 +- lib/StaticAnalyzer/Core/RegionStore.cpp | 7 +- lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp | 36 +- runtime/compiler-rt/Makefile | 2 +- test/ARCMT/Common.h | 55 + test/ARCMT/Inputs/test.h | 15 + test/ARCMT/Inputs/test.h.result | 13 + test/ARCMT/Inputs/test1.m.in | 6 + test/ARCMT/Inputs/test1.m.in.result | 5 + test/ARCMT/Inputs/test2.m.in | 6 + test/ARCMT/Inputs/test2.m.in.result | 5 + test/ARCMT/assign-prop-no-arc-runtime.m | 15 + test/ARCMT/assign-prop-no-arc-runtime.m.result | 15 + test/ARCMT/assign-prop-with-arc-runtime.m | 40 + test/ARCMT/assign-prop-with-arc-runtime.m.result | 40 + test/ARCMT/atautorelease-2.m | 29 + test/ARCMT/atautorelease-2.m.result | 28 + test/ARCMT/atautorelease-3.m | 40 + test/ARCMT/atautorelease-3.m.result | 31 + test/ARCMT/atautorelease-check.m | 144 + test/ARCMT/atautorelease.m | 47 + test/ARCMT/atautorelease.m.result | 46 + test/ARCMT/autoreleases.m | 48 + test/ARCMT/autoreleases.m.result | 48 + test/ARCMT/checking.m | 295 +++ test/ARCMT/cxx-checking.mm | 105 + test/ARCMT/cxx-rewrite.mm | 31 + test/ARCMT/cxx-rewrite.mm.result | 31 + test/ARCMT/dealloc.m | 24 + test/ARCMT/dealloc.m.result | 20 + test/ARCMT/driver-migrate.m | 3 + test/ARCMT/init.m | 37 + test/ARCMT/init.m.result | 37 + test/ARCMT/migrate.m | 4 + test/ARCMT/nonobjc-to-objc-cast-2.m | 14 + test/ARCMT/nonobjc-to-objc-cast.m | 38 + test/ARCMT/nonobjc-to-objc-cast.m.result | 38 + test/ARCMT/releases-driver.m | 68 + test/ARCMT/releases-driver.m.result | 61 + test/ARCMT/releases.m | 87 + test/ARCMT/releases.m.result | 79 + test/ARCMT/remove-dealloc-method.m | 26 + test/ARCMT/remove-dealloc-method.m.result | 20 + test/ARCMT/remove-dealloc-zerouts.m | 44 + test/ARCMT/remove-dealloc-zerouts.m.result | 39 + test/ARCMT/remove-statements.m | 45 + test/ARCMT/remove-statements.m.result | 38 + test/ARCMT/retains.m | 71 + test/ARCMT/retains.m.result | 65 + test/ARCMT/rewrite-block-var.m | 25 + test/ARCMT/rewrite-block-var.m.result | 25 + test/ARCMT/safe-arc-assign.m | 14 + test/ARCMT/safe-arc-assign.m.result | 14 + test/ARCMT/with-arc-mode-check.m | 9 + test/ARCMT/with-arc-mode-migrate.m | 12 + test/ARCMT/with-arc-mode-migrate.m.result | 11 + test/ARCMT/with-arc-mode-modify.m | 13 + test/ARCMT/with-arc-mode-modify.m.result | 12 + test/Analysis/bstring.c | 36 +- test/Analysis/misc-ps-eager-assume.m | 1 + test/Analysis/nullptr.cpp | 8 + test/Analysis/objc-arc.m | 149 ++ test/Analysis/pr4209.m | 6 +- test/Analysis/retain-release-gc-only.m | 1 + test/Analysis/retain-release-path-notes-gc.m | 74 + test/Analysis/retain-release-path-notes.m | 123 + test/Analysis/retain-release.m | 87 +- test/Analysis/retain-release.mm | 1 + test/Analysis/string-fail.c | 113 + test/Analysis/string.c | 402 ++- test/Analysis/uninit-ps-rdar6145427.m | 5 +- test/Analysis/uninit-vals-ps-region.m | 9 + test/Analysis/uninit-vals.m | 9 + test/Analysis/variadic-method-types.m | 8 +- test/CMakeLists.txt | 6 +- .../basic/basic.lookup/basic.lookup.argdep/p4.cpp | 13 +- test/CXX/class/p6-0x.cpp | 15 + test/CXX/dcl.dcl/dcl.spec/dcl.stc/p1.cpp | 4 +- .../dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp | 2 +- .../dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp | 3 +- test/CXX/except/except.spec/canonical.cpp | 53 + test/CXX/except/except.spec/p14-ir.cpp | 13 +- test/CXX/special/class.copy/p33-0x.cpp | 32 + test/CXX/stmt.stmt/stmt.dcl/p3-0x.cpp | 8 +- test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp | 2 +- test/CXX/temp/p3.cpp | 20 + .../temp.deduct/temp.deduct.call/p3.cpp | 25 +- test/CXX/temp/temp.res/temp.local/p3.cpp | 8 +- test/CXX/temp/temp.spec/temp.explicit/p7.cpp | 4 +- test/CodeGen/annotate.c | 2 +- test/CodeGen/arm-arguments.c | 4 +- test/CodeGen/arm-asm-variable.c | 31 + test/CodeGen/asm-errors.c | 6 +- test/CodeGen/asm-inout.c | 3 +- test/CodeGen/asm.c | 26 +- test/CodeGen/attr-weak-import.c | 26 + test/CodeGen/attributes.c | 2 +- test/CodeGen/bitfield-2.c | 8 +- test/CodeGen/blocksignature.c | 6 +- test/CodeGen/blockstret.c | 2 +- test/CodeGen/builtin-expect.c | 26 + test/CodeGen/byval-memcpy-elim.c | 33 + test/CodeGen/call-knr-indirect.c | 11 - test/CodeGen/call.c | 39 + test/CodeGen/complex-indirect.c | 10 + test/CodeGen/complex.c | 4 + test/CodeGen/compound-literal.c | 25 +- test/CodeGen/const-init.c | 20 +- test/CodeGen/darwin-thread-specifier.c | 3 + test/CodeGen/debug-info-iv.c | 35 + test/CodeGen/debug-info-member.c | 3 + test/CodeGen/debug-info.c | 5 + test/CodeGen/decl.c | 4 +- test/CodeGen/designated-initializers.c | 10 +- test/CodeGen/flexible-array-init.c | 4 +- test/CodeGen/functions.c | 6 + test/CodeGen/global-init.c | 4 +- test/CodeGen/init.c | 8 + test/CodeGen/libcalls.c | 23 + test/CodeGen/mmx-inline-asm.c | 2 +- test/CodeGen/ms-anonymous-struct.c | 4 +- test/CodeGen/packed-union.c | 1 - test/CodeGen/pragma-pack-3.c | 2 - test/CodeGen/private-extern-redef.c | 39 + test/CodeGen/struct-init.c | 10 +- test/CodeGen/struct.c | 13 + test/CodeGen/trapv.c | 20 +- test/CodeGen/union-init2.c | 4 +- test/CodeGen/vla.c | 63 +- test/CodeGen/volatile-1.c | 2 +- test/CodeGen/volatile-2.c | 12 +- test/CodeGen/x86_32-arguments-darwin.c | 7 +- test/CodeGen/x86_32-arguments-linux.c | 2 +- test/CodeGen/x86_32-arguments-nommx.c | 11 + test/CodeGen/x86_64-arguments.c | 55 +- .../anonymous-union-member-initializer.cpp | 18 +- test/CodeGenCXX/attr-used.cpp | 4 +- test/CodeGenCXX/block-byref-cxx-objc.cpp | 4 +- test/CodeGenCXX/blocks.cpp | 4 +- test/CodeGenCXX/class-layout.cpp | 2 +- test/CodeGenCXX/compound-literals.cpp | 27 + test/CodeGenCXX/const-init.cpp | 4 +- test/CodeGenCXX/constructor-init.cpp | 16 + test/CodeGenCXX/constructors.cpp | 15 +- test/CodeGenCXX/copy-constructor-elim-2.cpp | 14 +- test/CodeGenCXX/copy-constructor-synthesis-2.cpp | 2 +- test/CodeGenCXX/copy-initialization.cpp | 2 +- test/CodeGenCXX/cxx0x-defaulted-templates.cpp | 12 +- test/CodeGenCXX/cxx0x-delegating-ctors.cpp | 20 +- .../default-constructor-default-argument.cpp | 2 +- .../default-constructor-template-member.cpp | 6 +- test/CodeGenCXX/delete.cpp | 58 +- test/CodeGenCXX/destructors.cpp | 46 +- test/CodeGenCXX/eh.cpp | 14 +- test/CodeGenCXX/elide-call-reference.cpp | 4 +- test/CodeGenCXX/for-range.cpp | 8 +- test/CodeGenCXX/global-init.cpp | 31 +- test/CodeGenCXX/implicit-copy-constructor.cpp | 10 + test/CodeGenCXX/init-incomplete-type.cpp | 19 + test/CodeGenCXX/mangle-subst-std.cpp | 4 +- test/CodeGenCXX/mangle-template.cpp | 4 +- test/CodeGenCXX/mangle.cpp | 157 +- test/CodeGenCXX/member-function-pointers.cpp | 44 +- test/CodeGenCXX/member-init-assignment.cpp | 4 +- test/CodeGenCXX/member-init-ctor.cpp | 2 +- test/CodeGenCXX/new-overflow.cpp | 209 ++ test/CodeGenCXX/new.cpp | 36 +- test/CodeGenCXX/noinline-template.cpp | 16 + test/CodeGenCXX/nrvo.cpp | 42 +- test/CodeGenCXX/partial-destruction.cpp | 169 ++ test/CodeGenCXX/pointers-to-data-members.cpp | 6 +- test/CodeGenCXX/pr9965.cpp | 6 +- test/CodeGenCXX/references.cpp | 32 +- test/CodeGenCXX/static-init-3.cpp | 4 +- test/CodeGenCXX/static-init.cpp | 3 + test/CodeGenCXX/stmtexpr.cpp | 10 +- test/CodeGenCXX/template-anonymous-types.cpp | 4 +- test/CodeGenCXX/temporaries.cpp | 22 +- test/CodeGenCXX/value-init.cpp | 69 +- test/CodeGenCXX/variadic-templates.cpp | 11 + test/CodeGenCXX/virt-call-offsets.cpp | 2 +- test/CodeGenCXX/virtual-base-destructor-call.cpp | 30 +- test/CodeGenCXX/virtual-bases.cpp | 4 +- .../virtual-functions-incomplete-types.cpp | 2 +- test/CodeGenCXX/virtual-pseudo-destructor-call.cpp | 6 +- test/CodeGenCXX/visibility-inlines-hidden.cpp | 2 +- test/CodeGenCXX/visibility.cpp | 32 + test/CodeGenCXX/vla.cpp | 43 + test/CodeGenCXX/volatile-1.cpp | 2 +- test/CodeGenCXX/vtable-pointer-initialization.cpp | 6 +- test/CodeGenCXX/x86_32-arguments.cpp | 2 +- test/CodeGenCXX/x86_64-arguments.cpp | 34 + test/CodeGenObjC/arc-arm.m | 20 + test/CodeGenObjC/arc-block-ivar-layout.m | 60 + test/CodeGenObjC/arc-bridged-cast.m | 90 + test/CodeGenObjC/arc-compound-stmt.m | 29 + test/CodeGenObjC/arc-foreach.m | 72 + test/CodeGenObjC/arc-ivar-layout.m | 44 + test/CodeGenObjC/arc-no-runtime.m | 9 + test/CodeGenObjC/arc-related-result-type.m | 30 + test/CodeGenObjC/arc-unbridged-cast.m | 37 + test/CodeGenObjC/arc-unopt.m | 69 + test/CodeGenObjC/arc-weak-property.m | 55 + test/CodeGenObjC/arc.m | 1554 +++++++++++ test/CodeGenObjC/autorelease.m | 30 + test/CodeGenObjC/block-6.m | 14 +- test/CodeGenObjC/blocks.m | 10 +- test/CodeGenObjC/debug-info-foreach.m | 20 - test/CodeGenObjC/encode-test.m | 4 + test/CodeGenObjC/exceptions-nonfragile.m | 16 +- test/CodeGenObjC/gc.m | 14 + test/CodeGenObjC/mrr-autorelease.m | 24 + test/CodeGenObjC/nonlazy-msgSend.m | 6 + test/CodeGenObjC/property-list-in-class.m | 4 +- test/CodeGenObjC/related-result-type.m | 54 + test/CodeGenObjC/terminate.m | 29 + test/CodeGenObjC/variadic-sends.m | 8 +- test/CodeGenObjCXX/arc-globals.mm | 27 + test/CodeGenObjCXX/arc-mangle.mm | 25 + test/CodeGenObjCXX/arc-move.mm | 75 + test/CodeGenObjCXX/arc-new-delete.mm | 95 + test/CodeGenObjCXX/arc-pseudo-destructors.mm | 21 + test/CodeGenObjCXX/arc-references.mm | 83 + test/CodeGenObjCXX/arc-special-member-functions.mm | 161 ++ test/CodeGenObjCXX/arc.mm | 166 ++ test/CodeGenObjCXX/catch-id-type.mm | 48 + test/CodeGenObjCXX/copy.mm | 26 + test/CodeGenObjCXX/encode.mm | 14 + test/CodeGenObjCXX/gc.mm | 20 + .../property-object-conditional-exp.mm | 7 +- test/CodeGenObjCXX/property-objects.mm | 2 +- test/CodeGenOpenCL/2011-04-15-vec-init-from-vec.cl | 7 +- test/CodeGenOpenCL/vector_literals_valid.cl | 22 + test/Driver/arc-exceptions.m | 5 + test/Driver/arc.c | 14 + test/Driver/darwin-ld.c | 20 +- test/Driver/darwin-objc-options.m | 2 + test/Driver/darwin-xarch.c | 6 + test/Driver/gnu-runtime.m | 5 + test/Driver/ios-simulator-arcruntime.c | 6 + test/Driver/mg.c | 5 + test/Driver/no-objc-arr.m | 8 + test/Driver/noexecstack.c | 1 + test/Driver/rewrite-objc.m | 2 +- test/Driver/sysroot.c | 6 +- test/Driver/x86_features.c | 4 +- test/FixIt/fixit-objc.m | 14 + test/FixIt/fixit.c | 5 + test/FixIt/typo-crash.cpp | 11 + test/FixIt/typo.cpp | 12 + test/Frontend/dependency-gen.c | 34 +- test/Index/annotate-tokens-pp.c | 14 +- test/Index/annotate-tokens.cpp | 8 +- test/Index/annotate-tokens.m | 28 +- test/Index/arc-annotate.m | 38 + test/Index/arc-complete.m | 16 + test/Index/c-index-api-loadTU-test.m | 11 + test/Index/c-index-getCursor-pp.c | 8 +- test/Index/c-index-getCursor-test.m | 2 +- test/Index/code-completion.cpp | 20 + test/Index/complete-exprs.m | 9 +- test/Index/complete-natural.m | 5 +- test/Index/complete-property-flags.m | 2 + test/Index/get-cursor.cpp | 7 + test/Index/nested-macro-instantiations.cpp | 10 +- test/Index/werror.c | 15 + test/Lexer/has_feature_objc_arc.m | 20 + test/Makefile | 2 +- test/Misc/caret-diags-macros.c | 107 +- test/Misc/diag-aka-types.cpp | 38 + test/Misc/include-stack-for-note-flag.cpp | 4 +- test/Misc/macro-backtrace-limit.c | 12 +- test/PCH/Inputs/arc.h | 20 + test/PCH/Inputs/typo.hpp | 8 + test/PCH/arc.m | 9 + test/PCH/typo.cpp | 17 + test/PCH/variables.c | 34 +- test/PCH/variables.h | 1 - test/Parser/MicrosoftExtensions.c | 2 +- test/Parser/parenthesis-balance.cpp | 15 + test/Parser/recovery.c | 14 + test/Parser/switch-recovery.cpp | 14 + test/Preprocessor/include-directive2.c | 2 +- test/Preprocessor/init.c | 2 +- test/Preprocessor/macro_paste_bad.c | 1 - test/Preprocessor/macro_paste_hashhash.c | 6 +- test/Preprocessor/macro_paste_simple.c | 13 +- test/Preprocessor/pragma_diagnostic_output.c | 26 + test/Preprocessor/warn-macro-unused.c | 5 + test/Preprocessor/warn-macro-unused.h | 1 + test/Sema/arm-neon-types.c | 7 + test/Sema/asm.c | 20 +- test/Sema/attr-deprecated.c | 2 + test/Sema/attr-naked.c | 4 + test/Sema/attr-unavailable-message.c | 10 + test/Sema/attr-weak.c | 4 + test/Sema/bitfield.c | 1 + test/Sema/compare.c | 15 + test/Sema/const-eval.c | 2 +- test/Sema/conversion-64-32.c | 10 + test/Sema/conversion.c | 8 + test/Sema/ext_vector_casts.c | 2 +- test/Sema/extern-redecl.c | 15 +- test/Sema/format-strings.c | 14 + test/Sema/i-c-e.c | 2 +- test/Sema/incomplete-decl.c | 2 +- test/Sema/inline-redef.c | 24 + test/Sema/inline.c | 18 +- test/Sema/no-format-y2k-turnsoff-format.c | 9 + test/Sema/nonnull.c | 21 + test/Sema/paren-list-expr-type.cpp | 17 + test/Sema/parentheses.c | 30 +- test/Sema/parentheses.cpp | 38 +- test/Sema/pointer-addition.c | 25 +- test/Sema/pointer-subtract-compat.c | 2 +- test/Sema/shift.c | 2 +- test/Sema/sign-conversion.c | 8 + test/Sema/struct-decl.c | 2 +- test/Sema/typecheck-binop.c | 6 +- test/Sema/typedef-variable-type.c | 2 +- test/Sema/uninit-variables.c | 15 + test/Sema/varargs.c | 15 + test/Sema/vla.c | 4 +- test/Sema/warn-sizeof-arrayarg.c | 30 + test/Sema/x86-builtin-palignr.c | 4 +- test/SemaCXX/PR10243.cpp | 23 + test/SemaCXX/PR7410.cpp | 13 + test/SemaCXX/PR9459.cpp | 2 +- test/SemaCXX/alignof-sizeof-reference.cpp | 6 + test/SemaCXX/attr-unavailable.cpp | 9 + test/SemaCXX/c99-variable-length-array.cpp | 9 + test/SemaCXX/condition.cpp | 5 +- test/SemaCXX/conversion-function.cpp | 14 + test/SemaCXX/copy-assignment.cpp | 18 +- test/SemaCXX/crashes.cpp | 9 + test/SemaCXX/decltype.cpp | 5 + test/SemaCXX/enum-scoped.cpp | 23 + test/SemaCXX/expressions.cpp | 22 + test/SemaCXX/for-range-unused.cpp | 21 + test/SemaCXX/function-overload-typo-crash.cpp | 12 + test/SemaCXX/generalized-initializers.cpp | 62 +- test/SemaCXX/i-c-e-cxx.cpp | 13 + test/SemaCXX/member-init.cpp | 4 + test/SemaCXX/member-pointer.cpp | 16 + ...issing-namespace-qualifier-typo-corrections.cpp | 72 + test/SemaCXX/nested-name-spec.cpp | 21 +- test/SemaCXX/new-delete.cpp | 8 + test/SemaCXX/null_in_arithmetic_ops.cpp | 93 + test/SemaCXX/nullptr_in_arithmetic_ops.cpp | 73 + test/SemaCXX/overloaded-name.cpp | 16 + test/SemaCXX/return.cpp | 11 + test/SemaCXX/vararg-non-pod.cpp | 18 + test/SemaCXX/vector.cpp | 8 +- test/SemaCXX/virtuals.cpp | 29 +- test/SemaCXX/warn-bad-memaccess.cpp | 42 + test/SemaCXX/warn-memset-bad-sizeof.cpp | 101 + .../warn-pure-virtual-call-from-ctor-dtor.cpp | 7 + test/SemaCXX/warn-unused-variables.cpp | 26 + test/SemaObjC/Inputs/arc-system-header.h | 52 + test/SemaObjC/arc-bridged-cast.m | 43 + test/SemaObjC/arc-decls.m | 64 + test/SemaObjC/arc-jump-block.m | 84 + test/SemaObjC/arc-no-runtime.m | 15 + test/SemaObjC/arc-non-pod-memaccess.m | 55 + test/SemaObjC/arc-peformselector.m | 38 + test/SemaObjC/arc-property-decl-attrs.m | 67 + test/SemaObjC/arc-property-lifetime.m | 112 + test/SemaObjC/arc-property.m | 48 + test/SemaObjC/arc-system-header.m | 50 + test/SemaObjC/arc-type-conversion.m | 77 + test/SemaObjC/arc-unavailable-for-weakref.m | 47 + test/SemaObjC/arc-unbridged-cast.m | 18 + test/SemaObjC/arc-unsafe-assigns.m | 41 + test/SemaObjC/arc-unsafe_unretained.m | 12 + test/SemaObjC/arc.m | 628 +++++ test/SemaObjC/autoreleasepool.m | 22 + test/SemaObjC/class-proto-1.m | 4 +- test/SemaObjC/class-unavail-warning.m | 2 +- test/SemaObjC/debugger-support.m | 14 + test/SemaObjC/error-property-gc-attr.m | 4 +- test/SemaObjC/forward-class-1.m | 15 +- test/SemaObjC/ivar-ref-misuse.m | 5 +- test/SemaObjC/method-lookup-3.m | 16 + test/SemaObjC/no-warning-unavail-unimp.m | 12 + test/SemaObjC/property-10.m | 17 +- test/SemaObjC/property-inherited.m | 4 +- .../property-ns-returns-not-retained-attr.m | 21 + test/SemaObjC/related-result-type-inference.m | 2 +- test/SemaObjC/selector-3.m | 25 + test/SemaObjC/self-declared-in-block.m | 15 +- test/SemaObjC/sizeof-interface.m | 2 +- test/SemaObjC/special-dep-unavail-warning.m | 10 +- test/SemaObjC/synthesized-ivar.m | 8 + test/SemaObjC/typedef-class.m | 2 +- test/SemaObjC/undef-superclass-1.m | 6 +- test/SemaObjC/warn-retain-cycle.m | 91 + test/SemaObjC/weak-property.m | 24 + test/SemaObjCXX/Inputs/arc-system-header.h | 14 + test/SemaObjCXX/arc-0x.mm | 32 + test/SemaObjCXX/arc-bool-conversion.mm | 7 + test/SemaObjCXX/arc-bridged-cast.mm | 36 + test/SemaObjCXX/arc-libcxx.mm | 11 + test/SemaObjCXX/arc-libstdcxx.mm | 10 + test/SemaObjCXX/arc-memfunc.mm | 15 + test/SemaObjCXX/arc-non-pod.mm | 116 + test/SemaObjCXX/arc-object-init-destroy.mm | 52 + test/SemaObjCXX/arc-overloading.mm | 175 ++ test/SemaObjCXX/arc-system-header.mm | 10 + test/SemaObjCXX/arc-templates.mm | 254 ++ test/SemaObjCXX/arc-type-conversion.mm | 221 ++ test/SemaObjCXX/arc-type-traits.mm | 90 + test/SemaObjCXX/arc-unavailable-for-weakref.mm | 47 + test/SemaObjCXX/exceptions-fragile.mm | 2 +- test/SemaObjCXX/gc-attributes.mm | 4 +- test/SemaObjCXX/null_objc_pointer.mm | 13 + test/SemaObjCXX/nullptr.mm | 5 +- test/SemaObjCXX/property-type-mismatch.mm | 19 + test/SemaObjCXX/related-result-type-inference.mm | 2 +- test/SemaOpenCL/vector_literals_invalid.cl | 13 + test/SemaTemplate/class-template-decl.cpp | 2 +- test/SemaTemplate/deduction.cpp | 12 + test/SemaTemplate/default-arguments.cpp | 15 + test/SemaTemplate/dependent-names-no-std.cpp | 2 +- test/SemaTemplate/dependent-names.cpp | 42 +- test/SemaTemplate/ext-vector-type.cpp | 34 + test/SemaTemplate/instantiate-call.cpp | 2 +- test/SemaTemplate/instantiate-function-2.cpp | 33 + test/SemaTemplate/instantiate-member-class.cpp | 14 + test/SemaTemplate/instantiate-try-catch.cpp | 17 + .../member-inclass-init-value-dependent.cpp | 11 + test/SemaTemplate/unresolved-construct.cpp | 19 + test/Unit/lit.cfg | 18 +- tools/CMakeLists.txt | 2 + tools/Makefile | 4 +- tools/arcmt-test/CMakeLists.txt | 13 + tools/arcmt-test/Makefile | 24 + tools/arcmt-test/arcmt-test.cpp | 374 +++ tools/c-arcmt-test/CMakeLists.txt | 14 + tools/c-arcmt-test/Makefile | 25 + tools/c-arcmt-test/c-arcmt-test.c | 91 + tools/c-index-test/Makefile | 4 +- tools/c-index-test/c-index-test.c | 109 +- tools/driver/CMakeLists.txt | 1 + tools/driver/Makefile | 2 +- tools/driver/cc1_main.cpp | 2 + tools/driver/cc1as_main.cpp | 24 +- tools/driver/driver.cpp | 8 +- tools/libclang/ARCMigrate.cpp | 98 + tools/libclang/CIndex.cpp | 125 +- tools/libclang/CIndexCodeCompletion.cpp | 192 ++ tools/libclang/CMakeLists.txt | 3 + tools/libclang/CXCursor.cpp | 23 +- tools/libclang/CXCursor.h | 13 +- tools/libclang/CXType.cpp | 6 +- tools/libclang/Makefile | 5 +- tools/libclang/libclang.darwin.exports | 6 + tools/libclang/libclang.exports | 6 + tools/scan-build/ccc-analyzer | 19 +- unittests/Basic/FileManagerTest.cpp | 6 +- unittests/Frontend/Makefile | 4 +- www/compatibility.html | 4 +- 789 files changed, 45211 insertions(+), 11291 deletions(-) create mode 100644 INPUTS/cfg-big-switch.c create mode 100644 INPUTS/cfg-long-chain1.c create mode 100644 INPUTS/cfg-long-chain2.c create mode 100644 INPUTS/cfg-long-chain3.c create mode 100644 INPUTS/cfg-nested-switches.c create mode 100644 docs/AutomaticReferenceCounting.html delete mode 100644 docs/index.html create mode 100644 include/clang/ARCMigrate/ARCMT.h create mode 100644 include/clang/ARCMigrate/ARCMTActions.h create mode 100644 include/clang/ARCMigrate/FileRemapper.h create mode 100644 include/clang/AST/GlobalDecl.h create mode 100644 include/clang/Basic/DelayedCleanupPool.h create mode 100644 include/clang/Basic/DiagnosticCategories.h create mode 100644 include/clang/Driver/ObjCRuntime.h create mode 100644 include/clang/Sema/LocInfoType.h create mode 100644 include/clang/Sema/TypoCorrection.h create mode 100644 lib/ARCMigrate/ARCMT.cpp create mode 100644 lib/ARCMigrate/ARCMTActions.cpp create mode 100644 lib/ARCMigrate/CMakeLists.txt create mode 100644 lib/ARCMigrate/FileRemapper.cpp create mode 100644 lib/ARCMigrate/Internals.h create mode 100644 lib/ARCMigrate/Makefile create mode 100644 lib/ARCMigrate/TransARCAssign.cpp create mode 100644 lib/ARCMigrate/TransAutoreleasePool.cpp create mode 100644 lib/ARCMigrate/TransBlockObjCVariable.cpp create mode 100644 lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp create mode 100644 lib/ARCMigrate/TransProperties.cpp create mode 100644 lib/ARCMigrate/TransRetainReleaseDealloc.cpp create mode 100644 lib/ARCMigrate/TransUnbridgedCasts.cpp create mode 100644 lib/ARCMigrate/TransUnusedInitDelegate.cpp create mode 100644 lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp create mode 100644 lib/ARCMigrate/TransformActions.cpp create mode 100644 lib/ARCMigrate/Transforms.cpp create mode 100644 lib/ARCMigrate/Transforms.h delete mode 100644 lib/CodeGen/GlobalDecl.h delete mode 100644 lib/Frontend/BoostConAction.cpp create mode 100644 lib/Sema/SemaExprMember.cpp create mode 100644 test/ARCMT/Common.h create mode 100644 test/ARCMT/Inputs/test.h create mode 100644 test/ARCMT/Inputs/test.h.result create mode 100644 test/ARCMT/Inputs/test1.m.in create mode 100644 test/ARCMT/Inputs/test1.m.in.result create mode 100644 test/ARCMT/Inputs/test2.m.in create mode 100644 test/ARCMT/Inputs/test2.m.in.result create mode 100644 test/ARCMT/assign-prop-no-arc-runtime.m create mode 100644 test/ARCMT/assign-prop-no-arc-runtime.m.result create mode 100644 test/ARCMT/assign-prop-with-arc-runtime.m create mode 100644 test/ARCMT/assign-prop-with-arc-runtime.m.result create mode 100644 test/ARCMT/atautorelease-2.m create mode 100644 test/ARCMT/atautorelease-2.m.result create mode 100644 test/ARCMT/atautorelease-3.m create mode 100644 test/ARCMT/atautorelease-3.m.result create mode 100644 test/ARCMT/atautorelease-check.m create mode 100644 test/ARCMT/atautorelease.m create mode 100644 test/ARCMT/atautorelease.m.result create mode 100644 test/ARCMT/autoreleases.m create mode 100644 test/ARCMT/autoreleases.m.result create mode 100644 test/ARCMT/checking.m create mode 100644 test/ARCMT/cxx-checking.mm create mode 100644 test/ARCMT/cxx-rewrite.mm create mode 100644 test/ARCMT/cxx-rewrite.mm.result create mode 100644 test/ARCMT/dealloc.m create mode 100644 test/ARCMT/dealloc.m.result create mode 100644 test/ARCMT/driver-migrate.m create mode 100644 test/ARCMT/init.m create mode 100644 test/ARCMT/init.m.result create mode 100644 test/ARCMT/migrate.m create mode 100644 test/ARCMT/nonobjc-to-objc-cast-2.m create mode 100644 test/ARCMT/nonobjc-to-objc-cast.m create mode 100644 test/ARCMT/nonobjc-to-objc-cast.m.result create mode 100644 test/ARCMT/releases-driver.m create mode 100644 test/ARCMT/releases-driver.m.result create mode 100644 test/ARCMT/releases.m create mode 100644 test/ARCMT/releases.m.result create mode 100644 test/ARCMT/remove-dealloc-method.m create mode 100644 test/ARCMT/remove-dealloc-method.m.result create mode 100644 test/ARCMT/remove-dealloc-zerouts.m create mode 100644 test/ARCMT/remove-dealloc-zerouts.m.result create mode 100644 test/ARCMT/remove-statements.m create mode 100644 test/ARCMT/remove-statements.m.result create mode 100644 test/ARCMT/retains.m create mode 100644 test/ARCMT/retains.m.result create mode 100644 test/ARCMT/rewrite-block-var.m create mode 100644 test/ARCMT/rewrite-block-var.m.result create mode 100644 test/ARCMT/safe-arc-assign.m create mode 100644 test/ARCMT/safe-arc-assign.m.result create mode 100644 test/ARCMT/with-arc-mode-check.m create mode 100644 test/ARCMT/with-arc-mode-migrate.m create mode 100644 test/ARCMT/with-arc-mode-migrate.m.result create mode 100644 test/ARCMT/with-arc-mode-modify.m create mode 100644 test/ARCMT/with-arc-mode-modify.m.result create mode 100644 test/Analysis/objc-arc.m create mode 100644 test/Analysis/retain-release-path-notes-gc.m create mode 100644 test/Analysis/retain-release-path-notes.m create mode 100644 test/Analysis/string-fail.c create mode 100644 test/CXX/class/p6-0x.cpp create mode 100644 test/CXX/except/except.spec/canonical.cpp create mode 100644 test/CXX/temp/p3.cpp create mode 100644 test/CodeGen/arm-asm-variable.c create mode 100644 test/CodeGen/attr-weak-import.c delete mode 100644 test/CodeGen/call-knr-indirect.c create mode 100644 test/CodeGen/call.c create mode 100644 test/CodeGen/complex-indirect.c create mode 100644 test/CodeGen/darwin-thread-specifier.c create mode 100644 test/CodeGen/debug-info-iv.c create mode 100644 test/CodeGen/debug-info-member.c create mode 100644 test/CodeGen/private-extern-redef.c create mode 100644 test/CodeGen/x86_32-arguments-nommx.c create mode 100644 test/CodeGenCXX/compound-literals.cpp create mode 100644 test/CodeGenCXX/new-overflow.cpp create mode 100644 test/CodeGenCXX/noinline-template.cpp create mode 100644 test/CodeGenCXX/partial-destruction.cpp create mode 100644 test/CodeGenCXX/vla.cpp create mode 100644 test/CodeGenObjC/arc-arm.m create mode 100644 test/CodeGenObjC/arc-block-ivar-layout.m create mode 100644 test/CodeGenObjC/arc-bridged-cast.m create mode 100644 test/CodeGenObjC/arc-compound-stmt.m create mode 100644 test/CodeGenObjC/arc-foreach.m create mode 100644 test/CodeGenObjC/arc-ivar-layout.m create mode 100644 test/CodeGenObjC/arc-no-runtime.m create mode 100644 test/CodeGenObjC/arc-related-result-type.m create mode 100644 test/CodeGenObjC/arc-unbridged-cast.m create mode 100644 test/CodeGenObjC/arc-unopt.m create mode 100644 test/CodeGenObjC/arc-weak-property.m create mode 100644 test/CodeGenObjC/arc.m create mode 100644 test/CodeGenObjC/autorelease.m delete mode 100644 test/CodeGenObjC/debug-info-foreach.m create mode 100644 test/CodeGenObjC/gc.m create mode 100644 test/CodeGenObjC/mrr-autorelease.m create mode 100644 test/CodeGenObjC/nonlazy-msgSend.m create mode 100644 test/CodeGenObjC/related-result-type.m create mode 100644 test/CodeGenObjC/terminate.m create mode 100644 test/CodeGenObjCXX/arc-globals.mm create mode 100644 test/CodeGenObjCXX/arc-mangle.mm create mode 100644 test/CodeGenObjCXX/arc-move.mm create mode 100644 test/CodeGenObjCXX/arc-new-delete.mm create mode 100644 test/CodeGenObjCXX/arc-pseudo-destructors.mm create mode 100644 test/CodeGenObjCXX/arc-references.mm create mode 100644 test/CodeGenObjCXX/arc-special-member-functions.mm create mode 100644 test/CodeGenObjCXX/arc.mm create mode 100644 test/CodeGenObjCXX/catch-id-type.mm create mode 100644 test/CodeGenObjCXX/copy.mm create mode 100644 test/CodeGenObjCXX/gc.mm create mode 100644 test/CodeGenOpenCL/vector_literals_valid.cl create mode 100644 test/Driver/arc-exceptions.m create mode 100644 test/Driver/arc.c create mode 100644 test/Driver/gnu-runtime.m create mode 100644 test/Driver/ios-simulator-arcruntime.c create mode 100644 test/Driver/mg.c create mode 100644 test/Driver/no-objc-arr.m create mode 100644 test/Driver/noexecstack.c create mode 100644 test/FixIt/typo-crash.cpp create mode 100644 test/Index/arc-annotate.m create mode 100644 test/Index/arc-complete.m create mode 100644 test/Index/werror.c create mode 100644 test/Lexer/has_feature_objc_arc.m create mode 100644 test/PCH/Inputs/arc.h create mode 100644 test/PCH/Inputs/typo.hpp create mode 100644 test/PCH/arc.m create mode 100644 test/PCH/typo.cpp create mode 100644 test/Parser/parenthesis-balance.cpp create mode 100644 test/Preprocessor/pragma_diagnostic_output.c create mode 100644 test/Preprocessor/warn-macro-unused.h create mode 100644 test/Sema/inline-redef.c create mode 100644 test/Sema/no-format-y2k-turnsoff-format.c create mode 100644 test/Sema/nonnull.c create mode 100644 test/Sema/paren-list-expr-type.cpp create mode 100644 test/Sema/sign-conversion.c create mode 100644 test/Sema/warn-sizeof-arrayarg.c create mode 100644 test/SemaCXX/PR10243.cpp create mode 100644 test/SemaCXX/PR7410.cpp create mode 100644 test/SemaCXX/for-range-unused.cpp create mode 100644 test/SemaCXX/function-overload-typo-crash.cpp create mode 100644 test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp create mode 100644 test/SemaCXX/null_in_arithmetic_ops.cpp create mode 100644 test/SemaCXX/nullptr_in_arithmetic_ops.cpp create mode 100644 test/SemaCXX/warn-memset-bad-sizeof.cpp create mode 100644 test/SemaObjC/Inputs/arc-system-header.h create mode 100644 test/SemaObjC/arc-bridged-cast.m create mode 100644 test/SemaObjC/arc-decls.m create mode 100644 test/SemaObjC/arc-jump-block.m create mode 100644 test/SemaObjC/arc-no-runtime.m create mode 100644 test/SemaObjC/arc-non-pod-memaccess.m create mode 100644 test/SemaObjC/arc-peformselector.m create mode 100644 test/SemaObjC/arc-property-decl-attrs.m create mode 100644 test/SemaObjC/arc-property-lifetime.m create mode 100644 test/SemaObjC/arc-property.m create mode 100644 test/SemaObjC/arc-system-header.m create mode 100644 test/SemaObjC/arc-type-conversion.m create mode 100644 test/SemaObjC/arc-unavailable-for-weakref.m create mode 100644 test/SemaObjC/arc-unbridged-cast.m create mode 100644 test/SemaObjC/arc-unsafe-assigns.m create mode 100644 test/SemaObjC/arc-unsafe_unretained.m create mode 100644 test/SemaObjC/arc.m create mode 100644 test/SemaObjC/autoreleasepool.m create mode 100644 test/SemaObjC/debugger-support.m create mode 100644 test/SemaObjC/no-warning-unavail-unimp.m create mode 100644 test/SemaObjC/property-ns-returns-not-retained-attr.m create mode 100644 test/SemaObjC/warn-retain-cycle.m create mode 100644 test/SemaObjC/weak-property.m create mode 100644 test/SemaObjCXX/Inputs/arc-system-header.h create mode 100644 test/SemaObjCXX/arc-0x.mm create mode 100644 test/SemaObjCXX/arc-bool-conversion.mm create mode 100644 test/SemaObjCXX/arc-bridged-cast.mm create mode 100644 test/SemaObjCXX/arc-libcxx.mm create mode 100644 test/SemaObjCXX/arc-libstdcxx.mm create mode 100644 test/SemaObjCXX/arc-memfunc.mm create mode 100644 test/SemaObjCXX/arc-non-pod.mm create mode 100644 test/SemaObjCXX/arc-object-init-destroy.mm create mode 100644 test/SemaObjCXX/arc-overloading.mm create mode 100644 test/SemaObjCXX/arc-system-header.mm create mode 100644 test/SemaObjCXX/arc-templates.mm create mode 100644 test/SemaObjCXX/arc-type-conversion.mm create mode 100644 test/SemaObjCXX/arc-type-traits.mm create mode 100644 test/SemaObjCXX/arc-unavailable-for-weakref.mm create mode 100644 test/SemaObjCXX/null_objc_pointer.mm create mode 100644 test/SemaObjCXX/property-type-mismatch.mm create mode 100644 test/SemaOpenCL/vector_literals_invalid.cl create mode 100644 test/SemaTemplate/member-inclass-init-value-dependent.cpp create mode 100644 test/SemaTemplate/unresolved-construct.cpp create mode 100644 tools/arcmt-test/CMakeLists.txt create mode 100644 tools/arcmt-test/Makefile create mode 100644 tools/arcmt-test/arcmt-test.cpp create mode 100644 tools/c-arcmt-test/CMakeLists.txt create mode 100644 tools/c-arcmt-test/Makefile create mode 100644 tools/c-arcmt-test/c-arcmt-test.c create mode 100644 tools/libclang/ARCMigrate.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index aa89823e76f8..3ad60eaff516 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,11 @@ if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR ) endif() if( NOT EXISTS "${CLANG_PATH_TO_LLVM_BUILD}/bin/tblgen${CMAKE_EXECUTABLE_SUFFIX}" ) - message(FATAL_ERROR "Please set CLANG_PATH_TO_LLVM_BUILD to a directory containing a LLVM build.") + # Looking for bin/Debug/tblgen is a complete hack. How can we get + # around this? + if( NOT EXISTS "${CLANG_PATH_TO_LLVM_BUILD}/bin/Debug/tblgen${CMAKE_EXECUTABLE_SUFFIX}" ) + message(FATAL_ERROR "Please set CLANG_PATH_TO_LLVM_BUILD to a directory containing a LLVM build.") + endif() endif() list(APPEND CMAKE_MODULE_PATH "${CLANG_PATH_TO_LLVM_BUILD}/share/llvm/cmake") @@ -42,7 +46,12 @@ if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR ) include_directories("${PATH_TO_LLVM_BUILD}/include" "${LLVM_MAIN_INCLUDE_DIR}") link_directories("${PATH_TO_LLVM_BUILD}/lib") - set(LLVM_TABLEGEN_EXE "${PATH_TO_LLVM_BUILD}/bin/tblgen") + if( EXISTS "${CLANG_PATH_TO_LLVM_BUILD}/bin/tblgen${CMAKE_EXECUTABLE_SUFFIX}" ) + set(LLVM_TABLEGEN_EXE "${PATH_TO_LLVM_BUILD}/bin/tblgen") + else() + # FIXME: This is an utter hack. + set(LLVM_TABLEGEN_EXE "${PATH_TO_LLVM_BUILD}/bin/Debug/tblgen") + endif() set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin ) set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib ) diff --git a/INPUTS/cfg-big-switch.c b/INPUTS/cfg-big-switch.c new file mode 100644 index 000000000000..a48b51a2e301 --- /dev/null +++ b/INPUTS/cfg-big-switch.c @@ -0,0 +1,27 @@ +#define EXPAND_2_CASES(i, x, y) CASE(i, x, y); CASE(i + 1, x, y); +#define EXPAND_4_CASES(i, x, y) EXPAND_2_CASES(i, x, y) EXPAND_2_CASES(i + 2, x, y) +#define EXPAND_8_CASES(i, x, y) EXPAND_4_CASES(i, x, y) EXPAND_4_CASES(i + 4, x, y) +#define EXPAND_16_CASES(i, x, y) EXPAND_8_CASES(i, x, y) EXPAND_8_CASES(i + 8, x, y) +#define EXPAND_32_CASES(i, x, y) EXPAND_16_CASES(i, x, y) EXPAND_16_CASES(i + 16, x, y) +#define EXPAND_64_CASES(i, x, y) EXPAND_32_CASES(i, x, y) EXPAND_32_CASES(i + 32, x, y) +#define EXPAND_128_CASES(i, x, y) EXPAND_64_CASES(i, x, y) EXPAND_64_CASES(i + 64, x, y) +#define EXPAND_256_CASES(i, x, y) EXPAND_128_CASES(i, x, y) EXPAND_128_CASES(i + 128, x, y) +#define EXPAND_512_CASES(i, x, y) EXPAND_256_CASES(i, x, y) EXPAND_256_CASES(i + 256, x, y) +#define EXPAND_1024_CASES(i, x, y) EXPAND_512_CASES(i, x, y) EXPAND_512_CASES(i + 512, x, y) +#define EXPAND_2048_CASES(i, x, y) EXPAND_1024_CASES(i, x, y) EXPAND_1024_CASES(i + 1024, x, y) +#define EXPAND_4096_CASES(i, x, y) EXPAND_2048_CASES(i, x, y) EXPAND_2048_CASES(i + 2048, x, y) + +// This has a *monstrous* single fan-out in the CFG, across 8000 blocks inside +// the while loop. +unsigned cfg_big_switch(int x) { + unsigned y = 0; + while (x > 0) { + switch(x) { +#define CASE(i, x, y) \ + case i: { int case_var = 3*x + i; y += case_var - 1; break; } +EXPAND_4096_CASES(0, x, y); + } + --x; + } + return y; +} diff --git a/INPUTS/cfg-long-chain1.c b/INPUTS/cfg-long-chain1.c new file mode 100644 index 000000000000..2f55b2ada205 --- /dev/null +++ b/INPUTS/cfg-long-chain1.c @@ -0,0 +1,20 @@ +#define EXPAND_2_BRANCHES(i, x, y) BRANCH(i, x, y); BRANCH(i + 1, x, y); +#define EXPAND_4_BRANCHES(i, x, y) EXPAND_2_BRANCHES(i, x, y) EXPAND_2_BRANCHES(i + 2, x, y) +#define EXPAND_8_BRANCHES(i, x, y) EXPAND_4_BRANCHES(i, x, y) EXPAND_4_BRANCHES(i + 4, x, y) +#define EXPAND_16_BRANCHES(i, x, y) EXPAND_8_BRANCHES(i, x, y) EXPAND_8_BRANCHES(i + 8, x, y) +#define EXPAND_32_BRANCHES(i, x, y) EXPAND_16_BRANCHES(i, x, y) EXPAND_16_BRANCHES(i + 16, x, y) +#define EXPAND_64_BRANCHES(i, x, y) EXPAND_32_BRANCHES(i, x, y) EXPAND_32_BRANCHES(i + 32, x, y) +#define EXPAND_128_BRANCHES(i, x, y) EXPAND_64_BRANCHES(i, x, y) EXPAND_64_BRANCHES(i + 64, x, y) +#define EXPAND_256_BRANCHES(i, x, y) EXPAND_128_BRANCHES(i, x, y) EXPAND_128_BRANCHES(i + 128, x, y) +#define EXPAND_512_BRANCHES(i, x, y) EXPAND_256_BRANCHES(i, x, y) EXPAND_256_BRANCHES(i + 256, x, y) +#define EXPAND_1024_BRANCHES(i, x, y) EXPAND_512_BRANCHES(i, x, y) EXPAND_512_BRANCHES(i + 512, x, y) +#define EXPAND_2048_BRANCHES(i, x, y) EXPAND_1024_BRANCHES(i, x, y) EXPAND_1024_BRANCHES(i + 1024, x, y) +#define EXPAND_4096_BRANCHES(i, x, y) EXPAND_2048_BRANCHES(i, x, y) EXPAND_2048_BRANCHES(i + 2048, x, y) + +unsigned cfg_long_chain_single_exit(unsigned x) { + unsigned y = 0; +#define BRANCH(i, x, y) if ((x % 13171) < i) { int var = x / 13171; y ^= var; } + EXPAND_4096_BRANCHES(1, x, y); +#undef BRANCH + return y; +} diff --git a/INPUTS/cfg-long-chain2.c b/INPUTS/cfg-long-chain2.c new file mode 100644 index 000000000000..150a084e57b9 --- /dev/null +++ b/INPUTS/cfg-long-chain2.c @@ -0,0 +1,20 @@ +#define EXPAND_2_BRANCHES(i, x, y) BRANCH(i, x, y); BRANCH(i + 1, x, y); +#define EXPAND_4_BRANCHES(i, x, y) EXPAND_2_BRANCHES(i, x, y) EXPAND_2_BRANCHES(i + 2, x, y) +#define EXPAND_8_BRANCHES(i, x, y) EXPAND_4_BRANCHES(i, x, y) EXPAND_4_BRANCHES(i + 4, x, y) +#define EXPAND_16_BRANCHES(i, x, y) EXPAND_8_BRANCHES(i, x, y) EXPAND_8_BRANCHES(i + 8, x, y) +#define EXPAND_32_BRANCHES(i, x, y) EXPAND_16_BRANCHES(i, x, y) EXPAND_16_BRANCHES(i + 16, x, y) +#define EXPAND_64_BRANCHES(i, x, y) EXPAND_32_BRANCHES(i, x, y) EXPAND_32_BRANCHES(i + 32, x, y) +#define EXPAND_128_BRANCHES(i, x, y) EXPAND_64_BRANCHES(i, x, y) EXPAND_64_BRANCHES(i + 64, x, y) +#define EXPAND_256_BRANCHES(i, x, y) EXPAND_128_BRANCHES(i, x, y) EXPAND_128_BRANCHES(i + 128, x, y) +#define EXPAND_512_BRANCHES(i, x, y) EXPAND_256_BRANCHES(i, x, y) EXPAND_256_BRANCHES(i + 256, x, y) +#define EXPAND_1024_BRANCHES(i, x, y) EXPAND_512_BRANCHES(i, x, y) EXPAND_512_BRANCHES(i + 512, x, y) +#define EXPAND_2048_BRANCHES(i, x, y) EXPAND_1024_BRANCHES(i, x, y) EXPAND_1024_BRANCHES(i + 1024, x, y) +#define EXPAND_4096_BRANCHES(i, x, y) EXPAND_2048_BRANCHES(i, x, y) EXPAND_2048_BRANCHES(i + 2048, x, y) + +unsigned cfg_long_chain_multiple_exit(unsigned x) { + unsigned y = 0; +#define BRANCH(i, x, y) if (((x % 13171) + ++y) < i) { int var = x / 13171 + y; return var; } + EXPAND_4096_BRANCHES(1, x, y); +#undef BRANCH + return 42; +} diff --git a/INPUTS/cfg-long-chain3.c b/INPUTS/cfg-long-chain3.c new file mode 100644 index 000000000000..cca4bdcf1ac9 --- /dev/null +++ b/INPUTS/cfg-long-chain3.c @@ -0,0 +1,21 @@ +#define EXPAND_2_BRANCHES(i, x, y) BRANCH(i, x, y); BRANCH(i + 1, x, y); +#define EXPAND_4_BRANCHES(i, x, y) EXPAND_2_BRANCHES(i, x, y) EXPAND_2_BRANCHES(i + 2, x, y) +#define EXPAND_8_BRANCHES(i, x, y) EXPAND_4_BRANCHES(i, x, y) EXPAND_4_BRANCHES(i + 4, x, y) +#define EXPAND_16_BRANCHES(i, x, y) EXPAND_8_BRANCHES(i, x, y) EXPAND_8_BRANCHES(i + 8, x, y) +#define EXPAND_32_BRANCHES(i, x, y) EXPAND_16_BRANCHES(i, x, y) EXPAND_16_BRANCHES(i + 16, x, y) +#define EXPAND_64_BRANCHES(i, x, y) EXPAND_32_BRANCHES(i, x, y) EXPAND_32_BRANCHES(i + 32, x, y) +#define EXPAND_128_BRANCHES(i, x, y) EXPAND_64_BRANCHES(i, x, y) EXPAND_64_BRANCHES(i + 64, x, y) +#define EXPAND_256_BRANCHES(i, x, y) EXPAND_128_BRANCHES(i, x, y) EXPAND_128_BRANCHES(i + 128, x, y) +#define EXPAND_512_BRANCHES(i, x, y) EXPAND_256_BRANCHES(i, x, y) EXPAND_256_BRANCHES(i + 256, x, y) +#define EXPAND_1024_BRANCHES(i, x, y) EXPAND_512_BRANCHES(i, x, y) EXPAND_512_BRANCHES(i + 512, x, y) +#define EXPAND_2048_BRANCHES(i, x, y) EXPAND_1024_BRANCHES(i, x, y) EXPAND_1024_BRANCHES(i + 1024, x, y) +#define EXPAND_4096_BRANCHES(i, x, y) EXPAND_2048_BRANCHES(i, x, y) EXPAND_2048_BRANCHES(i + 2048, x, y) + +unsigned cfg_long_chain_many_preds(unsigned x) { + unsigned y = 0; +#define BRANCH(i, x, y) if ((x % 13171) < i) { int var = x / 13171; y ^= var; } else + EXPAND_4096_BRANCHES(1, x, y); +#undef BRANCH + int var = x / 13171; y^= var; + return y; +} diff --git a/INPUTS/cfg-nested-switches.c b/INPUTS/cfg-nested-switches.c new file mode 100644 index 000000000000..3db10b443d21 --- /dev/null +++ b/INPUTS/cfg-nested-switches.c @@ -0,0 +1,36 @@ +#define EXPAND_2_INNER_CASES(i, x, y) INNER_CASE(i, x, y); INNER_CASE(i + 1, x, y); +#define EXPAND_4_INNER_CASES(i, x, y) EXPAND_2_INNER_CASES(i, x, y) EXPAND_2_INNER_CASES(i + 2, x, y) +#define EXPAND_8_INNER_CASES(i, x, y) EXPAND_4_INNER_CASES(i, x, y) EXPAND_4_INNER_CASES(i + 4, x, y) +#define EXPAND_16_INNER_CASES(i, x, y) EXPAND_8_INNER_CASES(i, x, y) EXPAND_8_INNER_CASES(i + 8, x, y) +#define EXPAND_32_INNER_CASES(i, x, y) EXPAND_16_INNER_CASES(i, x, y) EXPAND_16_INNER_CASES(i + 16, x, y) +#define EXPAND_64_INNER_CASES(i, x, y) EXPAND_32_INNER_CASES(i, x, y) EXPAND_32_INNER_CASES(i + 32, x, y) + +#define EXPAND_2_OUTER_CASES(i, x, y) OUTER_CASE(i, x, y); OUTER_CASE(i + 1, x, y); +#define EXPAND_4_OUTER_CASES(i, x, y) EXPAND_2_OUTER_CASES(i, x, y) EXPAND_2_OUTER_CASES(i + 2, x, y) +#define EXPAND_8_OUTER_CASES(i, x, y) EXPAND_4_OUTER_CASES(i, x, y) EXPAND_4_OUTER_CASES(i + 4, x, y) +#define EXPAND_16_OUTER_CASES(i, x, y) EXPAND_8_OUTER_CASES(i, x, y) EXPAND_8_OUTER_CASES(i + 8, x, y) +#define EXPAND_32_OUTER_CASES(i, x, y) EXPAND_16_OUTER_CASES(i, x, y) EXPAND_16_OUTER_CASES(i + 16, x, y) +#define EXPAND_64_OUTER_CASES(i, x, y) EXPAND_32_OUTER_CASES(i, x, y) EXPAND_32_OUTER_CASES(i + 32, x, y) + +// Rather than a single monstrous fan-out, this fans out in smaller increments, +// but to a similar size. +unsigned cfg_nested_switch(int x) { + unsigned y = 0; + while (x > 0) { + switch (x) { +#define INNER_CASE(i, x, y) \ + case i: { int case_var = 3*x + i; y += case_var - 1; break; } +#define OUTER_CASE(i, x, y) \ + case i: { \ + int case_var = y >> 8; \ + switch (case_var) { \ + EXPAND_64_INNER_CASES(0, x, y); \ + } \ + break; \ + } +EXPAND_64_OUTER_CASES(0, x, y); + } + --x; + } + return y; +} diff --git a/LICENSE.TXT b/LICENSE.TXT index a378a5f7fd51..91895eba029d 100644 --- a/LICENSE.TXT +++ b/LICENSE.TXT @@ -4,7 +4,7 @@ LLVM Release License University of Illinois/NCSA Open Source License -Copyright (c) 2007-2010 University of Illinois at Urbana-Champaign. +Copyright (c) 2007-2011 University of Illinois at Urbana-Champaign. All rights reserved. Developed by: diff --git a/bindings/python/clang/cindex.py b/bindings/python/clang/cindex.py index 08ad80234e09..8cadcaa7ad06 100644 --- a/bindings/python/clang/cindex.py +++ b/bindings/python/clang/cindex.py @@ -321,6 +321,10 @@ class CursorKind(object): """Test if this is a statement kind.""" return CursorKind_is_stmt(self) + def is_attribute(self): + """Test if this is an attribute kind.""" + return CursorKind_is_attribute(self) + def is_invalid(self): """Test if this is an invalid kind.""" return CursorKind_is_inv(self) @@ -978,8 +982,9 @@ class TranslationUnit(ClangObject): headers. """ def visitor(fobj, lptr, depth, includes): - loc = lptr.contents - includes.append(FileInclusion(loc.file, File(fobj), loc, depth)) + if depth > 0: + loc = lptr.contents + includes.append(FileInclusion(loc.file, File(fobj), loc, depth)) # Automatically adapt CIndex/ctype pointers to python objects includes = [] @@ -1074,7 +1079,7 @@ class File(ClangObject): @property def name(self): """Return the complete file and path name of the file.""" - return File_name(self) + return _CXString_getCString(File_name(self)) @property def time(self): @@ -1147,6 +1152,10 @@ CursorKind_is_stmt = lib.clang_isStatement CursorKind_is_stmt.argtypes = [CursorKind] CursorKind_is_stmt.restype = bool +CursorKind_is_attribute = lib.clang_isAttribute +CursorKind_is_attribute.argtypes = [CursorKind] +CursorKind_is_attribute.restype = bool + CursorKind_is_inv = lib.clang_isInvalid CursorKind_is_inv.argtypes = [CursorKind] CursorKind_is_inv.restype = bool @@ -1183,6 +1192,11 @@ Cursor_spelling.argtypes = [Cursor] Cursor_spelling.restype = _CXString Cursor_spelling.errcheck = _CXString.from_result +Cursor_displayname = lib.clang_getCursorDisplayName +Cursor_displayname.argtypes = [Cursor] +Cursor_displayname.restype = _CXString +Cursor_displayname.errcheck = _CXString.from_result + Cursor_loc = lib.clang_getCursorLocation Cursor_loc.argtypes = [Cursor] Cursor_loc.restype = SourceLocation @@ -1253,7 +1267,7 @@ TranslationUnit_includes.argtypes = [TranslationUnit, # File Functions File_name = lib.clang_getFileName File_name.argtypes = [File] -File_name.restype = c_char_p +File_name.restype = _CXString File_time = lib.clang_getFileTime File_time.argtypes = [File] diff --git a/bindings/python/tests/cindex/test_cursor_kind.py b/bindings/python/tests/cindex/test_cursor_kind.py index bdfa31855835..d7a1cfad8f94 100644 --- a/bindings/python/tests/cindex/test_cursor_kind.py +++ b/bindings/python/tests/cindex/test_cursor_kind.py @@ -18,10 +18,14 @@ def test_kind_groups(): for k in CursorKind.get_all_kinds(): group = [n for n in ('is_declaration', 'is_reference', 'is_expression', - 'is_statement', 'is_invalid') + 'is_statement', 'is_invalid', 'is_attribute') if getattr(k, n)()] - if k == CursorKind.TRANSLATION_UNIT: + if k in ( CursorKind.TRANSLATION_UNIT, + CursorKind.MACRO_DEFINITION, + CursorKind.MACRO_INSTANTIATION, + CursorKind.INCLUSION_DIRECTIVE, + CursorKind.PREPROCESSING_DIRECTIVE): assert len(group) == 0 else: assert len(group) == 1 diff --git a/bindings/python/tests/cindex/test_translation_unit.py b/bindings/python/tests/cindex/test_translation_unit.py index f130db6aeb06..2e65d9518da0 100644 --- a/bindings/python/tests/cindex/test_translation_unit.py +++ b/bindings/python/tests/cindex/test_translation_unit.py @@ -58,24 +58,27 @@ def test_unsaved_files_2(): spellings = [c.spelling for c in tu.cursor.get_children()] assert spellings[-1] == 'x' +def normpaths_equal(path1, path2): + """ Compares two paths for equality after normalizing them with + os.path.normpath + """ + return os.path.normpath(path1) == os.path.normpath(path2) def test_includes(): def eq(expected, actual): if not actual.is_input_file: - return expected[0] == actual.source.name and \ - expected[1] == actual.include.name + return normpaths_equal(expected[0], actual.source.name) and \ + normpaths_equal(expected[1], actual.include.name) else: - return expected[1] == actual.include.name + return normpaths_equal(expected[1], actual.include.name) src = os.path.join(kInputsDir, 'include.cpp') h1 = os.path.join(kInputsDir, "header1.h") h2 = os.path.join(kInputsDir, "header2.h") h3 = os.path.join(kInputsDir, "header3.h") - inc = [(None, src), (src, h1), (h1, h3), (src, h2), (h2, h3)] + inc = [(src, h1), (h1, h3), (src, h2), (h2, h3)] index = Index.create() tu = index.parse(src) for i in zip(inc, tu.get_includes()): assert eq(i[0], i[1]) - - diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj index 1612d122f516..832e07ab44f2 100644 --- a/clang.xcodeproj/project.pbxproj +++ b/clang.xcodeproj/project.pbxproj @@ -373,6 +373,12 @@ 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 = ""; }; + BB20603B131EDDBF003C3343 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; + BB20603C131EDDBF003C3343 /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; }; + BB206041131EDDDA003C3343 /* ARRMT.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARRMT.h; sourceTree = ""; }; + BB206043131EDE03003C3343 /* arrmt-test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "arrmt-test.cpp"; sourceTree = ""; }; + BB206044131EDE03003C3343 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; + BB206045131EDE03003C3343 /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; }; BB5C372812A5057500259F53 /* DumpXML.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DumpXML.cpp; path = /Volumes/Data/llvm/tools/clang/lib/AST/DumpXML.cpp; sourceTree = ""; }; BBA5AB141309C2FA000B38F1 /* AdjustedReturnValueChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AdjustedReturnValueChecker.cpp; sourceTree = ""; }; BBA5AB151309C2FA000B38F1 /* AnalyzerStatsChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AnalyzerStatsChecker.cpp; sourceTree = ""; }; @@ -561,7 +567,6 @@ BF9FEE321225E898003A8B71 /* ItaniumCXXABI.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ItaniumCXXABI.cpp; path = lib/CodeGen/ItaniumCXXABI.cpp; sourceTree = ""; }; BF9FEE341225E8B1003A8B71 /* MicrosoftCXXABI.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MicrosoftCXXABI.cpp; path = lib/CodeGen/MicrosoftCXXABI.cpp; sourceTree = ""; }; BF9FEE361225E8CF003A8B71 /* README.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = README.txt; path = lib/CodeGen/README.txt; sourceTree = ""; }; - BF9FEE371225E925003A8B71 /* BoostConAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BoostConAction.cpp; path = lib/Frontend/BoostConAction.cpp; sourceTree = ""; }; BF9FEE451225EA24003A8B71 /* DelayedDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DelayedDiagnostic.h; path = clang/Sema/DelayedDiagnostic.h; sourceTree = ""; }; BF9FEE511226FE9F003A8B71 /* ParseAST.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ParseAST.cpp; path = lib/Parse/ParseAST.cpp; sourceTree = ""; }; BF9FEE531226FEC1003A8B71 /* RAIIObjectsForParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RAIIObjectsForParser.h; path = lib/Parse/RAIIObjectsForParser.h; sourceTree = ""; }; @@ -777,6 +782,7 @@ 08FB7795FE84155DC02AAC07 /* Libraries */ = { isa = PBXGroup; children = ( + BB20603A131EDDBF003C3343 /* ARRMigrate */, BBA5AB121309C2FA000B38F1 /* StaticAnalyzer */, 57EB5660121B034300ECA335 /* Serialization */, BFE2F67911DA95590007EDC0 /* Rewrite */, @@ -899,7 +905,6 @@ 352246E00F5C6BC000D0D279 /* Frontend */ = { isa = PBXGroup; children = ( - BF9FEE371225E925003A8B71 /* BoostConAction.cpp */, 1AFDD8701161085D00AE030A /* ASTMerge.cpp */, 9012911C1048068D0083456D /* ASTUnit.cpp */, 1A2A54A50FD1DD1C00F4CE45 /* ASTConsumers.cpp */, @@ -1105,6 +1110,38 @@ name = "index-test"; sourceTree = ""; }; + BB20603A131EDDBF003C3343 /* ARRMigrate */ = { + isa = PBXGroup; + children = ( + BB20603B131EDDBF003C3343 /* CMakeLists.txt */, + BB20603C131EDDBF003C3343 /* Makefile */, + BDDF60E91337BF40009F1764 /* Transforms.cpp */, + ); + name = ARRMigrate; + path = lib/ARRMigrate; + sourceTree = ""; + }; + BB206040131EDDDA003C3343 /* ARRMigrate */ = { + isa = PBXGroup; + children = ( + BB206041131EDDDA003C3343 /* ARRMT.h */, + ); + name = ARRMigrate; + path = clang/ARRMigrate; + sourceTree = ""; + }; + BB206042131EDE03003C3343 /* arrmt-test */ = { + isa = PBXGroup; + children = ( + BD8A47E7133D32660066FE40 /* ARRMT.cpp */, + BB206043131EDE03003C3343 /* arrmt-test.cpp */, + BB206044131EDE03003C3343 /* CMakeLists.txt */, + BB206045131EDE03003C3343 /* Makefile */, + ); + name = "arrmt-test"; + path = "tools/arrmt-test"; + sourceTree = ""; + }; BBA5AB121309C2FA000B38F1 /* StaticAnalyzer */ = { isa = PBXGroup; children = ( @@ -1575,6 +1612,7 @@ DED7D72E0A524295003AD0FB /* include */ = { isa = PBXGroup; children = ( + BB206040131EDDDA003C3343 /* ARRMigrate */, DED7D7300A524295003AD0FB /* Basic */, DED7D7390A524295003AD0FB /* Lex */, DE1F21F20A7D84E800FBF588 /* Parse */, @@ -1724,6 +1762,7 @@ DEDFE61F0F7B3AE10035BD10 /* Tools */ = { isa = PBXGroup; children = ( + BB206042131EDE03003C3343 /* arrmt-test */, 90F9EFA8104ABDC400D09A15 /* c-index-test */, 9012911E104812DA0083456D /* CIndex */, 90FD6DB4103D9763005F5B73 /* index-test */, diff --git a/docs/AutomaticReferenceCounting.html b/docs/AutomaticReferenceCounting.html new file mode 100644 index 000000000000..5090fa2b7952 --- /dev/null +++ b/docs/AutomaticReferenceCounting.html @@ -0,0 +1,1857 @@ + + +Objective-C Automatic Reference Counting (ARC) + + + + + + + + + + +
+

Automatic Reference Counting

+ +
+
+ +
+

About this document

+ +
+

Purpose

+ +

The first and primary purpose of this document is to serve as a +complete technical specification of Automatic Reference Counting. +Given a core Objective-C compiler and runtime, it should be possible +to write a compiler and runtime which implements these new +semantics.

+ +

The secondary purpose is to act as a rationale for why ARC was +designed in this way. This should remain tightly focused on the +technical design and should not stray into marketing speculation.

+ +
+ +
+

Background

+ +

This document assumes a basic familiarity with C.

+ +

Blocks are a C language extension for +creating anonymous functions. Users interact with and transfer block +objects using block pointers, which are +represented like a normal pointer. A block may capture values from +local variables; when this occurs, memory must be dynamically +allocated. The initial allocation is done on the stack, but the +runtime provides a Block_copy function which, given a block +pointer, either copies the underlying block object to the heap, +setting its reference count to 1 and returning the new block pointer, +or (if the block object is already on the heap) increases its +reference count by 1. The paired function is Block_release, +which decreases the reference count by 1 and destroys the object if +the count reaches zero and is on the heap.

+ +

Objective-C is a set of language extensions, significant enough to +be considered a different language. It is a strict superset of C. +The extensions can also be imposed on C++, producing a language called +Objective-C++. The primary feature is a single-inheritance object +system; we briefly describe the modern dialect.

+ +

Objective-C defines a new type kind, collectively called +the object pointer types. This kind has two +notable builtin members, id and Class; id +is the final supertype of all object pointers. The validity of +conversions between object pointer types is not checked at runtime. +Users may define classes; each class is a +type, and the pointer to that type is an object pointer type. A class +may have a superclass; its pointer type is a subtype of its +superclass's pointer type. A class has a set +of ivars, fields which appear on all +instances of that class. For every class T there's an +associated metaclass; it has no fields, its superclass is the +metaclass of T's superclass, and its metaclass is a global +class. Every class has a global object whose class is the +class's metaclass; metaclasses have no associated type, so pointers to +this object have type Class.

+ +

A class declaration (@interface) declares a set +of methods. A method has a return type, a +list of argument types, and a selector: a +name like foo:bar:baz:, where the number of colons +corresponds to the number of formal arguments. A method may be an +instance method, in which case it can be invoked on objects of the +class, or a class method, in which case it can be invoked on objects +of the metaclass. A method may be invoked by providing an object +(called the receiver) and a list of formal +arguments interspersed with the selector, like so:

+ +
[receiver foo: fooArg bar: barArg baz: bazArg]
+ +

This looks in the dynamic class of the receiver for a method with +this name, then in that class's superclass, etc., until it finds +something it can execute. The receiver expression may also be +the name of a class, in which case the actual receiver is the class +object for that class, or (within method definitions) it may +be super, in which case the lookup algorithm starts with the +static superclass instead of the dynamic class. The actual methods +dynamically found in a class are not those declared in the +@interface, but those defined in a separate +@implementation declaration; however, when compiling a +call, typechecking is done based on the methods declared in the +@interface.

+ +

Method declarations may also be grouped into +protocols, which are not inherently +associated with any class, but which classes may claim to follow. +Object pointer types may be qualified with additional protocols that +the object is known to support.

+ +

Class extensions are collections of ivars +and methods, designed to allow a class's @interface to be +split across multiple files; however, there is still a primary +implementation file which must see the @interfaces of all +class extensions. +Categories allow methods (but not ivars) to +be declared post hoc on an arbitrary class; the methods in the +category's @implementation will be dynamically added to that +class's method tables which the category is loaded at runtime, +replacing those methods in case of a collision.

+ +

In the standard environment, objects are allocated on the heap, and +their lifetime is manually managed using a reference count. This is +done using two instance methods which all classes are expected to +implement: retain increases the object's reference count by +1, whereas release decreases it by 1 and calls the instance +method dealloc if the count reaches 0. To simplify certain +operations, there is also an autorelease +pool, a thread-local list of objects to call release +on later; an object can be added to this pool by +calling autorelease on it.

+ +

Block pointers may be converted to type id; block objects +are laid out in a way that makes them compatible with Objective-C +objects. There is a builtin class that all block objects are +considered to be objects of; this class implements retain by +adjusting the reference count, not by calling Block_copy.

+ +
+ +
+ +
+

General

+ +

Automatic Reference Counting implements automatic memory management +for Objective-C objects and blocks, freeing the programmer from the +need explicitly insert retains and releases. It does not provide a +cycle collector; users must explicitly manage lifetime instead.

+ +

ARC may be explicitly enabled with the compiler +flag -fobjc-arc. It may also be explicitly disabled with the +compiler flag -fno-objc-arc. The last of these two flags +appearing on the compile line wins.

+ +

If ARC is enabled, __has_feature(objc_arc) will expand to +1 in the preprocessor. For more information about __has_feature, +see the language +extensions document.

+ +
+ +
+

Retainable object pointers

+ +

This section describes retainable object pointers, their basic +operations, and the restrictions imposed on their use under ARC. Note +in particular that it covers the rules for pointer values +(patterns of bits indicating the location of a pointed-to object), not +pointer +objects (locations in memory which store pointer values). +The rules for objects are covered in the next section.

+ +

A retainable object pointer +(or retainable pointer) is a value of +a retainable object pointer type +(retainable type). There are three kinds of retainable object +pointer types:

+
    +
  • block pointers (formed by applying the caret (^) +declarator sigil to a function type)
  • +
  • Objective-C object pointers (id, Class, NSFoo*, etc.)
  • +
  • typedefs marked with __attribute__((NSObject))
  • +
+ +

Other pointer types, such as int* and CFStringRef, +are not subject to ARC's semantics and restrictions.

+ +
+ +

Rationale: We are not at liberty to require +all code to be recompiled with ARC; therefore, ARC must interoperate +with Objective-C code which manages retains and releases manually. In +general, there are three requirements in order for a +compiler-supported reference-count system to provide reliable +interoperation:

+ +
    +
  • The type system must reliably identify which objects are to be +managed. An int* might be a pointer to a malloc'ed +array, or it might be a interior pointer to such an array, or it might +point to some field or local variable. In contrast, values of the +retainable object pointer types are never interior.
  • +
  • The type system must reliably indicate how to +manage objects of a type. This usually means that the type must imply +a procedure for incrementing and decrementing retain counts. +Supporting single-ownership objects requires a lot more explicit +mediation in the language.
  • +
  • There must be reliable conventions for whether and +when ownership is passed between caller and callee, for both +arguments and return values. Objective-C methods follow such a +convention very reliably, at least for system libraries on Mac OS X, +and functions always pass objects at +0. The C-based APIs for Core +Foundation objects, on the other hand, have much more varied transfer +semantics.
  • +
+
+ +

The use of __attribute__((NSObject)) typedefs is not +recommended. If it's absolutely necessary to use this attribute, be +very explicit about using the typedef, and do not assume that it will +be preserved by language features like __typeof and C++ +template argument substitution.

+ +

Rationale: any compiler operation which +incidentally strips type sugar from a type will yield a type +without the attribute, which may result in unexpected +behavior.

+ +
+

Retain count semantics

+ +

A retainable object pointer is either a null +pointer or a pointer to a valid object. Furthermore, if it has +block pointer type and is not null then it must actually be a +pointer to a block object, and if it has Class type (possibly +protocol-qualified) then it must actually be a pointer to a class +object. Otherwise ARC does not enforce the Objective-C type system as +long as the implementing methods follow the signature of the static +type. It is undefined behavior if ARC is exposed to an invalid +pointer.

+ +

For ARC's purposes, a valid object is one with well-behaved +retaining operations. Specifically, the object must be laid out such +that the Objective-C message send machinery can successfully send it +the following messages:

+ +
    +
  • retain, taking no arguments and returning a pointer to +the object.
  • +
  • release, taking no arguments and returning void.
  • +
  • autorelease, taking no arguments and returning a pointer +to the object.
  • +
+ +

The behavior of these methods is constrained in the following ways. +The term high-level semantics is an +intentionally vague term; the intent is that programmers must +implement these methods in a way such that the compiler, modifying +code in ways it deems safe according to these constraints, will not +violate their requirements. For example, if the user puts logging +statements in retain, they should not be surprised if those +statements are executed more or less often depending on optimization +settings. These constraints are not exhaustive of the optimization +opportunities: values held in local variables are subject to +additional restrictions, described later in this document.

+ +

It is undefined behavior if a computation history featuring a send +of retain followed by a send of release to the same +object, with no intervening release on that object, is not +equivalent under the high-level semantics to a computation +history in which these sends are removed. Note that this implies that +these methods may not raise exceptions.

+ +

It is undefined behavior if a computation history features any use +whatsoever of an object following the completion of a send +of release that is not preceded by a send of retain +to the same object.

+ +

The behavior of autorelease must be equivalent to sending +release when one of the autorelease pools currently in scope +is popped. It may not throw an exception.

+ +

When the semantics call for performing one of these operations on a +retainable object pointer, if that pointer is null then the +effect is a no-op.

+ +

All of the semantics described in this document are subject to +additional optimization rules which permit +the removal or optimization of operations based on local knowledge of +data flow. The semantics describe the high-level behaviors that the +compiler implements, not an exact sequence of operations that a +program will be compiled into.

+ +
+ +
+

Retainable object pointers as operands and arguments

+ +

In general, ARC does not perform retain or release operations when +simply using a retainable object pointer as an operand within an +expression. This includes:

+
    +
  • loading a retainable pointer from an object with non-weak +ownership,
  • +
  • passing a retainable pointer as an argument to a function or +method, and
  • +
  • receiving a retainable pointer as the result of a function or +method call.
  • +
+ +

Rationale: while this might seem +uncontroversial, it is actually unsafe when multiple expressions are +evaluated in parallel, as with binary operators and calls, +because (for example) one expression might load from an object while +another writes to it. However, C and C++ already call this undefined +behavior because the evaluations are unsequenced, and ARC simply +exploits that here to avoid needing to retain arguments across a large +number of calls.

+ +

The remainder of this section describes exceptions to these rules, +how those exceptions are detected, and what those exceptions imply +semantically.

+ +
+

Consumed parameters

+ +

A function or method parameter of retainable object pointer type +may be marked as consumed, signifying that +the callee expects to take ownership of a +1 retain count. This is +done by adding the ns_consumed attribute to the parameter +declaration, like so:

+ +
void foo(__attribute((ns_consumed)) id x);
+- (void) foo: (id) __attribute((ns_consumed)) x;
+ +

This attribute is part of the type of the function or method, not +the type of the parameter. It controls only how the argument is +passed and received.

+ +

When passing such an argument, ARC retains the argument prior to +making the call.

+ +

When receiving such an argument, ARC releases the argument at the +end of the function, subject to the usual optimizations for local +values.

+ +

Rationale: this formalizes direct transfers +of ownership from a caller to a callee. The most common scenario here +is passing the self parameter to init, but it is +useful to generalize. Typically, local optimization will remove any +extra retains and releases: on the caller side the retain will be +merged with a +1 source, and on the callee side the release will be +rolled into the initialization of the parameter.

+ +

The implicit self parameter of a method may be marked as +consumed by adding __attribute__((ns_consumes_self)) to the +method declaration. Methods in the init +family are treated as if they were implicitly +marked with this attribute.

+ +

It is undefined behavior if an Objective-C message send to a method +with ns_consumed parameters (other than self) is made with a +null receiver. It is undefined behavior if the method to which an +Objective-C message send statically resolves to has a different set +of ns_consumed parameters than the method it dynamically +resolves to. It is undefined behavior if a block or function call is +made through a static type with a different set of ns_consumed +parameters than the implementation of the called block or function.

+ +

Rationale: consumed parameters with null +receiver are a guaranteed leak. Mismatches with consumed parameters +will cause over-retains or over-releases, depending on the direction. +The rule about function calls is really just an application of the +existing C/C++ rule about calling functions through an incompatible +function type, but it's useful to state it explicitly.

+ +
+ +
+

Retained return values

+ +

A function or method which returns a retainable object pointer type +may be marked as returning a retained value, signifying that the +caller expects to take ownership of a +1 retain count. This is done +by adding the ns_returns_retained attribute to the function or +method declaration, like so:

+ +
id foo(void) __attribute((ns_returns_retained));
+- (id) foo __attribute((ns_returns_retained));
+ +

This attribute is part of the type of the function or method.

+ +

When returning from such a function or method, ARC retains the +value at the point of evaluation of the return statement, before +leaving all local scopes.

+ +

When receiving a return result from such a function or method, ARC +releases the value at the end of the full-expression it is contained +within, subject to the usual optimizations for local values.

+ +

Rationale: this formalizes direct transfers of +ownership from a callee to a caller. The most common scenario this +models is the retained return from init, alloc, +new, and copy methods, but there are other cases in +the frameworks. After optimization there are typically no extra +retains and releases required.

+ +

Methods in +the alloc, copy, init, mutableCopy, +and new families are implicitly marked +__attribute__((ns_returns_retained)). This may be suppressed +by explicitly marking the +method __attribute__((ns_returns_not_retained)).

+
+ +

It is undefined behavior if the method to which an Objective-C +message send statically resolves has different retain semantics on its +result from the method it dynamically resolves to. It is undefined +behavior if a block or function call is made through a static type +with different retain semantics on its result from the implementation +of the called block or function.

+ +

Rationale: Mismatches with returned results +will cause over-retains or over-releases, depending on the direction. +Again, the rule about function calls is really just an application of +the existing C/C++ rule about calling functions through an +incompatible function type.

+ + +
+

Unretained return values

+ +

A method or function which returns a retainable object type but +does not return a retained value must ensure that the object is +still valid across the return boundary.

+ +

When returning from such a function or method, ARC retains the +value at the point of evaluation of the return statement, then leaves +all local scopes, and then balances out the retain while ensuring that +the value lives across the call boundary. In the worst case, this may +involve an autorelease, but callers must not assume that the +value is actually in the autorelease pool.

+ +

ARC performs no extra mandatory work on the caller side, although +it may elect to do something to shorten the lifetime of the returned +value.

+ +

Rationale: it is common in non-ARC code to not +return an autoreleased value; therefore the convention does not force +either path. It is convenient to not be required to do unnecessary +retains and autoreleases; this permits optimizations such as eliding +retain/autoreleases when it can be shown that the original pointer +will still be valid at the point of return.

+ +

A method or function may be marked +with __attribute__((ns_returns_autoreleased)) to indicate +that it returns a pointer which is guaranteed to be valid at least as +long as the innermost autorelease pool. There are no additional +semantics enforced in the definition of such a method; it merely +enables optimizations in callers.

+
+ +
+

Bridged casts

+ +

A bridged cast is a C-style cast +annotated with one of three keywords:

+ +
    +
  • (__bridge T) op casts the operand to the destination +type T. If T is a retainable object pointer type, +then op must have a non-retainable pointer type. +If T is a non-retainable pointer type, then op must +have a retainable object pointer type. Otherwise the cast is +ill-formed. There is no transfer of ownership, and ARC inserts +no retain operations.
  • + +
  • (__bridge_retained T) op casts the operand, which must +have retainable object pointer type, to the destination type, which +must be a non-retainable pointer type. ARC retains the value, subject +to the usual optimizations on local values, and the recipient is +responsible for balancing that +1.
  • + +
  • (__bridge_transfer T) op casts the operand, which must +have non-retainable pointer type, to the destination type, which must +be a retainable object pointer type. ARC will release the value at +the end of the enclosing full-expression, subject to the usual +optimizations on local values.
  • +
+ +

These casts are required in order to transfer objects in and out of +ARC control; see the rationale in the section +on conversion of retainable +object pointers.

+ +

Using a __bridge_retained or __bridge_transfer +cast purely to convince ARC to emit an unbalanced retain or release, +respectively, is poor form.

+ +
+ +
+ +
+

Restrictions

+ +
+

Conversion of retainable object pointers

+ +

In general, a program which attempts to implicitly or explicitly +convert a value of retainable object pointer type to any +non-retainable type, or vice-versa, is ill-formed. For example, an +Objective-C object pointer shall not be converted to void*. +As an exception, cast to intptr_t is allowed becuase such +casts are not transferring ownership. The bridged +casts may be used to perform these conversions where +necessary.

+ +

Rationale: we cannot ensure the correct +management of the lifetime of objects if they may be freely passed +around as unmanaged types. The bridged casts are provided so that the +programmer may explicitly describe whether the cast transfers control +into or out of ARC.

+
+ +

An unbridged cast to a retainable object pointer type of the return +value of a Objective-C message send which yields a non-retainable +pointer is treated as a __bridge_transfer cast +if:

+ +
    +
  • the method has the cf_returns_retained attribute, or if +not that,
  • +
  • the method does not have the cf_returns_not_retained +attribute and
  • +
  • the method's selector family would imply +the ns_returns_retained attribute on a method which returned +a retainable object pointer type.
  • +
+ +

Otherwise the cast is treated as a __bridge cast.

+ +
+ +
+ +
+

Ownership qualification

+ +

This section describes the behavior of objects of +retainable object pointer type; that is, locations in memory which +store retainable object pointers.

+ +

A type is a retainable object owner type +if it is a retainable object pointer type or an array type whose +element type is a retainable object owner type.

+ +

An ownership qualifier is a type +qualifier which applies only to retainable object owner types. An array type is +ownership-qualified according to its element type, and adding an ownership +qualifier to an array type so qualifies its element type.

+ +

A program is ill-formed if it attempts to apply an ownership qualifier +to a type which is already ownership-qualified, even if it is the same +qualifier. There is a single exception to this rule: an ownership qualifier +may be applied to a substituted template type parameter, which overrides the +ownership qualifier provided by the template argument.

+ +

Except as described under +the inference rules, a program is +ill-formed if it attempts to form a pointer or reference type to a +retainable object owner type which lacks an ownership qualifier.

+ +

Rationale: these rules, together with the +inference rules, ensure that all objects and lvalues of retainable +object pointer type have an ownership qualifier. The ability to override an ownership qualifier during template substitution is required to counteract the inference of __strong for template type arguments.

+ +

There are four ownership qualifiers:

+ +
    +
  • __autoreleasing
  • +
  • __strong
  • +
  • __unsafe_unretained
  • +
  • __weak
  • +
+ +

A type is nontrivially ownership-qualified +if it is qualified with __autoreleasing, __strong, or +__weak.

+ +
+

Spelling

+ +

The names of the ownership qualifiers are reserved for the +implementation. A program may not assume that they are or are not +implemented with macros, or what those macros expand to.

+ +

An ownership qualifier may be written anywhere that any other type +qualifier may be written.

+ +

If an ownership qualifier appears in +the declaration-specifiers, the following rules apply:

+ +
    +
  • if the type specifier is a retainable object owner type, the +qualifier applies to that type;
  • +
  • if the outermost non-array part of the declarator is a pointer or +block pointer, the qualifier applies to that type;
  • +
  • otherwise the program is ill-formed.
  • +
+ +

If an ownership qualifier appears on the declarator name, or on the +declared object, it is applied to outermost pointer or block-pointer +type.

+ +

If an ownership qualifier appears anywhere else in a declarator, it +applies to the type there.

+ +
+

Property declarations

+ +

A property of retainable object pointer type may have ownership. +If the property's type is ownership-qualified, then the property has +that ownership. If the property has one of the following modifiers, +then the property has the corresponding ownership. A property is +ill-formed if it has conflicting sources of ownership, or if it has +redundant ownership modifiers, or if it has __autoreleasing +ownership.

+ +
    +
  • assign implies __unsafe_unretained ownership.
  • +
  • copy implies __strong ownership, as well as the + usual behavior of copy semantics on the setter.
  • +
  • retain implies __strong ownership.
  • +
  • strong implies __strong ownership.
  • +
  • unsafe_unretained implies __unsafe_unretained + ownership.
  • +
  • weak implies __weak ownership.
  • +
+ +

With the exception of weak, these modifiers are available +in non-ARC modes.

+ +

A property's specified ownership is preserved in its metadata, but +otherwise the meaning is purely conventional unless the property is +synthesized. If a property is synthesized, then the +associated instance variable is the +instance variable which is named, possibly implicitly, by the +@synthesize declaration. If the associated instance variable +already exists, then its ownership qualification must equal the +ownership of the property; otherwise, the instance variable is created +with that ownership qualification.

+ +
+ +
+ +
+

Semantics

+ +

There are five managed operations which +may be performed on an object of retainable object pointer type. Each +qualifier specifies different semantics for each of these operations. +It is still undefined behavior to access an object outside of its +lifetime.

+ +

A load or store with primitive semantics has the same +semantics as the respective operation would have on an void* +lvalue with the same alignment and non-ownership qualification.

+ +

Reading occurs when performing a +lvalue-to-rvalue conversion on an object lvalue. + +

    +
  • For __weak objects, the current pointee is retained and +then released at the end of the current full-expression. This must +execute atomically with respect to assignments and to the final +release of the pointee.
  • +
  • For all other objects, the lvalue is loaded with primitive +semantics.
  • +
+

+ +

Assignment occurs when evaluating +an assignment operator. The semantics vary based on the qualification: +

    +
  • For __strong objects, the new pointee is first retained; +second, the lvalue is loaded with primitive semantics; third, the new +pointee is stored into the lvalue with primitive semantics; and +finally, the old pointee is released. This is not performed +atomically; external synchronization must be used to make this safe in +the face of concurrent loads and stores.
  • +
  • For __weak objects, the lvalue is updated to point to the +new pointee, unless that object is currently undergoing deallocation, +in which case it the lvalue is updated to a null pointer. This must +execute atomically with respect to other assignments to the object, to +reads from the object, and to the final release of the new pointed-to +value.
  • +
  • For __unsafe_unretained objects, the new pointee is +stored into the lvalue using primitive semantics.
  • +
  • For __autoreleasing objects, the new pointee is retained, +autoreleased, and stored into the lvalue using primitive semantics.
  • +
+

+ +

Initialization occurs when an object's +lifetime begins, which depends on its storage duration. +Initialization proceeds in two stages: +

    +
  1. First, a null pointer is stored into the lvalue using primitive +semantics. This step is skipped if the object +is __unsafe_unretained.
  2. +
  3. Second, if the object has an initializer, that expression is +evaluated and then assigned into the object using the usual assignment +semantics.
  4. +
+

+ +

Destruction occurs when an object's +lifetime ends. In all cases it is semantically equivalent to +assigning a null pointer to the object, with the proviso that of +course the object cannot be legally read after the object's lifetime +ends.

+ +

Moving occurs in specific situations +where an lvalue is moved from, meaning that its current pointee +will be used but the object may be left in a different (but still +valid) state. This arises with __block variables and rvalue +references in C++. For __strong lvalues, moving is equivalent +to loading the lvalue with primitive semantics, writing a null pointer +to it with primitive semantics, and then releasing the result of the +load at the end of the current full-expression. For all other +lvalues, moving is equivalent to reading the object.

+ +
+ +
+

Restrictions

+ +
+

Weak-unavailable types

+ +

It is explicitly permitted for Objective-C classes to not +support __weak references. It is undefined behavior to +perform an operation with weak assignment semantics with a pointer to +an Objective-C object whose class does not support __weak +references.

+ +

Rationale: historically, it has been +possible for a class to provide its own reference-count implementation +by overriding retain, release, etc. However, weak +references to an object require coordination with its class's +reference-count implementation because, among other things, weak loads +and stores must be atomic with respect to the final release. +Therefore, existing custom reference-count implementations will +generally not support weak references without additional effort. This +is unavoidable without breaking binary compatibility.

+ +

A class may indicate that it does not support weak references by +providing the objc_arc_weak_unavailable attribute on the +class's interface declaration. A retainable object pointer type +is weak-unavailable if is a pointer to an +(optionally protocol-qualified) Objective-C class T +where T or one of its superclasses has +the objc_arc_weak_unavailable attribute. A program is +ill-formed if it applies the __weak ownership qualifier to a +weak-unavailable type or if the value operand of a weak assignment +operation has a weak-unavailable type.

+
+ +
+

Storage duration of __autoreleasing objects

+ +

A program is ill-formed if it declares an __autoreleasing +object of non-automatic storage duration.

+ +

Rationale: autorelease pools are tied to the +current thread and scope by their nature. While it is possible to +have temporary objects whose instance variables are filled with +autoreleased objects, there is no way that ARC can provide any sort of +safety guarantee there.

+ +

It is undefined behavior if a non-null pointer is assigned to +an __autoreleasing object while an autorelease pool is in +scope and then that object is read after the autorelease pool's scope +is left.

+ +
+ +
+

Conversion of pointers to ownership-qualified types

+ +

A program is ill-formed if an expression of type T* is +converted, explicitly or implicitly, to the type U*, +where T and U have different ownership +qualification, unless: +

    +
  • T is qualified with __strong, + __autoreleasing, or __unsafe_unretained, and + U is qualified with both const and + __unsafe_unretained; or
  • +
  • either T or U is cv void, where +cv is an optional sequence of non-ownership qualifiers; or
  • +
  • the conversion is requested with a reinterpret_cast in + Objective-C++; or
  • +
  • the conversion is a +well-formed pass-by-writeback.
  • +
+

+ +

The analogous rule applies to T& and U& in +Objective-C++.

+ +

Rationale: these rules provide a reasonable +level of type-safety for indirect pointers, as long as the underlying +memory is not deallocated. The conversion to const +__unsafe_unretained is permitted because the semantics of reads +are equivalent across all these ownership semantics, and that's a very +useful and common pattern. The interconversion with void* is +useful for allocating memory or otherwise escaping the type system, +but use it carefully. reinterpret_cast is considered to be +an obvious enough sign of taking responsibility for any +problems.

+ +

It is undefined behavior to access an ownership-qualified object +through an lvalue of a differently-qualified type, except that any +non-__weak object may be read through +an __unsafe_unretained lvalue.

+ +

It is undefined behavior if a managed operation is performed on +a __strong or __weak object without a guarantee that +it contains a primitive zero bit-pattern, or if the storage for such +an object is freed or reused without the object being first assigned a +null pointer.

+ +

Rationale: ARC cannot differentiate between +an assignment operator which is intended to initialize dynamic +memory and one which is intended to potentially replace a value. +Therefore the object's pointer must be valid before letting ARC at it. +Similarly, C and Objective-C do not provide any language hooks for +destroying objects held in dynamic memory, so it is the programmer's +responsibility to avoid leaks (__strong objects) and +consistency errors (__weak objects).

+ +

These requirements are followed automatically in Objective-C++ when +creating objects of retainable object owner type with new +or new[] and destroying them with delete, +delete[], or a pseudo-destructor expression. Note that +arrays of nontrivially-ownership-qualified type are not ABI compatible +with non-ARC code because the element type is non-POD: such arrays +that are new[]'d in ARC translation units cannot +be delete[]'d in non-ARC translation units and +vice-versa.

+ +
+ +
+

Passing to an out parameter by writeback

+ +

If the argument passed to a parameter of type +T __autoreleasing * has type U oq *, +where oq is an ownership qualifier, then the argument is a +candidate for pass-by-writeback if:

+ +
    +
  • oq is __strong or __weak, and +
  • it would be legal to initialize a T __strong * with +a U __strong *.
  • +
+ +

For purposes of overload resolution, an implicit conversion +sequence requiring a pass-by-writeback is always worse than an +implicit conversion sequence not requiring a pass-by-writeback.

+ +

The pass-by-writeback is ill-formed if the argument expression does +not have a legal form:

+ +
    +
  • &var, where var is a scalar variable of +automatic storage duration with retainable object pointer type
  • +
  • a conditional expression where the second and third operands are +both legal forms
  • +
  • a cast whose operand is a legal form
  • +
  • a null pointer constant
  • +
+ +

Rationale: the restriction in the form of +the argument serves two purposes. First, it makes it impossible to +pass the address of an array to the argument, which serves to protect +against an otherwise serious risk of mis-inferring an array +argument as an out-parameter. Second, it makes it much less likely +that the user will see confusing aliasing problems due to the +implementation, below, where their store to the writeback temporary is +not immediately seen in the original argument variable.

+ +

A pass-by-writeback is evaluated as follows: +

    +
  1. The argument is evaluated to yield a pointer p of + type U oq *.
  2. +
  3. If p is a null pointer, then a null pointer is passed as + the argument, and no further work is required for the pass-by-writeback.
  4. +
  5. Otherwise, a temporary of type T __autoreleasing is + created and initialized to a null pointer.
  6. +
  7. If the argument is not an Objective-C method parameter marked + out, then *p is read, and the result is written + into the temporary with primitive semantics.
  8. +
  9. The address of the temporary is passed as the argument to the + actual call.
  10. +
  11. After the call completes, the temporary is loaded with primitive + semantics, and that value is assigned into *p.
  12. +

+ +

Rationale: this is all admittedly +convoluted. In an ideal world, we would see that a local variable is +being passed to an out-parameter and retroactively modify its type to +be __autoreleasing rather than __strong. This would +be remarkably difficult and not always well-founded under the C type +system. However, it was judged unacceptably invasive to require +programmers to write __autoreleasing on all the variables +they intend to use for out-parameters. This was the least bad +solution.

+ +
+ +
+

Ownership-qualified fields of structs and unions

+ +

A program is ill-formed if it declares a member of a C struct or +union to have a nontrivially ownership-qualified type.

+ +

Rationale: the resulting type would be +non-POD in the C++ sense, but C does not give us very good language +tools for managing the lifetime of aggregates, so it is more +convenient to simply forbid them. It is still possible to manage this +with a void* or an __unsafe_unretained +object.

+ +

This restriction does not apply in Objective-C++. However, +nontrivally ownership-qualified types are considered non-POD: in C++0x +terms, they are not trivially default constructible, copy +constructible, move constructible, copy assignable, move assignable, +or destructible. It is a violation of C++ One Definition Rule to use +a class outside of ARC that, under ARC, would have an +ownership-qualified member.

+ +

Rationale: unlike in C, we can express all +the necessary ARC semantics for ownership-qualified subobjects as +suboperations of the (default) special member functions for the class. +These functions then become non-trivial. This has the non-obvious +repercussion that the class will have a non-trivial copy constructor +and non-trivial destructor; if it wouldn't outside of ARC, this means +that objects of the type will be passed and returned in an +ABI-incompatible manner.

+ +
+ +
+ +
+

Ownership inference

+ +
+

Objects

+ +

If an object is declared with retainable object owner type, but +without an explicit ownership qualifier, its type is implicitly +adjusted to have __strong qualification.

+ +

As a special case, if the object's base type is Class +(possibly protocol-qualified), the type is adjusted to +have __unsafe_unretained qualification instead.

+ +
+ +
+

Indirect parameters

+ +

If a function or method parameter has type T*, where +T is an ownership-unqualified retainable object pointer type, +then:

+ +
    +
  • if T is const-qualified or Class, then +it is implicitly qualified with __unsafe_unretained;
  • +
  • otherwise, it is implicitly qualified +with __autoreleasing.
  • +
+

+ +

Rationale: __autoreleasing exists +mostly for this case, the Cocoa convention for out-parameters. Since +a pointer to const is obviously not an out-parameter, we +instead use a type more useful for passing arrays. If the user +instead intends to pass in a mutable array, inferring +__autoreleasing is the wrong thing to do; this directs some +of the caution in the following rules about writeback.

+ +

Such a type written anywhere else would be ill-formed by the +general rule requiring ownership qualifiers.

+ +

This rule does not apply in Objective-C++ if a parameter's type is +dependent in a template pattern and is only instantiated to +a type which would be a pointer to an unqualified retainable object +pointer type. Such code is still ill-formed.

+ +

Rationale: the convention is very unlikely +to be intentional in template code.

+ +
+ +
+

Template arguments

+ +

If a template argument for a template type parameter is an +retainable object owner type that does not have an explicit ownership +qualifier, it is adjusted to have __strong +qualification. This adjustment occurs regardless of whether the +template argument was deduced or explicitly specified.

+ +

Rationale: __strong is a useful default for containers (e.g., std::vector<id>), which would otherwise require explicit qualification. Moreover, unqualified retainable object pointer types are unlikely to be useful within templates, since they generally need to have a qualifier applied to the before being used.

+ +
+
+
+ + +
+

Method families

+ +

An Objective-C method may fall into a method +family, which is a conventional set of behaviors ascribed to it +by the Cocoa conventions.

+ +

A method is in a certain method family if: +

    +
  • it has a objc_method_family attribute placing it in that + family; or if not that,
  • +
  • it does not have an objc_method_family attribute placing + it in a different or no family, and
  • +
  • its selector falls into the corresponding selector family, and
  • +
  • its signature obeys the added restrictions of the method family.
  • +

+ +

A selector is in a certain selector family if, ignoring any leading +underscores, the first component of the selector either consists +entirely of the name of the method family or it begins with that name +followed by a character other than a lowercase letter. For +example, _perform:with: and performWith: would fall +into the perform family (if we recognized one), +but performing:with would not.

+ +

The families and their added restrictions are:

+ +
    +
  • alloc methods must return a retainable object pointer type.
  • +
  • copy methods must return a retainable object pointer type.
  • +
  • mutableCopy methods must return a retainable object pointer type.
  • +
  • new methods must return a retainable object pointer type.
  • +
  • init methods must be instance methods and must return an +Objective-C pointer type. Additionally, a program is ill-formed if it +declares or contains a call to an init method whose return +type is neither id nor a pointer to a super-class or +sub-class of the declaring class (if the method was declared on +a class) or the static receiver type of the call (if it was declared +on a protocol).

    + +

    Rationale: there are a fair number of existing +methods with init-like selectors which nonetheless don't +follow the init conventions. Typically these are either +accidental naming collisions or helper methods called during +initialization. Because of the peculiar retain/release behavior +of init methods, it's very important not to treat these +methods as init methods if they aren't meant to be. It was +felt that implicitly defining these methods out of the family based on +the exact relationship between the return type and the declaring class +would be much too subtle and fragile. Therefore we identify a small +number of legitimate-seeming return types and call everything else an +error. This serves the secondary purpose of encouraging programmers +not to accidentally give methods names in the init family.

    + +

    Note that a method with an init-family selector which +returns a non-Objective-C type (e.g. void) is perfectly +well-formed; it simply isn't in the init family.

    +
  • +
+ +

A program is ill-formed if a method's declarations, +implementations, and overrides do not all have the same method +family.

+ +
+

Explicit method family control

+ +

A method may be annotated with the objc_method_family +attribute to precisely control which method family it belongs to. If +a method in an @implementation does not have this attribute, +but there is a method declared in the corresponding @interface +that does, then the attribute is copied to the declaration in the +@implementation. The attribute is available outside of ARC, +and may be tested for with the preprocessor query +__has_attribute(objc_method_family).

+ +

The attribute is spelled +__attribute__((objc_method_family(family))). +If family is none, the method has no family, even if +it would otherwise be considered to have one based on its selector and +type. Otherwise, family must be one +of alloc, copy, init, +mutableCopy, or new, in which case the method is +considered to belong to the corresponding family regardless of its +selector. It is an error if a method that is explicitly added to a +family in this way does not meet the requirements of the family other +than the selector naming convention.

+ +

Rationale: the rules codified in this document +describe the standard conventions of Objective-C. However, as these +conventions have not heretofore been enforced by an unforgiving +mechanical system, they are only imperfectly kept, especially as they +haven't always even been precisely defined. While it is possible to +define low-level ownership semantics with attributes like +ns_returns_retained, this attribute allows the user to +communicate semantic intent, which of use both to ARC (which, e.g., +treats calls to init specially) and the static analyzer.

+
+ +
+

Semantics of method families

+ +

A method's membership in a method family may imply non-standard +semantics for its parameters and return type.

+ +

Methods in the alloc, copy, mutableCopy, +and new families — that is, methods in all the +currently-defined families except init — implicitly +return a retained +object as if they were annotated with +the ns_returns_retained attribute. This can be overridden by +annotating the method with either of +the ns_returns_autoreleased or +ns_returns_not_retained attributes.

+ +

Properties also follow same naming rules as methods. This means that +those in the alloc, copy, mutableCopy, +and new families provide access to +retained objects. +This can be overridden by annotating the property with +ns_returns_not_retained attribute.

+ +
+

Semantics of init

+

Methods in the init family implicitly +consume their self +parameter and return a +retained object. Neither of these properties can be altered +through attributes.

+ +

A call to an init method with a receiver that is either +self (possibly parenthesized or casted) or super is +called a delegate init call. It is an error +for a delegate init call to be made except from an init +method, and excluding blocks within such methods.

+ +

As an exception to the usual rule, the +variable self is mutable in an init method and has +the usual semantics for a __strong variable. However, it is +undefined behavior and the program is ill-formed, no diagnostic +required, if an init method attempts to use the previous +value of self after the completion of a delegate init call. +It is conventional, but not required, for an init method to +return self.

+ +

It is undefined behavior for a program to cause two or more calls +to init methods on the same object, except that +each init method invocation may perform at most one delegate +init call.

+ +
+ +
+

Related result types

+ +

Certain methods are candidates to have related +result types:

+
    +
  • class methods in the alloc and new method families
  • +
  • instance methods in the init family
  • +
  • the instance method self
  • +
  • outside of ARC, the instance methods retain and autorelease
  • +
+ +

If the formal result type of such a method is id or +protocol-qualified id, or a type equal to the declaring class +or a superclass, then it is said to have a related result type. In +this case, when invoked in an explicit message send, it is assumed to +return a type related to the type of the receiver:

+ +
    +
  • if it is a class method, and the receiver is a class +name T, the message send expression has type T*; +otherwise
  • +
  • if it is an instance method, and the receiver has type T, +the message send expression has type T; otherwise
  • +
  • the message send expression has the normal result type of the +method.
  • +
+ +

This is a new rule of the Objective-C language and applies outside +of ARC.

+ +

Rationale: ARC's automatic code emission is +more prone than most code to signature errors, i.e. errors where a +call was emitted against one method signature, but the implementing +method has an incompatible signature. Having more precise type +information helps drastically lower this risks, as well as catching +a number of latent bugs.

+ +
+
+
+ +
+

Optimization

+ +

ARC applies aggressive rules for the optimization of local +behavior. These rules are based around a core assumption of +local balancing: that other code will +perform retains and releases as necessary (and only as necessary) for +its own safety, and so the optimizer does not need to consider global +properties of the retain and release sequence. For example, if a +retain and release immediately bracket a call, the optimizer can +delete the retain and release on the assumption that the called +function will not do a constant number of unmotivated releases +followed by a constant number of balancing retains, such that +the local retain/release pair is the only thing preventing the called +function from ending up with a dangling reference.

+ +

The optimizer assumes that when a new value enters local control, +e.g. from a load of a non-local object or as the result of a function +call, it is instaneously valid. Subsequently, a retain and release of +a value are necessary on a computation path only if there is a use of +that value before the release and after any operation which might +cause a release of the value (including indirectly or non-locally), +and only if the value is not demonstrably already retained.

+ +

The complete optimization rules are quite complicated, but it would +still be useful to document them here.

+ +
+ +
+

Miscellaneous

+ +
+

Special methods

+ +
+

Memory management methods

+ +

A program is ill-formed if it contains a method definition, message +send, or @selector expression for any of the following +selectors: +

    +
  • autorelease
  • +
  • release
  • +
  • retain
  • +
  • retainCount
  • +
+

+ +

Rationale: retainCount is banned +because ARC robs it of consistent semantics. The others were banned +after weighing three options for how to deal with message sends:

+ +

Honoring them would work out very poorly if a programmer +naively or accidentally tried to incorporate code written for manual +retain/release code into an ARC program. At best, such code would do +twice as much work as necessary; quite frequently, however, ARC and +the explicit code would both try to balance the same retain, leading +to crashes. The cost is losing the ability to perform unrooted +retains, i.e. retains not logically corresponding to a strong +reference in the object graph.

+ +

Ignoring them would badly violate user expectations about their +code. While it would make it easier to develop code simultaneously +for ARC and non-ARC, there is very little reason to do so except for +certain library developers. ARC and non-ARC translation units share +an execution model and can seamlessly interoperate. Within a +translation unit, a developer who faithfully maintains their code in +non-ARC mode is suffering all the restrictions of ARC for zero +benefit, while a developer who isn't testing the non-ARC mode is +likely to be unpleasantly surprised if they try to go back to it.

+ +

Banning them has the disadvantage of making it very awkward +to migrate existing code to ARC. The best answer to that, given a +number of other changes and restrictions in ARC, is to provide a +specialized tool to assist users in that migration.

+ +

Implementing these methods was banned because they are too integral +to the semantics of ARC; many tricks which worked tolerably under +manual reference counting will misbehave if ARC performs an ephemeral +extra retain or two. If absolutely required, it is still possible to +implement them in non-ARC code, for example in a category; the +implementations must obey the semantics +laid out elsewhere in this document.

+ +
+
+ +
+

dealloc

+ +

A program is ill-formed if it contains a message send +or @selector expression for the selector dealloc.

+ +

Rationale: there are no legitimate reasons +to call dealloc directly.

+ +

A class may provide a method definition for an instance method +named dealloc. This method will be called after the final +release of the object but before it is deallocated or any of +its instance variables are destroyed. The superclass's implementation +of dealloc will be called automatically when the method +returns.

+ +

Rationale: even though ARC destroys instance +variables automatically, there are still legitimate reasons to write +a dealloc method, such as freeing non-retainable resources. +Failing to call [super dealloc] in such a method is nearly +always a bug. Sometimes, the object is simply trying to prevent +itself from being destroyed, but dealloc is really far too +late for the object to be raising such objections. Somewhat more +legitimately, an object may have been pool-allocated and should not be +deallocated with free; for now, this can only be supported +with a dealloc implementation outside of ARC. Such an +implementation must be very careful to do all the other work +that NSObject's dealloc would, which is outside the +scope of this document to describe.

+ +
+ +
+ +
+

@autoreleasepool

+ +

To simplify the use of autorelease pools, and to bring them under +the control of the compiler, a new kind of statement is available in +Objective-C. It is written @autoreleasepool followed by +a compound-statement, i.e. by a new scope delimited by curly +braces. Upon entry to this block, the current state of the +autorelease pool is captured. When the block is exited normally, +whether by fallthrough or directed control flow (such +as return or break), the autorelease pool is +restored to the saved state, releasing all the objects in it. When +the block is exited with an exception, the pool is not drained.

+ +

@autoreleasepool may be used in non-ARC translation units, +with equivalent semantics.

+ +

A program is ill-formed if it refers to the +NSAutoreleasePool class.

+ +

Rationale: autorelease pools are clearly +important for the compiler to reason about, but it is far too much to +expect the compiler to accurately reason about control dependencies +between two calls. It is also very easy to accidentally forget to +drain an autorelease pool when using the manual API, and this can +significantly inflate the process's high-water-mark. The introduction +of a new scope is unfortunate but basically required for sane +interaction with the rest of the language. Not draining the pool +during an unwind is apparently required by the Objective-C exceptions +implementation.

+ +
+ +
+

self

+ +

The self parameter variable of an Objective-C method is +never actually retained by the implementation. It is undefined +behavior, or at least dangerous, to cause an object to be deallocated +during a message send to that object. To make this +safe, self is implicitly const unless the method is +in the init family.

+ +

Rationale: the cost of +retaining self in all methods was found to be prohibitive, as +it tends to be live across calls, preventing the optimizer from +proving that the retain and release are unnecessary — for good +reason, as it's quite possible in theory to cause an object to be +deallocated during its execution without this retain and release. +Since it's extremely uncommon to actually do so, even unintentionally, +and since there's no natural way for the programmer to remove this +retain/release pair otherwise (as there is for other parameters by, +say, making the variable __unsafe_unretained), we chose to +make this optimizing assumption and shift some amount of risk to the +user.

+ +
+ +
+

Fast enumeration iteration variables

+ +

If a variable is declared in the condition of an Objective-C fast +enumeration loop, and the variable has no explicit ownership +qualifier, then it is qualified with const __strong and +objects encountered during the enumeration are not actually +retained.

+ +

Rationale: this is an optimization made +possible because fast enumeration loops promise to keep the objects +retained during enumeration, and the collection itself cannot be +synchronously modified. It can be overridden by explicitly qualifying +the variable with __strong, which will make the variable +mutable again and cause the loop to retain the objects it +encounters.

+ +
+ +
+

Blocks

+ +

The implicit const capture variables created when +evaluating a block literal expression have the same ownership +semantics as the local variables they capture. The capture is +performed by reading from the captured variable and initializing the +capture variable with that value; the capture variable is destroyed +when the block literal is, i.e. at the end of the enclosing scope.

+ +

The inference rules apply +equally to __block variables, which is a shift in semantics +from non-ARC, where __block variables did not implicitly +retain during capture.

+ +

__block variables of retainable object owner type are +moved off the stack by initializing the heap copy with the result of +moving from the stack copy.

+ +

With the exception of retains done as part of initializing +a __strong parameter variable or reading a __weak +variable, whenever these semantics call for retaining a value of +block-pointer type, it has the effect of a Block_copy. The +optimizer may remove such copies when it sees that the result is +used only as an argument to a call.

+ +
+ +
+

Exceptions

+ +

By default in Objective C, ARC is not exception-safe for normal +releases: +

    +
  • It does not end the lifetime of __strong variables when +their scopes are abnormally terminated by an exception.
  • +
  • It does not perform releases which would occur at the end of +a full-expression if that full-expression throws an exception.
  • +
+ +

A program may be compiled with the option +-fobjc-arc-exceptions in order to enable these, or with the +option -fno-objc-arc-exceptions to explicitly disable them, +with the last such argument winning.

+ +

Rationale: the standard Cocoa convention is +that exceptions signal programmer error and are not intended to be +recovered from. Making code exceptions-safe by default would impose +severe runtime and code size penalties on code that typically does not +actually care about exceptions safety. Therefore, ARC-generated code +leaks by default on exceptions, which is just fine if the process is +going to be immediately terminated anyway. Programs which do care +about recovering from exceptions should enable the option.

+ +

In Objective-C++, -fobjc-arc-exceptions is enabled by +default.

+ +

Rationale: C++ already introduces pervasive +exceptions-cleanup code of the sort that ARC introduces. C++ +programmers who have not already disabled exceptions are much more +likely to actual require exception-safety.

+ +

ARC does end the lifetimes of __weak objects when an +exception terminates their scope unless exceptions are disabled in the +compiler.

+ +

Rationale: the consequence of a +local __weak object not being destroyed is very likely to be +corruption of the Objective-C runtime, so we want to be safer here. +Of course, potentially massive leaks are about as likely to take down +the process as this corruption is if the program does try to recover +from exceptions.

+ +
+ +
+ +
+

Runtime support

+ +

This section describes the interaction between the ARC runtime and +the code generated by the ARC compiler. This is not part of the ARC +language specification; instead, it is effectively a language-specific +ABI supplement, akin to the Itanium generic ABI for C++.

+ +

Ownership qualification does not alter the storage requirements for +objects, except that it is undefined behavior if a __weak +object is inadequately aligned for an object of type id. The +other qualifiers may be used on explicitly under-aligned memory.

+ +

The runtime tracks __weak objects which holds non-null +values. It is undefined behavior to direct modify a __weak +object which is being tracked by the runtime except through an +objc_storeWeak, +objc_destroyWeak, +or objc_moveWeak +call.

+ +

The runtime must provide a number of new entrypoints which the +compiler may emit, which are described in the remainder of this +section.

+ +

Rationale: Several of these functions are +semantically equivalent to a message send; we emit calls to C +functions instead because:

+
    +
  • the machine code to do so is significantly smaller,
  • +
  • it is much easier to recognize the C functions in the ARC optimizer, and
  • +
  • a sufficient sophisticated runtime may be able to avoid the +message send in common cases.
  • +
+ +

Several other of these functions are fused operations which +can be described entirely in terms of other operations. We use the +fused operations primarily as a code-size optimization, although in +some cases there is also a real potential for avoiding redundant +operations in the runtime.

+ +
+ +
+

id objc_autorelease(id value);

+

Precondition: value is null or a pointer to a +valid object.

+

If value is null, this call has no effect. Otherwise, it +adds the object to the innermost autorelease pool exactly as if the +object had been sent the autorelease message.

+

Always returns value.

+
+ +
+

void objc_autoreleasePoolPop(void *pool);

+

Precondition: pool is the result of a previous call to +objc_autoreleasePoolPush +on the current thread, where neither pool nor any enclosing +pool have previously been popped.

+

Releases all the objects added to the given autorelease pool and +any autorelease pools it encloses, then sets the current autorelease +pool to the pool directly enclosing pool.

+
+ +
+

void *objc_autoreleasePoolPush(void);

+

Creates a new autorelease pool that is enclosed by the current +pool, makes that the current pool, and returns an opaque handle +to it.

+ +

Rationale: while the interface is described +as an explicit hierarchy of pools, the rules allow the implementation +to just keep a stack of objects, using the stack depth as the opaque +pool handle.

+ +
+ +
+

id objc_autoreleaseReturnValue(id value);

+

Precondition: value is null or a pointer to a +valid object.

+

If value is null, this call has no effect. Otherwise, it +makes a best effort to hand off ownership of a retain count on the +object to a call +to objc_retainAutoreleasedReturnValue +for the same object in an enclosing call frame. If this is not +possible, the object is autoreleased as above.

+

Always returns value.

+
+ +
+

void objc_copyWeak(id *dest, id *src);

+

Precondition: src is a valid pointer which either +contains a null pointer or has been registered as a __weak +object. dest is a valid pointer which has not been +registered as a __weak object.

+

dest is initialized to be equivalent to src, +potentially registering it with the runtime. Equivalent to the +following code:

+
void objc_copyWeak(id *dest, id *src) {
+  objc_release(objc_initWeak(dest, objc_loadWeakRetained(src)));
+}
+

Must be atomic with respect to calls to objc_storeWeak +on src.

+
+ +
+

void objc_destroyWeak(id *object);

+

Precondition: object is a valid pointer which +either contains a null pointer or has been registered as +a __weak object.

+

object is unregistered as a weak object, if it ever was. +The current value of object is left unspecified; otherwise, +equivalent to the following code:

+
void objc_destroyWeak(id *object) {
+  objc_storeWeak(object, nil);
+}
+

Does not need to be atomic with respect to calls +to objc_storeWeak on object.

+
+ +
+

id objc_initWeak(id *object, id value);

+

Precondition: object is a valid pointer which has +not been registered as a __weak object. value is +null or a pointer to a valid object.

+

If value is a null pointer or the object to which it +points has begun deallocation, object is zero-initialized. +Otherwise, object is registered as a __weak object +pointing to value. Equivalent to the following code:

+
id objc_initWeak(id *object, id value) {
+  *object = nil;
+  return objc_storeWeak(object, value);
+}
+

Returns the value of object after the call.

+

Does not need to be atomic with respect to calls +to objc_storeWeak on object.

+
+ +
+

id objc_loadWeak(id *object);

+

Precondition: object is a valid pointer which +either contains a null pointer or has been registered as +a __weak object.

+

If object is registered as a __weak object, and +the last value stored into object has not yet been +deallocated or begun deallocation, retains and autoreleases that value +and returns it. Otherwise returns null. Equivalent to the following +code:

+
id objc_loadWeak(id *object) {
+  return objc_autorelease(objc_loadWeakRetained(object));
+}
+

Must be atomic with respect to calls to objc_storeWeak +on object.

+
Rationale: loading weak references would be +inherently prone to race conditions without the retain.
+
+ +
+

id objc_loadWeakRetained(id *object);

+

Precondition: object is a valid pointer which +either contains a null pointer or has been registered as +a __weak object.

+

If object is registered as a __weak object, and +the last value stored into object has not yet been +deallocated or begun deallocation, retains that value and returns it. +Otherwise returns null.

+

Must be atomic with respect to calls to objc_storeWeak +on object.

+
+ +
+

void objc_moveWeak(id *dest, id *src);

+

Precondition: src is a valid pointer which either +contains a null pointer or has been registered as a __weak +object. dest is a valid pointer which has not been +registered as a __weak object.

+

dest is initialized to be equivalent to src, +potentially registering it with the runtime. src may then be +left in its original state, in which case this call is equivalent +to objc_copyWeak, or it +may be left as null.

+

Must be atomic with respect to calls to objc_storeWeak +on src.

+
+ +
+

void objc_release(id value);

+

Precondition: value is null or a pointer to a +valid object.

+

If value is null, this call has no effect. Otherwise, it +performs a release operation exactly as if the object had been sent +the release message.

+
+ +
+

id objc_retain(id value);

+

Precondition: value is null or a pointer to a +valid object.

+

If value is null, this call has no effect. Otherwise, it +performs a retain operation exactly as if the object had been sent +the retain message.

+

Always returns value.

+
+ +
+

id objc_retainAutorelease(id value);

+

Precondition: value is null or a pointer to a +valid object.

+

If value is null, this call has no effect. Otherwise, it +performs a retain operation followed by an autorelease operation. +Equivalent to the following code:

+
id objc_retainAutorelease(id value) {
+  return objc_autorelease(objc_retain(value));
+}
+

Always returns value.

+
+ +
+

id objc_retainAutoreleaseReturnValue(id value);

+

Precondition: value is null or a pointer to a +valid object.

+

If value is null, this call has no effect. Otherwise, it +performs a retain operation followed by the operation described in +objc_autoreleaseReturnValue. +Equivalent to the following code:

+
id objc_retainAutoreleaseReturnValue(id value) {
+  return objc_autoreleaseReturnValue(objc_retain(value));
+}
+

Always returns value.

+
+ +
+

id objc_retainAutoreleasedReturnValue(id value);

+

Precondition: value is null or a pointer to a +valid object.

+

If value is null, this call has no effect. Otherwise, it +attempts to accept a hand off of a retain count from a call to +objc_autoreleaseReturnValue +on value in a recently-called function or something it +calls. If that fails, it performs a retain operation exactly +like objc_retain.

+

Always returns value.

+
+ +
+

id objc_retainBlock(id value);

+

Precondition: value is null or a pointer to a +valid block object.

+

If value is null, this call has no effect. Otherwise, if +the block pointed to by value is still on the stack, it is +copied to the heap and the address of the copy is returned. Otherwise +a retain operation is performed on the block exactly as if it had been +sent the retain message.

+
+ +
+

id objc_storeStrong(id *object, id value);

+

Precondition: object is a valid pointer to +a __strong object which is adequately aligned for a +pointer. value is null or a pointer to a valid object.

+

Performs the complete sequence for assigning to a __strong +object of non-block type. Equivalent to the following code:

+
id objc_storeStrong(id *object, id value) {
+  value = [value retain];
+  id oldValue = *object;
+  *object = value;
+  [oldValue release];
+  return value;
+}
+

Always returns value.

+
+ +
+

id objc_storeWeak(id *object, id value);

+

Precondition: object is a valid pointer which +either contains a null pointer or has been registered as +a __weak object. value is null or a pointer to a +valid object.

+

If value is a null pointer or the object to which it +points has begun deallocation, object is assigned null +and unregistered as a __weak object. Otherwise, +object is registered as a __weak object or has its +registration updated to point to value.

+

Returns the value of object after the call.

+
+ +
+
+ + diff --git a/docs/Block-ABI-Apple.txt b/docs/Block-ABI-Apple.txt index 4a97aa9bd65e..661ed50594de 100644 --- a/docs/Block-ABI-Apple.txt +++ b/docs/Block-ABI-Apple.txt @@ -317,7 +317,7 @@ would be rewritten to be: int flags; //refcount; int size; int captured_i; - } i = { NULL, &i, 0, sizeof(struct _block_byref_i), 11 }; + } i = { NULL, &i, 0, sizeof(struct _block_byref_i), 10 }; i.forwarding->captured_i = 11; @@ -476,7 +476,7 @@ struct _block_byref_obj { int size; void (*byref_keep)(struct _block_byref_i *dst, struct _block_byref_i *src); void (*byref_dispose)(struct _block_byref_i *); - int captured_obj; + id captured_obj; }; void _block_byref_obj_keep(struct _block_byref_voidBlock *dst, struct _block_byref_voidBlock *src) { diff --git a/docs/BlockLanguageSpec.txt b/docs/BlockLanguageSpec.txt index a612fd28892b..f7bbda365184 100644 --- a/docs/BlockLanguageSpec.txt +++ b/docs/BlockLanguageSpec.txt @@ -151,7 +151,7 @@ For example, given class Foo with member function fighter(void): ...a Block that used foo would import the variables as const variations: const Foo block_foo = foo; // const copy constructor const Foo &block_fooRef = fooRef; - const Foo *block_fooPtr = fooPtr; + Foo *const block_fooPtr = fooPtr; Stack-local objects are copied into a Block via a copy const constructor. If no such constructor exists, it is considered an error to reference such objects from within the Block compound statements. A destructor is run as control leaves the compound statement that contains the Block literal expression. diff --git a/docs/DriverInternals.html b/docs/DriverInternals.html index 4f5f0ae112f9..380de9909af0 100644 --- a/docs/DriverInternals.html +++ b/docs/DriverInternals.html @@ -405,7 +405,7 @@ to each compilation sequence. For example, the list of used temporary files (which must be removed once compilation is finished) and result files (which should be removed if - compilation files).

+ compilation fails).

Unified Parsing & Pipelining

diff --git a/docs/InternalsManual.html b/docs/InternalsManual.html index 961198938f20..5d97609373b7 100644 --- a/docs/InternalsManual.html +++ b/docs/InternalsManual.html @@ -68,7 +68,6 @@ td {
  • Constant Folding in the Clang AST
  • -
  • The Index Library
  • Howto guides
    • How to add an attribute
    • @@ -1213,8 +1212,8 @@ void g(); void g(int);

      the DeclContext::lookup operation will return - an OverloadedFunctionDecl that contains both - declarations of "g". Clients that perform semantic analysis on a + a DeclContext::lookup_result that contains a range of iterators + over declarations of "g". Clients that perform semantic analysis on a program that is not concerned with the actual source code will primarily use this semantics-centric view.

      @@ -1396,8 +1395,8 @@ namespace N { nodes in Snippet #1, each of which is a declaration context that contains a single declaration of "f". However, the semantics-centric view provided by name lookup into the namespace N for - "f" will return an OverloadedFunctionDecl that contains - both declarations of "f".

      + "f" will return a DeclContext::lookup_result that contains + a range of iterators over declarations of "f".

      DeclContext manages multiply-defined declaration contexts internally. The diff --git a/docs/LanguageExtensions.html b/docs/LanguageExtensions.html index 8f43725d82a2..7ee8f010a32b 100644 --- a/docs/LanguageExtensions.html +++ b/docs/LanguageExtensions.html @@ -1,13 +1,17 @@ + + -Clang Language Extensions - - - + + Clang LanguageExtensions + + + @@ -25,12 +29,12 @@ td {

    • Vectors and Extended Vectors
    • Messages on deprecated and unavailable attributes
    • Attributes on enumerators
    • -
    • Checks for Standard Language Features
    • +
    • Checks for Standard Language Features -
    • Checks for Upcoming Standard Language Features
    • +
  • +
  • Checks for Upcoming Standard Language Features
  • C1X - +
  • +
  • Checks for Type Traits
  • Blocks
  • Objective-C Features
  • Function Overloading in C
  • @@ -104,7 +110,7 @@ code without having to resort to something like autoconf or fragile "compiler version checks".

    -

    __has_builtin

    +

    __has_builtin

    This function-like macro takes a single identifier argument that is the name @@ -129,7 +135,7 @@ not. It can be used like this:

    -

    __has_feature and __has_extension

    +

    __has_feature and __has_extension

    These function-like macros take a single identifier argument that is the @@ -174,7 +180,7 @@ non-standardized features, i.e. features not prefixed c_,

    The feature tag is described along with the language feature below.

    -

    __has_attribute

    +

    __has_attribute

    This function-like macro takes a single identifier argument that is the name @@ -208,7 +214,7 @@ check for the existence of an include file before doing a possibly failing #include directive.

    -

    __has_include

    +

    __has_include

    This function-like macro takes a single file name string argument that @@ -218,12 +224,12 @@ be found using the include paths, or 0 otherwise:

     // Note the two possible file name string formats.
    -#if __has_include("myinclude.h") && __has_include(<stdint.h>)
    +#if __has_include("myinclude.h") && __has_include(<stdint.h>)
     # include "myinclude.h"
     #endif
     
     // To avoid problem with non-clang compilers not having this macro.
    -#if defined(__has_include) && __has_include("myinclude.h")
    +#if defined(__has_include) && __has_include("myinclude.h")
     # include "myinclude.h"
     #endif
     
    @@ -232,7 +238,7 @@ be found using the include paths, or 0 otherwise:

    To test for this feature, use #if defined(__has_include).

    -

    __has_include_next

    +

    __has_include_next

    This function-like macro takes a single file name string argument that @@ -244,12 +250,12 @@ be found using the include paths, or 0 otherwise:

     // Note the two possible file name string formats.
    -#if __has_include_next("myinclude.h") && __has_include_next(<stdint.h>)
    +#if __has_include_next("myinclude.h") && __has_include_next(<stdint.h>)
     # include_next "myinclude.h"
     #endif
     
     // To avoid problem with non-clang compilers not having this macro.
    -#if defined(__has_include_next) && __has_include_next("myinclude.h")
    +#if defined(__has_include_next) && __has_include_next("myinclude.h")
     # include_next "myinclude.h"
     #endif
     
    @@ -410,115 +416,120 @@ noted.

    C++0x standard. As a result, all these features are enabled with the -std=c++0x option when compiling C++ code.

    -

    C++0x decltype()

    +

    C++0x decltype()

    Use __has_feature(cxx_decltype) or __has_extension(cxx_decltype) to determine if support for the decltype() specifier is enabled.

    -

    C++0x SFINAE includes access control

    +

    C++0x SFINAE includes access control

    Use __has_feature(cxx_access_control_sfinae) or __has_extension(cxx_access_control_sfinae) to determine whether access-control errors (e.g., calling a private constructor) are considered to be template argument deduction errors (aka SFINAE errors), per C++ DR1170.

    -

    C++0x alias templates

    +

    C++0x alias templates

    Use __has_feature(cxx_alias_templates) or __has_extension(cxx_alias_templates) to determine if support for C++0x's alias declarations and alias templates is enabled.

    -

    C++0x attributes

    +

    C++0x attributes

    Use __has_feature(cxx_attributes) or __has_extension(cxx_attributes) to determine if support for attribute parsing with C++0x's square bracket notation is enabled.

    -

    C++0x default template arguments in function templates

    +

    C++0x default template arguments in function templates

    Use __has_feature(cxx_default_function_template_args) or __has_extension(cxx_default_function_template_args) to determine if support for default template arguments in function templates is enabled.

    -

    C++0x deleted functions

    +

    C++0x delegating constructors

    + +

    Use __has_feature(cxx_delegating_constructors) to determine if +support for delegating constructors is enabled.

    + +

    C++0x deleted functions

    Use __has_feature(cxx_deleted_functions) or __has_extension(cxx_deleted_functions) to determine if support for deleted function definitions (with = delete) is enabled.

    -

    C++0x lambdas

    +

    C++0x lambdas

    Use __has_feature(cxx_lambdas) or __has_extension(cxx_lambdas) to determine if support for lambdas is enabled. clang does not currently implement this feature.

    -

    C++0x nullptr

    +

    C++0x nullptr

    Use __has_feature(cxx_nullptr) or __has_extension(cxx_nullptr) to determine if support for nullptr is enabled.

    -

    C++0x override control

    +

    C++0x override control

    Use __has_feature(cxx_override_control) or __has_extension(cxx_override_control) to determine if support for the override control keywords is enabled.

    -

    C++0x reference-qualified functions

    +

    C++0x reference-qualified functions

    Use __has_feature(cxx_reference_qualified_functions) or __has_extension(cxx_reference_qualified_functions) to determine if support for reference-qualified functions (e.g., member functions with & or && applied to *this) is enabled.

    -

    C++0x range-based for loop

    +

    C++0x range-based for loop

    Use __has_feature(cxx_range_for) or __has_extension(cxx_range_for) to determine if support for the range-based for loop is enabled.

    -

    C++0x rvalue references

    +

    C++0x rvalue references

    Use __has_feature(cxx_rvalue_references) or __has_extension(cxx_rvalue_references) to determine if support for rvalue references is enabled.

    -

    C++0x static_assert()

    +

    C++0x static_assert()

    Use __has_feature(cxx_static_assert) or __has_extension(cxx_static_assert) to determine if support for compile-time assertions using static_assert is enabled.

    -

    C++0x type inference

    +

    C++0x type inference

    Use __has_feature(cxx_auto_type) or __has_extension(cxx_auto_type) to determine C++0x type inference is supported using the auto specifier. If this is disabled, auto will instead be a storage class specifier, as in C or C++98.

    -

    C++0x variadic templates

    +

    C++0x variadic templates

    Use __has_feature(cxx_variadic_templates) or __has_extension(cxx_variadic_templates) to determine if support for variadic templates is enabled.

    -

    C++0x inline namespaces

    +

    C++0x inline namespaces

    Use __has_feature(cxx_inline_namespaces) or __has_extension(cxx_inline_namespaces) to determine if support for inline namespaces is enabled.

    -

    C++0x trailing return type

    +

    C++0x trailing return type

    Use __has_feature(cxx_trailing_return) or __has_extension(cxx_trailing_return) to determine if support for the alternate function declaration syntax with trailing return type is enabled.

    -

    C++0x noexcept

    +

    C++0x noexcept

    Use __has_feature(cxx_noexcept) or __has_extension(cxx_noexcept) to determine if support for noexcept exception specifications is enabled.

    -

    C++0x strongly typed enumerations

    +

    C++0x strongly typed enumerations

    Use __has_feature(cxx_strong_enums) or __has_extension(cxx_strong_enums) to determine if support for @@ -530,7 +541,7 @@ strongly typed, scoped enumerations is enabled.

    C1X standard. As a result, all these features are enabled with the -std=c1x option when compiling C code.

    -

    C1X generic selections

    +

    C1X generic selections

    Use __has_feature(c_generic_selections) or __has_extension(c_generic_selections) to determine if support for @@ -544,7 +555,7 @@ C1X draft standard.

    appropriate standard, but in C++, which lacks the type compatibility rules used in C, types are considered compatible only if they are equivalent.

    -

    C1X _Static_assert()

    +

    C1X _Static_assert()

    Use __has_feature(c_static_assert) or __has_extension(c_static_assert) to determine if support for @@ -554,7 +565,7 @@ compile-time assertions using _Static_assert is enabled.

    Checks for Type Traits

    -

    Clang supports the GNU C++ type traits and a subset of the Microsoft Visual C++ Type traits. For each supported type trait __X, __has_extension(X) indicates the presence of the type trait. For example: +

    Clang supports the GNU C++ type traits and a subset of the Microsoft Visual C++ Type traits. For each supported type trait __X, __has_extension(X) indicates the presence of the type trait. For example:

     #if __has_extension(is_convertible_to)
    @@ -640,7 +651,7 @@ to have the type NSArray *. If neither alloc nor To determine whether a method has a related result type, the first
     word in the camel-case selector (e.g., "init" in "initWithObjects") is
     considered, and the method will a related result type if its return
    -type is compatible with the type of its class and if
    +type is compatible with the type of its class and if

      @@ -650,7 +661,7 @@ type is compatible with the type of its class and if
    • the first word is "autorelease", "init", "retain", or "self", and the method is an instance method.
    • -

    +

    If a method with a related result type is overridden by a subclass method, the subclass method must also return a type that is compatible @@ -669,6 +680,12 @@ property access via the given method. In all other respects, a method with a related result type is treated the same way as method without a related result type.

    + +

    Automatic reference counting

    + + +

    Clang provides support for automated reference counting in Objective-C, which eliminates the need for manual retain/release/autorelease message sends. There are two feature macros associated with automatic reference counting: __has_feature(objc_arc) indicates the availability of automated reference counting in general, while __has_feature(objc_arc_weak) indicates that automated reference counting also includes support for __weak pointers to Objective-C objects.

    +

    Function Overloading in C

    @@ -790,7 +807,7 @@ vector support instead of builtins, in order to reduce the number of builtins that we need to implement.

    -

    __builtin_shufflevector

    +

    __builtin_shufflevector

    __builtin_shufflevector is used to express generic vector @@ -842,7 +859,7 @@ the number of indices specified.

    Query for this feature with __has_builtin(__builtin_shufflevector).

    -

    __builtin_unreachable

    +

    __builtin_unreachable

    __builtin_unreachable is used to indicate that a specific point in @@ -880,7 +897,7 @@ no arguments and produces a void result.

    Query for this feature with __has_builtin(__builtin_unreachable).

    -

    __sync_swap

    +

    __sync_swap

    __sync_swap is used to atomically swap integers or pointers in @@ -896,7 +913,7 @@ memory.

    Example of Use:

    -int old_value = __sync_swap(&value, new_value);
    +int old_value = __sync_swap(&value, new_value);
     

    Description:

    diff --git a/docs/UsersManual.html b/docs/UsersManual.html index 4962a9211066..639892714ef8 100644 --- a/docs/UsersManual.html +++ b/docs/UsersManual.html @@ -846,6 +846,10 @@ variants "__asm__" and "__typeof__" are recognized in all modes.
  • The Apple "blocks" extension is recognized by default in gnu* modes on some platforms; it can be enabled in any mode with the "-fblocks" option.
  • +
  • Arrays that are VLA's according to the standard, but which can be constant + folded by the frontend are treated as fixed size arrays. This occurs for + things like "int X[(1, 2)];", which is technically a VLA. c* modes are + strictly compliant and treat these as VLAs.
  • Differences between *89 and *99 modes:

    @@ -882,11 +886,6 @@ extensions are not implemented yet:

    the uses described in the bug, this is likely to be implemented at some point, at least partially. -
  • clang does not support code generation for local variables pinned to -registers (bug 3933). -This is a relatively small feature, so it is likely to be implemented -relatively soon.
  • -
  • clang does not support decimal floating point types (_Decimal32 and friends) or fixed-point types (_Fract and friends); nobody has expressed interest in these features yet, so it's hard to say when they will be @@ -937,16 +936,9 @@ extension appears to be rarely used. Note that clang does support flexible array members (arrays with a zero or unspecified size at the end of a structure).
  • -
  • clang does not support duplicate definitions of a function where one is -inline. This complicates clients of the AST which normally can expect there is -at most one definition for each function. Source code using this feature should -be changed to define the inline and out-of-line definitions in separate -translation units.
  • -
  • clang does not have an equivalent to gcc's "fold"; this means that clang doesn't accept some constructs gcc might accept in contexts where a -constant expression is required, like "x-x" where x is a variable, or calls -to C library functions like strlen.
  • +constant expression is required, like "x-x" where x is a variable.
  • clang does not support multiple alternative constraints in inline asm; this is an extremely obscure feature which would be complicated to implement diff --git a/docs/index.html b/docs/index.html deleted file mode 100644 index d741b68a4160..000000000000 --- a/docs/index.html +++ /dev/null @@ -1,4 +0,0 @@ -'clang' C frontend documentation - -None yet, sorry :( - diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index cb0b3c1babcb..4852ded7f883 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -833,14 +833,24 @@ enum CXTranslationUnit_Flags { /** * \brief Used to indicate that the "detailed" preprocessing record, - * if requested, should also contain nested macro instantiations. + * if requested, should also contain nested macro expansions. * - * Nested macro instantiations (i.e., macro instantiations that occur - * inside another macro instantiation) can, in some code bases, require + * Nested macro expansions (i.e., macro expansions that occur + * inside another macro expansion) can, in some code bases, require * a large amount of storage to due preprocessor metaprogramming. Moreover, * its fairly rare that this information is useful for libclang clients. */ - CXTranslationUnit_NestedMacroInstantiations = 0x40 + CXTranslationUnit_NestedMacroExpansions = 0x40, + + /** + * \brief Legacy name to indicate that the "detailed" preprocessing record, + * if requested, should contain nested macro expansions. + * + * \see CXTranslationUnit_NestedMacroExpansions for the current name for this + * value, and its semantics. This is just an alias. + */ + CXTranslationUnit_NestedMacroInstantiations = + CXTranslationUnit_NestedMacroExpansions }; /** @@ -932,6 +942,41 @@ enum CXSaveTranslationUnit_Flags { */ CINDEX_LINKAGE unsigned clang_defaultSaveOptions(CXTranslationUnit TU); +/** + * \brief Describes the kind of error that occurred (if any) in a call to + * \c clang_saveTranslationUnit(). + */ +enum CXSaveError { + /** + * \brief Indicates that no error occurred while saving a translation unit. + */ + CXSaveError_None = 0, + + /** + * \brief Indicates that an unknown error occurred while attempting to save + * the file. + * + * This error typically indicates that file I/O failed when attempting to + * write the file. + */ + CXSaveError_Unknown = 1, + + /** + * \brief Indicates that errors during translation prevented this attempt + * to save the translation unit. + * + * Errors that prevent the translation unit from being saved can be + * extracted using \c clang_getNumDiagnostics() and \c clang_getDiagnostic(). + */ + CXSaveError_TranslationErrors = 2, + + /** + * \brief Indicates that the translation unit to be saved was somehow + * invalid (e.g., NULL). + */ + CXSaveError_InvalidTU = 3 +}; + /** * \brief Saves a translation unit into a serialized representation of * that translation unit on disk. @@ -951,8 +996,9 @@ CINDEX_LINKAGE unsigned clang_defaultSaveOptions(CXTranslationUnit TU); * is saved. This should be a bitwise OR of the * CXSaveTranslationUnit_XXX flags. * - * \returns Zero if the translation unit was saved successfully, a - * non-zero value otherwise. + * \returns A value that will match one of the enumerators of the CXSaveError + * enumeration. Zero (CXSaveError_None) indicates that the translation unit was + * saved successfully, while a non-zero value indicates that a problem occurred. */ CINDEX_LINKAGE int clang_saveTranslationUnit(CXTranslationUnit TU, const char *FileName, @@ -1385,7 +1431,8 @@ enum CXCursorKind { /* Preprocessing */ CXCursor_PreprocessingDirective = 500, CXCursor_MacroDefinition = 501, - CXCursor_MacroInstantiation = 502, + CXCursor_MacroExpansion = 502, + CXCursor_MacroInstantiation = CXCursor_MacroExpansion, CXCursor_InclusionDirective = 503, CXCursor_FirstPreprocessing = CXCursor_PreprocessingDirective, CXCursor_LastPreprocessing = CXCursor_InclusionDirective @@ -1473,6 +1520,11 @@ CINDEX_LINKAGE unsigned clang_isExpression(enum CXCursorKind); */ CINDEX_LINKAGE unsigned clang_isStatement(enum CXCursorKind); +/** + * \brief Determine whether the given cursor kind represents an attribute. + */ +CINDEX_LINKAGE unsigned clang_isAttribute(enum CXCursorKind); + /** * \brief Determine whether the given cursor kind represents an invalid * cursor. @@ -2829,6 +2881,137 @@ enum CXCodeComplete_Flags { CXCodeComplete_IncludeCodePatterns = 0x02 }; +/** + * \brief Bits that represent the context under which completion is occurring. + * + * The enumerators in this enumeration may be bitwise-OR'd together if multiple + * contexts are occurring simultaneously. + */ +enum CXCompletionContext { + /** + * \brief The context for completions is unexposed, as only Clang results + * should be included. (This is equivalent to having no context bits set.) + */ + CXCompletionContext_Unexposed = 0, + + /** + * \brief Completions for any possible type should be included in the results. + */ + CXCompletionContext_AnyType = 1 << 0, + + /** + * \brief Completions for any possible value (variables, function calls, etc.) + * should be included in the results. + */ + CXCompletionContext_AnyValue = 1 << 1, + /** + * \brief Completions for values that resolve to an Objective-C object should + * be included in the results. + */ + CXCompletionContext_ObjCObjectValue = 1 << 2, + /** + * \brief Completions for values that resolve to an Objective-C selector + * should be included in the results. + */ + CXCompletionContext_ObjCSelectorValue = 1 << 3, + /** + * \brief Completions for values that resolve to a C++ class type should be + * included in the results. + */ + CXCompletionContext_CXXClassTypeValue = 1 << 4, + + /** + * \brief Completions for fields of the member being accessed using the dot + * operator should be included in the results. + */ + CXCompletionContext_DotMemberAccess = 1 << 5, + /** + * \brief Completions for fields of the member being accessed using the arrow + * operator should be included in the results. + */ + CXCompletionContext_ArrowMemberAccess = 1 << 6, + /** + * \brief Completions for properties of the Objective-C object being accessed + * using the dot operator should be included in the results. + */ + CXCompletionContext_ObjCPropertyAccess = 1 << 7, + + /** + * \brief Completions for enum tags should be included in the results. + */ + CXCompletionContext_EnumTag = 1 << 8, + /** + * \brief Completions for union tags should be included in the results. + */ + CXCompletionContext_UnionTag = 1 << 9, + /** + * \brief Completions for struct tags should be included in the results. + */ + CXCompletionContext_StructTag = 1 << 10, + + /** + * \brief Completions for C++ class names should be included in the results. + */ + CXCompletionContext_ClassTag = 1 << 11, + /** + * \brief Completions for C++ namespaces and namespace aliases should be + * included in the results. + */ + CXCompletionContext_Namespace = 1 << 12, + /** + * \brief Completions for C++ nested name specifiers should be included in + * the results. + */ + CXCompletionContext_NestedNameSpecifier = 1 << 13, + + /** + * \brief Completions for Objective-C interfaces (classes) should be included + * in the results. + */ + CXCompletionContext_ObjCInterface = 1 << 14, + /** + * \brief Completions for Objective-C protocols should be included in + * the results. + */ + CXCompletionContext_ObjCProtocol = 1 << 15, + /** + * \brief Completions for Objective-C categories should be included in + * the results. + */ + CXCompletionContext_ObjCCategory = 1 << 16, + /** + * \brief Completions for Objective-C instance messages should be included + * in the results. + */ + CXCompletionContext_ObjCInstanceMessage = 1 << 17, + /** + * \brief Completions for Objective-C class messages should be included in + * the results. + */ + CXCompletionContext_ObjCClassMessage = 1 << 18, + /** + * \brief Completions for Objective-C selector names should be included in + * the results. + */ + CXCompletionContext_ObjCSelectorName = 1 << 19, + + /** + * \brief Completions for preprocessor macro names should be included in + * the results. + */ + CXCompletionContext_MacroName = 1 << 20, + + /** + * \brief Natural language completions should be included in the results. + */ + CXCompletionContext_NaturalLanguage = 1 << 21, + + /** + * \brief The current context is unknown, so set all contexts. + */ + CXCompletionContext_Unknown = ((1 << 22) - 1) +}; + /** * \brief Returns a default set of code-completion options that can be * passed to\c clang_codeCompleteAt(). @@ -2949,6 +3132,19 @@ CINDEX_LINKAGE CXDiagnostic clang_codeCompleteGetDiagnostic(CXCodeCompleteResults *Results, unsigned Index); +/** + * \brief Determines what compeltions are appropriate for the context + * the given code completion. + * + * \param Results the code completion results to query + * + * \returns the kinds of completions that are appropriate for use + * along with the given code completion results. + */ +CINDEX_LINKAGE +unsigned long long clang_codeCompleteGetContexts( + CXCodeCompleteResults *Results); + /** * @} */ @@ -3001,6 +3197,51 @@ CINDEX_LINKAGE void clang_getInclusions(CXTranslationUnit tu, CXInclusionVisitor visitor, CXClientData client_data); +/** + * @} + */ + +/** \defgroup CINDEX_REMAPPING Remapping functions + * + * @{ + */ + +/** + * \brief A remapping of original source files and their translated files. + */ +typedef void *CXRemapping; + +/** + * \brief Retrieve a remapping. + * + * \param path the path that contains metadata about remappings. + * + * \returns the requested remapping. This remapping must be freed + * via a call to \c clang_remap_dispose(). Can return NULL if an error occurred. + */ +CINDEX_LINKAGE CXRemapping clang_getRemappings(const char *path); + +/** + * \brief Determine the number of remappings. + */ +CINDEX_LINKAGE unsigned clang_remap_getNumFiles(CXRemapping); + +/** + * \brief Get the original and the associated filename from the remapping. + * + * \param original If non-NULL, will be set to the original filename. + * + * \param transformed If non-NULL, will be set to the filename that the original + * is associated with. + */ +CINDEX_LINKAGE void clang_remap_getFilenames(CXRemapping, unsigned index, + CXString *original, CXString *transformed); + +/** + * \brief Dispose the remapping. + */ +CINDEX_LINKAGE void clang_remap_dispose(CXRemapping); + /** * @} */ diff --git a/include/clang/ARCMigrate/ARCMT.h b/include/clang/ARCMigrate/ARCMT.h new file mode 100644 index 000000000000..ad5cf4a2c16c --- /dev/null +++ b/include/clang/ARCMigrate/ARCMT.h @@ -0,0 +1,94 @@ +//===-- ARCMT.h - ARC Migration Rewriter ------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ARCMIGRATE_ARCMT_H +#define LLVM_CLANG_ARCMIGRATE_ARCMT_H + +#include "clang/ARCMigrate/FileRemapper.h" +#include "clang/Frontend/CompilerInvocation.h" + +namespace clang { + class ASTContext; + class DiagnosticClient; + +namespace arcmt { + class MigrationPass; + +/// \brief Creates an AST with the provided CompilerInvocation but with these +/// changes: +/// -if a PCH/PTH is set, the original header is used instead +/// -Automatic Reference Counting mode is enabled +/// +/// It then checks the AST and produces errors/warning for ARC migration issues +/// that the user needs to handle manually. +/// +/// \returns false if no error is produced, true otherwise. +bool checkForManualIssues(CompilerInvocation &CI, + llvm::StringRef Filename, InputKind Kind, + DiagnosticClient *DiagClient); + +/// \brief Works similar to checkForManualIssues but instead of checking, it +/// applies automatic modifications to source files to conform to ARC. +/// +/// \returns false if no error is produced, true otherwise. +bool applyTransformations(CompilerInvocation &origCI, + llvm::StringRef Filename, InputKind Kind, + DiagnosticClient *DiagClient); + +/// \brief Applies automatic modifications and produces temporary files +/// and metadata into the \arg outputDir path. +/// +/// \returns false if no error is produced, true otherwise. +bool migrateWithTemporaryFiles(CompilerInvocation &origCI, + llvm::StringRef Filename, InputKind Kind, + DiagnosticClient *DiagClient, + llvm::StringRef outputDir); + +/// \brief Get the set of file remappings from the \arg outputDir path that +/// migrateWithTemporaryFiles produced. +/// +/// \returns false if no error is produced, true otherwise. +bool getFileRemappings(std::vector > &remap, + llvm::StringRef outputDir, + DiagnosticClient *DiagClient); + +typedef void (*TransformFn)(MigrationPass &pass); + +std::vector getAllTransformations(); + +class MigrationProcess { + CompilerInvocation OrigCI; + DiagnosticClient *DiagClient; + FileRemapper Remapper; + +public: + MigrationProcess(const CompilerInvocation &CI, DiagnosticClient *diagClient, + llvm::StringRef outputDir = llvm::StringRef()); + + class RewriteListener { + public: + virtual ~RewriteListener(); + + virtual void start(ASTContext &Ctx) { } + virtual void finish() { } + + virtual void insert(SourceLocation loc, llvm::StringRef text) { } + virtual void remove(CharSourceRange range) { } + }; + + bool applyTransform(TransformFn trans, RewriteListener *listener = 0); + + FileRemapper &getRemapper() { return Remapper; } +}; + +} // end namespace arcmt + +} // end namespace clang + +#endif diff --git a/include/clang/ARCMigrate/ARCMTActions.h b/include/clang/ARCMigrate/ARCMTActions.h new file mode 100644 index 000000000000..4c714f55b390 --- /dev/null +++ b/include/clang/ARCMigrate/ARCMTActions.h @@ -0,0 +1,47 @@ +//===--- ARCMTActions.h - ARC Migrate Tool Frontend Actions -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ARCMIGRATE_ARCMT_ACTION_H +#define LLVM_CLANG_ARCMIGRATE_ARCMT_ACTION_H + +#include "clang/Frontend/FrontendAction.h" +#include "llvm/ADT/OwningPtr.h" + +namespace clang { +namespace arcmt { + +class CheckAction : public WrapperFrontendAction { +protected: + virtual bool BeginInvocation(CompilerInstance &CI); + +public: + CheckAction(FrontendAction *WrappedAction); +}; + +class ModifyAction : public WrapperFrontendAction { +protected: + virtual bool BeginInvocation(CompilerInstance &CI); + +public: + ModifyAction(FrontendAction *WrappedAction); +}; + +class MigrateAction : public WrapperFrontendAction { + std::string MigrateDir; +protected: + virtual bool BeginInvocation(CompilerInstance &CI); + +public: + MigrateAction(FrontendAction *WrappedAction, llvm::StringRef migrateDir); +}; + +} +} + +#endif diff --git a/include/clang/ARCMigrate/FileRemapper.h b/include/clang/ARCMigrate/FileRemapper.h new file mode 100644 index 000000000000..809f6a5f71be --- /dev/null +++ b/include/clang/ARCMigrate/FileRemapper.h @@ -0,0 +1,76 @@ +//===-- FileRemapper.h - File Remapping Helper ------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ARCMIGRATE_FILEREMAPPER_H +#define LLVM_CLANG_ARCMIGRATE_FILEREMAPPER_H + +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringRef.h" + +namespace llvm { + class MemoryBuffer; +} + +namespace clang { + class FileManager; + class FileEntry; + class Diagnostic; + class CompilerInvocation; + +namespace arcmt { + +class FileRemapper { + // FIXME: Reuse the same FileManager for multiple ASTContexts. + llvm::OwningPtr FileMgr; + + typedef llvm::PointerUnion Target; + typedef llvm::DenseMap MappingsTy; + MappingsTy FromToMappings; + + llvm::DenseMap ToFromMappings; + +public: + FileRemapper(); + ~FileRemapper(); + + bool initFromDisk(llvm::StringRef outputDir, Diagnostic &Diag, + bool ignoreIfFilesChanged); + bool flushToDisk(llvm::StringRef outputDir, Diagnostic &Diag); + + bool overwriteOriginal(Diagnostic &Diag, + llvm::StringRef outputDir = llvm::StringRef()); + + void remap(llvm::StringRef filePath, llvm::MemoryBuffer *memBuf); + void remap(llvm::StringRef filePath, llvm::StringRef newPath); + + void applyMappings(CompilerInvocation &CI) const; + + void transferMappingsAndClear(CompilerInvocation &CI); + + void clear(llvm::StringRef outputDir = llvm::StringRef()); + +private: + void remap(const FileEntry *file, llvm::MemoryBuffer *memBuf); + void remap(const FileEntry *file, const FileEntry *newfile); + + const FileEntry *getOriginalFile(llvm::StringRef filePath); + void resetTarget(Target &targ); + + bool report(const std::string &err, Diagnostic &Diag); + + std::string getRemapInfoFile(llvm::StringRef outputDir); +}; + +} // end namespace arcmt + +} // end namespace clang + +#endif diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 517c25df24bb..1526f36ba2fb 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -124,7 +124,10 @@ class ASTContext : public llvm::RefCountedBase { mutable llvm::FoldingSet QualifiedTemplateNames; mutable llvm::FoldingSet DependentTemplateNames; - mutable llvm::FoldingSet + mutable llvm::FoldingSet + SubstTemplateTemplateParms; + mutable llvm::ContextualFoldingSet SubstTemplateTemplateParmPacks; /// \brief The set of nested name specifiers. @@ -993,6 +996,18 @@ public: return getExtQualType(T, Qs); } + /// getLifetimeQualifiedType - Returns a type with the given + /// lifetime qualifier. + QualType getLifetimeQualifiedType(QualType type, + Qualifiers::ObjCLifetime lifetime) { + assert(type.getObjCLifetime() == Qualifiers::OCL_None); + assert(lifetime != Qualifiers::OCL_None); + + Qualifiers qs; + qs.addObjCLifetime(lifetime); + return getQualifiedType(type, qs); + } + DeclarationNameInfo getNameForTemplate(TemplateName Name, SourceLocation NameLoc) const; @@ -1007,6 +1022,8 @@ public: const IdentifierInfo *Name) const; TemplateName getDependentTemplateName(NestedNameSpecifier *NNS, OverloadedOperatorKind Operator) const; + TemplateName getSubstTemplateTemplateParm(TemplateTemplateParmDecl *param, + TemplateName replacement) const; TemplateName getSubstTemplateTemplateParmPack(TemplateTemplateParmDecl *Param, const TemplateArgument &ArgPack) const; @@ -1044,7 +1061,9 @@ public: /// isObjCNSObjectType - Return true if this is an NSObject object with /// its NSObject attribute set. - bool isObjCNSObjectType(QualType Ty) const; + static bool isObjCNSObjectType(QualType Ty) { + return Ty->isObjCNSObjectType(); + } //===--------------------------------------------------------------------===// // Type Sizing and Analysis @@ -1315,6 +1334,18 @@ public: /// getConstantArrayElementCount - Returns number of constant array elements. uint64_t getConstantArrayElementCount(const ConstantArrayType *CA) const; + /// \brief Perform adjustment on the parameter type of a function. + /// + /// This routine adjusts the given parameter type @p T to the actual + /// parameter type used by semantic analysis (C99 6.7.5.3p[7,8], + /// C++ [dcl.fct]p3). The adjusted parameter type is returned. + QualType getAdjustedParameterType(QualType T); + + /// \brief Retrieve the parameter type as adjusted for use in the signature + /// of a function, decaying array and function types and removing top-level + /// cv-qualifiers. + QualType getSignatureParameterType(QualType T); + /// 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, @@ -1328,6 +1359,10 @@ public: /// integer type. QualType getPromotedIntegerType(QualType PromotableType) const; + /// \brief Recurses in pointer/array types until it finds an objc retainable + /// type and returns its ownership. + Qualifiers::ObjCLifetime getInnerObjCOwnership(QualType T) const; + /// \brief Whether this is a promotable bitfield reference according /// to C99 6.3.1.1p2, bullet 2 (and GCC extensions). /// @@ -1382,6 +1417,7 @@ public: bool typesAreCompatible(QualType T1, QualType T2, bool CompareUnqualified = false); // C99 6.2.7p1 + bool propertyTypesAreCompatible(QualType, QualType); bool typesAreBlockPointerCompatible(QualType, QualType); bool isObjCIdType(QualType T) const { diff --git a/include/clang/AST/ASTDiagnostic.h b/include/clang/AST/ASTDiagnostic.h index 1cb803a3396a..70a548d4e965 100644 --- a/include/clang/AST/ASTDiagnostic.h +++ b/include/clang/AST/ASTDiagnostic.h @@ -33,16 +33,18 @@ namespace clang { /// diagnostics. It is meant to be used as the argument to /// \c Diagnostic::SetArgToStringFn(), where the cookie is an \c ASTContext /// pointer. - void FormatASTNodeDiagnosticArgument(Diagnostic::ArgumentKind Kind, - intptr_t Val, - const char *Modifier, - unsigned ModLen, - const char *Argument, - unsigned ArgLen, - const Diagnostic::ArgumentValue *PrevArgs, - unsigned NumPrevArgs, - llvm::SmallVectorImpl &Output, - void *Cookie); + void FormatASTNodeDiagnosticArgument( + Diagnostic::ArgumentKind Kind, + intptr_t Val, + const char *Modifier, + unsigned ModLen, + const char *Argument, + unsigned ArgLen, + const Diagnostic::ArgumentValue *PrevArgs, + unsigned NumPrevArgs, + llvm::SmallVectorImpl &Output, + void *Cookie, + llvm::SmallVectorImpl &QualTypeVals); } // end namespace clang #endif diff --git a/include/clang/AST/CanonicalType.h b/include/clang/AST/CanonicalType.h index 251881490499..38e6b41977f8 100644 --- a/include/clang/AST/CanonicalType.h +++ b/include/clang/AST/CanonicalType.h @@ -250,7 +250,6 @@ public: 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) @@ -295,6 +294,7 @@ public: LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isUnsignedIntegerOrEnumerationType) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isConstantSizeType) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isSpecifierType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(CXXRecordDecl*, getAsCXXRecordDecl) /// \brief Retrieve the proxy-adaptor type. /// diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index d993d345ef96..5691e99e7297 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -702,8 +702,12 @@ private: /// \brief Whether this variable is the for-range-declaration in a C++0x /// for-range statement. unsigned CXXForRangeDecl : 1; + + /// \brief Whether this variable is an ARC pseudo-__strong + /// variable; see isARCPseudoStrong() for details. + unsigned ARCPseudoStrong : 1; }; - enum { NumVarDeclBits = 13 }; // two reserved bits for now + enum { NumVarDeclBits = 13 }; // one reserved bit friend class ASTDeclReader; friend class StmtIteratorBase; @@ -975,6 +979,20 @@ public: void setInit(Expr *I); + /// \brief Determine whether this variable is a reference that + /// extends the lifetime of its temporary initializer. + /// + /// A reference extends the lifetime of its temporary initializer if + /// it's initializer is an rvalue that would normally go out of scope + /// at the end of the initializer (a full expression). In such cases, + /// the reference itself takes ownership of the temporary, which will + /// be destroyed when the reference goes out of scope. For example: + /// + /// \code + /// const int &r = 1.0; // creates a temporary of type 'int' + /// \endcode + bool extendsLifetimeOfTemporary() const; + EvaluatedStmt *EnsureEvaluatedStmt() const { EvaluatedStmt *Eval = Init.dyn_cast(); if (!Eval) { @@ -1102,6 +1120,13 @@ public: /// a C++0x for-range statement. bool isCXXForRangeDecl() const { return VarDeclBits.CXXForRangeDecl; } void setCXXForRangeDecl(bool FRD) { VarDeclBits.CXXForRangeDecl = FRD; } + + /// \brief Determine whether this variable is an ARC pseudo-__strong + /// variable. A pseudo-__strong variable has a __strong-qualified + /// type but does not actually retain the object written into it. + /// Generally such variables are also 'const' for safety. + bool isARCPseudoStrong() const { return VarDeclBits.ARCPseudoStrong; } + void setARCPseudoStrong(bool ps) { VarDeclBits.ARCPseudoStrong = ps; } /// \brief If this variable is an instantiated static data member of a /// class template specialization, returns the templated static data member @@ -2014,6 +2039,11 @@ public: InitializerOrBitWidth.setPointer(BW); InitializerOrBitWidth.setInt(1); } + /// removeBitWidth - Remove the bitfield width from this member. + void removeBitWidth() { + assert(isBitField() && "no bit width to remove"); + InitializerOrBitWidth.setPointer(0); + } /// hasInClassInitializer - Determine whether this member has a C++0x in-class /// initializer. @@ -2956,6 +2986,8 @@ public: bool capturesCXXThis() const { return CapturesCXXThis; } + bool capturesVariable(const VarDecl *var) const; + void setCaptures(ASTContext &Context, const Capture *begin, const Capture *end, diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index b5047b91c0e8..8b2ef2a81acb 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -381,7 +381,24 @@ public: attr_iterator attr_end() const { return hasAttrs() ? getAttrs().end() : 0; } - + + template + void dropAttr() { + if (!HasAttrs) return; + + AttrVec &Attrs = getAttrs(); + for (unsigned i = 0, e = Attrs.size(); i != e; /* in loop */) { + if (isa(Attrs[i])) { + Attrs.erase(Attrs.begin() + i); + --e; + } + else + ++i; + } + if (Attrs.empty()) + HasAttrs = false; + } + template specific_attr_iterator specific_attr_begin() const { return specific_attr_iterator(attr_begin()); diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 42a12eb5a34c..dd490f48c52c 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -19,7 +19,6 @@ #include "clang/AST/Decl.h" #include "clang/AST/TypeLoc.h" #include "clang/AST/UnresolvedSet.h" -#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallPtrSet.h" namespace clang { diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index 74ceb43c713c..d318fc27a8ba 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -641,6 +641,18 @@ public: return false; } + /// isArcWeakrefUnavailable - Checks for a class or one of its super classes + /// to be incompatible with __weak references. Returns true if it is. + bool isArcWeakrefUnavailable() const { + const ObjCInterfaceDecl *Class = this; + while (Class) { + if (Class->hasAttr()) + return true; + Class = Class->getSuperClass(); + } + return false; + } + ObjCIvarDecl *lookupInstanceVariable(IdentifierInfo *IVarName, ObjCInterfaceDecl *&ClassDeclared); ObjCIvarDecl *lookupInstanceVariable(IdentifierInfo *IVarName) { @@ -1240,6 +1252,9 @@ class ObjCImplementationDecl : public ObjCImplDecl { /// IvarInitializers - The arguments used to initialize the ivars CXXCtorInitializer **IvarInitializers; unsigned NumIvarInitializers; + + /// true if class has a .cxx_[construct,destruct] method. + bool HasCXXStructors : 1; /// true of class extension has at least one bitfield ivar. bool HasSynthBitfield : 1; @@ -1249,7 +1264,7 @@ class ObjCImplementationDecl : public ObjCImplDecl { ObjCInterfaceDecl *superDecl) : ObjCImplDecl(ObjCImplementation, DC, L, classInterface), SuperClass(superDecl), IvarInitializers(0), NumIvarInitializers(0), - HasSynthBitfield(false) {} + HasCXXStructors(false), HasSynthBitfield(false) {} public: static ObjCImplementationDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, @@ -1287,6 +1302,9 @@ public: void setIvarInitializers(ASTContext &C, CXXCtorInitializer ** initializers, unsigned numInitializers); + + bool hasCXXStructors() const { return HasCXXStructors; } + void setHasCXXStructors(bool val) { HasCXXStructors = val; } bool hasSynthBitfield() const { return HasSynthBitfield; } void setHasSynthBitfield (bool val) { HasSynthBitfield = val; } @@ -1393,7 +1411,16 @@ public: OBJC_PR_copy = 0x20, OBJC_PR_nonatomic = 0x40, OBJC_PR_setter = 0x80, - OBJC_PR_atomic = 0x100 + OBJC_PR_atomic = 0x100, + OBJC_PR_weak = 0x200, + OBJC_PR_strong = 0x400, + OBJC_PR_unsafe_unretained = 0x800 + // Adding a property should change NumPropertyAttrsBits + }; + + enum { + /// \brief Number of bits fitting all the property attributes. + NumPropertyAttrsBits = 12 }; enum SetterKind { Assign, Retain, Copy }; @@ -1401,8 +1428,8 @@ public: private: SourceLocation AtLoc; // location of @property TypeSourceInfo *DeclType; - unsigned PropertyAttributes : 9; - unsigned PropertyAttributesAsWritten : 9; + unsigned PropertyAttributes : NumPropertyAttrsBits; + unsigned PropertyAttributesAsWritten : NumPropertyAttrsBits; // @required/@optional unsigned PropertyImplementation : 2; @@ -1445,6 +1472,12 @@ public: PropertyAttributeKind getPropertyAttributesAsWritten() const { return PropertyAttributeKind(PropertyAttributesAsWritten); } + + bool hasWrittenStorageAttribute() const { + return PropertyAttributesAsWritten & (OBJC_PR_assign | OBJC_PR_copy | + OBJC_PR_unsafe_unretained | OBJC_PR_retain | OBJC_PR_strong | + OBJC_PR_weak); + } void setPropertyAttributesAsWritten(PropertyAttributeKind PRVal) { PropertyAttributesAsWritten = PRVal; @@ -1466,7 +1499,7 @@ public: /// the property setter. This is only valid if the property has been /// defined to have a setter. SetterKind getSetterKind() const { - if (PropertyAttributes & OBJC_PR_retain) + if (PropertyAttributes & (OBJC_PR_retain|OBJC_PR_strong)) return Retain; if (PropertyAttributes & OBJC_PR_copy) return Copy; diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index dc50d614bf7c..d2b1d3990c66 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -314,6 +314,10 @@ public: return (TemplateSpecializationKind)(Template.getInt() + 1); } + bool isExplicitSpecialization() const { + return getTemplateSpecializationKind() == TSK_ExplicitSpecialization; + } + /// \brief Set the template specialization kind. void setTemplateSpecializationKind(TemplateSpecializationKind TSK) { assert(TSK != TSK_Undeclared && @@ -1398,6 +1402,10 @@ public: return static_cast(SpecializationKind); } + bool isExplicitSpecialization() const { + return getSpecializationKind() == TSK_ExplicitSpecialization; + } + void setSpecializationKind(TemplateSpecializationKind TSK) { SpecializationKind = TSK; } diff --git a/include/clang/AST/DeclarationName.h b/include/clang/AST/DeclarationName.h index e54719b33d30..bb098313ea3a 100644 --- a/include/clang/AST/DeclarationName.h +++ b/include/clang/AST/DeclarationName.h @@ -492,6 +492,9 @@ public: LocInfo.CXXLiteralOperatorName.OpNameLoc = Loc.getRawEncoding(); } + /// \brief Determine whether this name involves a template parameter. + bool isInstantiationDependent() const; + /// \brief Determine whether this name contains an unexpanded /// parameter pack. bool containsUnexpandedParameterPack() const; diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index ce86458ed4f4..c7f870725c42 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -57,9 +57,12 @@ class Expr : public Stmt { protected: Expr(StmtClass SC, QualType T, ExprValueKind VK, ExprObjectKind OK, - bool TD, bool VD, bool ContainsUnexpandedParameterPack) : Stmt(SC) { + bool TD, bool VD, bool ID, bool ContainsUnexpandedParameterPack) + : Stmt(SC) + { ExprBits.TypeDependent = TD; ExprBits.ValueDependent = VD; + ExprBits.InstantiationDependent = ID; ExprBits.ValueKind = VK; ExprBits.ObjectKind = OK; ExprBits.ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack; @@ -95,7 +98,11 @@ public: bool isValueDependent() const { return ExprBits.ValueDependent; } /// \brief Set whether this expression is value-dependent or not. - void setValueDependent(bool VD) { ExprBits.ValueDependent = VD; } + void setValueDependent(bool VD) { + ExprBits.ValueDependent = VD; + if (VD) + ExprBits.InstantiationDependent = true; + } /// isTypeDependent - Determines whether this expression is /// type-dependent (C++ [temp.dep.expr]), which means that its type @@ -111,7 +118,37 @@ public: bool isTypeDependent() const { return ExprBits.TypeDependent; } /// \brief Set whether this expression is type-dependent or not. - void setTypeDependent(bool TD) { ExprBits.TypeDependent = TD; } + void setTypeDependent(bool TD) { + ExprBits.TypeDependent = TD; + if (TD) + ExprBits.InstantiationDependent = true; + } + + /// \brief Whether this expression is instantiation-dependent, meaning that + /// it depends in some way on a template parameter, even if neither its type + /// nor (constant) value can change due to the template instantiation. + /// + /// In the following example, the expression \c sizeof(sizeof(T() + T())) is + /// instantiation-dependent (since it involves a template parameter \c T), but + /// is neither type- nor value-dependent, since the type of the inner + /// \c sizeof is known (\c std::size_t) and therefore the size of the outer + /// \c sizeof is known. + /// + /// \code + /// template + /// void f(T x, T y) { + /// sizeof(sizeof(T() + T()); + /// } + /// \endcode + /// + bool isInstantiationDependent() const { + return ExprBits.InstantiationDependent; + } + + /// \brief Set whether this expression is instantiation-dependent or not. + void setInstantiationDependent(bool ID) { + ExprBits.InstantiationDependent = ID; + } /// \brief Whether this expression contains an unexpanded parameter /// pack (for C++0x variadic templates). @@ -501,6 +538,14 @@ public: /// the rules of C++ [expr.unary.noexcept]. CanThrowResult CanThrow(ASTContext &C) const; + /// IgnoreImpCasts - Skip past any implicit casts which might + /// surround this expression. Only skips ImplicitCastExprs. + Expr *IgnoreImpCasts(); + + /// IgnoreImplicit - Skip past any implicit AST nodes which might + /// surround this expression. + Expr *IgnoreImplicit() { return cast(Stmt::IgnoreImplicit()); } + /// IgnoreParens - Ignore parentheses. If this Expr is a ParenExpr, return /// its subexpression. If that subexpression is also a ParenExpr, /// then this method recursively returns its subexpression, and so forth. @@ -555,7 +600,10 @@ public: /// \brief Whether this expression is an implicit reference to 'this' in C++. bool isImplicitCXXThis() const; - + + const Expr *IgnoreImpCasts() const { + return const_cast(this)->IgnoreImpCasts(); + } const Expr *IgnoreParens() const { return const_cast(this)->IgnoreParens(); } @@ -595,7 +643,9 @@ public: OpaqueValueExpr(SourceLocation Loc, QualType T, ExprValueKind VK, ExprObjectKind OK = OK_Ordinary) : Expr(OpaqueValueExprClass, T, VK, OK, - T->isDependentType(), T->isDependentType(), false), + T->isDependentType(), T->isDependentType(), + T->isInstantiationDependentType(), + false), SourceExpr(0), Loc(Loc) { } @@ -664,7 +714,8 @@ struct ExplicitTemplateArgumentList { void initializeFrom(const TemplateArgumentListInfo &List); void initializeFrom(const TemplateArgumentListInfo &List, - bool &Dependent, bool &ContainsUnexpandedParameterPack); + bool &Dependent, bool &InstantiationDependent, + bool &ContainsUnexpandedParameterPack); void copyInto(TemplateArgumentListInfo &List) const; static std::size_t sizeFor(unsigned NumTemplateArgs); static std::size_t sizeFor(const TemplateArgumentListInfo &List); @@ -746,9 +797,10 @@ class DeclRefExpr : public Expr { void computeDependence(); public: - DeclRefExpr(ValueDecl *D, QualType T, ExprValueKind VK, SourceLocation L) - : Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false), - D(D), Loc(L) { + DeclRefExpr(ValueDecl *D, QualType T, ExprValueKind VK, SourceLocation L, + const DeclarationNameLoc &LocInfo = DeclarationNameLoc()) + : Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false, false), + D(D), Loc(L), DNLoc(LocInfo) { DeclRefExprBits.HasQualifier = 0; DeclRefExprBits.HasExplicitTemplateArgs = 0; DeclRefExprBits.HasFoundDecl = 0; @@ -936,6 +988,7 @@ public: PredefinedExpr(SourceLocation l, QualType type, IdentType IT) : Expr(PredefinedExprClass, type, VK_LValue, OK_Ordinary, type->isDependentType(), type->isDependentType(), + type->isInstantiationDependentType(), /*ContainsUnexpandedParameterPack=*/false), Loc(l), Type(IT) {} @@ -1023,7 +1076,7 @@ public: IntegerLiteral(ASTContext &C, const llvm::APInt &V, QualType type, SourceLocation l) : Expr(IntegerLiteralClass, type, VK_RValue, OK_Ordinary, false, false, - false), + false, false), Loc(l) { assert(type->isIntegerType() && "Illegal type in IntegerLiteral"); assert(V.getBitWidth() == C.getIntWidth(type) && @@ -1066,7 +1119,7 @@ public: // type should be IntTy CharacterLiteral(unsigned value, bool iswide, QualType type, SourceLocation l) : Expr(CharacterLiteralClass, type, VK_RValue, OK_Ordinary, false, false, - false), + false, false), Value(value), Loc(l), IsWide(iswide) { } @@ -1101,7 +1154,7 @@ class FloatingLiteral : public Expr { FloatingLiteral(ASTContext &C, const llvm::APFloat &V, bool isexact, QualType Type, SourceLocation L) : Expr(FloatingLiteralClass, Type, VK_RValue, OK_Ordinary, false, false, - false), + false, false), IsExact(isexact), Loc(L) { setValue(C, V); } @@ -1152,7 +1205,7 @@ class ImaginaryLiteral : public Expr { public: ImaginaryLiteral(Expr *val, QualType Ty) : Expr(ImaginaryLiteralClass, Ty, VK_RValue, OK_Ordinary, false, false, - false), + false, false), Val(val) {} /// \brief Build an empty imaginary literal. @@ -1200,21 +1253,20 @@ class StringLiteral : public Expr { SourceLocation TokLocs[1]; StringLiteral(QualType Ty) : - Expr(StringLiteralClass, Ty, VK_LValue, OK_Ordinary, false, false, false) {} + Expr(StringLiteralClass, Ty, VK_LValue, OK_Ordinary, false, false, false, + false) {} public: /// This is the "fully general" constructor that allows representation of /// strings formed from multiple concatenated tokens. - static StringLiteral *Create(ASTContext &C, const char *StrData, - unsigned ByteLength, bool Wide, bool Pascal, - QualType Ty, + static StringLiteral *Create(ASTContext &C, llvm::StringRef Str, bool Wide, + bool Pascal, QualType Ty, const SourceLocation *Loc, unsigned NumStrs); /// Simple constructor for string literals made from one token. - static StringLiteral *Create(ASTContext &C, const char *StrData, - unsigned ByteLength, bool Wide, + static StringLiteral *Create(ASTContext &C, llvm::StringRef Str, bool Wide, bool Pascal, QualType Ty, SourceLocation Loc) { - return Create(C, StrData, ByteLength, Wide, Pascal, Ty, &Loc, 1); + return Create(C, Str, Wide, Pascal, Ty, &Loc, 1); } /// \brief Construct an empty string literal. @@ -1289,6 +1341,7 @@ public: : Expr(ParenExprClass, val->getType(), val->getValueKind(), val->getObjectKind(), val->isTypeDependent(), val->isValueDependent(), + val->isInstantiationDependent(), val->containsUnexpandedParameterPack()), L(l), R(r), Val(val) {} @@ -1345,6 +1398,8 @@ public: : Expr(UnaryOperatorClass, type, VK, OK, input->isTypeDependent() || type->isDependentType(), input->isValueDependent(), + (input->isInstantiationDependent() || + type->isInstantiationDependentType()), input->containsUnexpandedParameterPack()), Opc(opc), Loc(l), Val(input) {} @@ -1640,6 +1695,7 @@ public: false, // Never type-dependent (C++ [temp.dep.expr]p3). // Value-dependent if the argument is type-dependent. TInfo->getType()->isDependentType(), + TInfo->getType()->isInstantiationDependentType(), TInfo->getType()->containsUnexpandedParameterPack()), Kind(ExprKind), isType(true), OpLoc(op), RParenLoc(rp) { Argument.Ty = TInfo; @@ -1652,6 +1708,7 @@ public: false, // Never type-dependent (C++ [temp.dep.expr]p3). // Value-dependent if the argument is type-dependent. E->isTypeDependent(), + E->isInstantiationDependent(), E->containsUnexpandedParameterPack()), Kind(ExprKind), isType(false), OpLoc(op), RParenLoc(rp) { Argument.Ex = E; @@ -1729,6 +1786,8 @@ public: : Expr(ArraySubscriptExprClass, t, VK, OK, lhs->isTypeDependent() || rhs->isTypeDependent(), lhs->isValueDependent() || rhs->isValueDependent(), + (lhs->isInstantiationDependent() || + rhs->isInstantiationDependent()), (lhs->containsUnexpandedParameterPack() || rhs->containsUnexpandedParameterPack())), RBracketLoc(rbracketloc) { @@ -1986,7 +2045,9 @@ public: const DeclarationNameInfo &NameInfo, QualType ty, ExprValueKind VK, ExprObjectKind OK) : Expr(MemberExprClass, ty, VK, OK, - base->isTypeDependent(), base->isValueDependent(), + base->isTypeDependent(), + base->isValueDependent(), + base->isInstantiationDependent(), base->containsUnexpandedParameterPack()), Base(base), MemberDecl(memberdecl), MemberLoc(NameInfo.getLoc()), MemberDNLoc(NameInfo.getInfo()), IsArrow(isarrow), @@ -2003,6 +2064,7 @@ public: ExprValueKind VK, ExprObjectKind OK) : Expr(MemberExprClass, ty, VK, OK, base->isTypeDependent(), base->isValueDependent(), + base->isInstantiationDependent(), base->containsUnexpandedParameterPack()), Base(base), MemberDecl(memberdecl), MemberLoc(l), MemberDNLoc(), IsArrow(isarrow), @@ -2188,6 +2250,8 @@ public: : Expr(CompoundLiteralExprClass, T, VK, OK_Ordinary, tinfo->getType()->isDependentType(), init->isValueDependent(), + (init->isInstantiationDependent() || + tinfo->getType()->isInstantiationDependentType()), init->containsUnexpandedParameterPack()), LParenLoc(lparenloc), TInfo(tinfo), Init(init), FileScope(fileScope) {} @@ -2276,6 +2340,9 @@ private: case CK_IntegralComplexToReal: case CK_IntegralComplexCast: case CK_IntegralComplexToFloatingComplex: + case CK_ObjCProduceObject: + case CK_ObjCConsumeObject: + case CK_ObjCReclaimReturnedObject: assert(!getType()->isBooleanType() && "unheralded conversion to bool"); // fallthrough to check for null base path @@ -2318,6 +2385,8 @@ protected: // Cast expressions are value-dependent if the type is // dependent or if the subexpression is value-dependent. ty->isDependentType() || (op && op->isValueDependent()), + (ty->isInstantiationDependentType() || + (op && op->isInstantiationDependent())), (ty->containsUnexpandedParameterPack() || op->containsUnexpandedParameterPack())), Op(op) { @@ -2426,6 +2495,13 @@ public: static bool classof(const ImplicitCastExpr *) { return true; } }; +inline Expr *Expr::IgnoreImpCasts() { + Expr *e = this; + while (ImplicitCastExpr *ice = dyn_cast(e)) + e = ice->getSubExpr(); + return e; +} + /// ExplicitCastExpr - An explicit cast written in the source /// code. /// @@ -2551,6 +2627,8 @@ public: : Expr(BinaryOperatorClass, ResTy, VK, OK, lhs->isTypeDependent() || rhs->isTypeDependent(), lhs->isValueDependent() || rhs->isValueDependent(), + (lhs->isInstantiationDependent() || + rhs->isInstantiationDependent()), (lhs->containsUnexpandedParameterPack() || rhs->containsUnexpandedParameterPack())), Opc(opc), OpLoc(opLoc) { @@ -2653,6 +2731,8 @@ protected: : Expr(CompoundAssignOperatorClass, ResTy, VK, OK, lhs->isTypeDependent() || rhs->isTypeDependent(), lhs->isValueDependent() || rhs->isValueDependent(), + (lhs->isInstantiationDependent() || + rhs->isInstantiationDependent()), (lhs->containsUnexpandedParameterPack() || rhs->containsUnexpandedParameterPack())), Opc(opc), OpLoc(opLoc) { @@ -2713,11 +2793,11 @@ class AbstractConditionalOperator : public Expr { protected: AbstractConditionalOperator(StmtClass SC, QualType T, ExprValueKind VK, ExprObjectKind OK, - bool TD, bool VD, + bool TD, bool VD, bool ID, bool ContainsUnexpandedParameterPack, SourceLocation qloc, SourceLocation cloc) - : Expr(SC, T, VK, OK, TD, VD, ContainsUnexpandedParameterPack), + : Expr(SC, T, VK, OK, TD, VD, ID, ContainsUnexpandedParameterPack), QuestionLoc(qloc), ColonLoc(cloc) {} AbstractConditionalOperator(StmtClass SC, EmptyShell Empty) @@ -2765,6 +2845,9 @@ public: (lhs->isTypeDependent() || rhs->isTypeDependent()), (cond->isValueDependent() || lhs->isValueDependent() || rhs->isValueDependent()), + (cond->isInstantiationDependent() || + lhs->isInstantiationDependent() || + rhs->isInstantiationDependent()), (cond->containsUnexpandedParameterPack() || lhs->containsUnexpandedParameterPack() || rhs->containsUnexpandedParameterPack()), @@ -2833,6 +2916,8 @@ public: : AbstractConditionalOperator(BinaryConditionalOperatorClass, t, VK, OK, (common->isTypeDependent() || rhs->isTypeDependent()), (common->isValueDependent() || rhs->isValueDependent()), + (common->isInstantiationDependent() || + rhs->isInstantiationDependent()), (common->containsUnexpandedParameterPack() || rhs->containsUnexpandedParameterPack()), qloc, cloc), @@ -2914,7 +2999,8 @@ class AddrLabelExpr : public Expr { public: AddrLabelExpr(SourceLocation AALoc, SourceLocation LLoc, LabelDecl *L, QualType t) - : Expr(AddrLabelExprClass, t, VK_RValue, OK_Ordinary, false, false, false), + : Expr(AddrLabelExprClass, t, VK_RValue, OK_Ordinary, false, false, false, + false), AmpAmpLoc(AALoc), LabelLoc(LLoc), Label(L) {} /// \brief Build an empty address of a label expression. @@ -2953,10 +3039,12 @@ class StmtExpr : public Expr { SourceLocation LParenLoc, RParenLoc; public: // FIXME: Does type-dependence need to be computed differently? + // FIXME: Do we need to compute instantiation instantiation-dependence for + // statements? (ugh!) StmtExpr(CompoundStmt *substmt, QualType T, SourceLocation lp, SourceLocation rp) : Expr(StmtExprClass, T, VK_RValue, OK_Ordinary, - T->isDependentType(), false, false), + T->isDependentType(), false, false, false), SubStmt(substmt), LParenLoc(lp), RParenLoc(rp) { } /// \brief Build an empty statement expression. @@ -3073,6 +3161,9 @@ public: QualType t, ExprValueKind VK, ExprObjectKind OK, SourceLocation RP, bool TypeDependent, bool ValueDependent) : Expr(ChooseExprClass, t, VK, OK, TypeDependent, ValueDependent, + (cond->isInstantiationDependent() || + lhs->isInstantiationDependent() || + rhs->isInstantiationDependent()), (cond->containsUnexpandedParameterPack() || lhs->containsUnexpandedParameterPack() || rhs->containsUnexpandedParameterPack())), @@ -3134,7 +3225,8 @@ class GNUNullExpr : public Expr { public: GNUNullExpr(QualType Ty, SourceLocation Loc) - : Expr(GNUNullExprClass, Ty, VK_RValue, OK_Ordinary, false, false, false), + : Expr(GNUNullExprClass, Ty, VK_RValue, OK_Ordinary, false, false, false, + false), TokenLoc(Loc) { } /// \brief Build an empty GNU __null expression. @@ -3166,6 +3258,8 @@ public: SourceLocation RPLoc, QualType t) : Expr(VAArgExprClass, t, VK_RValue, OK_Ordinary, t->isDependentType(), false, + (TInfo->getType()->isInstantiationDependentType() || + e->isInstantiationDependent()), (TInfo->getType()->containsUnexpandedParameterPack() || e->containsUnexpandedParameterPack())), Val(e), TInfo(TInfo), @@ -3537,9 +3631,9 @@ public: bool isArrayDesignator() const { return Kind == ArrayDesignator; } bool isArrayRangeDesignator() const { return Kind == ArrayRangeDesignator; } - IdentifierInfo * getFieldName(); + IdentifierInfo *getFieldName() const; - FieldDecl *getField() { + FieldDecl *getField() const { assert(Kind == FieldDesignator && "Only valid on a field designator"); if (Field.NameOrField & 0x01) return 0; @@ -3612,12 +3706,18 @@ public: unsigned size() const { return NumDesignators; } // Iterator access to the designators. - typedef Designator* designators_iterator; + typedef Designator *designators_iterator; designators_iterator designators_begin() { return Designators; } designators_iterator designators_end() { return Designators + NumDesignators; } + typedef const Designator *const_designators_iterator; + const_designators_iterator designators_begin() const { return Designators; } + const_designators_iterator designators_end() const { + return Designators + NumDesignators; + } + typedef std::reverse_iterator reverse_designators_iterator; reverse_designators_iterator designators_rbegin() { @@ -3627,6 +3727,15 @@ public: return reverse_designators_iterator(designators_begin()); } + typedef std::reverse_iterator + const_reverse_designators_iterator; + const_reverse_designators_iterator designators_rbegin() const { + return const_reverse_designators_iterator(designators_end()); + } + const_reverse_designators_iterator designators_rend() const { + return const_reverse_designators_iterator(designators_begin()); + } + Designator *getDesignator(unsigned Idx) { return &designators_begin()[Idx]; } void setDesignators(ASTContext &C, const Designator *Desigs, @@ -3708,7 +3817,7 @@ class ImplicitValueInitExpr : public Expr { public: explicit ImplicitValueInitExpr(QualType ty) : Expr(ImplicitValueInitExprClass, ty, VK_RValue, OK_Ordinary, - false, false, false) { } + false, false, ty->isInstantiationDependentType(), false) { } /// \brief Construct an empty implicit value initialization. explicit ImplicitValueInitExpr(EmptyShell Empty) @@ -3735,7 +3844,7 @@ class ParenListExpr : public Expr { public: ParenListExpr(ASTContext& C, SourceLocation lparenloc, Expr **exprs, - unsigned numexprs, SourceLocation rparenloc); + unsigned numexprs, SourceLocation rparenloc, QualType T); /// \brief Build an empty paren list. explicit ParenListExpr(EmptyShell Empty) : Expr(ParenListExprClass, Empty) { } @@ -3909,6 +4018,7 @@ public: : Expr(ExtVectorElementExprClass, ty, VK, (VK == VK_RValue ? OK_Ordinary : OK_VectorComponent), base->isTypeDependent(), base->isValueDependent(), + base->isInstantiationDependent(), base->containsUnexpandedParameterPack()), Base(base), Accessor(&accessor), AccessorLoc(loc) {} @@ -3963,7 +4073,10 @@ protected: public: BlockExpr(BlockDecl *BD, QualType ty) : Expr(BlockExprClass, ty, VK_RValue, OK_Ordinary, - ty->isDependentType(), false, false), + ty->isDependentType(), false, + // FIXME: Check for instantiate-dependence in the statement? + ty->isInstantiationDependentType(), + false), TheBlock(BD) {} /// \brief Build an empty block expression. @@ -4037,26 +4150,36 @@ public: /// AsTypeExpr - Clang builtin function __builtin_astype [OpenCL 6.2.4.2] /// This AST node provides support for reinterpreting a type to another /// type of the same size. -class AsTypeExpr : public Expr { +class AsTypeExpr : public Expr { // Should this be an ExplicitCastExpr? private: - Expr* SrcExpr; - QualType DstType; + Stmt *SrcExpr; SourceLocation BuiltinLoc, RParenLoc; + + friend class ASTReader; + friend class ASTStmtReader; + explicit AsTypeExpr(EmptyShell Empty) : Expr(AsTypeExprClass, Empty) {} public: AsTypeExpr(Expr* SrcExpr, QualType DstType, ExprValueKind VK, ExprObjectKind OK, SourceLocation BuiltinLoc, SourceLocation RParenLoc) - : Expr(AsTypeExprClass, DstType, VK, OK, false, false, false), - SrcExpr(SrcExpr), DstType(DstType), - BuiltinLoc(BuiltinLoc), RParenLoc(RParenLoc) {} - - /// \brief Build an empty __builtin_astype - explicit AsTypeExpr(EmptyShell Empty) : Expr(AsTypeExprClass, Empty) {} + : Expr(AsTypeExprClass, DstType, VK, OK, + DstType->isDependentType(), + DstType->isDependentType() || SrcExpr->isValueDependent(), + (DstType->isInstantiationDependentType() || + SrcExpr->isInstantiationDependent()), + (DstType->containsUnexpandedParameterPack() || + SrcExpr->containsUnexpandedParameterPack())), + SrcExpr(SrcExpr), BuiltinLoc(BuiltinLoc), RParenLoc(RParenLoc) {} /// getSrcExpr - Return the Expr to be converted. - Expr *getSrcExpr() const { return SrcExpr; } - QualType getDstType() const { return DstType; } + Expr *getSrcExpr() const { return cast(SrcExpr); } + + /// getBuiltinLoc - Return the location of the __builtin_astype token. + SourceLocation getBuiltinLoc() const { return BuiltinLoc; } + + /// getRParenLoc - Return the location of final right parenthesis. + SourceLocation getRParenLoc() const { return RParenLoc; } SourceRange getSourceRange() const { return SourceRange(BuiltinLoc, RParenLoc); @@ -4068,7 +4191,7 @@ public: static bool classof(const AsTypeExpr *) { return true; } // Iterators - child_range children() { return child_range(); } + child_range children() { return child_range(&SrcExpr, &SrcExpr+1); } }; } // end namespace clang diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index a97057973745..19117040ef96 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -330,7 +330,7 @@ class CXXBoolLiteralExpr : public Expr { public: CXXBoolLiteralExpr(bool val, QualType Ty, SourceLocation l) : Expr(CXXBoolLiteralExprClass, Ty, VK_RValue, OK_Ordinary, false, false, - false), + false, false), Value(val), Loc(l) {} explicit CXXBoolLiteralExpr(EmptyShell Empty) @@ -359,7 +359,7 @@ class CXXNullPtrLiteralExpr : public Expr { public: CXXNullPtrLiteralExpr(QualType Ty, SourceLocation l) : Expr(CXXNullPtrLiteralExprClass, Ty, VK_RValue, OK_Ordinary, false, false, - false), + false, false), Loc(l) {} explicit CXXNullPtrLiteralExpr(EmptyShell Empty) @@ -395,6 +395,7 @@ public: false, // typeid is value-dependent if the type or expression are dependent Operand->getType()->isDependentType(), + Operand->getType()->isInstantiationDependentType(), Operand->getType()->containsUnexpandedParameterPack()), Operand(Operand), Range(R) { } @@ -404,6 +405,7 @@ public: false, // typeid is value-dependent if the type or expression are dependent Operand->isTypeDependent() || Operand->isValueDependent(), + Operand->isInstantiationDependent(), Operand->containsUnexpandedParameterPack()), Operand(Operand), Range(R) { } @@ -471,12 +473,14 @@ public: CXXUuidofExpr(QualType Ty, TypeSourceInfo *Operand, SourceRange R) : Expr(CXXUuidofExprClass, Ty, VK_LValue, OK_Ordinary, false, Operand->getType()->isDependentType(), + Operand->getType()->isInstantiationDependentType(), Operand->getType()->containsUnexpandedParameterPack()), Operand(Operand), Range(R) { } CXXUuidofExpr(QualType Ty, Expr *Operand, SourceRange R) : Expr(CXXUuidofExprClass, Ty, VK_LValue, OK_Ordinary, false, Operand->isTypeDependent(), + Operand->isInstantiationDependent(), Operand->containsUnexpandedParameterPack()), Operand(Operand), Range(R) { } @@ -552,6 +556,7 @@ public: // 'this' is type-dependent if the class type of the enclosing // member function is dependent (C++ [temp.dep.expr]p2) Type->isDependentType(), Type->isDependentType(), + Type->isInstantiationDependentType(), /*ContainsUnexpandedParameterPack=*/false), Loc(L), Implicit(isImplicit) { } @@ -581,23 +586,35 @@ public: class CXXThrowExpr : public Expr { Stmt *Op; SourceLocation ThrowLoc; + /// \brief Whether the thrown variable (if any) is in scope. + unsigned IsThrownVariableInScope : 1; + + friend class ASTStmtReader; + public: // Ty is the void type which is used as the result type of the // exepression. The l is the location of the throw keyword. expr // can by null, if the optional expression to throw isn't present. - CXXThrowExpr(Expr *expr, QualType Ty, SourceLocation l) : + CXXThrowExpr(Expr *expr, QualType Ty, SourceLocation l, + bool IsThrownVariableInScope) : Expr(CXXThrowExprClass, Ty, VK_RValue, OK_Ordinary, false, false, + expr && expr->isInstantiationDependent(), expr && expr->containsUnexpandedParameterPack()), - Op(expr), ThrowLoc(l) {} + Op(expr), ThrowLoc(l), IsThrownVariableInScope(IsThrownVariableInScope) {} CXXThrowExpr(EmptyShell Empty) : Expr(CXXThrowExprClass, Empty) {} const Expr *getSubExpr() const { return cast_or_null(Op); } Expr *getSubExpr() { return cast_or_null(Op); } - void setSubExpr(Expr *E) { Op = E; } SourceLocation getThrowLoc() const { return ThrowLoc; } - void setThrowLoc(SourceLocation L) { ThrowLoc = L; } + /// \brief Determines whether the variable thrown by this expression (if any!) + /// is within the innermost try block. + /// + /// This information is required to determine whether the NRVO can apply to + /// this variable. + bool isThrownVariableInScope() const { return IsThrownVariableInScope; } + SourceRange getSourceRange() const { if (getSubExpr() == 0) return SourceRange(ThrowLoc, ThrowLoc); @@ -636,14 +653,14 @@ class CXXDefaultArgExpr : public Expr { ? param->getType().getNonReferenceType() : param->getDefaultArg()->getType(), param->getDefaultArg()->getValueKind(), - param->getDefaultArg()->getObjectKind(), false, false, false), + param->getDefaultArg()->getObjectKind(), false, false, false, false), Param(param, false), Loc(Loc) { } CXXDefaultArgExpr(StmtClass SC, SourceLocation Loc, ParmVarDecl *param, Expr *SubExpr) : Expr(SC, SubExpr->getType(), SubExpr->getValueKind(), SubExpr->getObjectKind(), - false, false, false), + false, false, false, false), Param(param, true), Loc(Loc) { *reinterpret_cast(this + 1) = SubExpr; } @@ -742,6 +759,7 @@ class CXXBindTemporaryExpr : public Expr { : Expr(CXXBindTemporaryExprClass, SubExpr->getType(), VK_RValue, OK_Ordinary, SubExpr->isTypeDependent(), SubExpr->isValueDependent(), + SubExpr->isInstantiationDependent(), SubExpr->containsUnexpandedParameterPack()), Temp(temp), SubExpr(SubExpr) { } @@ -995,7 +1013,7 @@ public: TypeSourceInfo *TypeInfo, SourceLocation rParenLoc ) : Expr(CXXScalarValueInitExprClass, Type, VK_RValue, OK_Ordinary, - false, false, false), + false, false, Type->isInstantiationDependentType(), false), RParenLoc(rParenLoc), TypeInfo(TypeInfo) {} explicit CXXScalarValueInitExpr(EmptyShell Shell) @@ -1241,6 +1259,7 @@ public: bool arrayFormAsWritten, bool usualArrayDeleteWantsSize, FunctionDecl *operatorDelete, Expr *arg, SourceLocation loc) : Expr(CXXDeleteExprClass, ty, VK_RValue, OK_Ordinary, false, false, + arg->isInstantiationDependent(), arg->containsUnexpandedParameterPack()), GlobalDelete(globalDelete), ArrayForm(arrayForm), ArrayFormAsWritten(arrayFormAsWritten), @@ -1500,6 +1519,7 @@ public: SourceLocation rparen, QualType ty) : Expr(UnaryTypeTraitExprClass, ty, VK_RValue, OK_Ordinary, false, queried->getType()->isDependentType(), + queried->getType()->isInstantiationDependentType(), queried->getType()->containsUnexpandedParameterPack()), UTT(utt), Value(value), Loc(loc), RParen(rparen), QueriedType(queried) { } @@ -1558,6 +1578,8 @@ public: : Expr(BinaryTypeTraitExprClass, ty, VK_RValue, OK_Ordinary, false, lhsType->getType()->isDependentType() || rhsType->getType()->isDependentType(), + (lhsType->getType()->isInstantiationDependentType() || + rhsType->getType()->isInstantiationDependentType()), (lhsType->getType()->containsUnexpandedParameterPack() || rhsType->getType()->containsUnexpandedParameterPack())), BTT(btt), Value(value), Loc(loc), RParen(rparen), @@ -1625,6 +1647,8 @@ public: Expr *dimension, SourceLocation rparen, QualType ty) : Expr(ArrayTypeTraitExprClass, ty, VK_RValue, OK_Ordinary, false, queried->getType()->isDependentType(), + (queried->getType()->isInstantiationDependentType() || + (dimension && dimension->isInstantiationDependent())), queried->getType()->containsUnexpandedParameterPack()), ATT(att), Value(value), Dimension(dimension), Loc(loc), RParen(rparen), QueriedType(queried) { } @@ -1684,6 +1708,7 @@ public: false, // Not type-dependent // Value-dependent if the argument is type-dependent. queried->isTypeDependent(), + queried->isInstantiationDependent(), queried->containsUnexpandedParameterPack()), ET(et), Value(value), Loc(loc), RParen(rparen), QueriedExpression(queried) { } @@ -1736,8 +1761,9 @@ protected: const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs, UnresolvedSetIterator Begin, UnresolvedSetIterator End, - bool KnownDependent = false, - bool KnownContainsUnexpandedParameterPack = false); + bool KnownDependent, + bool KnownInstantiationDependent, + bool KnownContainsUnexpandedParameterPack); OverloadExpr(StmtClass K, EmptyShell Empty) : Expr(K, Empty), Results(0), NumResults(0), @@ -1880,7 +1906,7 @@ class UnresolvedLookupExpr : public OverloadExpr { UnresolvedSetIterator Begin, UnresolvedSetIterator End, bool StdIsAssociatedNamespace) : OverloadExpr(UnresolvedLookupExprClass, C, QualifierLoc, NameInfo, - TemplateArgs, Begin, End), + TemplateArgs, Begin, End, false, false, false), RequiresADL(RequiresADL), StdIsAssociatedNamespace(StdIsAssociatedNamespace), Overloaded(Overloaded), NamingClass(NamingClass) @@ -2727,6 +2753,7 @@ public: : Expr(CXXNoexceptExprClass, Ty, VK_RValue, OK_Ordinary, /*TypeDependent*/false, /*ValueDependent*/Val == CT_Dependent, + Val == CT_Dependent || Operand->isInstantiationDependent(), Operand->containsUnexpandedParameterPack()), Value(Val == CT_Cannot), Operand(Operand), Range(Keyword, RParen) { } @@ -2787,7 +2814,8 @@ public: llvm::Optional NumExpansions) : Expr(PackExpansionExprClass, T, Pattern->getValueKind(), Pattern->getObjectKind(), /*TypeDependent=*/true, - /*ValueDependent=*/true, /*ContainsUnexpandedParameterPack=*/false), + /*ValueDependent=*/true, /*InstantiationDependent=*/true, + /*ContainsUnexpandedParameterPack=*/false), EllipsisLoc(EllipsisLoc), NumExpansions(NumExpansions? *NumExpansions + 1 : 0), Pattern(Pattern) { } @@ -2874,6 +2902,7 @@ public: SourceLocation PackLoc, SourceLocation RParenLoc) : Expr(SizeOfPackExprClass, SizeType, VK_RValue, OK_Ordinary, /*TypeDependent=*/false, /*ValueDependent=*/true, + /*InstantiationDependent=*/true, /*ContainsUnexpandedParameterPack=*/false), OperatorLoc(OperatorLoc), PackLoc(PackLoc), RParenLoc(RParenLoc), Length(0), Pack(Pack) { } @@ -2885,6 +2914,7 @@ public: unsigned Length) : Expr(SizeOfPackExprClass, SizeType, VK_RValue, OK_Ordinary, /*TypeDependent=*/false, /*ValueDependent=*/false, + /*InstantiationDependent=*/false, /*ContainsUnexpandedParameterPack=*/false), OperatorLoc(OperatorLoc), PackLoc(PackLoc), RParenLoc(RParenLoc), Length(Length), Pack(Pack) { } @@ -2927,6 +2957,53 @@ public: child_range children() { return child_range(); } }; +/// \brief Represents a reference to a non-type template parameter +/// that has been substituted with a template argument. +class SubstNonTypeTemplateParmExpr : public Expr { + /// \brief The replaced parameter. + NonTypeTemplateParmDecl *Param; + + /// \brief The replacement expression. + Stmt *Replacement; + + /// \brief The location of the non-type template parameter reference. + SourceLocation NameLoc; + + friend class ASTReader; + friend class ASTStmtReader; + explicit SubstNonTypeTemplateParmExpr(EmptyShell Empty) + : Expr(SubstNonTypeTemplateParmExprClass, Empty) { } + +public: + SubstNonTypeTemplateParmExpr(QualType type, + ExprValueKind valueKind, + SourceLocation loc, + NonTypeTemplateParmDecl *param, + Expr *replacement) + : Expr(SubstNonTypeTemplateParmExprClass, type, valueKind, OK_Ordinary, + replacement->isTypeDependent(), replacement->isValueDependent(), + replacement->isInstantiationDependent(), + replacement->containsUnexpandedParameterPack()), + Param(param), Replacement(replacement), NameLoc(loc) {} + + SourceLocation getNameLoc() const { return NameLoc; } + SourceRange getSourceRange() const { return NameLoc; } + + Expr *getReplacement() const { return cast(Replacement); } + + NonTypeTemplateParmDecl *getParameter() const { return Param; } + + static bool classof(const Stmt *s) { + return s->getStmtClass() == SubstNonTypeTemplateParmExprClass; + } + static bool classof(const SubstNonTypeTemplateParmExpr *) { + return true; + } + + // Iterators + child_range children() { return child_range(&Replacement, &Replacement+1); } +}; + /// \brief Represents a reference to a non-type template parameter pack that /// has been substituted with a non-template argument pack. /// @@ -2953,8 +3030,10 @@ class SubstNonTypeTemplateParmPackExpr : public Expr { /// \brief The location of the non-type template parameter pack reference. SourceLocation NameLoc; + friend class ASTReader; friend class ASTStmtReader; - friend class ASTStmtWriter; + explicit SubstNonTypeTemplateParmPackExpr(EmptyShell Empty) + : Expr(SubstNonTypeTemplateParmPackExprClass, Empty) { } public: SubstNonTypeTemplateParmPackExpr(QualType T, @@ -2962,9 +3041,6 @@ public: SourceLocation NameLoc, const TemplateArgument &ArgPack); - SubstNonTypeTemplateParmPackExpr(EmptyShell Empty) - : Expr(SubstNonTypeTemplateParmPackExprClass, Empty) { } - /// \brief Retrieve the non-type template parameter pack being substituted. NonTypeTemplateParmDecl *getParameterPack() const { return Param; } @@ -2987,6 +3063,66 @@ public: // Iterators child_range children() { return child_range(); } }; + +/// \brief Represents a prvalue temporary that written into memory so that +/// a reference can bind to it. +/// +/// Prvalue expressions are materialized when they need to have an address +/// in memory for a reference to bind to. This happens when binding a +/// reference to the result of a conversion, e.g., +/// +/// \code +/// const int &r = 1.0; +/// \endcode +/// +/// Here, 1.0 is implicitly converted to an \c int. That resulting \c int is +/// then materialized via a \c MaterializeTemporaryExpr, and the reference +/// binds to the temporary. \c MaterializeTemporaryExprs are always glvalues +/// (either an lvalue or an xvalue, depending on the kind of reference binding +/// to it), maintaining the invariant that references always bind to glvalues. +class MaterializeTemporaryExpr : public Expr { + /// \brief The temporary-generating expression whose value will be + /// materialized. + Stmt *Temporary; + + friend class ASTStmtReader; + friend class ASTStmtWriter; + +public: + MaterializeTemporaryExpr(QualType T, Expr *Temporary, + bool BoundToLvalueReference) + : Expr(MaterializeTemporaryExprClass, T, + BoundToLvalueReference? VK_LValue : VK_XValue, OK_Ordinary, + Temporary->isTypeDependent(), Temporary->isValueDependent(), + Temporary->isInstantiationDependent(), + Temporary->containsUnexpandedParameterPack()), + Temporary(Temporary) { } + + MaterializeTemporaryExpr(EmptyShell Empty) + : Expr(MaterializeTemporaryExprClass, Empty) { } + + /// \brief Retrieve the temporary-generating subexpression whose value will + /// be materialized into a glvalue. + Expr *GetTemporaryExpr() const { return reinterpret_cast(Temporary); } + + /// \brief Determine whether this materialized temporary is bound to an + /// lvalue reference; otherwise, it's bound to an rvalue reference. + bool isBoundToLvalueReference() const { + return getValueKind() == VK_LValue; + } + + SourceRange getSourceRange() const { return Temporary->getSourceRange(); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == MaterializeTemporaryExprClass; + } + static bool classof(const MaterializeTemporaryExpr *) { + return true; + } + + // Iterators + child_range children() { return child_range(&Temporary, &Temporary + 1); } +}; } // end namespace clang diff --git a/include/clang/AST/ExprObjC.h b/include/clang/AST/ExprObjC.h index 8163923d62d1..49d4cfe67626 100644 --- a/include/clang/AST/ExprObjC.h +++ b/include/clang/AST/ExprObjC.h @@ -30,7 +30,7 @@ class ObjCStringLiteral : public Expr { public: ObjCStringLiteral(StringLiteral *SL, QualType T, SourceLocation L) : Expr(ObjCStringLiteralClass, T, VK_RValue, OK_Ordinary, false, false, - false), + false, false), String(SL), AtLoc(L) {} explicit ObjCStringLiteral(EmptyShell Empty) : Expr(ObjCStringLiteralClass, Empty) {} @@ -67,6 +67,7 @@ public: : Expr(ObjCEncodeExprClass, T, VK_LValue, OK_Ordinary, EncodedType->getType()->isDependentType(), EncodedType->getType()->isDependentType(), + EncodedType->getType()->isInstantiationDependentType(), EncodedType->getType()->containsUnexpandedParameterPack()), EncodedType(EncodedType), AtLoc(at), RParenLoc(rp) {} @@ -106,7 +107,7 @@ public: ObjCSelectorExpr(QualType T, Selector selInfo, SourceLocation at, SourceLocation rp) : Expr(ObjCSelectorExprClass, T, VK_RValue, OK_Ordinary, false, false, - false), + false, false), SelName(selInfo), AtLoc(at), RParenLoc(rp){} explicit ObjCSelectorExpr(EmptyShell Empty) : Expr(ObjCSelectorExprClass, Empty) {} @@ -146,7 +147,7 @@ public: ObjCProtocolExpr(QualType T, ObjCProtocolDecl *protocol, SourceLocation at, SourceLocation rp) : Expr(ObjCProtocolExprClass, T, VK_RValue, OK_Ordinary, false, false, - false), + false, false), TheProtocol(protocol), AtLoc(at), RParenLoc(rp) {} explicit ObjCProtocolExpr(EmptyShell Empty) : Expr(ObjCProtocolExprClass, Empty) {} @@ -186,6 +187,7 @@ public: bool arrow = false, bool freeIvar = false) : Expr(ObjCIvarRefExprClass, t, VK_LValue, OK_Ordinary, /*TypeDependent=*/false, base->isValueDependent(), + base->isInstantiationDependent(), base->containsUnexpandedParameterPack()), D(d), Loc(l), Base(base), IsArrow(arrow), IsFreeIvar(freeIvar) {} @@ -248,6 +250,7 @@ public: SourceLocation l, Expr *base) : Expr(ObjCPropertyRefExprClass, t, VK, OK, /*TypeDependent=*/false, base->isValueDependent(), + base->isInstantiationDependent(), base->containsUnexpandedParameterPack()), PropertyOrGetter(PD, false), Setter(0), IdLoc(l), ReceiverLoc(), Receiver(base) { @@ -257,7 +260,7 @@ public: ExprValueKind VK, ExprObjectKind OK, SourceLocation l, SourceLocation sl, QualType st) : Expr(ObjCPropertyRefExprClass, t, VK, OK, - /*TypeDependent=*/false, false, + /*TypeDependent=*/false, false, st->isInstantiationDependentType(), st->containsUnexpandedParameterPack()), PropertyOrGetter(PD, false), Setter(0), IdLoc(l), ReceiverLoc(sl), Receiver(st.getTypePtr()) { @@ -267,7 +270,7 @@ public: QualType T, ExprValueKind VK, ExprObjectKind OK, SourceLocation IdLoc, Expr *Base) : Expr(ObjCPropertyRefExprClass, T, VK, OK, false, - Base->isValueDependent(), + Base->isValueDependent(), Base->isInstantiationDependent(), Base->containsUnexpandedParameterPack()), PropertyOrGetter(Getter, true), Setter(Setter), IdLoc(IdLoc), ReceiverLoc(), Receiver(Base) { @@ -277,7 +280,7 @@ public: QualType T, ExprValueKind VK, ExprObjectKind OK, SourceLocation IdLoc, SourceLocation SuperLoc, QualType SuperTy) - : Expr(ObjCPropertyRefExprClass, T, VK, OK, false, false, false), + : Expr(ObjCPropertyRefExprClass, T, VK, OK, false, false, false, false), PropertyOrGetter(Getter, true), Setter(Setter), IdLoc(IdLoc), ReceiverLoc(SuperLoc), Receiver(SuperTy.getTypePtr()) { } @@ -286,7 +289,7 @@ public: QualType T, ExprValueKind VK, ExprObjectKind OK, SourceLocation IdLoc, SourceLocation ReceiverLoc, ObjCInterfaceDecl *Receiver) - : Expr(ObjCPropertyRefExprClass, T, VK, OK, false, false, false), + : Expr(ObjCPropertyRefExprClass, T, VK, OK, false, false, false, false), PropertyOrGetter(Getter, true), Setter(Setter), IdLoc(IdLoc), ReceiverLoc(ReceiverLoc), Receiver(Receiver) { } @@ -456,7 +459,11 @@ class ObjCMessageExpr : public Expr { /// /// When non-zero, we have a method declaration; otherwise, we just /// have a selector. - unsigned HasMethod : 8; + unsigned HasMethod : 1; + + /// \brief Whether this message send is a "delegate init call", + /// i.e. a call of an init method on self from within an init method. + unsigned IsDelegateInitCall : 1; /// \brief When the message expression is a send to 'super', this is /// the location of the 'super' keyword. @@ -476,7 +483,7 @@ class ObjCMessageExpr : public Expr { ObjCMessageExpr(EmptyShell Empty, unsigned NumArgs) : Expr(ObjCMessageExprClass, Empty), NumArgs(NumArgs), Kind(0), - HasMethod(0), SelectorOrMethod(0) { } + HasMethod(0), IsDelegateInitCall(0), SelectorOrMethod(0) { } ObjCMessageExpr(QualType T, ExprValueKind VK, SourceLocation LBracLoc, @@ -807,6 +814,12 @@ public: getArgs()[Arg] = ArgExpr; } + /// isDelegateInitCall - Answers whether this message send has been + /// tagged as a "delegate init call", i.e. a call to a method in the + /// -init family on self from within an -init method implementation. + bool isDelegateInitCall() const { return IsDelegateInitCall; } + void setDelegateInitCall(bool isDelegate) { IsDelegateInitCall = isDelegate; } + SourceLocation getLeftLoc() const { return LBracLoc; } SourceLocation getRightLoc() const { return RBracLoc; } SourceLocation getSelectorLoc() const { return SelectorLoc; } @@ -860,6 +873,7 @@ public: ObjCIsaExpr(Expr *base, bool isarrow, SourceLocation l, QualType ty) : Expr(ObjCIsaExprClass, ty, VK_LValue, OK_Ordinary, /*TypeDependent=*/false, base->isValueDependent(), + base->isInstantiationDependent(), /*ContainsUnexpandedParameterPack=*/false), Base(base), IsaMemberLoc(l), IsArrow(isarrow) {} @@ -892,6 +906,123 @@ public: child_range children() { return child_range(&Base, &Base+1); } }; + +/// ObjCIndirectCopyRestoreExpr - Represents the passing of a function +/// argument by indirect copy-restore in ARC. This is used to support +/// passing indirect arguments with the wrong lifetime, e.g. when +/// passing the address of a __strong local variable to an 'out' +/// parameter. This expression kind is only valid in an "argument" +/// position to some sort of call expression. +/// +/// The parameter must have type 'pointer to T', and the argument must +/// have type 'pointer to U', where T and U agree except possibly in +/// qualification. If the argument value is null, then a null pointer +/// is passed; otherwise it points to an object A, and: +/// 1. A temporary object B of type T is initialized, either by +/// zero-initialization (used when initializing an 'out' parameter) +/// or copy-initialization (used when initializing an 'inout' +/// parameter). +/// 2. The address of the temporary is passed to the function. +/// 3. If the call completes normally, A is move-assigned from B. +/// 4. Finally, A is destroyed immediately. +/// +/// Currently 'T' must be a retainable object lifetime and must be +/// __autoreleasing; this qualifier is ignored when initializing +/// the value. +class ObjCIndirectCopyRestoreExpr : public Expr { + Stmt *Operand; + + // unsigned ObjCIndirectCopyRestoreBits.ShouldCopy : 1; + + friend class ASTReader; + friend class ASTStmtReader; + + void setShouldCopy(bool shouldCopy) { + ObjCIndirectCopyRestoreExprBits.ShouldCopy = shouldCopy; + } + + explicit ObjCIndirectCopyRestoreExpr(EmptyShell Empty) + : Expr(ObjCIndirectCopyRestoreExprClass, Empty) { } + +public: + ObjCIndirectCopyRestoreExpr(Expr *operand, QualType type, bool shouldCopy) + : Expr(ObjCIndirectCopyRestoreExprClass, type, VK_LValue, OK_Ordinary, + operand->isTypeDependent(), operand->isValueDependent(), + operand->isInstantiationDependent(), + operand->containsUnexpandedParameterPack()), + Operand(operand) { + setShouldCopy(shouldCopy); + } + + Expr *getSubExpr() { return cast(Operand); } + const Expr *getSubExpr() const { return cast(Operand); } + + /// shouldCopy - True if we should do the 'copy' part of the + /// copy-restore. If false, the temporary will be zero-initialized. + bool shouldCopy() const { return ObjCIndirectCopyRestoreExprBits.ShouldCopy; } + + child_range children() { return child_range(&Operand, &Operand+1); } + + // Source locations are determined by the subexpression. + SourceRange getSourceRange() const { return Operand->getSourceRange(); } + SourceLocation getExprLoc() const { return getSubExpr()->getExprLoc(); } + + static bool classof(const Stmt *s) { + return s->getStmtClass() == ObjCIndirectCopyRestoreExprClass; + } + static bool classof(const ObjCIndirectCopyRestoreExpr *) { return true; } +}; + +/// \brief An Objective-C "bridged" cast expression, which casts between +/// Objective-C pointers and C pointers, transferring ownership in the process. +/// +/// \code +/// NSString *str = (__bridge_transfer NSString *)CFCreateString(); +/// \endcode +class ObjCBridgedCastExpr : public ExplicitCastExpr { + SourceLocation LParenLoc; + SourceLocation BridgeKeywordLoc; + unsigned Kind : 2; + + friend class ASTStmtReader; + friend class ASTStmtWriter; + +public: + ObjCBridgedCastExpr(SourceLocation LParenLoc, ObjCBridgeCastKind Kind, + SourceLocation BridgeKeywordLoc, TypeSourceInfo *TSInfo, + Expr *Operand) + : ExplicitCastExpr(ObjCBridgedCastExprClass, TSInfo->getType(), VK_RValue, + CK_BitCast, Operand, 0, TSInfo), + LParenLoc(LParenLoc), BridgeKeywordLoc(BridgeKeywordLoc), Kind(Kind) { } + + /// \brief Construct an empty Objective-C bridged cast. + explicit ObjCBridgedCastExpr(EmptyShell Shell) + : ExplicitCastExpr(ObjCBridgedCastExprClass, Shell, 0) { } + + SourceLocation getLParenLoc() const { return LParenLoc; } + + /// \brief Determine which kind of bridge is being performed via this cast. + ObjCBridgeCastKind getBridgeKind() const { + return static_cast(Kind); + } + + /// \brief Retrieve the kind of bridge being performed as a string. + llvm::StringRef getBridgeKindName() const; + + /// \brief The location of the bridge keyword. + SourceLocation getBridgeKeywordLoc() const { return BridgeKeywordLoc; } + + SourceRange getSourceRange() const { + return SourceRange(LParenLoc, getSubExpr()->getLocEnd()); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCBridgedCastExprClass; + } + static bool classof(const ObjCBridgedCastExpr *) { return true; } + +}; + } // end namespace clang #endif diff --git a/include/clang/AST/ExternalASTSource.h b/include/clang/AST/ExternalASTSource.h index 846813adf7c3..ef1f1618ba1d 100644 --- a/include/clang/AST/ExternalASTSource.h +++ b/include/clang/AST/ExternalASTSource.h @@ -32,6 +32,20 @@ class Selector; class Stmt; class TagDecl; +/// \brief Enumeration describing the result of loading information from +/// an external source. +enum ExternalLoadResult { + /// \brief Loading the external information has succeeded. + ELR_Success, + + /// \brief Loading the external information has failed. + ELR_Failure, + + /// \brief The external information has already been loaded, and therefore + /// no additional processing is required. + ELR_AlreadyLoaded +}; + /// \brief Abstract interface for external sources of AST nodes. /// /// External AST sources provide AST nodes constructed from some @@ -132,10 +146,10 @@ public: /// declaration kind is one we are looking for. If NULL, all declarations /// are returned. /// - /// \return true if an error occurred + /// \return an indication of whether the load succeeded or failed. /// /// The default implementation of this method is a no-op. - virtual bool FindExternalLexicalDecls(const DeclContext *DC, + virtual ExternalLoadResult FindExternalLexicalDecls(const DeclContext *DC, bool (*isKindWeWant)(Decl::Kind), llvm::SmallVectorImpl &Result); @@ -143,14 +157,14 @@ public: /// DeclContext. /// /// \return true if an error occurred - bool FindExternalLexicalDecls(const DeclContext *DC, + ExternalLoadResult FindExternalLexicalDecls(const DeclContext *DC, llvm::SmallVectorImpl &Result) { return FindExternalLexicalDecls(DC, 0, Result); } template - bool FindExternalLexicalDeclsBy(const DeclContext *DC, - llvm::SmallVectorImpl &Result) { + ExternalLoadResult FindExternalLexicalDeclsBy(const DeclContext *DC, + llvm::SmallVectorImpl &Result) { return FindExternalLexicalDecls(DC, DeclTy::classofKind, Result); } diff --git a/include/clang/AST/GlobalDecl.h b/include/clang/AST/GlobalDecl.h new file mode 100644 index 000000000000..c43e44c26f31 --- /dev/null +++ b/include/clang/AST/GlobalDecl.h @@ -0,0 +1,124 @@ +//===--- GlobalDecl.h - Global declaration holder ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// A GlobalDecl can hold either a regular variable/function or a C++ ctor/dtor +// together with its type. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_GLOBALDECL_H +#define LLVM_CLANG_AST_GLOBALDECL_H + +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/ABI.h" + +namespace clang { + +/// 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 VarDecl, a FunctionDecl or a BlockDecl. +class GlobalDecl { + 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() {} + + 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) {} + + GlobalDecl getCanonicalDecl() const { + GlobalDecl CanonGD; + CanonGD.Value.setPointer(Value.getPointer()->getCanonicalDecl()); + CanonGD.Value.setInt(Value.getInt()); + + return CanonGD; + } + + 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()); + } + + friend bool operator==(const GlobalDecl &LHS, const GlobalDecl &RHS) { + return LHS.Value == RHS.Value; + } + + void *getAsOpaquePtr() const { return Value.getOpaqueValue(); } + + static GlobalDecl getFromOpaquePtr(void *P) { + GlobalDecl GD; + GD.Value.setFromOpaqueValue(P); + return GD; + } + + GlobalDecl getWithDecl(const Decl *D) { + GlobalDecl Result(*this); + Result.Value.setPointer(D); + return Result; + } +}; + +} // end namespace clang + +namespace llvm { + template struct DenseMapInfo; + + template<> struct DenseMapInfo { + static inline clang::GlobalDecl getEmptyKey() { + return clang::GlobalDecl(); + } + + static inline clang::GlobalDecl getTombstoneKey() { + return clang::GlobalDecl:: + getFromOpaquePtr(reinterpret_cast(-1)); + } + + static unsigned getHashValue(clang::GlobalDecl GD) { + return DenseMapInfo::getHashValue(GD.getAsOpaquePtr()); + } + + static bool isEqual(clang::GlobalDecl LHS, + clang::GlobalDecl RHS) { + return LHS == RHS; + } + + }; + + // GlobalDecl isn't *technically* a POD type. However, its copy constructor, + // copy assignment operator, and destructor are all trivial. + template <> + struct isPodLike { + static const bool value = true; + }; +} // end namespace llvm + +#endif diff --git a/include/clang/AST/NestedNameSpecifier.h b/include/clang/AST/NestedNameSpecifier.h index c21c76b006ff..018041f8ba20 100644 --- a/include/clang/AST/NestedNameSpecifier.h +++ b/include/clang/AST/NestedNameSpecifier.h @@ -186,6 +186,10 @@ public: /// type or not. bool isDependent() const; + /// \brief Whether this nested name specifier involves a template + /// parameter. + bool isInstantiationDependent() const; + /// \brief Whether this nested-name-specifier contains an unexpanded /// parameter pack (for C++0x variadic templates). bool containsUnexpandedParameterPack() const; @@ -435,6 +439,14 @@ public: /// copied. NestedNameSpecifierLoc getWithLocInContext(ASTContext &Context) const; + /// \brief Retrieve a nested-name-specifier with location + /// information based on the information in this builder. This loc + /// will contain references to the builder's internal data and may + /// be invalidated by any change to the builder. + NestedNameSpecifierLoc getTemporary() const { + return NestedNameSpecifierLoc(Representation, Buffer); + } + /// \brief Clear out this builder, and prepare it to build another /// nested-name-specifier with source-location information. void Clear() { diff --git a/include/clang/AST/OperationKinds.h b/include/clang/AST/OperationKinds.h index 35c72c45ce7c..92ff6041371c 100644 --- a/include/clang/AST/OperationKinds.h +++ b/include/clang/AST/OperationKinds.h @@ -245,7 +245,22 @@ enum CastKind { /// \brief Converts from an integral complex to a floating complex. /// _Complex unsigned -> _Complex float - CK_IntegralComplexToFloatingComplex + CK_IntegralComplexToFloatingComplex, + + /// \brief Produces a retainable object pointer so that it may be + /// consumed, e.g. by being passed to a consuming parameter. Calls + /// objc_retain. + CK_ObjCProduceObject, + + /// \brief Consumes a retainable object pointer that has just been + /// produced, e.g. as the return value of a retaining call. Enters + /// a cleanup to call objc_release at some indefinite time. + CK_ObjCConsumeObject, + + /// \brief Reclaim a retainable object pointer object that may have + /// been produced and autoreleased as part of a function return + /// sequence. + CK_ObjCReclaimReturnedObject }; #define CK_Invalid ((CastKind) -1) @@ -284,6 +299,19 @@ enum UnaryOperatorKind { UO_Extension // __extension__ marker. }; +/// \brief The kind of bridging performed by the Objective-C bridge cast. +enum ObjCBridgeCastKind { + /// \brief Bridging via __bridge, which does nothing but reinterpret + /// the bits. + OBC_Bridge, + /// \brief Bridging via __bridge_transfer, which transfers ownership of an + /// Objective-C pointer into ARC. + OBC_BridgeTransfer, + /// \brief Bridging via __bridge_retain, which makes an ARC object available + /// as a +1 C pointer. + OBC_BridgeRetained +}; + } #endif diff --git a/include/clang/AST/ParentMap.h b/include/clang/AST/ParentMap.h index 9ea5a0930d32..22c1e7269fac 100644 --- a/include/clang/AST/ParentMap.h +++ b/include/clang/AST/ParentMap.h @@ -32,6 +32,7 @@ public: Stmt *getParent(Stmt*) const; Stmt *getParentIgnoreParens(Stmt *) const; Stmt *getParentIgnoreParenCasts(Stmt *) const; + Stmt *getOuterParenParent(Stmt *) const; const Stmt *getParent(const Stmt* S) const { return getParent(const_cast(S)); diff --git a/include/clang/AST/PrettyPrinter.h b/include/clang/AST/PrettyPrinter.h index cf5fadbd1850..fc8ac36b3b97 100644 --- a/include/clang/AST/PrettyPrinter.h +++ b/include/clang/AST/PrettyPrinter.h @@ -41,7 +41,7 @@ struct PrintingPolicy { SuppressTagKeyword(false), SuppressTag(false), SuppressScope(false), SuppressInitializers(false), Dump(false), ConstantArraySizeAsWritten(false), - AnonymousTagLocations(true) { } + AnonymousTagLocations(true), SuppressStrongLifetime(false) { } /// \brief The number of spaces to use to indent each line. unsigned Indentation : 8; @@ -129,6 +129,10 @@ struct PrintingPolicy { /// that entity (e.g., "enum "). Otherwise, just /// prints "" for the name. bool AnonymousTagLocations : 1; + + /// \brief When true, suppress printing of the __strong lifetime qualifier in + /// ARC. + unsigned SuppressStrongLifetime : 1; }; } // end namespace clang diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index a8f182a5bc92..85c5c08853d1 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -1721,6 +1721,7 @@ DEF_TRAVERSE_STMT(ObjCAtSynchronizedStmt, { }) DEF_TRAVERSE_STMT(ObjCAtThrowStmt, { }) DEF_TRAVERSE_STMT(ObjCAtTryStmt, { }) DEF_TRAVERSE_STMT(ObjCForCollectionStmt, { }) +DEF_TRAVERSE_STMT(ObjCAutoreleasePoolStmt, { }) DEF_TRAVERSE_STMT(CXXForRangeStmt, { }) DEF_TRAVERSE_STMT(ReturnStmt, { }) DEF_TRAVERSE_STMT(SwitchStmt, { }) @@ -1933,6 +1934,10 @@ DEF_TRAVERSE_STMT(ObjCMessageExpr, { }) DEF_TRAVERSE_STMT(ObjCPropertyRefExpr, { }) DEF_TRAVERSE_STMT(ObjCProtocolExpr, { }) DEF_TRAVERSE_STMT(ObjCSelectorExpr, { }) +DEF_TRAVERSE_STMT(ObjCIndirectCopyRestoreExpr, { }) +DEF_TRAVERSE_STMT(ObjCBridgedCastExpr, { + TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc())); +}) DEF_TRAVERSE_STMT(ParenExpr, { }) DEF_TRAVERSE_STMT(ParenListExpr, { }) DEF_TRAVERSE_STMT(PredefinedExpr, { }) @@ -1973,6 +1978,8 @@ DEF_TRAVERSE_STMT(CXXNoexceptExpr, { }) DEF_TRAVERSE_STMT(PackExpansionExpr, { }) DEF_TRAVERSE_STMT(SizeOfPackExpr, { }) DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmPackExpr, { }) +DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmExpr, { }) +DEF_TRAVERSE_STMT(MaterializeTemporaryExpr, { }) // These literals (all of them) do not need any action. DEF_TRAVERSE_STMT(IntegerLiteral, { }) diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h index 695fb0403ead..bf5f383be5e0 100644 --- a/include/clang/AST/Stmt.h +++ b/include/clang/AST/Stmt.h @@ -154,9 +154,10 @@ protected: unsigned ObjectKind : 2; unsigned TypeDependent : 1; unsigned ValueDependent : 1; + unsigned InstantiationDependent : 1; unsigned ContainsUnexpandedParameterPack : 1; }; - enum { NumExprBits = 15 }; + enum { NumExprBits = 16 }; class DeclRefExprBitfields { friend class DeclRefExpr; @@ -183,6 +184,13 @@ protected: unsigned NumPreArgs : 1; }; + class ObjCIndirectCopyRestoreExprBitfields { + friend class ObjCIndirectCopyRestoreExpr; + unsigned : NumExprBits; + + unsigned ShouldCopy : 1; + }; + union { // FIXME: this is wasteful on 64-bit platforms. void *Aligner; @@ -193,6 +201,7 @@ protected: DeclRefExprBitfields DeclRefExprBits; CastExprBitfields CastExprBits; CallExprBitfields CallExprBits; + ObjCIndirectCopyRestoreExprBitfields ObjCIndirectCopyRestoreExprBits; }; friend class ASTStmtReader; @@ -284,6 +293,10 @@ public: /// works on systems with GraphViz (Mac OS X) or dot+gv installed. void viewAST() const; + /// Skip past any implicit AST nodes which might surround this + /// statement, such as ExprWithCleanups or ImplicitCastExpr nodes. + Stmt *IgnoreImplicit(); + // Implement isa support. static bool classof(const Stmt *) { return true; } @@ -327,7 +340,7 @@ public: /// declaration pointers) or the exact representation of the statement as /// written in the source. void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, - bool Canonical); + bool Canonical) const; }; /// DeclStmt - Adaptor class for mixing declarations with statements and @@ -1458,6 +1471,10 @@ class SEHExceptStmt : public Stmt { Expr *FilterExpr, Stmt *Block); + friend class ASTReader; + friend class ASTStmtReader; + explicit SEHExceptStmt(EmptyShell E) : Stmt(SEHExceptStmtClass, E) { } + public: static SEHExceptStmt* Create(ASTContext &C, SourceLocation ExceptLoc, @@ -1492,6 +1509,10 @@ class SEHFinallyStmt : public Stmt { SEHFinallyStmt(SourceLocation Loc, Stmt *Block); + friend class ASTReader; + friend class ASTStmtReader; + explicit SEHFinallyStmt(EmptyShell E) : Stmt(SEHFinallyStmtClass, E) { } + public: static SEHFinallyStmt* Create(ASTContext &C, SourceLocation FinallyLoc, @@ -1530,6 +1551,10 @@ class SEHTryStmt : public Stmt { Stmt *TryBlock, Stmt *Handler); + friend class ASTReader; + friend class ASTStmtReader; + explicit SEHTryStmt(EmptyShell E) : Stmt(SEHTryStmtClass, E) { } + public: static SEHTryStmt* Create(ASTContext &C, bool isCXXTry, diff --git a/include/clang/AST/StmtObjC.h b/include/clang/AST/StmtObjC.h index 1800a71f9154..d996fc5cada3 100644 --- a/include/clang/AST/StmtObjC.h +++ b/include/clang/AST/StmtObjC.h @@ -342,6 +342,39 @@ public: child_range children() { return child_range(&Throw, &Throw+1); } }; +/// ObjCAutoreleasePoolStmt - This represent objective-c's +/// @autoreleasepool Statement +class ObjCAutoreleasePoolStmt : public Stmt { + Stmt *SubStmt; + SourceLocation AtLoc; +public: + ObjCAutoreleasePoolStmt(SourceLocation atLoc, + Stmt *subStmt) + : Stmt(ObjCAutoreleasePoolStmtClass), + SubStmt(subStmt), AtLoc(atLoc) {} + + explicit ObjCAutoreleasePoolStmt(EmptyShell Empty) : + Stmt(ObjCAutoreleasePoolStmtClass, Empty) { } + + const Stmt *getSubStmt() const { return SubStmt; } + Stmt *getSubStmt() { return SubStmt; } + void setSubStmt(Stmt *S) { SubStmt = S; } + + SourceRange getSourceRange() const { + return SourceRange(AtLoc, SubStmt->getLocEnd()); + } + + SourceLocation getAtLoc() const { return AtLoc; } + void setAtLoc(SourceLocation Loc) { AtLoc = Loc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCAutoreleasePoolStmtClass; + } + static bool classof(const ObjCAutoreleasePoolStmt *) { return true; } + + child_range children() { return child_range(&SubStmt, &SubStmt + 1); } +}; + } // end namespace clang #endif diff --git a/include/clang/AST/TemplateBase.h b/include/clang/AST/TemplateBase.h index 821b4fcbb168..1c693e00c8cc 100644 --- a/include/clang/AST/TemplateBase.h +++ b/include/clang/AST/TemplateBase.h @@ -235,9 +235,14 @@ public: bool isNull() const { return Kind == Null; } /// \brief Whether this template argument is dependent on a template - /// parameter. + /// parameter such that its result can change from one instantiation to + /// another. bool isDependent() const; + /// \brief Whether this template argument is dependent on a template + /// parameter. + bool isInstantiationDependent() const; + /// \brief Whether this template argument contains an unexpanded /// parameter pack. bool containsUnexpandedParameterPack() const; diff --git a/include/clang/AST/TemplateName.h b/include/clang/AST/TemplateName.h index 1721973e8229..a180f587eddd 100644 --- a/include/clang/AST/TemplateName.h +++ b/include/clang/AST/TemplateName.h @@ -33,6 +33,7 @@ class OverloadedTemplateStorage; struct PrintingPolicy; class QualifiedTemplateName; class NamedDecl; +class SubstTemplateTemplateParmStorage; class SubstTemplateTemplateParmPackStorage; class TemplateArgument; class TemplateDecl; @@ -42,38 +43,49 @@ class TemplateTemplateParmDecl; /// template names or an already-substituted template template parameter pack. class UncommonTemplateNameStorage { protected: + enum Kind { + Overloaded, + SubstTemplateTemplateParm, + SubstTemplateTemplateParmPack + }; + union { struct { - /// \brief If true, this is an OverloadedTemplateStorage instance; - /// otherwise, it's a SubstTemplateTemplateParmPackStorage instance. - unsigned IsOverloadedStorage : 1; + /// \brief A Kind. + unsigned Kind : 2; /// \brief The number of stored templates or template arguments, /// depending on which subclass we have. - unsigned Size : 31; + unsigned Size : 30; } Bits; void *PointerAlignment; }; - UncommonTemplateNameStorage(unsigned Size, bool OverloadedStorage) { - Bits.IsOverloadedStorage = OverloadedStorage; - Bits.Size = Size; + UncommonTemplateNameStorage(Kind kind, unsigned size) { + Bits.Kind = kind; + Bits.Size = size; } public: unsigned size() const { return Bits.Size; } OverloadedTemplateStorage *getAsOverloadedStorage() { - return Bits.IsOverloadedStorage + return Bits.Kind == Overloaded ? reinterpret_cast(this) : 0; } + SubstTemplateTemplateParmStorage *getAsSubstTemplateTemplateParm() { + return Bits.Kind == SubstTemplateTemplateParm + ? reinterpret_cast(this) + : 0; + } + SubstTemplateTemplateParmPackStorage *getAsSubstTemplateTemplateParmPack() { - return Bits.IsOverloadedStorage - ? 0 - : reinterpret_cast(this) ; + return Bits.Kind == SubstTemplateTemplateParmPack + ? reinterpret_cast(this) + : 0; } }; @@ -82,8 +94,8 @@ public: class OverloadedTemplateStorage : public UncommonTemplateNameStorage { friend class ASTContext; - OverloadedTemplateStorage(unsigned Size) - : UncommonTemplateNameStorage(Size, true) { } + OverloadedTemplateStorage(unsigned size) + : UncommonTemplateNameStorage(Overloaded, size) { } NamedDecl **getStorage() { return reinterpret_cast(this + 1); @@ -98,8 +110,7 @@ public: iterator begin() const { return getStorage(); } iterator end() const { return getStorage() + size(); } }; - - + /// \brief A structure for storing an already-substituted template template /// parameter pack. /// @@ -109,16 +120,14 @@ public: class SubstTemplateTemplateParmPackStorage : public UncommonTemplateNameStorage, public llvm::FoldingSetNode { - ASTContext &Context; TemplateTemplateParmDecl *Parameter; const TemplateArgument *Arguments; public: - SubstTemplateTemplateParmPackStorage(ASTContext &Context, - TemplateTemplateParmDecl *Parameter, + SubstTemplateTemplateParmPackStorage(TemplateTemplateParmDecl *Parameter, unsigned Size, const TemplateArgument *Arguments) - : UncommonTemplateNameStorage(Size, false), Context(Context), + : UncommonTemplateNameStorage(SubstTemplateTemplateParmPack, Size), Parameter(Parameter), Arguments(Arguments) { } /// \brief Retrieve the template template parameter pack being substituted. @@ -130,9 +139,10 @@ public: /// parameter was substituted. TemplateArgument getArgumentPack() const; - void Profile(llvm::FoldingSetNodeID &ID); + void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context); - static void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context, + static void Profile(llvm::FoldingSetNodeID &ID, + ASTContext &Context, TemplateTemplateParmDecl *Parameter, const TemplateArgument &ArgPack); }; @@ -189,6 +199,9 @@ public: /// \brief A dependent template name that has not been resolved to a /// template (or set of templates). DependentTemplate, + /// \brief A template template parameter that has been substituted + /// for some other template name. + SubstTemplateTemplateParm, /// \brief A template template parameter pack that has been substituted for /// a template template argument pack, but has not yet been expanded into /// individual arguments. @@ -199,6 +212,7 @@ public: explicit TemplateName(TemplateDecl *Template) : Storage(Template) { } explicit TemplateName(OverloadedTemplateStorage *Storage) : Storage(Storage) { } + explicit TemplateName(SubstTemplateTemplateParmStorage *Storage); explicit TemplateName(SubstTemplateTemplateParmPackStorage *Storage) : Storage(Storage) { } explicit TemplateName(QualifiedTemplateName *Qual) : Storage(Qual) { } @@ -234,6 +248,19 @@ public: return 0; } + /// \brief Retrieve the substituted template template parameter, if + /// known. + /// + /// \returns The storage for the substituted template template parameter, + /// if known. Otherwise, returns NULL. + SubstTemplateTemplateParmStorage *getAsSubstTemplateTemplateParm() const { + if (UncommonTemplateNameStorage *uncommon = + Storage.dyn_cast()) + return uncommon->getAsSubstTemplateTemplateParm(); + + return 0; + } + /// \brief Retrieve the substituted template template parameter pack, if /// known. /// @@ -260,9 +287,15 @@ public: return Storage.dyn_cast(); } + TemplateName getUnderlying() const; + /// \brief Determines whether this is a dependent template name. bool isDependent() const; + /// \brief Determines whether this is a template name that somehow + /// depends on a template parameter. + bool isInstantiationDependent() const; + /// \brief Determines whether this template name contains an /// unexpanded parameter pack (for C++0x variadic templates). bool containsUnexpandedParameterPack() const; @@ -300,6 +333,41 @@ public: const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, TemplateName N); +/// \brief A structure for storing the information associated with a +/// substituted template template parameter. +class SubstTemplateTemplateParmStorage + : public UncommonTemplateNameStorage, public llvm::FoldingSetNode { + friend class ASTContext; + + TemplateTemplateParmDecl *Parameter; + TemplateName Replacement; + + SubstTemplateTemplateParmStorage(TemplateTemplateParmDecl *parameter, + TemplateName replacement) + : UncommonTemplateNameStorage(SubstTemplateTemplateParm, 0), + Parameter(parameter), Replacement(replacement) {} + +public: + TemplateTemplateParmDecl *getParameter() const { return Parameter; } + TemplateName getReplacement() const { return Replacement; } + + void Profile(llvm::FoldingSetNodeID &ID); + + static void Profile(llvm::FoldingSetNodeID &ID, + TemplateTemplateParmDecl *parameter, + TemplateName replacement); +}; + +inline TemplateName::TemplateName(SubstTemplateTemplateParmStorage *Storage) + : Storage(Storage) { } + +inline TemplateName TemplateName::getUnderlying() const { + if (SubstTemplateTemplateParmStorage *subst + = getAsSubstTemplateTemplateParm()) + return subst->getReplacement().getUnderlying(); + return *this; +} + /// \brief Represents a template name that was expressed as a /// qualified name. /// diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 77633831ff27..ef0dbdae037c 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -126,6 +126,28 @@ public: Strong }; + enum ObjCLifetime { + /// There is no lifetime qualification on this type. + OCL_None, + + /// This object can be modified without requiring retains or + /// releases. + OCL_ExplicitNone, + + /// Assigning into this object requires the old value to be + /// released and the new value to be retained. The timing of the + /// release of the old value is inexact: it may be moved to + /// immediately after the last known point where the value is + /// live. + OCL_Strong, + + /// Reading or writing from this object requires a barrier call. + OCL_Weak, + + /// Assigning into this object requires a lifetime extension. + OCL_Autoreleasing + }; + enum { /// The maximum supported address space number. /// 24 bits should be enough for anyone. @@ -218,7 +240,37 @@ public: qs.removeObjCGCAttr(); return qs; } + Qualifiers withoutObjCGLifetime() const { + Qualifiers qs = *this; + qs.removeObjCLifetime(); + return qs; + } + + bool hasObjCLifetime() const { return Mask & LifetimeMask; } + ObjCLifetime getObjCLifetime() const { + return ObjCLifetime((Mask & LifetimeMask) >> LifetimeShift); + } + void setObjCLifetime(ObjCLifetime type) { + Mask = (Mask & ~LifetimeMask) | (type << LifetimeShift); + } + void removeObjCLifetime() { setObjCLifetime(OCL_None); } + void addObjCLifetime(ObjCLifetime type) { + assert(type); + setObjCLifetime(type); + } + + /// True if the lifetime is neither None or ExplicitNone. + bool hasNonTrivialObjCLifetime() const { + ObjCLifetime lifetime = getObjCLifetime(); + return (lifetime > OCL_ExplicitNone); + } + /// True if the lifetime is either strong or weak. + bool hasStrongOrWeakObjCLifetime() const { + ObjCLifetime lifetime = getObjCLifetime(); + return (lifetime == OCL_Strong || lifetime == OCL_Weak); + } + bool hasAddressSpace() const { return Mask & AddressSpaceMask; } unsigned getAddressSpace() const { return Mask >> AddressSpaceShift; } void setAddressSpace(unsigned space) { @@ -277,6 +329,8 @@ public: addAddressSpace(Q.getAddressSpace()); if (Q.hasObjCGCAttr()) addObjCGCAttr(Q.getObjCGCAttr()); + if (Q.hasObjCLifetime()) + addObjCLifetime(Q.getObjCLifetime()); } } @@ -287,6 +341,8 @@ public: !hasAddressSpace() || !qs.hasAddressSpace()); assert(getObjCGCAttr() == qs.getObjCGCAttr() || !hasObjCGCAttr() || !qs.hasObjCGCAttr()); + assert(getObjCLifetime() == qs.getObjCLifetime() || + !hasObjCLifetime() || !qs.hasObjCLifetime()); Mask |= qs.Mask; } @@ -301,10 +357,30 @@ public: // changed. (getObjCGCAttr() == other.getObjCGCAttr() || !hasObjCGCAttr() || !other.hasObjCGCAttr()) && + // ObjC lifetime qualifiers must match exactly. + getObjCLifetime() == other.getObjCLifetime() && // CVR qualifiers may subset. (((Mask & CVRMask) | (other.Mask & CVRMask)) == (Mask & CVRMask)); } + /// \brief Determines if these qualifiers compatibly include another set of + /// qualifiers from the narrow perspective of Objective-C ARC lifetime. + /// + /// One set of Objective-C lifetime qualifiers compatibly includes the other + /// if the lifetime qualifiers match, or if both are non-__weak and the + /// including set also contains the 'const' qualifier. + bool compatiblyIncludesObjCLifetime(Qualifiers other) const { + if (getObjCLifetime() == other.getObjCLifetime()) + return true; + + if (getObjCLifetime() == OCL_Weak || other.getObjCLifetime() == OCL_Weak) + return false; + + return hasConst(); + } + + bool isSupersetOf(Qualifiers Other) const; + /// \brief Determine whether this set of qualifiers is a strict superset of /// another set of qualifiers, not considering qualifier compatibility. bool isStrictSupersetOf(Qualifiers Other) const; @@ -351,14 +427,16 @@ public: private: - // bits: |0 1 2|3 .. 4|5 .. 31| - // |C R V|GCAttr|AddrSpace| + // bits: |0 1 2|3 .. 4|5 .. 7|8 ... 31| + // |C R V|GCAttr|Lifetime|AddressSpace| 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; + static const uint32_t LifetimeMask = 0xE0; + static const uint32_t LifetimeShift = 5; + static const uint32_t AddressSpaceMask = ~(CVRMask|GCAttrMask|LifetimeMask); + static const uint32_t AddressSpaceShift = 8; }; /// CallingConv - Specifies the calling convention that a function uses. @@ -527,6 +605,23 @@ public: return QualType::isConstant(*this, Ctx); } + /// \brief Determine whether this is a Plain Old Data (POD) type (C++ 3.9p10). + bool isPODType(ASTContext &Context) const; + + /// isCXX11PODType() - Return true if this is a POD type according to the + /// more relaxed rules of the C++11 standard, regardless of the current + /// compilation's language. + /// (C++0x [basic.types]p9) + bool isCXX11PODType(ASTContext &Context) const; + + /// isTrivialType - Return true if this is a trivial type + /// (C++0x [basic.types]p9) + bool isTrivialType(ASTContext &Context) const; + + /// isTriviallyCopyableType - Return true if this is a trivially + /// copyable type (C++0x [basic.types]p9) + bool isTriviallyCopyableType(ASTContext &Context) const; + // Don't promise in the API that anything besides 'const' can be // easily added. @@ -546,6 +641,10 @@ public: return withFastQualifiers(Qualifiers::Volatile); } + QualType withCVRQualifiers(unsigned CVR) const { + return withFastQualifiers(CVR); + } + void addFastQualifiers(unsigned TQs) { assert(!(TQs & ~Qualifiers::FastMask) && "non-fast qualifier bits set in mask!"); @@ -658,6 +757,13 @@ public: return getSplitDesugaredType(*this); } + /// \brief Return the specified type with one level of "sugar" removed from + /// the type. + /// + /// This routine takes off the first typedef, typeof, etc. If the outer level + /// of the type is already concrete, it returns it unmodified. + QualType getSingleStepDesugaredType(const ASTContext &Context) const; + /// IgnoreParens - Returns the specified type after dropping any /// outer-level parentheses. QualType IgnoreParens() const { @@ -709,7 +815,7 @@ public: /// getAddressSpace - Return the address space of this type. inline unsigned getAddressSpace() const; - /// GCAttrTypesAttr - Returns gc attribute of this type. + /// getObjCGCAttr - Returns gc attribute of this type. inline Qualifiers::GC getObjCGCAttr() const; /// isObjCGCWeak true when Type is objc's weak. @@ -722,9 +828,24 @@ public: return getObjCGCAttr() == Qualifiers::Strong; } + /// getObjCLifetime - Returns lifetime attribute of this type. + Qualifiers::ObjCLifetime getObjCLifetime() const { + return getQualifiers().getObjCLifetime(); + } + + bool hasNonTrivialObjCLifetime() const { + return getQualifiers().hasNonTrivialObjCLifetime(); + } + + bool hasStrongOrWeakObjCLifetime() const { + return getQualifiers().hasStrongOrWeakObjCLifetime(); + } + enum DestructionKind { DK_none, - DK_cxx_destructor + DK_cxx_destructor, + DK_objc_strong_lifetime, + DK_objc_weak_lifetime }; /// isDestructedType - nonzero if objects of this type require @@ -735,6 +856,21 @@ public: return isDestructedTypeImpl(*this); } + /// \brief Determine whether expressions of the given type are forbidden + /// from being lvalues in C. + /// + /// The expression types that are forbidden to be lvalues are: + /// - 'void', but not qualified void + /// - function types + /// + /// The exact rule here is C99 6.3.2.1: + /// An lvalue is an expression with an object type or an incomplete + /// type other than void. + bool isCForbiddenLValueType() const; + + /// \brief Determine whether this type has trivial copy-assignment semantics. + bool hasTrivialCopyAssignment(ASTContext &Context) const; + private: // These methods are implemented in a separate translation unit; // "static"-ize them to avoid creating temporary QualTypes in the @@ -849,6 +985,11 @@ public: bool hasObjCGCAttr() const { return Quals.hasObjCGCAttr(); } Qualifiers::GC getObjCGCAttr() const { return Quals.getObjCGCAttr(); } + bool hasObjCLifetime() const { return Quals.hasObjCLifetime(); } + Qualifiers::ObjCLifetime getObjCLifetime() const { + return Quals.getObjCLifetime(); + } + bool hasAddressSpace() const { return Quals.hasAddressSpace(); } unsigned getAddressSpace() const { return Quals.getAddressSpace(); } @@ -931,6 +1072,10 @@ private: /// subclasses can pack their bitfields into the same word. unsigned Dependent : 1; + /// \brief Whether this type somehow involves a template parameter, even + /// if the resolution of the type does not depend on a template parameter. + unsigned InstantiationDependent : 1; + /// \brief Whether this type is a variably-modified type (C99 6.7.5). unsigned VariablyModified : 1; @@ -968,7 +1113,7 @@ private: return CachedLocalOrUnnamed; } }; - enum { NumTypeBits = 17 }; + enum { NumTypeBits = 18 }; protected: // These classes allow subclasses to somewhat cleanly pack bitfields @@ -1111,12 +1256,14 @@ private: protected: // silence VC++ warning C4355: 'this' : used in base member initializer list Type *this_() { return this; } - Type(TypeClass tc, QualType canon, bool Dependent, bool VariablyModified, + Type(TypeClass tc, QualType canon, bool Dependent, + bool InstantiationDependent, bool VariablyModified, bool ContainsUnexpandedParameterPack) : ExtQualsTypeCommonBase(this, canon.isNull() ? QualType(this_(), 0) : canon) { TypeBits.TC = tc; TypeBits.Dependent = Dependent; + TypeBits.InstantiationDependent = Dependent || InstantiationDependent; TypeBits.VariablyModified = VariablyModified; TypeBits.ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack; TypeBits.CacheValidAndVisibility = 0; @@ -1126,8 +1273,15 @@ protected: } friend class ASTContext; - void setDependent(bool D = true) { TypeBits.Dependent = D; } - void setVariablyModified(bool VM = true) { TypeBits.VariablyModified = VM; } + void setDependent(bool D = true) { + TypeBits.Dependent = D; + if (D) + TypeBits.InstantiationDependent = true; + } + void setInstantiationDependent(bool D = true) { + TypeBits.InstantiationDependent = D; } + void setVariablyModified(bool VM = true) { TypeBits.VariablyModified = VM; + } void setContainsUnexpandedParameterPack(bool PP = true) { TypeBits.ContainsUnexpandedParameterPack = PP; } @@ -1186,31 +1340,14 @@ public: return !isReferenceType() && !isFunctionType() && !isVoidType(); } - /// isPODType - Return true if this is a plain-old-data type (C++ 3.9p10). - bool isPODType() const; - /// isLiteralType - Return true if this is a literal type /// (C++0x [basic.types]p10) bool isLiteralType() const; - /// isTrivialType - Return true if this is a trivial type - /// (C++0x [basic.types]p9) - bool isTrivialType() const; - - /// isTriviallyCopyableType - Return true if this is a trivially copyable type - /// (C++0x [basic.types]p9 - bool isTriviallyCopyableType() const; - /// \brief Test if this type is a standard-layout type. /// (C++0x [basic.type]p9) bool isStandardLayoutType() const; - /// isCXX11PODType() - Return true if this is a POD type according to the - /// more relaxed rules of the C++11 standard, regardless of the current - /// compilation's language. - /// (C++0x [basic.types]p9) - bool isCXX11PODType() const; - /// Helper methods to distinguish type categories. All type predicates /// operate on the canonical type, ignoring typedefs and qualifiers. @@ -1290,7 +1427,11 @@ public: 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. + bool isObjCObjectPointerType() const; // pointer to ObjC object + bool isObjCRetainableType() const; // ObjC object or block pointer + bool isObjCLifetimeType() const; // (array of)* retainable type + bool isObjCIndirectLifetimeType() const; // (pointer to)* lifetime type + bool isObjCNSObjectType() const; // __attribute__((NSObject)) // FIXME: change this to 'raw' interface type, so we can used 'interface' type // for the common case. bool isObjCObjectType() const; // NSString or typeof(*(id)0) @@ -1302,9 +1443,19 @@ public: bool isObjCClassType() const; // Class bool isObjCSelType() const; // Class bool isObjCBuiltinType() const; // 'id' or 'Class' + bool isObjCARCBridgableType() const; + bool isCARCBridgableType() const; bool isTemplateTypeParmType() const; // C++ template type parameter bool isNullPtrType() const; // C++0x nullptr_t + /// Determines if this type, which must satisfy + /// isObjCLifetimeType(), is implicitly __unsafe_unretained rather + /// than implicitly __strong. + bool isObjCARCImplicitlyUnretainedType() const; + + /// Return the implicit lifetime for this type, which must not be dependent. + Qualifiers::ObjCLifetime getObjCARCImplicitLifetime() const; + enum ScalarTypeKind { STK_Pointer, STK_MemberPointer, @@ -1322,6 +1473,14 @@ public: /// (C++ [temp.dep.type]). bool isDependentType() const { return TypeBits.Dependent; } + /// \brief Determine whether this type is an instantiation-dependent type, + /// meaning that the type involves a template parameter (even if the + /// definition does not actually depend on the type substituted for that + /// template parameter). + bool isInstantiationDependentType() const { + return TypeBits.InstantiationDependent; + } + /// \brief Whether this type is a variably-modified type (C99 6.7.5). bool isVariablyModifiedType() const { return TypeBits.VariablyModified; } @@ -1336,6 +1495,8 @@ public: /// \brief Determine wither this type is a C++ elaborated-type-specifier. bool isElaboratedTypeSpecifier() const; + + bool canDecayToPointerType() const; /// hasPointerRepresentation - Whether this type is represented /// natively as a pointer; this includes pointers, references, block @@ -1480,6 +1641,7 @@ public: } CanQualType getCanonicalTypeUnqualified() const; // in CanonicalType.h void dump() const; + static bool classof(const Type *) { return true; } friend class ASTReader; @@ -1586,6 +1748,7 @@ public: public: BuiltinType(Kind K) : Type(Builtin, QualType(), /*Dependent=*/(K == Dependent), + /*InstantiationDependent=*/(K == Dependent), /*VariablyModified=*/false, /*Unexpanded paramter pack=*/false) { BuiltinTypeBits.Kind = K; @@ -1631,6 +1794,7 @@ class ComplexType : public Type, public llvm::FoldingSetNode { QualType ElementType; ComplexType(QualType Element, QualType CanonicalPtr) : Type(Complex, CanonicalPtr, Element->isDependentType(), + Element->isInstantiationDependentType(), Element->isVariablyModifiedType(), Element->containsUnexpandedParameterPack()), ElementType(Element) { @@ -1661,6 +1825,7 @@ class ParenType : public Type, public llvm::FoldingSetNode { ParenType(QualType InnerType, QualType CanonType) : Type(Paren, CanonType, InnerType->isDependentType(), + InnerType->isInstantiationDependentType(), InnerType->isVariablyModifiedType(), InnerType->containsUnexpandedParameterPack()), Inner(InnerType) { @@ -1692,6 +1857,7 @@ class PointerType : public Type, public llvm::FoldingSetNode { PointerType(QualType Pointee, QualType CanonicalPtr) : Type(Pointer, CanonicalPtr, Pointee->isDependentType(), + Pointee->isInstantiationDependentType(), Pointee->isVariablyModifiedType(), Pointee->containsUnexpandedParameterPack()), PointeeType(Pointee) { @@ -1724,6 +1890,7 @@ 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(), + Pointee->isInstantiationDependentType(), Pointee->isVariablyModifiedType(), Pointee->containsUnexpandedParameterPack()), PointeeType(Pointee) { @@ -1760,6 +1927,7 @@ protected: ReferenceType(TypeClass tc, QualType Referencee, QualType CanonicalRef, bool SpelledAsLValue) : Type(tc, CanonicalRef, Referencee->isDependentType(), + Referencee->isInstantiationDependentType(), Referencee->isVariablyModifiedType(), Referencee->containsUnexpandedParameterPack()), PointeeType(Referencee) @@ -1844,6 +2012,8 @@ class MemberPointerType : public Type, public llvm::FoldingSetNode { MemberPointerType(QualType Pointee, const Type *Cls, QualType CanonicalPtr) : Type(MemberPointer, CanonicalPtr, Cls->isDependentType() || Pointee->isDependentType(), + (Cls->isInstantiationDependentType() || + Pointee->isInstantiationDependentType()), Pointee->isVariablyModifiedType(), (Cls->containsUnexpandedParameterPack() || Pointee->containsUnexpandedParameterPack())), @@ -1911,6 +2081,7 @@ protected: ArraySizeModifier sm, unsigned tq, bool ContainsUnexpandedParameterPack) : Type(tc, can, et->isDependentType() || tc == DependentSizedArray, + et->isInstantiationDependentType() || tc == DependentSizedArray, (tc == VariableArray || et->isVariablyModifiedType()), ContainsUnexpandedParameterPack), ElementType(et) { @@ -2344,28 +2515,32 @@ class FunctionType : public Type { // you'll need to adjust both the Bits field below and // Type::FunctionTypeBitfields. - // | CC |noreturn|hasregparm|regparm - // |0 .. 2| 3 | 4 |5 .. 7 + // | CC |noreturn|produces|regparm| + // |0 .. 2| 3 | 4 | 5 .. 7| + // + // regparm is either 0 (no regparm attribute) or the regparm value+1. enum { CallConvMask = 0x7 }; enum { NoReturnMask = 0x8 }; - enum { HasRegParmMask = 0x10 }; - enum { RegParmMask = ~(CallConvMask | NoReturnMask), - RegParmOffset = 5 }; + enum { ProducesResultMask = 0x10 }; + enum { RegParmMask = ~(CallConvMask | NoReturnMask | ProducesResultMask), + RegParmOffset = 5 }; // Assumed to be the last field - unsigned char Bits; + uint16_t Bits; - ExtInfo(unsigned Bits) : Bits(static_cast(Bits)) {} + ExtInfo(unsigned Bits) : Bits(static_cast(Bits)) {} friend class FunctionType; public: // Constructor with no defaults. Use this when you know that you // have all the elements (when reading an AST file for example). - ExtInfo(bool noReturn, bool hasRegParm, unsigned regParm, CallingConv cc) { + ExtInfo(bool noReturn, bool hasRegParm, unsigned regParm, CallingConv cc, + bool producesResult) { + assert((!hasRegParm || regParm < 7) && "Invalid regparm value"); Bits = ((unsigned) cc) | (noReturn ? NoReturnMask : 0) | - (hasRegParm ? HasRegParmMask : 0) | - (regParm << RegParmOffset); + (producesResult ? ProducesResultMask : 0) | + (hasRegParm ? ((regParm + 1) << RegParmOffset) : 0); } // Constructor with all defaults. Use when for example creating a @@ -2373,8 +2548,14 @@ class FunctionType : public Type { ExtInfo() : Bits(0) {} bool getNoReturn() const { return Bits & NoReturnMask; } - bool getHasRegParm() const { return Bits & HasRegParmMask; } - unsigned getRegParm() const { return Bits >> RegParmOffset; } + bool getProducesResult() const { return Bits & ProducesResultMask; } + bool getHasRegParm() const { return (Bits >> RegParmOffset) != 0; } + unsigned getRegParm() const { + unsigned RegParm = Bits >> RegParmOffset; + if (RegParm > 0) + --RegParm; + return RegParm; + } CallingConv getCC() const { return CallingConv(Bits & CallConvMask); } bool operator==(ExtInfo Other) const { @@ -2394,8 +2575,17 @@ class FunctionType : public Type { return ExtInfo(Bits & ~NoReturnMask); } + ExtInfo withProducesResult(bool producesResult) const { + if (producesResult) + return ExtInfo(Bits | ProducesResultMask); + else + return ExtInfo(Bits & ~ProducesResultMask); + } + ExtInfo withRegParm(unsigned RegParm) const { - return ExtInfo(HasRegParmMask | (Bits & ~RegParmMask) | (RegParm << RegParmOffset)); + assert(RegParm < 7 && "Invalid regparm value"); + return ExtInfo((Bits & ~RegParmMask) | + ((RegParm + 1) << RegParmOffset)); } ExtInfo withCallingConv(CallingConv cc) const { @@ -2411,9 +2601,10 @@ protected: FunctionType(TypeClass tc, QualType res, bool variadic, unsigned typeQuals, RefQualifierKind RefQualifier, QualType Canonical, bool Dependent, + bool InstantiationDependent, bool VariablyModified, bool ContainsUnexpandedParameterPack, ExtInfo Info) - : Type(tc, Canonical, Dependent, VariablyModified, + : Type(tc, Canonical, Dependent, InstantiationDependent, VariablyModified, ContainsUnexpandedParameterPack), ResultType(res) { FunctionTypeBits.ExtInfo = Info.Bits; @@ -2458,7 +2649,8 @@ public: class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode { FunctionNoProtoType(QualType Result, QualType Canonical, ExtInfo Info) : FunctionType(FunctionNoProto, Result, false, 0, RQ_None, Canonical, - /*Dependent=*/false, Result->isVariablyModifiedType(), + /*Dependent=*/false, /*InstantiationDependent=*/false, + Result->isVariablyModifiedType(), /*ContainsUnexpandedParameterPack=*/false, Info) {} friend class ASTContext; // ASTContext creates these. @@ -2495,7 +2687,8 @@ public: struct ExtProtoInfo { ExtProtoInfo() : Variadic(false), ExceptionSpecType(EST_None), TypeQuals(0), - RefQualifier(RQ_None), NumExceptions(0), Exceptions(0), NoexceptExpr(0) {} + RefQualifier(RQ_None), NumExceptions(0), Exceptions(0), NoexceptExpr(0), + ConsumedArguments(0) {} FunctionType::ExtInfo ExtInfo; bool Variadic; @@ -2505,6 +2698,7 @@ public: unsigned NumExceptions; const QualType *Exceptions; Expr *NoexceptExpr; + const bool *ConsumedArguments; }; private: @@ -2523,7 +2717,7 @@ private: QualType canonical, const ExtProtoInfo &epi); /// NumArgs - The number of arguments this function has, not counting '...'. - unsigned NumArgs : 20; + unsigned NumArgs : 19; /// NumExceptions - The number of types in the exception spec, if any. unsigned NumExceptions : 9; @@ -2531,6 +2725,9 @@ private: /// ExceptionSpecType - The type of exception specification this function has. unsigned ExceptionSpecType : 3; + /// HasAnyConsumedArgs - Whether this function has any consumed arguments. + unsigned HasAnyConsumedArgs : 1; + /// ArgInfo - There is an variable size array after the class in memory that /// holds the argument types. @@ -2540,8 +2737,25 @@ private: /// NoexceptExpr - Instead of Exceptions, there may be a single Expr* pointing /// to the expression in the noexcept() specifier. + /// ConsumedArgs - A variable size array, following Exceptions + /// and of length NumArgs, holding flags indicating which arguments + /// are consumed. This only appears if HasAnyConsumedArgs is true. + friend class ASTContext; // ASTContext creates these. + const bool *getConsumedArgsBuffer() const { + assert(hasAnyConsumedArgs()); + + // Find the end of the exceptions. + Expr * const *eh_end = reinterpret_cast(arg_type_end()); + if (getExceptionSpecType() != EST_ComputedNoexcept) + eh_end += NumExceptions; + else + eh_end += 1; // NoexceptExpr + + return reinterpret_cast(eh_end); + } + public: unsigned getNumArgs() const { return NumArgs; } QualType getArgType(unsigned i) const { @@ -2562,6 +2776,8 @@ public: } else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) { EPI.NoexceptExpr = getNoexceptExpr(); } + if (hasAnyConsumedArgs()) + EPI.ConsumedArguments = getConsumedArgsBuffer(); return EPI; } @@ -2647,6 +2863,16 @@ public: return exception_begin() + NumExceptions; } + bool hasAnyConsumedArgs() const { + return HasAnyConsumedArgs; + } + bool isArgConsumed(unsigned I) const { + assert(I < getNumArgs() && "argument index out of range!"); + if (hasAnyConsumedArgs()) + return getConsumedArgsBuffer()[I]; + return false; + } + bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } @@ -2670,7 +2896,7 @@ class UnresolvedUsingType : public Type { UnresolvedUsingTypenameDecl *Decl; UnresolvedUsingType(const UnresolvedUsingTypenameDecl *D) - : Type(UnresolvedUsing, QualType(), true, false, + : Type(UnresolvedUsing, QualType(), true, true, false, /*ContainsUnexpandedParameterPack=*/false), Decl(const_cast(D)) {} friend class ASTContext; // ASTContext creates these. @@ -2700,7 +2926,9 @@ class TypedefType : public Type { TypedefNameDecl *Decl; protected: TypedefType(TypeClass tc, const TypedefNameDecl *D, QualType can) - : Type(tc, can, can->isDependentType(), can->isVariablyModifiedType(), + : Type(tc, can, can->isDependentType(), + can->isInstantiationDependentType(), + can->isVariablyModifiedType(), /*ContainsUnexpandedParameterPack=*/false), Decl(const_cast(D)) { assert(!isa(can) && "Invalid canonical type"); @@ -2731,7 +2959,7 @@ public: QualType desugar() const; /// \brief Returns whether this type directly provides sugar. - bool isSugared() const { return true; } + bool isSugared() const; static bool classof(const Type *T) { return T->getTypeClass() == TypeOfExpr; } static bool classof(const TypeOfExprType *) { return true; } @@ -2751,9 +2979,6 @@ public: DependentTypeOfExprType(const 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()); } @@ -2766,7 +2991,9 @@ public: class TypeOfType : public Type { QualType TOType; TypeOfType(QualType T, QualType can) - : Type(TypeOf, can, T->isDependentType(), T->isVariablyModifiedType(), + : Type(TypeOf, can, T->isDependentType(), + T->isInstantiationDependentType(), + T->isVariablyModifiedType(), T->containsUnexpandedParameterPack()), TOType(T) { assert(!isa(can) && "Invalid canonical type"); @@ -2802,10 +3029,10 @@ public: QualType getUnderlyingType() const { return UnderlyingType; } /// \brief Remove a single level of sugar. - QualType desugar() const { return getUnderlyingType(); } + QualType desugar() const; /// \brief Returns whether this type directly provides sugar. - bool isSugared() const { return !isDependentType(); } + bool isSugared() const; static bool classof(const Type *T) { return T->getTypeClass() == Decltype; } static bool classof(const DecltypeType *) { return true; } @@ -2823,9 +3050,6 @@ class DependentDecltypeType : public DecltypeType, public llvm::FoldingSetNode { public: DependentDecltypeType(const 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()); } @@ -2971,6 +3195,7 @@ public: // Enumerated operand (string or keyword). attr_objc_gc, + attr_objc_ownership, attr_pcs, FirstEnumOperandKind = attr_objc_gc, @@ -2994,6 +3219,7 @@ private: AttributedType(QualType canon, Kind attrKind, QualType modified, QualType equivalent) : Type(Attributed, canon, canon->isDependentType(), + canon->isInstantiationDependentType(), canon->isVariablyModifiedType(), canon->containsUnexpandedParameterPack()), ModifiedType(modified), EquivalentType(equivalent) { @@ -3046,13 +3272,16 @@ class TemplateTypeParmType : public Type, public llvm::FoldingSetNode { /// Build a non-canonical type. TemplateTypeParmType(TemplateTypeParmDecl *TTPDecl, QualType Canon) : Type(TemplateTypeParm, Canon, /*Dependent=*/true, + /*InstantiationDependent=*/true, /*VariablyModified=*/false, Canon->containsUnexpandedParameterPack()), TTPDecl(TTPDecl) { } /// Build the canonical type. TemplateTypeParmType(unsigned D, unsigned I, bool PP) - : Type(TemplateTypeParm, QualType(this, 0), /*Dependent=*/true, + : Type(TemplateTypeParm, QualType(this, 0), + /*Dependent=*/true, + /*InstantiationDependent=*/true, /*VariablyModified=*/false, PP) { CanTTPTInfo.Depth = D; CanTTPTInfo.Index = I; @@ -3112,6 +3341,7 @@ class SubstTemplateTypeParmType : public Type, public llvm::FoldingSetNode { SubstTemplateTypeParmType(const TemplateTypeParmType *Param, QualType Canon) : Type(SubstTemplateTypeParm, Canon, Canon->isDependentType(), + Canon->isInstantiationDependentType(), Canon->isVariablyModifiedType(), Canon->containsUnexpandedParameterPack()), Replaced(Param) { } @@ -3211,6 +3441,7 @@ class AutoType : public Type, public llvm::FoldingSetNode { AutoType(QualType DeducedType) : Type(Auto, DeducedType.isNull() ? QualType(this, 0) : DeducedType, /*Dependent=*/DeducedType.isNull(), + /*InstantiationDependent=*/DeducedType.isNull(), /*VariablyModified=*/false, /*ContainsParameterPack=*/false) { assert((DeducedType.isNull() || !DeducedType->isDependentType()) && "deduced a dependent type for auto"); @@ -3244,28 +3475,35 @@ public: static bool classof(const AutoType *T) { return true; } }; -/// \brief Represents the type of a template specialization as written -/// in the source code. +/// \brief Represents a type template specialization; the template +/// must be a class template, a type alias template, or a template +/// template parameter. A template which cannot be resolved to one of +/// these, e.g. because it is written with a dependent scope +/// specifier, is instead represented as a +/// @c DependentTemplateSpecializationType. /// -/// Template specialization types represent the syntactic form of a -/// template-id that refers to a type, e.g., @c vector. Some -/// template specialization types are syntactic sugar, whose canonical -/// type will point to some other type node that represents the -/// instantiation or class template specialization. For example, a -/// class template specialization type of @c vector will refer to -/// a tag type for the instantiation -/// @c std::vector>. +/// A non-dependent template specialization type is always "sugar", +/// typically for a @c RecordType. For example, a class template +/// specialization type of @c vector will refer to 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. +/// Template specializations are dependent if either the template or +/// any of the template arguments are dependent, in which case the +/// type may also be canonical. /// -/// An instance of this type is followed by an array of TemplateArgument*s, -/// then, if the template specialization type is for a type alias template, -/// a QualType representing the non-canonical aliased type. +/// Instances of this type are allocated with a trailing array of +/// TemplateArguments, followed by a QualType representing the +/// non-canonical aliased type when the template is a type alias +/// template. class TemplateSpecializationType : public Type, public llvm::FoldingSetNode { - /// \brief The name of the template being specialized. + /// \brief The name of the template being specialized. This is + /// either a TemplateName::Template (in which case it is a + /// ClassTemplateDecl*, a TemplateTemplateParmDecl*, or a + /// TypeAliasTemplateDecl*), a + /// TemplateName::SubstTemplateTemplateParmPack, or a + /// TemplateName::SubstTemplateTemplateParm (in which case the + /// replacement must, recursively, be one of these). TemplateName Template; /// \brief - The number of template arguments named in this class @@ -3283,12 +3521,15 @@ public: /// \brief Determine whether any of the given template arguments are /// dependent. static bool anyDependentTemplateArguments(const TemplateArgument *Args, - unsigned NumArgs); + unsigned NumArgs, + bool &InstantiationDependent); static bool anyDependentTemplateArguments(const TemplateArgumentLoc *Args, - unsigned NumArgs); + unsigned NumArgs, + bool &InstantiationDependent); - static bool anyDependentTemplateArguments(const TemplateArgumentListInfo &); + static bool anyDependentTemplateArguments(const TemplateArgumentListInfo &, + bool &InstantiationDependent); /// \brief Print a template argument list, including the '<' and '>' /// enclosing the template arguments. @@ -3399,6 +3640,7 @@ class InjectedClassNameType : public Type { // interdependencies. InjectedClassNameType(CXXRecordDecl *D, QualType TST) : Type(InjectedClassName, QualType(), /*Dependent=*/true, + /*InstantiationDependent=*/true, /*VariablyModified=*/false, /*ContainsUnexpandedParameterPack=*/false), Decl(D), InjectedType(TST) { @@ -3461,9 +3703,10 @@ enum ElaboratedTypeKeyword { class TypeWithKeyword : public Type { protected: TypeWithKeyword(ElaboratedTypeKeyword Keyword, TypeClass tc, - QualType Canonical, bool Dependent, bool VariablyModified, + QualType Canonical, bool Dependent, + bool InstantiationDependent, bool VariablyModified, bool ContainsUnexpandedParameterPack) - : Type(tc, Canonical, Dependent, VariablyModified, + : Type(tc, Canonical, Dependent, InstantiationDependent, VariablyModified, ContainsUnexpandedParameterPack) { TypeWithKeywordBits.Keyword = Keyword; } @@ -3523,6 +3766,7 @@ class ElaboratedType : public TypeWithKeyword, public llvm::FoldingSetNode { QualType NamedType, QualType CanonType) : TypeWithKeyword(Keyword, Elaborated, CanonType, NamedType->isDependentType(), + NamedType->isInstantiationDependentType(), NamedType->isVariablyModifiedType(), NamedType->containsUnexpandedParameterPack()), NNS(NNS), NamedType(NamedType) { @@ -3585,6 +3829,7 @@ class DependentNameType : public TypeWithKeyword, public llvm::FoldingSetNode { DependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, const IdentifierInfo *Name, QualType CanonType) : TypeWithKeyword(Keyword, DependentName, CanonType, /*Dependent=*/true, + /*InstantiationDependent=*/true, /*VariablyModified=*/false, NNS->containsUnexpandedParameterPack()), NNS(NNS), Name(Name) { @@ -3738,6 +3983,7 @@ class PackExpansionType : public Type, public llvm::FoldingSetNode { PackExpansionType(QualType Pattern, QualType Canon, llvm::Optional NumExpansions) : Type(PackExpansion, Canon, /*Dependent=*/true, + /*InstantiationDependent=*/true, /*VariableModified=*/Pattern->isVariablyModifiedType(), /*ContainsUnexpandedParameterPack=*/false), Pattern(Pattern), @@ -3829,7 +4075,7 @@ protected: enum Nonce_ObjCInterface { Nonce_ObjCInterface }; ObjCObjectType(enum Nonce_ObjCInterface) - : Type(ObjCInterface, QualType(), false, false, false), + : Type(ObjCInterface, QualType(), false, false, false, false), BaseType(QualType(this_(), 0)) { ObjCObjectTypeBits.NumProtocols = 0; } @@ -3986,7 +4232,7 @@ class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode { QualType PointeeType; ObjCObjectPointerType(QualType Canonical, QualType Pointee) - : Type(ObjCObjectPointer, Canonical, false, false, false), + : Type(ObjCObjectPointer, Canonical, false, false, false, false), PointeeType(Pointee) {} friend class ASTContext; // ASTContext creates these. @@ -4303,6 +4549,11 @@ inline QualType QualType::getNonReferenceType() const { return *this; } +inline bool QualType::isCForbiddenLValueType() const { + return ((getTypePtr()->isVoidType() && !hasQualifiers()) || + getTypePtr()->isFunctionType()); +} + /// \brief Tests whether the type is categorized as a fundamental type. /// /// \returns True for types specified in C++0x [basic.fundamental]. @@ -4480,6 +4731,11 @@ inline bool Type::isOverloadableType() const { return isDependentType() || isRecordType() || isEnumeralType(); } +/// \brief Determines whether this type can decay to a pointer type. +inline bool Type::canDecayToPointerType() const { + return isFunctionType() || isArrayType(); +} + inline bool Type::hasPointerRepresentation() const { return (isPointerType() || isReferenceType() || isBlockPointerType() || isObjCObjectPointerType() || isNullPtrType()); diff --git a/include/clang/Analysis/Analyses/UninitializedValues.h b/include/clang/Analysis/Analyses/UninitializedValues.h index b966f3a90fff..badb493a9df4 100644 --- a/include/clang/Analysis/Analyses/UninitializedValues.h +++ b/include/clang/Analysis/Analyses/UninitializedValues.h @@ -32,10 +32,16 @@ public: const VarDecl *vd, bool isAlwaysUninit) {} }; - + +struct UninitVariablesAnalysisStats { + unsigned NumVariablesAnalyzed; + unsigned NumBlockVisits; +}; + void runUninitializedVariablesAnalysis(const DeclContext &dc, const CFG &cfg, AnalysisContext &ac, - UninitVariablesHandler &handler); + UninitVariablesHandler &handler, + UninitVariablesAnalysisStats &stats); } #endif diff --git a/include/clang/Analysis/AnalysisContext.h b/include/clang/Analysis/AnalysisContext.h index 66c12a5384d4..6a1876e65900 100644 --- a/include/clang/Analysis/AnalysisContext.h +++ b/include/clang/Analysis/AnalysisContext.h @@ -107,6 +107,11 @@ public: void dumpCFG(); + /// \brief Returns true if we have built a CFG for this analysis context. + /// Note that this doesn't correspond to whether or not a valid CFG exists, it + /// corresponds to whether we *attempted* to build one. + bool isCFGBuilt() const { return builtCFG; } + ParentMap &getParentMap(); PseudoConstantAnalysis *getPseudoConstantAnalysis(); LiveVariables *getLiveVariables(); diff --git a/include/clang/Analysis/DomainSpecific/CocoaConventions.h b/include/clang/Analysis/DomainSpecific/CocoaConventions.h index 18e81fed79f8..5a4e06ff53e5 100644 --- a/include/clang/Analysis/DomainSpecific/CocoaConventions.h +++ b/include/clang/Analysis/DomainSpecific/CocoaConventions.h @@ -7,34 +7,45 @@ // //===----------------------------------------------------------------------===// // -// This file defines +// This file implements cocoa naming convention analysis. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_ANALYSIS_DS_COCOA #define LLVM_CLANG_ANALYSIS_DS_COCOA +#include "llvm/ADT/StringRef.h" #include "clang/AST/Type.h" namespace clang { + +class ObjCMethodDecl; + namespace ento { namespace cocoa { enum NamingConvention { NoConvention, CreateRule, InitRule }; - NamingConvention deriveNamingConvention(Selector S); + NamingConvention deriveNamingConvention(Selector S, const ObjCMethodDecl *MD); - static inline bool followsFundamentalRule(Selector S) { - return deriveNamingConvention(S) == CreateRule; + static inline bool followsFundamentalRule(Selector S, + const ObjCMethodDecl *MD) { + return deriveNamingConvention(S, MD) == CreateRule; } bool isRefType(QualType RetTy, llvm::StringRef Prefix, llvm::StringRef Name = llvm::StringRef()); - + + bool isCocoaObjectRef(QualType T); + +} + +namespace coreFoundation { bool isCFObjectRef(QualType T); - bool isCocoaObjectRef(QualType T); + bool followsCreateRule(llvm::StringRef functionName); +} -}}} +}} // end: "clang:ento" #endif diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index e4c6722e8378..e64dc6a2ade0 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -400,6 +400,11 @@ def ObjCNSObject : InheritableAttr { let Spellings = ["NSObject"]; } +def ObjCPreciseLifetime : Attr { + let Spellings = ["objc_precise_lifetime"]; + let Subjects = [Var]; +} + def Overloadable : Attr { let Spellings = ["overloadable"]; } @@ -479,6 +484,10 @@ def Unavailable : InheritableAttr { let Args = [StringArgument<"Message">]; } +def ArcWeakrefUnavailable : InheritableAttr { + let Spellings = ["objc_arc_weak_reference_unavailable"]; +} + def Unused : InheritableAttr { let Spellings = ["unused"]; } diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def index 9a4c768dc649..a3cc6156238e 100644 --- a/include/clang/Basic/Builtins.def +++ b/include/clang/Basic/Builtins.def @@ -604,6 +604,8 @@ BUILTIN(__builtin_rindex, "c*cC*i", "Fn") // Microsoft builtins. BUILTIN(__assume, "vb", "n") BUILTIN(__noop, "v.", "n") +BUILTIN(__debugbreak, "v", "n") + // C99 library functions // C99 stdlib.h @@ -727,6 +729,10 @@ LIBBUILTIN(cos, "dd", "fe", "math.h", ALL_LANGUAGES) LIBBUILTIN(cosl, "LdLd", "fe", "math.h", ALL_LANGUAGES) LIBBUILTIN(cosf, "ff", "fe", "math.h", ALL_LANGUAGES) +LIBBUILTIN(fma, "dddd", "fc", "math.h", ALL_LANGUAGES) +LIBBUILTIN(fmal, "LdLdLdLd", "fc", "math.h", ALL_LANGUAGES) +LIBBUILTIN(fmaf, "ffff", "fc", "math.h", ALL_LANGUAGES) + // Blocks runtime Builtin math library functions LIBBUILTIN(_Block_object_assign, "vv*vC*iC", "f", "Blocks.h", ALL_LANGUAGES) LIBBUILTIN(_Block_object_dispose, "vvC*iC", "f", "Blocks.h", ALL_LANGUAGES) diff --git a/include/clang/Basic/Builtins.h b/include/clang/Basic/Builtins.h index 0d17e03d8a52..7469e144c150 100644 --- a/include/clang/Basic/Builtins.h +++ b/include/clang/Basic/Builtins.h @@ -50,7 +50,6 @@ enum ID { struct Info { const char *Name, *Type, *Attributes, *HeaderName; LanguageID builtin_lang; - bool Suppressed; bool operator==(const Info &RHS) const { return !strcmp(Name, RHS.Name) && diff --git a/include/clang/Basic/BuiltinsX86.def b/include/clang/Basic/BuiltinsX86.def index 6ef667db7beb..6bd901469cee 100644 --- a/include/clang/Basic/BuiltinsX86.def +++ b/include/clang/Basic/BuiltinsX86.def @@ -26,6 +26,7 @@ // 3DNow! // +BUILTIN(__builtin_ia32_femms, "v", "") BUILTIN(__builtin_ia32_pavgusb, "V8cV8cV8c", "nc") BUILTIN(__builtin_ia32_pf2id, "V2iV2f", "nc") BUILTIN(__builtin_ia32_pfacc, "V2fV2fV2f", "nc") @@ -47,7 +48,7 @@ BUILTIN(__builtin_ia32_pfsub, "V2fV2fV2f", "nc") BUILTIN(__builtin_ia32_pfsubr, "V2fV2fV2f", "nc") BUILTIN(__builtin_ia32_pi2fd, "V2fV2i", "nc") BUILTIN(__builtin_ia32_pmulhrw, "V4sV4sV4s", "nc") -// 3DNow! Extensions. +// 3DNow! Extensions (3dnowa). BUILTIN(__builtin_ia32_pf2iw, "V2iV2f", "nc") BUILTIN(__builtin_ia32_pfnacc, "V2fV2fV2f", "nc") BUILTIN(__builtin_ia32_pfpnacc, "V2fV2fV2f", "nc") @@ -57,15 +58,13 @@ BUILTIN(__builtin_ia32_pswapdsi, "V2iV2i", "nc") // MMX // -// FIXME: All MMX instructions will be generated via builtins. Any MMX vector +// All MMX instructions will be generated via builtins. Any MMX vector // types (<1 x i64>, <2 x i32>, etc.) that aren't used by these builtins will be // expanded by the back-end. BUILTIN(__builtin_ia32_emms, "v", "") -BUILTIN(__builtin_ia32_femms, "v", "") BUILTIN(__builtin_ia32_paddb, "V8cV8cV8c", "") BUILTIN(__builtin_ia32_paddw, "V4sV4sV4s", "") BUILTIN(__builtin_ia32_paddd, "V2iV2iV2i", "") -BUILTIN(__builtin_ia32_paddq, "V1LLiV1LLiV1LLi", "") BUILTIN(__builtin_ia32_paddsb, "V8cV8cV8c", "") BUILTIN(__builtin_ia32_paddsw, "V4sV4sV4s", "") BUILTIN(__builtin_ia32_paddusb, "V8cV8cV8c", "") @@ -73,27 +72,17 @@ BUILTIN(__builtin_ia32_paddusw, "V4sV4sV4s", "") BUILTIN(__builtin_ia32_psubb, "V8cV8cV8c", "") BUILTIN(__builtin_ia32_psubw, "V4sV4sV4s", "") BUILTIN(__builtin_ia32_psubd, "V2iV2iV2i", "") -BUILTIN(__builtin_ia32_psubq, "V1LLiV1LLiV1LLi", "") BUILTIN(__builtin_ia32_psubsb, "V8cV8cV8c", "") BUILTIN(__builtin_ia32_psubsw, "V4sV4sV4s", "") BUILTIN(__builtin_ia32_psubusb, "V8cV8cV8c", "") BUILTIN(__builtin_ia32_psubusw, "V4sV4sV4s", "") BUILTIN(__builtin_ia32_pmulhw, "V4sV4sV4s", "") BUILTIN(__builtin_ia32_pmullw, "V4sV4sV4s", "") -BUILTIN(__builtin_ia32_pmulhuw, "V4sV4sV4s", "") -BUILTIN(__builtin_ia32_pmuludq, "V1LLiV2iV2i", "") BUILTIN(__builtin_ia32_pmaddwd, "V2iV4sV4s", "") BUILTIN(__builtin_ia32_pand, "V1LLiV1LLiV1LLi", "") BUILTIN(__builtin_ia32_pandn, "V1LLiV1LLiV1LLi", "") BUILTIN(__builtin_ia32_por, "V1LLiV1LLiV1LLi", "") BUILTIN(__builtin_ia32_pxor, "V1LLiV1LLiV1LLi", "") -BUILTIN(__builtin_ia32_pavgb, "V8cV8cV8c", "") -BUILTIN(__builtin_ia32_pavgw, "V4sV4sV4s", "") -BUILTIN(__builtin_ia32_pmaxub, "V8cV8cV8c", "") -BUILTIN(__builtin_ia32_pmaxsw, "V4sV4sV4s", "") -BUILTIN(__builtin_ia32_pminub, "V8cV8cV8c", "") -BUILTIN(__builtin_ia32_pminsw, "V4sV4sV4s", "") -BUILTIN(__builtin_ia32_psadbw, "V4sV8cV8c", "") BUILTIN(__builtin_ia32_psllw, "V4sV4sV1LLi", "") BUILTIN(__builtin_ia32_pslld, "V2iV2iV1LLi", "") BUILTIN(__builtin_ia32_psllq, "V1LLiV1LLiV1LLi", "") @@ -113,7 +102,6 @@ BUILTIN(__builtin_ia32_psradi, "V2iV2ii", "") BUILTIN(__builtin_ia32_packsswb, "V8cV4sV4s", "") BUILTIN(__builtin_ia32_packssdw, "V4sV2iV2i", "") BUILTIN(__builtin_ia32_packuswb, "V8cV4sV4s", "") -BUILTIN(__builtin_ia32_pshufw, "V4sV4sIc", "") BUILTIN(__builtin_ia32_punpckhbw, "V8cV8cV8c", "") BUILTIN(__builtin_ia32_punpckhwd, "V4sV4sV4s", "") BUILTIN(__builtin_ia32_punpckhdq, "V2iV2iV2i", "") @@ -127,14 +115,53 @@ BUILTIN(__builtin_ia32_pcmpgtb, "V8cV8cV8c", "") BUILTIN(__builtin_ia32_pcmpgtw, "V4sV4sV4s", "") BUILTIN(__builtin_ia32_pcmpgtd, "V2iV2iV2i", "") BUILTIN(__builtin_ia32_maskmovq, "vV8cV8cc*", "") -BUILTIN(__builtin_ia32_pmovmskb, "iV8c", "") BUILTIN(__builtin_ia32_movntq, "vV1LLi*V1LLi", "") -BUILTIN(__builtin_ia32_palignr, "V8cV8cV8cIc", "") BUILTIN(__builtin_ia32_vec_init_v2si, "V2iii", "") BUILTIN(__builtin_ia32_vec_init_v4hi, "V4sssss", "") BUILTIN(__builtin_ia32_vec_init_v8qi, "V8ccccccccc", "") BUILTIN(__builtin_ia32_vec_ext_v2si, "iV2ii", "") +// MMX2 (MMX+SSE) intrinsics +BUILTIN(__builtin_ia32_cvtpi2ps, "V4fV4fV2i", "") +BUILTIN(__builtin_ia32_cvtps2pi, "V2iV4f", "") +BUILTIN(__builtin_ia32_cvttps2pi, "V2iV4f", "") +BUILTIN(__builtin_ia32_pavgb, "V8cV8cV8c", "") +BUILTIN(__builtin_ia32_pavgw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_pmaxsw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_pmaxub, "V8cV8cV8c", "") +BUILTIN(__builtin_ia32_pminsw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_pminub, "V8cV8cV8c", "") +BUILTIN(__builtin_ia32_pmovmskb, "iV8c", "") +BUILTIN(__builtin_ia32_pmulhuw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_psadbw, "V4sV8cV8c", "") +BUILTIN(__builtin_ia32_pshufw, "V4sV4sIc", "") + +// MMX+SSE2 +BUILTIN(__builtin_ia32_cvtpd2pi, "V2iV2d", "") +BUILTIN(__builtin_ia32_cvtpi2pd, "V2dV2i", "") +BUILTIN(__builtin_ia32_cvttpd2pi, "V2iV2d", "") +BUILTIN(__builtin_ia32_paddq, "V1LLiV1LLiV1LLi", "") +BUILTIN(__builtin_ia32_pmuludq, "V1LLiV2iV2i", "") +BUILTIN(__builtin_ia32_psubq, "V1LLiV1LLiV1LLi", "") + +// MMX+SSSE3 +BUILTIN(__builtin_ia32_pabsb, "V8cV8c", "") +BUILTIN(__builtin_ia32_pabsd, "V2iV2i", "") +BUILTIN(__builtin_ia32_pabsw, "V4sV4s", "") +BUILTIN(__builtin_ia32_palignr, "V8cV8cV8cIc", "") +BUILTIN(__builtin_ia32_phaddd, "V2iV2iV2i", "") +BUILTIN(__builtin_ia32_phaddsw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_phaddw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_phsubd, "V2iV2iV2i", "") +BUILTIN(__builtin_ia32_phsubsw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_phsubw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_pmaddubsw, "V8cV8cV8c", "") +BUILTIN(__builtin_ia32_pmulhrsw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_pshufb, "V8cV8cV8c", "") +BUILTIN(__builtin_ia32_psignw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_psignb, "V8cV8cV8c", "") +BUILTIN(__builtin_ia32_psignd, "V2iV2iV2i", "") + // SSE intrinsics. BUILTIN(__builtin_ia32_comieq, "iV4fV4f", "") BUILTIN(__builtin_ia32_comilt, "iV4fV4f", "") @@ -204,42 +231,24 @@ BUILTIN(__builtin_ia32_haddpd, "V2dV2dV2d", "") BUILTIN(__builtin_ia32_hsubps, "V4fV4fV4f", "") BUILTIN(__builtin_ia32_hsubpd, "V2dV2dV2d", "") BUILTIN(__builtin_ia32_phaddw128, "V8sV8sV8s", "") -BUILTIN(__builtin_ia32_phaddw, "V4sV4sV4s", "") BUILTIN(__builtin_ia32_phaddd128, "V4iV4iV4i", "") -BUILTIN(__builtin_ia32_phaddd, "V2iV2iV2i", "") BUILTIN(__builtin_ia32_phaddsw128, "V8sV8sV8s", "") -BUILTIN(__builtin_ia32_phaddsw, "V4sV4sV4s", "") BUILTIN(__builtin_ia32_phsubw128, "V8sV8sV8s", "") -BUILTIN(__builtin_ia32_phsubw, "V4sV4sV4s", "") BUILTIN(__builtin_ia32_phsubd128, "V4iV4iV4i", "") -BUILTIN(__builtin_ia32_phsubd, "V2iV2iV2i", "") BUILTIN(__builtin_ia32_phsubsw128, "V8sV8sV8s", "") -BUILTIN(__builtin_ia32_phsubsw, "V4sV4sV4s", "") BUILTIN(__builtin_ia32_pmaddubsw128, "V16cV16cV16c", "") -BUILTIN(__builtin_ia32_pmaddubsw, "V8cV8cV8c", "") BUILTIN(__builtin_ia32_pmulhrsw128, "V8sV8sV8s", "") -BUILTIN(__builtin_ia32_pmulhrsw, "V4sV4sV4s", "") BUILTIN(__builtin_ia32_pshufb128, "V16cV16cV16c", "") -BUILTIN(__builtin_ia32_pshufb, "V8cV8cV8c", "") BUILTIN(__builtin_ia32_psignb128, "V16cV16cV16c", "") -BUILTIN(__builtin_ia32_psignb, "V8cV8cV8c", "") BUILTIN(__builtin_ia32_psignw128, "V8sV8sV8s", "") -BUILTIN(__builtin_ia32_psignw, "V4sV4sV4s", "") BUILTIN(__builtin_ia32_psignd128, "V4iV4iV4i", "") -BUILTIN(__builtin_ia32_psignd, "V2iV2iV2i", "") BUILTIN(__builtin_ia32_pabsb128, "V16cV16c", "") -BUILTIN(__builtin_ia32_pabsb, "V8cV8c", "") BUILTIN(__builtin_ia32_pabsw128, "V8sV8s", "") -BUILTIN(__builtin_ia32_pabsw, "V4sV4s", "") BUILTIN(__builtin_ia32_pabsd128, "V4iV4i", "") -BUILTIN(__builtin_ia32_pabsd, "V2iV2i", "") BUILTIN(__builtin_ia32_ldmxcsr, "vUi", "") BUILTIN(__builtin_ia32_stmxcsr, "Ui", "") -BUILTIN(__builtin_ia32_cvtpi2ps, "V4fV4fV2i", "") -BUILTIN(__builtin_ia32_cvtps2pi, "V2iV4f", "") BUILTIN(__builtin_ia32_cvtss2si, "iV4f", "") BUILTIN(__builtin_ia32_cvtss2si64, "LLiV4f", "") -BUILTIN(__builtin_ia32_cvttps2pi, "V2iV4f", "") BUILTIN(__builtin_ia32_storeups, "vf*V4f", "") BUILTIN(__builtin_ia32_storehps, "vV2i*V4f", "") BUILTIN(__builtin_ia32_storelps, "vV2i*V4f", "") @@ -265,11 +274,8 @@ BUILTIN(__builtin_ia32_sqrtsd, "V2dV2d", "") BUILTIN(__builtin_ia32_cvtdq2pd, "V2dV4i", "") BUILTIN(__builtin_ia32_cvtdq2ps, "V4fV4i", "") BUILTIN(__builtin_ia32_cvtpd2dq, "V2LLiV2d", "") -BUILTIN(__builtin_ia32_cvtpd2pi, "V2iV2d", "") BUILTIN(__builtin_ia32_cvtpd2ps, "V4fV2d", "") BUILTIN(__builtin_ia32_cvttpd2dq, "V4iV2d", "") -BUILTIN(__builtin_ia32_cvttpd2pi, "V2iV2d", "") -BUILTIN(__builtin_ia32_cvtpi2pd, "V2dV2i", "") BUILTIN(__builtin_ia32_cvtsd2si, "iV2d", "") BUILTIN(__builtin_ia32_cvtsd2si64, "LLiV2d", "") BUILTIN(__builtin_ia32_cvtps2dq, "V4iV4f", "") diff --git a/include/clang/Basic/DelayedCleanupPool.h b/include/clang/Basic/DelayedCleanupPool.h new file mode 100644 index 000000000000..843205f7b011 --- /dev/null +++ b/include/clang/Basic/DelayedCleanupPool.h @@ -0,0 +1,109 @@ +//=== DelayedCleanupPool.h - Delayed Clean-up Pool Implementation *- C++ -*===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a facility to delay calling cleanup methods until specific +// points. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_DELAYEDCLEANUPPOOL_H +#define LLVM_CLANG_BASIC_DELAYEDCLEANUPPOOL_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallVector.h" + +namespace clang { + +/// \brief Gathers pairs of pointer-to-object/pointer-to-cleanup-function +/// allowing the cleanup functions to get called (with the pointer as parameter) +/// at specific points. +/// +/// The use case is to simplify clean-up of certain resources that, while their +/// lifetime is well-known and restricted, cleaning them up manually is easy to +/// miss and cause a leak. +/// +/// The same pointer can be added multiple times; its clean-up function will +/// only be called once. +class DelayedCleanupPool { +public: + typedef void (*CleanupFn)(void *ptr); + + /// \brief Adds a pointer and its associated cleanup function to be called + /// at a later point. + /// + /// \returns false if the pointer is already added, true otherwise. + bool delayCleanup(void *ptr, CleanupFn fn) { + assert(ptr && "Expected valid pointer to object"); + assert(fn && "Expected valid pointer to function"); + + CleanupFn &mapFn = Ptrs[ptr]; + assert((!mapFn || mapFn == fn) && + "Adding a pointer with different cleanup function!"); + + if (!mapFn) { + mapFn = fn; + Cleanups.push_back(std::make_pair(ptr, fn)); + return true; + } + + return false; + } + + template + bool delayDelete(T *ptr) { + return delayCleanup(ptr, cleanupWithDelete); + } + + template + bool delayMemberFunc(T *ptr) { + return delayCleanup(ptr, cleanupWithMemberFunc); + } + + void doCleanup() { + for (llvm::SmallVector, 8>::reverse_iterator + I = Cleanups.rbegin(), E = Cleanups.rend(); I != E; ++I) + I->second(I->first); + Cleanups.clear(); + Ptrs.clear(); + } + + ~DelayedCleanupPool() { + doCleanup(); + } + +private: + llvm::DenseMap Ptrs; + llvm::SmallVector, 8> Cleanups; + + template + static void cleanupWithDelete(void *ptr) { + delete static_cast(ptr); + } + + template + static void cleanupWithMemberFunc(void *ptr) { + (static_cast(ptr)->*Fn)(); + } +}; + +/// \brief RAII object for triggering a cleanup of a DelayedCleanupPool. +class DelayedCleanupPoint { + DelayedCleanupPool &Pool; + +public: + DelayedCleanupPoint(DelayedCleanupPool &pool) : Pool(pool) { } + + ~DelayedCleanupPoint() { + Pool.doCleanup(); + } +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h index fa763246d1b8..6f72976bfcf0 100644 --- a/include/clang/Basic/Diagnostic.h +++ b/include/clang/Basic/Diagnostic.h @@ -251,6 +251,14 @@ private: bool ErrorOccurred; bool FatalErrorOccurred; + /// \brief Indicates that an unrecoverable error has occurred. + bool UnrecoverableErrorOccurred; + + /// \brief Toggles for DiagnosticErrorTrap to check whether an error occurred + /// during a parsing section, e.g. during parsing a function. + bool TrapErrorOccurred; + bool TrapUnrecoverableErrorOccurred; + /// 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. @@ -269,13 +277,15 @@ private: /// can use this information to avoid redundancy across arguments. /// /// This is a hack to avoid a layering violation between libbasic and libsema. - typedef void (*ArgToStringFnTy)(ArgumentKind Kind, intptr_t Val, - const char *Modifier, unsigned ModifierLen, - const char *Argument, unsigned ArgumentLen, - const ArgumentValue *PrevArgs, - unsigned NumPrevArgs, - llvm::SmallVectorImpl &Output, - void *Cookie); + typedef void (*ArgToStringFnTy)( + ArgumentKind Kind, intptr_t Val, + const char *Modifier, unsigned ModifierLen, + const char *Argument, unsigned ArgumentLen, + const ArgumentValue *PrevArgs, + unsigned NumPrevArgs, + llvm::SmallVectorImpl &Output, + void *Cookie, + llvm::SmallVectorImpl &QualTypeVals); void *ArgToStringCookie; ArgToStringFnTy ArgToStringFn; @@ -432,7 +442,12 @@ public: bool hasErrorOccurred() const { return ErrorOccurred; } bool hasFatalErrorOccurred() const { return FatalErrorOccurred; } - + + /// \brief Determine whether any kind of unrecoverable error has occurred. + bool hasUnrecoverableErrorOccurred() const { + return FatalErrorOccurred || UnrecoverableErrorOccurred; + } + unsigned getNumWarnings() const { return NumWarnings; } void setNumWarnings(unsigned NumWarnings) { @@ -452,9 +467,11 @@ public: const char *Modifier, unsigned ModLen, const char *Argument, unsigned ArgLen, const ArgumentValue *PrevArgs, unsigned NumPrevArgs, - llvm::SmallVectorImpl &Output) const { + llvm::SmallVectorImpl &Output, + llvm::SmallVectorImpl &QualTypeVals) const { ArgToStringFn(Kind, Val, Modifier, ModLen, Argument, ArgLen, - PrevArgs, NumPrevArgs, Output, ArgToStringCookie); + PrevArgs, NumPrevArgs, Output, ArgToStringCookie, + QualTypeVals); } void SetArgToStringFn(ArgToStringFnTy Fn, void *Cookie) { @@ -621,20 +638,28 @@ private: /// queried. class DiagnosticErrorTrap { Diagnostic &Diag; - unsigned PrevErrors; public: explicit DiagnosticErrorTrap(Diagnostic &Diag) - : Diag(Diag), PrevErrors(Diag.NumErrors) {} + : Diag(Diag) { reset(); } /// \brief Determine whether any errors have occurred since this /// object instance was created. bool hasErrorOccurred() const { - return Diag.NumErrors > PrevErrors; + return Diag.TrapErrorOccurred; + } + + /// \brief Determine whether any unrecoverable errors have occurred since this + /// object instance was created. + bool hasUnrecoverableErrorOccurred() const { + return Diag.TrapUnrecoverableErrorOccurred; } // Set to initial state of "no errors occurred". - void reset() { PrevErrors = Diag.NumErrors; } + void reset() { + Diag.TrapErrorOccurred = false; + Diag.TrapUnrecoverableErrorOccurred = false; + } }; //===----------------------------------------------------------------------===// diff --git a/include/clang/Basic/DiagnosticCategories.h b/include/clang/Basic/DiagnosticCategories.h new file mode 100644 index 000000000000..4dd067ba1e98 --- /dev/null +++ b/include/clang/Basic/DiagnosticCategories.h @@ -0,0 +1,26 @@ +//===- DiagnosticCategories.h - Diagnostic Categories Enumerators-*- C++ -*===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_DIAGNOSTICCATEGORIES_H +#define LLVM_CLANG_BASIC_DIAGNOSTICCATEGORIES_H + +namespace clang { + namespace diag { + enum { +#define GET_CATEGORY_TABLE +#define CATEGORY(X, ENUM) ENUM, +#include "clang/Basic/DiagnosticGroups.inc" +#undef CATEGORY +#undef GET_CATEGORY_TABLE + DiagCat_NUM_CATEGORIES + }; + } // end namespace diag +} // end namespace clang + +#endif diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td index 50110fb53729..4b5de366cbc0 100644 --- a/include/clang/Basic/DiagnosticCommonKinds.td +++ b/include/clang/Basic/DiagnosticCommonKinds.td @@ -32,6 +32,7 @@ def note_type_being_defined : Note< def note_matching : Note<"to match this '%0'">; def note_using : Note<"using">; +def note_possibility : Note<"one possibility">; def note_also_found : Note<"also found">; // Parse && Lex diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td index 908a69b162c4..e33b67ef7a07 100644 --- a/include/clang/Basic/DiagnosticDriverKinds.td +++ b/include/clang/Basic/DiagnosticDriverKinds.td @@ -82,6 +82,12 @@ def err_drv_conflicting_deployment_targets : Error< "conflicting deployment targets, both '%0' and '%1' are present in environment">; def err_drv_invalid_arch_for_deployment_target : Error< "invalid architecture '%0' for deployment target '%1'">; +def err_drv_objc_gc_arr : Error< + "cannot specify both '-fobjc-arc' and '%0'">; +def err_arc_nonfragile_abi : Error< + "-fobjc-arc is not supported with fragile abi">; +def err_drv_mg_requires_m_or_mm : Error< + "option '-MG' requires '-M' or '-MM'">; def warn_c_kext : Warning< "ignoring -fapple-kext which is valid for c++ and objective-c++ only">; diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td index 4aa85134aae4..120ba67dc1f6 100644 --- a/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/include/clang/Basic/DiagnosticFrontendKinds.td @@ -137,6 +137,9 @@ def warn_pch_nonfragile_abi2 : Error< "PCH file was compiled with the %select{32-bit|enhanced non-fragile}0 " "Objective-C ABI but the %select{32-bit|enhanced non-fragile}1 " "Objective-C ABI is selected">; +def warn_pch_auto_ref_count : Error< + "PCH file was compiled %select{without|with} automated reference counting," + "which is currently %select{disabled|enabled}">; def warn_pch_apple_kext : Error< "PCH file was compiled %select{with|without}0 support for Apple's kernel " "extensions ABI but it is currently %select{disabled|enabled}1">; diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index 9abd6d3c5769..8a109149884f 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/include/clang/Basic/DiagnosticGroups.td @@ -62,6 +62,7 @@ def ExitTimeDestructors : DiagGroup<"exit-time-destructors">; def FourByteMultiChar : DiagGroup<"four-char-constants">; def GlobalConstructors : DiagGroup<"global-constructors">; def : DiagGroup<"idiomatic-parentheses">; +def BitwiseOpParentheses: DiagGroup<"bitwise-op-parentheses">; def LogicalOpParentheses: DiagGroup<"logical-op-parentheses">; def IgnoredQualifiers : DiagGroup<"ignored-qualifiers">; def : DiagGroup<"import">; @@ -115,6 +116,7 @@ def SignCompare : DiagGroup<"sign-compare">; def : DiagGroup<"stack-protector">; def : DiagGroup<"switch-default">; def : DiagGroup<"synth">; +def SizeofArrayArgument : DiagGroup<"sizeof-array-argument">; def TautologicalCompare : DiagGroup<"tautological-compare">; def HeaderHygiene : DiagGroup<"header-hygiene">; @@ -168,6 +170,15 @@ def ImplicitAtomic : DiagGroup<"implicit-atomic-properties">; def CustomAtomic : DiagGroup<"custom-atomic-properties">; def AtomicProperties : DiagGroup<"atomic-properties", [ImplicitAtomic, CustomAtomic]>; +def AutomaticReferenceCountingABI : DiagGroup<"arc-abi">; +def ARCUnsafeRetainedAssign : DiagGroup<"arc-unsafe-retained-assign">; +def ARCRetainCycles : DiagGroup<"arc-retain-cycles">; +def ARCNonPodMemAccess : DiagGroup<"arc-non-pod-memaccess">; +def AutomaticReferenceCounting : DiagGroup<"arc", + [AutomaticReferenceCountingABI, + ARCUnsafeRetainedAssign, + ARCRetainCycles, + ARCNonPodMemAccess]>; def Selector : DiagGroup<"selector">; def NonfragileAbi2 : DiagGroup<"nonfragile-abi2">; def Protocol : DiagGroup<"protocol">; @@ -192,7 +203,8 @@ def DuplicateArgDecl : DiagGroup<"duplicate-method-arg">; // in -Wparentheses because most users who use -Wparentheses explicitly // do not want these warnings. def Parentheses : DiagGroup<"parentheses", - [LogicalOpParentheses]>; + [LogicalOpParentheses, + BitwiseOpParentheses]>; // -Wconversion has its own warnings, but we split a few out for // legacy reasons: @@ -217,12 +229,12 @@ def Unused : DiagGroup<"unused", // Format settings. def FormatSecurity : DiagGroup<"format-security">; +def FormatY2K : DiagGroup<"format-y2k">; def Format : DiagGroup<"format", [FormatExtraArgs, FormatZeroLength, NonNull, - FormatSecurity]>, + FormatSecurity, FormatY2K]>, DiagCategory<"Format String Issue">; def FormatNonLiteral : DiagGroup<"format-nonliteral", [FormatSecurity]>; -def FormatY2K : DiagGroup<"format-y2k", [Format]>; def Format2 : DiagGroup<"format=2", [FormatNonLiteral, FormatSecurity, FormatY2K]>; @@ -248,6 +260,7 @@ def Most : DiagGroup<"most", [ ReturnType, SelfAssignment, Switch, + SizeofArrayArgument, Trigraphs, Uninitialized, UnknownPragmas, @@ -283,3 +296,6 @@ def GNU : DiagGroup<"gnu", [GNUDesignator, VLA]>; // A warning group for warnings about Microsoft extensions. def Microsoft : DiagGroup<"microsoft">; + +def ObjCNonUnifiedException : DiagGroup<"objc-nonunified-exceptions">; + diff --git a/include/clang/Basic/DiagnosticIDs.h b/include/clang/Basic/DiagnosticIDs.h index fa816de4fddb..ae4ed5bbb13c 100644 --- a/include/clang/Basic/DiagnosticIDs.h +++ b/include/clang/Basic/DiagnosticIDs.h @@ -227,6 +227,10 @@ private: /// suppressed. bool ProcessDiag(Diagnostic &Diag) const; + /// \brief Whether the diagnostic may leave the AST in a state where some + /// invariants can break. + bool isUnrecoverable(unsigned DiagID) const; + friend class Diagnostic; }; diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td index 3514ccace22a..38d6a8001655 100644 --- a/include/clang/Basic/DiagnosticLexKinds.td +++ b/include/clang/Basic/DiagnosticLexKinds.td @@ -178,7 +178,7 @@ def ext_empty_fnmacro_arg : Extension< def err_pp_invalid_directive : Error<"invalid preprocessing directive">; def err_pp_hash_error : Error<"#error%0">; -def err_pp_file_not_found : Error<"'%0' file not found">, DefaultFatal; +def warn_pp_file_not_found : Warning<"'%0' file not found">, DefaultFatal; def err_pp_error_opening_file : Error< "error opening file '%0': %1">, DefaultFatal; def err_pp_empty_filename : Error<"empty filename">; diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index fb1c90950822..3764a4091546 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -263,6 +263,11 @@ def warn_objc_protocol_qualifier_missing_id : Warning< def err_objc_unknown_at : Error<"expected an Objective-C directive after '@'">; def err_illegal_super_cast : Error< "cannot cast 'super' (it isn't an expression)">; + +let CategoryName = "Automatic Reference Counting Issue" in { +def err_arc_bridge_retain : Error< + "unknown cast annotation __bridge_retain; did you mean __bridge_retained?">; +} def err_objc_illegal_visibility_spec : Error< "illegal visibility specification">; diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 5cfa61b3972d..97414f23d796 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -48,6 +48,8 @@ def err_vla_decl_has_static_storage : Error< "variable length array declaration can not have 'static' storage duration">; def err_vla_decl_has_extern_linkage : Error< "variable length array declaration can not have 'extern' linkage">; +def ext_vla_folded_to_constant : Extension< + "variable length array folded to constant array as an extension">; // C99 variably modified types def err_variably_modified_template_arg : Error< @@ -267,6 +269,15 @@ def warn_dyn_class_memaccess : Warning< InGroup>; def note_bad_memaccess_silence : Note< "explicitly cast the pointer to silence this warning">; +def warn_sizeof_pointer_expr_memaccess : Warning< + "argument to 'sizeof' in %0 call is the same expression as the " + "%select{destination|source}1; did you mean to " + "%select{dereference it|remove the addressof|provide an explicit length}2?">, + InGroup>; +def warn_sizeof_pointer_type_memaccess : Warning< + "argument to 'sizeof' in %0 call is the same pointer type %1 as the " + "%select{destination|source}2; expected %3 or an explicit length">, + InGroup>; /// main() // static/inline main() are not errors in C, just in C++. @@ -319,6 +330,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_forward_superclass : Error< + "attempting to use the forward class %0 as superclass of %1">; def err_no_nsconstant_string_class : Error< "cannot find interface declaration for %0">; def err_recursive_superclass : Error< @@ -344,6 +357,8 @@ def err_class_extension_after_impl : Error< "cannot declare class extension for %0 after class implementation">; def note_implementation_declared : Note< "class implementation is declared here">; +def note_class_declared : Note< + "class is declared here">; 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">; @@ -425,6 +440,15 @@ def warn_objc_property_copy_missing_on_block : Warning< def warn_atomic_property_rule : Warning< "writable atomic property %0 cannot pair a synthesized setter/getter " "with a user defined setter/getter">; +def warn_ownin_getter_rule : Warning< + "property's synthesized getter follows Cocoa naming" + " convention for returning 'owned' objects">; +def warn_property_getter_owning_mismatch : Warning< + "property declared as returning non-retained objects" + "; getter returning retained objects">; +def err_ownin_getter_rule : Error< + "property's synthesized getter follows Cocoa naming" + " convention for returning 'owned' objects">; def warn_default_atomic_custom_getter_setter : Warning< "atomic by default property %0 has a user defined %select{getter|setter}1 " "(property should be marked 'atomic' if this is intended)">, @@ -460,6 +484,12 @@ def error_bad_property_context : Error< def error_missing_property_ivar_decl : Error< "synthesized property %0 must either be named the same as a compatible" " ivar or must explicitly name an ivar">; +def error_synthesize_weak_non_arc_or_gc : Error< + "@synthesize of 'weak' property is only allowed in ARC or GC mode">; +def err_arc_perform_selector_retains : Error< + "performSelector names a selector which retains the object">; +def warn_arc_perform_selector_leaks : Warning< + "performSelector may cause a leak because its selector is unknown">; def error_synthesized_ivar_yet_not_supported : Error< "instance variable synthesis not yet supported" @@ -472,7 +502,7 @@ def error_ivar_in_superclass_use : Error< def error_weak_property : Error< "existing ivar %1 for __weak property %0 must be __weak">; def error_strong_property : Error< - "property %0 must be declared __weak to match existing ivar %1 with __weak attribute">; + "existing ivar %1 for strong property %0 may not be __weak">; def error_dynamic_property_ivar_decl : Error< "dynamic property can not have ivar specification">; def error_duplicate_ivar_use : Error< @@ -729,8 +759,6 @@ def err_not_integral_type_bitfield : Error< "bit-field %0 has non-integral type %1">; def err_not_integral_type_anon_bitfield : Error< "anonymous bit-field has non-integral type %0">; -def err_member_initialization : Error< - "fields can only be initialized in constructors">; def err_member_function_initialization : Error< "initializer on function does not look like a pure-specifier">; def err_non_virtual_pure : Error< @@ -1135,6 +1163,8 @@ def err_format_attribute_implicit_this_format_string : Error< "format attribute cannot specify the implicit this argument as the format " "string">; def warn_unknown_method_family : Warning<"unrecognized method family">; +def err_init_method_bad_return_type : Error< + "init methods must return an object pointer type, not %0">; def err_attribute_invalid_size : Error< "vector size not an integral multiple of component size">; def err_attribute_zero_size : Error<"zero vector size">; @@ -1160,6 +1190,10 @@ def err_as_qualified_auto_decl : Error< "automatic variable qualified with an address space">; def err_arg_with_address_space : Error< "parameter may not be qualified with an address space">; +def err_attr_objc_ownership_bad_type : Error< + "the type %0 cannot be retained">; +def err_attr_objc_ownership_redundant : Error< + "the type %0 already has retainment attributes set on it">; def err_attribute_not_string : Error< "argument to %0 attribute was not a string literal">; def err_attribute_section_invalid_for_target : Error< @@ -1215,6 +1249,8 @@ def warn_function_attribute_wrong_type : Warning< "'%0' only applies to function types; type here is %1">; def warn_pointer_attribute_wrong_type : Warning< "'%0' only applies to pointer types; type here is %1">; +def warn_objc_object_attribute_wrong_type : Warning< + "'%0' only applies to objective-c object or block pointer types; type here is %1">; def warn_gnu_inline_attribute_requires_inline : Warning< "'gnu_inline' attribute requires function to be marked 'inline'," " attribute ignored">; @@ -1232,6 +1268,13 @@ def err_cconv_varargs : Error< def err_regparm_mismatch : Error<"function declared with with regparm(%0) " "attribute was previously declared " "%plural{0:without the regparm|:with the regparm(%1)}1 attribute">; +def err_objc_precise_lifetime_bad_type : Error< + "objc_precise_lifetime only applies to retainable types; type here is %0">; +def warn_objc_precise_lifetime_meaningless : Error< + "objc_precise_lifetime is not meaningful for " + "%select{__unsafe_unretained|__autoreleasing}0 objects">; +def warn_label_attribute_not_unused : Warning< + "The only valid attribute for labels is 'unused'">; def err_invalid_pcs : Error<"Invalid PCS type">; // Availability attribute @@ -1505,7 +1548,13 @@ def note_ovl_candidate_arity : Note<"candidate " def note_ovl_candidate_deleted : Note< "candidate %select{function|function|constructor|" - "function |function |constructor ||||constructor (inherited)}0%1 " + "function |function |constructor |" + "constructor (the implicit default constructor)|" + "constructor (the implicit copy constructor)|" + "constructor (the implicit move constructor)|" + "function (the implicit copy assignment operator)|" + "function (the implicit move assignment operator)|" + "constructor (inherited)}0%1 " "has been explicitly %select{made unavailable|deleted}2">; // Giving the index of the bad argument really clutters this message, and @@ -1565,7 +1614,18 @@ def note_ovl_candidate_bad_gc : Note<"candidate " "function (the implicit move assignment operator)|" "constructor (inherited)}0%1 not viable: " "%select{%ordinal6|'this'}5 argument (%2) has %select{no|__weak|__strong}3 " - "lifetime, but parameter has %select{no|__weak|__strong}4 lifetime">; + "ownership, but parameter has %select{no|__weak|__strong}4 ownership">; +def note_ovl_candidate_bad_ownership : Note<"candidate " + "%select{function|function|constructor|" + "function |function |constructor |" + "constructor (the implicit default constructor)|" + "constructor (the implicit copy constructor)|" + "function (the implicit copy assignment operator)|" + "constructor (inherited)}0%1 not viable: " + "%select{%ordinal6|'this'}5 argument (%2) has " + "%select{no|__unsafe_unretained|__strong|__weak|__autoreleasing}3 ownership," + " but parameter has %select{no|__unsafe_unretained|__strong|__weak|" + "__autoreleasing}4 ownership">; def note_ovl_candidate_bad_cvr_this : Note<"candidate " "%select{|function|||function||||" "function (the implicit copy assignment operator)|}0 not viable: " @@ -1871,8 +1931,11 @@ def err_not_class_template_specialization : Error< "parameter}0">; def err_function_specialization_in_class : Error< "cannot specialize a function %0 within class scope">; -def err_explicit_specialization_storage_class : Error< +def ext_explicit_specialization_storage_class : ExtWarn< "explicit specialization cannot have a storage class">; +def err_explicit_specialization_inconsistent_storage_class : Error< + "explicit specialization has extraneous, inconsistent storage class " + "'%select{none|extern|static|__private_extern__|auto|register}0'">; // C++ class template specializations and out-of-line definitions def err_template_spec_needs_header : Error< @@ -2180,7 +2243,7 @@ def err_undeclared_var_use : Error<"use of undeclared identifier %0">; def note_dependent_var_use : Note<"must qualify identifier to find this " "declaration in dependent base class">; def err_not_found_by_two_phase_lookup : Error<"call to function %0 that is neither " - "visible in the template definition nor found by argument dependent lookup">; + "visible in the template definition nor found by argument-dependent lookup">; def note_not_found_by_two_phase_lookup : Note<"%0 should be declared prior to the " "call site%select{| or in %2| or in an associated namespace of one of its arguments}1">; def err_undeclared_use : Error<"use of undeclared %0">; @@ -2199,8 +2262,8 @@ def err_unavailable_message : Error<"%0 is unavailable: %1">; def warn_unavailable_fwdclass_message : Warning< "%0 maybe unavailable because receiver type is unknown">; def note_unavailable_here : Note< - "function has been explicitly marked " - "%select{unavailable|deleted|deprecated}0 here">; + "%select{declaration|function}0 has been explicitly marked " + "%select{unavailable|deleted|deprecated}1 here">; def warn_not_enough_argument : Warning< "not enough variable arguments in %0 declaration to fit a sentinel">; def warn_missing_sentinel : Warning < @@ -2237,6 +2300,8 @@ def err_inline_declaration_block_scope : Error< "inline declaration of %0 not allowed in block scope">; def err_static_non_static : Error< "static declaration of %0 follows non-static declaration">; +def warn_weak_import : Warning < + "an already-declared variable is made a weak_import declaration %0">; def warn_static_non_static : ExtWarn< "static declaration of %0 follows non-static declaration">; def err_non_static_static : Error< @@ -2418,6 +2483,8 @@ def err_indirect_goto_in_protected_scope : Error< def note_indirect_goto_target : Note<"possible target of indirect goto">; def note_protected_by_variable_init : Note< "jump bypasses variable initialization">; +def note_protected_by_variable_nontriv_destructor : Note< + "jump bypasses variable with a non-trivial destructor">; def note_protected_by_cleanup : Note< "jump bypasses initialization of variable with __attribute__((cleanup))">; def note_protected_by_vla_typedef : Note< @@ -2434,12 +2501,22 @@ def note_protected_by_objc_finally : Note< "jump bypasses initialization of @finally block">; def note_protected_by_objc_synchronized : Note< "jump bypasses initialization of @synchronized block">; +def note_protected_by_objc_autoreleasepool : Note< + "jump bypasses auto release push of @autoreleasepool block">; def note_protected_by_cxx_try : Note< "jump bypasses initialization of try block">; def note_protected_by_cxx_catch : Note< "jump bypasses initialization of catch block">; def note_protected_by___block : Note< "jump bypasses setup of __block variable">; +def note_protected_by_objc_ownership : Note< + "jump bypasses initialization of retaining variable">; +def note_enters_block_captures_cxx_obj : Note< + "jump enters lifetime of block which captures a destructible c++ object">; +def note_enters_block_captures_strong : Note< + "jump enters lifetime of block which strongly captures a variable">; +def note_enters_block_captures_weak : Note< + "jump enters lifetime of block which weakly captures a variable">; def note_exits_cleanup : Note< "jump exits scope of variable with __attribute__((cleanup))">; @@ -2459,6 +2536,16 @@ def note_exits_cxx_try : Note< "jump exits try block">; def note_exits_cxx_catch : Note< "jump exits catch block">; +def note_exits_objc_autoreleasepool : Note< + "jump exits autoreleasepool block">; +def note_exits_objc_ownership : Note< + "jump exits scope of retaining variable">; +def note_exits_block_captures_cxx_obj : Note< + "jump exits lifetime of block which captures a destructible c++ object">; +def note_exits_block_captures_strong : Note< + "jump exits lifetime of block which strongly captures a variable">; +def note_exits_block_captures_weak : Note< + "jump exits lifetime of block which weakly captures a variable">; def err_func_returning_array_function : Error< "function cannot return %select{array|function}0 type %1">; @@ -2490,6 +2577,152 @@ def ext_flexible_array_empty_aggregate_gnu : Extension< def ext_flexible_array_union_gnu : Extension< "flexible array member %0 in a union is a GNU extension">, InGroup; +let CategoryName = "Automatic Reference Counting Issue" in { + +// ARC-mode diagnostics. +def err_arc_weak_no_runtime : Error< + "the current deployment target does not support automated __weak references">; +def err_arc_unsupported_weak_class : Error< + "class is incompatible with __weak references">; +def err_arc_weak_unavailable_assign : Error< + "assignment of a weak-unavailable object to a __weak object">; +def err_arc_convesion_of_weak_unavailable : Error< + "%select{implicit conversion|cast}0 of weak-unavailable object of type %1 to" + " a __weak object of type %2">; +def err_arc_illegal_explicit_message : Error< + "ARC forbids explicit message send of %0">; +def err_arc_unused_init_message : Error< + "the result of a delegate init call must be immediately returned " + "or assigned to 'self'">; +def err_arc_mismatched_cast : Error< + "%select{implicit conversion|cast}0 of " + "%select{%2|a non-Objective-C pointer type %2|a block pointer|" + "an Objective-C pointer|an indirect pointer to an Objective-C pointer}1" + " to %3 is disallowed with ARC">; +def err_arc_objc_object_in_struct : Error< + "ARC forbids Objective-C objects in structs or unions">; +def err_arc_objc_property_default_assign_on_object : Error< + "ARC forbids synthesizing a property of an Objective-C object " + "with unspecified storage attribute">; +def err_arc_illegal_selector : Error< + "ARC forbids use of %0 in a @selector">; +def err_arc_illegal_method_def : Error< + "ARC forbids implementation of %0">; +def err_arc_lost_method_convention : Error< + "method was declared as %select{an 'alloc'|a 'copy'|an 'init'|a 'new'}0 " + "method, but its implementation doesn't match because %select{" + "its result type is not an object pointer|" + "its result type is unrelated to its receiver type}1">; +def note_arc_lost_method_convention : Note<"declaration in interface">; +def err_arc_gained_method_convention : Error< + "method implementation does not match its declaration">; +def note_arc_gained_method_convention : Note< + "declaration in interface is not in the '%select{alloc|copy|init|new}0' " + "family because %select{its result type is not an object pointer|" + "its result type is unrelated to its receiver type}1">; +def err_typecheck_arr_assign_self : Error< + "cannot assign to 'self' outside of a method in the init family">; +def err_typecheck_arr_assign_enumeration : Error< + "fast enumeration variables can't be modified in ARC by default; " + "declare the variable __strong to allow this">; +def warn_arc_non_pod_class_with_object_member : Warning< + "%0 cannot be shared between ARC and non-ARC " + "code; add a copy constructor, a copy assignment operator, and a destructor " + "to make it ABI-compatible">, InGroup, + DefaultIgnore; +def warn_arc_retained_assign : Warning< + "assigning retained object to %select{weak|unsafe_unretained}0 variable" + "; object will be released after assignment">, + InGroup; +def warn_arc_retained_property_assign : Warning< + "assigning retained object to unsafe property" + "; object will be released after assignment">, + InGroup; +def warn_arc_trivial_member_function_with_object_member : Warning< + "%0 cannot be shared between ARC and non-ARC " + "code; add a non-trivial %select{copy constructor|copy assignment operator|" + "destructor}1 to make it ABI-compatible">, + InGroup, DefaultIgnore; +def err_arc_new_array_without_ownership : Error< + "'new' cannot allocate an array of %0 with no explicit ownership">; +def warn_err_new_delete_object_array : Warning< + "%select{allocating|destroying}0 an array of %1; this array must not " + "%select{be deleted in|have been allocated from}0 non-ARC code">, + InGroup, DefaultIgnore; +def err_arc_autoreleasing_var : Error< + "%select{__block variables|global variables|fields|ivars}0 cannot have " + "__autoreleasing ownership">; +def err_arc_thread_ownership : Error< + "thread-local variable has non-trivial ownership: type is %0">; +def err_arc_indirect_no_ownership : Error< + "%select{pointer|reference}1 to non-const type %0 with no explicit ownership">, + InGroup; +def err_arc_array_param_no_ownership : Error< + "must explicitly describe intended ownership of an object array parameter">; +def err_arc_pseudo_dtor_inconstant_quals : Error< + "pseudo-destructor destroys object of type %0 with inconsistently-qualified " + "type %1">; +def err_arc_init_method_unrelated_result_type : Error< + "init methods must return a type related to the receiver type">; +def err_arc_nonlocal_writeback : Error< + "passing address of %select{non-local|non-scalar}0 object to " + "__autoreleasing parameter for write-back">; +def err_arc_method_not_found : Error< + "no known %select{instance|class}1 method for selector %0">; +def err_arc_receiver_forward_class : Error< + "receiver %0 for class message is a forward declaration">; +def err_arc_may_not_respond : Error< + "receiver type %0 for instance message does not declare a method with " + "selector %1">; +def err_arc_receiver_forward_instance : Error< + "receiver type %0 for instance message is a forward declaration">; +def err_arc_multiple_method_decl : Error< + "multiple methods named %0 found with mismatched result, " + "parameter type or attributes">; +def warn_arc_retain_cycle : Warning< + "capturing %0 strongly in this block is likely to lead to a retain cycle">, + InGroup; +def note_arc_retain_cycle_owner : Note< + "block will be retained by %select{the captured object|an object strongly " + "retained by the captured object}0">; +def note_nontrivial_objc_ownership : Note< + "because type %0 has %select{no|no|__strong|__weak|__autoreleasing}1 " + "ownership">; +def warn_arc_object_memaccess : Warning< + "%select{destination for|source of}0 this %1 call is a pointer to " + "ownership-qualified type %2">, InGroup; + +def err_arc_strong_property_ownership : Error< + "existing ivar %1 for strong property %0 may not be " + "%select{|__unsafe_unretained||__weak}2">; +def err_arc_assign_property_ownership : Error< + "existing ivar %1 for unsafe_unretained property %0 must be __unsafe_unretained">; +def err_arc_inconsistent_property_ownership : Error< + "%select{strong|weak|unsafe_unretained}1 property %0 may not also be " + "declared %select{|__unsafe_unretained|__strong|__weak|__autoreleasing}2">; +def err_arc_atomic_ownership : Error< + "cannot perform atomic operation on a pointer to type %0: type has " + "non-trivial ownership">; + +def err_arc_bridge_cast_incompatible : Error< + "incompatible types casting %0 to %1 with a %select{__bridge|" + "__bridge_transfer|__bridge_retained}2 cast">; +def err_arc_bridge_cast_wrong_kind : Error< + "cast of %select{Objective-C|block|C}0 pointer type %1 to " + "%select{Objective-C|block|C}2 pointer type %3 cannot use %select{__bridge|" + "__bridge_transfer|__bridge_retained}4">; +def err_arc_cast_requires_bridge : Error< + "cast of %select{Objective-C|block|C}0 pointer type %1 to " + "%select{Objective-C|block|C}2 pointer type %3 requires a bridged cast">; +def note_arc_bridge : Note< + "use __bridge to convert directly (no change in ownership)">; +def note_arc_bridge_transfer : Note< + "use __bridge_transfer to transfer ownership of a +1 %0 into ARC">; +def note_arc_bridge_retained : Note< + "use __bridge_retained to make an ARC object available as a +1 %0">; + +} // ARC category name + def err_flexible_array_init_needs_braces : Error< "flexible array requires brace-enclosed initializer">; def err_illegal_decl_array_of_functions : Error< @@ -2563,11 +2796,11 @@ def warn_remainder_by_zero : Warning<"remainder by zero is undefined">; def warn_shift_negative : Warning<"shift count is negative">; def warn_shift_gt_typewidth : Warning<"shift count >= width of type">; def warn_shift_result_gt_typewidth : Warning< - "shift result (%0) requires %1 bits to represent, but %2 only has %3 bits">, - InGroup>; -def warn_shift_result_overrides_sign_bit : Warning< - "shift result (%0) overrides the sign bit of the shift expression's type " - "(%1) and becomes negative">, + "signed shift result (%0) requires %1 bits to represent, but %2 only has " + "%3 bits">, InGroup>; +def warn_shift_result_sets_sign_bit : Warning< + "signed shift result (%0) sets the sign bit of the shift expression's " + "type (%1) and becomes negative">, InGroup>, DefaultIgnore; def warn_precedence_bitwise_rel : Warning< @@ -2579,17 +2812,22 @@ def note_precedence_bitwise_silence : Note< "place parentheses around the %0 expression to silence this warning">; def warn_precedence_conditional : Warning< - "?: has lower precedence than %0; %0 will be evaluated first">, + "operator '?:' has lower precedence than '%0'; '%0' will be evaluated first">, InGroup; def note_precedence_conditional_first : Note< - "place parentheses around the ?: expression to evaluate it first">; + "place parentheses around the '?:' expression to evaluate it first">; def note_precedence_conditional_silence : Note< - "place parentheses around the %0 expression to silence this warning">; + "place parentheses around the '%0' expression to silence this warning">; def warn_logical_instead_of_bitwise : Warning< "use of logical %0 with constant operand; switch to bitwise %1 or " "remove constant">, InGroup>; +def warn_bitwise_and_in_bitwise_or : Warning< + "'&' within '|'">, InGroup; +def note_bitwise_and_in_bitwise_or_silence : Note< + "place parentheses around the '&' expression to silence this warning">; + def warn_logical_and_in_logical_or : Warning< "'&&' within '||'">, InGroup; def note_logical_and_in_logical_or_silence : Note< @@ -2599,6 +2837,10 @@ def warn_self_assignment : Warning< "explicitly assigning a variable of type %0 to itself">, InGroup, DefaultIgnore; +def warn_sizeof_array_param : Warning< + "sizeof on array function parameter will return size of %0 instead of %1">, + InGroup; + def err_sizeof_nonfragile_interface : Error< "invalid application of '%select{alignof|sizeof}1' to interface %0 in " "non-fragile ABI">; @@ -2623,10 +2865,15 @@ def err_subscript_function_type : Error< "subscript of pointer to function type %0">; def err_subscript_incomplete_type : Error< "subscript of pointer to incomplete type %0">; +def ext_gnu_subscript_void_type : Extension< + "subscript of a pointer to void is a GNU extension">, InGroup; def err_typecheck_member_reference_struct_union : Error< "member reference base type %0 is not a structure or union">; def err_typecheck_member_reference_ivar : Error< "%0 does not have a member named %1">; +def error_arc_weak_ivar_access : Error< + "dereferencing a __weak pointer is not allowed due to possible " + "null value caused by race condition, assign it to strong variable first">; def err_typecheck_member_reference_arrow : Error< "member reference type %0 is not a pointer">; def err_typecheck_member_reference_suggestion : Error< @@ -2658,7 +2905,7 @@ def err_member_def_undefined_record : Error< def err_member_def_does_not_match : Error< "out-of-line definition of %0 does not match any declaration in %1">; def err_member_def_does_not_match_ret_type : Error< - "out-of-line definition of %q0 differ from the declaration in the return type">; + "out-of-line definition of %q0 differs from the declaration in the return type">; def err_nonstatic_member_out_of_line : Error< "non-static data member defined out-of-line">; def err_nonstatic_flexible_variable : Error< @@ -2682,11 +2929,12 @@ def err_ivar_reference_type : Error< def err_typecheck_illegal_increment_decrement : Error< "cannot %select{decrement|increment}1 value of type %0">; def err_typecheck_arithmetic_incomplete_type : Error< - "arithmetic on pointer to incomplete type %0">; + "arithmetic on a pointer to an incomplete type %0">; def err_typecheck_pointer_arith_function_type : Error< - "arithmetic on pointer to function type %0">; + "arithmetic on%select{ a|}0 pointer%select{|s}0 to%select{ the|}2 " + "function type%select{|s}2 %1%select{| and %3}2">; def err_typecheck_pointer_arith_void_type : Error< - "arithmetic on pointer to void type">; + "arithmetic on%select{ a|}0 pointer%select{|s}0 to void">; def err_typecheck_decl_incomplete_type : Error< "variable has incomplete type %0">; def ext_typecheck_decl_incomplete_type : ExtWarn< @@ -2803,6 +3051,9 @@ def warn_runsigned_always_true_comparison : Warning< def warn_comparison_of_mixed_enum_types : Warning< "comparison of two values with different enumeration types (%0 and %1)">, InGroup>; +def warn_null_in_arithmetic_operation : Warning< + "use of NULL in arithmetic operation">, + InGroup>; def err_invalid_this_use : Error< "invalid use of 'this' outside of a nonstatic member function">; @@ -2871,9 +3122,11 @@ def note_forward_class : Note< def err_duplicate_property : Error< "property has a previous declaration">; def ext_gnu_void_ptr : Extension< - "use of GNU void* extension">, InGroup; + "arithmetic on%select{ a|}0 pointer%select{|s}0 to void is a GNU extension">, + InGroup; def ext_gnu_ptr_func_arith : Extension< - "arithmetic on pointer to function type %0 is a GNU extension">, + "arithmetic on%select{ a|}0 pointer%select{|s}0 to%select{ the|}2 function " + "type%select{|s}2 %1%select{| and %3}2 is a GNU extension">, InGroup; def error_readonly_property_assignment : Error< "assigning to property with 'readonly' attribute not allowed">; @@ -2942,9 +3195,9 @@ def err_qualified_objc_catch_parm : Error< "@catch parameter declarator cannot be qualified">; def err_objc_pointer_cxx_catch_gnu : Error< "can't catch Objective C exceptions in C++ in the GNU runtime">; -def err_objc_pointer_cxx_catch_fragile : Error< - "can't catch Objective C exceptions in C++ in the non-unified " - "exception model">; +def warn_objc_pointer_cxx_catch_fragile : Warning< + "can not catch an exception thrown with @throw in C++ in the non-unified " + "exception model">, InGroup; def err_objc_object_catch : Error< "can't catch an Objective C object by value">; def err_incomplete_type_objc_at_encode : Error< @@ -3328,6 +3581,15 @@ def err_typecheck_incompatible_address_space : Error< "|sending %0 to parameter of type %1" "|casting %0 to type %1}2" " changes address space of pointer">; +def err_typecheck_incompatible_ownership : Error< + "%select{assigning %1 to %0" + "|passing %0 to parameter of type %1" + "|returning %0 from a function with result type %1" + "|converting %0 to type %1" + "|initializing %0 with an expression of type %1" + "|sending %0 to parameter of type %1" + "|casting %0 to type %1}2" + " changes retain/release properties of pointer">; def err_typecheck_convert_ambiguous : Error< "ambiguity in initializing value of type %0 with initializer of type %1">; def err_typecheck_comparison_of_distinct_blocks : Error< @@ -3544,6 +3806,9 @@ def ext_in_class_initializer_float_type : ExtWarn< def err_in_class_initializer_non_constant : Error< "in-class initializer is not a constant expression">; +def ext_in_class_initializer_non_constant : Extension< + "in-class initializer is not a constant expression, accepted as an extension">; + // C++ anonymous unions and GNU anonymous structs/unions def ext_anonymous_union : Extension< "anonymous unions are a GNU extension in C">, InGroup; @@ -3929,12 +4194,23 @@ def err_switch_incomplete_class_type : Error< "switch condition has incomplete class type %0">; def warn_empty_if_body : Warning< "if statement has empty body">, InGroup; + def err_va_start_used_in_non_variadic_function : Error< "'va_start' used in function with fixed args">; def warn_second_parameter_of_va_start_not_last_named_argument : Warning< "second parameter of 'va_start' not last named argument">; def err_first_argument_to_va_arg_not_of_type_va_list : Error< "first argument to 'va_arg' is of type %0 and not 'va_list'">; +def err_second_parameter_to_va_arg_incomplete: Error< + "second argument to 'va_arg' is of incomplete type %0">; +def err_second_parameter_to_va_arg_abstract: Error< + "second argument to 'va_arg' is of abstract type %0">; +def warn_second_parameter_to_va_arg_not_pod : Warning< + "second argument to 'va_arg' is of non-POD type %0">, + InGroup>, DefaultError; +def warn_second_parameter_to_va_arg_never_compatible : Warning< + "second argument to 'va_arg' is of promotable type %0; this va_arg has " + "undefined behavior because arguments will be promoted to %1">; def warn_return_missing_expr : Warning< "non-void %select{function|method}1 %0 should return a value">, DefaultError, @@ -3943,8 +4219,9 @@ def ext_return_missing_expr : ExtWarn< "non-void %select{function|method}1 %0 should return a value">, DefaultError, InGroup; def ext_return_has_expr : ExtWarn< - "void %select{function|method}1 %0 should not return a value">, DefaultError, - InGroup; + "%select{void function|void method|constructor|destructor}1 %0 " + "should not return a value">, + DefaultError, InGroup; def ext_return_has_void_expr : Extension< "void %select{function|method}1 %0 should not return void expression">; def warn_noreturn_function_has_return_expr : Warning< @@ -4074,6 +4351,11 @@ def err_typecheck_member_reference_ivar_suggest : Error< "%0 does not have a member named %1; did you mean %2?">; def err_property_not_found_suggest : Error< "property %0 not found on object of type %1; did you mean %2?">; +def err_ivar_access_using_property_syntax_suggest : Error< + "property %0 not found on object of type %1; did you mean to access ivar %2?">; +def err_property_found_suggest : Error< + "property %0 found on object of type %1; did you mean to access " + "it with the \".\" operator?">; def err_undef_interface_suggest : Error< "cannot find interface declaration for %0; did you mean %1?">; def warn_undef_interface_suggest : Warning< diff --git a/include/clang/Basic/FileManager.h b/include/clang/Basic/FileManager.h index 2ca344d55370..1324533fa03e 100644 --- a/include/clang/Basic/FileManager.h +++ b/include/clang/Basic/FileManager.h @@ -21,10 +21,13 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/Support/Allocator.h" -#include "llvm/Config/config.h" // for mode_t // FIXME: Enhance libsystem to support inode and other fields in stat. #include +#ifdef _MSC_VER +typedef unsigned short mode_t; +#endif + struct stat; namespace llvm { diff --git a/include/clang/Basic/IdentifierTable.h b/include/clang/Basic/IdentifierTable.h index b4eca6d8fbdb..bebcffdddede 100644 --- a/include/clang/Basic/IdentifierTable.h +++ b/include/clang/Basic/IdentifierTable.h @@ -411,23 +411,15 @@ public: return II; } - IdentifierInfo &get(const char *NameStart, const char *NameEnd) { - return get(llvm::StringRef(NameStart, NameEnd-NameStart)); - } - - IdentifierInfo &get(const char *Name, size_t NameLen) { - return get(llvm::StringRef(Name, NameLen)); - } - /// \brief Gets an IdentifierInfo for the given name without consulting /// external sources. /// /// This is a version of get() meant for external sources that want to /// introduce or modify an identifier. If they called get(), they would /// likely end up in a recursion. - IdentifierInfo &getOwn(const char *NameStart, const char *NameEnd) { + IdentifierInfo &getOwn(llvm::StringRef Name) { llvm::StringMapEntry &Entry = - HashTable.GetOrCreateValue(NameStart, NameEnd); + HashTable.GetOrCreateValue(Name); IdentifierInfo *II = Entry.getValue(); if (!II) { @@ -444,9 +436,6 @@ public: return *II; } - IdentifierInfo &getOwn(llvm::StringRef Name) { - return getOwn(Name.begin(), Name.end()); - } typedef HashTableTy::const_iterator iterator; typedef HashTableTy::const_iterator const_iterator; @@ -499,7 +488,10 @@ enum ObjCMethodFamily { OMF_release, OMF_retain, OMF_retainCount, - OMF_self + OMF_self, + + // performSelector families + OMF_performSelector }; /// Enough bits to store any enumerator in ObjCMethodFamily or diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h index f0f1432ca0b8..dc77d4c1496b 100644 --- a/include/clang/Basic/LangOptions.h +++ b/include/clang/Basic/LangOptions.h @@ -119,6 +119,8 @@ public: unsigned InlineVisibilityHidden : 1; // Whether inline C++ methods have // hidden visibility by default. unsigned ParseUnknownAnytype: 1; /// Let the user write __unknown_anytype. + unsigned DebuggerSupport : 1; /// Do things that only make sense when + /// supporting a debugger unsigned SpellChecking : 1; // Whether to perform spell-checking for error // recovery. @@ -130,6 +132,10 @@ public: unsigned DefaultFPContract : 1; // Default setting for FP_CONTRACT // FIXME: This is just a temporary option, for testing purposes. unsigned NoBitFieldTypeAlign : 1; + unsigned ObjCAutoRefCount : 1; // Objective C automated reference counting + unsigned ObjCRuntimeHasWeak : 1; // The ARC runtime supports __weak + unsigned ObjCInferRelatedReturnType : 1; // Infer Objective-C related return + // types unsigned FakeAddressSpaceMap : 1; // Use a fake address space map, for // testing languages such as OpenCL. @@ -172,10 +178,13 @@ public: Trigraphs = BCPLComment = Bool = DollarIdents = AsmPreprocessor = 0; GNUMode = GNUKeywords = ImplicitInt = Digraphs = 0; HexFloats = 0; + ObjCAutoRefCount = 0; + ObjCRuntimeHasWeak = 0; + ObjCInferRelatedReturnType = 0; GC = ObjC1 = ObjC2 = ObjCNonFragileABI = ObjCNonFragileABI2 = 0; AppleKext = 0; ObjCDefaultSynthProperties = 0; - ObjCInferRelatedResultType = 0; + ObjCInferRelatedResultType = 1; NoConstantCFStrings = 0; InlineVisibilityHidden = 0; C99 = C1X = Microsoft = Borland = CPlusPlus = CPlusPlus0x = 0; CXXOperatorNames = PascalStrings = WritableStrings = ConstStrings = 0; @@ -234,7 +243,7 @@ public: FakeAddressSpaceMap = 0; MRTD = 0; DelayedTemplateParsing = 0; - ParseUnknownAnytype = 0; + ParseUnknownAnytype = DebuggerSupport = 0; } GCMode getGCMode() const { return (GCMode) GC; } diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h index df5074cb42e6..6301f3197859 100644 --- a/include/clang/Basic/SourceManager.h +++ b/include/clang/Basic/SourceManager.h @@ -36,6 +36,7 @@ class SourceManager; class FileManager; class FileEntry; class LineTableInfo; +class LangOptions; /// SrcMgr - Public enums and private classes that are part of the /// SourceManager implementation. @@ -89,7 +90,7 @@ namespace SrcMgr { /// getBuffer - Returns the memory buffer for the associated content. /// - /// \param Diag Object through which diagnostics will be emitted it the + /// \param Diag Object through which diagnostics will be emitted if the /// buffer cannot be retrieved. /// /// \param Loc If specified, is the location that invalid file diagnostics @@ -238,8 +239,11 @@ namespace SrcMgr { /// InstantiationLocStart/InstantiationLocEnd - In a macro expansion, these /// indicate the start and end of the instantiation. In object-like macros, /// these will be the same. In a function-like macro instantiation, the - /// start will be the identifier and the end will be the ')'. + /// start will be the identifier and the end will be the ')'. Finally, in + /// macro-argument instantitions, the end will be 'SourceLocation()', an + /// invalid location. unsigned InstantiationLocStart, InstantiationLocEnd; + public: SourceLocation getSpellingLoc() const { return SourceLocation::getFromRawEncoding(SpellingLoc); @@ -248,7 +252,9 @@ namespace SrcMgr { return SourceLocation::getFromRawEncoding(InstantiationLocStart); } SourceLocation getInstantiationLocEnd() const { - return SourceLocation::getFromRawEncoding(InstantiationLocEnd); + SourceLocation EndLoc = + SourceLocation::getFromRawEncoding(InstantiationLocEnd); + return EndLoc.isInvalid() ? getInstantiationLocStart() : EndLoc; } std::pair getInstantiationLocRange() const { @@ -256,19 +262,52 @@ namespace SrcMgr { getInstantiationLocEnd()); } - /// get - Return a InstantiationInfo for an expansion. IL specifies - /// the instantiation location (where the macro is expanded), and SL - /// specifies the spelling location (where the characters from the token - /// come from). IL and PL can both refer to normal File SLocs or + bool isMacroArgInstantiation() const { + // Note that this needs to return false for default constructed objects. + return getInstantiationLocStart().isValid() && + SourceLocation::getFromRawEncoding(InstantiationLocEnd).isInvalid(); + } + + /// create - Return a InstantiationInfo for an expansion. ILStart and + /// ILEnd specify the instantiation range (where the macro is expanded), + /// and SL specifies the spelling location (where the characters from the + /// token come from). All three can refer to normal File SLocs or /// instantiation locations. - static InstantiationInfo get(SourceLocation ILStart, SourceLocation ILEnd, - SourceLocation SL) { + static InstantiationInfo create(SourceLocation SL, + SourceLocation ILStart, + SourceLocation ILEnd) { InstantiationInfo X; X.SpellingLoc = SL.getRawEncoding(); X.InstantiationLocStart = ILStart.getRawEncoding(); X.InstantiationLocEnd = ILEnd.getRawEncoding(); return X; } + + /// createForMacroArg - Return a special InstantiationInfo for the + /// expansion of a macro argument into a function-like macro's body. IL + /// specifies the instantiation location (where the macro is expanded). + /// This doesn't need to be a range because a macro is always instantiated + /// at a macro parameter reference, and macro parameters are always exactly + /// one token. SL specifies the spelling location (where the characters + /// from the token come from). IL and SL can both refer to normal File + /// SLocs or instantiation locations. + /// + /// Given the code: + /// \code + /// #define F(x) f(x) + /// F(42); + /// \endcode + /// + /// When expanding '\c F(42)', the '\c x' would call this with an SL + /// pointing at '\c 42' anad an IL pointing at its location in the + /// definition of '\c F'. + static InstantiationInfo createForMacroArg(SourceLocation SL, + SourceLocation IL) { + // We store an intentionally invalid source location for the end of the + // instantiation range to mark that this is a macro argument instantation + // rather than a normal one. + return create(SL, IL, SourceLocation()); + } }; /// SLocEntry - This is a discriminated union of FileInfo and @@ -500,8 +539,8 @@ public: //===--------------------------------------------------------------------===// /// 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. + /// being #included from the specified IncludePosition. This translates NULL + /// into standard input. /// PreallocateID should be non-zero to specify which pre-allocated, /// lazily computed source location is being filled in by this operation. FileID createFileID(const FileEntry *SourceFile, SourceLocation IncludePos, @@ -532,9 +571,17 @@ public: return MainFileID; } + /// createMacroArgInstantiationLoc - Return a new SourceLocation that encodes + /// the fact that a token from SpellingLoc should actually be referenced from + /// InstantiationLoc, and that it represents the instantiation of a macro + /// argument into the function-like macro body. + SourceLocation createMacroArgInstantiationLoc(SourceLocation Loc, + SourceLocation InstantiationLoc, + unsigned TokLength); + /// createInstantiationLoc - Return a new SourceLocation that encodes the fact - /// that a token at Loc should actually be referenced from InstantiationLoc. - /// TokLength is the length of the token being instantiated. + /// that a token from SpellingLoc should actually be referenced from + /// InstantiationLoc. SourceLocation createInstantiationLoc(SourceLocation Loc, SourceLocation InstantiationLocStart, SourceLocation InstantiationLocEnd, @@ -721,7 +768,7 @@ public: if (Loc.isFileID()) return std::make_pair(FID, Offset); - return getDecomposedInstantiationLocSlowCase(E, Offset); + return getDecomposedInstantiationLocSlowCase(E); } /// getDecomposedSpellingLoc - Decompose the specified location into a raw @@ -745,6 +792,12 @@ public: return getDecomposedLoc(SpellingLoc).second; } + /// isMacroArgInstantiation - This method tests whether the given source + /// location represents a macro argument's instantiation into the + /// function-like macro definition. Such source locations only appear inside + /// of the instantiation locations representing where a particular + /// function-like macro was expanded. + bool isMacroArgInstantiation(SourceLocation Loc) const; //===--------------------------------------------------------------------===// // Queries about the code at a SourceLocation. @@ -831,13 +884,38 @@ public: return getFileCharacteristic(Loc) == SrcMgr::C_ExternCSystem; } - /// \brief Returns true if the given MacroID location points at the first - /// token of the macro instantiation. - bool isAtStartOfMacroInstantiation(SourceLocation Loc) const; + /// \brief Given a specific chunk of a FileID (FileID with offset+length), + /// returns true if \arg Loc is inside that chunk and sets relative offset + /// (offset of \arg Loc from beginning of chunk) to \arg relativeOffset. + bool isInFileID(SourceLocation Loc, + FileID FID, unsigned offset, unsigned length, + unsigned *relativeOffset = 0) const { + assert(!FID.isInvalid()); + if (Loc.isInvalid()) + return false; + + unsigned start = getSLocEntry(FID).getOffset() + offset; + unsigned end = start + length; + +#ifndef NDEBUG + // Make sure offset/length describe a chunk inside the given FileID. + unsigned NextOffset; + if (FID.ID+1 == SLocEntryTable.size()) + NextOffset = getNextOffset(); + else + NextOffset = getSLocEntry(FID.ID+1).getOffset(); + assert(start < NextOffset); + assert(end < NextOffset); +#endif - /// \brief Returns true if the given MacroID location points at the last - /// token of the macro instantiation. - bool isAtEndOfMacroInstantiation(SourceLocation Loc) const; + if (Loc.getOffset() >= start && Loc.getOffset() < end) { + if (relativeOffset) + *relativeOffset = Loc.getOffset() - start; + return true; + } + + return false; + } //===--------------------------------------------------------------------===// // Line Table Manipulation Routines @@ -845,7 +923,7 @@ public: /// getLineTableFilenameID - Return the uniqued ID for the specified filename. /// - unsigned getLineTableFilenameID(const char *Ptr, unsigned Len); + unsigned getLineTableFilenameID(llvm::StringRef Str); /// AddLineNote - Add a line note to the line table for the FileID and offset /// specified by Loc. If FilenameID is -1, it is considered to be @@ -899,6 +977,19 @@ public: /// \returns true if LHS source location comes before RHS, false otherwise. bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const; + /// \brief Determines the order of 2 source locations in the "source location + /// address space". + static bool isBeforeInSourceLocationOffset(SourceLocation LHS, + SourceLocation RHS) { + return isBeforeInSourceLocationOffset(LHS, RHS.getOffset()); + } + + /// \brief Determines the order of a source location and a source location + /// offset in the "source location address space". + static bool isBeforeInSourceLocationOffset(SourceLocation LHS, unsigned RHS) { + return LHS.getOffset() < RHS; + } + // Iterators over FileInfos. typedef llvm::DenseMap ::const_iterator fileinfo_iterator; @@ -952,6 +1043,14 @@ public: private: const llvm::MemoryBuffer *getFakeBufferForRecovery() const; + /// createInstantiationLoc - Implements the common elements of storing an + /// instantiation info struct into the SLocEntry table and producing a source + /// location that refers to it. + SourceLocation createInstantiationLocImpl(const SrcMgr::InstantiationInfo &II, + unsigned TokLength, + unsigned PreallocatedID = 0, + unsigned Offset = 0); + /// isOffsetInFileID - Return true if the specified FileID contains the /// specified SourceLocation offset. This is a very hot method. inline bool isOffsetInFileID(FileID FID, unsigned SLocOffset) const { @@ -989,8 +1088,7 @@ private: SourceLocation getSpellingLocSlowCase(SourceLocation Loc) const; std::pair - getDecomposedInstantiationLocSlowCase(const SrcMgr::SLocEntry *E, - unsigned Offset) const; + getDecomposedInstantiationLocSlowCase(const SrcMgr::SLocEntry *E) 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 258989cb7787..3f5d1a35e595 100644 --- a/include/clang/Basic/SourceManagerInternals.h +++ b/include/clang/Basic/SourceManagerInternals.h @@ -97,7 +97,7 @@ public: ~LineTableInfo() {} - unsigned getLineTableFilenameID(const char *Ptr, unsigned Len); + unsigned getLineTableFilenameID(llvm::StringRef Str); const char *getFilename(unsigned ID) const { assert(ID < FilenamesByID.size() && "Invalid FilenameID"); return FilenamesByID[ID]->getKeyData(); diff --git a/include/clang/Basic/Specifiers.h b/include/clang/Basic/Specifiers.h index d21bda7d9a2e..cfce0ccbc9dd 100644 --- a/include/clang/Basic/Specifiers.h +++ b/include/clang/Basic/Specifiers.h @@ -83,7 +83,7 @@ namespace clang { /// ExprValueKind - The categorization of expression values, /// currently following the C++0x scheme. enum ExprValueKind { - /// An r-value expression (a gr-value in the C++0x taxonomy) + /// An r-value expression (a pr-value in the C++0x taxonomy) /// produces a temporary value. VK_RValue, diff --git a/include/clang/Basic/StmtNodes.td b/include/clang/Basic/StmtNodes.td index 03f4cc3ec6d8..73996e43d5da 100644 --- a/include/clang/Basic/StmtNodes.td +++ b/include/clang/Basic/StmtNodes.td @@ -37,6 +37,7 @@ def ObjCAtFinallyStmt : Stmt; def ObjCAtThrowStmt : Stmt; def ObjCAtSynchronizedStmt : Stmt; def ObjCForCollectionStmt : Stmt; +def ObjCAutoreleasePoolStmt : Stmt; // C++ statments def CXXCatchStmt : Stmt; @@ -119,7 +120,9 @@ def UnresolvedMemberExpr : DStmt; def CXXNoexceptExpr : DStmt; def PackExpansionExpr : DStmt; def SizeOfPackExpr : DStmt; +def SubstNonTypeTemplateParmExpr : DStmt; def SubstNonTypeTemplateParmPackExpr : DStmt; +def MaterializeTemporaryExpr : DStmt; // Obj-C Expressions. def ObjCStringLiteral : DStmt; @@ -130,6 +133,10 @@ def ObjCProtocolExpr : DStmt; def ObjCIvarRefExpr : DStmt; def ObjCPropertyRefExpr : DStmt; def ObjCIsaExpr : DStmt; +def ObjCIndirectCopyRestoreExpr : DStmt; + +// Obj-C ARC Expressions. +def ObjCBridgedCastExpr : DStmt; // CUDA Expressions. def CUDAKernelCallExpr : DStmt; diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h index 76006d4292e8..4559cf2f64be 100644 --- a/include/clang/Basic/TargetInfo.h +++ b/include/clang/Basic/TargetInfo.h @@ -240,6 +240,14 @@ public: return getTypeWidth(IntMaxType); } + /// getRegisterWidth - Return the "preferred" register width on this target. + uint64_t getRegisterWidth() const { + // Currently we assume the register width on the target matches the pointer + // width, we can introduce a new variable for this if/when some target wants + // it. + return LongWidth; + } + /// 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 @@ -295,6 +303,11 @@ public: /// __builtin_va_list, which is target-specific. virtual const char *getVAListDeclaration() const = 0; + /// isValidClobber - Returns whether the passed in string is + /// a valid clobber in an inline asm statement. This is used by + /// Sema. + bool isValidClobber(llvm::StringRef Name) const; + /// isValidGCCRegisterName - Returns whether the passed in string /// is a valid register name according to GCC. This is used by Sema for /// inline asm statements. @@ -396,6 +409,11 @@ public: const char * const Register; }; + struct AddlRegName { + const char * const Names[5]; + const unsigned RegNum; + }; + virtual bool useGlobalsForAutomaticVariables() const { return false; } /// getCFStringSection - Return the section to use for CFString @@ -511,6 +529,7 @@ public: // getRegParmMax - Returns maximal number of args passed in registers. unsigned getRegParmMax() const { + assert(RegParmMax < 7 && "RegParmMax value is larger than AST can handle"); return RegParmMax; } @@ -566,6 +585,11 @@ protected: unsigned &NumNames) const = 0; virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, unsigned &NumAliases) const = 0; + virtual void getGCCAddlRegNames(const AddlRegName *&Addl, + unsigned &NumAddl) const { + Addl = 0; + NumAddl = 0; + } 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 dfba7eec8ae7..86172b83ff42 100644 --- a/include/clang/Basic/TokenKinds.def +++ b/include/clang/Basic/TokenKinds.def @@ -422,6 +422,12 @@ KEYWORD(__pascal , KEYALL) KEYWORD(__vector , KEYALTIVEC) KEYWORD(__pixel , KEYALTIVEC) +// Objective-C ARC keywords. +KEYWORD(__bridge , KEYARC) +KEYWORD(__bridge_transfer , KEYARC) +KEYWORD(__bridge_retained , KEYARC) +KEYWORD(__bridge_retain , KEYARC) + // Alternate spelling for various tokens. There are GCC extensions in all // languages, but should not be disabled in strict conformance mode. ALIAS("__alignof__" , __alignof , KEYALL) @@ -507,6 +513,7 @@ OBJC1_AT_KEYWORD(try) OBJC1_AT_KEYWORD(catch) OBJC1_AT_KEYWORD(finally) OBJC1_AT_KEYWORD(synchronized) +OBJC1_AT_KEYWORD(autoreleasepool) OBJC2_AT_KEYWORD(property) OBJC2_AT_KEYWORD(package) diff --git a/include/clang/Basic/arm_neon.td b/include/clang/Basic/arm_neon.td index b3da12254a84..71a0aa2726c0 100644 --- a/include/clang/Basic/arm_neon.td +++ b/include/clang/Basic/arm_neon.td @@ -182,7 +182,7 @@ def VMAX : SInst<"vmax", "ddd", "csiUcUsUifQcQsQiQUcQUsQUiQf">; def VMIN : SInst<"vmin", "ddd", "csiUcUsUifQcQsQiQUcQUsQUiQf">; //////////////////////////////////////////////////////////////////////////////// -// E.3.7 Pairdise Addition +// E.3.7 Pairwise Addition def VPADD : IInst<"vpadd", "ddd", "csiUcUsUif">; def VPADDL : SInst<"vpaddl", "nd", "csiUcUsUiQcQsQiQUcQUsQUi">; def VPADAL : SInst<"vpadal", "nnd", "csiUcUsUiQcQsQiQUcQUsQUi">; @@ -352,7 +352,7 @@ def VEXT : WInst<"vext", "dddi", "cUcPcsUsPsiUilUlfQcQUcQPcQsQUsQPsQiQUiQlQUlQf">; //////////////////////////////////////////////////////////////////////////////// -// E.3.27 Reverse vector elements (sdap endianness) +// E.3.27 Reverse vector elements def VREV64 : Inst<"vrev64", "dd", "csiUcUsUiPcPsfQcQsQiQUcQUsQUiQPcQPsQf", OP_REV64>; def VREV32 : Inst<"vrev32", "dd", "csUcUsPcPsQcQsQUcQUsQPcQPs", OP_REV32>; diff --git a/include/clang/CodeGen/BackendUtil.h b/include/clang/CodeGen/BackendUtil.h index abcef8130dbc..9636d6e527c2 100644 --- a/include/clang/CodeGen/BackendUtil.h +++ b/include/clang/CodeGen/BackendUtil.h @@ -19,6 +19,7 @@ namespace clang { class Diagnostic; class CodeGenOptions; class TargetOptions; + class LangOptions; enum BackendAction { Backend_EmitAssembly, ///< Emit native assembly files @@ -30,7 +31,8 @@ namespace clang { }; void EmitBackendOutput(Diagnostic &Diags, const CodeGenOptions &CGOpts, - const TargetOptions &TOpts, llvm::Module *M, + const TargetOptions &TOpts, const LangOptions &LOpts, + llvm::Module *M, BackendAction Action, llvm::raw_ostream *OS); } diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td index 14d8f67b9de3..d8e9e3d3e88b 100644 --- a/include/clang/Driver/CC1Options.td +++ b/include/clang/Driver/CC1Options.td @@ -143,6 +143,8 @@ def femit_coverage_data: Flag<"-femit-coverage-data">, def coverage_file : Separate<"-coverage-file">, HelpText<"Emit coverage data to this filename. The extension will be replaced.">; def coverage_file_EQ : Joined<"-coverage-file=">, Alias; +def fuse_register_sized_bitfield_access: Flag<"-fuse-register-sized-bitfield-access">, + HelpText<"Use register sized accesses to bit-fields, when possible.">; def relaxed_aliasing : Flag<"-relaxed-aliasing">, HelpText<"Turn off Type Based Alias Analysis">; def masm_verbose : Flag<"-masm-verbose">, @@ -157,6 +159,8 @@ def mfloat_abi : Separate<"-mfloat-abi">, HelpText<"The float ABI to use">; def mlimit_float_precision : Separate<"-mlimit-float-precision">, HelpText<"Limit float precision to the given value">; +def mno_exec_stack : Flag<"-mnoexecstack">, + HelpText<"Mark the file as not needing an executable stack">; def mno_zero_initialized_in_bss : Flag<"-mno-zero-initialized-in-bss">, HelpText<"Do not put zero initialized data in the BSS">; def momit_leaf_frame_pointer : Flag<"-momit-leaf-frame-pointer">, @@ -204,6 +208,7 @@ def MQ : Separate<"-MQ">, HelpText<"Specify target to quote for dependency">; def MT : Separate<"-MT">, HelpText<"Specify target for dependency">; def MP : Flag<"-MP">, HelpText<"Create phony target for each dependency (other than main file)">; +def MG : Flag<"-MG">, HelpText<"Add missing headers to dependency list">; //===----------------------------------------------------------------------===// // Diagnostic Options @@ -259,7 +264,7 @@ def ftabstop : Separate<"-ftabstop">, MetaVarName<"">, def ferror_limit : Separate<"-ferror-limit">, MetaVarName<"">, HelpText<"Set the maximum number of errors to emit before stopping (0 = no limit).">; def fmacro_backtrace_limit : Separate<"-fmacro-backtrace-limit">, MetaVarName<"">, - HelpText<"Set the maximum number of entries to print in a macro instantiation backtrace (0 = no limit).">; + HelpText<"Set the maximum number of entries to print in a macro expansion backtrace (0 = no limit).">; def ftemplate_backtrace_limit : Separate<"-ftemplate-backtrace-limit">, MetaVarName<"">, HelpText<"Set the maximum number of entries to print in a template instantiation backtrace (0 = no limit).">; def fmessage_length : Separate<"-fmessage-length">, MetaVarName<"">, @@ -352,8 +357,6 @@ def ast_dump_xml : Flag<"-ast-dump-xml">, HelpText<"Build ASTs and then debug dump them in a verbose XML format">; def ast_view : Flag<"-ast-view">, HelpText<"Build ASTs and view them with GraphViz">; -def boostcon : Flag<"-boostcon">, - HelpText<"BoostCon workshop mode">; def print_decl_contexts : Flag<"-print-decl-contexts">, HelpText<"Print DeclContexts and their Decls">; def emit_pth : Flag<"-emit-pth">, @@ -383,6 +386,15 @@ def create_module : Flag<"-create-module">, HelpText<"Create a module definition file">; } +def arcmt_check : Flag<"-arcmt-check">, + HelpText<"Check for ARC migration issues that need manual handling">; +def arcmt_modify : Flag<"-arcmt-modify">, + HelpText<"Apply modifications to files to conform to ARC">; +def arcmt_migrate : Flag<"-arcmt-migrate">, + HelpText<"Apply modifications and produces temporary files that conform to ARC">; +def arcmt_migrate_directory : Separate<"-arcmt-migrate-directory">, + HelpText<"Directory for temporary files produced during ARC migration">; + def import_module : Separate<"-import-module">, HelpText<"Import a module definition file">; @@ -452,6 +464,8 @@ def fhidden_weak_vtables : Flag<"-fhidden-weak-vtables">, HelpText<"Generate weak vtables and RTTI with hidden visibility">; def std_EQ : Joined<"-std=">, HelpText<"Language standard to compile for">; +def stdlib_EQ : Joined<"-stdlib=">, + HelpText<"C++ standard library to use">; def fmath_errno : Flag<"-fmath-errno">, HelpText<"Require math functions to indicate errors by setting errno">; def fms_extensions : Flag<"-fms-extensions">, @@ -479,6 +493,18 @@ def fconstant_string_class : Separate<"-fconstant-string-class">, HelpText<"Specify the class to use for constant Objective-C string objects.">; def fno_constant_cfstrings : Flag<"-fno-constant-cfstrings">, HelpText<"Enable creation of CodeFoundation-type constant strings">; +def fobjc_arc : Flag<"-fobjc-arc">, + HelpText<"Synthesize retain and release calls for Objective-C pointers">; +def fobjc_arc_cxxlib_EQ : Joined<"-fobjc-arc-cxxlib=">, + HelpText<"Objective-C++ Automatic Reference Counting standard library kind">; +def fobjc_arc_exceptions : Flag<"-fobjc-arc-exceptions">, + HelpText<"Use EH-safe code when synthesizing retains and releases in -fobjc-arc">; +def fobjc_runtime_has_arc : Flag<"-fobjc-runtime-has-arc">, + HelpText<"The target Objective-C runtime provides ARC entrypoints">; +def fobjc_runtime_has_weak : Flag<"-fobjc-runtime-has-weak">, + HelpText<"The target Objective-C runtime supports ARC weak operations">; +def fobjc_runtime_has_terminate : Flag<"-fobjc-runtime-has-terminate">, + HelpText<"The target Objective-C runtime provides an objc_terminate entrypoint">; def fobjc_gc : Flag<"-fobjc-gc">, HelpText<"Enable Objective-C garbage collection">; def fobjc_gc_only : Flag<"-fobjc-gc-only">, @@ -493,8 +519,10 @@ def print_ivar_layout : Flag<"-print-ivar-layout">, HelpText<"Enable Objective-C Ivar layout bitmap print trace">; def fobjc_nonfragile_abi : Flag<"-fobjc-nonfragile-abi">, HelpText<"enable objective-c's nonfragile abi">; -def fobjc_infer_related_result_type : Flag<"-fobjc-infer-related-result-type">, - HelpText<"infer Objective-C related result type based on method family">; +def fno_objc_infer_related_result_type : Flag< + "-fno-objc-infer-related-result-type">, + HelpText< + "do not infer Objective-C related result type based on method family">; def ftrapv : Flag<"-ftrapv">, HelpText<"Trap on integer overflow">; def ftrapv_handler : Separate<"-ftrapv-handler">, @@ -554,6 +582,8 @@ def fdelayed_template_parsing : Flag<"-fdelayed-template-parsing">, "translation unit ">; def funknown_anytype : Flag<"-funknown-anytype">, HelpText<"Enable parser support for the __unknown_anytype type; for testing purposes only">; +def fdebugger_support : Flag<"-fdebugger-support">, + HelpText<"Enable special debugger support behavior">; def fdeprecated_macro : Flag<"-fdeprecated-macro">, HelpText<"Defines the __DEPRECATED macro">; def fno_deprecated_macro : Flag<"-fno-deprecated-macro">, diff --git a/include/clang/Driver/Compilation.h b/include/clang/Driver/Compilation.h index 22d6b4ec6c8f..2db712d9321f 100644 --- a/include/clang/Driver/Compilation.h +++ b/include/clang/Driver/Compilation.h @@ -14,7 +14,6 @@ #include "clang/Driver/Util.h" #include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/SmallVector.h" namespace llvm { class raw_ostream; diff --git a/include/clang/Driver/Driver.h b/include/clang/Driver/Driver.h index 5a7d830b069d..b6951663148b 100644 --- a/include/clang/Driver/Driver.h +++ b/include/clang/Driver/Driver.h @@ -357,6 +357,8 @@ public: bool ShouldUseClangCompiler(const Compilation &C, const JobAction &JA, const llvm::Triple &ArchName) const; + bool IsUsingLTO(const ArgList &Args) const; + /// @} /// GetReleaseVersion - Parse (([0-9]+)(.([0-9]+)(.([0-9]+)?))?)? and diff --git a/include/clang/Driver/ObjCRuntime.h b/include/clang/Driver/ObjCRuntime.h new file mode 100644 index 000000000000..55164604338d --- /dev/null +++ b/include/clang/Driver/ObjCRuntime.h @@ -0,0 +1,46 @@ +//===--- ObjCRuntime.h - Objective C runtime features -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_DRIVER_OBJCRUNTIME_H_ +#define CLANG_DRIVER_OBJCRUNTIME_H_ + +namespace clang { +namespace driver { + +class ObjCRuntime { +public: + enum Kind { GNU, NeXT }; +private: + unsigned RuntimeKind : 1; +public: + void setKind(Kind k) { RuntimeKind = k; } + Kind getKind() const { return static_cast(RuntimeKind); } + + /// True if the runtime provides native ARC entrypoints. ARC may + /// still be usable without this if the tool-chain provides a + /// statically-linked runtime support library. + unsigned HasARC : 1; + + /// True if the runtime supports ARC zeroing __weak. + unsigned HasWeak : 1; + + /// True if the runtime provides the following entrypoint: + /// void objc_terminate(void); + /// If available, this will be called instead of abort() when an + /// exception is thrown out of an EH cleanup. + unsigned HasTerminate : 1; + + ObjCRuntime() : RuntimeKind(NeXT), HasARC(false), HasWeak(false), + HasTerminate(false) {} +}; + +} +} + +#endif diff --git a/include/clang/Driver/Option.h b/include/clang/Driver/Option.h index 9625465f48f4..9dfa4614009f 100644 --- a/include/clang/Driver/Option.h +++ b/include/clang/Driver/Option.h @@ -11,6 +11,7 @@ #define CLANG_DRIVER_OPTION_H_ #include "clang/Driver/OptSpecifier.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" using llvm::isa; using llvm::cast; @@ -64,7 +65,7 @@ namespace driver { OptSpecifier ID; /// The option name. - const char *Name; + llvm::StringRef Name; /// Group this option is a member of, if any. const OptionGroup *Group; @@ -103,7 +104,7 @@ namespace driver { unsigned getID() const { return ID.getID(); } OptionClass getKind() const { return Kind; } - const char *getName() const { return Name; } + llvm::StringRef getName() const { return Name; } const OptionGroup *getGroup() const { return Group; } const Option *getAlias() const { return Alias; } @@ -143,7 +144,7 @@ namespace driver { /// getRenderName - Return the name to use when rendering this /// option. - const char *getRenderName() const { + llvm::StringRef getRenderName() const { return getUnaliasedOption()->getName(); } diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index 72039766d907..d5482765e756 100644 --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -112,6 +112,17 @@ def ccc_print_phases : Flag<"-ccc-print-phases">, CCCDebugOpt, def ccc_print_bindings : Flag<"-ccc-print-bindings">, CCCDebugOpt, HelpText<"Show bindings of tools to actions">; +def ccc_arcmt_check : Flag<"-ccc-arcmt-check">, CCCDriverOpt, + HelpText<"Check for ARC migration issues that need manual handling">; +def ccc_arcmt_modify : Flag<"-ccc-arcmt-modify">, CCCDriverOpt, + HelpText<"Apply modifications to files to conform to ARC">; +def ccc_arrmt_check : Flag<"-ccc-arrmt-check">, Alias; +def ccc_arrmt_modify : Flag<"-ccc-arrmt-modify">, Alias; +def ccc_arcmt_migrate : Separate<"-ccc-arcmt-migrate">, CCCDriverOpt, + HelpText<"Apply modifications and produces temporary files that conform to ARC">; +def ccc_arcmt_migrate_EQ : Joined<"-ccc-arcmt-migrate=">, CCCDriverOpt, + Alias; + // Make sure all other -ccc- options are rejected. def ccc_ : Joined<"-ccc-">, Group, Flags<[Unsupported]>; @@ -382,6 +393,10 @@ def fno_verbose_asm : Flag<"-fno-verbose-asm">, Group; def fno_working_directory : Flag<"-fno-working-directory">, Group; def fno_wrapv : Flag<"-fno-wrapv">, Group; def fno_zero_initialized_in_bss : Flag<"-fno-zero-initialized-in-bss">, Group; +def fobjc_arc : Flag<"-fobjc-arc">, Group; +def fno_objc_arc : Flag<"-fno-objc-arc">, Group; +def fobjc_arc_exceptions : Flag<"-fobjc-arc-exceptions">, Group; +def fno_objc_arc_exceptions : Flag<"-fno-objc-arc-exceptions">, Group; def fobjc_atdefs : Flag<"-fobjc-atdefs">, Group; def fobjc_call_cxx_cdtors : Flag<"-fobjc-call-cxx-cdtors">, Group; def fobjc_default_synthesize_properties : @@ -409,6 +424,7 @@ def fomit_frame_pointer : Flag<"-fomit-frame-pointer">, Group; def fopenmp : Flag<"-fopenmp">, Group; def force__cpusubtype__ALL : Flag<"-force_cpusubtype_ALL">; def force__flat__namespace : Flag<"-force_flat_namespace">; +def force__load : Separate<"-force_load">; def foutput_class_dir_EQ : Joined<"-foutput-class-dir=">, Group; def fpascal_strings : Flag<"-fpascal-strings">, Group; def fpch_preprocess : Flag<"-fpch-preprocess">, Group; @@ -803,8 +819,8 @@ def _specs : Separate<"--specs">, Alias; def _static : Flag<"--static">, Alias; def _std_EQ : Joined<"--std=">, Alias; def _std : Separate<"--std">, Alias; -def _stdlib_EQ : Joined<"--stdlib=">, Alias; -def _stdlib : Separate<"--stdlib">, Alias; +def _stdlib_EQ : Joined<"--stdlib=">, Alias; +def _stdlib : Separate<"--stdlib">, Alias; def _sysroot_EQ : Joined<"--sysroot=">; def _sysroot : Separate<"--sysroot">, Alias<_sysroot_EQ>; def _target_help : Flag<"--target-help">; diff --git a/include/clang/Driver/ToolChain.h b/include/clang/Driver/ToolChain.h index 626d54c37b8a..4836d3ffac22 100644 --- a/include/clang/Driver/ToolChain.h +++ b/include/clang/Driver/ToolChain.h @@ -26,6 +26,7 @@ namespace driver { class HostInfo; class InputArgList; class JobAction; + class ObjCRuntime; class Tool; /// ToolChain - Access to tools for a single platform. @@ -177,6 +178,12 @@ public: /// Clang. virtual std::string ComputeEffectiveClangTriple(const ArgList &Args) const; + /// configureObjCRuntime - Configure the known properties of the + /// Objective-C runtime for this platform. + /// + /// FIXME: this doesn't really belong here. + virtual void configureObjCRuntime(ObjCRuntime &runtime) const; + // GetCXXStdlibType - Determine the C++ standard library type to use with the // given compilation arguments. virtual CXXStdlibType GetCXXStdlibType(const ArgList &Args) const; @@ -184,7 +191,8 @@ public: /// AddClangCXXStdlibIncludeArgs - Add the clang -cc1 level arguments to set /// the include paths to use for the given C++ standard library type. virtual void AddClangCXXStdlibIncludeArgs(const ArgList &Args, - ArgStringList &CmdArgs) const; + ArgStringList &CmdArgs, + bool ObjCXXAutoRefCount) const; /// AddCXXStdlibLibArgs - Add the system specific linker arguments to use /// for the given C++ standard library type. diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h index 339297eb9362..58a60a1f9d87 100644 --- a/include/clang/Frontend/ASTUnit.h +++ b/include/clang/Frontend/ASTUnit.h @@ -249,9 +249,9 @@ private: /// \brief Whether we should be caching code-completion results. bool ShouldCacheCodeCompletionResults; - /// \brief Whether we want to include nested macro instantiations in the + /// \brief Whether we want to include nested macro expansions in the /// detailed preprocessing record. - bool NestedMacroInstantiations; + bool NestedMacroExpansions; static void ConfigureDiags(llvm::IntrusiveRefCntPtr &Diags, const char **ArgBegin, const char **ArgEnd, @@ -363,7 +363,7 @@ private: unsigned MaxLines, bool &CreatedBuffer); llvm::MemoryBuffer *getMainBufferWithPrecompiledPreamble( - CompilerInvocation PreambleInvocation, + const CompilerInvocation &PreambleInvocationIn, bool AllowRebuild = true, unsigned MaxLines = 0); void RealizeTopLevelDeclsFromPreamble(); @@ -612,7 +612,7 @@ public: bool PrecompilePreamble = false, bool CompleteTranslationUnit = true, bool CacheCodeCompletionResults = false, - bool NestedMacroInstantiations = true); + bool NestedMacroExpansions = true); /// LoadFromCommandLine - Create an ASTUnit from a vector of command line /// arguments, which must specify exactly one source file. @@ -642,7 +642,7 @@ public: bool CacheCodeCompletionResults = false, bool CXXPrecompilePreamble = false, bool CXXChainedPCH = false, - bool NestedMacroInstantiations = true); + bool NestedMacroExpansions = true); /// \brief Reparse the source files using the same command-line options that /// were originally used to produce this translation unit. @@ -680,8 +680,8 @@ public: /// \brief Save this translation unit to a file with the given name. /// - /// \returns True if an error occurred, false otherwise. - bool Save(llvm::StringRef File); + /// \returns An indication of whether the save was successful or not. + CXSaveError Save(llvm::StringRef File); /// \brief Serialize this translation unit with the given output stream. /// diff --git a/include/clang/Frontend/CodeGenOptions.h b/include/clang/Frontend/CodeGenOptions.h index 1c686c76df5f..5d040b4f266c 100644 --- a/include/clang/Frontend/CodeGenOptions.h +++ b/include/clang/Frontend/CodeGenOptions.h @@ -36,6 +36,7 @@ public: }; unsigned AsmVerbose : 1; /// -dA, -fverbose-asm. + unsigned ObjCAutoRefCountExceptions : 1; /// Whether ARC should be EH-safe. unsigned CXAAtExit : 1; /// Use __cxa_atexit for calling destructors. unsigned CXXCtorDtorAliases: 1; /// Emit complete ctors/dtors as linker /// aliases to base ctors when possible. @@ -69,11 +70,14 @@ public: unsigned MergeAllConstants : 1; /// Merge identical constants. unsigned NoCommon : 1; /// Set when -fno-common or C++ is enabled. unsigned NoDwarf2CFIAsm : 1; /// Set when -fno-dwarf2-cfi-asm is enabled. + unsigned NoExecStack : 1; /// Set when -Wa,--noexecstack is enabled. unsigned NoImplicitFloat : 1; /// Set when -mno-implicit-float is enabled. unsigned NoInfsFPMath : 1; /// Assume FP arguments, results not +-Inf. unsigned NoNaNsFPMath : 1; /// Assume FP arguments, results not NaN. unsigned NoZeroInitializedInBSS : 1; /// -fno-zero-initialized-in-bss unsigned ObjCDispatchMethod : 2; /// Method of Objective-C dispatch to use. + unsigned ObjCRuntimeHasARC : 1; /// The target runtime supports ARC natively + unsigned ObjCRuntimeHasTerminate : 1; /// The ObjC runtime has objc_terminate unsigned OmitLeafFramePointer : 1; /// Set when -momit-leaf-frame-pointer is /// enabled. unsigned OptimizationLevel : 3; /// The -O[0-4] option specified. @@ -89,6 +93,11 @@ public: unsigned UnrollLoops : 1; /// Control whether loops are unrolled. unsigned UnsafeFPMath : 1; /// Allow unsafe floating point optzns. unsigned UnwindTables : 1; /// Emit unwind tables. + + /// Attempt to use register sized accesses to bit-fields in structures, when + /// possible. + unsigned UseRegisterSizedBitfieldAccess : 1; + unsigned VerifyModule : 1; /// Control whether the module should be run /// through the LLVM Verifier. @@ -159,7 +168,10 @@ public: NoNaNsFPMath = 0; NoZeroInitializedInBSS = 0; NumRegisterParameters = 0; + ObjCAutoRefCountExceptions = 0; ObjCDispatchMethod = Legacy; + ObjCRuntimeHasARC = 0; + ObjCRuntimeHasTerminate = 0; OmitLeafFramePointer = 0; OptimizationLevel = 0; OptimizeSize = 0; @@ -173,6 +185,7 @@ public: UnrollLoops = 0; UnsafeFPMath = 0; UnwindTables = 0; + UseRegisterSizedBitfieldAccess = 0; VerifyModule = 1; Inlining = NoInlining; diff --git a/include/clang/Frontend/DependencyOutputOptions.h b/include/clang/Frontend/DependencyOutputOptions.h index 35aa6c6aace6..1e22c227fcea 100644 --- a/include/clang/Frontend/DependencyOutputOptions.h +++ b/include/clang/Frontend/DependencyOutputOptions.h @@ -24,6 +24,7 @@ public: unsigned UsePhonyTargets : 1; ///< Include phony targets for each /// dependency, which can avoid some 'make' /// problems. + unsigned AddMissingHeaderDeps : 1; ///< Add missing headers to dependency list /// The file to write dependency output to. std::string OutputFile; @@ -43,6 +44,7 @@ public: IncludeSystemHeaders = 0; ShowHeaderIncludes = 0; UsePhonyTargets = 0; + AddMissingHeaderDeps = 0; } }; diff --git a/include/clang/Frontend/DiagnosticOptions.h b/include/clang/Frontend/DiagnosticOptions.h index 56093c3c950c..5ae8eb367788 100644 --- a/include/clang/Frontend/DiagnosticOptions.h +++ b/include/clang/Frontend/DiagnosticOptions.h @@ -49,8 +49,7 @@ public: /// input source file. unsigned ErrorLimit; /// Limit # errors emitted. - unsigned MacroBacktraceLimit; /// Limit depth of macro instantiation - /// backtrace. + unsigned MacroBacktraceLimit; /// Limit depth of macro expansion backtrace. unsigned TemplateBacktraceLimit; /// Limit depth of instantiation backtrace. /// The distance between tab stops. diff --git a/include/clang/Frontend/FrontendAction.h b/include/clang/Frontend/FrontendAction.h index ee0863a4776f..f335475665fd 100644 --- a/include/clang/Frontend/FrontendAction.h +++ b/include/clang/Frontend/FrontendAction.h @@ -51,6 +51,7 @@ class FrontendAction { llvm::OwningPtr CurrentASTUnit; CompilerInstance *Instance; friend class ASTMergeAction; + friend class WrapperFrontendAction; private: ASTConsumer* CreateWrappedASTConsumer(CompilerInstance &CI, @@ -77,6 +78,14 @@ protected: virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) = 0; + /// \brief Callback before starting processing a single input, giving the + /// opportunity to modify the CompilerInvocation or do some other action + /// before BeginSourceFileAction is called. + /// + /// \return True on success; on failure \see BeginSourceFileAction() and + /// ExecutionAction() and EndSourceFileAction() will not be called. + virtual bool BeginInvocation(CompilerInstance &CI) { return true; } + /// BeginSourceFileAction - Callback at the start of processing a single /// input. /// @@ -253,6 +262,36 @@ public: virtual bool usesPreprocessorOnly() const { return true; } }; +/// WrapperFrontendAction - A frontend action which simply wraps some other +/// runtime specified frontend action. Deriving from this class allows an +/// action to inject custom logic around some existing action's behavior. It +/// implements every virtual method in the FrontendAction interface by +/// forwarding to the wrapped action. +class WrapperFrontendAction : public FrontendAction { + llvm::OwningPtr WrappedAction; + +protected: + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile); + virtual bool BeginInvocation(CompilerInstance &CI); + virtual bool BeginSourceFileAction(CompilerInstance &CI, + llvm::StringRef Filename); + virtual void ExecuteAction(); + virtual void EndSourceFileAction(); + +public: + /// Construct a WrapperFrontendAction from an existing action, taking + /// ownership of it. + WrapperFrontendAction(FrontendAction *WrappedAction); + + virtual bool usesPreprocessorOnly() const; + virtual bool usesCompleteTranslationUnit(); + virtual bool hasPCHSupport() const; + virtual bool hasASTFileSupport() const; + virtual bool hasIRSupport() const; + virtual bool hasCodeCompletionSupport() const; +}; + } // end namespace clang #endif diff --git a/include/clang/Frontend/FrontendActions.h b/include/clang/Frontend/FrontendActions.h index 4e67449b8549..b409ad1e0963 100644 --- a/include/clang/Frontend/FrontendActions.h +++ b/include/clang/Frontend/FrontendActions.h @@ -97,12 +97,6 @@ public: virtual bool hasCodeCompletionSupport() const { return true; } }; -class BoostConAction : public SyntaxOnlyAction { -protected: - virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile); -}; - /** * \brief Frontend action adaptor that merges ASTs together. * diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h index 02f6f868fe49..225a955b4ac6 100644 --- a/include/clang/Frontend/FrontendOptions.h +++ b/include/clang/Frontend/FrontendOptions.h @@ -24,7 +24,6 @@ namespace frontend { ASTDumpXML, ///< Parse ASTs and dump them in XML. ASTPrint, ///< Parse ASTs and print them. ASTView, ///< Parse ASTs and view them in Graphviz. - BoostCon, ///< BoostCon mode. CreateModule, ///< Create module definition DumpRawTokens, ///< Dump out raw tokens. DumpTokens, ///< Dump out preprocessed tokens. @@ -77,6 +76,15 @@ public: unsigned FixWhatYouCan : 1; ///< Apply fixes even if there are /// unfixable errors. + enum { + ARCMT_None, + ARCMT_Check, + ARCMT_Modify, + ARCMT_Migrate + } ARCMTAction; + + std::string ARCMTMigrateDir; + /// The input files and their types. std::vector > Inputs; @@ -131,6 +139,7 @@ public: ShowStats = 0; ShowTimers = 0; ShowVersion = 0; + ARCMTAction = ARCMT_None; } /// getInputKindForExtension - Return the appropriate input kind for a file diff --git a/include/clang/Frontend/HeaderSearchOptions.h b/include/clang/Frontend/HeaderSearchOptions.h index b0669eba4ccc..0347f98fd5ba 100644 --- a/include/clang/Frontend/HeaderSearchOptions.h +++ b/include/clang/Frontend/HeaderSearchOptions.h @@ -17,10 +17,12 @@ namespace clang { namespace frontend { /// IncludeDirGroup - Identifiers the group a include entry belongs to, which - /// represents its relative positive in the search list. + /// represents its relative positive in the search list. A #include of a "" + /// path starts at the -iquote group, then searches the Angled group, then + /// searches the system group, etc. enum IncludeDirGroup { - Quoted = 0, ///< `#include ""` paths. Thing `gcc -iquote`. - Angled, ///< Paths for both `#include ""` and `#include <>`. (`-I`) + Quoted = 0, ///< '#include ""' paths, added by'gcc -iquote'. + Angled, ///< Paths for '#include <>' added by '-I'. System, ///< Like Angled, but marks system directories. CXXSystem, ///< Like System, but only used for C++. After ///< Like System, but searched after the system directories. @@ -37,15 +39,15 @@ public: unsigned IsUserSupplied : 1; unsigned IsFramework : 1; - /// IsSysRootRelative - This is true if an absolute path should be treated - /// relative to the sysroot, or false if it should always be the absolute + /// IgnoreSysRoot - This is false if an absolute path should be treated + /// relative to the sysroot, or true if it should always be the absolute /// path. - unsigned IsSysRootRelative : 1; + unsigned IgnoreSysRoot : 1; Entry(llvm::StringRef path, frontend::IncludeDirGroup group, - bool isUserSupplied, bool isFramework, bool isSysRootRelative) + bool isUserSupplied, bool isFramework, bool ignoreSysRoot) : Path(path), Group(group), IsUserSupplied(isUserSupplied), - IsFramework(isFramework), IsSysRootRelative(isSysRootRelative) {} + IsFramework(isFramework), IgnoreSysRoot(ignoreSysRoot) {} }; /// If non-empty, the directory to use as a "virtual system root" for include @@ -80,20 +82,23 @@ public: /// Include the system standard C++ library include search directories. unsigned UseStandardCXXIncludes : 1; + /// Use libc++ instead of the default libstdc++. + unsigned UseLibcxx : 1; + /// Whether header search information should be output as for -v. unsigned Verbose : 1; public: HeaderSearchOptions(llvm::StringRef _Sysroot = "/") : Sysroot(_Sysroot), UseBuiltinIncludes(true), - UseStandardIncludes(true), UseStandardCXXIncludes(true), + UseStandardIncludes(true), UseStandardCXXIncludes(true), UseLibcxx(false), Verbose(false) {} /// AddPath - Add the \arg Path path to the specified \arg Group list. void AddPath(llvm::StringRef Path, frontend::IncludeDirGroup Group, - bool IsUserSupplied, bool IsFramework, bool IsSysRootRelative) { + bool IsUserSupplied, bool IsFramework, bool IgnoreSysRoot) { UserEntries.push_back(Entry(Path, Group, IsUserSupplied, IsFramework, - IsSysRootRelative)); + IgnoreSysRoot)); } }; diff --git a/include/clang/Frontend/PreprocessorOptions.h b/include/clang/Frontend/PreprocessorOptions.h index e471c5cf1d82..2e16c97e7d43 100644 --- a/include/clang/Frontend/PreprocessorOptions.h +++ b/include/clang/Frontend/PreprocessorOptions.h @@ -1,4 +1,4 @@ -//===--- PreprocessorOptionms.h ---------------------------------*- C++ -*-===// +//===--- PreprocessorOptions.h ----------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -26,6 +26,15 @@ namespace clang { class Preprocessor; class LangOptions; +/// \brief Enumerate the kinds of standard library that +enum ObjCXXARCStandardLibraryKind { + ARCXX_nolib, + /// \brief libc++ + ARCXX_libcxx, + /// \brief libstdc++ + ARCXX_libstdcxx +}; + /// PreprocessorOptions - This class is used for passing the various options /// used in preprocessor initialization to InitializePreprocessor(). class PreprocessorOptions { @@ -39,11 +48,11 @@ public: unsigned DetailedRecord : 1; /// Whether we should maintain a detailed /// record of all macro definitions and - /// instantiations. + /// expansions. /// \brief Whether the detailed preprocessing record includes nested macro - /// instantiations. - unsigned DetailedRecordIncludesNestedMacroInstantiations : 1; + /// expansions. + unsigned DetailedRecordIncludesNestedMacroExpansions : 1; /// The implicit PCH included at the start of the translation unit, or empty. std::string ImplicitPCHInclude; @@ -104,6 +113,11 @@ public: /// compiler invocation and its buffers will be reused. bool RetainRemappedFileBuffers; + /// \brief The Objective-C++ ARC standard library that we should support, + /// by providing appropriate definitions to retrofit the standard library + /// with support for lifetime-qualified pointers. + ObjCXXARCStandardLibraryKind ObjCXXARCStandardLibrary; + typedef std::vector >::iterator remapped_file_iterator; typedef std::vector >::const_iterator @@ -140,12 +154,13 @@ public: public: PreprocessorOptions() : UsePredefines(true), DetailedRecord(false), - DetailedRecordIncludesNestedMacroInstantiations(true), + DetailedRecordIncludesNestedMacroExpansions(true), DisablePCHValidation(false), DisableStatCache(false), DumpDeserializedPCHDecls(false), PrecompiledPreambleBytes(0, true), RemappedFilesKeepOriginalName(true), - RetainRemappedFileBuffers(false) { } + RetainRemappedFileBuffers(false), + ObjCXXARCStandardLibrary(ARCXX_nolib) { } void addMacroDef(llvm::StringRef Name) { Macros.push_back(std::make_pair(Name, false)); diff --git a/include/clang/Frontend/TextDiagnosticPrinter.h b/include/clang/Frontend/TextDiagnosticPrinter.h index d7d2692cb547..79a9916cb435 100644 --- a/include/clang/Frontend/TextDiagnosticPrinter.h +++ b/include/clang/Frontend/TextDiagnosticPrinter.h @@ -62,18 +62,17 @@ public: std::string &CaretLine, const std::string &SourceLine); - void EmitCaretDiagnostic(Diagnostic::Level Level, SourceLocation Loc, - CharSourceRange *Ranges, unsigned NumRanges, - const SourceManager &SM, - const FixItHint *Hints, - unsigned NumHints, - unsigned Columns, - unsigned OnMacroInst, - unsigned MacroSkipStart, - unsigned MacroSkipEnd); - virtual void HandleDiagnostic(Diagnostic::Level Level, const DiagnosticInfo &Info); + +private: + void EmitCaretDiagnostic(SourceLocation Loc, CharSourceRange *Ranges, + unsigned NumRanges, const SourceManager &SM, + const FixItHint *Hints, + unsigned NumHints, unsigned Columns, + unsigned OnMacroInst, unsigned MacroSkipStart, + unsigned MacroSkipEnd); + }; } // end namespace clang diff --git a/include/clang/Frontend/Utils.h b/include/clang/Frontend/Utils.h index 3c34c2dce24b..93d2c7d501e7 100644 --- a/include/clang/Frontend/Utils.h +++ b/include/clang/Frontend/Utils.h @@ -19,6 +19,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/Support/raw_ostream.h" +#include "clang/Basic/Diagnostic.h" namespace llvm { class Triple; diff --git a/include/clang/Lex/Lexer.h b/include/clang/Lex/Lexer.h index 7c3d863bd3d3..f4297627e86f 100644 --- a/include/clang/Lex/Lexer.h +++ b/include/clang/Lex/Lexer.h @@ -95,8 +95,8 @@ public: /// _Pragma expansion. This has a variety of magic semantics that this method /// sets up. It returns a new'd Lexer that must be delete'd when done. static Lexer *Create_PragmaLexer(SourceLocation SpellingLoc, - SourceLocation InstantiationLocStart, - SourceLocation InstantiationLocEnd, + SourceLocation ExpansionLocStart, + SourceLocation ExpansionLocEnd, unsigned TokLen, Preprocessor &PP); @@ -241,8 +241,8 @@ public: /// is not necessary to copy any data, then the returned string may /// not point into the provided buffer. /// - /// This method lexes at the instantiation depth of the given - /// location and does not jump to the instantiation or spelling + /// This method lexes at the expansion depth of the given + /// location and does not jump to the expansion or spelling /// location. static llvm::StringRef getSpelling(SourceLocation loc, llvm::SmallVectorImpl &buffer, @@ -293,7 +293,19 @@ public: static SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset, const SourceManager &SM, const LangOptions &Features); - + + /// \brief Returns true if the given MacroID location points at the first + /// token of the macro expansion. + static bool isAtStartOfMacroExpansion(SourceLocation loc, + const SourceManager &SM, + const LangOptions &LangOpts); + + /// \brief Returns true if the given MacroID location points at the last + /// token of the macro expansion. + static bool isAtEndOfMacroExpansion(SourceLocation loc, + const SourceManager &SM, + const LangOptions &LangOpts); + /// \brief Compute the preamble of the given file. /// /// The preamble of a file contains the initial comments, include directives, diff --git a/include/clang/Lex/LiteralSupport.h b/include/clang/Lex/LiteralSupport.h index ec3d9c58d67e..0dbcd6d72d63 100644 --- a/include/clang/Lex/LiteralSupport.h +++ b/include/clang/Lex/LiteralSupport.h @@ -167,7 +167,9 @@ public: bool AnyWide; bool Pascal; - const char *GetString() { return ResultBuf.data(); } + llvm::StringRef GetString() const { + return llvm::StringRef(ResultBuf.data(), GetStringLength()); + } unsigned GetStringLength() const { return ResultPtr-ResultBuf.data(); } unsigned GetNumStringChars() const { diff --git a/include/clang/Lex/MacroInfo.h b/include/clang/Lex/MacroInfo.h index 7c4cfb007233..9e9d7cf500a4 100644 --- a/include/clang/Lex/MacroInfo.h +++ b/include/clang/Lex/MacroInfo.h @@ -43,6 +43,10 @@ class MacroInfo { /// to. llvm::SmallVector ReplacementTokens; + /// \brief Length in characters of the macro definition. + mutable unsigned DefinitionLength; + mutable bool IsDefinitionLengthCached : 1; + /// IsFunctionLike - True if this macro is a function-like macro, false if it /// is an object-like macro. bool IsFunctionLike : 1; @@ -116,6 +120,13 @@ public: /// getDefinitionEndLoc - Return the location of the last token in the macro. /// SourceLocation getDefinitionEndLoc() const { return EndLocation; } + + /// \brief Get length in characters of the macro definition. + unsigned getDefinitionLength(SourceManager &SM) const { + if (IsDefinitionLengthCached) + return DefinitionLength; + return getDefinitionLengthSlow(SM); + } /// isIdenticalTo - Return true if the specified macro definition is equal to /// this macro in spelling, arguments, and whitespace. This is used to emit @@ -232,6 +243,8 @@ public: /// AddTokenToBody - Add the specified token to the replacement text for the /// macro. void AddTokenToBody(const Token &Tok) { + assert(!IsDefinitionLengthCached && + "Changing replacement tokens after definition length got calculated"); ReplacementTokens.push_back(Tok); } @@ -248,6 +261,9 @@ public: assert(!IsDisabled && "Cannot disable an already-disabled macro!"); IsDisabled = true; } + +private: + unsigned getDefinitionLengthSlow(SourceManager &SM) const; }; } // end namespace clang diff --git a/include/clang/Lex/PPCallbacks.h b/include/clang/Lex/PPCallbacks.h index fd07a29f8e9d..a7948153a728 100644 --- a/include/clang/Lex/PPCallbacks.h +++ b/include/clang/Lex/PPCallbacks.h @@ -16,6 +16,7 @@ #include "clang/Lex/DirectoryLookup.h" #include "clang/Basic/SourceLocation.h" +#include "clang/Basic/DiagnosticIDs.h" #include "llvm/ADT/StringRef.h" #include @@ -124,6 +125,24 @@ public: virtual void PragmaMessage(SourceLocation Loc, llvm::StringRef Str) { } + /// PragmaDiagnosticPush - This callback is invoked when a + /// #pragma gcc dianostic push directive is read. + virtual void PragmaDiagnosticPush(SourceLocation Loc, + llvm::StringRef Namespace) { + } + + /// PragmaDiagnosticPop - This callback is invoked when a + /// #pragma gcc dianostic pop directive is read. + virtual void PragmaDiagnosticPop(SourceLocation Loc, + llvm::StringRef Namespace) { + } + + /// PragmaDiagnostic - This callback is invoked when a + /// #pragma gcc dianostic directive is read. + virtual void PragmaDiagnostic(SourceLocation Loc, llvm::StringRef Namespace, + diag::Mapping mapping, llvm::StringRef Str) { + } + /// MacroExpands - This is called by /// Preprocessor::HandleMacroExpandedIdentifier when a macro invocation is /// found. @@ -232,6 +251,24 @@ public: Second->PragmaMessage(Loc, Str); } + virtual void PragmaDiagnosticPush(SourceLocation Loc, + llvm::StringRef Namespace) { + First->PragmaDiagnosticPush(Loc, Namespace); + Second->PragmaDiagnosticPush(Loc, Namespace); + } + + virtual void PragmaDiagnosticPop(SourceLocation Loc, + llvm::StringRef Namespace) { + First->PragmaDiagnosticPop(Loc, Namespace); + Second->PragmaDiagnosticPop(Loc, Namespace); + } + + virtual void PragmaDiagnostic(SourceLocation Loc, llvm::StringRef Namespace, + diag::Mapping mapping, llvm::StringRef Str) { + First->PragmaDiagnostic(Loc, Namespace, mapping, Str); + Second->PragmaDiagnostic(Loc, Namespace, mapping, Str); + } + virtual void MacroExpands(const Token &MacroNameTok, const MacroInfo* MI) { First->MacroExpands(MacroNameTok, MI); Second->MacroExpands(MacroNameTok, MI); diff --git a/include/clang/Lex/PreprocessingRecord.h b/include/clang/Lex/PreprocessingRecord.h index e498e9d0a020..b38303a2f40b 100644 --- a/include/clang/Lex/PreprocessingRecord.h +++ b/include/clang/Lex/PreprocessingRecord.h @@ -38,13 +38,13 @@ namespace clang { class FileEntry; /// \brief Base class that describes a preprocessed entity, which may be a - /// preprocessor directive or macro instantiation. + /// preprocessor directive or macro expansion. class PreprocessedEntity { public: /// \brief The kind of preprocessed entity an object describes. enum EntityKind { - /// \brief A macro instantiation. - MacroInstantiationKind, + /// \brief A macro expansion. + MacroExpansionKind, /// \brief A preprocessing directive whose kind is not specified. /// @@ -110,31 +110,31 @@ namespace clang { void operator delete(void* data) throw(); }; - /// \brief Records the location of a macro instantiation. - class MacroInstantiation : public PreprocessedEntity { - /// \brief The name of the macro being instantiation. + /// \brief Records the location of a macro expansion. + class MacroExpansion : public PreprocessedEntity { + /// \brief The name of the macro being expanded. IdentifierInfo *Name; /// \brief The definition of this macro. MacroDefinition *Definition; public: - MacroInstantiation(IdentifierInfo *Name, SourceRange Range, - MacroDefinition *Definition) - : PreprocessedEntity(MacroInstantiationKind, Range), Name(Name), + MacroExpansion(IdentifierInfo *Name, SourceRange Range, + MacroDefinition *Definition) + : PreprocessedEntity(MacroExpansionKind, Range), Name(Name), Definition(Definition) { } - /// \brief The name of the macro being instantiated. + /// \brief The name of the macro being expanded. IdentifierInfo *getName() const { return Name; } - /// \brief The definition of the macro being instantiated. + /// \brief The definition of the macro being expanded. MacroDefinition *getDefinition() const { return Definition; } // Implement isa/cast/dyncast/etc. static bool classof(const PreprocessedEntity *PE) { - return PE->getKind() == MacroInstantiationKind; + return PE->getKind() == MacroExpansionKind; } - static bool classof(const MacroInstantiation *) { return true; } + static bool classof(const MacroExpansion *) { return true; } }; @@ -256,11 +256,11 @@ namespace clang { /// \brief A record of the steps taken while preprocessing a source file, /// including the various preprocessing directives processed, macros - /// instantiated, etc. + /// expanded, etc. class PreprocessingRecord : public PPCallbacks { - /// \brief Whether we should include nested macro instantiations in + /// \brief Whether we should include nested macro expansions in /// the preprocessing record. - bool IncludeNestedMacroInstantiations; + bool IncludeNestedMacroExpansions; /// \brief Allocator used to store preprocessing objects. llvm::BumpPtrAllocator BumpAlloc; @@ -286,7 +286,7 @@ namespace clang { public: /// \brief Construct - explicit PreprocessingRecord(bool IncludeNestedMacroInstantiations); + explicit PreprocessingRecord(bool IncludeNestedMacroExpansions); /// \brief Allocate memory in the preprocessing record. void *Allocate(unsigned Size, unsigned Align = 8) { diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h index 76e3f59ef4c4..f6f3205099a0 100644 --- a/include/clang/Lex/Preprocessor.h +++ b/include/clang/Lex/Preprocessor.h @@ -29,6 +29,7 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/Support/Allocator.h" #include @@ -120,7 +121,7 @@ class Preprocessor : public llvm::RefCountedBase { /// 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/expanded here because it's role/lifetime is /// conceptually similar the IdentifierTable. In addition, the current control /// flow (in clang::ParseAST()), make it convenient to put here. /// FIXME: Make sure the lifetime of Identifiers/Selectors *isn't* tied to @@ -219,9 +220,9 @@ class Preprocessor : public llvm::RefCountedBase { /// previous macro value. llvm::DenseMap > PragmaPushMacroInfo; - /// \brief Instantiation source location for the last macro that expanded + /// \brief Expansion source location for the last macro that expanded /// to no tokens. - SourceLocation LastEmptyMacroInstantiationLoc; + SourceLocation LastEmptyMacroExpansionLoc; // Various statistics we track for performance analysis. unsigned NumDirectives, NumIncluded, NumDefined, NumUndefined, NumPragma; @@ -240,7 +241,15 @@ class Preprocessor : public llvm::RefCountedBase { unsigned NumCachedTokenLexers; TokenLexer *TokenLexerCache[TokenLexerCacheSize]; - /// \brief A record of the macro definitions and instantiations that + /// \brief Keeps macro expanded tokens for TokenLexers. + // + /// Works like a stack; a TokenLexer adds the macro expanded tokens that is + /// going to lex in the cache and when it finishes the tokens are removed + /// from the end of the cache. + llvm::SmallVector MacroExpandedTokens; + std::vector > MacroExpandingLexersStack; + + /// \brief A record of the macro definitions and expansions that /// occurred during preprocessing. /// /// This is an optional side structure that can be enabled with @@ -371,10 +380,10 @@ public: macro_iterator macro_begin(bool IncludeExternalMacros = true) const; macro_iterator macro_end(bool IncludeExternalMacros = true) const; - /// \brief Instantiation source location for the last macro that expanded + /// \brief Expansion source location for the last macro that expanded /// to no tokens. - SourceLocation getLastEmptyMacroInstantiationLoc() const { - return LastEmptyMacroInstantiationLoc; + SourceLocation getLastEmptyMacroExpansionLoc() const { + return LastEmptyMacroExpansionLoc; } const std::string &getPredefines() const { return Predefines; } @@ -442,7 +451,7 @@ public: /// \brief Create a new preprocessing record, which will keep track of /// all macro expansions, macro definitions, etc. - void createPreprocessingRecord(bool IncludeNestedMacroInstantiations); + void createPreprocessingRecord(bool IncludeNestedMacroExpansions); /// EnterMainSourceFile - Enter the specified FileID as the main source file, /// which implicitly adds the builtin defines etc. @@ -658,7 +667,7 @@ public: /// getSpelling() - Return the 'spelling' of the token at the given /// location; does not go up to the spelling location or down to the - /// instantiation location. + /// expansion location. /// /// \param buffer A buffer which will be used only if the token requires /// "cleaning", e.g. if it contains trigraphs or escaped newlines @@ -721,7 +730,7 @@ public: /// CreateString - Plop the specified string into a scratch buffer and set the /// specified token's location and length to it. If specified, the source - /// location provides a location of the instantiation point of the token. + /// location provides a location of the expansion point of the token. void CreateString(const char *Buf, unsigned Len, Token &Tok, SourceLocation SourceLoc = SourceLocation()); @@ -744,6 +753,18 @@ public: return Lexer::getLocForEndOfToken(Loc, Offset, SourceMgr, Features); } + /// \brief Returns true if the given MacroID location points at the first + /// token of the macro expansion. + bool isAtStartOfMacroExpansion(SourceLocation loc) const { + return Lexer::isAtStartOfMacroExpansion(loc, SourceMgr, Features); + } + + /// \brief Returns true if the given MacroID location points at the last + /// token of the macro expansion. + bool isAtEndOfMacroExpansion(SourceLocation loc) const { + return Lexer::isAtEndOfMacroExpansion(loc, SourceMgr, Features); + } + /// DumpToken - Print the token to stderr, used for debugging. /// void DumpToken(const Token &Tok, bool DumpFlags = false) const; @@ -770,6 +791,8 @@ public: void PrintStats(); + size_t getTotalMemory() const; + /// 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. @@ -977,6 +1000,16 @@ private: /// the macro should not be expanded return true, otherwise return false. bool HandleMacroExpandedIdentifier(Token &Tok, MacroInfo *MI); + /// \brief Cache macro expanded tokens for TokenLexers. + // + /// Works like a stack; a TokenLexer adds the macro expanded tokens that is + /// going to lex in the cache and when it finishes the tokens are removed + /// from the end of the cache. + Token *cacheMacroExpandedTokens(TokenLexer *tokLexer, + llvm::ArrayRef tokens); + void removeCachedMacroExpandedTokensOfLastLexer(); + friend void TokenLexer::ExpandFunctionArguments(); + /// 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. @@ -986,7 +1019,7 @@ private: /// invoked to read all of the formal arguments specified for the macro /// invocation. This returns null on error. MacroArgs *ReadFunctionLikeMacroArgs(Token &MacroName, MacroInfo *MI, - SourceLocation &InstantiationEnd); + SourceLocation &ExpansionEnd); /// 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'. diff --git a/include/clang/Lex/Token.h b/include/clang/Lex/Token.h index edcfcc10d2ee..9cf11d9a64c4 100644 --- a/include/clang/Lex/Token.h +++ b/include/clang/Lex/Token.h @@ -63,9 +63,7 @@ class Token { /// Kind - The actual flavor of token this is. /// - unsigned char Kind; // DON'T make Kind a 'tok::TokenKind'; - // MSVC will treat it as a signed char and - // TokenKinds > 127 won't be handled correctly. + unsigned short Kind; /// Flags - Bits we track about this token, members of the TokenFlags enum. unsigned char Flags; diff --git a/include/clang/Lex/TokenLexer.h b/include/clang/Lex/TokenLexer.h index 6ae00cd58658..45ff8a03442e 100644 --- a/include/clang/Lex/TokenLexer.h +++ b/include/clang/Lex/TokenLexer.h @@ -43,10 +43,13 @@ class TokenLexer { /// Tokens - This is the pointer to an array of tokens that the macro is /// defined to, with arguments expanded for function-like macros. If this is /// a token stream, these are the tokens we are returning. This points into - /// the macro definition we are lexing from, a scratch buffer allocated from - /// the preprocessor's bump pointer allocator, or some other buffer that we - /// may or may not own (depending on OwnsTokens). + /// the macro definition we are lexing from, a cache buffer that is owned by + /// the preprocessor, or some other buffer that we may or may not own + /// (depending on OwnsTokens). + /// Note that if it points into Preprocessor's cache buffer, the Preprocessor + /// may update the pointer as needed. const Token *Tokens; + friend class Preprocessor; /// NumTokens - This is the length of the Tokens array. /// @@ -56,9 +59,20 @@ class TokenLexer { /// unsigned CurToken; - /// InstantiateLocStart/End - The source location range where this macro was - /// instantiated. - SourceLocation InstantiateLocStart, InstantiateLocEnd; + /// ExpandLocStart/End - The source location range where this macro was + /// expanded. + SourceLocation ExpandLocStart, ExpandLocEnd; + + /// \brief Source location pointing at the source location entry chunk that + /// was reserved for the current macro expansion. + SourceLocation MacroExpansionStart; + + /// \brief The offset of the macro expansion in the + /// "source location address space". + unsigned MacroStartSLocOffset; + + /// \brief FileID/offset of the start of the macro definition. + std::pair MacroDefStartInfo; /// Lexical information about the expansion point of the macro: the identifier /// that the macro expanded from had these properties. @@ -148,9 +162,14 @@ private: /// HandleMicrosoftCommentPaste - In microsoft compatibility mode, /##/ pastes /// together to form a comment that comments out everything in the current /// macro, other active macros, and anything left on the current physical - /// source line of the instantiated buffer. Handle this by returning the + /// source line of the expanded buffer. Handle this by returning the /// first token on the next line. void HandleMicrosoftCommentPaste(Token &Tok); + + /// \brief If \arg loc is a FileID and points inside the current macro + /// definition, returns the appropriate source location pointing at the + /// macro expansion source location entry. + SourceLocation getMacroExpansionLocation(SourceLocation loc) const; }; } // end namespace clang diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index e4cdc27c436a..8f49ddad2cec 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -15,6 +15,7 @@ #define LLVM_CLANG_PARSE_PARSER_H #include "clang/Basic/Specifiers.h" +#include "clang/Basic/DelayedCleanupPool.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/CodeCompletionHandler.h" #include "clang/Sema/Sema.h" @@ -170,6 +171,10 @@ class Parser : public CodeCompletionHandler { /// Factory object for creating AttributeList objects. AttributeFactory AttrFactory; + /// \brief Gathers and cleans up objects when parsing of a top-level + /// declaration is finished. + DelayedCleanupPool TopLevelDeclCleanupPool; + public: Parser(Preprocessor &PP, Sema &Actions); ~Parser(); @@ -419,25 +424,7 @@ private: Tok.setAnnotationValue(ER.get()); } - /// TryAnnotateTypeOrScopeToken - If the current token position is on a - /// typename (possibly qualified in C++) or a C++ scope specifier not followed - /// by a typename, TryAnnotateTypeOrScopeToken will replace one or more tokens - /// with a single annotation token representing the typename or C++ scope - /// respectively. - /// This simplifies handling of C++ scope specifiers and allows efficient - /// backtracking without the need to re-parse and resolve nested-names and - /// typenames. - /// It will mainly be called when we expect to treat identifiers as typenames - /// (if they are typenames). For example, in C we do not expect identifiers - /// inside expressions to be treated as typenames so it will not be called - /// for expressions in C. - /// - /// This returns true if the token was annotated. bool TryAnnotateTypeOrScopeToken(bool EnteringContext = false); - - /// TryAnnotateCXXScopeToken - Like TryAnnotateTypeOrScopeToken but - /// only annotates C++ scope specifiers. This returns true if there - /// was an unrecoverable error. bool TryAnnotateCXXScopeToken(bool EnteringContext = false); /// TryAltiVecToken - Check for context-sensitive AltiVec identifier tokens, @@ -467,7 +454,12 @@ private: bool TryAltiVecTokenOutOfLine(DeclSpec &DS, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID, bool &isInvalid); - + + /// \brief Get the TemplateIdAnnotation from the token and put it in the + /// cleanup pool so that it gets destroyed when parsing the current top level + /// declaration is finished. + TemplateIdAnnotation *takeTemplateIdAnnotation(const Token &tok); + /// TentativeParsingAction - An object that is used as a kind of "tentative /// parsing transaction". It gets instantiated to mark the token position and /// after the token consumption is done, Commit() or Revert() is called to @@ -507,12 +499,6 @@ private: }; - /// MatchRHSPunctuation - For punctuation with a LHS and RHS (e.g. '['/']'), - /// this helper function matches and consumes the specified RHS token if - /// present. If not present, it emits the specified diagnostic indicating - /// that the parser failed to match the RHS of the token at LHSLoc. LHSName - /// should be the name of the unmatched LHS token. This returns the location - /// of the consumed token. SourceLocation MatchRHSPunctuation(tok::TokenKind RHSTok, SourceLocation LHSLoc); @@ -1125,10 +1111,10 @@ private: ExprResult ParseCastExpression(bool isUnaryExpression, bool isAddressOfOperand, bool &NotCastExpr, - ParsedType TypeOfCast); + bool isTypeCast); ExprResult ParseCastExpression(bool isUnaryExpression, bool isAddressOfOperand = false, - ParsedType TypeOfCast = ParsedType()); + bool isTypeCast = false); /// Returns true if the next token would start a postfix-expression /// suffix. @@ -1169,7 +1155,7 @@ private: }; ExprResult ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, - ParsedType TypeOfCast, + bool isTypeCast, ParsedType &CastTy, SourceLocation &RParenLoc); @@ -1328,6 +1314,9 @@ private: StmtResult ParseDefaultStatement(ParsedAttributes &Attr); StmtResult ParseCompoundStatement(ParsedAttributes &Attr, bool isStmtExpr = false); + StmtResult ParseCompoundStatement(ParsedAttributes &Attr, + bool isStmtExpr, + unsigned ScopeFlags); StmtResult ParseCompoundStatementBody(bool isStmtExpr = false); bool ParseParenExprOrCondition(ExprResult &ExprResult, Decl *&DeclResult, @@ -1375,6 +1364,7 @@ bool ParseAsmOperandsOpt(llvm::SmallVectorImpl &Names, StmtResult ParseObjCTryStmt(SourceLocation atLoc); StmtResult ParseObjCThrowStmt(SourceLocation atLoc); StmtResult ParseObjCSynchronizedStmt(SourceLocation atLoc); + StmtResult ParseObjCAutoreleasePoolStmt(SourceLocation atLoc); //===--------------------------------------------------------------------===// @@ -1439,7 +1429,7 @@ bool ParseAsmOperandsOpt(llvm::SmallVectorImpl &Names, const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), bool SuppressDeclarations = false); - void ParseSpecifierQualifierList(DeclSpec &DS); + void ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS = AS_none); void ParseObjCTypeQualifierList(ObjCDeclSpec &DS, ObjCTypeNameContext Context); @@ -1616,7 +1606,10 @@ bool ParseAsmOperandsOpt(llvm::SmallVectorImpl &Names, TypeResult ParseTypeName(SourceRange *Range = 0, Declarator::TheContext Context - = Declarator::TypeNameContext); + = Declarator::TypeNameContext, + ObjCDeclSpec *objcQuals = 0, + AccessSpecifier AS = AS_none, + Decl **OwnedType = 0); void ParseBlockId(); void ProhibitAttributes(ParsedAttributesWithRange &attrs) { @@ -1742,10 +1735,15 @@ bool ParseAsmOperandsOpt(llvm::SmallVectorImpl &Names, void ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, ParsedAttributes &attrs, bool RequiresArg = false); - void ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc, - IdentifierInfo *FirstIdent, - SourceLocation FirstIdentLoc, - Declarator &D); + bool isFunctionDeclaratorIdentifierList(); + void ParseFunctionDeclaratorIdentifierList( + Declarator &D, + llvm::SmallVector &ParamInfo); + void ParseParameterDeclarationClause( + Declarator &D, + ParsedAttributes &attrs, + llvm::SmallVector &ParamInfo, + SourceLocation &EllipsisLoc); void ParseBracketDeclarator(Declarator &D); //===--------------------------------------------------------------------===// @@ -1766,7 +1764,8 @@ bool ParseAsmOperandsOpt(llvm::SmallVectorImpl &Names, Decl *ParseUsingDirectiveOrDeclaration(unsigned Context, const ParsedTemplateInfo &TemplateInfo, SourceLocation &DeclEnd, - ParsedAttributesWithRange &attrs); + ParsedAttributesWithRange &attrs, + Decl **OwnedType = 0); Decl *ParseUsingDirective(unsigned Context, SourceLocation UsingLoc, SourceLocation &DeclEnd, @@ -1775,7 +1774,8 @@ bool ParseAsmOperandsOpt(llvm::SmallVectorImpl &Names, const ParsedTemplateInfo &TemplateInfo, SourceLocation UsingLoc, SourceLocation &DeclEnd, - AccessSpecifier AS = AS_none); + AccessSpecifier AS = AS_none, + Decl **OwnedType = 0); Decl *ParseStaticAssertDeclaration(SourceLocation &DeclEnd); Decl *ParseNamespaceAlias(SourceLocation NamespaceLoc, SourceLocation AliasLoc, IdentifierInfo *Alias, diff --git a/include/clang/Rewrite/FixItRewriter.h b/include/clang/Rewrite/FixItRewriter.h index 26a0d72baa2a..bab99624ba4a 100644 --- a/include/clang/Rewrite/FixItRewriter.h +++ b/include/clang/Rewrite/FixItRewriter.h @@ -18,7 +18,6 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Basic/SourceLocation.h" #include "clang/Rewrite/Rewriter.h" -#include "llvm/ADT/SmallVector.h" namespace llvm { class raw_ostream; } diff --git a/include/clang/Rewrite/Rewriter.h b/include/clang/Rewrite/Rewriter.h index 7861e9992891..676744ada36c 100644 --- a/include/clang/Rewrite/Rewriter.h +++ b/include/clang/Rewrite/Rewriter.h @@ -183,8 +183,11 @@ public: /// 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. + /// + /// \param indentNewLines if true new lines in the string are indented + /// using the indentation of the source line in position \arg Loc. bool InsertText(SourceLocation Loc, llvm::StringRef Str, - bool InsertAfter = true); + bool InsertAfter = true, bool indentNewLines = false); /// InsertTextAfter - Insert the specified string at the specified location in /// the original buffer. This method returns true (and does nothing) if diff --git a/include/clang/Sema/AnalysisBasedWarnings.h b/include/clang/Sema/AnalysisBasedWarnings.h index 8b389b169b3c..8e781cd521c2 100644 --- a/include/clang/Sema/AnalysisBasedWarnings.h +++ b/include/clang/Sema/AnalysisBasedWarnings.h @@ -14,7 +14,6 @@ #ifndef LLVM_CLANG_SEMA_ANALYSIS_WARNINGS_H #define LLVM_CLANG_SEMA_ANALYSIS_WARNINGS_H -#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/DenseMap.h" namespace clang { @@ -50,6 +49,41 @@ private: enum VisitFlag { NotVisited = 0, Visited = 1, Pending = 2 }; llvm::DenseMap VisitedFD; + /// \name Statistics + /// @{ + + /// \brief Number of function CFGs built and analyzed. + unsigned NumFunctionsAnalyzed; + + /// \brief Number of functions for which the CFG could not be successfully + /// built. + unsigned NumFunctionsWithBadCFGs; + + /// \brief Total number of blocks across all CFGs. + unsigned NumCFGBlocks; + + /// \brief Largest number of CFG blocks for a single function analyzed. + unsigned MaxCFGBlocksPerFunction; + + /// \brief Total number of CFGs with variables analyzed for uninitialized + /// uses. + unsigned NumUninitAnalysisFunctions; + + /// \brief Total number of variables analyzed for uninitialized uses. + unsigned NumUninitAnalysisVariables; + + /// \brief Max number of variables analyzed for uninitialized uses in a single + /// function. + unsigned MaxUninitAnalysisVariablesPerFunction; + + /// \brief Total number of block visits during uninitialized use analysis. + unsigned NumUninitAnalysisBlockVisits; + + /// \brief Max number of block visits during uninitialized use analysis of + /// a single function. + unsigned MaxUninitAnalysisBlockVisitsPerFunction; + + /// @} public: AnalysisBasedWarnings(Sema &s); @@ -58,6 +92,8 @@ public: const Decl *D, const BlockExpr *blkExpr); Policy getDefaultPolicy() { return DefaultPolicy; } + + void PrintStats() const; }; }} // end namespace clang::sema diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h index 72cd47589f91..5d2d6c2ec691 100644 --- a/include/clang/Sema/AttributeList.h +++ b/include/clang/Sema/AttributeList.h @@ -77,6 +77,8 @@ private: /// availability attribute. unsigned IsAvailability : 1; + unsigned AttrKind : 8; + /// \brief The location of the 'unavailable' keyword in an /// availability attribute. SourceLocation UnavailableLoc; @@ -123,6 +125,7 @@ private: DeclspecAttribute(declspec), CXX0XAttribute(cxx0x), Invalid(false), IsAvailability(false), NextInPosition(0), NextInPool(0) { if (numArgs) memcpy(getArgsBuffer(), args, numArgs * sizeof(Expr*)); + AttrKind = getKind(getName()); } AttributeList(IdentifierInfo *attrName, SourceLocation attrLoc, @@ -141,6 +144,7 @@ private: new (&getAvailabilitySlot(IntroducedSlot)) AvailabilityChange(introduced); new (&getAvailabilitySlot(DeprecatedSlot)) AvailabilityChange(deprecated); new (&getAvailabilitySlot(ObsoletedSlot)) AvailabilityChange(obsoleted); + AttrKind = getKind(getName()); } friend class AttributePool; @@ -148,20 +152,22 @@ private: public: enum Kind { // Please keep this list alphabetized. - AT_IBAction, // Clang-specific. - AT_IBOutlet, // Clang-specific. - AT_IBOutletCollection, // Clang-specific. AT_address_space, AT_alias, AT_aligned, AT_always_inline, AT_analyzer_noreturn, AT_annotate, + AT_arc_weakref_unavailable, AT_availability, // Clang-specific AT_base_check, AT_blocks, AT_carries_dependency, AT_cdecl, + AT_cf_consumed, // Clang-specific. + AT_cf_returns_autoreleased, // Clang-specific. + AT_cf_returns_not_retained, // Clang-specific. + AT_cf_returns_retained, // Clang-specific. AT_cleanup, AT_common, AT_const, @@ -179,32 +185,36 @@ public: AT_global, AT_gnu_inline, AT_host, + AT_IBAction, // Clang-specific. + AT_IBOutlet, // Clang-specific. + AT_IBOutletCollection, // Clang-specific. + AT_init_priority, AT_launch_bounds, AT_malloc, AT_may_alias, AT_mode, + AT_MsStruct, + AT_naked, AT_neon_polyvector_type, // Clang-specific. AT_neon_vector_type, // Clang-specific. - AT_naked, - AT_nodebug, - AT_noinline, AT_no_instrument_function, AT_nocommon, + AT_nodebug, + AT_noinline, AT_nonnull, AT_noreturn, AT_nothrow, - AT_nsobject, - AT_objc_exception, - AT_objc_method_family, - AT_cf_returns_not_retained, // Clang-specific. - AT_cf_returns_retained, // Clang-specific. - AT_ns_returns_not_retained, // Clang-specific. - AT_ns_returns_retained, // Clang-specific. - AT_ns_returns_autoreleased, // Clang-specific. - AT_cf_consumed, // Clang-specific. AT_ns_consumed, // Clang-specific. AT_ns_consumes_self, // Clang-specific. + AT_ns_returns_autoreleased, // Clang-specific. + AT_ns_returns_not_retained, // Clang-specific. + AT_ns_returns_retained, // Clang-specific. + AT_nsobject, + AT_objc_exception, AT_objc_gc, + AT_objc_method_family, + AT_objc_ownership, // Clang-specific. + AT_objc_precise_lifetime, // Clang-specific. AT_opencl_image_access, // OpenCL-specific. AT_opencl_kernel_function, // OpenCL-specific. AT_overloadable, // Clang-specific. @@ -216,6 +226,7 @@ public: AT_pcs, // ARM specific AT_pure, AT_regparm, + AT_reqd_wg_size, AT_section, AT_sentinel, AT_shared, @@ -231,11 +242,8 @@ public: AT_visibility, AT_warn_unused_result, AT_weak, - AT_weakref, AT_weak_import, - AT_reqd_wg_size, - AT_init_priority, - AT_MsStruct, + AT_weakref, IgnoredAttribute, UnknownAttribute }; @@ -256,7 +264,7 @@ public: bool isInvalid() const { return Invalid; } void setInvalid(bool b = true) const { Invalid = b; } - Kind getKind() const { return getKind(getName()); } + Kind getKind() const { return Kind(AttrKind); } static Kind getKind(const IdentifierInfo *Name); AttributeList *getNext() const { return NextInPosition; } diff --git a/include/clang/Sema/CodeCompleteConsumer.h b/include/clang/Sema/CodeCompleteConsumer.h index d3221809b981..74b0105b3310 100644 --- a/include/clang/Sema/CodeCompleteConsumer.h +++ b/include/clang/Sema/CodeCompleteConsumer.h @@ -185,12 +185,26 @@ public: /// is expected. CCC_ObjCMessageReceiver, /// \brief Code completion occurred on the right-hand side of a member - /// access expression. + /// access expression using the dot operator. /// /// The results of this completion are the members of the type being /// accessed. The type itself is available via /// \c CodeCompletionContext::getType(). - CCC_MemberAccess, + CCC_DotMemberAccess, + /// \brief Code completion occurred on the right-hand side of a member + /// access expression using the arrow operator. + /// + /// The results of this completion are the members of the type being + /// accessed. The type itself is available via + /// \c CodeCompletionContext::getType(). + CCC_ArrowMemberAccess, + /// \brief Code completion occurred on the right-hand side of an Objective-C + /// property access expression. + /// + /// The results of this completion are the members of the type being + /// accessed. The type itself is available via + /// \c CodeCompletionContext::getType(). + CCC_ObjCPropertyAccess, /// \brief Code completion occurred after the "enum" keyword, to indicate /// an enumeration name. CCC_EnumTag, @@ -235,6 +249,15 @@ public: /// \brief Code completion in a parenthesized expression, which means that /// we may also have types here in C and Objective-C (as well as in C++). CCC_ParenthesizedExpression, + /// \brief Code completion where an Objective-C instance message is expcted. + CCC_ObjCInstanceMessage, + /// \brief Code completion where an Objective-C class message is expected. + CCC_ObjCClassMessage, + /// \brief Code completion where a superclass of an Objective-C class is + /// expected. + CCC_ObjCSuperclass, + /// \brief Code completion where an Objective-C category name is expected. + CCC_ObjCCategoryName, /// \brief An unknown context, in which we are recovering from a parsing /// error and don't know which completions we should give. CCC_Recovery @@ -256,7 +279,8 @@ public: /// \brief Construct a new code-completion context of the given kind. CodeCompletionContext(enum Kind Kind, QualType T) : Kind(Kind) { - if (Kind == CCC_MemberAccess) + if (Kind == CCC_DotMemberAccess || Kind == CCC_ArrowMemberAccess || + Kind == CCC_ObjCPropertyAccess) BaseType = T; else PreferredType = T; diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h index 7ce4e009432c..a66649955c8c 100644 --- a/include/clang/Sema/DeclSpec.h +++ b/include/clang/Sema/DeclSpec.h @@ -40,6 +40,7 @@ namespace clang { class NamespaceDecl; class NestedNameSpecifier; class NestedNameSpecifierLoc; + class ObjCDeclSpec; class Preprocessor; class Declarator; struct TemplateIdAnnotation; @@ -153,6 +154,12 @@ public: /// copied. NestedNameSpecifierLoc getWithLocInContext(ASTContext &Context) const; + /// \brief Retrieve the location of the name in the last qualifier + /// in this nested name specifier. For example: + /// ::foo::bar<0>:: + /// ^~~ + SourceLocation getLastQualifierNameLoc() const; + /// No scope specifier. bool isEmpty() const { return !Range.isValid(); } /// A scope specifier is present, but may be valid or invalid. @@ -344,6 +351,8 @@ private: void SaveWrittenBuiltinSpecs(); void SaveStorageSpecifierAsWritten(); + ObjCDeclSpec *ObjCQualifiers; + static bool isTypeRep(TST T) { return (T == TST_typename || T == TST_typeofType || T == TST_underlyingType); @@ -383,7 +392,8 @@ public: ProtocolQualifiers(0), NumProtocolQualifiers(0), ProtocolLocs(0), - writtenBS() { + writtenBS(), + ObjCQualifiers(0) { } ~DeclSpec() { delete [] ProtocolQualifiers; @@ -653,6 +663,9 @@ public: return writtenBS; } + ObjCDeclSpec *getObjCQualifiers() const { return ObjCQualifiers; } + void setObjCQualifiers(ObjCDeclSpec *quals) { ObjCQualifiers = quals; } + /// isMissingDeclaratorOk - This checks if this DeclSpec can stand alone, /// without a Declarator. Only tag declspecs can stand alone. bool isMissingDeclaratorOk(); @@ -689,7 +702,10 @@ public: DQ_PR_copy = 0x20, DQ_PR_nonatomic = 0x40, DQ_PR_setter = 0x80, - DQ_PR_atomic = 0x100 + DQ_PR_atomic = 0x100, + DQ_PR_weak = 0x200, + DQ_PR_strong = 0x400, + DQ_PR_unsafe_unretained = 0x800 }; @@ -723,7 +739,7 @@ private: ObjCDeclQualifier objcDeclQualifier : 6; // NOTE: VC++ treats enums as signed, avoid using ObjCPropertyAttributeKind - unsigned PropertyAttributes : 9; + unsigned PropertyAttributes : 12; IdentifierInfo *GetterName; // getter name of NULL if no getter IdentifierInfo *SetterName; // setter name of NULL if no setter }; @@ -751,7 +767,9 @@ public: /// \brief A destructor name. IK_DestructorName, /// \brief A template-id, e.g., f. - IK_TemplateId + IK_TemplateId, + /// \brief An implicit 'self' parameter + IK_ImplicitSelfParam } Kind; /// \brief Anonymous union that holds extra data associated with the @@ -804,7 +822,7 @@ public: SourceLocation EndLocation; UnqualifiedId() : Kind(IK_Identifier), Identifier(0) { } - + /// \brief Do not use this copy constructor. It is temporary, and only /// exists because we are holding FieldDeclarators in a SmallVector when we /// don't actually need them. @@ -831,6 +849,7 @@ public: /// \brief Determine what kind of name we have. IdKind getKind() const { return Kind; } + void setKind(IdKind kind) { Kind = kind; } /// \brief Specify that this unqualified-id was parsed as an identifier. /// @@ -1078,6 +1097,10 @@ struct DeclaratorChunk { /// If this is an invalid location, there is no ref-qualifier. unsigned RefQualifierLoc; + /// \brief The location of the 'mutable' qualifer in a lambda-declarator, if + /// any. + unsigned MutableLoc; + /// \brief When ExceptionSpecType isn't EST_None or EST_Delayed, the /// location of the keyword introducing the spec. unsigned ExceptionSpecLoc; @@ -1139,10 +1162,19 @@ struct DeclaratorChunk { return SourceLocation::getFromRawEncoding(RefQualifierLoc); } + /// \brief Retrieve the location of the 'mutable' qualifier, if any. + SourceLocation getMutableLoc() const { + return SourceLocation::getFromRawEncoding(MutableLoc); + } + /// \brief Determine whether this function declaration contains a /// ref-qualifier. bool hasRefQualifier() const { return getRefQualifierLoc().isValid(); } + /// \brief Determine whether this lambda-declarator contains a 'mutable' + /// qualifier. + bool hasMutableQualifier() const { return getMutableLoc().isValid(); } + /// \brief Get the type of exception specification this function has. ExceptionSpecificationType getExceptionSpecType() const { return static_cast(ExceptionSpecType); @@ -1266,6 +1298,7 @@ struct DeclaratorChunk { unsigned TypeQuals, bool RefQualifierIsLvalueRef, SourceLocation RefQualifierLoc, + SourceLocation MutableLoc, ExceptionSpecificationType ESpecType, SourceLocation ESpecLoc, ParsedType *Exceptions, @@ -1339,7 +1372,9 @@ public: ForContext, // Declaration within first part of a for loop. ConditionContext, // Condition declaration in a C++ if/switch/while/for. TemplateParamContext,// Within a template parameter list. + CXXNewContext, // C++ new-expression. CXXCatchContext, // C++ catch exception-declaration + ObjCCatchContext, // Objective-C catch exception-declaration BlockLiteralContext, // Block literal declarator. TemplateTypeArgContext, // Template type argument. AliasDeclContext, // C++0x alias-declaration. @@ -1489,7 +1524,9 @@ public: case PrototypeContext: case ObjCPrototypeContext: case TemplateParamContext: + case CXXNewContext: case CXXCatchContext: + case ObjCCatchContext: case BlockLiteralContext: case TemplateTypeArgContext: return true; @@ -1511,9 +1548,11 @@ public: case PrototypeContext: case TemplateParamContext: case CXXCatchContext: + case ObjCCatchContext: return true; case TypeNameContext: + case CXXNewContext: case AliasDeclContext: case AliasTemplateContext: case ObjCPrototypeContext: @@ -1542,7 +1581,9 @@ public: case ObjCPrototypeContext: case TemplateParamContext: case CXXCatchContext: + case ObjCCatchContext: case TypeNameContext: + case CXXNewContext: case AliasDeclContext: case AliasTemplateContext: case BlockLiteralContext: @@ -1687,6 +1728,14 @@ public: return const_cast(this)->getFunctionTypeInfo(); } + /// \brief Determine whether the declaration that will be produced from + /// this declaration will be a function. + /// + /// A declaration can declare a function even if the declarator itself + /// isn't a function declarator, if the type specifier refers to a function + /// type. This routine checks for both cases. + bool isDeclarationOfFunction() const; + /// takeAttributes - Takes attributes from the given parsed-attributes /// set and add them to this declarator. /// diff --git a/include/clang/Sema/DelayedDiagnostic.h b/include/clang/Sema/DelayedDiagnostic.h index 8395138ab612..8ab938226482 100644 --- a/include/clang/Sema/DelayedDiagnostic.h +++ b/include/clang/Sema/DelayedDiagnostic.h @@ -112,7 +112,7 @@ private: /// the complete parsing of the current declaration. class DelayedDiagnostic { public: - enum DDKind { Deprecation, Access }; + enum DDKind { Deprecation, Access, ForbiddenType }; unsigned char Kind; // actually a DDKind bool Triggered; @@ -135,6 +135,20 @@ public: return DD; } + static DelayedDiagnostic makeForbiddenType(SourceLocation loc, + unsigned diagnostic, + QualType type, + unsigned argument) { + DelayedDiagnostic DD; + DD.Kind = ForbiddenType; + DD.Triggered = false; + DD.Loc = loc; + DD.ForbiddenTypeData.Diagnostic = diagnostic; + DD.ForbiddenTypeData.OperandType = type.getAsOpaquePtr(); + DD.ForbiddenTypeData.Argument = argument; + return DD; + } + AccessedEntity &getAccessData() { assert(Kind == Access && "Not an access diagnostic."); return *reinterpret_cast(AccessData); @@ -155,6 +169,25 @@ public: DeprecationData.MessageLen); } + /// The diagnostic ID to emit. Used like so: + /// Diag(diag.Loc, diag.getForbiddenTypeDiagnostic()) + /// << diag.getForbiddenTypeOperand() + /// << diag.getForbiddenTypeArgument(); + unsigned getForbiddenTypeDiagnostic() const { + assert(Kind == ForbiddenType && "not a forbidden-type diagnostic"); + return ForbiddenTypeData.Diagnostic; + } + + unsigned getForbiddenTypeArgument() const { + assert(Kind == ForbiddenType && "not a forbidden-type diagnostic"); + return ForbiddenTypeData.Argument; + } + + QualType getForbiddenTypeOperand() const { + assert(Kind == ForbiddenType && "not a forbidden-type diagnostic"); + return QualType::getFromOpaquePtr(ForbiddenTypeData.OperandType); + } + private: union { /// Deprecation. @@ -164,6 +197,12 @@ private: size_t MessageLen; } DeprecationData; + struct { + unsigned Diagnostic; + unsigned Argument; + void *OperandType; + } ForbiddenTypeData; + /// Access control. char AccessData[sizeof(AccessedEntity)]; }; diff --git a/include/clang/Sema/ExternalSemaSource.h b/include/clang/Sema/ExternalSemaSource.h index e2b083e83047..072e1b58d138 100644 --- a/include/clang/Sema/ExternalSemaSource.h +++ b/include/clang/Sema/ExternalSemaSource.h @@ -49,6 +49,11 @@ public: /// instance and factory methods, respectively, with this selector. virtual std::pair ReadMethodPool(Selector Sel); + /// \brief Load the set of namespaces that are known to the external source, + /// which will be used during typo correction. + virtual void ReadKnownNamespaces( + llvm::SmallVectorImpl &Namespaces); + /// \brief Do last resort, unqualified lookup on a LookupResult that /// Sema cannot find. /// diff --git a/include/clang/Sema/Initialization.h b/include/clang/Sema/Initialization.h index 5dc4438671bb..df6138c7f039 100644 --- a/include/clang/Sema/Initialization.h +++ b/include/clang/Sema/Initialization.h @@ -86,9 +86,13 @@ private: QualType Type; union { - /// \brief When Kind == EK_Variable, EK_Parameter, or EK_Member, - /// the VarDecl, ParmVarDecl, or FieldDecl, respectively. + /// \brief When Kind == EK_Variable or EK_Member, the VarDecl or + /// FieldDecl, respectively. DeclaratorDecl *VariableOrMember; + + /// \brief When Kind == EK_Parameter, the ParmVarDecl, with the + /// low bit indicating whether the parameter is "consumed". + uintptr_t Parameter; /// \brief When Kind == EK_Temporary, the type source information for /// the temporary. @@ -123,11 +127,6 @@ private: : Kind(EK_Variable), Parent(0), Type(Var->getType()), VariableOrMember(Var) { } - /// \brief Create the initialization entity for a parameter. - InitializedEntity(ParmVarDecl *Parm) - : Kind(EK_Parameter), Parent(0), Type(Parm->getType().getUnqualifiedType()), - VariableOrMember(Parm) { } - /// \brief Create the initialization entity for the result of a /// function, throwing an object, performing an explicit cast, or /// initializing a parameter for which there is no declaration. @@ -157,20 +156,29 @@ public: /// \brief Create the initialization entity for a parameter. static InitializedEntity InitializeParameter(ASTContext &Context, ParmVarDecl *Parm) { - InitializedEntity Res(Parm); - Res.Type = Context.getVariableArrayDecayedType(Res.Type); - return Res; + bool Consumed = (Context.getLangOptions().ObjCAutoRefCount && + Parm->hasAttr()); + + InitializedEntity Entity; + Entity.Kind = EK_Parameter; + Entity.Type = Context.getVariableArrayDecayedType( + Parm->getType().getUnqualifiedType()); + Entity.Parent = 0; + Entity.Parameter + = (static_cast(Consumed) | reinterpret_cast(Parm)); + return Entity; } /// \brief Create the initialization entity for a parameter that is /// only known by its type. static InitializedEntity InitializeParameter(ASTContext &Context, - QualType Type) { + QualType Type, + bool Consumed) { InitializedEntity Entity; Entity.Kind = EK_Parameter; Entity.Type = Context.getVariableArrayDecayedType(Type); Entity.Parent = 0; - Entity.VariableOrMember = 0; + Entity.Parameter = (Consumed); return Entity; } @@ -268,6 +276,13 @@ public: /// \brief Determine whether this initialization allows the named return /// value optimization, which also applies to thrown objects. bool allowsNRVO() const; + + /// \brief Determine whether this initialization consumes the + /// parameter. + bool isParameterConsumed() const { + assert(getKind() == EK_Parameter && "Not a parameter"); + return (Parameter & 1); + } /// \brief Retrieve the base specifier. CXXBaseSpecifier *getBaseSpecifier() const { @@ -287,7 +302,7 @@ public: assert(getKind() == EK_Result && "No 'return' location!"); return SourceLocation::getFromRawEncoding(LocAndNRVO.Location); } - + /// \brief Determine the location of the 'throw' keyword when initializing /// an exception object. SourceLocation getThrowLoc() const { @@ -325,8 +340,10 @@ private: SIK_Value = IK_Value, ///< Value initialization SIK_ImplicitValue, ///< Implicit value initialization SIK_DirectCast, ///< Direct initialization due to a cast - /// \brief Direct initialization due to a C-style or functional cast. - SIK_DirectCStyleOrFunctionalCast + /// \brief Direct initialization due to a C-style cast. + SIK_DirectCStyleCast, + /// \brief Direct initialization due to a functional-style cast. + SIK_DirectFunctionalCast }; /// \brief The kind of initialization being performed. @@ -352,15 +369,29 @@ public: return InitializationKind(SIK_Direct, InitLoc, LParenLoc, RParenLoc); } - /// \brief Create a direct initialization due to a cast. - static InitializationKind CreateCast(SourceRange TypeRange, - bool IsCStyleCast) { - return InitializationKind(IsCStyleCast? SIK_DirectCStyleOrFunctionalCast - : SIK_DirectCast, + /// \brief Create a direct initialization due to a cast that isn't a C-style + /// or functional cast. + static InitializationKind CreateCast(SourceRange TypeRange) { + return InitializationKind(SIK_DirectCast, TypeRange.getBegin(), TypeRange.getBegin(), TypeRange.getEnd()); } + /// \brief Create a direct initialization for a C-style cast. + static InitializationKind CreateCStyleCast(SourceLocation StartLoc, + SourceRange TypeRange) { + return InitializationKind(SIK_DirectCStyleCast, + StartLoc, TypeRange.getBegin(), + TypeRange.getEnd()); + } + + /// \brief Create a direct initialization for a functional cast. + static InitializationKind CreateFunctionalCast(SourceRange TypeRange) { + return InitializationKind(SIK_DirectFunctionalCast, + TypeRange.getBegin(), TypeRange.getBegin(), + TypeRange.getEnd()); + } + /// \brief Create a copy initialization. static InitializationKind CreateCopy(SourceLocation InitLoc, SourceLocation EqualLoc) { @@ -393,12 +424,24 @@ public: /// \brief Determine whether this initialization is an explicit cast. bool isExplicitCast() const { - return Kind == SIK_DirectCast || Kind == SIK_DirectCStyleOrFunctionalCast; + return Kind == SIK_DirectCast || + Kind == SIK_DirectCStyleCast || + Kind == SIK_DirectFunctionalCast; } /// \brief Determine whether this initialization is a C-style cast. bool isCStyleOrFunctionalCast() const { - return Kind == SIK_DirectCStyleOrFunctionalCast; + return Kind == SIK_DirectCStyleCast || Kind == SIK_DirectFunctionalCast; + } + + /// brief Determine whether this is a C-style cast. + bool isCStyleCast() const { + return Kind == SIK_DirectCStyleCast; + } + + /// brief Determine whether this is a functional-style cast. + bool isFunctionalCast() const { + return Kind == SIK_DirectFunctionalCast; } /// \brief Determine whether this initialization is an implicit @@ -448,10 +491,7 @@ public: DependentSequence, /// \brief A normal sequence. - NormalSequence, - - /// \brief A reference binding. - ReferenceBinding // FIXME: Still looks redundant, but complicated. + NormalSequence }; /// \brief Describes the kind of a particular step in an initialization @@ -500,7 +540,13 @@ public: SK_ObjCObjectConversion, /// \brief Array initialization (from an array rvalue). /// This is a GNU C extension. - SK_ArrayInit + SK_ArrayInit, + /// \brief Pass an object by indirect copy-and-restore. + SK_PassByIndirectCopyRestore, + /// \brief Pass an object by indirect restore. + SK_PassByIndirectRestore, + /// \brief Produce an Objective-C object pointer. + SK_ProduceObjCObject }; /// \brief A single step in the initialization sequence. @@ -774,6 +820,13 @@ public: /// \brief Add an array initialization step. void AddArrayInitStep(QualType T); + /// \brief Add a step to pass an object by indirect copy-restore. + void AddPassByIndirectCopyRestoreStep(QualType T, bool shouldCopy); + + /// \brief Add a step to "produce" an Objective-C object (by + /// retaining it). + void AddProduceObjCObjectStep(QualType T); + /// \brief Note that this initialization sequence failed. void SetFailed(FailureKind Failure) { SequenceKind = FailedSequence; diff --git a/include/clang/Sema/LocInfoType.h b/include/clang/Sema/LocInfoType.h new file mode 100644 index 000000000000..e1d3ae905170 --- /dev/null +++ b/include/clang/Sema/LocInfoType.h @@ -0,0 +1,63 @@ +//===--- LocInfoType.h - Parsed Type with Location 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 defines the LocInfoType class, which holds a type and its +// source-location information. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_SEMA_LOCINFOTYPE_H +#define LLVM_CLANG_SEMA_LOCINFOTYPE_H + +#include "clang/AST/Type.h" + +namespace clang { + +class TypeSourceInfo; + +/// \brief Holds a QualType and a TypeSourceInfo* that came out of a declarator +/// parsing. +/// +/// LocInfoType is a "transient" type, only needed for passing to/from Parser +/// and Sema, when we want to preserve type source info for a parsed type. +/// It will not participate in the type system semantics in any way. +class LocInfoType : public Type { + enum { + // The last number that can fit in Type's TC. + // Avoids conflict with an existing Type class. + LocInfo = Type::TypeLast + 1 + }; + + TypeSourceInfo *DeclInfo; + + LocInfoType(QualType ty, TypeSourceInfo *TInfo) + : Type((TypeClass)LocInfo, ty, ty->isDependentType(), + ty->isInstantiationDependentType(), + ty->isVariablyModifiedType(), + ty->containsUnexpandedParameterPack()), + DeclInfo(TInfo) { + assert(getTypeClass() == (TypeClass)LocInfo && "LocInfo didn't fit in TC?"); + } + friend class Sema; + + public: + QualType getType() const { return getCanonicalTypeInternal(); } + TypeSourceInfo *getTypeSourceInfo() const { return DeclInfo; } + + void getAsStringInternal(std::string &Str, + const PrintingPolicy &Policy) const; + + static bool classof(const Type *T) { + return T->getTypeClass() == (TypeClass)LocInfo; + } + static bool classof(const LocInfoType *) { return true; } +}; + +} // end namespace clang + +#endif // LLVM_CLANG_SEMA_LOCINFOTYPE_H diff --git a/include/clang/Sema/Overload.h b/include/clang/Sema/Overload.h index 55931f2318f6..32d4cbdac15e 100644 --- a/include/clang/Sema/Overload.h +++ b/include/clang/Sema/Overload.h @@ -77,6 +77,7 @@ namespace clang { ICK_Complex_Real, ///< Complex-real conversions (C99 6.3.1.7) ICK_Block_Pointer_Conversion, ///< Block Pointer conversions ICK_TransparentUnionConversion, /// Transparent Union Conversions + ICK_Writeback_Conversion, ///< Objective-C ARC writeback conversion ICK_Num_Conversion_Kinds ///< The number of conversion kinds }; @@ -100,10 +101,11 @@ namespace clang { /// 13.3.3.1.1) and are listed such that better conversion ranks /// have smaller values. enum ImplicitConversionRank { - ICR_Exact_Match = 0, ///< Exact Match - ICR_Promotion, ///< Promotion - ICR_Conversion, ///< Conversion - ICR_Complex_Real_Conversion ///< Complex <-> Real conversion + ICR_Exact_Match = 0, ///< Exact Match + ICR_Promotion, ///< Promotion + ICR_Conversion, ///< Conversion + ICR_Complex_Real_Conversion, ///< Complex <-> Real conversion + ICR_Writeback_Conversion ///< ObjC ARC writeback conversion }; ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind); @@ -137,6 +139,10 @@ namespace clang { /// (C++ 4.2p2). unsigned DeprecatedStringLiteralToCharPtr : 1; + /// \brief Whether the qualification conversion involves a change in the + /// Objective-C lifetime (for automatic reference counting). + unsigned QualificationIncludesObjCLifetime : 1; + /// IncompatibleObjC - Whether this is an Objective-C conversion /// that we should warn about (if we actually use it). unsigned IncompatibleObjC : 1; @@ -163,6 +169,10 @@ namespace clang { /// non-static member function without a ref-qualifier. unsigned BindsImplicitObjectArgumentWithoutRefQualifier : 1; + /// \brief Whether this binds a reference to an object with a different + /// Objective-C lifetime qualifier. + unsigned ObjCLifetimeConversionBinding : 1; + /// FromType - The type that this conversion is converting /// from. This is an opaque pointer that can be translated into a /// QualType. diff --git a/include/clang/Sema/Scope.h b/include/clang/Sema/Scope.h index 7514633c0ef8..95d29781e704 100644 --- a/include/clang/Sema/Scope.h +++ b/include/clang/Sema/Scope.h @@ -84,7 +84,10 @@ public: /// ThisScope - This is the scope of a struct/union/class definition, /// outside of any member function definition, where 'this' is nonetheless /// usable. - ThisScope = 0x1000 + ThisScope = 0x1000, + + /// TryScope - This is the scope of a C++ try statement. + TryScope = 0x2000 }; private: /// The parent scope for this scope. This is null for the translation-unit @@ -303,6 +306,9 @@ public: } return false; } + + /// \brief Determine whether this scope is a C++ 'try' block. + bool isTryScope() const { return getFlags() & Scope::TryScope; } typedef UsingDirectivesTy::iterator udir_iterator; typedef UsingDirectivesTy::const_iterator const_udir_iterator; diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 6dd0d3ceab4c..263c1bd49ac9 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -20,6 +20,8 @@ #include "clang/Sema/IdentifierResolver.h" #include "clang/Sema/ObjCMethodList.h" #include "clang/Sema/DeclSpec.h" +#include "clang/Sema/LocInfoType.h" +#include "clang/Sema/TypoCorrection.h" #include "clang/AST/Expr.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/ExternalASTSource.h" @@ -45,6 +47,8 @@ namespace clang { class ASTConsumer; class ASTContext; class ASTMutationListener; + class ASTReader; + class ASTWriter; class ArrayType; class AttributeList; class BlockDecl; @@ -108,6 +112,7 @@ namespace clang { class ObjCInterfaceDecl; class ObjCIvarDecl; template class ObjCList; + class ObjCMessageExpr; class ObjCMethodDecl; class ObjCPropertyDecl; class ObjCProtocolDecl; @@ -156,43 +161,6 @@ namespace sema { class TemplateDeductionInfo; } -/// \brief Holds a QualType and a TypeSourceInfo* that came out of a declarator -/// parsing. -/// -/// LocInfoType is a "transient" type, only needed for passing to/from Parser -/// and Sema, when we want to preserve type source info for a parsed type. -/// It will not participate in the type system semantics in any way. -class LocInfoType : public Type { - enum { - // The last number that can fit in Type's TC. - // Avoids conflict with an existing Type class. - LocInfo = Type::TypeLast + 1 - }; - - TypeSourceInfo *DeclInfo; - - LocInfoType(QualType ty, TypeSourceInfo *TInfo) - : Type((TypeClass)LocInfo, ty, ty->isDependentType(), - ty->isVariablyModifiedType(), - ty->containsUnexpandedParameterPack()), - DeclInfo(TInfo) { - assert(getTypeClass() == (TypeClass)LocInfo && "LocInfo didn't fit in TC?"); - } - friend class Sema; - -public: - QualType getType() const { return getCanonicalTypeInternal(); } - TypeSourceInfo *getTypeSourceInfo() const { return DeclInfo; } - - void getAsStringInternal(std::string &Str, - const PrintingPolicy &Policy) const; - - static bool classof(const Type *T) { - return T->getTypeClass() == (TypeClass)LocInfo; - } - static bool classof(const LocInfoType *) { return true; } -}; - // FIXME: No way to easily map from TemplateTypeParmTypes to // TemplateTypeParmDecls, so we have this horrible PointerUnion. typedef std::pair, @@ -225,6 +193,9 @@ public: Diagnostic &Diags; SourceManager &SourceMgr; + /// \brief Flag indicating whether or not to collect detailed statistics. + bool CollectStats; + /// \brief Source of additional semantic information. ExternalSemaSource *ExternalSource; @@ -247,6 +218,10 @@ public: /// VisContext - Manages the stack for #pragma GCC visibility. void *VisContext; // Really a "PragmaVisStack*" + /// ExprNeedsCleanups - True if the current evaluation context + /// requires cleanups to be run at its conclusion. + bool ExprNeedsCleanups; + /// \brief Stack containing information about each of the nested /// function, block, and method scopes that are currently active. /// @@ -555,6 +530,9 @@ public: /// \brief The expression evaluation context. ExpressionEvaluationContext Context; + /// \brief Whether the enclosing context needed a cleanup. + bool ParentNeedsCleanups; + /// \brief The number of temporaries that were active when we /// entered this expression evaluation context. unsigned NumTemporaries; @@ -573,8 +551,10 @@ public: PotentiallyEmittedDiagnostics *PotentiallyDiagnosed; ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context, - unsigned NumTemporaries) - : Context(Context), NumTemporaries(NumTemporaries), + unsigned NumTemporaries, + bool ParentNeedsCleanups) + : Context(Context), ParentNeedsCleanups(ParentNeedsCleanups), + NumTemporaries(NumTemporaries), PotentiallyReferenced(0), PotentiallyDiagnosed(0) { } void addReferencedDecl(SourceLocation Loc, Decl *Decl) { @@ -712,7 +692,9 @@ public: ASTContext &getASTContext() const { return Context; } ASTConsumer &getASTConsumer() const { return Consumer; } ASTMutationListener *getASTMutationListener() const; - + + void PrintStats() const; + /// \brief Helper class that creates diagnostics with optional /// template instantiation stacks. /// @@ -766,7 +748,7 @@ public: return FunctionScopes.back(); } - bool hasAnyErrorsInThisFunction() const; + bool hasAnyUnrecoverableErrorsInThisFunction() const; /// \brief Retrieve the current block, if any. sema::BlockScopeInfo *getCurBlock(); @@ -778,7 +760,6 @@ public: // Type Analysis / Processing: SemaType.cpp. // - QualType adjustParameterType(QualType T); QualType BuildQualifiedType(QualType T, SourceLocation Loc, Qualifiers Qs); QualType BuildQualifiedType(QualType T, SourceLocation Loc, unsigned CVR) { return BuildQualifiedType(T, Loc, Qualifiers::fromCVRMask(CVR)); @@ -805,9 +786,8 @@ public: SourceLocation Loc, DeclarationName Entity); QualType BuildParenType(QualType T); - TypeSourceInfo *GetTypeForDeclarator(Declarator &D, Scope *S, - TagDecl **OwnedDecl = 0, - bool AllowAutoInTypeName = false); + TypeSourceInfo *GetTypeForDeclarator(Declarator &D, Scope *S); + TypeSourceInfo *GetTypeForDeclaratorCast(Declarator &D, QualType FromTy); TypeSourceInfo *GetTypeSourceInfoForDeclarator(Declarator &D, QualType T, TypeSourceInfo *ReturnTypeInfo); /// \brief Package the given type and TSI into a ParsedType. @@ -838,7 +818,7 @@ public: const FunctionProtoType *Source, SourceLocation SourceLoc); TypeResult ActOnTypeName(Scope *S, Declarator &D); - + bool RequireCompleteType(SourceLocation Loc, QualType T, const PartialDiagnostic &PD, std::pair Note); @@ -864,7 +844,7 @@ public: // Symbol table / Decl tracking callbacks: SemaDecl.cpp. // - DeclGroupPtrTy ConvertDeclToDeclGroup(Decl *Ptr); + DeclGroupPtrTy ConvertDeclToDeclGroup(Decl *Ptr, Decl *OwnedType = 0); void DiagnoseUseOfUnimplementedSelectors(); @@ -983,8 +963,7 @@ public: SourceLocation NameLoc, const Token &NextToken); - Decl *ActOnDeclarator(Scope *S, Declarator &D, - bool IsFunctionDefintion = false); + Decl *ActOnDeclarator(Scope *S, Declarator &D); Decl *HandleDeclarator(Scope *S, Declarator &D, MultiTemplateParamsArg TemplateParameterLists, @@ -1305,13 +1284,20 @@ public: bool IsForUsingDecl); bool IsOverload(FunctionDecl *New, FunctionDecl *Old, bool IsForUsingDecl); - bool TryImplicitConversion(InitializationSequence &Sequence, - const InitializedEntity &Entity, - Expr *From, - bool SuppressUserConversions, - bool AllowExplicit, - bool InOverloadResolution, - bool CStyle); + /// \brief Checks availability of the function depending on the current + /// function context.Inside an unavailable function,unavailability is ignored. + /// + /// \returns true if \arg FD is unavailable and current context is inside + /// an available function, false otherwise. + bool isFunctionConsideredUnavailable(FunctionDecl *FD); + + ImplicitConversionSequence + TryImplicitConversion(Expr *From, QualType ToType, + bool SuppressUserConversions, + bool AllowExplicit, + bool InOverloadResolution, + bool CStyle, + bool AllowObjCWritebackConversion); bool IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType); bool IsFloatingPointPromotion(QualType FromType, QualType ToType); @@ -1321,6 +1307,8 @@ public: QualType& ConvertedType, bool &IncompatibleObjC); bool isObjCPointerConversion(QualType FromType, QualType ToType, QualType& ConvertedType, bool &IncompatibleObjC); + bool isObjCWritebackConversion(QualType FromType, QualType ToType, + QualType &ConvertedType); bool IsBlockPointerConversion(QualType FromType, QualType ToType, QualType& ConvertedType); bool FunctionArgTypesAreEqual(const FunctionProtoType *OldType, @@ -1338,14 +1326,17 @@ public: CXXCastPath &BasePath, bool IgnoreBaseAccess); bool IsQualificationConversion(QualType FromType, QualType ToType, - bool CStyle); + bool CStyle, bool &ObjCLifetimeConversion); + bool IsNoReturnConversion(QualType FromType, QualType ToType, + QualType &ResultTy); bool DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType); ExprResult PerformMoveOrCopyInitialization(const InitializedEntity &Entity, const VarDecl *NRVOCandidate, QualType ResultType, - Expr *Value); + Expr *Value, + bool AllowNRVO = true); bool CanPerformCopyInitialization(const InitializedEntity &Entity, ExprResult Init); @@ -1614,6 +1605,8 @@ public: LookupRedeclarationWithLinkage, /// Look up the name of an Objective-C protocol. LookupObjCProtocolName, + /// Look up implicit 'self' parameter of an objective-c method. + LookupObjCImplicitSelfParam, /// \brief Look up any declaration with any name. LookupAnyName }; @@ -1640,6 +1633,16 @@ private: bool ConstThis, bool VolatileThis); + // \brief The set of known/encountered (unique, canonicalized) NamespaceDecls. + // + // The boolean value will be true to indicate that the namespace was loaded + // from an AST/PCH file, or false otherwise. + llvm::DenseMap KnownNamespaces; + + /// \brief Whether we have already loaded known namespaces from an extenal + /// source. + bool LoadedExternalKnownNamespaces; + public: /// \brief Look up a name, looking for a single declaration. Return /// null if the results were absent, ambiguous, or overloaded. @@ -1669,9 +1672,12 @@ public: DeclContextLookupResult LookupConstructors(CXXRecordDecl *Class); CXXConstructorDecl *LookupDefaultConstructor(CXXRecordDecl *Class); - CXXConstructorDecl *LookupCopyConstructor(CXXRecordDecl *Class, - unsigned Quals, - bool *ConstParam = 0); + CXXConstructorDecl *LookupCopyingConstructor(CXXRecordDecl *Class, + unsigned Quals, + bool *ConstParam = 0); + CXXMethodDecl *LookupCopyingAssignment(CXXRecordDecl *Class, unsigned Quals, + bool RValueThis, unsigned ThisQuals, + bool *ConstParam = 0); CXXDestructorDecl *LookupDestructor(CXXRecordDecl *Class); void ArgumentDependentLookup(DeclarationName Name, bool Operator, @@ -1713,11 +1719,13 @@ public: CTC_ObjCMessageReceiver }; - DeclarationName CorrectTypo(LookupResult &R, Scope *S, CXXScopeSpec *SS, - DeclContext *MemberContext = 0, - bool EnteringContext = false, - CorrectTypoContext CTC = CTC_Unknown, - const ObjCObjectPointerType *OPT = 0); + TypoCorrection CorrectTypo(const DeclarationNameInfo &Typo, + Sema::LookupNameKind LookupKind, + Scope *S, CXXScopeSpec *SS, + DeclContext *MemberContext = NULL, + bool EnteringContext = false, + CorrectTypoContext CTC = CTC_Unknown, + const ObjCObjectPointerType *OPT = NULL); void FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs, AssociatedNamespaceSet &AssociatedNamespaces, @@ -1853,14 +1861,20 @@ public: void AtomicPropertySetterGetterRules(ObjCImplDecl* IMPDecl, ObjCContainerDecl* IDecl); + void DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl *D); + void DiagnoseDuplicateIvars(ObjCInterfaceDecl *ID, ObjCInterfaceDecl *SID); + enum MethodMatchStrategy { + MMS_loose, + MMS_strict + }; + /// MatchTwoMethodDeclarations - Checks if two methods' type match and returns /// true, or false, accordingly. bool MatchTwoMethodDeclarations(const ObjCMethodDecl *Method, const ObjCMethodDecl *PrevMethod, - bool matchBasedOnSizeAndAlignment = false, - bool matchBasedOnStrictEqulity = false); + MethodMatchStrategy strategy = MMS_strict); /// MatchAllMethodDeclarations - Check methods declaraed in interface or /// or protocol against those declared in their implementations. @@ -2073,10 +2087,13 @@ public: Expr *SynchExpr, Stmt *SynchBody); + StmtResult ActOnObjCAutoreleasePoolStmt(SourceLocation AtLoc, Stmt *Body); + VarDecl *BuildExceptionDeclaration(Scope *S, TypeSourceInfo *TInfo, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id); + Decl *ActOnExceptionDeclarator(Scope *S, Declarator &D); StmtResult ActOnCXXCatchBlock(SourceLocation CatchLoc, @@ -2130,6 +2147,9 @@ public: void HandleDelayedDeprecationCheck(sema::DelayedDiagnostic &DD, Decl *Ctx); + bool makeUnavailableInSystemHeader(SourceLocation loc, + llvm::StringRef message); + //===--------------------------------------------------------------------===// // Expression Parsing Callbacks: SemaExpr.cpp. @@ -2146,6 +2166,8 @@ public: void PopExpressionEvaluationContext(); + void DiscardCleanupsInEvaluationContext(); + void MarkDeclarationReferenced(SourceLocation Loc, Decl *D); void MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T); void MarkDeclarationsReferencedInExpr(Expr *E); @@ -2177,6 +2199,11 @@ public: ExprResult ActOnIdExpression(Scope *S, CXXScopeSpec &SS, UnqualifiedId &Name, bool HasTrailingLParen, bool IsAddressOfOperand); + void DecomposeUnqualifiedId(const UnqualifiedId &Id, + TemplateArgumentListInfo &Buffer, + DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *&TemplateArgs); + bool DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, CorrectTypoContext CTC = CTC_Unknown); @@ -2232,8 +2259,7 @@ public: ExprResult ActOnParenExpr(SourceLocation L, SourceLocation R, Expr *Val); ExprResult ActOnParenOrParenListExpr(SourceLocation L, SourceLocation R, - MultiExprArg Val, - ParsedType TypeOfCast = ParsedType()); + MultiExprArg Val); /// ActOnStringLiteral - The specified tokens were lexed as pasted string /// fragments (e.g. "foo" "bar" L"baz"). @@ -2356,21 +2382,19 @@ public: MultiExprArg ExecConfig, SourceLocation GGGLoc); ExprResult ActOnCastExpr(Scope *S, SourceLocation LParenLoc, - ParsedType Ty, SourceLocation RParenLoc, - Expr *Op); + Declarator &D, ParsedType &Ty, + SourceLocation RParenLoc, Expr *Op); ExprResult BuildCStyleCastExpr(SourceLocation LParenLoc, TypeSourceInfo *Ty, SourceLocation RParenLoc, Expr *Op); - bool TypeIsVectorType(ParsedType Ty) { - return GetTypeFromParser(Ty)->isVectorType(); - } + /// \brief Build an altivec or OpenCL literal. + ExprResult BuildVectorLiteral(SourceLocation LParenLoc, + SourceLocation RParenLoc, Expr *E, + TypeSourceInfo *TInfo); ExprResult MaybeConvertParenListExprToParenExpr(Scope *S, Expr *ME); - ExprResult ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc, - SourceLocation RParenLoc, Expr *E, - TypeSourceInfo *TInfo); ExprResult ActOnCompoundLiteral(SourceLocation LParenLoc, ParsedType Ty, @@ -2805,7 +2829,7 @@ public: ExprResult ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, SourceLocation LAngleBracketLoc, - ParsedType Ty, + Declarator &D, SourceLocation RAngleBracketLoc, SourceLocation LParenLoc, Expr *E, @@ -2863,8 +2887,11 @@ public: ExprResult ActOnCXXNullPtrLiteral(SourceLocation Loc); //// ActOnCXXThrow - Parse throw expressions. - ExprResult ActOnCXXThrow(SourceLocation OpLoc, Expr *expr); - ExprResult CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E); + ExprResult ActOnCXXThrow(Scope *S, SourceLocation OpLoc, Expr *expr); + ExprResult BuildCXXThrow(SourceLocation OpLoc, Expr *Ex, + bool IsThrownVarInScope); + ExprResult CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E, + bool IsThrownVarInScope); /// ActOnCXXTypeConstructExpr - Parse construction of a specified type. /// Can be interpreted either as function-style casting ("int(x)") @@ -4290,12 +4317,27 @@ public: QualType *FunctionType, sema::TemplateDeductionInfo &Info); + /// brief A function argument from which we performed template argument + // deduction for a call. + struct OriginalCallArg { + OriginalCallArg(QualType OriginalParamType, + unsigned ArgIdx, + QualType OriginalArgType) + : OriginalParamType(OriginalParamType), ArgIdx(ArgIdx), + OriginalArgType(OriginalArgType) { } + + QualType OriginalParamType; + unsigned ArgIdx; + QualType OriginalArgType; + }; + TemplateDeductionResult FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, llvm::SmallVectorImpl &Deduced, unsigned NumExplicitlySpecified, FunctionDecl *&Specialization, - sema::TemplateDeductionInfo &Info); + sema::TemplateDeductionInfo &Info, + llvm::SmallVectorImpl const *OriginalCallArgs = 0); TemplateDeductionResult DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, @@ -4701,7 +4743,7 @@ public: /// \brief The number of typos corrected by CorrectTypo. unsigned TyposCorrected; - typedef llvm::DenseMap > + typedef llvm::DenseMap UnqualifiedTyposCorrectedMap; /// \brief A cache containing the results of typo correction for unqualified @@ -4806,7 +4848,7 @@ public: bool Complain = true); void InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, - Decl *Pattern, Decl *Inst); + const Decl *Pattern, Decl *Inst); bool InstantiateClassTemplateSpecialization(SourceLocation PointOfInstantiation, @@ -4982,6 +5024,15 @@ public: IdentifierInfo *PropertyIvar, SourceLocation PropertyIvarLoc); + enum ObjCSpecialMethodKind { + OSMK_None, + OSMK_Alloc, + OSMK_New, + OSMK_Copy, + OSMK_RetainingInit, + OSMK_NonRetainingInit + }; + struct ObjCArgInfo { IdentifierInfo *Name; SourceLocation NameLoc; @@ -5020,9 +5071,12 @@ public: const ObjCObjectPointerType *OPT, bool IsInstance); + bool inferObjCARCLifetime(ValueDecl *decl); + ExprResult HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, Expr *BaseExpr, + SourceLocation OpLoc, DeclarationName MemberName, SourceLocation MemberLoc, SourceLocation SuperLoc, QualType SuperType, @@ -5098,6 +5152,22 @@ public: SourceLocation RBracLoc, MultiExprArg Args); + ExprResult BuildObjCBridgedCast(SourceLocation LParenLoc, + ObjCBridgeCastKind Kind, + SourceLocation BridgeKeywordLoc, + TypeSourceInfo *TSInfo, + Expr *SubExpr); + + ExprResult ActOnObjCBridgedCast(Scope *S, + SourceLocation LParenLoc, + ObjCBridgeCastKind Kind, + SourceLocation BridgeKeywordLoc, + ParsedType Type, + SourceLocation RParenLoc, + Expr *SubExpr); + + bool checkInitMethod(ObjCMethodDecl *method, QualType receiverTypeIfCall); + /// \brief Check whether the given new method is a valid override of the /// given overridden method, and set any properties that should be inherited. /// @@ -5105,7 +5175,7 @@ public: bool CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, const ObjCMethodDecl *Overridden, bool IsImplementation); - + /// \brief Check whether the given method overrides any methods in its class, /// calling \c CheckObjCMethodOverride for each overridden method. bool CheckObjCMethodOverrides(ObjCMethodDecl *NewMethod, DeclContext *DC); @@ -5208,12 +5278,26 @@ public: /// from the inner expression. ExprValueKind CastCategory(Expr *E); + /// \brief The kind of conversion being performed. + enum CheckedConversionKind { + /// \brief An implicit conversion. + CCK_ImplicitConversion, + /// \brief A C-style cast. + CCK_CStyleCast, + /// \brief A functional-style cast. + CCK_FunctionalCast, + /// \brief A cast other than a C-style cast. + CCK_OtherCast + }; + /// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit /// cast. If there is already an implicit cast, merge into the existing one. /// If isLvalue, the result of the cast is an lvalue. ExprResult ImpCastExprToType(Expr *E, QualType Type, CastKind CK, ExprValueKind VK = VK_RValue, - const CXXCastPath *BasePath = 0); + const CXXCastPath *BasePath = 0, + CheckedConversionKind CCK + = CCK_ImplicitConversion); /// ScalarTypeToBooleanCastKind - Returns the cast kind corresponding /// to the conversion from scalar type ScalarTy to the Boolean type. @@ -5343,6 +5427,10 @@ public: /// "id " = "Foo *", where "Foo *" doesn't implement the XXX protocol. IncompatibleObjCQualifiedId, + /// IncompatibleObjCWeakRef - Assigning a weak-unavailable object to an + /// object with __weak qualifier. + IncompatibleObjCWeakRef, + /// Incompatible - We reject this conversion outright, it is invalid to /// represent it in the AST. Incompatible @@ -5393,11 +5481,12 @@ public: ExprResult PerformImplicitConversion(Expr *From, QualType ToType, const ImplicitConversionSequence& ICS, AssignmentAction Action, - bool CStyle = false); + CheckedConversionKind CCK + = CCK_ImplicitConversion); ExprResult PerformImplicitConversion(Expr *From, QualType ToType, const StandardConversionSequence& SCS, AssignmentAction Action, - bool CStyle); + CheckedConversionKind CCK); /// the following "Check" methods will return a valid/converted QualType /// or a null QualType (indicating an error diagnostic was issued). @@ -5459,7 +5548,8 @@ public: SourceLocation QuestionLoc); /// type checking for vector binary operators. - QualType CheckVectorOperands(SourceLocation l, ExprResult &lex, ExprResult &rex); + QualType CheckVectorOperands(ExprResult &lex, ExprResult &rex, + SourceLocation Loc, bool isCompAssign); QualType CheckVectorCompareOperands(ExprResult &lex, ExprResult &rx, SourceLocation l, bool isRel); @@ -5494,12 +5584,14 @@ public: ReferenceCompareResult CompareReferenceRelationship(SourceLocation Loc, QualType T1, QualType T2, bool &DerivedToBase, - bool &ObjCConversion); + bool &ObjCConversion, + bool &ObjCLifetimeConversion); /// CheckCastTypes - Check type constraints for casting between types under /// C semantics, or forward to CXXCheckCStyleCast in C++. - ExprResult CheckCastTypes(SourceRange TyRange, QualType CastTy, Expr *CastExpr, - CastKind &Kind, ExprValueKind &VK, CXXCastPath &BasePath, + ExprResult CheckCastTypes(SourceLocation CastStartLoc, SourceRange TyRange, + QualType CastTy, Expr *CastExpr, CastKind &Kind, + ExprValueKind &VK, CXXCastPath &BasePath, bool FunctionalStyle = false); ExprResult checkUnknownAnyCast(SourceRange TyRange, QualType castType, @@ -5526,6 +5618,31 @@ public: ExprResult CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK, Expr *CastExpr, CastKind &Kind, CXXCastPath &BasePath, bool FunctionalStyle); + + /// \brief Checks for valid expressions which can be cast to an ObjC + /// pointer without needing a bridge cast. + bool ValidObjCARCNoBridgeCastExpr(Expr *&Exp, QualType castType); + + /// \brief Checks for invalid conversions and casts between + /// retainable pointers and other pointer kinds. + void CheckObjCARCConversion(SourceRange castRange, QualType castType, + Expr *&op, CheckedConversionKind CCK); + + bool CheckObjCARCUnavailableWeakConversion(QualType castType, + QualType ExprType); + + /// checkRetainCycles - Check whether an Objective-C message send + /// might create an obvious retain cycle. + void checkRetainCycles(ObjCMessageExpr *msg); + void checkRetainCycles(Expr *receiver, Expr *argument); + + /// checkUnsafeAssigns - Check whether +1 expr is being assigned + /// to weak/__unsafe_unretained type. + bool checkUnsafeAssigns(SourceLocation Loc, QualType LHS, Expr *RHS); + + /// checkUnsafeExprAssigns - Check whether +1 expr is being assigned + /// to weak/__unsafe_unretained expression. + void checkUnsafeExprAssigns(SourceLocation Loc, Expr *LHS, Expr *RHS); /// CheckMessageArgumentTypes - Check types in an Obj-C message send. /// \param Method - May be null. @@ -5544,7 +5661,7 @@ public: QualType getMessageSendResultType(QualType ReceiverType, ObjCMethodDecl *Method, bool isClassMessage, bool isSuperMessage); - + /// \brief If the given expression involves a message send to a method /// with a related result type, emit a note describing what happened. void EmitRelatedResultTypeNote(const Expr *E); @@ -5749,8 +5866,6 @@ public: llvm::SmallVectorImpl &Results); //@} - void PrintStats() const {} - //===--------------------------------------------------------------------===// // Extra semantic analysis beyond the C type system @@ -5802,8 +5917,17 @@ private: unsigned format_idx, unsigned firstDataArg, bool isPrintf); - void CheckMemsetcpymoveArguments(const CallExpr *Call, - const IdentifierInfo *FnName); + /// \brief Enumeration used to describe which of the memory setting or copying + /// functions is being checked by \c CheckMemsetcpymoveArguments(). + enum CheckedMemoryFunction { + CMF_Memset, + CMF_Memcpy, + CMF_Memmove + }; + + void CheckMemsetcpymoveArguments(const CallExpr *Call, + CheckedMemoryFunction CMF, + IdentifierInfo *FnName); void CheckReturnStackAddr(Expr *RetValExp, QualType lhsType, SourceLocation ReturnLoc); @@ -5820,10 +5944,20 @@ private: protected: friend class Parser; - friend class InitializationSequence; + friend class InitializationSequence; + friend class ASTReader; + friend class ASTWriter; +public: /// \brief Retrieve the parser's current scope. - Scope *getCurScope() const { return CurScope; } + /// + /// This routine must only be used when it is certain that semantic analysis + /// and the parser are in precisely the same context, which is not the case + /// when, e.g., we are performing any kind of template instantiation. + /// Therefore, the only safe places to use this scope are in the parser + /// itself and in routines directly invoked from the parser and *never* from + /// template substitution or instantiation. + Scope *getCurScope() const { return CurScope; } }; /// \brief RAII object that enters a new expression evaluation context. diff --git a/include/clang/Sema/TypoCorrection.h b/include/clang/Sema/TypoCorrection.h new file mode 100644 index 000000000000..9965953538a1 --- /dev/null +++ b/include/clang/Sema/TypoCorrection.h @@ -0,0 +1,105 @@ +//===--- TypoCorrection.h - Class for typo correction results ---*- 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 TypoCorrection class, which stores the results of +// Sema's typo correction (Sema::CorrectTypo). +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_TYPOCORRECTION_H +#define LLVM_CLANG_SEMA_TYPOCORRECTION_H + +#include "clang/AST/DeclCXX.h" + +namespace clang { + +/// @brief Simple class containing the result of Sema::CorrectTypo +class TypoCorrection { +public: + TypoCorrection(const DeclarationName &Name, NamedDecl *NameDecl, + NestedNameSpecifier *NNS=NULL, unsigned distance=0) + : CorrectionName(Name), + CorrectionNameSpec(NNS), + CorrectionDecl(NameDecl), + EditDistance(distance) {} + + TypoCorrection(NamedDecl *Name, NestedNameSpecifier *NNS=NULL, + unsigned distance=0) + : CorrectionName(Name->getDeclName()), + CorrectionNameSpec(NNS), + CorrectionDecl(Name), + EditDistance(distance) {} + + TypoCorrection(DeclarationName Name, NestedNameSpecifier *NNS=NULL, + unsigned distance=0) + : CorrectionName(Name), + CorrectionNameSpec(NNS), + CorrectionDecl(NULL), + EditDistance(distance) {} + + TypoCorrection() + : CorrectionName(), CorrectionNameSpec(NULL), CorrectionDecl(NULL), + EditDistance(0) {} + + /// \brief Gets the DeclarationName of the typo correction + DeclarationName getCorrection() const { return CorrectionName; } + IdentifierInfo* getCorrectionAsIdentifierInfo() const { + return CorrectionName.getAsIdentifierInfo(); + } + + /// \brief Gets the NestedNameSpecifier needed to use the typo correction + NestedNameSpecifier* getCorrectionSpecifier() const { + return CorrectionNameSpec; + } + void setCorrectionSpecifier(NestedNameSpecifier* NNS) { + CorrectionNameSpec = NNS; + } + + /// \brief Gets the "edit distance" of the typo correction from the typo + unsigned getEditDistance() const { return EditDistance; } + + /// \brief Gets the pointer to the declaration of the typo correction + NamedDecl* getCorrectionDecl() const { + return isKeyword() ? NULL : CorrectionDecl; + } + template + DeclClass *getCorrectionDeclAs() const { + return dyn_cast_or_null(getCorrectionDecl()); + } + + void setCorrectionDecl(NamedDecl *CDecl) { + CorrectionDecl = CDecl; + if (!CorrectionName) + CorrectionName = CDecl->getDeclName(); + } + + std::string getAsString(const LangOptions &LO) const; + std::string getQuoted(const LangOptions &LO) const { + return "'" + getAsString(LO) + "'"; + } + + operator bool() const { return bool(CorrectionName); } + + static inline NamedDecl *KeywordDecl() { return (NamedDecl*)-1; } + bool isKeyword() const { return CorrectionDecl == KeywordDecl(); } + + // Returns true if the correction either is a keyword or has a known decl. + bool isResolved() const { return CorrectionDecl != NULL; } + +private: + // Results. + DeclarationName CorrectionName; + NestedNameSpecifier *CorrectionNameSpec; + NamedDecl *CorrectionDecl; + unsigned EditDistance; +}; + +} + +#endif diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index c881b23ed116..11b8bed903d6 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -371,7 +371,11 @@ namespace clang { /// \brief Record code for the table of offsets into the block /// of file source-location information. - FILE_SOURCE_LOCATION_OFFSETS = 45 + FILE_SOURCE_LOCATION_OFFSETS = 45, + + /// \brief Record code for the set of known namespaces, which are used + /// for typo correction. + KNOWN_NAMESPACES = 46 }; @@ -388,8 +392,8 @@ namespace clang { /// SM_SLOC_BUFFER_ENTRY record. SM_SLOC_BUFFER_BLOB = 3, /// \brief Describes a source location entry (SLocEntry) for a - /// macro instantiation. - SM_SLOC_INSTANTIATION_ENTRY = 4, + /// macro expansion. + SM_SLOC_EXPANSION_ENTRY = 4, /// \brief Describes the SourceManager's line table, with /// information about #line directives. SM_LINE_TABLE = 5 @@ -416,9 +420,8 @@ namespace clang { /// \brief Record types used within a preprocessor detail block. enum PreprocessorDetailRecordTypes { - /// \brief Describes a macro instantiation within the preprocessing - /// record. - PPD_MACRO_INSTANTIATION = 0, + /// \brief Describes a macro expansion within the preprocessing record. + PPD_MACRO_EXPANSION = 0, /// \brief Describes a macro definition within the preprocessing record. PPD_MACRO_DEFINITION = 1, @@ -922,6 +925,8 @@ namespace clang { EXPR_OBJC_MESSAGE_EXPR, /// \brief An ObjCIsa Expr record. EXPR_OBJC_ISA, + /// \breif An ObjCIndirectCopyRestoreExpr record. + EXPR_OBJC_INDIRECT_COPY_RESTORE, /// \brief An ObjCForCollectionStmt record. STMT_OBJC_FOR_COLLECTION, @@ -935,6 +940,8 @@ namespace clang { STMT_OBJC_AT_SYNCHRONIZED, /// \brief An ObjCAtThrowStmt record. STMT_OBJC_AT_THROW, + /// \brief An ObjCAutoreleasePoolStmt record. + STMT_OBJC_AUTORELEASE_POOL, // C++ @@ -968,8 +975,6 @@ namespace clang { EXPR_CXX_NULL_PTR_LITERAL, // CXXNullPtrLiteralExpr EXPR_CXX_TYPEID_EXPR, // CXXTypeidExpr (of expr). EXPR_CXX_TYPEID_TYPE, // CXXTypeidExpr (of type). - EXPR_CXX_UUIDOF_EXPR, // CXXUuidofExpr (of expr). - EXPR_CXX_UUIDOF_TYPE, // CXXUuidofExpr (of type). EXPR_CXX_THIS, // CXXThisExpr EXPR_CXX_THROW, // CXXThrowExpr EXPR_CXX_DEFAULT_ARG, // CXXDefaultArgExpr @@ -999,14 +1004,25 @@ namespace clang { EXPR_PACK_EXPANSION, // PackExpansionExpr EXPR_SIZEOF_PACK, // SizeOfPackExpr + EXPR_SUBST_NON_TYPE_TEMPLATE_PARM, // SubstNonTypeTemplateParmExpr EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK,// SubstNonTypeTemplateParmPackExpr - + EXPR_MATERIALIZE_TEMPORARY, // MaterializeTemporaryExpr + // CUDA + EXPR_CUDA_KERNEL_CALL, // CUDAKernelCallExpr - EXPR_CUDA_KERNEL_CALL, // CUDAKernelCallExpr - // OpenCL - EXPR_ASTYPE // An AsTypeExpr record. + EXPR_ASTYPE, // AsTypeExpr + + // Microsoft + EXPR_CXX_UUIDOF_EXPR, // CXXUuidofExpr (of expr). + EXPR_CXX_UUIDOF_TYPE, // CXXUuidofExpr (of type). + STMT_SEH_EXCEPT, // SEHExceptStmt + STMT_SEH_FINALLY, // SEHFinallyStmt + STMT_SEH_TRY, // SEHTryStmt + + // ARC + EXPR_OBJC_BRIDGED_CAST // ObjCBridgedCastExpr }; /// \brief The kinds of designators that can occur in a diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h index 8923e2ab0d71..9e210c3db28c 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -625,6 +625,9 @@ private: /// \brief The OpenCL extension settings. llvm::SmallVector OpenCLExtensions; + /// \brief A list of the namespaces we've seen. + llvm::SmallVector KnownNamespaces; + //@} /// \brief Diagnostic IDs and their mappings that the user changed. @@ -1067,7 +1070,7 @@ public: /// /// \returns true if there was an error while reading the /// declarations for this declaration context. - virtual bool FindExternalLexicalDecls(const DeclContext *DC, + virtual ExternalLoadResult FindExternalLexicalDecls(const DeclContext *DC, bool (*isKindWeWant)(Decl::Kind), llvm::SmallVectorImpl &Decls); @@ -1125,6 +1128,11 @@ public: virtual std::pair ReadMethodPool(Selector Sel); + /// \brief Load the set of namespaces that are known to the external source, + /// which will be used during typo correction. + virtual void ReadKnownNamespaces( + llvm::SmallVectorImpl &Namespaces); + /// \brief Load a selector from disk, registering its ID if it exists. void LoadSelector(Selector Sel); diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h index 78a63abd9eba..18e15014be70 100644 --- a/include/clang/Serialization/ASTWriter.h +++ b/include/clang/Serialization/ASTWriter.h @@ -383,7 +383,7 @@ public: /// are relative to the given system root. /// /// \param PPRec Record of the preprocessing actions that occurred while - /// preprocessing this file, e.g., macro instantiations + /// preprocessing this file, e.g., macro expansions void WriteAST(Sema &SemaRef, MemorizeStatCalls *StatCalls, const std::string &OutputFile, const char* isysroot); diff --git a/include/clang/Serialization/ChainedIncludesSource.h b/include/clang/Serialization/ChainedIncludesSource.h index 0c3e86faf414..f547902ef0eb 100644 --- a/include/clang/Serialization/ChainedIncludesSource.h +++ b/include/clang/Serialization/ChainedIncludesSource.h @@ -47,7 +47,7 @@ protected: virtual DeclContextLookupResult FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name); virtual void MaterializeVisibleDecls(const DeclContext *DC); - virtual bool FindExternalLexicalDecls(const DeclContext *DC, + virtual ExternalLoadResult FindExternalLexicalDecls(const DeclContext *DC, bool (*isKindWeWant)(Decl::Kind), llvm::SmallVectorImpl &Result); virtual void CompleteType(TagDecl *Tag); diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h b/include/clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h index 07cdbf523427..de7b8684066f 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h @@ -124,6 +124,10 @@ namespace ento { return F.add(K, L); } + static bool Contains(data_type L, key_type K) { + return L.contains(K); + } + static inline data_type MakeData(void* const* p) { return p ? data_type((const llvm::ImmutableListImpl*) *p) : data_type(0); diff --git a/lib/ARCMigrate/ARCMT.cpp b/lib/ARCMigrate/ARCMT.cpp new file mode 100644 index 000000000000..f1d947da677e --- /dev/null +++ b/lib/ARCMigrate/ARCMT.cpp @@ -0,0 +1,541 @@ +//===--- ARCMT.cpp - Migration to ARC mode --------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Internals.h" +#include "clang/Frontend/ASTUnit.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/Utils.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/Rewrite/Rewriter.h" +#include "clang/Sema/SemaDiagnostic.h" +#include "clang/Basic/DiagnosticCategories.h" +#include "clang/Lex/Preprocessor.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/ADT/Triple.h" + +using namespace clang; +using namespace arcmt; +using llvm::StringRef; + +bool CapturedDiagList::clearDiagnostic(llvm::ArrayRef IDs, + SourceRange range) { + if (range.isInvalid()) + return false; + + bool cleared = false; + ListTy::iterator I = List.begin(); + while (I != List.end()) { + FullSourceLoc diagLoc = I->getLocation(); + if ((IDs.empty() || // empty means clear all diagnostics in the range. + std::find(IDs.begin(), IDs.end(), I->getID()) != IDs.end()) && + !diagLoc.isBeforeInTranslationUnitThan(range.getBegin()) && + (diagLoc == range.getEnd() || + diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) { + cleared = true; + ListTy::iterator eraseS = I++; + while (I != List.end() && I->getLevel() == Diagnostic::Note) + ++I; + // Clear the diagnostic and any notes following it. + List.erase(eraseS, I); + continue; + } + + ++I; + } + + return cleared; +} + +bool CapturedDiagList::hasDiagnostic(llvm::ArrayRef IDs, + SourceRange range) const { + if (range.isInvalid()) + return false; + + ListTy::const_iterator I = List.begin(); + while (I != List.end()) { + FullSourceLoc diagLoc = I->getLocation(); + if ((IDs.empty() || // empty means any diagnostic in the range. + std::find(IDs.begin(), IDs.end(), I->getID()) != IDs.end()) && + !diagLoc.isBeforeInTranslationUnitThan(range.getBegin()) && + (diagLoc == range.getEnd() || + diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) { + return true; + } + + ++I; + } + + return false; +} + +void CapturedDiagList::reportDiagnostics(Diagnostic &Diags) const { + for (ListTy::const_iterator I = List.begin(), E = List.end(); I != E; ++I) + Diags.Report(*I); +} + +bool CapturedDiagList::hasErrors() const { + for (ListTy::const_iterator I = List.begin(), E = List.end(); I != E; ++I) + if (I->getLevel() >= Diagnostic::Error) + return true; + + return false; +} + +namespace { + +class CaptureDiagnosticClient : public DiagnosticClient { + Diagnostic &Diags; + CapturedDiagList &CapturedDiags; +public: + CaptureDiagnosticClient(Diagnostic &diags, + CapturedDiagList &capturedDiags) + : Diags(diags), CapturedDiags(capturedDiags) { } + + virtual void HandleDiagnostic(Diagnostic::Level level, + const DiagnosticInfo &Info) { + if (arcmt::isARCDiagnostic(Info.getID(), Diags) || + level >= Diagnostic::Error || level == Diagnostic::Note) { + CapturedDiags.push_back(StoredDiagnostic(level, Info)); + return; + } + + // Non-ARC warnings are ignored. + Diags.setLastDiagnosticIgnored(); + } +}; + +} // end anonymous namespace + +static inline llvm::StringRef SimulatorVersionDefineName() { + return "__IPHONE_OS_VERSION_MIN_REQUIRED="; +} + +/// \brief Parse the simulator version define: +/// __IPHONE_OS_VERSION_MIN_REQUIRED=([0-9])([0-9][0-9])([0-9][0-9]) +// and return the grouped values as integers, e.g: +// __IPHONE_OS_VERSION_MIN_REQUIRED=40201 +// will return Major=4, Minor=2, Micro=1. +static bool GetVersionFromSimulatorDefine(llvm::StringRef define, + unsigned &Major, unsigned &Minor, + unsigned &Micro) { + assert(define.startswith(SimulatorVersionDefineName())); + llvm::StringRef name, version; + llvm::tie(name, version) = define.split('='); + if (version.empty()) + return false; + std::string verstr = version.str(); + char *end; + unsigned num = (unsigned) strtol(verstr.c_str(), &end, 10); + if (*end != '\0') + return false; + Major = num / 10000; + num = num % 10000; + Minor = num / 100; + Micro = num % 100; + return true; +} + +static bool HasARCRuntime(CompilerInvocation &origCI) { + // This duplicates some functionality from Darwin::AddDeploymentTarget + // but this function is well defined, so keep it decoupled from the driver + // and avoid unrelated complications. + + for (unsigned i = 0, e = origCI.getPreprocessorOpts().Macros.size(); + i != e; ++i) { + StringRef define = origCI.getPreprocessorOpts().Macros[i].first; + bool isUndef = origCI.getPreprocessorOpts().Macros[i].second; + if (isUndef) + continue; + if (!define.startswith(SimulatorVersionDefineName())) + continue; + unsigned Major, Minor, Micro; + if (GetVersionFromSimulatorDefine(define, Major, Minor, Micro) && + Major < 10 && Minor < 100 && Micro < 100) + return Major >= 5; + } + + llvm::Triple triple(origCI.getTargetOpts().Triple); + + if (triple.getOS() == llvm::Triple::IOS) + return triple.getOSMajorVersion() >= 5; + + if (triple.getOS() == llvm::Triple::Darwin) + return triple.getOSMajorVersion() >= 11; + + if (triple.getOS() == llvm::Triple::MacOSX) { + unsigned Major, Minor, Micro; + triple.getOSVersion(Major, Minor, Micro); + return Major > 10 || (Major == 10 && Minor >= 7); + } + + return false; +} + +CompilerInvocation *createInvocationForMigration(CompilerInvocation &origCI) { + llvm::OwningPtr CInvok; + CInvok.reset(new CompilerInvocation(origCI)); + CInvok->getPreprocessorOpts().ImplicitPCHInclude = std::string(); + CInvok->getPreprocessorOpts().ImplicitPTHInclude = std::string(); + std::string define = getARCMTMacroName(); + define += '='; + CInvok->getPreprocessorOpts().addMacroDef(define); + CInvok->getLangOpts().ObjCAutoRefCount = true; + CInvok->getDiagnosticOpts().ErrorLimit = 0; + CInvok->getDiagnosticOpts().Warnings.push_back( + "error=arc-unsafe-retained-assign"); + CInvok->getLangOpts().ObjCRuntimeHasWeak = HasARCRuntime(origCI); + + return CInvok.take(); +} + +//===----------------------------------------------------------------------===// +// checkForManualIssues. +//===----------------------------------------------------------------------===// + +bool arcmt::checkForManualIssues(CompilerInvocation &origCI, + llvm::StringRef Filename, InputKind Kind, + DiagnosticClient *DiagClient) { + if (!origCI.getLangOpts().ObjC1) + return false; + + std::vector transforms = arcmt::getAllTransformations(); + assert(!transforms.empty()); + + llvm::OwningPtr CInvok; + CInvok.reset(createInvocationForMigration(origCI)); + CInvok->getFrontendOpts().Inputs.clear(); + CInvok->getFrontendOpts().Inputs.push_back(std::make_pair(Kind, Filename)); + + CapturedDiagList capturedDiags; + + assert(DiagClient); + llvm::IntrusiveRefCntPtr DiagID(new DiagnosticIDs()); + llvm::IntrusiveRefCntPtr Diags( + new Diagnostic(DiagID, DiagClient, /*ShouldOwnClient=*/false)); + + // Filter of all diagnostics. + CaptureDiagnosticClient errRec(*Diags, capturedDiags); + Diags->setClient(&errRec, /*ShouldOwnClient=*/false); + + llvm::OwningPtr Unit( + ASTUnit::LoadFromCompilerInvocationAction(CInvok.take(), Diags)); + if (!Unit) + return true; + + // Don't filter diagnostics anymore. + Diags->setClient(DiagClient, /*ShouldOwnClient=*/false); + + ASTContext &Ctx = Unit->getASTContext(); + + if (Diags->hasFatalErrorOccurred()) { + Diags->Reset(); + DiagClient->BeginSourceFile(Ctx.getLangOptions(), &Unit->getPreprocessor()); + capturedDiags.reportDiagnostics(*Diags); + DiagClient->EndSourceFile(); + return true; + } + + // After parsing of source files ended, we want to reuse the + // diagnostics objects to emit further diagnostics. + // We call BeginSourceFile because DiagnosticClient requires that + // diagnostics with source range information are emitted only in between + // BeginSourceFile() and EndSourceFile(). + DiagClient->BeginSourceFile(Ctx.getLangOptions(), &Unit->getPreprocessor()); + + // No macros will be added since we are just checking and we won't modify + // source code. + std::vector ARCMTMacroLocs; + + TransformActions testAct(*Diags, capturedDiags, Ctx, Unit->getPreprocessor()); + MigrationPass pass(Ctx, Unit->getSema(), testAct, ARCMTMacroLocs); + + for (unsigned i=0, e = transforms.size(); i != e; ++i) + transforms[i](pass); + + capturedDiags.reportDiagnostics(*Diags); + + DiagClient->EndSourceFile(); + + // If we are migrating code that gets the '-fobjc-arc' flag, make sure + // to remove it so that we don't get errors from normal compilation. + origCI.getLangOpts().ObjCAutoRefCount = false; + + return capturedDiags.hasErrors(); +} + +//===----------------------------------------------------------------------===// +// applyTransformations. +//===----------------------------------------------------------------------===// + +static bool applyTransforms(CompilerInvocation &origCI, + llvm::StringRef Filename, InputKind Kind, + DiagnosticClient *DiagClient, + llvm::StringRef outputDir) { + if (!origCI.getLangOpts().ObjC1) + return false; + + // Make sure checking is successful first. + CompilerInvocation CInvokForCheck(origCI); + if (arcmt::checkForManualIssues(CInvokForCheck, Filename, Kind, DiagClient)) + return true; + + CompilerInvocation CInvok(origCI); + CInvok.getFrontendOpts().Inputs.clear(); + CInvok.getFrontendOpts().Inputs.push_back(std::make_pair(Kind, Filename)); + + MigrationProcess migration(CInvok, DiagClient, outputDir); + + std::vector transforms = arcmt::getAllTransformations(); + assert(!transforms.empty()); + + for (unsigned i=0, e = transforms.size(); i != e; ++i) { + bool err = migration.applyTransform(transforms[i]); + if (err) return true; + } + + llvm::IntrusiveRefCntPtr DiagID(new DiagnosticIDs()); + llvm::IntrusiveRefCntPtr Diags( + new Diagnostic(DiagID, DiagClient, /*ShouldOwnClient=*/false)); + + if (outputDir.empty()) { + origCI.getLangOpts().ObjCAutoRefCount = true; + return migration.getRemapper().overwriteOriginal(*Diags); + } else { + // If we are migrating code that gets the '-fobjc-arc' flag, make sure + // to remove it so that we don't get errors from normal compilation. + origCI.getLangOpts().ObjCAutoRefCount = false; + return migration.getRemapper().flushToDisk(outputDir, *Diags); + } +} + +bool arcmt::applyTransformations(CompilerInvocation &origCI, + llvm::StringRef Filename, InputKind Kind, + DiagnosticClient *DiagClient) { + return applyTransforms(origCI, Filename, Kind, DiagClient, llvm::StringRef()); +} + +bool arcmt::migrateWithTemporaryFiles(CompilerInvocation &origCI, + llvm::StringRef Filename, InputKind Kind, + DiagnosticClient *DiagClient, + llvm::StringRef outputDir) { + assert(!outputDir.empty() && "Expected output directory path"); + return applyTransforms(origCI, Filename, Kind, DiagClient, outputDir); +} + +bool arcmt::getFileRemappings(std::vector > & + remap, + llvm::StringRef outputDir, + DiagnosticClient *DiagClient) { + assert(!outputDir.empty()); + + llvm::IntrusiveRefCntPtr DiagID(new DiagnosticIDs()); + llvm::IntrusiveRefCntPtr Diags( + new Diagnostic(DiagID, DiagClient, /*ShouldOwnClient=*/false)); + + FileRemapper remapper; + bool err = remapper.initFromDisk(outputDir, *Diags, + /*ignoreIfFilesChanged=*/true); + if (err) + return true; + + CompilerInvocation CI; + remapper.applyMappings(CI); + remap = CI.getPreprocessorOpts().RemappedFiles; + + return false; +} + +//===----------------------------------------------------------------------===// +// CollectTransformActions. +//===----------------------------------------------------------------------===// + +namespace { + +class ARCMTMacroTrackerPPCallbacks : public PPCallbacks { + std::vector &ARCMTMacroLocs; + +public: + ARCMTMacroTrackerPPCallbacks(std::vector &ARCMTMacroLocs) + : ARCMTMacroLocs(ARCMTMacroLocs) { } + + virtual void MacroExpands(const Token &MacroNameTok, const MacroInfo *MI) { + if (MacroNameTok.getIdentifierInfo()->getName() == getARCMTMacroName()) + ARCMTMacroLocs.push_back(MacroNameTok.getLocation()); + } +}; + +class ARCMTMacroTrackerAction : public ASTFrontendAction { + std::vector &ARCMTMacroLocs; + +public: + ARCMTMacroTrackerAction(std::vector &ARCMTMacroLocs) + : ARCMTMacroLocs(ARCMTMacroLocs) { } + + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + CI.getPreprocessor().addPPCallbacks( + new ARCMTMacroTrackerPPCallbacks(ARCMTMacroLocs)); + return new ASTConsumer(); + } +}; + +class RewritesApplicator : public TransformActions::RewriteReceiver { + Rewriter &rewriter; + ASTContext &Ctx; + MigrationProcess::RewriteListener *Listener; + +public: + RewritesApplicator(Rewriter &rewriter, ASTContext &ctx, + MigrationProcess::RewriteListener *listener) + : rewriter(rewriter), Ctx(ctx), Listener(listener) { + if (Listener) + Listener->start(ctx); + } + ~RewritesApplicator() { + if (Listener) + Listener->finish(); + } + + virtual void insert(SourceLocation loc, llvm::StringRef text) { + bool err = rewriter.InsertText(loc, text, /*InsertAfter=*/true, + /*indentNewLines=*/true); + if (!err && Listener) + Listener->insert(loc, text); + } + + virtual void remove(CharSourceRange range) { + Rewriter::RewriteOptions removeOpts; + removeOpts.IncludeInsertsAtBeginOfRange = false; + removeOpts.IncludeInsertsAtEndOfRange = false; + removeOpts.RemoveLineIfEmpty = true; + + bool err = rewriter.RemoveText(range, removeOpts); + if (!err && Listener) + Listener->remove(range); + } + + virtual void increaseIndentation(CharSourceRange range, + SourceLocation parentIndent) { + rewriter.IncreaseIndentation(range, parentIndent); + } +}; + +} // end anonymous namespace. + +/// \brief Anchor for VTable. +MigrationProcess::RewriteListener::~RewriteListener() { } + +MigrationProcess::MigrationProcess(const CompilerInvocation &CI, + DiagnosticClient *diagClient, + llvm::StringRef outputDir) + : OrigCI(CI), DiagClient(diagClient) { + if (!outputDir.empty()) { + llvm::IntrusiveRefCntPtr DiagID(new DiagnosticIDs()); + llvm::IntrusiveRefCntPtr Diags( + new Diagnostic(DiagID, DiagClient, /*ShouldOwnClient=*/false)); + Remapper.initFromDisk(outputDir, *Diags, /*ignoreIfFilesChanges=*/true); + } +} + +bool MigrationProcess::applyTransform(TransformFn trans, + RewriteListener *listener) { + llvm::OwningPtr CInvok; + CInvok.reset(createInvocationForMigration(OrigCI)); + CInvok->getDiagnosticOpts().IgnoreWarnings = true; + + Remapper.applyMappings(*CInvok); + + CapturedDiagList capturedDiags; + std::vector ARCMTMacroLocs; + + assert(DiagClient); + llvm::IntrusiveRefCntPtr DiagID(new DiagnosticIDs()); + llvm::IntrusiveRefCntPtr Diags( + new Diagnostic(DiagID, DiagClient, /*ShouldOwnClient=*/false)); + + // Filter of all diagnostics. + CaptureDiagnosticClient errRec(*Diags, capturedDiags); + Diags->setClient(&errRec, /*ShouldOwnClient=*/false); + + llvm::OwningPtr ASTAction; + ASTAction.reset(new ARCMTMacroTrackerAction(ARCMTMacroLocs)); + + llvm::OwningPtr Unit( + ASTUnit::LoadFromCompilerInvocationAction(CInvok.take(), Diags, + ASTAction.get())); + if (!Unit) + return true; + Unit->setOwnsRemappedFileBuffers(false); // FileRemapper manages that. + + // Don't filter diagnostics anymore. + Diags->setClient(DiagClient, /*ShouldOwnClient=*/false); + + ASTContext &Ctx = Unit->getASTContext(); + + if (Diags->hasFatalErrorOccurred()) { + Diags->Reset(); + DiagClient->BeginSourceFile(Ctx.getLangOptions(), &Unit->getPreprocessor()); + capturedDiags.reportDiagnostics(*Diags); + DiagClient->EndSourceFile(); + return true; + } + + // After parsing of source files ended, we want to reuse the + // diagnostics objects to emit further diagnostics. + // We call BeginSourceFile because DiagnosticClient requires that + // diagnostics with source range information are emitted only in between + // BeginSourceFile() and EndSourceFile(). + DiagClient->BeginSourceFile(Ctx.getLangOptions(), &Unit->getPreprocessor()); + + Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOptions()); + TransformActions TA(*Diags, capturedDiags, Ctx, Unit->getPreprocessor()); + MigrationPass pass(Ctx, Unit->getSema(), TA, ARCMTMacroLocs); + + trans(pass); + + { + RewritesApplicator applicator(rewriter, Ctx, listener); + TA.applyRewrites(applicator); + } + + DiagClient->EndSourceFile(); + + if (DiagClient->getNumErrors()) + return true; + + for (Rewriter::buffer_iterator + I = rewriter.buffer_begin(), E = rewriter.buffer_end(); I != E; ++I) { + FileID FID = I->first; + RewriteBuffer &buf = I->second; + const FileEntry *file = Ctx.getSourceManager().getFileEntryForID(FID); + assert(file); + std::string newFname = file->getName(); + newFname += "-trans"; + llvm::SmallString<512> newText; + llvm::raw_svector_ostream vecOS(newText); + buf.write(vecOS); + vecOS.flush(); + llvm::MemoryBuffer *memBuf = llvm::MemoryBuffer::getMemBufferCopy( + llvm::StringRef(newText.data(), newText.size()), newFname); + llvm::SmallString<64> filePath(file->getName()); + Unit->getFileManager().FixupRelativePath(filePath); + Remapper.remap(filePath.str(), memBuf); + } + + return false; +} + +//===----------------------------------------------------------------------===// +// isARCDiagnostic. +//===----------------------------------------------------------------------===// + +bool arcmt::isARCDiagnostic(unsigned diagID, Diagnostic &Diag) { + return Diag.getDiagnosticIDs()->getCategoryNumberForDiag(diagID) == + diag::DiagCat_Automatic_Reference_Counting_Issue; +} diff --git a/lib/ARCMigrate/ARCMTActions.cpp b/lib/ARCMigrate/ARCMTActions.cpp new file mode 100644 index 000000000000..345c7452420e --- /dev/null +++ b/lib/ARCMigrate/ARCMTActions.cpp @@ -0,0 +1,53 @@ +//===--- ARCMTActions.cpp - ARC Migrate Tool Frontend Actions ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/ARCMigrate/ARCMTActions.h" +#include "clang/ARCMigrate/ARCMT.h" +#include "clang/Frontend/CompilerInstance.h" + +using namespace clang; +using namespace arcmt; + +bool CheckAction::BeginInvocation(CompilerInstance &CI) { + if (arcmt::checkForManualIssues(CI.getInvocation(), getCurrentFile(), + getCurrentFileKind(), + CI.getDiagnostics().getClient())) + return false; // errors, stop the action. + + // We only want to see warnings reported from arcmt::checkForManualIssues. + CI.getDiagnostics().setIgnoreAllWarnings(true); + return true; +} + +CheckAction::CheckAction(FrontendAction *WrappedAction) + : WrapperFrontendAction(WrappedAction) {} + +bool ModifyAction::BeginInvocation(CompilerInstance &CI) { + return !arcmt::applyTransformations(CI.getInvocation(), + getCurrentFile(), getCurrentFileKind(), + CI.getDiagnostics().getClient()); +} + +ModifyAction::ModifyAction(FrontendAction *WrappedAction) + : WrapperFrontendAction(WrappedAction) {} + +bool MigrateAction::BeginInvocation(CompilerInstance &CI) { + return !arcmt::migrateWithTemporaryFiles(CI.getInvocation(), + getCurrentFile(), + getCurrentFileKind(), + CI.getDiagnostics().getClient(), + MigrateDir); +} + +MigrateAction::MigrateAction(FrontendAction *WrappedAction, + llvm::StringRef migrateDir) + : WrapperFrontendAction(WrappedAction), MigrateDir(migrateDir) { + if (MigrateDir.empty()) + MigrateDir = "."; // user current directory if none is given. +} diff --git a/lib/ARCMigrate/CMakeLists.txt b/lib/ARCMigrate/CMakeLists.txt new file mode 100644 index 000000000000..5f2711e36f26 --- /dev/null +++ b/lib/ARCMigrate/CMakeLists.txt @@ -0,0 +1,24 @@ +set(LLVM_USED_LIBS clangBasic clangAST clangParse clangFrontend clangRewrite) + +add_clang_library(clangARCMigrate + ARCMT.cpp + ARCMTActions.cpp + FileRemapper.cpp + TransARCAssign.cpp + TransAutoreleasePool.cpp + TransBlockObjCVariable.cpp + TransEmptyStatementsAndDealloc.cpp + TransformActions.cpp + Transforms.cpp + TransProperties.cpp + TransRetainReleaseDealloc.cpp + TransUnbridgedCasts.cpp + TransUnusedInitDelegate.cpp + TransZeroOutPropsInDealloc.cpp + ) + +add_dependencies(clangARCMigrate + ClangAttrClasses + ClangAttrList + ClangDeclNodes + ClangStmtNodes) diff --git a/lib/ARCMigrate/FileRemapper.cpp b/lib/ARCMigrate/FileRemapper.cpp new file mode 100644 index 000000000000..db26c29a3dda --- /dev/null +++ b/lib/ARCMigrate/FileRemapper.cpp @@ -0,0 +1,291 @@ +//===--- FileRemapper.cpp - File Remapping Helper -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/ARCMigrate/FileRemapper.h" +#include "clang/Frontend/CompilerInvocation.h" +#include "clang/Basic/FileManager.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/raw_ostream.h" +#include + +using namespace clang; +using namespace arcmt; + +FileRemapper::FileRemapper() { + FileMgr.reset(new FileManager(FileSystemOptions())); +} + +FileRemapper::~FileRemapper() { + clear(); +} + +void FileRemapper::clear(llvm::StringRef outputDir) { + for (MappingsTy::iterator + I = FromToMappings.begin(), E = FromToMappings.end(); I != E; ++I) + resetTarget(I->second); + FromToMappings.clear(); + assert(ToFromMappings.empty()); + if (!outputDir.empty()) { + std::string infoFile = getRemapInfoFile(outputDir); + bool existed; + llvm::sys::fs::remove(infoFile, existed); + } +} + +std::string FileRemapper::getRemapInfoFile(llvm::StringRef outputDir) { + assert(!outputDir.empty()); + llvm::sys::Path dir(outputDir); + llvm::sys::Path infoFile = dir; + infoFile.appendComponent("remap"); + return infoFile.str(); +} + +bool FileRemapper::initFromDisk(llvm::StringRef outputDir, Diagnostic &Diag, + bool ignoreIfFilesChanged) { + assert(FromToMappings.empty() && + "initFromDisk should be called before any remap calls"); + std::string infoFile = getRemapInfoFile(outputDir); + bool fileExists = false; + llvm::sys::fs::exists(infoFile, fileExists); + if (!fileExists) + return false; + + std::vector > pairs; + + std::ifstream fin(infoFile.c_str()); + if (!fin.good()) + return report(std::string("Error opening file: ") + infoFile, Diag); + + while (true) { + std::string fromFilename, toFilename; + uint64_t timeModified; + + fin >> fromFilename >> timeModified >> toFilename; + if (fin.eof()) + break; + if (!fin.good()) + return report(std::string("Error in format of file: ") + infoFile, Diag); + + const FileEntry *origFE = FileMgr->getFile(fromFilename); + if (!origFE) { + if (ignoreIfFilesChanged) + continue; + return report(std::string("File does not exist: ") + fromFilename, Diag); + } + const FileEntry *newFE = FileMgr->getFile(toFilename); + if (!newFE) { + if (ignoreIfFilesChanged) + continue; + return report(std::string("File does not exist: ") + toFilename, Diag); + } + + if ((uint64_t)origFE->getModificationTime() != timeModified) { + if (ignoreIfFilesChanged) + continue; + return report(std::string("File was modified: ") + fromFilename, Diag); + } + + pairs.push_back(std::make_pair(origFE, newFE)); + } + + for (unsigned i = 0, e = pairs.size(); i != e; ++i) + remap(pairs[i].first, pairs[i].second); + + return false; +} + +bool FileRemapper::flushToDisk(llvm::StringRef outputDir, Diagnostic &Diag) { + using namespace llvm::sys; + + bool existed; + if (fs::create_directory(outputDir, existed) != llvm::errc::success) + return report(std::string("Could not create directory: ") + outputDir.str(), + Diag); + + std::string errMsg; + std::string infoFile = getRemapInfoFile(outputDir); + llvm::raw_fd_ostream infoOut(infoFile.c_str(), errMsg, + llvm::raw_fd_ostream::F_Binary); + if (!errMsg.empty()) + return report(errMsg, Diag); + + for (MappingsTy::iterator + I = FromToMappings.begin(), E = FromToMappings.end(); I != E; ++I) { + + const FileEntry *origFE = I->first; + llvm::SmallString<200> origPath = llvm::StringRef(origFE->getName()); + fs::make_absolute(origPath); + infoOut << origPath << '\n'; + infoOut << (uint64_t)origFE->getModificationTime() << '\n'; + + if (const FileEntry *FE = I->second.dyn_cast()) { + llvm::SmallString<200> newPath = llvm::StringRef(FE->getName()); + fs::make_absolute(newPath); + infoOut << newPath << '\n'; + } else { + + llvm::SmallString<64> tempPath; + tempPath = path::filename(origFE->getName()); + tempPath += "-%%%%%%%%"; + tempPath += path::extension(origFE->getName()); + int fd; + if (fs::unique_file(tempPath.str(), fd, tempPath) != llvm::errc::success) + return report(std::string("Could not create file: ") + tempPath.c_str(), + Diag); + + llvm::raw_fd_ostream newOut(fd, /*shouldClose=*/true); + llvm::MemoryBuffer *mem = I->second.get(); + newOut.write(mem->getBufferStart(), mem->getBufferSize()); + newOut.close(); + + const FileEntry *newE = FileMgr->getFile(tempPath); + remap(origFE, newE); + infoOut << newE->getName() << '\n'; + } + } + + infoOut.close(); + return false; +} + +bool FileRemapper::overwriteOriginal(Diagnostic &Diag, + llvm::StringRef outputDir) { + using namespace llvm::sys; + + for (MappingsTy::iterator + I = FromToMappings.begin(), E = FromToMappings.end(); I != E; ++I) { + const FileEntry *origFE = I->first; + if (const FileEntry *newFE = I->second.dyn_cast()) { + if (fs::copy_file(newFE->getName(), origFE->getName(), + fs::copy_option::overwrite_if_exists) != llvm::errc::success) { + std::string err = "Could not copy file '"; + llvm::raw_string_ostream os(err); + os << "Could not copy file '" << newFE->getName() << "' to file '" + << origFE->getName() << "'"; + os.flush(); + return report(err, Diag); + } + } else { + + bool fileExists = false; + fs::exists(origFE->getName(), fileExists); + if (!fileExists) + return report(std::string("File does not exist: ") + origFE->getName(), + Diag); + + std::string errMsg; + llvm::raw_fd_ostream Out(origFE->getName(), errMsg, + llvm::raw_fd_ostream::F_Binary); + if (!errMsg.empty()) + return report(errMsg, Diag); + + llvm::MemoryBuffer *mem = I->second.get(); + Out.write(mem->getBufferStart(), mem->getBufferSize()); + Out.close(); + } + } + + clear(outputDir); + return false; +} + +void FileRemapper::applyMappings(CompilerInvocation &CI) const { + PreprocessorOptions &PPOpts = CI.getPreprocessorOpts(); + for (MappingsTy::const_iterator + I = FromToMappings.begin(), E = FromToMappings.end(); I != E; ++I) { + if (const FileEntry *FE = I->second.dyn_cast()) { + PPOpts.addRemappedFile(I->first->getName(), FE->getName()); + } else { + llvm::MemoryBuffer *mem = I->second.get(); + PPOpts.addRemappedFile(I->first->getName(), mem); + } + } + + PPOpts.RetainRemappedFileBuffers = true; +} + +void FileRemapper::transferMappingsAndClear(CompilerInvocation &CI) { + PreprocessorOptions &PPOpts = CI.getPreprocessorOpts(); + for (MappingsTy::iterator + I = FromToMappings.begin(), E = FromToMappings.end(); I != E; ++I) { + if (const FileEntry *FE = I->second.dyn_cast()) { + PPOpts.addRemappedFile(I->first->getName(), FE->getName()); + } else { + llvm::MemoryBuffer *mem = I->second.get(); + PPOpts.addRemappedFile(I->first->getName(), mem); + } + I->second = Target(); + } + + PPOpts.RetainRemappedFileBuffers = false; + clear(); +} + +void FileRemapper::remap(llvm::StringRef filePath, llvm::MemoryBuffer *memBuf) { + remap(getOriginalFile(filePath), memBuf); +} + +void FileRemapper::remap(llvm::StringRef filePath, llvm::StringRef newPath) { + const FileEntry *file = getOriginalFile(filePath); + const FileEntry *newfile = FileMgr->getFile(newPath); + remap(file, newfile); +} + +void FileRemapper::remap(const FileEntry *file, llvm::MemoryBuffer *memBuf) { + assert(file); + Target &targ = FromToMappings[file]; + resetTarget(targ); + targ = memBuf; +} + +void FileRemapper::remap(const FileEntry *file, const FileEntry *newfile) { + assert(file && newfile); + Target &targ = FromToMappings[file]; + resetTarget(targ); + targ = newfile; + ToFromMappings[newfile] = file; +} + +const FileEntry *FileRemapper::getOriginalFile(llvm::StringRef filePath) { + const FileEntry *file = FileMgr->getFile(filePath); + // If we are updating a file that overriden an original file, + // actually update the original file. + llvm::DenseMap::iterator + I = ToFromMappings.find(file); + if (I != ToFromMappings.end()) { + file = I->second; + assert(FromToMappings.find(file) != FromToMappings.end() && + "Original file not in mappings!"); + } + return file; +} + +void FileRemapper::resetTarget(Target &targ) { + if (!targ) + return; + + if (llvm::MemoryBuffer *oldmem = targ.dyn_cast()) { + delete oldmem; + } else { + const FileEntry *toFE = targ.get(); + llvm::DenseMap::iterator + I = ToFromMappings.find(toFE); + if (I != ToFromMappings.end()) + ToFromMappings.erase(I); + } +} + +bool FileRemapper::report(const std::string &err, Diagnostic &Diag) { + unsigned ID = Diag.getDiagnosticIDs()->getCustomDiagID(DiagnosticIDs::Error, + err); + Diag.Report(ID); + return true; +} diff --git a/lib/ARCMigrate/Internals.h b/lib/ARCMigrate/Internals.h new file mode 100644 index 000000000000..4f9b138a06ce --- /dev/null +++ b/lib/ARCMigrate/Internals.h @@ -0,0 +1,148 @@ +//===-- Internals.h - Implementation Details---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_ARCMIGRATE_INTERNALS_H +#define LLVM_CLANG_LIB_ARCMIGRATE_INTERNALS_H + +#include "clang/ARCMigrate/ARCMT.h" +#include "llvm/ADT/ArrayRef.h" + +namespace clang { + class Sema; + class Stmt; + +namespace arcmt { + +class CapturedDiagList { + typedef std::list ListTy; + ListTy List; + +public: + void push_back(const StoredDiagnostic &diag) { List.push_back(diag); } + + bool clearDiagnostic(llvm::ArrayRef IDs, SourceRange range); + bool hasDiagnostic(llvm::ArrayRef IDs, SourceRange range) const; + + void reportDiagnostics(Diagnostic &diags) const; + + bool hasErrors() const; +}; + +class TransformActions { + Diagnostic &Diags; + CapturedDiagList &CapturedDiags; + void *Impl; // TransformActionsImpl. + +public: + TransformActions(Diagnostic &diag, CapturedDiagList &capturedDiags, + ASTContext &ctx, Preprocessor &PP); + ~TransformActions(); + + void startTransaction(); + bool commitTransaction(); + void abortTransaction(); + + void insert(SourceLocation loc, llvm::StringRef text); + void insertAfterToken(SourceLocation loc, llvm::StringRef text); + void remove(SourceRange range); + void removeStmt(Stmt *S); + void replace(SourceRange range, llvm::StringRef text); + void replace(SourceRange range, SourceRange replacementRange); + void replaceStmt(Stmt *S, llvm::StringRef text); + void replaceText(SourceLocation loc, llvm::StringRef text, + llvm::StringRef replacementText); + void increaseIndentation(SourceRange range, + SourceLocation parentIndent); + + bool clearDiagnostic(llvm::ArrayRef IDs, SourceRange range); + bool clearAllDiagnostics(SourceRange range) { + return clearDiagnostic(llvm::ArrayRef(), range); + } + bool clearDiagnostic(unsigned ID1, unsigned ID2, SourceRange range) { + unsigned IDs[] = { ID1, ID2 }; + return clearDiagnostic(IDs, range); + } + bool clearDiagnostic(unsigned ID1, unsigned ID2, unsigned ID3, + SourceRange range) { + unsigned IDs[] = { ID1, ID2, ID3 }; + return clearDiagnostic(IDs, range); + } + + bool hasDiagnostic(unsigned ID, SourceRange range) { + return CapturedDiags.hasDiagnostic(ID, range); + } + + bool hasDiagnostic(unsigned ID1, unsigned ID2, SourceRange range) { + unsigned IDs[] = { ID1, ID2 }; + return CapturedDiags.hasDiagnostic(IDs, range); + } + + void reportError(llvm::StringRef error, SourceLocation loc, + SourceRange range = SourceRange()); + void reportNote(llvm::StringRef note, SourceLocation loc, + SourceRange range = SourceRange()); + + class RewriteReceiver { + public: + virtual ~RewriteReceiver(); + + virtual void insert(SourceLocation loc, llvm::StringRef text) = 0; + virtual void remove(CharSourceRange range) = 0; + virtual void increaseIndentation(CharSourceRange range, + SourceLocation parentIndent) = 0; + }; + + void applyRewrites(RewriteReceiver &receiver); +}; + +class Transaction { + TransformActions &TA; + bool Aborted; + +public: + Transaction(TransformActions &TA) : TA(TA), Aborted(false) { + TA.startTransaction(); + } + + ~Transaction() { + if (!isAborted()) + TA.commitTransaction(); + } + + void abort() { + TA.abortTransaction(); + Aborted = true; + } + + bool isAborted() const { return Aborted; } +}; + +class MigrationPass { +public: + ASTContext &Ctx; + Sema &SemaRef; + TransformActions &TA; + std::vector &ARCMTMacroLocs; + + MigrationPass(ASTContext &Ctx, Sema &sema, TransformActions &TA, + std::vector &ARCMTMacroLocs) + : Ctx(Ctx), SemaRef(sema), TA(TA), ARCMTMacroLocs(ARCMTMacroLocs) { } +}; + +bool isARCDiagnostic(unsigned diagID, Diagnostic &Diag); + +static inline llvm::StringRef getARCMTMacroName() { + return "__IMPL_ARCMT_REMOVED_EXPR__"; +} + +} // end namespace arcmt + +} // end namespace clang + +#endif diff --git a/lib/ARCMigrate/Makefile b/lib/ARCMigrate/Makefile new file mode 100644 index 000000000000..5232c5e5aff4 --- /dev/null +++ b/lib/ARCMigrate/Makefile @@ -0,0 +1,18 @@ +##===- clang/lib/ARCMigrate/Makefile --------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +# +# This implements code transformation to ARC mode. +# +##===----------------------------------------------------------------------===## + +CLANG_LEVEL := ../.. +LIBRARYNAME := clangARCMigrate + +include $(CLANG_LEVEL)/Makefile + diff --git a/lib/ARCMigrate/TransARCAssign.cpp b/lib/ARCMigrate/TransARCAssign.cpp new file mode 100644 index 000000000000..8c00df5daa03 --- /dev/null +++ b/lib/ARCMigrate/TransARCAssign.cpp @@ -0,0 +1,75 @@ +//===--- TransARCAssign.cpp - Tranformations to ARC mode ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// makeAssignARCSafe: +// +// Add '__strong' where appropriate. +// +// for (id x in collection) { +// x = 0; +// } +// ----> +// for (__strong id x in collection) { +// x = 0; +// } +// +//===----------------------------------------------------------------------===// + +#include "Transforms.h" +#include "Internals.h" +#include "clang/Sema/SemaDiagnostic.h" + +using namespace clang; +using namespace arcmt; +using namespace trans; +using llvm::StringRef; + +namespace { + +class ARCAssignChecker : public RecursiveASTVisitor { + MigrationPass &Pass; + llvm::DenseSet ModifiedVars; + +public: + ARCAssignChecker(MigrationPass &pass) : Pass(pass) { } + + bool VisitBinaryOperator(BinaryOperator *Exp) { + Expr *E = Exp->getLHS(); + SourceLocation OrigLoc = E->getExprLoc(); + SourceLocation Loc = OrigLoc; + DeclRefExpr *declRef = dyn_cast(E->IgnoreParenCasts()); + if (declRef && isa(declRef->getDecl())) { + ASTContext &Ctx = Pass.Ctx; + Expr::isModifiableLvalueResult IsLV = E->isModifiableLvalue(Ctx, &Loc); + if (IsLV != Expr::MLV_ConstQualified) + return true; + VarDecl *var = cast(declRef->getDecl()); + if (var->isARCPseudoStrong()) { + Transaction Trans(Pass.TA); + if (Pass.TA.clearDiagnostic(diag::err_typecheck_arr_assign_enumeration, + Exp->getOperatorLoc())) { + if (!ModifiedVars.count(var)) { + TypeLoc TLoc = var->getTypeSourceInfo()->getTypeLoc(); + Pass.TA.insert(TLoc.getBeginLoc(), "__strong "); + ModifiedVars.insert(var); + } + } + } + } + + return true; + } +}; + +} // anonymous namespace + +void trans::makeAssignARCSafe(MigrationPass &pass) { + ARCAssignChecker assignCheck(pass); + assignCheck.TraverseDecl(pass.Ctx.getTranslationUnitDecl()); +} diff --git a/lib/ARCMigrate/TransAutoreleasePool.cpp b/lib/ARCMigrate/TransAutoreleasePool.cpp new file mode 100644 index 000000000000..5b8485432c52 --- /dev/null +++ b/lib/ARCMigrate/TransAutoreleasePool.cpp @@ -0,0 +1,436 @@ +//===--- TransAutoreleasePool.cpp - Tranformations to ARC mode ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// rewriteAutoreleasePool: +// +// Calls to NSAutoreleasePools will be rewritten as an @autorelease scope. +// +// NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; +// ... +// [pool release]; +// ----> +// @autorelease { +// ... +// } +// +// An NSAutoreleasePool will not be touched if: +// - There is not a corresponding -release/-drain in the same scope +// - Not all references of the NSAutoreleasePool variable can be removed +// - There is a variable that is declared inside the intended @autorelease scope +// which is also used outside it. +// +//===----------------------------------------------------------------------===// + +#include "Transforms.h" +#include "Internals.h" +#include "clang/Sema/SemaDiagnostic.h" +#include "clang/Basic/SourceManager.h" +#include + +using namespace clang; +using namespace arcmt; +using namespace trans; +using llvm::StringRef; + +namespace { + +class ReleaseCollector : public RecursiveASTVisitor { + Decl *Dcl; + llvm::SmallVectorImpl &Releases; + +public: + ReleaseCollector(Decl *D, llvm::SmallVectorImpl &releases) + : Dcl(D), Releases(releases) { } + + bool VisitObjCMessageExpr(ObjCMessageExpr *E) { + if (!E->isInstanceMessage()) + return true; + if (E->getMethodFamily() != OMF_release) + return true; + Expr *instance = E->getInstanceReceiver()->IgnoreParenCasts(); + if (DeclRefExpr *DE = dyn_cast(instance)) { + if (DE->getDecl() == Dcl) + Releases.push_back(E); + } + return true; + } +}; + +} + +namespace { + +class AutoreleasePoolRewriter + : public RecursiveASTVisitor { +public: + AutoreleasePoolRewriter(MigrationPass &pass) + : Body(0), Pass(pass) { + PoolII = &pass.Ctx.Idents.get("NSAutoreleasePool"); + DrainSel = pass.Ctx.Selectors.getNullarySelector( + &pass.Ctx.Idents.get("drain")); + } + + void transformBody(Stmt *body) { + Body = body; + TraverseStmt(body); + } + + ~AutoreleasePoolRewriter() { + llvm::SmallVector VarsToHandle; + + for (std::map::iterator + I = PoolVars.begin(), E = PoolVars.end(); I != E; ++I) { + VarDecl *var = I->first; + PoolVarInfo &info = I->second; + + // Check that we can handle/rewrite all references of the pool. + + clearRefsIn(info.Dcl, info.Refs); + for (llvm::SmallVectorImpl::iterator + scpI = info.Scopes.begin(), + scpE = info.Scopes.end(); scpI != scpE; ++scpI) { + PoolScope &scope = *scpI; + clearRefsIn(*scope.Begin, info.Refs); + clearRefsIn(*scope.End, info.Refs); + clearRefsIn(scope.Releases.begin(), scope.Releases.end(), info.Refs); + } + + // Even if one reference is not handled we will not do anything about that + // pool variable. + if (info.Refs.empty()) + VarsToHandle.push_back(var); + } + + for (unsigned i = 0, e = VarsToHandle.size(); i != e; ++i) { + PoolVarInfo &info = PoolVars[VarsToHandle[i]]; + + Transaction Trans(Pass.TA); + + clearUnavailableDiags(info.Dcl); + Pass.TA.removeStmt(info.Dcl); + + // Add "@autoreleasepool { }" + for (llvm::SmallVectorImpl::iterator + scpI = info.Scopes.begin(), + scpE = info.Scopes.end(); scpI != scpE; ++scpI) { + PoolScope &scope = *scpI; + clearUnavailableDiags(*scope.Begin); + clearUnavailableDiags(*scope.End); + if (scope.IsFollowedBySimpleReturnStmt) { + // Include the return in the scope. + Pass.TA.replaceStmt(*scope.Begin, "@autoreleasepool {"); + Pass.TA.removeStmt(*scope.End); + Stmt::child_iterator retI = scope.End; + ++retI; + SourceLocation afterSemi = findLocationAfterSemi((*retI)->getLocEnd(), + Pass.Ctx); + assert(afterSemi.isValid() && + "Didn't we check before setting IsFollowedBySimpleReturnStmt " + "to true?"); + Pass.TA.insertAfterToken(afterSemi, "\n}"); + Pass.TA.increaseIndentation( + SourceRange(scope.getIndentedRange().getBegin(), + (*retI)->getLocEnd()), + scope.CompoundParent->getLocStart()); + } else { + Pass.TA.replaceStmt(*scope.Begin, "@autoreleasepool {"); + Pass.TA.replaceStmt(*scope.End, "}"); + Pass.TA.increaseIndentation(scope.getIndentedRange(), + scope.CompoundParent->getLocStart()); + } + } + + // Remove rest of pool var references. + for (llvm::SmallVectorImpl::iterator + scpI = info.Scopes.begin(), + scpE = info.Scopes.end(); scpI != scpE; ++scpI) { + PoolScope &scope = *scpI; + for (llvm::SmallVectorImpl::iterator + relI = scope.Releases.begin(), + relE = scope.Releases.end(); relI != relE; ++relI) { + clearUnavailableDiags(*relI); + Pass.TA.removeStmt(*relI); + } + } + } + } + + bool VisitCompoundStmt(CompoundStmt *S) { + llvm::SmallVector Scopes; + + for (Stmt::child_iterator + I = S->body_begin(), E = S->body_end(); I != E; ++I) { + Stmt *child = getEssential(*I); + if (DeclStmt *DclS = dyn_cast(child)) { + if (DclS->isSingleDecl()) { + if (VarDecl *VD = dyn_cast(DclS->getSingleDecl())) { + if (isNSAutoreleasePool(VD->getType())) { + PoolVarInfo &info = PoolVars[VD]; + info.Dcl = DclS; + collectRefs(VD, S, info.Refs); + // Does this statement follow the pattern: + // NSAutoreleasePool * pool = [NSAutoreleasePool new]; + if (isPoolCreation(VD->getInit())) { + Scopes.push_back(PoolScope()); + Scopes.back().PoolVar = VD; + Scopes.back().CompoundParent = S; + Scopes.back().Begin = I; + } + } + } + } + } else if (BinaryOperator *bop = dyn_cast(child)) { + if (DeclRefExpr *dref = dyn_cast(bop->getLHS())) { + if (VarDecl *VD = dyn_cast(dref->getDecl())) { + // Does this statement follow the pattern: + // pool = [NSAutoreleasePool new]; + if (isNSAutoreleasePool(VD->getType()) && + isPoolCreation(bop->getRHS())) { + Scopes.push_back(PoolScope()); + Scopes.back().PoolVar = VD; + Scopes.back().CompoundParent = S; + Scopes.back().Begin = I; + } + } + } + } + + if (Scopes.empty()) + continue; + + if (isPoolDrain(Scopes.back().PoolVar, child)) { + PoolScope &scope = Scopes.back(); + scope.End = I; + handlePoolScope(scope, S); + Scopes.pop_back(); + } + } + return true; + } + +private: + void clearUnavailableDiags(Stmt *S) { + if (S) + Pass.TA.clearDiagnostic(diag::err_unavailable, + diag::err_unavailable_message, + S->getSourceRange()); + } + + struct PoolScope { + VarDecl *PoolVar; + CompoundStmt *CompoundParent; + Stmt::child_iterator Begin; + Stmt::child_iterator End; + bool IsFollowedBySimpleReturnStmt; + llvm::SmallVector Releases; + + PoolScope() : PoolVar(0), CompoundParent(0), Begin(), End(), + IsFollowedBySimpleReturnStmt(false) { } + + SourceRange getIndentedRange() const { + Stmt::child_iterator rangeS = Begin; + ++rangeS; + if (rangeS == End) + return SourceRange(); + Stmt::child_iterator rangeE = Begin; + for (Stmt::child_iterator I = rangeS; I != End; ++I) + ++rangeE; + return SourceRange((*rangeS)->getLocStart(), (*rangeE)->getLocEnd()); + } + }; + + class NameReferenceChecker : public RecursiveASTVisitor{ + ASTContext &Ctx; + SourceRange ScopeRange; + SourceLocation &referenceLoc, &declarationLoc; + + public: + NameReferenceChecker(ASTContext &ctx, PoolScope &scope, + SourceLocation &referenceLoc, + SourceLocation &declarationLoc) + : Ctx(ctx), referenceLoc(referenceLoc), + declarationLoc(declarationLoc) { + ScopeRange = SourceRange((*scope.Begin)->getLocStart(), + (*scope.End)->getLocStart()); + } + + bool VisitDeclRefExpr(DeclRefExpr *E) { + return checkRef(E->getLocation(), E->getDecl()->getLocation()); + } + + bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { + return checkRef(E->getLocation(), E->getDecl()->getLocation()); + } + + bool VisitTypedefTypeLoc(TypedefTypeLoc TL) { + return checkRef(TL.getBeginLoc(), TL.getTypedefNameDecl()->getLocation()); + } + + bool VisitTagTypeLoc(TagTypeLoc TL) { + return checkRef(TL.getBeginLoc(), TL.getDecl()->getLocation()); + } + + private: + bool checkRef(SourceLocation refLoc, SourceLocation declLoc) { + if (isInScope(declLoc)) { + referenceLoc = refLoc; + declarationLoc = declLoc; + return false; + } + return true; + } + + bool isInScope(SourceLocation loc) { + SourceManager &SM = Ctx.getSourceManager(); + if (SM.isBeforeInTranslationUnit(loc, ScopeRange.getBegin())) + return false; + return SM.isBeforeInTranslationUnit(loc, ScopeRange.getEnd()); + } + }; + + void handlePoolScope(PoolScope &scope, CompoundStmt *compoundS) { + // Check that all names declared inside the scope are not used + // outside the scope. + { + bool nameUsedOutsideScope = false; + SourceLocation referenceLoc, declarationLoc; + Stmt::child_iterator SI = scope.End, SE = compoundS->body_end(); + ++SI; + // Check if the autoreleasepool scope is followed by a simple return + // statement, in which case we will include the return in the scope. + if (SI != SE) + if (ReturnStmt *retS = dyn_cast(*SI)) + if ((retS->getRetValue() == 0 || + isa(retS->getRetValue()->IgnoreParenCasts())) && + findLocationAfterSemi(retS->getLocEnd(), Pass.Ctx).isValid()) { + scope.IsFollowedBySimpleReturnStmt = true; + ++SI; // the return will be included in scope, don't check it. + } + + for (; SI != SE; ++SI) { + nameUsedOutsideScope = !NameReferenceChecker(Pass.Ctx, scope, + referenceLoc, + declarationLoc).TraverseStmt(*SI); + if (nameUsedOutsideScope) + break; + } + + // If not all references were cleared it means some variables/typenames/etc + // declared inside the pool scope are used outside of it. + // We won't try to rewrite the pool. + if (nameUsedOutsideScope) { + Pass.TA.reportError("a name is referenced outside the " + "NSAutoreleasePool scope that it was declared in", referenceLoc); + Pass.TA.reportNote("name declared here", declarationLoc); + Pass.TA.reportNote("intended @autoreleasepool scope begins here", + (*scope.Begin)->getLocStart()); + Pass.TA.reportNote("intended @autoreleasepool scope ends here", + (*scope.End)->getLocStart()); + return; + } + } + + // Collect all releases of the pool; they will be removed. + { + ReleaseCollector releaseColl(scope.PoolVar, scope.Releases); + Stmt::child_iterator I = scope.Begin; + ++I; + for (; I != scope.End; ++I) + releaseColl.TraverseStmt(*I); + } + + PoolVars[scope.PoolVar].Scopes.push_back(scope); + } + + bool isPoolCreation(Expr *E) { + if (!E) return false; + E = getEssential(E); + ObjCMessageExpr *ME = dyn_cast(E); + if (!ME) return false; + if (ME->getMethodFamily() == OMF_new && + ME->getReceiverKind() == ObjCMessageExpr::Class && + isNSAutoreleasePool(ME->getReceiverInterface())) + return true; + if (ME->getReceiverKind() == ObjCMessageExpr::Instance && + ME->getMethodFamily() == OMF_init) { + Expr *rec = getEssential(ME->getInstanceReceiver()); + if (ObjCMessageExpr *recME = dyn_cast_or_null(rec)) { + if (recME->getMethodFamily() == OMF_alloc && + recME->getReceiverKind() == ObjCMessageExpr::Class && + isNSAutoreleasePool(recME->getReceiverInterface())) + return true; + } + } + + return false; + } + + bool isPoolDrain(VarDecl *poolVar, Stmt *S) { + if (!S) return false; + S = getEssential(S); + ObjCMessageExpr *ME = dyn_cast(S); + if (!ME) return false; + if (ME->getReceiverKind() == ObjCMessageExpr::Instance) { + Expr *rec = getEssential(ME->getInstanceReceiver()); + if (DeclRefExpr *dref = dyn_cast(rec)) + if (dref->getDecl() == poolVar) + return ME->getMethodFamily() == OMF_release || + ME->getSelector() == DrainSel; + } + + return false; + } + + bool isNSAutoreleasePool(ObjCInterfaceDecl *IDecl) { + return IDecl && IDecl->getIdentifier() == PoolII; + } + + bool isNSAutoreleasePool(QualType Ty) { + QualType pointee = Ty->getPointeeType(); + if (pointee.isNull()) + return false; + if (const ObjCInterfaceType *interT = pointee->getAs()) + return isNSAutoreleasePool(interT->getDecl()); + return false; + } + + static Expr *getEssential(Expr *E) { + return cast(getEssential((Stmt*)E)); + } + static Stmt *getEssential(Stmt *S) { + if (ExprWithCleanups *EWC = dyn_cast(S)) + S = EWC->getSubExpr(); + if (Expr *E = dyn_cast(S)) + S = E->IgnoreParenCasts(); + return S; + } + + Stmt *Body; + MigrationPass &Pass; + + IdentifierInfo *PoolII; + Selector DrainSel; + + struct PoolVarInfo { + DeclStmt *Dcl; + ExprSet Refs; + llvm::SmallVector Scopes; + + PoolVarInfo() : Dcl(0) { } + }; + + std::map PoolVars; +}; + +} // anonymous namespace + +void trans::rewriteAutoreleasePool(MigrationPass &pass) { + BodyTransform trans(pass); + trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl()); +} diff --git a/lib/ARCMigrate/TransBlockObjCVariable.cpp b/lib/ARCMigrate/TransBlockObjCVariable.cpp new file mode 100644 index 000000000000..0e342b7a8f8c --- /dev/null +++ b/lib/ARCMigrate/TransBlockObjCVariable.cpp @@ -0,0 +1,143 @@ +//===--- TransBlockObjCVariable.cpp - Tranformations to ARC mode ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// rewriteBlockObjCVariable: +// +// Adding __block to an obj-c variable could be either because the the variable +// is used for output storage or the user wanted to break a retain cycle. +// This transformation checks whether a reference of the variable for the block +// is actually needed (it is assigned to or its address is taken) or not. +// If the reference is not needed it will assume __block was added to break a +// cycle so it will remove '__block' and add __weak/__unsafe_unretained. +// e.g +// +// __block Foo *x; +// bar(^ { [x cake]; }); +// ----> +// __weak Foo *x; +// bar(^ { [x cake]; }); +// +//===----------------------------------------------------------------------===// + +#include "Transforms.h" +#include "Internals.h" +#include "clang/Basic/SourceManager.h" + +using namespace clang; +using namespace arcmt; +using namespace trans; +using llvm::StringRef; + +namespace { + +class RootBlockObjCVarRewriter : + public RecursiveASTVisitor { + MigrationPass &Pass; + llvm::DenseSet CheckedVars; + + class BlockVarChecker : public RecursiveASTVisitor { + VarDecl *Var; + + typedef RecursiveASTVisitor base; + public: + BlockVarChecker(VarDecl *var) : Var(var) { } + + bool TraverseImplicitCastExpr(ImplicitCastExpr *castE) { + if (BlockDeclRefExpr * + ref = dyn_cast(castE->getSubExpr())) { + if (ref->getDecl() == Var) { + if (castE->getCastKind() == CK_LValueToRValue) + return true; // Using the value of the variable. + if (castE->getCastKind() == CK_NoOp && castE->isLValue() && + Var->getASTContext().getLangOptions().CPlusPlus) + return true; // Binding to const C++ reference. + } + } + + return base::TraverseImplicitCastExpr(castE); + } + + bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { + if (E->getDecl() == Var) + return false; // The reference of the variable, and not just its value, + // is needed. + return true; + } + }; + +public: + RootBlockObjCVarRewriter(MigrationPass &pass) : Pass(pass) { } + + bool VisitBlockDecl(BlockDecl *block) { + llvm::SmallVector BlockVars; + + for (BlockDecl::capture_iterator + I = block->capture_begin(), E = block->capture_end(); I != E; ++I) { + VarDecl *var = I->getVariable(); + if (I->isByRef() && + !isAlreadyChecked(var) && + var->getType()->isObjCObjectPointerType() && + isImplicitStrong(var->getType())) { + BlockVars.push_back(var); + } + } + + for (unsigned i = 0, e = BlockVars.size(); i != e; ++i) { + VarDecl *var = BlockVars[i]; + CheckedVars.insert(var); + + BlockVarChecker checker(var); + bool onlyValueOfVarIsNeeded = checker.TraverseStmt(block->getBody()); + if (onlyValueOfVarIsNeeded) { + BlocksAttr *attr = var->getAttr(); + if(!attr) + continue; + bool useWeak = canApplyWeak(Pass.Ctx, var->getType()); + SourceManager &SM = Pass.Ctx.getSourceManager(); + Transaction Trans(Pass.TA); + Pass.TA.replaceText(SM.getInstantiationLoc(attr->getLocation()), + "__block", + useWeak ? "__weak" : "__unsafe_unretained"); + } + + } + + return true; + } + +private: + bool isAlreadyChecked(VarDecl *VD) { + return CheckedVars.count(VD); + } + + bool isImplicitStrong(QualType ty) { + if (isa(ty.getTypePtr())) + return false; + return ty.getLocalQualifiers().getObjCLifetime() == Qualifiers::OCL_Strong; + } +}; + +class BlockObjCVarRewriter : public RecursiveASTVisitor { + MigrationPass &Pass; + +public: + BlockObjCVarRewriter(MigrationPass &pass) : Pass(pass) { } + + bool TraverseBlockDecl(BlockDecl *block) { + RootBlockObjCVarRewriter(Pass).TraverseDecl(block); + return true; + } +}; + +} // anonymous namespace + +void trans::rewriteBlockObjCVariable(MigrationPass &pass) { + BlockObjCVarRewriter trans(pass); + trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl()); +} diff --git a/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp b/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp new file mode 100644 index 000000000000..d0bc332ff160 --- /dev/null +++ b/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp @@ -0,0 +1,211 @@ +//===--- TransEmptyStatements.cpp - Tranformations to ARC mode ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// removeEmptyStatementsAndDealloc: +// +// Removes empty statements that are leftovers from previous transformations. +// e.g for +// +// [x retain]; +// +// removeRetainReleaseDealloc will leave an empty ";" that removeEmptyStatements +// will remove. +// +//===----------------------------------------------------------------------===// + +#include "Transforms.h" +#include "Internals.h" +#include "clang/AST/StmtVisitor.h" + +using namespace clang; +using namespace arcmt; +using namespace trans; +using llvm::StringRef; + +namespace { + +/// \brief Returns true if the statement became empty due to previous +/// transformations. +class EmptyChecker : public StmtVisitor { + ASTContext &Ctx; + llvm::DenseSet &MacroLocs; + +public: + EmptyChecker(ASTContext &ctx, llvm::DenseSet ¯oLocs) + : Ctx(ctx), MacroLocs(macroLocs) { } + + bool VisitNullStmt(NullStmt *S) { + return isMacroLoc(S->getLeadingEmptyMacroLoc()); + } + bool VisitCompoundStmt(CompoundStmt *S) { + if (S->body_empty()) + return false; // was already empty, not because of transformations. + for (CompoundStmt::body_iterator + I = S->body_begin(), E = S->body_end(); I != E; ++I) + if (!Visit(*I)) + return false; + return true; + } + bool VisitIfStmt(IfStmt *S) { + if (S->getConditionVariable()) + return false; + Expr *condE = S->getCond(); + if (!condE) + return false; + if (hasSideEffects(condE, Ctx)) + return false; + if (!S->getThen() || !Visit(S->getThen())) + return false; + if (S->getElse() && !Visit(S->getElse())) + return false; + return true; + } + bool VisitWhileStmt(WhileStmt *S) { + if (S->getConditionVariable()) + return false; + Expr *condE = S->getCond(); + if (!condE) + return false; + if (hasSideEffects(condE, Ctx)) + return false; + if (!S->getBody()) + return false; + return Visit(S->getBody()); + } + bool VisitDoStmt(DoStmt *S) { + Expr *condE = S->getCond(); + if (!condE) + return false; + if (hasSideEffects(condE, Ctx)) + return false; + if (!S->getBody()) + return false; + return Visit(S->getBody()); + } + bool VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) { + Expr *Exp = S->getCollection(); + if (!Exp) + return false; + if (hasSideEffects(Exp, Ctx)) + return false; + if (!S->getBody()) + return false; + return Visit(S->getBody()); + } + bool VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) { + if (!S->getSubStmt()) + return false; + return Visit(S->getSubStmt()); + } + +private: + bool isMacroLoc(SourceLocation loc) { + if (loc.isInvalid()) return false; + return MacroLocs.count(loc.getRawEncoding()); + } +}; + +class EmptyStatementsRemover : + public RecursiveASTVisitor { + MigrationPass &Pass; + llvm::DenseSet &MacroLocs; + +public: + EmptyStatementsRemover(MigrationPass &pass, + llvm::DenseSet ¯oLocs) + : Pass(pass), MacroLocs(macroLocs) { } + + bool TraverseStmtExpr(StmtExpr *E) { + CompoundStmt *S = E->getSubStmt(); + for (CompoundStmt::body_iterator + I = S->body_begin(), E = S->body_end(); I != E; ++I) { + if (I != E - 1) + check(*I); + TraverseStmt(*I); + } + return true; + } + + bool VisitCompoundStmt(CompoundStmt *S) { + for (CompoundStmt::body_iterator + I = S->body_begin(), E = S->body_end(); I != E; ++I) + check(*I); + return true; + } + + bool isMacroLoc(SourceLocation loc) { + if (loc.isInvalid()) return false; + return MacroLocs.count(loc.getRawEncoding()); + } + + ASTContext &getContext() { return Pass.Ctx; } + +private: + void check(Stmt *S) { + if (!S) return; + if (EmptyChecker(Pass.Ctx, MacroLocs).Visit(S)) { + Transaction Trans(Pass.TA); + Pass.TA.removeStmt(S); + } + } +}; + +} // anonymous namespace + +static bool isBodyEmpty(CompoundStmt *body, + ASTContext &Ctx, llvm::DenseSet &MacroLocs) { + for (CompoundStmt::body_iterator + I = body->body_begin(), E = body->body_end(); I != E; ++I) + if (!EmptyChecker(Ctx, MacroLocs).Visit(*I)) + return false; + + return true; +} + +static void removeDeallocMethod(MigrationPass &pass, + llvm::DenseSet &MacroLocs) { + ASTContext &Ctx = pass.Ctx; + TransformActions &TA = pass.TA; + DeclContext *DC = Ctx.getTranslationUnitDecl(); + + typedef DeclContext::specific_decl_iterator + impl_iterator; + for (impl_iterator I = impl_iterator(DC->decls_begin()), + E = impl_iterator(DC->decls_end()); I != E; ++I) { + for (ObjCImplementationDecl::instmeth_iterator + MI = (*I)->instmeth_begin(), + ME = (*I)->instmeth_end(); MI != ME; ++MI) { + ObjCMethodDecl *MD = *MI; + if (MD->getMethodFamily() == OMF_dealloc) { + if (MD->hasBody() && + isBodyEmpty(MD->getCompoundBody(), Ctx, MacroLocs)) { + Transaction Trans(TA); + TA.remove(MD->getSourceRange()); + } + break; + } + } + } +} + +void trans::removeEmptyStatementsAndDealloc(MigrationPass &pass) { + llvm::DenseSet MacroLocs; + for (unsigned i = 0, e = pass.ARCMTMacroLocs.size(); i != e; ++i) + MacroLocs.insert(pass.ARCMTMacroLocs[i].getRawEncoding()); + + EmptyStatementsRemover(pass, MacroLocs) + .TraverseDecl(pass.Ctx.getTranslationUnitDecl()); + + removeDeallocMethod(pass, MacroLocs); + + for (unsigned i = 0, e = pass.ARCMTMacroLocs.size(); i != e; ++i) { + Transaction Trans(pass.TA); + pass.TA.remove(pass.ARCMTMacroLocs[i]); + } +} diff --git a/lib/ARCMigrate/TransProperties.cpp b/lib/ARCMigrate/TransProperties.cpp new file mode 100644 index 000000000000..872c95e1a444 --- /dev/null +++ b/lib/ARCMigrate/TransProperties.cpp @@ -0,0 +1,364 @@ +//===--- TransProperties.cpp - Tranformations to ARC mode -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// rewriteProperties: +// +// - Adds strong/weak/unsafe_unretained ownership specifier to properties that +// are missing one. +// - Migrates properties from (retain) to (strong) and (assign) to +// (unsafe_unretained/weak). +// - If a property is synthesized, adds the ownership specifier in the ivar +// backing the property. +// +// @interface Foo : NSObject { +// NSObject *x; +// } +// @property (assign) id x; +// @end +// ----> +// @interface Foo : NSObject { +// NSObject *__weak x; +// } +// @property (weak) id x; +// @end +// +//===----------------------------------------------------------------------===// + +#include "Transforms.h" +#include "Internals.h" +#include "clang/Sema/SemaDiagnostic.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Lex/Lexer.h" +#include + +using namespace clang; +using namespace arcmt; +using namespace trans; +using llvm::StringRef; + +namespace { + +class PropertiesRewriter { + MigrationPass &Pass; + + struct PropData { + ObjCPropertyDecl *PropD; + ObjCIvarDecl *IvarD; + ObjCPropertyImplDecl *ImplD; + + PropData(ObjCPropertyDecl *propD) : PropD(propD), IvarD(0), ImplD(0) { } + }; + + typedef llvm::SmallVector PropsTy; + typedef std::map AtPropDeclsTy; + AtPropDeclsTy AtProps; + +public: + PropertiesRewriter(MigrationPass &pass) : Pass(pass) { } + + void doTransform(ObjCImplementationDecl *D) { + ObjCInterfaceDecl *iface = D->getClassInterface(); + if (!iface) + return; + + for (ObjCInterfaceDecl::prop_iterator + propI = iface->prop_begin(), + propE = iface->prop_end(); propI != propE; ++propI) { + if (propI->getAtLoc().isInvalid()) + continue; + PropsTy &props = AtProps[propI->getAtLoc().getRawEncoding()]; + props.push_back(*propI); + } + + typedef DeclContext::specific_decl_iterator + prop_impl_iterator; + for (prop_impl_iterator + I = prop_impl_iterator(D->decls_begin()), + E = prop_impl_iterator(D->decls_end()); I != E; ++I) { + ObjCPropertyImplDecl *implD = *I; + if (implD->getPropertyImplementation() != ObjCPropertyImplDecl::Synthesize) + continue; + ObjCPropertyDecl *propD = implD->getPropertyDecl(); + if (!propD || propD->isInvalidDecl()) + continue; + ObjCIvarDecl *ivarD = implD->getPropertyIvarDecl(); + if (!ivarD || ivarD->isInvalidDecl()) + continue; + unsigned rawAtLoc = propD->getAtLoc().getRawEncoding(); + AtPropDeclsTy::iterator findAtLoc = AtProps.find(rawAtLoc); + if (findAtLoc == AtProps.end()) + continue; + + PropsTy &props = findAtLoc->second; + for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) { + if (I->PropD == propD) { + I->IvarD = ivarD; + I->ImplD = implD; + break; + } + } + } + + for (AtPropDeclsTy::iterator + I = AtProps.begin(), E = AtProps.end(); I != E; ++I) { + SourceLocation atLoc = SourceLocation::getFromRawEncoding(I->first); + PropsTy &props = I->second; + QualType ty = getPropertyType(props); + if (!ty->isObjCRetainableType()) + continue; + if (hasIvarWithExplicitOwnership(props)) + continue; + + Transaction Trans(Pass.TA); + rewriteProperty(props, atLoc); + } + } + +private: + void rewriteProperty(PropsTy &props, SourceLocation atLoc) const { + ObjCPropertyDecl::PropertyAttributeKind propAttrs = getPropertyAttrs(props); + + if (propAttrs & (ObjCPropertyDecl::OBJC_PR_copy | + ObjCPropertyDecl::OBJC_PR_unsafe_unretained | + ObjCPropertyDecl::OBJC_PR_strong | + ObjCPropertyDecl::OBJC_PR_weak)) + return; + + if (propAttrs & ObjCPropertyDecl::OBJC_PR_retain) { + rewriteAttribute("retain", "strong", atLoc); + return; + } + + if (propAttrs & ObjCPropertyDecl::OBJC_PR_assign) + return rewriteAssign(props, atLoc); + + return maybeAddWeakOrUnsafeUnretainedAttr(props, atLoc); + } + + void rewriteAssign(PropsTy &props, SourceLocation atLoc) const { + bool canUseWeak = canApplyWeak(Pass.Ctx, getPropertyType(props)); + + bool rewroteAttr = rewriteAttribute("assign", + canUseWeak ? "weak" : "unsafe_unretained", + atLoc); + if (!rewroteAttr) + canUseWeak = false; + + for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) { + if (isUserDeclared(I->IvarD)) + Pass.TA.insert(I->IvarD->getLocation(), + canUseWeak ? "__weak " : "__unsafe_unretained "); + if (I->ImplD) + Pass.TA.clearDiagnostic(diag::err_arc_assign_property_ownership, + I->ImplD->getLocation()); + } + } + + void maybeAddWeakOrUnsafeUnretainedAttr(PropsTy &props, + SourceLocation atLoc) const { + ObjCPropertyDecl::PropertyAttributeKind propAttrs = getPropertyAttrs(props); + if ((propAttrs & ObjCPropertyDecl::OBJC_PR_readonly) && + hasNoBackingIvars(props)) + return; + + bool canUseWeak = canApplyWeak(Pass.Ctx, getPropertyType(props)); + bool addedAttr = addAttribute(canUseWeak ? "weak" : "unsafe_unretained", + atLoc); + if (!addedAttr) + canUseWeak = false; + + for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) { + if (isUserDeclared(I->IvarD)) + Pass.TA.insert(I->IvarD->getLocation(), + canUseWeak ? "__weak " : "__unsafe_unretained "); + if (I->ImplD) { + Pass.TA.clearDiagnostic(diag::err_arc_assign_property_ownership, + I->ImplD->getLocation()); + Pass.TA.clearDiagnostic( + diag::err_arc_objc_property_default_assign_on_object, + I->ImplD->getLocation()); + } + } + } + + bool rewriteAttribute(llvm::StringRef fromAttr, llvm::StringRef toAttr, + SourceLocation atLoc) const { + if (atLoc.isMacroID()) + return false; + + SourceManager &SM = Pass.Ctx.getSourceManager(); + + // Break down the source location. + std::pair locInfo = SM.getDecomposedLoc(atLoc); + + // Try to load the file buffer. + bool invalidTemp = false; + llvm::StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); + if (invalidTemp) + return false; + + const char *tokenBegin = file.data() + locInfo.second; + + // Lex from the start of the given location. + Lexer lexer(SM.getLocForStartOfFile(locInfo.first), + Pass.Ctx.getLangOptions(), + file.begin(), tokenBegin, file.end()); + Token tok; + lexer.LexFromRawLexer(tok); + if (tok.isNot(tok::at)) return false; + lexer.LexFromRawLexer(tok); + if (tok.isNot(tok::raw_identifier)) return false; + if (llvm::StringRef(tok.getRawIdentifierData(), tok.getLength()) + != "property") + return false; + lexer.LexFromRawLexer(tok); + if (tok.isNot(tok::l_paren)) return false; + + lexer.LexFromRawLexer(tok); + if (tok.is(tok::r_paren)) + return false; + + while (1) { + if (tok.isNot(tok::raw_identifier)) return false; + llvm::StringRef ident(tok.getRawIdentifierData(), tok.getLength()); + if (ident == fromAttr) { + Pass.TA.replaceText(tok.getLocation(), fromAttr, toAttr); + return true; + } + + do { + lexer.LexFromRawLexer(tok); + } while (tok.isNot(tok::comma) && tok.isNot(tok::r_paren)); + if (tok.is(tok::r_paren)) + break; + lexer.LexFromRawLexer(tok); + } + + return false; + } + + bool addAttribute(llvm::StringRef attr, SourceLocation atLoc) const { + if (atLoc.isMacroID()) + return false; + + SourceManager &SM = Pass.Ctx.getSourceManager(); + + // Break down the source location. + std::pair locInfo = SM.getDecomposedLoc(atLoc); + + // Try to load the file buffer. + bool invalidTemp = false; + llvm::StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); + if (invalidTemp) + return false; + + const char *tokenBegin = file.data() + locInfo.second; + + // Lex from the start of the given location. + Lexer lexer(SM.getLocForStartOfFile(locInfo.first), + Pass.Ctx.getLangOptions(), + file.begin(), tokenBegin, file.end()); + Token tok; + lexer.LexFromRawLexer(tok); + if (tok.isNot(tok::at)) return false; + lexer.LexFromRawLexer(tok); + if (tok.isNot(tok::raw_identifier)) return false; + if (llvm::StringRef(tok.getRawIdentifierData(), tok.getLength()) + != "property") + return false; + lexer.LexFromRawLexer(tok); + + if (tok.isNot(tok::l_paren)) { + Pass.TA.insert(tok.getLocation(), std::string("(") + attr.str() + ") "); + return true; + } + + lexer.LexFromRawLexer(tok); + if (tok.is(tok::r_paren)) { + Pass.TA.insert(tok.getLocation(), attr); + return true; + } + + if (tok.isNot(tok::raw_identifier)) return false; + + Pass.TA.insert(tok.getLocation(), std::string(attr) + ", "); + return true; + } + + bool hasIvarWithExplicitOwnership(PropsTy &props) const { + for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) { + if (isUserDeclared(I->IvarD)) { + if (isa(I->IvarD->getType())) + return true; + if (I->IvarD->getType().getLocalQualifiers().getObjCLifetime() + != Qualifiers::OCL_Strong) + return true; + } + } + + return false; + } + + bool hasNoBackingIvars(PropsTy &props) const { + for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) + if (I->IvarD) + return false; + + return true; + } + + bool isUserDeclared(ObjCIvarDecl *ivarD) const { + return ivarD && !ivarD->getSynthesize(); + } + + QualType getPropertyType(PropsTy &props) const { + assert(!props.empty()); + QualType ty = props[0].PropD->getType(); + +#ifndef NDEBUG + for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) + assert(ty == I->PropD->getType()); +#endif + + return ty; + } + + ObjCPropertyDecl::PropertyAttributeKind + getPropertyAttrs(PropsTy &props) const { + assert(!props.empty()); + ObjCPropertyDecl::PropertyAttributeKind + attrs = props[0].PropD->getPropertyAttributesAsWritten(); + +#ifndef NDEBUG + for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) + assert(attrs == I->PropD->getPropertyAttributesAsWritten()); +#endif + + return attrs; + } +}; + +class ImplementationChecker : + public RecursiveASTVisitor { + MigrationPass &Pass; + +public: + ImplementationChecker(MigrationPass &pass) : Pass(pass) { } + + bool TraverseObjCImplementationDecl(ObjCImplementationDecl *D) { + PropertiesRewriter(Pass).doTransform(D); + return true; + } +}; + +} // anonymous namespace + +void trans::rewriteProperties(MigrationPass &pass) { + ImplementationChecker(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl()); +} diff --git a/lib/ARCMigrate/TransRetainReleaseDealloc.cpp b/lib/ARCMigrate/TransRetainReleaseDealloc.cpp new file mode 100644 index 000000000000..ed6ed0adfdf2 --- /dev/null +++ b/lib/ARCMigrate/TransRetainReleaseDealloc.cpp @@ -0,0 +1,219 @@ +//===--- TransRetainReleaseDealloc.cpp - Tranformations to ARC mode -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// removeRetainReleaseDealloc: +// +// Removes retain/release/autorelease/dealloc messages. +// +// return [[foo retain] autorelease]; +// ----> +// return foo; +// +//===----------------------------------------------------------------------===// + +#include "Transforms.h" +#include "Internals.h" +#include "clang/Sema/SemaDiagnostic.h" +#include "clang/AST/ParentMap.h" + +using namespace clang; +using namespace arcmt; +using namespace trans; +using llvm::StringRef; + +namespace { + +class RetainReleaseDeallocRemover : + public RecursiveASTVisitor { + Stmt *Body; + MigrationPass &Pass; + + ExprSet Removables; + llvm::OwningPtr StmtMap; + + Selector DelegateSel; + +public: + RetainReleaseDeallocRemover(MigrationPass &pass) + : Body(0), Pass(pass) { + DelegateSel = + Pass.Ctx.Selectors.getNullarySelector(&Pass.Ctx.Idents.get("delegate")); + } + + void transformBody(Stmt *body) { + Body = body; + collectRemovables(body, Removables); + StmtMap.reset(new ParentMap(body)); + TraverseStmt(body); + } + + bool VisitObjCMessageExpr(ObjCMessageExpr *E) { + switch (E->getMethodFamily()) { + default: + return true; + case OMF_autorelease: + if (isRemovable(E)) { + // An unused autorelease is badness. If we remove it the receiver + // will likely die immediately while previously it was kept alive + // by the autorelease pool. This is bad practice in general, leave it + // and emit an error to force the user to restructure his code. + Pass.TA.reportError("it is not safe to remove an unused 'autorelease' " + "message; its receiver may be destroyed immediately", + E->getLocStart(), E->getSourceRange()); + return true; + } + // Pass through. + case OMF_retain: + case OMF_release: + if (E->getReceiverKind() == ObjCMessageExpr::Instance) + if (Expr *rec = E->getInstanceReceiver()) { + rec = rec->IgnoreParenImpCasts(); + if (rec->getType().getObjCLifetime() == Qualifiers::OCL_ExplicitNone && + (E->getMethodFamily() != OMF_retain || isRemovable(E))) { + std::string err = "it is not safe to remove '"; + err += E->getSelector().getAsString() + "' message on " + "an __unsafe_unretained type"; + Pass.TA.reportError(err, rec->getLocStart()); + return true; + } + + if (isGlobalVar(rec) && + (E->getMethodFamily() != OMF_retain || isRemovable(E))) { + std::string err = "it is not safe to remove '"; + err += E->getSelector().getAsString() + "' message on " + "a global variable"; + Pass.TA.reportError(err, rec->getLocStart()); + return true; + } + + if (E->getMethodFamily() == OMF_release && isDelegateMessage(rec)) { + Pass.TA.reportError("it is not safe to remove 'retain' " + "message on the result of a 'delegate' message; " + "the object that was passed to 'setDelegate:' may not be " + "properly retained", rec->getLocStart()); + return true; + } + } + case OMF_dealloc: + break; + } + + switch (E->getReceiverKind()) { + default: + return true; + case ObjCMessageExpr::SuperInstance: { + Transaction Trans(Pass.TA); + clearDiagnostics(E->getSuperLoc()); + if (tryRemoving(E)) + return true; + Pass.TA.replace(E->getSourceRange(), "self"); + return true; + } + case ObjCMessageExpr::Instance: + break; + } + + Expr *rec = E->getInstanceReceiver(); + if (!rec) return true; + + Transaction Trans(Pass.TA); + clearDiagnostics(rec->getExprLoc()); + + if (E->getMethodFamily() == OMF_release && + isRemovable(E) && isInAtFinally(E)) { + // Change the -release to "receiver = nil" in a finally to avoid a leak + // when an exception is thrown. + Pass.TA.replace(E->getSourceRange(), rec->getSourceRange()); + if (Pass.Ctx.Idents.get("nil").hasMacroDefinition()) + Pass.TA.insertAfterToken(rec->getLocEnd(), " = nil"); + else + Pass.TA.insertAfterToken(rec->getLocEnd(), " = 0"); + return true; + } + + if (!hasSideEffects(E, Pass.Ctx)) { + if (tryRemoving(E)) + return true; + } + Pass.TA.replace(E->getSourceRange(), rec->getSourceRange()); + + return true; + } + +private: + void clearDiagnostics(SourceLocation loc) const { + Pass.TA.clearDiagnostic(diag::err_arc_illegal_explicit_message, + diag::err_unavailable, + diag::err_unavailable_message, + loc); + } + + bool isDelegateMessage(Expr *E) const { + if (!E) return false; + + E = E->IgnoreParenCasts(); + if (ObjCMessageExpr *ME = dyn_cast(E)) + return (ME->isInstanceMessage() && ME->getSelector() == DelegateSel); + + if (ObjCPropertyRefExpr *propE = dyn_cast(E)) + return propE->getGetterSelector() == DelegateSel; + + return false; + } + + bool isInAtFinally(Expr *E) const { + assert(E); + Stmt *S = E; + while (S) { + if (isa(S)) + return true; + S = StmtMap->getParent(S); + } + + return false; + } + + bool isRemovable(Expr *E) const { + return Removables.count(E); + } + + bool tryRemoving(Expr *E) const { + if (isRemovable(E)) { + Pass.TA.removeStmt(E); + return true; + } + + Stmt *parent = StmtMap->getParent(E); + + if (ImplicitCastExpr *castE = dyn_cast_or_null(parent)) + return tryRemoving(castE); + + if (ParenExpr *parenE = dyn_cast_or_null(parent)) + return tryRemoving(parenE); + + if (BinaryOperator * + bopE = dyn_cast_or_null(parent)) { + if (bopE->getOpcode() == BO_Comma && bopE->getLHS() == E && + isRemovable(bopE)) { + Pass.TA.replace(bopE->getSourceRange(), bopE->getRHS()->getSourceRange()); + return true; + } + } + + return false; + } + +}; + +} // anonymous namespace + +void trans::removeRetainReleaseDealloc(MigrationPass &pass) { + BodyTransform trans(pass); + trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl()); +} diff --git a/lib/ARCMigrate/TransUnbridgedCasts.cpp b/lib/ARCMigrate/TransUnbridgedCasts.cpp new file mode 100644 index 000000000000..1cacd6d84e6d --- /dev/null +++ b/lib/ARCMigrate/TransUnbridgedCasts.cpp @@ -0,0 +1,203 @@ +//===--- TransUnbridgedCasts.cpp - Tranformations to ARC mode -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// rewriteUnbridgedCasts: +// +// A cast of non-objc pointer to an objc one is checked. If the non-objc pointer +// is from a file-level variable, __bridge cast is used to convert it. +// For the result of a function call that we know is +1/+0, +// __bridge/__bridge_transfer is used. +// +// NSString *str = (NSString *)kUTTypePlainText; +// str = b ? kUTTypeRTF : kUTTypePlainText; +// NSString *_uuidString = (NSString *)CFUUIDCreateString(kCFAllocatorDefault, +// _uuid); +// ----> +// NSString *str = (__bridge NSString *)kUTTypePlainText; +// str = (__bridge NSString *)(b ? kUTTypeRTF : kUTTypePlainText); +// NSString *_uuidString = (__bridge_transfer NSString *) +// CFUUIDCreateString(kCFAllocatorDefault, _uuid); +// +// For a C pointer to ObjC, for casting 'self', __bridge is used. +// +// CFStringRef str = (CFStringRef)self; +// ----> +// CFStringRef str = (__bridge CFStringRef)self; +// +//===----------------------------------------------------------------------===// + +#include "Transforms.h" +#include "Internals.h" +#include "clang/Analysis/DomainSpecific/CocoaConventions.h" +#include "clang/Sema/SemaDiagnostic.h" +#include "clang/Basic/SourceManager.h" + +using namespace clang; +using namespace arcmt; +using namespace trans; +using llvm::StringRef; + +namespace { + +class UnbridgedCastRewriter : public RecursiveASTVisitor{ + MigrationPass &Pass; + IdentifierInfo *SelfII; +public: + UnbridgedCastRewriter(MigrationPass &pass) : Pass(pass) { + SelfII = &Pass.Ctx.Idents.get("self"); + } + + bool VisitCastExpr(CastExpr *E) { + if (E->getCastKind() != CK_AnyPointerToObjCPointerCast + && E->getCastKind() != CK_BitCast) + return true; + + QualType castType = E->getType(); + Expr *castExpr = E->getSubExpr(); + QualType castExprType = castExpr->getType(); + + if (castType->isObjCObjectPointerType() && + castExprType->isObjCObjectPointerType()) + return true; + if (!castType->isObjCObjectPointerType() && + !castExprType->isObjCObjectPointerType()) + return true; + + bool exprRetainable = castExprType->isObjCIndirectLifetimeType(); + bool castRetainable = castType->isObjCIndirectLifetimeType(); + if (exprRetainable == castRetainable) return true; + + if (castExpr->isNullPointerConstant(Pass.Ctx, + Expr::NPC_ValueDependentIsNull)) + return true; + + SourceLocation loc = castExpr->getExprLoc(); + if (loc.isValid() && Pass.Ctx.getSourceManager().isInSystemHeader(loc)) + return true; + + if (castType->isObjCObjectPointerType()) + transformNonObjCToObjCCast(E); + else + transformObjCToNonObjCCast(E); + + return true; + } + +private: + void transformNonObjCToObjCCast(CastExpr *E) { + if (!E) return; + + // Global vars are assumed that are cast as unretained. + if (isGlobalVar(E)) + if (E->getSubExpr()->getType()->isPointerType()) { + castToObjCObject(E, /*retained=*/false); + return; + } + + // If the cast is directly over the result of a Core Foundation function + // try to figure out whether it should be cast as retained or unretained. + Expr *inner = E->IgnoreParenCasts(); + if (CallExpr *callE = dyn_cast(inner)) { + if (FunctionDecl *FD = callE->getDirectCallee()) { + if (FD->getAttr()) { + castToObjCObject(E, /*retained=*/true); + return; + } + if (FD->getAttr()) { + castToObjCObject(E, /*retained=*/false); + return; + } + if (FD->isGlobal() && + FD->getIdentifier() && + ento::cocoa::isRefType(E->getSubExpr()->getType(), "CF", + FD->getIdentifier()->getName())) { + StringRef fname = FD->getIdentifier()->getName(); + if (fname.endswith("Retain") || + fname.find("Create") != StringRef::npos || + fname.find("Copy") != StringRef::npos) { + castToObjCObject(E, /*retained=*/true); + return; + } + + if (fname.find("Get") != StringRef::npos) { + castToObjCObject(E, /*retained=*/false); + return; + } + } + } + } + } + + void castToObjCObject(CastExpr *E, bool retained) { + rewriteToBridgedCast(E, retained ? OBC_BridgeTransfer : OBC_Bridge); + } + + void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind) { + TransformActions &TA = Pass.TA; + + // We will remove the compiler diagnostic. + if (!TA.hasDiagnostic(diag::err_arc_mismatched_cast, + diag::err_arc_cast_requires_bridge, + E->getLocStart())) + return; + + StringRef bridge; + switch(Kind) { + case OBC_Bridge: + bridge = "__bridge "; break; + case OBC_BridgeTransfer: + bridge = "__bridge_transfer "; break; + case OBC_BridgeRetained: + bridge = "__bridge_retained "; break; + } + + Transaction Trans(TA); + TA.clearDiagnostic(diag::err_arc_mismatched_cast, + diag::err_arc_cast_requires_bridge, + E->getLocStart()); + if (CStyleCastExpr *CCE = dyn_cast(E)) { + TA.insertAfterToken(CCE->getLParenLoc(), bridge); + } else { + SourceLocation insertLoc = E->getSubExpr()->getLocStart(); + llvm::SmallString<128> newCast; + newCast += '('; + newCast += bridge; + newCast += E->getType().getAsString(Pass.Ctx.PrintingPolicy); + newCast += ')'; + + if (isa(E->getSubExpr())) { + TA.insert(insertLoc, newCast.str()); + } else { + newCast += '('; + TA.insert(insertLoc, newCast.str()); + TA.insertAfterToken(E->getLocEnd(), ")"); + } + } + } + + void transformObjCToNonObjCCast(CastExpr *E) { + if (isSelf(E->getSubExpr())) + return rewriteToBridgedCast(E, OBC_Bridge); + } + + bool isSelf(Expr *E) { + E = E->IgnoreParenLValueCasts(); + if (DeclRefExpr *DRE = dyn_cast(E)) + if (DRE->getDecl()->getIdentifier() == SelfII) + return true; + return false; + } +}; + +} // end anonymous namespace + +void trans::rewriteUnbridgedCasts(MigrationPass &pass) { + UnbridgedCastRewriter trans(pass); + trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl()); +} diff --git a/lib/ARCMigrate/TransUnusedInitDelegate.cpp b/lib/ARCMigrate/TransUnusedInitDelegate.cpp new file mode 100644 index 000000000000..1019ab4ff1f6 --- /dev/null +++ b/lib/ARCMigrate/TransUnusedInitDelegate.cpp @@ -0,0 +1,74 @@ +//===--- TransUnusedInitDelegate.cpp - Tranformations to ARC mode ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Transformations: +//===----------------------------------------------------------------------===// +// +// rewriteUnusedInitDelegate: +// +// Rewrites an unused result of calling a delegate initialization, to assigning +// the result to self. +// e.g +// [self init]; +// ----> +// self = [self init]; +// +//===----------------------------------------------------------------------===// + +#include "Transforms.h" +#include "Internals.h" +#include "clang/Sema/SemaDiagnostic.h" + +using namespace clang; +using namespace arcmt; +using namespace trans; +using llvm::StringRef; + +namespace { + +class UnusedInitRewriter : public RecursiveASTVisitor { + Stmt *Body; + MigrationPass &Pass; + + ExprSet Removables; + +public: + UnusedInitRewriter(MigrationPass &pass) + : Body(0), Pass(pass) { } + + void transformBody(Stmt *body) { + Body = body; + collectRemovables(body, Removables); + TraverseStmt(body); + } + + bool VisitObjCMessageExpr(ObjCMessageExpr *ME) { + if (ME->isDelegateInitCall() && + isRemovable(ME) && + Pass.TA.hasDiagnostic(diag::err_arc_unused_init_message, + ME->getExprLoc())) { + Transaction Trans(Pass.TA); + Pass.TA.clearDiagnostic(diag::err_arc_unused_init_message, + ME->getExprLoc()); + Pass.TA.insert(ME->getExprLoc(), "self = "); + } + return true; + } + +private: + bool isRemovable(Expr *E) const { + return Removables.count(E); + } +}; + +} // anonymous namespace + +void trans::rewriteUnusedInitDelegate(MigrationPass &pass) { + BodyTransform trans(pass); + trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl()); +} diff --git a/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp b/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp new file mode 100644 index 000000000000..07ccf70d4dfb --- /dev/null +++ b/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp @@ -0,0 +1,198 @@ +//===--- TransZeroOutPropsInDealloc.cpp - Tranformations to ARC mode ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// removeZeroOutPropsInDealloc: +// +// Removes zero'ing out "strong" @synthesized properties in a -dealloc method. +// +//===----------------------------------------------------------------------===// + +#include "Transforms.h" +#include "Internals.h" + +using namespace clang; +using namespace arcmt; +using namespace trans; +using llvm::StringRef; + +namespace { + +class ZeroOutInDeallocRemover : + public RecursiveASTVisitor { + typedef RecursiveASTVisitor base; + + MigrationPass &Pass; + + llvm::DenseMap SynthesizedProperties; + ImplicitParamDecl *SelfD; + ExprSet Removables; + +public: + ZeroOutInDeallocRemover(MigrationPass &pass) : Pass(pass), SelfD(0) { } + + bool VisitObjCMessageExpr(ObjCMessageExpr *ME) { + ASTContext &Ctx = Pass.Ctx; + TransformActions &TA = Pass.TA; + + if (ME->getReceiverKind() != ObjCMessageExpr::Instance) + return true; + Expr *receiver = ME->getInstanceReceiver(); + if (!receiver) + return true; + + DeclRefExpr *refE = dyn_cast(receiver->IgnoreParenCasts()); + if (!refE || refE->getDecl() != SelfD) + return true; + + bool BackedBySynthesizeSetter = false; + for (llvm::DenseMap::iterator + P = SynthesizedProperties.begin(), + E = SynthesizedProperties.end(); P != E; ++P) { + ObjCPropertyDecl *PropDecl = P->first; + if (PropDecl->getSetterName() == ME->getSelector()) { + BackedBySynthesizeSetter = true; + break; + } + } + if (!BackedBySynthesizeSetter) + return true; + + // Remove the setter message if RHS is null + Transaction Trans(TA); + Expr *RHS = ME->getArg(0); + bool RHSIsNull = + RHS->isNullPointerConstant(Ctx, + Expr::NPC_ValueDependentIsNull); + if (RHSIsNull && isRemovable(ME)) + TA.removeStmt(ME); + + return true; + } + + bool VisitBinaryOperator(BinaryOperator *BOE) { + if (isZeroingPropIvar(BOE) && isRemovable(BOE)) { + Transaction Trans(Pass.TA); + Pass.TA.removeStmt(BOE); + } + + return true; + } + + bool TraverseObjCMethodDecl(ObjCMethodDecl *D) { + if (D->getMethodFamily() != OMF_dealloc) + return true; + if (!D->hasBody()) + return true; + + ObjCImplDecl *IMD = dyn_cast(D->getDeclContext()); + if (!IMD) + return true; + + SelfD = D->getSelfDecl(); + collectRemovables(D->getBody(), Removables); + + // For a 'dealloc' method use, find all property implementations in + // this class implementation. + for (ObjCImplDecl::propimpl_iterator + I = IMD->propimpl_begin(), EI = IMD->propimpl_end(); I != EI; ++I) { + ObjCPropertyImplDecl *PID = *I; + if (PID->getPropertyImplementation() == + ObjCPropertyImplDecl::Synthesize) { + ObjCPropertyDecl *PD = PID->getPropertyDecl(); + ObjCMethodDecl *setterM = PD->getSetterMethodDecl(); + if (!(setterM && setterM->isDefined())) { + ObjCPropertyDecl::PropertyAttributeKind AttrKind = + PD->getPropertyAttributes(); + if (AttrKind & + (ObjCPropertyDecl::OBJC_PR_retain | + ObjCPropertyDecl::OBJC_PR_copy | + ObjCPropertyDecl::OBJC_PR_strong)) + SynthesizedProperties[PD] = PID; + } + } + } + + // Now, remove all zeroing of ivars etc. + base::TraverseObjCMethodDecl(D); + + // clear out for next method. + SynthesizedProperties.clear(); + SelfD = 0; + Removables.clear(); + return true; + } + + bool TraverseFunctionDecl(FunctionDecl *D) { return true; } + bool TraverseBlockDecl(BlockDecl *block) { return true; } + bool TraverseBlockExpr(BlockExpr *block) { return true; } + +private: + bool isRemovable(Expr *E) const { + return Removables.count(E); + } + + bool isZeroingPropIvar(Expr *E) { + BinaryOperator *BOE = dyn_cast_or_null(E); + if (!BOE) return false; + + if (BOE->getOpcode() == BO_Comma) + return isZeroingPropIvar(BOE->getLHS()) && + isZeroingPropIvar(BOE->getRHS()); + + if (BOE->getOpcode() != BO_Assign) + return false; + + ASTContext &Ctx = Pass.Ctx; + + Expr *LHS = BOE->getLHS(); + if (ObjCIvarRefExpr *IV = dyn_cast(LHS)) { + ObjCIvarDecl *IVDecl = IV->getDecl(); + if (!IVDecl->getType()->isObjCObjectPointerType()) + return false; + bool IvarBacksPropertySynthesis = false; + for (llvm::DenseMap::iterator + P = SynthesizedProperties.begin(), + E = SynthesizedProperties.end(); P != E; ++P) { + ObjCPropertyImplDecl *PropImpDecl = P->second; + if (PropImpDecl && PropImpDecl->getPropertyIvarDecl() == IVDecl) { + IvarBacksPropertySynthesis = true; + break; + } + } + if (!IvarBacksPropertySynthesis) + return false; + } + else if (ObjCPropertyRefExpr *PropRefExp = dyn_cast(LHS)) { + // TODO: Using implicit property decl. + if (PropRefExp->isImplicitProperty()) + return false; + if (ObjCPropertyDecl *PDecl = PropRefExp->getExplicitProperty()) { + if (!SynthesizedProperties.count(PDecl)) + return false; + } + } + else + return false; + + Expr *RHS = BOE->getRHS(); + bool RHSIsNull = RHS->isNullPointerConstant(Ctx, + Expr::NPC_ValueDependentIsNull); + if (RHSIsNull) + return true; + + return isZeroingPropIvar(RHS); + } +}; + +} // anonymous namespace + +void trans::removeZeroOutPropsInDealloc(MigrationPass &pass) { + ZeroOutInDeallocRemover trans(pass); + trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl()); +} diff --git a/lib/ARCMigrate/TransformActions.cpp b/lib/ARCMigrate/TransformActions.cpp new file mode 100644 index 000000000000..c99940b494b9 --- /dev/null +++ b/lib/ARCMigrate/TransformActions.cpp @@ -0,0 +1,699 @@ +//===--- ARCMT.cpp - Migration to ARC mode --------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Internals.h" +#include "clang/AST/Expr.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/ADT/DenseSet.h" +#include + +using namespace clang; +using namespace arcmt; +using llvm::StringRef; + +namespace { + +/// \brief Collects transformations and merges them before applying them with +/// with applyRewrites(). E.g. if the same source range +/// is requested to be removed twice, only one rewriter remove will be invoked. +/// Rewrites happen in "transactions"; if one rewrite in the transaction cannot +/// be done (e.g. it resides in a macro) all rewrites in the transaction are +/// aborted. +/// FIXME: "Transactional" rewrites support should be baked in the Rewriter. +class TransformActionsImpl { + CapturedDiagList &CapturedDiags; + ASTContext &Ctx; + Preprocessor &PP; + + bool IsInTransaction; + + enum ActionKind { + Act_Insert, Act_InsertAfterToken, + Act_Remove, Act_RemoveStmt, + Act_Replace, Act_ReplaceText, + Act_IncreaseIndentation, + Act_ClearDiagnostic + }; + + struct ActionData { + ActionKind Kind; + SourceLocation Loc; + SourceRange R1, R2; + llvm::StringRef Text1, Text2; + Stmt *S; + llvm::SmallVector DiagIDs; + }; + + std::vector CachedActions; + + enum RangeComparison { + Range_Before, + Range_After, + Range_Contains, + Range_Contained, + Range_ExtendsBegin, + Range_ExtendsEnd + }; + + /// \brief A range to remove. It is a character range. + struct CharRange { + FullSourceLoc Begin, End; + + CharRange(CharSourceRange range, SourceManager &srcMgr, Preprocessor &PP) { + SourceLocation beginLoc = range.getBegin(), endLoc = range.getEnd(); + assert(beginLoc.isValid() && endLoc.isValid()); + if (range.isTokenRange()) { + Begin = FullSourceLoc(srcMgr.getInstantiationLoc(beginLoc), srcMgr); + End = FullSourceLoc(getLocForEndOfToken(endLoc, srcMgr, PP), srcMgr); + } else { + Begin = FullSourceLoc(srcMgr.getInstantiationLoc(beginLoc), srcMgr); + End = FullSourceLoc(srcMgr.getInstantiationLoc(endLoc), srcMgr); + } + assert(Begin.isValid() && End.isValid()); + } + + RangeComparison compareWith(const CharRange &RHS) const { + if (End.isBeforeInTranslationUnitThan(RHS.Begin)) + return Range_Before; + if (RHS.End.isBeforeInTranslationUnitThan(Begin)) + return Range_After; + if (!Begin.isBeforeInTranslationUnitThan(RHS.Begin) && + !RHS.End.isBeforeInTranslationUnitThan(End)) + return Range_Contained; + if (Begin.isBeforeInTranslationUnitThan(RHS.Begin) && + RHS.End.isBeforeInTranslationUnitThan(End)) + return Range_Contains; + if (Begin.isBeforeInTranslationUnitThan(RHS.Begin)) + return Range_ExtendsBegin; + else + return Range_ExtendsEnd; + } + + static RangeComparison compare(SourceRange LHS, SourceRange RHS, + SourceManager &SrcMgr, Preprocessor &PP) { + return CharRange(CharSourceRange::getTokenRange(LHS), SrcMgr, PP) + .compareWith(CharRange(CharSourceRange::getTokenRange(RHS), + SrcMgr, PP)); + } + }; + + typedef llvm::SmallVector TextsVec; + typedef std::map + InsertsMap; + InsertsMap Inserts; + /// \brief A list of ranges to remove. They are always sorted and they never + /// intersect with each other. + std::list Removals; + + llvm::DenseSet StmtRemovals; + + std::vector > IndentationRanges; + + /// \brief Keeps text passed to transformation methods. + llvm::StringMap UniqueText; + +public: + TransformActionsImpl(CapturedDiagList &capturedDiags, + ASTContext &ctx, Preprocessor &PP) + : CapturedDiags(capturedDiags), Ctx(ctx), PP(PP), IsInTransaction(false) { } + + void startTransaction(); + bool commitTransaction(); + void abortTransaction(); + + bool isInTransaction() const { return IsInTransaction; } + + void insert(SourceLocation loc, llvm::StringRef text); + void insertAfterToken(SourceLocation loc, llvm::StringRef text); + void remove(SourceRange range); + void removeStmt(Stmt *S); + void replace(SourceRange range, llvm::StringRef text); + void replace(SourceRange range, SourceRange replacementRange); + void replaceStmt(Stmt *S, llvm::StringRef text); + void replaceText(SourceLocation loc, llvm::StringRef text, + llvm::StringRef replacementText); + void increaseIndentation(SourceRange range, + SourceLocation parentIndent); + + bool clearDiagnostic(llvm::ArrayRef IDs, SourceRange range); + + void applyRewrites(TransformActions::RewriteReceiver &receiver); + +private: + bool canInsert(SourceLocation loc); + bool canInsertAfterToken(SourceLocation loc); + bool canRemoveRange(SourceRange range); + bool canReplaceRange(SourceRange range, SourceRange replacementRange); + bool canReplaceText(SourceLocation loc, llvm::StringRef text); + + void commitInsert(SourceLocation loc, StringRef text); + void commitInsertAfterToken(SourceLocation loc, StringRef text); + void commitRemove(SourceRange range); + void commitRemoveStmt(Stmt *S); + void commitReplace(SourceRange range, SourceRange replacementRange); + void commitReplaceText(SourceLocation loc, llvm::StringRef text, + llvm::StringRef replacementText); + void commitIncreaseIndentation(SourceRange range,SourceLocation parentIndent); + void commitClearDiagnostic(llvm::ArrayRef IDs, SourceRange range); + + void addRemoval(CharSourceRange range); + void addInsertion(SourceLocation loc, StringRef text); + + /// \brief Stores text passed to the transformation methods to keep the string + /// "alive". Since the vast majority of text will be the same, we also unique + /// the strings using a StringMap. + StringRef getUniqueText(StringRef text); + + /// \brief Computes the source location just past the end of the token at + /// the given source location. If the location points at a macro, the whole + /// macro expansion is skipped. + static SourceLocation getLocForEndOfToken(SourceLocation loc, + SourceManager &SM,Preprocessor &PP); +}; + +} // anonymous namespace + +void TransformActionsImpl::startTransaction() { + assert(!IsInTransaction && + "Cannot start a transaction in the middle of another one"); + IsInTransaction = true; +} + +bool TransformActionsImpl::commitTransaction() { + assert(IsInTransaction && "No transaction started"); + + if (CachedActions.empty()) { + IsInTransaction = false; + return false; + } + + // Verify that all actions are possible otherwise abort the whole transaction. + bool AllActionsPossible = true; + for (unsigned i = 0, e = CachedActions.size(); i != e; ++i) { + ActionData &act = CachedActions[i]; + switch (act.Kind) { + case Act_Insert: + if (!canInsert(act.Loc)) + AllActionsPossible = false; + break; + case Act_InsertAfterToken: + if (!canInsertAfterToken(act.Loc)) + AllActionsPossible = false; + break; + case Act_Remove: + if (!canRemoveRange(act.R1)) + AllActionsPossible = false; + break; + case Act_RemoveStmt: + assert(act.S); + if (!canRemoveRange(act.S->getSourceRange())) + AllActionsPossible = false; + break; + case Act_Replace: + if (!canReplaceRange(act.R1, act.R2)) + AllActionsPossible = false; + break; + case Act_ReplaceText: + if (!canReplaceText(act.Loc, act.Text1)) + AllActionsPossible = false; + break; + case Act_IncreaseIndentation: + // This is not important, we don't care if it will fail. + break; + case Act_ClearDiagnostic: + // We are just checking source rewrites. + break; + } + if (!AllActionsPossible) + break; + } + + if (!AllActionsPossible) { + abortTransaction(); + return true; + } + + for (unsigned i = 0, e = CachedActions.size(); i != e; ++i) { + ActionData &act = CachedActions[i]; + switch (act.Kind) { + case Act_Insert: + commitInsert(act.Loc, act.Text1); + break; + case Act_InsertAfterToken: + commitInsertAfterToken(act.Loc, act.Text1); + break; + case Act_Remove: + commitRemove(act.R1); + break; + case Act_RemoveStmt: + commitRemoveStmt(act.S); + break; + case Act_Replace: + commitReplace(act.R1, act.R2); + break; + case Act_ReplaceText: + commitReplaceText(act.Loc, act.Text1, act.Text2); + break; + case Act_IncreaseIndentation: + commitIncreaseIndentation(act.R1, act.Loc); + break; + case Act_ClearDiagnostic: + commitClearDiagnostic(act.DiagIDs, act.R1); + break; + } + } + + CachedActions.clear(); + IsInTransaction = false; + return false; +} + +void TransformActionsImpl::abortTransaction() { + assert(IsInTransaction && "No transaction started"); + CachedActions.clear(); + IsInTransaction = false; +} + +void TransformActionsImpl::insert(SourceLocation loc, StringRef text) { + assert(IsInTransaction && "Actions only allowed during a transaction"); + text = getUniqueText(text); + ActionData data; + data.Kind = Act_Insert; + data.Loc = loc; + data.Text1 = text; + CachedActions.push_back(data); +} + +void TransformActionsImpl::insertAfterToken(SourceLocation loc, StringRef text) { + assert(IsInTransaction && "Actions only allowed during a transaction"); + text = getUniqueText(text); + ActionData data; + data.Kind = Act_InsertAfterToken; + data.Loc = loc; + data.Text1 = text; + CachedActions.push_back(data); +} + +void TransformActionsImpl::remove(SourceRange range) { + assert(IsInTransaction && "Actions only allowed during a transaction"); + ActionData data; + data.Kind = Act_Remove; + data.R1 = range; + CachedActions.push_back(data); +} + +void TransformActionsImpl::removeStmt(Stmt *S) { + assert(IsInTransaction && "Actions only allowed during a transaction"); + ActionData data; + data.Kind = Act_RemoveStmt; + data.S = S->IgnoreImplicit(); // important for uniquing + CachedActions.push_back(data); +} + +void TransformActionsImpl::replace(SourceRange range, StringRef text) { + assert(IsInTransaction && "Actions only allowed during a transaction"); + text = getUniqueText(text); + remove(range); + insert(range.getBegin(), text); +} + +void TransformActionsImpl::replace(SourceRange range, + SourceRange replacementRange) { + assert(IsInTransaction && "Actions only allowed during a transaction"); + ActionData data; + data.Kind = Act_Replace; + data.R1 = range; + data.R2 = replacementRange; + CachedActions.push_back(data); +} + +void TransformActionsImpl::replaceText(SourceLocation loc, StringRef text, + StringRef replacementText) { + text = getUniqueText(text); + replacementText = getUniqueText(replacementText); + ActionData data; + data.Kind = Act_ReplaceText; + data.Loc = loc; + data.Text1 = text; + data.Text2 = replacementText; + CachedActions.push_back(data); +} + +void TransformActionsImpl::replaceStmt(Stmt *S, StringRef text) { + assert(IsInTransaction && "Actions only allowed during a transaction"); + text = getUniqueText(text); + insert(S->getLocStart(), text); + removeStmt(S); +} + +void TransformActionsImpl::increaseIndentation(SourceRange range, + SourceLocation parentIndent) { + if (range.isInvalid()) return; + assert(IsInTransaction && "Actions only allowed during a transaction"); + ActionData data; + data.Kind = Act_IncreaseIndentation; + data.R1 = range; + data.Loc = parentIndent; + CachedActions.push_back(data); +} + +bool TransformActionsImpl::clearDiagnostic(llvm::ArrayRef IDs, + SourceRange range) { + assert(IsInTransaction && "Actions only allowed during a transaction"); + if (!CapturedDiags.hasDiagnostic(IDs, range)) + return false; + + ActionData data; + data.Kind = Act_ClearDiagnostic; + data.R1 = range; + data.DiagIDs.append(IDs.begin(), IDs.end()); + CachedActions.push_back(data); + return true; +} + +bool TransformActionsImpl::canInsert(SourceLocation loc) { + if (loc.isInvalid()) + return false; + + SourceManager &SM = Ctx.getSourceManager(); + if (SM.isInSystemHeader(SM.getInstantiationLoc(loc))) + return false; + + if (loc.isFileID()) + return true; + return PP.isAtStartOfMacroExpansion(loc); +} + +bool TransformActionsImpl::canInsertAfterToken(SourceLocation loc) { + if (loc.isInvalid()) + return false; + + SourceManager &SM = Ctx.getSourceManager(); + if (SM.isInSystemHeader(SM.getInstantiationLoc(loc))) + return false; + + if (loc.isFileID()) + return true; + return PP.isAtEndOfMacroExpansion(loc); +} + +bool TransformActionsImpl::canRemoveRange(SourceRange range) { + return canInsert(range.getBegin()) && canInsertAfterToken(range.getEnd()); +} + +bool TransformActionsImpl::canReplaceRange(SourceRange range, + SourceRange replacementRange) { + return canRemoveRange(range) && canRemoveRange(replacementRange); +} + +bool TransformActionsImpl::canReplaceText(SourceLocation loc, StringRef text) { + if (!canInsert(loc)) + return false; + + SourceManager &SM = Ctx.getSourceManager(); + loc = SM.getInstantiationLoc(loc); + + // Break down the source location. + std::pair locInfo = SM.getDecomposedLoc(loc); + + // Try to load the file buffer. + bool invalidTemp = false; + llvm::StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); + if (invalidTemp) + return false; + + return file.substr(locInfo.second).startswith(text); +} + +void TransformActionsImpl::commitInsert(SourceLocation loc, StringRef text) { + addInsertion(loc, text); +} + +void TransformActionsImpl::commitInsertAfterToken(SourceLocation loc, + StringRef text) { + addInsertion(getLocForEndOfToken(loc, Ctx.getSourceManager(), PP), text); +} + +void TransformActionsImpl::commitRemove(SourceRange range) { + addRemoval(CharSourceRange::getTokenRange(range)); +} + +void TransformActionsImpl::commitRemoveStmt(Stmt *S) { + assert(S); + if (StmtRemovals.count(S)) + return; // already removed. + + if (Expr *E = dyn_cast(S)) { + commitRemove(E->getSourceRange()); + commitInsert(E->getSourceRange().getBegin(), getARCMTMacroName()); + } else + commitRemove(S->getSourceRange()); + + StmtRemovals.insert(S); +} + +void TransformActionsImpl::commitReplace(SourceRange range, + SourceRange replacementRange) { + RangeComparison comp = CharRange::compare(replacementRange, range, + Ctx.getSourceManager(), PP); + assert(comp == Range_Contained); + if (comp != Range_Contained) + return; // Although we asserted, be extra safe for release build. + if (range.getBegin() != replacementRange.getBegin()) + addRemoval(CharSourceRange::getCharRange(range.getBegin(), + replacementRange.getBegin())); + if (replacementRange.getEnd() != range.getEnd()) + addRemoval(CharSourceRange::getTokenRange( + getLocForEndOfToken(replacementRange.getEnd(), + Ctx.getSourceManager(), PP), + range.getEnd())); +} +void TransformActionsImpl::commitReplaceText(SourceLocation loc, + StringRef text, + StringRef replacementText) { + SourceManager &SM = Ctx.getSourceManager(); + loc = SM.getInstantiationLoc(loc); + // canReplaceText already checked if loc points at text. + SourceLocation afterText = loc.getFileLocWithOffset(text.size()); + + addRemoval(CharSourceRange::getCharRange(loc, afterText)); + commitInsert(loc, replacementText); +} + +void TransformActionsImpl::commitIncreaseIndentation(SourceRange range, + SourceLocation parentIndent) { + SourceManager &SM = Ctx.getSourceManager(); + IndentationRanges.push_back( + std::make_pair(CharRange(CharSourceRange::getTokenRange(range), + SM, PP), + SM.getInstantiationLoc(parentIndent))); +} + +void TransformActionsImpl::commitClearDiagnostic(llvm::ArrayRef IDs, + SourceRange range) { + CapturedDiags.clearDiagnostic(IDs, range); +} + +void TransformActionsImpl::addInsertion(SourceLocation loc, StringRef text) { + SourceManager &SM = Ctx.getSourceManager(); + loc = SM.getInstantiationLoc(loc); + for (std::list::reverse_iterator + I = Removals.rbegin(), E = Removals.rend(); I != E; ++I) { + if (!SM.isBeforeInTranslationUnit(loc, I->End)) + break; + if (I->Begin.isBeforeInTranslationUnitThan(loc)) + return; + } + + Inserts[FullSourceLoc(loc, SM)].push_back(text); +} + +void TransformActionsImpl::addRemoval(CharSourceRange range) { + CharRange newRange(range, Ctx.getSourceManager(), PP); + if (newRange.Begin == newRange.End) + return; + + Inserts.erase(Inserts.upper_bound(newRange.Begin), + Inserts.lower_bound(newRange.End)); + + std::list::iterator I = Removals.end(); + while (I != Removals.begin()) { + std::list::iterator RI = I; + --RI; + RangeComparison comp = newRange.compareWith(*RI); + switch (comp) { + case Range_Before: + --I; + break; + case Range_After: + Removals.insert(I, newRange); + return; + case Range_Contained: + return; + case Range_Contains: + RI->End = newRange.End; + case Range_ExtendsBegin: + newRange.End = RI->End; + Removals.erase(RI); + break; + case Range_ExtendsEnd: + RI->End = newRange.End; + return; + } + } + + Removals.insert(Removals.begin(), newRange); +} + +void TransformActionsImpl::applyRewrites( + TransformActions::RewriteReceiver &receiver) { + for (InsertsMap::iterator I = Inserts.begin(), E = Inserts.end(); I!=E; ++I) { + SourceLocation loc = I->first; + for (TextsVec::iterator + TI = I->second.begin(), TE = I->second.end(); TI != TE; ++TI) { + receiver.insert(loc, *TI); + } + } + + for (std::vector >::iterator + I = IndentationRanges.begin(), E = IndentationRanges.end(); I!=E; ++I) { + CharSourceRange range = CharSourceRange::getCharRange(I->first.Begin, + I->first.End); + receiver.increaseIndentation(range, I->second); + } + + for (std::list::iterator + I = Removals.begin(), E = Removals.end(); I != E; ++I) { + CharSourceRange range = CharSourceRange::getCharRange(I->Begin, I->End); + receiver.remove(range); + } +} + +/// \brief Stores text passed to the transformation methods to keep the string +/// "alive". Since the vast majority of text will be the same, we also unique +/// the strings using a StringMap. +StringRef TransformActionsImpl::getUniqueText(StringRef text) { + llvm::StringMapEntry &entry = UniqueText.GetOrCreateValue(text); + return entry.getKey(); +} + +/// \brief Computes the source location just past the end of the token at +/// the given source location. If the location points at a macro, the whole +/// macro expansion is skipped. +SourceLocation TransformActionsImpl::getLocForEndOfToken(SourceLocation loc, + SourceManager &SM, + Preprocessor &PP) { + if (loc.isMacroID()) + loc = SM.getInstantiationRange(loc).second; + return PP.getLocForEndOfToken(loc); +} + +TransformActions::RewriteReceiver::~RewriteReceiver() { } + +TransformActions::TransformActions(Diagnostic &diag, + CapturedDiagList &capturedDiags, + ASTContext &ctx, Preprocessor &PP) + : Diags(diag), CapturedDiags(capturedDiags) { + Impl = new TransformActionsImpl(capturedDiags, ctx, PP); +} + +TransformActions::~TransformActions() { + delete static_cast(Impl); +} + +void TransformActions::startTransaction() { + static_cast(Impl)->startTransaction(); +} + +bool TransformActions::commitTransaction() { + return static_cast(Impl)->commitTransaction(); +} + +void TransformActions::abortTransaction() { + static_cast(Impl)->abortTransaction(); +} + + +void TransformActions::insert(SourceLocation loc, llvm::StringRef text) { + static_cast(Impl)->insert(loc, text); +} + +void TransformActions::insertAfterToken(SourceLocation loc, + llvm::StringRef text) { + static_cast(Impl)->insertAfterToken(loc, text); +} + +void TransformActions::remove(SourceRange range) { + static_cast(Impl)->remove(range); +} + +void TransformActions::removeStmt(Stmt *S) { + static_cast(Impl)->removeStmt(S); +} + +void TransformActions::replace(SourceRange range, llvm::StringRef text) { + static_cast(Impl)->replace(range, text); +} + +void TransformActions::replace(SourceRange range, + SourceRange replacementRange) { + static_cast(Impl)->replace(range, replacementRange); +} + +void TransformActions::replaceStmt(Stmt *S, llvm::StringRef text) { + static_cast(Impl)->replaceStmt(S, text); +} + +void TransformActions::replaceText(SourceLocation loc, llvm::StringRef text, + llvm::StringRef replacementText) { + static_cast(Impl)->replaceText(loc, text, + replacementText); +} + +void TransformActions::increaseIndentation(SourceRange range, + SourceLocation parentIndent) { + static_cast(Impl)->increaseIndentation(range, + parentIndent); +} + +bool TransformActions::clearDiagnostic(llvm::ArrayRef IDs, + SourceRange range) { + return static_cast(Impl)->clearDiagnostic(IDs, range); +} + +void TransformActions::applyRewrites(RewriteReceiver &receiver) { + static_cast(Impl)->applyRewrites(receiver); +} + +void TransformActions::reportError(llvm::StringRef error, SourceLocation loc, + SourceRange range) { + assert(!static_cast(Impl)->isInTransaction() && + "Errors should be emitted out of a transaction"); + // FIXME: Use a custom category name to distinguish rewriter errors. + std::string rewriteErr = "[rewriter] "; + rewriteErr += error; + unsigned diagID + = Diags.getDiagnosticIDs()->getCustomDiagID(DiagnosticIDs::Error, + rewriteErr); + Diags.Report(loc, diagID) << range; +} + +void TransformActions::reportNote(llvm::StringRef note, SourceLocation loc, + SourceRange range) { + assert(!static_cast(Impl)->isInTransaction() && + "Errors should be emitted out of a transaction"); + // FIXME: Use a custom category name to distinguish rewriter errors. + std::string rewriteNote = "[rewriter] "; + rewriteNote += note; + unsigned diagID + = Diags.getDiagnosticIDs()->getCustomDiagID(DiagnosticIDs::Note, + rewriteNote); + Diags.Report(loc, diagID) << range; +} diff --git a/lib/ARCMigrate/Transforms.cpp b/lib/ARCMigrate/Transforms.cpp new file mode 100644 index 000000000000..7bd95e54bc27 --- /dev/null +++ b/lib/ARCMigrate/Transforms.cpp @@ -0,0 +1,296 @@ +//===--- Tranforms.cpp - Tranformations to ARC mode -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Transforms.h" +#include "Internals.h" +#include "clang/Sema/SemaDiagnostic.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/ParentMap.h" +#include "clang/Analysis/DomainSpecific/CocoaConventions.h" +#include "clang/Lex/Lexer.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/DenseSet.h" +#include + +using namespace clang; +using namespace arcmt; +using namespace trans; +using llvm::StringRef; + +//===----------------------------------------------------------------------===// +// Helpers. +//===----------------------------------------------------------------------===// + +/// \brief True if the class is one that does not support weak. +static bool isClassInWeakBlacklist(ObjCInterfaceDecl *cls) { + if (!cls) + return false; + + bool inList = llvm::StringSwitch(cls->getName()) + .Case("NSColorSpace", true) + .Case("NSFont", true) + .Case("NSFontPanel", true) + .Case("NSImage", true) + .Case("NSLazyBrowserCell", true) + .Case("NSWindow", true) + .Case("NSWindowController", true) + .Case("NSMenuView", true) + .Case("NSPersistentUIWindowInfo", true) + .Case("NSTableCellView", true) + .Case("NSATSTypeSetter", true) + .Case("NSATSGlyphStorage", true) + .Case("NSLineFragmentRenderingContext", true) + .Case("NSAttributeDictionary", true) + .Case("NSParagraphStyle", true) + .Case("NSTextTab", true) + .Case("NSSimpleHorizontalTypesetter", true) + .Case("_NSCachedAttributedString", true) + .Case("NSStringDrawingTextStorage", true) + .Case("NSTextView", true) + .Case("NSSubTextStorage", true) + .Default(false); + + if (inList) + return true; + + return isClassInWeakBlacklist(cls->getSuperClass()); +} + +bool trans::canApplyWeak(ASTContext &Ctx, QualType type) { + if (!Ctx.getLangOptions().ObjCRuntimeHasWeak) + return false; + + QualType T = type; + while (const PointerType *ptr = T->getAs()) + T = ptr->getPointeeType(); + if (const ObjCObjectPointerType *ObjT = T->getAs()) { + ObjCInterfaceDecl *Class = ObjT->getInterfaceDecl(); + if (!Class || Class->getName() == "NSObject") + return false; // id/NSObject is not safe for weak. + if (Class->isForwardDecl()) + return false; // forward classes are not verifiable, therefore not safe. + if (Class->isArcWeakrefUnavailable()) + return false; + if (isClassInWeakBlacklist(Class)) + return false; + } + + return true; +} + +/// \brief 'Loc' is the end of a statement range. This returns the location +/// immediately after the semicolon following the statement. +/// If no semicolon is found or the location is inside a macro, the returned +/// source location will be invalid. +SourceLocation trans::findLocationAfterSemi(SourceLocation loc, + ASTContext &Ctx) { + SourceManager &SM = Ctx.getSourceManager(); + if (loc.isMacroID()) { + if (!Lexer::isAtEndOfMacroExpansion(loc, SM, Ctx.getLangOptions())) + return SourceLocation(); + loc = SM.getInstantiationRange(loc).second; + } + loc = Lexer::getLocForEndOfToken(loc, /*Offset=*/0, SM, Ctx.getLangOptions()); + + // Break down the source location. + std::pair locInfo = SM.getDecomposedLoc(loc); + + // Try to load the file buffer. + bool invalidTemp = false; + llvm::StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); + if (invalidTemp) + return SourceLocation(); + + const char *tokenBegin = file.data() + locInfo.second; + + // Lex from the start of the given location. + Lexer lexer(SM.getLocForStartOfFile(locInfo.first), + Ctx.getLangOptions(), + file.begin(), tokenBegin, file.end()); + Token tok; + lexer.LexFromRawLexer(tok); + if (tok.isNot(tok::semi)) + return SourceLocation(); + + return tok.getLocation().getFileLocWithOffset(1); +} + +bool trans::hasSideEffects(Expr *E, ASTContext &Ctx) { + if (!E || !E->HasSideEffects(Ctx)) + return false; + + E = E->IgnoreParenCasts(); + ObjCMessageExpr *ME = dyn_cast(E); + if (!ME) + return true; + switch (ME->getMethodFamily()) { + case OMF_autorelease: + case OMF_dealloc: + case OMF_release: + case OMF_retain: + switch (ME->getReceiverKind()) { + case ObjCMessageExpr::SuperInstance: + return false; + case ObjCMessageExpr::Instance: + return hasSideEffects(ME->getInstanceReceiver(), Ctx); + default: + break; + } + break; + default: + break; + } + + return true; +} + +bool trans::isGlobalVar(Expr *E) { + E = E->IgnoreParenCasts(); + if (DeclRefExpr *DRE = dyn_cast(E)) + return DRE->getDecl()->getDeclContext()->isFileContext(); + if (ConditionalOperator *condOp = dyn_cast(E)) + return isGlobalVar(condOp->getTrueExpr()) && + isGlobalVar(condOp->getFalseExpr()); + + return false; +} + +namespace { + +class ReferenceClear : public RecursiveASTVisitor { + ExprSet &Refs; +public: + ReferenceClear(ExprSet &refs) : Refs(refs) { } + bool VisitDeclRefExpr(DeclRefExpr *E) { Refs.erase(E); return true; } + bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { Refs.erase(E); return true; } +}; + +class ReferenceCollector : public RecursiveASTVisitor { + ValueDecl *Dcl; + ExprSet &Refs; + +public: + ReferenceCollector(ValueDecl *D, ExprSet &refs) + : Dcl(D), Refs(refs) { } + + bool VisitDeclRefExpr(DeclRefExpr *E) { + if (E->getDecl() == Dcl) + Refs.insert(E); + return true; + } + + bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { + if (E->getDecl() == Dcl) + Refs.insert(E); + return true; + } +}; + +class RemovablesCollector : public RecursiveASTVisitor { + ExprSet &Removables; + +public: + RemovablesCollector(ExprSet &removables) + : Removables(removables) { } + + bool shouldWalkTypesOfTypeLocs() const { return false; } + + bool TraverseStmtExpr(StmtExpr *E) { + CompoundStmt *S = E->getSubStmt(); + for (CompoundStmt::body_iterator + I = S->body_begin(), E = S->body_end(); I != E; ++I) { + if (I != E - 1) + mark(*I); + TraverseStmt(*I); + } + return true; + } + + bool VisitCompoundStmt(CompoundStmt *S) { + for (CompoundStmt::body_iterator + I = S->body_begin(), E = S->body_end(); I != E; ++I) + mark(*I); + return true; + } + + bool VisitIfStmt(IfStmt *S) { + mark(S->getThen()); + mark(S->getElse()); + return true; + } + + bool VisitWhileStmt(WhileStmt *S) { + mark(S->getBody()); + return true; + } + + bool VisitDoStmt(DoStmt *S) { + mark(S->getBody()); + return true; + } + + bool VisitForStmt(ForStmt *S) { + mark(S->getInit()); + mark(S->getInc()); + mark(S->getBody()); + return true; + } + +private: + void mark(Stmt *S) { + if (!S) return; + + while (LabelStmt *Label = dyn_cast(S)) + S = Label->getSubStmt(); + S = S->IgnoreImplicit(); + if (Expr *E = dyn_cast(S)) + Removables.insert(E); + } +}; + +} // end anonymous namespace + +void trans::clearRefsIn(Stmt *S, ExprSet &refs) { + ReferenceClear(refs).TraverseStmt(S); +} + +void trans::collectRefs(ValueDecl *D, Stmt *S, ExprSet &refs) { + ReferenceCollector(D, refs).TraverseStmt(S); +} + +void trans::collectRemovables(Stmt *S, ExprSet &exprs) { + RemovablesCollector(exprs).TraverseStmt(S); +} + +//===----------------------------------------------------------------------===// +// getAllTransformations. +//===----------------------------------------------------------------------===// + +static void independentTransforms(MigrationPass &pass) { + rewriteAutoreleasePool(pass); + rewriteProperties(pass); + removeRetainReleaseDealloc(pass); + rewriteUnusedInitDelegate(pass); + removeZeroOutPropsInDealloc(pass); + makeAssignARCSafe(pass); + rewriteUnbridgedCasts(pass); + rewriteBlockObjCVariable(pass); +} + +std::vector arcmt::getAllTransformations() { + std::vector transforms; + + transforms.push_back(independentTransforms); + // This depends on previous transformations removing various expressions. + transforms.push_back(removeEmptyStatementsAndDealloc); + + return transforms; +} diff --git a/lib/ARCMigrate/Transforms.h b/lib/ARCMigrate/Transforms.h new file mode 100644 index 000000000000..b47d6d8e9b8b --- /dev/null +++ b/lib/ARCMigrate/Transforms.h @@ -0,0 +1,92 @@ +//===-- Transforms.h - Tranformations to ARC mode ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_ARCMIGRATE_TRANSFORMS_H +#define LLVM_CLANG_LIB_ARCMIGRATE_TRANSFORMS_H + +#include "clang/AST/RecursiveASTVisitor.h" +#include "llvm/ADT/DenseSet.h" + +namespace clang { + class Decl; + class Stmt; + class BlockDecl; + class ObjCMethodDecl; + class FunctionDecl; + +namespace arcmt { + class MigrationPass; + +namespace trans { + +//===----------------------------------------------------------------------===// +// Transformations. +//===----------------------------------------------------------------------===// + +void rewriteAutoreleasePool(MigrationPass &pass); +void rewriteUnbridgedCasts(MigrationPass &pass); +void makeAssignARCSafe(MigrationPass &pass); +void removeRetainReleaseDealloc(MigrationPass &pass); +void removeZeroOutPropsInDealloc(MigrationPass &pass); +void rewriteProperties(MigrationPass &pass); +void rewriteBlockObjCVariable(MigrationPass &pass); +void rewriteUnusedInitDelegate(MigrationPass &pass); + +void removeEmptyStatementsAndDealloc(MigrationPass &pass); + +//===----------------------------------------------------------------------===// +// Helpers. +//===----------------------------------------------------------------------===// + +/// \brief Determine whether we can add weak to the given type. +bool canApplyWeak(ASTContext &Ctx, QualType type); + +/// \brief 'Loc' is the end of a statement range. This returns the location +/// immediately after the semicolon following the statement. +/// If no semicolon is found or the location is inside a macro, the returned +/// source location will be invalid. +SourceLocation findLocationAfterSemi(SourceLocation loc, ASTContext &Ctx); + +bool hasSideEffects(Expr *E, ASTContext &Ctx); +bool isGlobalVar(Expr *E); + + +template +class BodyTransform : public RecursiveASTVisitor > { + MigrationPass &Pass; + +public: + BodyTransform(MigrationPass &pass) : Pass(pass) { } + + bool TraverseStmt(Stmt *rootS) { + BODY_TRANS(Pass).transformBody(rootS); + return true; + } +}; + +typedef llvm::DenseSet ExprSet; + +void clearRefsIn(Stmt *S, ExprSet &refs); +template +void clearRefsIn(iterator begin, iterator end, ExprSet &refs) { + for (; begin != end; ++begin) + clearRefsIn(*begin, refs); +} + +void collectRefs(ValueDecl *D, Stmt *S, ExprSet &refs); + +void collectRemovables(Stmt *S, ExprSet &exprs); + +} // end namespace trans + +} // end namespace arcmt + +} // end namespace clang + +#endif diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 9094abad2ef1..6eada6e22f4e 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -219,11 +219,12 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM, FunctionProtoTypes(this_()), TemplateSpecializationTypes(this_()), DependentTemplateSpecializationTypes(this_()), + SubstTemplateTemplateParmPacks(this_()), GlobalNestedNameSpecifier(0), IsInt128Installed(false), CFConstantStringTypeDecl(0), NSConstantStringTypeDecl(0), - ObjCFastEnumerationStateTypeDecl(0), FILEDecl(0), jmp_bufDecl(0), - sigjmp_bufDecl(0), BlockDescriptorType(0), BlockDescriptorExtendedType(0), - cudaConfigureCallDecl(0), + ObjCFastEnumerationStateTypeDecl(0), FILEDecl(0), + jmp_bufDecl(0), sigjmp_bufDecl(0), BlockDescriptorType(0), + BlockDescriptorExtendedType(0), cudaConfigureCallDecl(0), NullTypeSourceInfo(QualType()), SourceMgr(SM), LangOpts(LOpts), ABI(createCXXABI(t)), AddrSpaceMap(getAddressSpaceMap(t, LOpts)), Target(t), @@ -288,8 +289,8 @@ ASTContext::setExternalSource(llvm::OwningPtr &Source) { } void ASTContext::PrintStats() const { - fprintf(stderr, "*** AST Context Stats:\n"); - fprintf(stderr, " %d types total.\n", (int)Types.size()); + llvm::errs() << "\n*** AST Context Stats:\n"; + llvm::errs() << " " << Types.size() << " types total.\n"; unsigned counts[] = { #define TYPE(Name, Parent) 0, @@ -307,40 +308,42 @@ void ASTContext::PrintStats() const { unsigned TotalBytes = 0; #define TYPE(Name, Parent) \ if (counts[Idx]) \ - fprintf(stderr, " %d %s types\n", (int)counts[Idx], #Name); \ + llvm::errs() << " " << counts[Idx] << " " << #Name \ + << " types\n"; \ TotalBytes += counts[Idx] * sizeof(Name##Type); \ ++Idx; #define ABSTRACT_TYPE(Name, Parent) #include "clang/AST/TypeNodes.def" - fprintf(stderr, "Total bytes = %d\n", int(TotalBytes)); - + llvm::errs() << "Total bytes = " << TotalBytes << "\n"; + // Implicit special member functions. - fprintf(stderr, " %u/%u implicit default constructors created\n", - NumImplicitDefaultConstructorsDeclared, - NumImplicitDefaultConstructors); - fprintf(stderr, " %u/%u implicit copy constructors created\n", - NumImplicitCopyConstructorsDeclared, - NumImplicitCopyConstructors); + llvm::errs() << NumImplicitDefaultConstructorsDeclared << "/" + << NumImplicitDefaultConstructors + << " implicit default constructors created\n"; + llvm::errs() << NumImplicitCopyConstructorsDeclared << "/" + << NumImplicitCopyConstructors + << " implicit copy constructors created\n"; if (getLangOptions().CPlusPlus) - fprintf(stderr, " %u/%u implicit move constructors created\n", - NumImplicitMoveConstructorsDeclared, - NumImplicitMoveConstructors); - fprintf(stderr, " %u/%u implicit copy assignment operators created\n", - NumImplicitCopyAssignmentOperatorsDeclared, - NumImplicitCopyAssignmentOperators); + llvm::errs() << NumImplicitMoveConstructorsDeclared << "/" + << NumImplicitMoveConstructors + << " implicit move constructors created\n"; + llvm::errs() << NumImplicitCopyAssignmentOperatorsDeclared << "/" + << NumImplicitCopyAssignmentOperators + << " implicit copy assignment operators created\n"; if (getLangOptions().CPlusPlus) - fprintf(stderr, " %u/%u implicit move assignment operators created\n", - NumImplicitMoveAssignmentOperatorsDeclared, - NumImplicitMoveAssignmentOperators); - fprintf(stderr, " %u/%u implicit destructors created\n", - NumImplicitDestructorsDeclared, NumImplicitDestructors); - + llvm::errs() << NumImplicitMoveAssignmentOperatorsDeclared << "/" + << NumImplicitMoveAssignmentOperators + << " implicit move assignment operators created\n"; + llvm::errs() << NumImplicitDestructorsDeclared << "/" + << NumImplicitDestructors + << " implicit destructors created\n"; + if (ExternalSource.get()) { - fprintf(stderr, "\n"); + llvm::errs() << "\n"; ExternalSource->PrintStats(); } - + BumpAlloc.PrintStats(); } @@ -753,7 +756,7 @@ ASTContext::getTypeInfo(const Type *T) const { #define NON_CANONICAL_TYPE(Class, Base) #define DEPENDENT_TYPE(Class, Base) case Type::Class: #include "clang/AST/TypeNodes.def" - assert(false && "Should not see dependent types"); + llvm_unreachable("Should not see dependent types"); break; case Type::FunctionNoProto: @@ -1089,8 +1092,12 @@ void ASTContext::DeepCollectObjCIvars(const ObjCInterfaceDecl *OI, E = OI->ivar_end(); I != E; ++I) Ivars.push_back(*I); } - else - ShallowCollectObjCIvars(OI, Ivars); + else { + ObjCInterfaceDecl *IDecl = const_cast(OI); + for (ObjCIvarDecl *Iv = IDecl->all_declared_ivar_begin(); Iv; + Iv= Iv->getNextIvar()) + Ivars.push_back(Iv); + } } /// CollectInheritedProtocols - Collect all protocols in current class and @@ -1881,7 +1888,7 @@ 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) const { - assert(vecType->isBuiltinType()); + assert(vecType->isBuiltinType() || vecType->isDependentType()); // Check if we've already instantiated a vector of this type. llvm::FoldingSetNodeID ID; @@ -2040,10 +2047,13 @@ ASTContext::getFunctionType(QualType ResultTy, assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP; } - // FunctionProtoType objects are allocated with extra bytes after them - // for two variable size arrays (for parameter and exception types) at the - // end of them. Instead of the exception types, there could be a noexcept - // expression and a context pointer. + // FunctionProtoType objects are allocated with extra bytes after + // them for three variable size arrays at the end: + // - parameter types + // - exception types + // - consumed-arguments flags + // Instead of the exception types, there could be a noexcept + // expression. size_t Size = sizeof(FunctionProtoType) + NumArgs * sizeof(QualType); if (EPI.ExceptionSpecType == EST_Dynamic) @@ -2051,6 +2061,9 @@ ASTContext::getFunctionType(QualType ResultTy, else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) { Size += sizeof(Expr*); } + if (EPI.ConsumedArguments) + Size += NumArgs * sizeof(bool); + FunctionProtoType *FTP = (FunctionProtoType*) Allocate(Size, TypeAlignment); FunctionProtoType::ExtProtoInfo newEPI = EPI; newEPI.ExtInfo = EPI.ExtInfo.withCallingConv(CallConv); @@ -2791,7 +2804,12 @@ static QualType getDecltypeForExpr(const Expr *e, const ASTContext &Context) { /// on canonical type's (which are always unique). QualType ASTContext::getDecltypeType(Expr *e) const { DecltypeType *dt; - if (e->isTypeDependent()) { + + // C++0x [temp.type]p2: + // If an expression e involves a template parameter, decltype(e) denotes a + // unique dependent type. Two such decltype-specifiers refer to the same + // type only if their expressions are equivalent (14.5.6.1). + if (e->isInstantiationDependent()) { llvm::FoldingSetNodeID ID; DependentDecltypeType::Profile(ID, *this, e); @@ -2925,7 +2943,6 @@ CanQualType ASTContext::getCanonicalParamType(QualType T) const { return CanQualType::CreateUnsafe(Result); } - QualType ASTContext::getUnqualifiedArrayType(QualType type, Qualifiers &quals) { SplitQualType splitType = type.getSplitUnqualifiedType(); @@ -3027,11 +3044,21 @@ bool ASTContext::UnwrapSimilarPointerTypes(QualType &T1, QualType &T2) { DeclarationNameInfo ASTContext::getNameForTemplate(TemplateName Name, SourceLocation NameLoc) const { - if (TemplateDecl *TD = Name.getAsTemplateDecl()) + switch (Name.getKind()) { + case TemplateName::QualifiedTemplate: + case TemplateName::Template: // DNInfo work in progress: CHECKME: what about DNLoc? - return DeclarationNameInfo(TD->getDeclName(), NameLoc); + return DeclarationNameInfo(Name.getAsTemplateDecl()->getDeclName(), + NameLoc); - if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) { + case TemplateName::OverloadedTemplate: { + OverloadedTemplateStorage *Storage = Name.getAsOverloadedTemplate(); + // DNInfo work in progress: CHECKME: what about DNLoc? + return DeclarationNameInfo((*Storage->begin())->getDeclName(), NameLoc); + } + + case TemplateName::DependentTemplate: { + DependentTemplateName *DTN = Name.getAsDependentTemplateName(); DeclarationName DName; if (DTN->isIdentifier()) { DName = DeclarationNames.getIdentifier(DTN->getIdentifier()); @@ -3046,36 +3073,64 @@ ASTContext::getNameForTemplate(TemplateName Name, } } - OverloadedTemplateStorage *Storage = Name.getAsOverloadedTemplate(); - assert(Storage); - // DNInfo work in progress: CHECKME: what about DNLoc? - return DeclarationNameInfo((*Storage->begin())->getDeclName(), NameLoc); + case TemplateName::SubstTemplateTemplateParm: { + SubstTemplateTemplateParmStorage *subst + = Name.getAsSubstTemplateTemplateParm(); + return DeclarationNameInfo(subst->getParameter()->getDeclName(), + NameLoc); + } + + case TemplateName::SubstTemplateTemplateParmPack: { + SubstTemplateTemplateParmPackStorage *subst + = Name.getAsSubstTemplateTemplateParmPack(); + return DeclarationNameInfo(subst->getParameterPack()->getDeclName(), + NameLoc); + } + } + + llvm_unreachable("bad template name kind!"); } TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) const { - if (TemplateDecl *Template = Name.getAsTemplateDecl()) { + switch (Name.getKind()) { + case TemplateName::QualifiedTemplate: + case TemplateName::Template: { + TemplateDecl *Template = Name.getAsTemplateDecl(); if (TemplateTemplateParmDecl *TTP - = dyn_cast(Template)) + = dyn_cast(Template)) Template = getCanonicalTemplateTemplateParmDecl(TTP); // The canonical template name is the canonical template declaration. return TemplateName(cast(Template->getCanonicalDecl())); } - if (SubstTemplateTemplateParmPackStorage *SubstPack - = Name.getAsSubstTemplateTemplateParmPack()) { - TemplateTemplateParmDecl *CanonParam - = getCanonicalTemplateTemplateParmDecl(SubstPack->getParameterPack()); - TemplateArgument CanonArgPack - = getCanonicalTemplateArgument(SubstPack->getArgumentPack()); - return getSubstTemplateTemplateParmPack(CanonParam, CanonArgPack); + case TemplateName::OverloadedTemplate: + llvm_unreachable("cannot canonicalize overloaded template"); + + case TemplateName::DependentTemplate: { + DependentTemplateName *DTN = Name.getAsDependentTemplateName(); + assert(DTN && "Non-dependent template names must refer to template decls."); + return DTN->CanonicalTemplateName; + } + + case TemplateName::SubstTemplateTemplateParm: { + SubstTemplateTemplateParmStorage *subst + = Name.getAsSubstTemplateTemplateParm(); + return getCanonicalTemplateName(subst->getReplacement()); } - - assert(!Name.getAsOverloadedTemplate()); - DependentTemplateName *DTN = Name.getAsDependentTemplateName(); - assert(DTN && "Non-dependent template names must refer to template decls."); - return DTN->CanonicalTemplateName; + case TemplateName::SubstTemplateTemplateParmPack: { + SubstTemplateTemplateParmPackStorage *subst + = Name.getAsSubstTemplateTemplateParmPack(); + TemplateTemplateParmDecl *canonParameter + = getCanonicalTemplateTemplateParmDecl(subst->getParameterPack()); + TemplateArgument canonArgPack + = getCanonicalTemplateArgument(subst->getArgumentPack()); + return getSubstTemplateTemplateParmPack(canonParameter, canonArgPack); + } + } + + llvm_unreachable("bad template name!"); } bool ASTContext::hasSameTemplateName(TemplateName X, TemplateName Y) { @@ -3260,6 +3315,31 @@ const ArrayType *ASTContext::getAsArrayType(QualType T) const { VAT->getBracketsRange())); } +QualType ASTContext::getAdjustedParameterType(QualType T) { + // C99 6.7.5.3p7: + // A declaration of a parameter as "array of type" shall be + // adjusted to "qualified pointer to type", where the type + // qualifiers (if any) are those specified within the [ and ] of + // the array type derivation. + if (T->isArrayType()) + return getArrayDecayedType(T); + + // C99 6.7.5.3p8: + // A declaration of a parameter as "function returning type" + // shall be adjusted to "pointer to function returning type", as + // in 6.3.2.1. + if (T->isFunctionType()) + return getPointerType(T); + + return T; +} + +QualType ASTContext::getSignatureParameterType(QualType T) { + T = getVariableArrayDecayedType(T); + T = getAdjustedParameterType(T); + return T.getUnqualifiedType(); +} + /// 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, @@ -3459,6 +3539,25 @@ QualType ASTContext::getPromotedIntegerType(QualType Promotable) const { return (PromotableSize != IntSize) ? IntTy : UnsignedIntTy; } +/// \brief Recurses in pointer/array types until it finds an objc retainable +/// type and returns its ownership. +Qualifiers::ObjCLifetime ASTContext::getInnerObjCOwnership(QualType T) const { + while (!T.isNull()) { + if (T.getObjCLifetime() != Qualifiers::OCL_None) + return T.getObjCLifetime(); + if (T->isArrayType()) + T = getBaseElementType(T); + else if (const PointerType *PT = T->getAs()) + T = PT->getPointeeType(); + else if (const ReferenceType *RT = T->getAs()) + T = RT->getPointeeType(); + else + break; + } + + return Qualifiers::OCL_None; +} + /// 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. @@ -3725,11 +3824,7 @@ void ASTContext::setBlockDescriptorExtendedType(QualType T) { } bool ASTContext::BlockRequiresCopying(QualType Ty) const { - if (Ty->isBlockPointerType()) - return true; - if (isObjCNSObjectType(Ty)) - return true; - if (Ty->isObjCObjectPointerType()) + if (Ty->isObjCRetainableType()) return true; if (getLangOptions().CPlusPlus) { if (const RecordType *RT = Ty->getAs()) { @@ -4180,17 +4275,7 @@ static void EncodeBitField(const ASTContext *Ctx, std::string& S, if (!Ctx->getLangOptions().NeXTRuntime) { const RecordDecl *RD = FD->getParent(); const ASTRecordLayout &RL = Ctx->getASTRecordLayout(RD); - // FIXME: This same linear search is also used in ExprConstant - it might - // be better if the FieldDecl stored its offset. We'd be increasing the - // size of the object slightly, but saving some time every time it is used. - unsigned i = 0; - for (RecordDecl::field_iterator Field = RD->field_begin(), - FieldEnd = RD->field_end(); - Field != FieldEnd; (void)++Field, ++i) { - if (*Field == FD) - break; - } - S += llvm::utostr(RL.getFieldOffset(i)); + S += llvm::utostr(RL.getFieldOffset(FD->getFieldIndex())); if (T->isEnumeralType()) S += 'i'; else @@ -4510,6 +4595,8 @@ void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl, BE = CXXRec->bases_end(); BI != BE; ++BI) { if (!BI->isVirtual()) { CXXRecordDecl *base = BI->getType()->getAsCXXRecordDecl(); + if (base->isEmpty()) + continue; uint64_t offs = layout.getBaseClassOffsetInBits(base); FieldOrBaseOffsets.insert(FieldOrBaseOffsets.upper_bound(offs), std::make_pair(offs, base)); @@ -4531,6 +4618,8 @@ void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl, BI = CXXRec->vbases_begin(), BE = CXXRec->vbases_end(); BI != BE; ++BI) { CXXRecordDecl *base = BI->getType()->getAsCXXRecordDecl(); + if (base->isEmpty()) + continue; uint64_t offs = layout.getVBaseClassOffsetInBits(base); FieldOrBaseOffsets.insert(FieldOrBaseOffsets.upper_bound(offs), std::make_pair(offs, base)); @@ -4594,8 +4683,8 @@ void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl, // expands virtual bases each time one is encountered in the hierarchy, // making the encoding type bigger than it really is. getObjCEncodingForStructureImpl(base, S, FD, /*includeVBases*/false); - if (!base->isEmpty()) - CurOffs += toBits(getASTRecordLayout(base).getNonVirtualSize()); + assert(!base->isEmpty()); + CurOffs += toBits(getASTRecordLayout(base).getNonVirtualSize()); } else { FieldDecl *field = cast(dcl); if (FD) { @@ -4781,6 +4870,24 @@ ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS, return TemplateName(QTN); } +TemplateName +ASTContext::getSubstTemplateTemplateParm(TemplateTemplateParmDecl *param, + TemplateName replacement) const { + llvm::FoldingSetNodeID ID; + SubstTemplateTemplateParmStorage::Profile(ID, param, replacement); + + void *insertPos = 0; + SubstTemplateTemplateParmStorage *subst + = SubstTemplateTemplateParms.FindNodeOrInsertPos(ID, insertPos); + + if (!subst) { + subst = new (*this) SubstTemplateTemplateParmStorage(param, replacement); + SubstTemplateTemplateParms.InsertNode(subst, insertPos); + } + + return TemplateName(subst); +} + TemplateName ASTContext::getSubstTemplateTemplateParmPack(TemplateTemplateParmDecl *Param, const TemplateArgument &ArgPack) const { @@ -4793,7 +4900,7 @@ ASTContext::getSubstTemplateTemplateParmPack(TemplateTemplateParmDecl *Param, = SubstTemplateTemplateParmPacks.FindNodeOrInsertPos(ID, InsertPos); if (!Subst) { - Subst = new (*this) SubstTemplateTemplateParmPackStorage(Self, Param, + Subst = new (*this) SubstTemplateTemplateParmPackStorage(Param, ArgPack.pack_size(), ArgPack.pack_begin()); SubstTemplateTemplateParmPacks.InsertNode(Subst, InsertPos); @@ -4826,20 +4933,6 @@ CanQualType ASTContext::getFromTargetType(unsigned Type) const { // Type Predicates. //===----------------------------------------------------------------------===// -/// isObjCNSObjectType - Return true if this is an NSObject object using -/// NSObject attribute on a c-style pointer type. -/// FIXME - Make it work directly on types. -/// FIXME: Move to Type. -/// -bool ASTContext::isObjCNSObjectType(QualType Ty) const { - if (const TypedefType *TDT = dyn_cast(Ty)) { - if (TypedefNameDecl *TD = TDT->getDecl()) - if (TD->getAttr()) - return true; - } - return false; -} - /// getObjCGCAttr - Returns one of GCNone, Weak or Strong objc's /// garbage collection attribute. /// @@ -5348,6 +5441,10 @@ bool ASTContext::typesAreCompatible(QualType LHS, QualType RHS, return !mergeTypes(LHS, RHS, false, CompareUnqualified).isNull(); } +bool ASTContext::propertyTypesAreCompatible(QualType LHS, QualType RHS) { + return typesAreCompatible(LHS, RHS); +} + bool ASTContext::typesAreBlockPointerCompatible(QualType LHS, QualType RHS) { return !mergeTypes(LHS, RHS, true).isNull(); } @@ -5452,6 +5549,9 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, if (lbaseInfo.getRegParm() != rbaseInfo.getRegParm()) return QualType(); + if (lbaseInfo.getProducesResult() != rbaseInfo.getProducesResult()) + return QualType(); + // It's noreturn if either type is. // FIXME: some uses, e.g. conditional exprs, really want this to be 'both'. bool NoReturn = lbaseInfo.getNoReturn() || rbaseInfo.getNoReturn(); @@ -5460,10 +5560,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, if (NoReturn != rbaseInfo.getNoReturn()) allRTypes = false; - FunctionType::ExtInfo einfo(NoReturn, - lbaseInfo.getHasRegParm(), - lbaseInfo.getRegParm(), - lbaseInfo.getCC()); + FunctionType::ExtInfo einfo = lbaseInfo.withNoReturn(NoReturn); if (lproto && rproto) { // two C99 style function prototypes assert(!lproto->hasExceptionSpec() && !rproto->hasExceptionSpec() && @@ -5584,7 +5681,8 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, // If any of these qualifiers are different, we have a type // mismatch. if (LQuals.getCVRQualifiers() != RQuals.getCVRQualifiers() || - LQuals.getAddressSpace() != RQuals.getAddressSpace()) + LQuals.getAddressSpace() != RQuals.getAddressSpace() || + LQuals.getObjCLifetime() != RQuals.getObjCLifetime()) return QualType(); // Exactly one GC qualifier difference is allowed: __strong is @@ -6401,4 +6499,3 @@ size_t ASTContext::getSideTableAllocatedMemory() const { bytes += InstantiatedFromUnnamedFieldDecl.getMemorySize(); return bytes; } - diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp index 16d2f853606e..7c91b5cb7a00 100644 --- a/lib/AST/ASTDiagnostic.cpp +++ b/lib/AST/ASTDiagnostic.cpp @@ -129,7 +129,7 @@ break; \ /// \brief Convert the given type to a string suitable for printing as part of /// a diagnostic. /// -/// There are three main criteria when determining whether we should have an +/// There are four main criteria when determining whether we should have an /// a.k.a. clause when pretty-printing a type: /// /// 1) Some types provide very minimal sugar that doesn't impede the @@ -142,15 +142,44 @@ break; \ /// want to desugar these, even if we do produce an a.k.a. clause. /// 3) Some types may have already been desugared previously in this diagnostic. /// if this is the case, doing another "aka" would just be clutter. +/// 4) Two different types within the same diagnostic have the same output +/// string. In this case, force an a.k.a with the desugared type when +/// doing so will provide additional information. /// /// \param Context the context in which the type was allocated /// \param Ty the type to print +/// \param QualTypeVals pointer values to QualTypes which are used in the +/// diagnostic message static std::string ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty, const Diagnostic::ArgumentValue *PrevArgs, - unsigned NumPrevArgs) { + unsigned NumPrevArgs, + llvm::SmallVectorImpl &QualTypeVals) { // FIXME: Playing with std::string is really slow. + bool ForceAKA = false; + QualType CanTy = Ty.getCanonicalType(); std::string S = Ty.getAsString(Context.PrintingPolicy); + std::string CanS = CanTy.getAsString(Context.PrintingPolicy); + + for (llvm::SmallVectorImpl::iterator I = QualTypeVals.begin(), + E = QualTypeVals.end(); I != E; ++I) { + QualType CompareTy = + QualType::getFromOpaquePtr(reinterpret_cast(*I)); + if (CompareTy == Ty) + continue; // Same types + QualType CompareCanTy = CompareTy.getCanonicalType(); + if (CompareCanTy == CanTy) + continue; // Same canonical types + std::string CompareS = CompareTy.getAsString(Context.PrintingPolicy); + if (CompareS != S) + continue; // Original strings are different + std::string CompareCanS = CompareCanTy.getAsString(Context.PrintingPolicy); + if (CompareCanS == CanS) + continue; // No new info from canonical type + + ForceAKA = true; + break; + } // Check to see if we already desugared this type in this // diagnostic. If so, don't do it again. @@ -172,11 +201,15 @@ ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty, if (!Repeated) { bool ShouldAKA = false; QualType DesugaredTy = Desugar(Context, Ty, ShouldAKA); - if (ShouldAKA) { - S = "'" + S + "' (aka '"; - S += DesugaredTy.getAsString(Context.PrintingPolicy); - S += "')"; - return S; + if (ShouldAKA || ForceAKA) { + if (DesugaredTy == Ty) { + DesugaredTy = Ty.getCanonicalType(); + } + std::string akaStr = DesugaredTy.getAsString(Context.PrintingPolicy); + if (akaStr != S) { + S = "'" + S + "' (aka '" + akaStr + "')"; + return S; + } } } @@ -184,16 +217,18 @@ ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty, return S; } -void clang::FormatASTNodeDiagnosticArgument(Diagnostic::ArgumentKind Kind, - intptr_t Val, - const char *Modifier, - unsigned ModLen, - const char *Argument, - unsigned ArgLen, - const Diagnostic::ArgumentValue *PrevArgs, - unsigned NumPrevArgs, - llvm::SmallVectorImpl &Output, - void *Cookie) { +void clang::FormatASTNodeDiagnosticArgument( + Diagnostic::ArgumentKind Kind, + intptr_t Val, + const char *Modifier, + unsigned ModLen, + const char *Argument, + unsigned ArgLen, + const Diagnostic::ArgumentValue *PrevArgs, + unsigned NumPrevArgs, + llvm::SmallVectorImpl &Output, + void *Cookie, + llvm::SmallVectorImpl &QualTypeVals) { ASTContext &Context = *static_cast(Cookie); std::string S; @@ -206,7 +241,8 @@ void clang::FormatASTNodeDiagnosticArgument(Diagnostic::ArgumentKind Kind, "Invalid modifier for QualType argument"); QualType Ty(QualType::getFromOpaquePtr(reinterpret_cast(Val))); - S = ConvertTypeToDiagnosticString(Context, Ty, PrevArgs, NumPrevArgs); + S = ConvertTypeToDiagnosticString(Context, Ty, PrevArgs, NumPrevArgs, + QualTypeVals); NeedQuotes = false; break; } @@ -257,7 +293,7 @@ void clang::FormatASTNodeDiagnosticArgument(Diagnostic::ArgumentKind Kind, } else if (TypeDecl *Type = dyn_cast(DC)) { S = ConvertTypeToDiagnosticString(Context, Context.getTypeDeclType(Type), - PrevArgs, NumPrevArgs); + PrevArgs, NumPrevArgs, QualTypeVals); } else { // FIXME: Get these strings from some localized place NamedDecl *ND = cast(DC); diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 100e604d1c46..f5e392f88d0b 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -4201,6 +4201,20 @@ TemplateName ASTImporter::Import(TemplateName From) { return ToContext.getDependentTemplateName(Qualifier, DTN->getOperator()); } + + case TemplateName::SubstTemplateTemplateParm: { + SubstTemplateTemplateParmStorage *subst + = From.getAsSubstTemplateTemplateParm(); + TemplateTemplateParmDecl *param + = cast_or_null(Import(subst->getParameter())); + if (!param) + return TemplateName(); + + TemplateName replacement = Import(subst->getReplacement()); + if (replacement.isNull()) return TemplateName(); + + return ToContext.getSubstTemplateTemplateParm(param, replacement); + } case TemplateName::SubstTemplateTemplateParmPack: { SubstTemplateTemplateParmPackStorage *SubstPack @@ -4232,8 +4246,8 @@ SourceLocation ASTImporter::Import(SourceLocation FromLoc) { SourceManager &FromSM = FromContext.getSourceManager(); // For now, map everything down to its spelling location, so that we - // don't have to import macro instantiations. - // FIXME: Import macro instantiations! + // don't have to import macro expansions. + // FIXME: Import macro expansions! FromLoc = FromSM.getSpellingLoc(FromLoc); std::pair Decomposed = FromSM.getDecomposedLoc(FromLoc); SourceManager &ToSM = ToContext.getSourceManager(); @@ -4254,7 +4268,7 @@ FileID ASTImporter::Import(FileID FromID) { SourceManager &FromSM = FromContext.getSourceManager(); SourceManager &ToSM = ToContext.getSourceManager(); const SrcMgr::SLocEntry &FromSLoc = FromSM.getSLocEntry(FromID); - assert(FromSLoc.isFile() && "Cannot handle macro instantiations yet"); + assert(FromSLoc.isFile() && "Cannot handle macro expansions yet"); // Include location of this file. SourceLocation ToIncludeLoc = Import(FromSLoc.getFile().getIncludeLoc()); diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 12357c07a794..4c323da7eee3 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -197,6 +197,16 @@ getLVForTemplateArgumentList(const TemplateArgumentList &TArgs, return getLVForTemplateArgumentList(TArgs.data(), TArgs.size(), F); } +static bool shouldConsiderTemplateLV(const FunctionDecl *fn, + const FunctionTemplateSpecializationInfo *spec) { + return !(spec->isExplicitSpecialization() && + fn->hasAttr()); +} + +static bool shouldConsiderTemplateLV(const ClassTemplateSpecializationDecl *d) { + return !(d->isExplicitSpecialization() && d->hasAttr()); +} + static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) { assert(D->getDeclContext()->getRedeclContext()->isFileContext() && "Not a name having namespace scope"); @@ -231,6 +241,14 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) { if (!FoundExtern) return LinkageInfo::internal(); } + if (Var->getStorageClass() == SC_None) { + const VarDecl *PrevVar = Var->getPreviousDeclaration(); + for (; PrevVar; PrevVar = PrevVar->getPreviousDeclaration()) + if (PrevVar->getStorageClass() == SC_PrivateExtern) + break; + if (PrevVar) + return PrevVar->getLinkageAndVisibility(); + } } else if (isa(D) || isa(D)) { // C++ [temp]p4: // A non-member function template can have internal linkage; any @@ -389,12 +407,16 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) { Function->getType()->getLinkage() == UniqueExternalLinkage) return LinkageInfo::uniqueExternal(); - if (FunctionTemplateSpecializationInfo *SpecInfo + // Consider LV from the template and the template arguments unless + // this is an explicit specialization with a visibility attribute. + if (FunctionTemplateSpecializationInfo *specInfo = Function->getTemplateSpecializationInfo()) { - LV.merge(getLVForDecl(SpecInfo->getTemplate(), - F.onlyTemplateVisibility())); - const TemplateArgumentList &TemplateArgs = *SpecInfo->TemplateArguments; - LV.merge(getLVForTemplateArgumentList(TemplateArgs, F)); + if (shouldConsiderTemplateLV(Function, specInfo)) { + LV.merge(getLVForDecl(specInfo->getTemplate(), + F.onlyTemplateVisibility())); + const TemplateArgumentList &templateArgs = *specInfo->TemplateArguments; + LV.merge(getLVForTemplateArgumentList(templateArgs, F)); + } } // - a named class (Clause 9), or an unnamed class defined in a @@ -410,15 +432,17 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) { // If this is a class template specialization, consider the // linkage of the template and template arguments. - if (const ClassTemplateSpecializationDecl *Spec + if (const ClassTemplateSpecializationDecl *spec = dyn_cast(Tag)) { - // From the template. - LV.merge(getLVForDecl(Spec->getSpecializedTemplate(), - F.onlyTemplateVisibility())); - - // The arguments at which the template was instantiated. - const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); - LV.merge(getLVForTemplateArgumentList(TemplateArgs, F)); + if (shouldConsiderTemplateLV(spec)) { + // From the template. + LV.merge(getLVForDecl(spec->getSpecializedTemplate(), + F.onlyTemplateVisibility())); + + // The arguments at which the template was instantiated. + const TemplateArgumentList &TemplateArgs = spec->getTemplateArgs(); + LV.merge(getLVForTemplateArgumentList(TemplateArgs, F)); + } } // Consider -fvisibility unless the type has C linkage. @@ -519,14 +543,16 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, LVFlags F) { // If this is a method template specialization, use the linkage for // the template parameters and arguments. - if (FunctionTemplateSpecializationInfo *Spec + if (FunctionTemplateSpecializationInfo *spec = MD->getTemplateSpecializationInfo()) { - LV.merge(getLVForTemplateArgumentList(*Spec->TemplateArguments, F)); - if (F.ConsiderTemplateParameterTypes) - LV.merge(getLVForTemplateParameterList( - Spec->getTemplate()->getTemplateParameters())); + if (shouldConsiderTemplateLV(MD, spec)) { + LV.merge(getLVForTemplateArgumentList(*spec->TemplateArguments, F)); + if (F.ConsiderTemplateParameterTypes) + LV.merge(getLVForTemplateParameterList( + spec->getTemplate()->getTemplateParameters())); + } - TSK = Spec->getTemplateSpecializationKind(); + TSK = spec->getTemplateSpecializationKind(); } else if (MemberSpecializationInfo *MSI = MD->getMemberSpecializationInfo()) { TSK = MSI->getTemplateSpecializationKind(); @@ -553,14 +579,16 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, LVFlags F) { // *do* apply -fvisibility to method declarations. } else if (const CXXRecordDecl *RD = dyn_cast(D)) { - if (const ClassTemplateSpecializationDecl *Spec + if (const ClassTemplateSpecializationDecl *spec = dyn_cast(RD)) { - // Merge template argument/parameter information for member - // class template specializations. - LV.merge(getLVForTemplateArgumentList(Spec->getTemplateArgs(), F)); + if (shouldConsiderTemplateLV(spec)) { + // Merge template argument/parameter information for member + // class template specializations. + LV.merge(getLVForTemplateArgumentList(spec->getTemplateArgs(), F)); if (F.ConsiderTemplateParameterTypes) LV.merge(getLVForTemplateParameterList( - Spec->getSpecializedTemplate()->getTemplateParameters())); + spec->getSpecializedTemplate()->getTemplateParameters())); + } } // Static data members. @@ -1304,6 +1332,19 @@ void VarDecl::setInit(Expr *I) { Init = I; } +bool VarDecl::extendsLifetimeOfTemporary() const { + assert(getType()->isReferenceType() &&"Non-references never extend lifetime"); + + const Expr *E = getInit(); + if (!E) + return false; + + if (const ExprWithCleanups *Cleanups = dyn_cast(E)) + E = Cleanups->getSubExpr(); + + return isa(E); +} + VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const { if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) return cast(MSI->getInstantiatedFrom()); @@ -2320,8 +2361,15 @@ void RecordDecl::LoadFieldsFromExternalStorage() const { ExternalASTSource::Deserializing TheFields(Source); llvm::SmallVector Decls; - if (Source->FindExternalLexicalDeclsBy(this, Decls)) + LoadedFieldsFromExternalStorage = true; + switch (Source->FindExternalLexicalDeclsBy(this, Decls)) { + case ELR_Success: + break; + + case ELR_AlreadyLoaded: + case ELR_Failure: return; + } #ifndef NDEBUG // Check that all decls we got were FieldDecls. @@ -2329,8 +2377,6 @@ void RecordDecl::LoadFieldsFromExternalStorage() const { assert(isa(Decls[i])); #endif - LoadedFieldsFromExternalStorage = true; - if (Decls.empty()) return; @@ -2376,6 +2422,16 @@ void BlockDecl::setCaptures(ASTContext &Context, Captures = static_cast(buffer); } +bool BlockDecl::capturesVariable(const VarDecl *variable) const { + for (capture_const_iterator + i = capture_begin(), e = capture_end(); i != e; ++i) + // Only auto vars can be captured, so no redeclaration worries. + if (i->getVariable() == variable) + return true; + + return false; +} + SourceRange BlockDecl::getSourceRange() const { return SourceRange(getLocation(), Body? Body->getLocEnd() : getLocation()); } diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 1766d39c1405..b2806f092cbd 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -29,7 +29,6 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/Support/raw_ostream.h" #include -#include using namespace clang; //===----------------------------------------------------------------------===// @@ -76,26 +75,27 @@ bool Decl::CollectingStats(bool Enable) { } void Decl::PrintStats() { - fprintf(stderr, "*** Decl Stats:\n"); + llvm::errs() << "\n*** Decl Stats:\n"; int totalDecls = 0; #define DECL(DERIVED, BASE) totalDecls += n##DERIVED##s; #define ABSTRACT_DECL(DECL) #include "clang/AST/DeclNodes.inc" - fprintf(stderr, " %d decls total.\n", totalDecls); + llvm::errs() << " " << totalDecls << " decls total.\n"; int totalBytes = 0; #define DECL(DERIVED, BASE) \ if (n##DERIVED##s > 0) { \ totalBytes += (int)(n##DERIVED##s * sizeof(DERIVED##Decl)); \ - fprintf(stderr, " %d " #DERIVED " decls, %d each (%d bytes)\n", \ - n##DERIVED##s, (int)sizeof(DERIVED##Decl), \ - (int)(n##DERIVED##s * sizeof(DERIVED##Decl))); \ + llvm::errs() << " " << n##DERIVED##s << " " #DERIVED " decls, " \ + << sizeof(DERIVED##Decl) << " each (" \ + << n##DERIVED##s * sizeof(DERIVED##Decl) \ + << " bytes)\n"; \ } #define ABSTRACT_DECL(DECL) #include "clang/AST/DeclNodes.inc" - fprintf(stderr, "Total bytes = %d\n", totalBytes); + llvm::errs() << "Total bytes = " << totalBytes << "\n"; } void Decl::add(Kind k) { @@ -641,12 +641,8 @@ DeclContext *Decl::getNonClosureContext() { // This is basically "while (DC->isClosure()) DC = DC->getParent();" // except that it's significantly more efficient to cast to a known // decl type and call getDeclContext() than to call getParent(). - do { - if (isa(DC)) { - DC = cast(DC)->getDeclContext(); - continue; - } - } while (false); + while (isa(DC)) + DC = cast(DC)->getDeclContext(); assert(!DC->isClosure()); return DC; @@ -843,12 +839,17 @@ DeclContext::LoadLexicalDeclsFromExternalStorage() const { // Notify that we have a DeclContext that is initializing. ExternalASTSource::Deserializing ADeclContext(Source); + // Load the external declarations, if any. llvm::SmallVector Decls; - if (Source->FindExternalLexicalDecls(this, Decls)) - return; - - // There is no longer any lexical storage in this context ExternalLexicalStorage = false; + switch (Source->FindExternalLexicalDecls(this, Decls)) { + case ELR_Success: + break; + + case ELR_Failure: + case ELR_AlreadyLoaded: + return; + } if (Decls.empty()) return; diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 08ac2a5be4d9..4b59bf37d74b 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -228,6 +228,11 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, if (!BaseClassDecl->hasTrivialDestructor()) data().HasTrivialDestructor = false; + // A class has an Objective-C object member if... or any of its bases + // has an Objective-C object member. + if (BaseClassDecl->hasObjectMember()) + setHasObjectMember(true); + // Keep track of the presence of mutable fields. if (BaseClassDecl->hasMutableFields()) data().HasMutableFields = true; @@ -239,22 +244,8 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, // Create base specifier for any direct or indirect virtual bases. data().VBases = new (C) CXXBaseSpecifier[VBases.size()]; data().NumVBases = VBases.size(); - for (int I = 0, E = VBases.size(); I != E; ++I) { - TypeSourceInfo *VBaseTypeInfo = VBases[I]->getTypeSourceInfo(); - - // Skip dependent types; we can't do any checking on them now. - if (VBaseTypeInfo->getType()->isDependentType()) - continue; - - CXXRecordDecl *VBaseClassDecl = cast( - VBaseTypeInfo->getType()->getAs()->getDecl()); - - data().getVBases()[I] = - CXXBaseSpecifier(VBaseClassDecl->getSourceRange(), true, - VBaseClassDecl->getTagKind() == TTK_Class, - VBases[I]->getAccessSpecifier(), VBaseTypeInfo, - SourceLocation()); - } + for (int I = 0, E = VBases.size(); I != E; ++I) + data().getVBases()[I] = *VBases[I]; } /// Callback function for CXXRecordDecl::forallBases that acknowledges @@ -698,10 +689,23 @@ NotASpecialMember:; // A POD struct is a class that is both a trivial class and a // standard-layout class, and has no non-static data members of type // non-POD struct, non-POD union (or array of such types). + // + // Automatic Reference Counting: the presence of a member of Objective-C pointer type + // that does not explicitly have no lifetime makes the class a non-POD. + // However, we delay setting PlainOldData to false in this case so that + // Sema has a chance to diagnostic causes where the same class will be + // non-POD with Automatic Reference Counting but a POD without Instant Objects. + // In this case, the class will become a non-POD class when we complete + // the definition. ASTContext &Context = getASTContext(); QualType T = Context.getBaseElementType(Field->getType()); - if (!T->isPODType()) + if (T->isObjCRetainableType() || T.isObjCGCStrong()) { + if (!Context.getLangOptions().ObjCAutoRefCount || + T.getObjCLifetime() != Qualifiers::OCL_ExplicitNone) + setHasObjectMember(true); + } else if (!T.isPODType(Context)) data().PlainOldData = false; + if (T->isReferenceType()) { data().HasTrivialDefaultConstructor = false; @@ -768,6 +772,8 @@ NotASpecialMember:; if (!FieldRec->hasTrivialDestructor()) data().HasTrivialDestructor = false; + if (FieldRec->hasObjectMember()) + setHasObjectMember(true); // C++0x [class]p7: // A standard-layout class is a class that: @@ -1078,6 +1084,20 @@ void CXXRecordDecl::completeDefinition() { void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) { RecordDecl::completeDefinition(); + if (hasObjectMember() && getASTContext().getLangOptions().ObjCAutoRefCount) { + // Objective-C Automatic Reference Counting: + // If a class has a non-static data member of Objective-C pointer + // type (or array thereof), it is a non-POD type and its + // default constructor (if any), copy constructor, copy assignment + // operator, and destructor are non-trivial. + struct DefinitionData &Data = data(); + Data.PlainOldData = false; + Data.HasTrivialDefaultConstructor = false; + Data.HasTrivialCopyConstructor = false; + Data.HasTrivialCopyAssignment = false; + Data.HasTrivialDestructor = false; + } + // If the class may be abstract (but hasn't been marked as such), check for // any pure final overriders. if (mayBeAbstract()) { diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index e2c4f38ff9be..557b681d2fa6 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -452,6 +452,34 @@ ObjCMethodFamily ObjCMethodDecl::getMethodFamily() const { if (!isInstanceMethod()) family = OMF_None; break; + + case OMF_performSelector: + if (!isInstanceMethod() || + !getResultType()->isObjCIdType()) + family = OMF_None; + else { + unsigned noParams = param_size(); + if (noParams < 1 || noParams > 3) + family = OMF_None; + else { + ObjCMethodDecl::arg_type_iterator it = arg_type_begin(); + QualType ArgT = (*it); + if (!ArgT->isObjCSelType()) { + family = OMF_None; + break; + } + while (--noParams) { + it++; + ArgT = (*it); + if (!ArgT->isObjCIdType()) { + family = OMF_None; + break; + } + } + } + } + break; + } // Cache the result. @@ -474,8 +502,34 @@ void ObjCMethodDecl::createImplicitParams(ASTContext &Context, } else // we have a factory method. selfTy = Context.getObjCClassType(); - setSelfDecl(ImplicitParamDecl::Create(Context, this, SourceLocation(), - &Context.Idents.get("self"), selfTy)); + bool selfIsPseudoStrong = false; + bool selfIsConsumed = false; + if (isInstanceMethod() && Context.getLangOptions().ObjCAutoRefCount) { + selfIsConsumed = hasAttr(); + + // 'self' is always __strong. It's actually pseudo-strong except + // in init methods, though. + Qualifiers qs; + qs.setObjCLifetime(Qualifiers::OCL_Strong); + selfTy = Context.getQualifiedType(selfTy, qs); + + // In addition, 'self' is const unless this is an init method. + if (getMethodFamily() != OMF_init) { + selfTy = selfTy.withConst(); + selfIsPseudoStrong = true; + } + } + + ImplicitParamDecl *self + = ImplicitParamDecl::Create(Context, this, SourceLocation(), + &Context.Idents.get("self"), selfTy); + setSelfDecl(self); + + if (selfIsConsumed) + self->addAttr(new (Context) NSConsumedAttr(SourceLocation(), Context)); + + if (selfIsPseudoStrong) + self->setARCPseudoStrong(true); setCmdDecl(ImplicitParamDecl::Create(Context, this, SourceLocation(), &Context.Idents.get("_cmd"), diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index 421770ea70fb..19554a3baaea 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -933,6 +933,11 @@ void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) { first = false; } + if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_strong) { + Out << (first ? ' ' : ',') << "strong"; + first = false; + } + if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_copy) { Out << (first ? ' ' : ',') << "copy"; first = false; diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp index cef54e97c93a..72c0e9da7f1d 100644 --- a/lib/AST/DeclarationName.cpp +++ b/lib/AST/DeclarationName.cpp @@ -533,6 +533,28 @@ bool DeclarationNameInfo::containsUnexpandedParameterPack() const { llvm_unreachable("All name kinds handled."); } +bool DeclarationNameInfo::isInstantiationDependent() const { + switch (Name.getNameKind()) { + case DeclarationName::Identifier: + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + case DeclarationName::CXXOperatorName: + case DeclarationName::CXXLiteralOperatorName: + case DeclarationName::CXXUsingDirective: + return false; + + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: + if (TypeSourceInfo *TInfo = LocInfo.NamedType.TInfo) + return TInfo->getType()->isInstantiationDependentType(); + + return Name.getCXXNameType()->isInstantiationDependentType(); + } + llvm_unreachable("All name kinds handled."); +} + std::string DeclarationNameInfo::getAsString() const { std::string Result; llvm::raw_string_ostream OS(Result); diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 987213907e45..4611ae369969 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -142,9 +142,10 @@ void ExplicitTemplateArgumentList::initializeFrom( } void ExplicitTemplateArgumentList::initializeFrom( - const TemplateArgumentListInfo &Info, - bool &Dependent, - bool &ContainsUnexpandedParameterPack) { + const TemplateArgumentListInfo &Info, + bool &Dependent, + bool &InstantiationDependent, + bool &ContainsUnexpandedParameterPack) { LAngleLoc = Info.getLAngleLoc(); RAngleLoc = Info.getRAngleLoc(); NumTemplateArgs = Info.size(); @@ -152,6 +153,8 @@ void ExplicitTemplateArgumentList::initializeFrom( TemplateArgumentLoc *ArgBuffer = getTemplateArgs(); for (unsigned i = 0; i != NumTemplateArgs; ++i) { Dependent = Dependent || Info[i].getArgument().isDependent(); + InstantiationDependent = InstantiationDependent || + Info[i].getArgument().isInstantiationDependent(); ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack || Info[i].getArgument().containsUnexpandedParameterPack(); @@ -178,14 +181,16 @@ std::size_t ExplicitTemplateArgumentList::sizeFor( return sizeFor(Info.size()); } -/// \brief Compute the type- and value-dependence of a declaration reference +/// \brief Compute the type-, value-, and instantiation-dependence of a +/// declaration reference /// based on the declaration being referenced. static void computeDeclRefDependence(NamedDecl *D, QualType T, bool &TypeDependent, - bool &ValueDependent) { + bool &ValueDependent, + bool &InstantiationDependent) { TypeDependent = false; ValueDependent = false; - + InstantiationDependent = false; // (TD) C++ [temp.dep.expr]p3: // An id-expression is type-dependent if it contains: @@ -200,20 +205,31 @@ static void computeDeclRefDependence(NamedDecl *D, QualType T, if (T->isDependentType()) { TypeDependent = true; ValueDependent = true; + InstantiationDependent = true; return; + } else if (T->isInstantiationDependentType()) { + InstantiationDependent = true; } // (TD) - a conversion-function-id that specifies a dependent type if (D->getDeclName().getNameKind() - == DeclarationName::CXXConversionFunctionName && - D->getDeclName().getCXXNameType()->isDependentType()) { - TypeDependent = true; - ValueDependent = true; - return; + == DeclarationName::CXXConversionFunctionName) { + QualType T = D->getDeclName().getCXXNameType(); + if (T->isDependentType()) { + TypeDependent = true; + ValueDependent = true; + InstantiationDependent = true; + return; + } + + if (T->isInstantiationDependentType()) + InstantiationDependent = true; } + // (VD) - the name of a non-type template parameter, if (isa(D)) { ValueDependent = true; + InstantiationDependent = true; return; } @@ -223,16 +239,20 @@ static void computeDeclRefDependence(NamedDecl *D, QualType T, if (Var->getType()->isIntegralOrEnumerationType() && Var->getType().getCVRQualifiers() == Qualifiers::Const) { if (const Expr *Init = Var->getAnyInitializer()) - if (Init->isValueDependent()) + if (Init->isValueDependent()) { ValueDependent = true; + InstantiationDependent = true; + } } // (VD) - FIXME: Missing from the standard: // - a member function or a static data member of the current // instantiation else if (Var->isStaticDataMember() && - Var->getDeclContext()->isDependentContext()) + Var->getDeclContext()->isDependentContext()) { ValueDependent = true; + InstantiationDependent = true; + } return; } @@ -242,6 +262,7 @@ static void computeDeclRefDependence(NamedDecl *D, QualType T, // instantiation if (isa(D) && D->getDeclContext()->isDependentContext()) { ValueDependent = true; + InstantiationDependent = true; return; } } @@ -249,7 +270,9 @@ static void computeDeclRefDependence(NamedDecl *D, QualType T, void DeclRefExpr::computeDependence() { bool TypeDependent = false; bool ValueDependent = false; - computeDeclRefDependence(getDecl(), getType(), TypeDependent, ValueDependent); + bool InstantiationDependent = false; + computeDeclRefDependence(getDecl(), getType(), TypeDependent, ValueDependent, + InstantiationDependent); // (TD) C++ [temp.dep.expr]p3: // An id-expression is type-dependent if it contains: @@ -262,13 +285,16 @@ void DeclRefExpr::computeDependence() { hasExplicitTemplateArgs() && TemplateSpecializationType::anyDependentTemplateArguments( getTemplateArgs(), - getNumTemplateArgs())) { + getNumTemplateArgs(), + InstantiationDependent)) { TypeDependent = true; ValueDependent = true; + InstantiationDependent = true; } ExprBits.TypeDependent = TypeDependent; ExprBits.ValueDependent = ValueDependent; + ExprBits.InstantiationDependent = InstantiationDependent; // Is the declaration a parameter pack? if (getDecl()->isParameterPack()) @@ -280,7 +306,7 @@ DeclRefExpr::DeclRefExpr(NestedNameSpecifierLoc QualifierLoc, NamedDecl *FoundD, const TemplateArgumentListInfo *TemplateArgs, QualType T, ExprValueKind VK) - : Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false), + : Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false, false), D(D), Loc(NameInfo.getLoc()), DNLoc(NameInfo.getInfo()) { DeclRefExprBits.HasQualifier = QualifierLoc ? 1 : 0; if (QualifierLoc) @@ -289,9 +315,17 @@ DeclRefExpr::DeclRefExpr(NestedNameSpecifierLoc QualifierLoc, if (FoundD) getInternalFoundDecl() = FoundD; DeclRefExprBits.HasExplicitTemplateArgs = TemplateArgs ? 1 : 0; - if (TemplateArgs) - getExplicitTemplateArgs().initializeFrom(*TemplateArgs); - + if (TemplateArgs) { + bool Dependent = false; + bool InstantiationDependent = false; + bool ContainsUnexpandedParameterPack = false; + getExplicitTemplateArgs().initializeFrom(*TemplateArgs, Dependent, + InstantiationDependent, + ContainsUnexpandedParameterPack); + if (InstantiationDependent) + setInstantiationDependent(true); + } + computeDependence(); } @@ -498,8 +532,8 @@ double FloatingLiteral::getValueAsApproximateDouble() const { return V.convertToDouble(); } -StringLiteral *StringLiteral::Create(ASTContext &C, const char *StrData, - unsigned ByteLength, bool Wide, +StringLiteral *StringLiteral::Create(ASTContext &C, llvm::StringRef Str, + bool Wide, bool Pascal, QualType Ty, const SourceLocation *Loc, unsigned NumStrs) { @@ -511,10 +545,10 @@ StringLiteral *StringLiteral::Create(ASTContext &C, const char *StrData, 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); + char *AStrData = new (C, 1) char[Str.size()]; + memcpy(AStrData, Str.data(), Str.size()); SL->StrData = AStrData; - SL->ByteLength = ByteLength; + SL->ByteLength = Str.size(); SL->IsWide = Wide; SL->IsPascal = Pascal; SL->TokLocs[0] = Loc[0]; @@ -593,7 +627,7 @@ getLocationOfByte(unsigned ByteNo, const SourceManager &SM, // If the byte is in this token, return the location of the byte. if (ByteNo < TokNumBytes || - (ByteNo == TokNumBytes && TokNo == getNumConcatenated())) { + (ByteNo == TokNumBytes && TokNo == getNumConcatenated() - 1)) { unsigned Offset = SLP.getOffsetOfStringByte(TheTok, ByteNo); // Now that we know the offset of the token in the spelling, use the @@ -670,6 +704,7 @@ CallExpr::CallExpr(ASTContext& C, StmtClass SC, Expr *fn, unsigned NumPreArgs, : Expr(SC, t, VK, OK_Ordinary, fn->isTypeDependent(), fn->isValueDependent(), + fn->isInstantiationDependent(), fn->containsUnexpandedParameterPack()), NumArgs(numargs) { @@ -680,6 +715,8 @@ CallExpr::CallExpr(ASTContext& C, StmtClass SC, Expr *fn, unsigned NumPreArgs, ExprBits.TypeDependent = true; if (args[i]->isValueDependent()) ExprBits.ValueDependent = true; + if (args[i]->isInstantiationDependent()) + ExprBits.InstantiationDependent = true; if (args[i]->containsUnexpandedParameterPack()) ExprBits.ContainsUnexpandedParameterPack = true; @@ -695,6 +732,7 @@ CallExpr::CallExpr(ASTContext& C, Expr *fn, Expr **args, unsigned numargs, : Expr(CallExprClass, t, VK, OK_Ordinary, fn->isTypeDependent(), fn->isValueDependent(), + fn->isInstantiationDependent(), fn->containsUnexpandedParameterPack()), NumArgs(numargs) { @@ -705,6 +743,8 @@ CallExpr::CallExpr(ASTContext& C, Expr *fn, Expr **args, unsigned numargs, ExprBits.TypeDependent = true; if (args[i]->isValueDependent()) ExprBits.ValueDependent = true; + if (args[i]->isInstantiationDependent()) + ExprBits.InstantiationDependent = true; if (args[i]->containsUnexpandedParameterPack()) ExprBits.ContainsUnexpandedParameterPack = true; @@ -862,6 +902,7 @@ OffsetOfExpr::OffsetOfExpr(ASTContext &C, QualType type, : Expr(OffsetOfExprClass, type, VK_RValue, OK_Ordinary, /*TypeDependent=*/false, /*ValueDependent=*/tsi->getType()->isDependentType(), + tsi->getType()->isInstantiationDependentType(), tsi->getType()->containsUnexpandedParameterPack()), OperatorLoc(OperatorLoc), RParenLoc(RParenLoc), TSInfo(tsi), NumComps(numComps), NumExprs(numExprs) @@ -917,7 +958,12 @@ MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow, if (QualifierLoc && QualifierLoc.getNestedNameSpecifier()->isDependent()) { E->setValueDependent(true); E->setTypeDependent(true); - } + E->setInstantiationDependent(true); + } + else if (QualifierLoc && + QualifierLoc.getNestedNameSpecifier()->isInstantiationDependent()) + E->setInstantiationDependent(true); + E->HasQualifierOrFoundDecl = true; MemberNameQualifier *NQ = E->getMemberQualifier(); @@ -926,8 +972,15 @@ MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow, } if (targs) { + bool Dependent = false; + bool InstantiationDependent = false; + bool ContainsUnexpandedParameterPack = false; E->HasExplicitTemplateArgumentList = true; - E->getExplicitTemplateArgs().initializeFrom(*targs); + E->getExplicitTemplateArgs().initializeFrom(*targs, Dependent, + InstantiationDependent, + ContainsUnexpandedParameterPack); + if (InstantiationDependent) + E->setInstantiationDependent(true); } return E; @@ -1045,6 +1098,12 @@ const char *CastExpr::getCastKindName() const { return "IntegralComplexCast"; case CK_IntegralComplexToFloatingComplex: return "IntegralComplexToFloatingComplex"; + case CK_ObjCConsumeObject: + return "ObjCConsumeObject"; + case CK_ObjCProduceObject: + return "ObjCProduceObject"; + case CK_ObjCReclaimReturnedObject: + return "ObjCReclaimReturnedObject"; } llvm_unreachable("Unhandled cast kind!"); @@ -1056,7 +1115,12 @@ Expr *CastExpr::getSubExprAsWritten() { CastExpr *E = this; do { SubExpr = E->getSubExpr(); - + + // Skip through reference binding to temporary. + if (MaterializeTemporaryExpr *Materialize + = dyn_cast(SubExpr)) + SubExpr = Materialize->GetTemporaryExpr(); + // Skip any temporary bindings; they're implicit. if (CXXBindTemporaryExpr *Binder = dyn_cast(SubExpr)) SubExpr = Binder->getSubExpr(); @@ -1242,7 +1306,7 @@ InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc, Expr **initExprs, unsigned numInits, SourceLocation rbraceloc) : Expr(InitListExprClass, QualType(), VK_RValue, OK_Ordinary, false, false, - false), + false, false), InitExprs(C, numInits), LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0), HadArrayRangeDesignator(false) @@ -1252,6 +1316,8 @@ InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc, ExprBits.TypeDependent = true; if (initExprs[I]->isValueDependent()) ExprBits.ValueDependent = true; + if (initExprs[I]->isInstantiationDependent()) + ExprBits.InstantiationDependent = true; if (initExprs[I]->containsUnexpandedParameterPack()) ExprBits.ContainsUnexpandedParameterPack = true; } @@ -1490,6 +1556,17 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, case ObjCMessageExprClass: { const ObjCMessageExpr *ME = cast(this); + if (Ctx.getLangOptions().ObjCAutoRefCount && + ME->isInstanceMessage() && + !ME->getType()->isVoidType() && + ME->getSelector().getIdentifierInfoForSlot(0) && + ME->getSelector().getIdentifierInfoForSlot(0) + ->getName().startswith("init")) { + Loc = getExprLoc(); + R1 = ME->getSourceRange(); + return true; + } + const ObjCMethodDecl *MD = ME->getMethodDecl(); if (MD && MD->getAttr()) { Loc = getExprLoc(); @@ -1584,6 +1661,9 @@ bool Expr::isOBJCGCCandidate(ASTContext &Ctx) const { return cast(E)->getSubExpr()->isOBJCGCCandidate(Ctx); case ImplicitCastExprClass: return cast(E)->getSubExpr()->isOBJCGCCandidate(Ctx); + case MaterializeTemporaryExprClass: + return cast(E)->GetTemporaryExpr() + ->isOBJCGCCandidate(Ctx); case CStyleCastExprClass: return cast(E)->getSubExpr()->isOBJCGCCandidate(Ctx); case DeclRefExprClass: { @@ -1858,7 +1938,8 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const { case CXXStaticCastExprClass: case CXXFunctionalCastExprClass: case BinaryOperatorClass: - case CompoundAssignOperatorClass: { + case CompoundAssignOperatorClass: + case MaterializeTemporaryExprClass: { CanThrowResult CT = isTypeDependent() ? CT_Dependent : CT_Cannot; return MergeCanThrow(CT, CanSubExprsThrow(C, this)); } @@ -1938,6 +2019,12 @@ Expr *Expr::IgnoreParenCasts() { continue; } } + if (MaterializeTemporaryExpr *Materialize + = dyn_cast(E)) { + E = Materialize->GetTemporaryExpr(); + continue; + } + return E; } } @@ -1967,6 +2054,10 @@ Expr *Expr::IgnoreParenLValueCasts() { E = P->getResultExpr(); continue; } + } else if (MaterializeTemporaryExpr *Materialize + = dyn_cast(E)) { + E = Materialize->GetTemporaryExpr(); + continue; } break; } @@ -1996,13 +2087,18 @@ Expr *Expr::IgnoreParenImpCasts() { continue; } } + if (MaterializeTemporaryExpr *Materialize + = dyn_cast(E)) { + E = Materialize->GetTemporaryExpr(); + continue; + } return E; } } Expr *Expr::IgnoreConversionOperator() { if (CXXMemberCallExpr *MCE = dyn_cast(this)) { - if (isa(MCE->getMethodDecl())) + if (MCE->getMethodDecl() && isa(MCE->getMethodDecl())) return MCE->getImplicitObjectArgument(); } return this; @@ -2059,6 +2155,9 @@ Expr *Expr::IgnoreParenNoopCasts(ASTContext &Ctx) { bool Expr::isDefaultArgument() const { const Expr *E = this; + if (const MaterializeTemporaryExpr *M = dyn_cast(E)) + E = M->GetTemporaryExpr(); + while (const ImplicitCastExpr *ICE = dyn_cast(E)) E = ICE->getSubExprAsWritten(); @@ -2068,6 +2167,9 @@ bool Expr::isDefaultArgument() const { /// \brief Skip over any no-op casts and any temporary-binding /// expressions. static const Expr *skipTemporaryBindingsNoOpCastsAndParens(const Expr *E) { + if (const MaterializeTemporaryExpr *M = dyn_cast(E)) + E = M->GetTemporaryExpr(); + while (const ImplicitCastExpr *ICE = dyn_cast(E)) { if (ICE->getCastKind() == CK_NoOp) E = ICE->getSubExpr(); @@ -2155,6 +2257,12 @@ bool Expr::isImplicitCXXThis() const { } } + if (const MaterializeTemporaryExpr *M + = dyn_cast(E)) { + E = M->GetTemporaryExpr(); + continue; + } + break; } @@ -2287,6 +2395,10 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const { ->isConstantInitializer(Ctx, false); break; + + case MaterializeTemporaryExprClass: + return llvm::cast(this)->GetTemporaryExpr() + ->isConstantInitializer(Ctx, false); } return isEvaluatable(Ctx); } @@ -2345,6 +2457,9 @@ Expr::isNullPointerConstant(ASTContext &Ctx, } else if (isa(this)) { // The GNU __null extension is always a null pointer constant. return NPCK_GNUNull; + } else if (const MaterializeTemporaryExpr *M + = dyn_cast(this)) { + return M->GetTemporaryExpr()->isNullPointerConstant(Ctx, NPC); } // C++0x nullptr_t is always a null pointer constant. @@ -2414,10 +2529,14 @@ FieldDecl *Expr::getBitField() { if (Field->isBitField()) return Field; - if (BinaryOperator *BinOp = dyn_cast(E)) + if (BinaryOperator *BinOp = dyn_cast(E)) { if (BinOp->isAssignmentOp() && BinOp->getLHS()) return BinOp->getLHS()->getBitField(); + if (BinOp->getOpcode() == BO_Comma && BinOp->getRHS()) + return BinOp->getRHS()->getBitField(); + } + return 0; } @@ -2517,9 +2636,10 @@ ObjCMessageExpr::ObjCMessageExpr(QualType T, SourceLocation RBracLoc) : Expr(ObjCMessageExprClass, T, VK, OK_Ordinary, /*TypeDependent=*/false, /*ValueDependent=*/false, + /*InstantiationDependent=*/false, /*ContainsUnexpandedParameterPack=*/false), NumArgs(NumArgs), Kind(IsInstanceSuper? SuperInstance : SuperClass), - HasMethod(Method != 0), SuperLoc(SuperLoc), + HasMethod(Method != 0), IsDelegateInitCall(false), SuperLoc(SuperLoc), SelectorOrMethod(reinterpret_cast(Method? Method : Sel.getAsOpaquePtr())), SelectorLoc(SelLoc), LBracLoc(LBracLoc), RBracLoc(RBracLoc) @@ -2539,8 +2659,10 @@ ObjCMessageExpr::ObjCMessageExpr(QualType T, Expr **Args, unsigned NumArgs, SourceLocation RBracLoc) : Expr(ObjCMessageExprClass, T, VK, OK_Ordinary, T->isDependentType(), - T->isDependentType(), T->containsUnexpandedParameterPack()), - NumArgs(NumArgs), Kind(Class), HasMethod(Method != 0), + T->isDependentType(), T->isInstantiationDependentType(), + T->containsUnexpandedParameterPack()), + NumArgs(NumArgs), Kind(Class), + HasMethod(Method != 0), IsDelegateInitCall(false), SelectorOrMethod(reinterpret_cast(Method? Method : Sel.getAsOpaquePtr())), SelectorLoc(SelLoc), LBracLoc(LBracLoc), RBracLoc(RBracLoc) @@ -2552,6 +2674,8 @@ ObjCMessageExpr::ObjCMessageExpr(QualType T, ExprBits.TypeDependent = true; if (Args[I]->isValueDependent()) ExprBits.ValueDependent = true; + if (Args[I]->isInstantiationDependent()) + ExprBits.InstantiationDependent = true; if (Args[I]->containsUnexpandedParameterPack()) ExprBits.ContainsUnexpandedParameterPack = true; @@ -2570,8 +2694,10 @@ ObjCMessageExpr::ObjCMessageExpr(QualType T, SourceLocation RBracLoc) : Expr(ObjCMessageExprClass, T, VK, OK_Ordinary, Receiver->isTypeDependent(), Receiver->isTypeDependent(), + Receiver->isInstantiationDependent(), Receiver->containsUnexpandedParameterPack()), - NumArgs(NumArgs), Kind(Instance), HasMethod(Method != 0), + NumArgs(NumArgs), Kind(Instance), + HasMethod(Method != 0), IsDelegateInitCall(false), SelectorOrMethod(reinterpret_cast(Method? Method : Sel.getAsOpaquePtr())), SelectorLoc(SelLoc), LBracLoc(LBracLoc), RBracLoc(RBracLoc) @@ -2583,6 +2709,8 @@ ObjCMessageExpr::ObjCMessageExpr(QualType T, ExprBits.TypeDependent = true; if (Args[I]->isValueDependent()) ExprBits.ValueDependent = true; + if (Args[I]->isInstantiationDependent()) + ExprBits.InstantiationDependent = true; if (Args[I]->containsUnexpandedParameterPack()) ExprBits.ContainsUnexpandedParameterPack = true; @@ -2702,6 +2830,19 @@ ObjCInterfaceDecl *ObjCMessageExpr::getReceiverInterface() const { return 0; } +llvm::StringRef ObjCBridgedCastExpr::getBridgeKindName() const { + switch (getBridgeKind()) { + case OBC_Bridge: + return "__bridge"; + case OBC_BridgeTransfer: + return "__bridge_transfer"; + case OBC_BridgeRetained: + return "__bridge_retained"; + } + + return "__bridge"; +} + bool ChooseExpr::isConditionTrue(const ASTContext &C) const { return getCond()->EvaluateAsInt(C) != 0; } @@ -2711,6 +2852,7 @@ ShuffleVectorExpr::ShuffleVectorExpr(ASTContext &C, Expr **args, unsigned nexpr, SourceLocation RP) : Expr(ShuffleVectorExprClass, Type, VK_RValue, OK_Ordinary, Type->isDependentType(), Type->isDependentType(), + Type->isInstantiationDependentType(), Type->containsUnexpandedParameterPack()), BuiltinLoc(BLoc), RParenLoc(RP), NumExprs(nexpr) { @@ -2720,6 +2862,8 @@ ShuffleVectorExpr::ShuffleVectorExpr(ASTContext &C, Expr **args, unsigned nexpr, ExprBits.TypeDependent = true; if (args[i]->isValueDependent()) ExprBits.ValueDependent = true; + if (args[i]->isInstantiationDependent()) + ExprBits.InstantiationDependent = true; if (args[i]->containsUnexpandedParameterPack()) ExprBits.ContainsUnexpandedParameterPack = true; @@ -2749,6 +2893,7 @@ GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context, AssocExprs[ResultIndex]->getObjectKind(), AssocExprs[ResultIndex]->isTypeDependent(), AssocExprs[ResultIndex]->isValueDependent(), + AssocExprs[ResultIndex]->isInstantiationDependent(), ContainsUnexpandedParameterPack), AssocTypes(new (Context) TypeSourceInfo*[NumAssocs]), SubExprs(new (Context) Stmt*[END_EXPR+NumAssocs]), NumAssocs(NumAssocs), @@ -2769,8 +2914,9 @@ GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context, Context.DependentTy, VK_RValue, OK_Ordinary, - /*isTypeDependent=*/ true, - /*isValueDependent=*/ true, + /*isTypeDependent=*/true, + /*isValueDependent=*/true, + /*isInstantiationDependent=*/true, ContainsUnexpandedParameterPack), AssocTypes(new (Context) TypeSourceInfo*[NumAssocs]), SubExprs(new (Context) Stmt*[END_EXPR+NumAssocs]), NumAssocs(NumAssocs), @@ -2785,7 +2931,7 @@ GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context, // DesignatedInitExpr //===----------------------------------------------------------------------===// -IdentifierInfo *DesignatedInitExpr::Designator::getFieldName() { +IdentifierInfo *DesignatedInitExpr::Designator::getFieldName() const { assert(Kind == FieldDesignator && "Only valid on a field designator"); if (Field.NameOrField & 0x01) return reinterpret_cast(Field.NameOrField&~0x01); @@ -2804,6 +2950,7 @@ DesignatedInitExpr::DesignatedInitExpr(ASTContext &C, QualType Ty, : Expr(DesignatedInitExprClass, Ty, Init->getValueKind(), Init->getObjectKind(), Init->isTypeDependent(), Init->isValueDependent(), + Init->isInstantiationDependent(), Init->containsUnexpandedParameterPack()), EqualOrColonLoc(EqualOrColonLoc), GNUSyntax(GNUSyntax), NumDesignators(NumDesignators), NumSubExprs(NumIndexExprs + 1) { @@ -2824,7 +2971,8 @@ DesignatedInitExpr::DesignatedInitExpr(ASTContext &C, QualType Ty, Expr *Index = IndexExprs[IndexIdx]; if (Index->isTypeDependent() || Index->isValueDependent()) ExprBits.ValueDependent = true; - + if (Index->isInstantiationDependent()) + ExprBits.InstantiationDependent = true; // Propagate unexpanded parameter packs. if (Index->containsUnexpandedParameterPack()) ExprBits.ContainsUnexpandedParameterPack = true; @@ -2836,9 +2984,14 @@ DesignatedInitExpr::DesignatedInitExpr(ASTContext &C, QualType Ty, Expr *Start = IndexExprs[IndexIdx]; Expr *End = IndexExprs[IndexIdx + 1]; if (Start->isTypeDependent() || Start->isValueDependent() || - End->isTypeDependent() || End->isValueDependent()) + End->isTypeDependent() || End->isValueDependent()) { ExprBits.ValueDependent = true; - + ExprBits.InstantiationDependent = true; + } else if (Start->isInstantiationDependent() || + End->isInstantiationDependent()) { + ExprBits.InstantiationDependent = true; + } + // Propagate unexpanded parameter packs. if (Start->containsUnexpandedParameterPack() || End->containsUnexpandedParameterPack()) @@ -2960,17 +3113,19 @@ void DesignatedInitExpr::ExpandDesignator(ASTContext &C, unsigned Idx, ParenListExpr::ParenListExpr(ASTContext& C, SourceLocation lparenloc, Expr **exprs, unsigned nexprs, - SourceLocation rparenloc) - : Expr(ParenListExprClass, QualType(), VK_RValue, OK_Ordinary, - false, false, false), + SourceLocation rparenloc, QualType T) + : Expr(ParenListExprClass, T, VK_RValue, OK_Ordinary, + false, false, false, false), NumExprs(nexprs), LParenLoc(lparenloc), RParenLoc(rparenloc) { - + assert(!T.isNull() && "ParenListExpr must have a valid type"); Exprs = new (C) Stmt*[nexprs]; for (unsigned i = 0; i != nexprs; ++i) { if (exprs[i]->isTypeDependent()) ExprBits.TypeDependent = true; if (exprs[i]->isValueDependent()) ExprBits.ValueDependent = true; + if (exprs[i]->isInstantiationDependent()) + ExprBits.InstantiationDependent = true; if (exprs[i]->containsUnexpandedParameterPack()) ExprBits.ContainsUnexpandedParameterPack = true; @@ -2981,6 +3136,8 @@ ParenListExpr::ParenListExpr(ASTContext& C, SourceLocation lparenloc, const OpaqueValueExpr *OpaqueValueExpr::findInCopyConstruct(const Expr *e) { if (const ExprWithCleanups *ewc = dyn_cast(e)) e = ewc->getSubExpr(); + if (const MaterializeTemporaryExpr *m = dyn_cast(e)) + e = m->GetTemporaryExpr(); e = cast(e)->getArg(0); while (const ImplicitCastExpr *ice = dyn_cast(e)) e = ice->getSubExpr(); @@ -3033,13 +3190,16 @@ Stmt::child_range ObjCMessageExpr::children() { BlockDeclRefExpr::BlockDeclRefExpr(VarDecl *d, QualType t, ExprValueKind VK, SourceLocation l, bool ByRef, bool constAdded) - : Expr(BlockDeclRefExprClass, t, VK, OK_Ordinary, false, false, + : Expr(BlockDeclRefExprClass, t, VK, OK_Ordinary, false, false, false, d->isParameterPack()), D(d), Loc(l), IsByRef(ByRef), ConstQualAdded(constAdded) { bool TypeDependent = false; bool ValueDependent = false; - computeDeclRefDependence(D, getType(), TypeDependent, ValueDependent); + bool InstantiationDependent = false; + computeDeclRefDependence(D, getType(), TypeDependent, ValueDependent, + InstantiationDependent); ExprBits.TypeDependent = TypeDependent; ExprBits.ValueDependent = ValueDependent; + ExprBits.InstantiationDependent = InstantiationDependent; } diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 1a1a0a36a65b..f92afffb5851 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -57,6 +57,7 @@ CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew, SourceLocation constructorRParen) : Expr(CXXNewExprClass, ty, VK_RValue, OK_Ordinary, ty->isDependentType(), ty->isDependentType(), + ty->isInstantiationDependentType(), ty->containsUnexpandedParameterPack()), GlobalNew(globalNew), Initializer(initializer), UsualArrayDeleteWantsSize(usualArrayDeleteWantsSize), @@ -68,6 +69,9 @@ CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew, AllocateArgsArray(C, arraySize != 0, numPlaceArgs, numConsArgs); unsigned i = 0; if (Array) { + if (arraySize->isInstantiationDependent()) + ExprBits.InstantiationDependent = true; + if (arraySize->containsUnexpandedParameterPack()) ExprBits.ContainsUnexpandedParameterPack = true; @@ -75,6 +79,8 @@ CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew, } for (unsigned j = 0; j < NumPlacementArgs; ++j) { + if (placementArgs[j]->isInstantiationDependent()) + ExprBits.InstantiationDependent = true; if (placementArgs[j]->containsUnexpandedParameterPack()) ExprBits.ContainsUnexpandedParameterPack = true; @@ -82,6 +88,8 @@ CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew, } for (unsigned j = 0; j < NumConstructorArgs; ++j) { + if (constructorArgs[j]->isInstantiationDependent()) + ExprBits.InstantiationDependent = true; if (constructorArgs[j]->containsUnexpandedParameterPack()) ExprBits.ContainsUnexpandedParameterPack = true; @@ -144,6 +152,14 @@ CXXPseudoDestructorExpr::CXXPseudoDestructorExpr(ASTContext &Context, (DestroyedType.getTypeSourceInfo() && DestroyedType.getTypeSourceInfo()->getType()->isDependentType())), /*isValueDependent=*/Base->isValueDependent(), + (Base->isInstantiationDependent() || + (QualifierLoc && + QualifierLoc.getNestedNameSpecifier()->isInstantiationDependent()) || + (ScopeType && + ScopeType->getType()->isInstantiationDependentType()) || + (DestroyedType.getTypeSourceInfo() && + DestroyedType.getTypeSourceInfo()->getType() + ->isInstantiationDependentType())), // ContainsUnexpandedParameterPack (Base->containsUnexpandedParameterPack() || (QualifierLoc && @@ -212,9 +228,14 @@ OverloadExpr::OverloadExpr(StmtClass K, ASTContext &C, UnresolvedSetIterator Begin, UnresolvedSetIterator End, bool KnownDependent, + bool KnownInstantiationDependent, bool KnownContainsUnexpandedParameterPack) : Expr(K, C.OverloadTy, VK_LValue, OK_Ordinary, KnownDependent, KnownDependent, + (KnownInstantiationDependent || + NameInfo.isInstantiationDependent() || + (QualifierLoc && + QualifierLoc.getNestedNameSpecifier()->isInstantiationDependent())), (KnownContainsUnexpandedParameterPack || NameInfo.containsUnexpandedParameterPack() || (QualifierLoc && @@ -246,14 +267,18 @@ OverloadExpr::OverloadExpr(StmtClass K, ASTContext &C, // expansions. if (TemplateArgs) { bool Dependent = false; + bool InstantiationDependent = false; bool ContainsUnexpandedParameterPack = false; getExplicitTemplateArgs().initializeFrom(*TemplateArgs, Dependent, + InstantiationDependent, ContainsUnexpandedParameterPack); if (Dependent) { - ExprBits.TypeDependent = true; - ExprBits.ValueDependent = true; - } + ExprBits.TypeDependent = true; + ExprBits.ValueDependent = true; + } + if (InstantiationDependent) + ExprBits.InstantiationDependent = true; if (ContainsUnexpandedParameterPack) ExprBits.ContainsUnexpandedParameterPack = true; } @@ -291,6 +316,9 @@ DependentScopeDeclRefExpr::DependentScopeDeclRefExpr(QualType T, const TemplateArgumentListInfo *Args) : Expr(DependentScopeDeclRefExprClass, T, VK_LValue, OK_Ordinary, true, true, + (NameInfo.isInstantiationDependent() || + (QualifierLoc && + QualifierLoc.getNestedNameSpecifier()->isInstantiationDependent())), (NameInfo.containsUnexpandedParameterPack() || (QualifierLoc && QualifierLoc.getNestedNameSpecifier() @@ -300,11 +328,14 @@ DependentScopeDeclRefExpr::DependentScopeDeclRefExpr(QualType T, { if (Args) { bool Dependent = true; + bool InstantiationDependent = true; bool ContainsUnexpandedParameterPack = ExprBits.ContainsUnexpandedParameterPack; reinterpret_cast(this+1) - ->initializeFrom(*Args, Dependent, ContainsUnexpandedParameterPack); + ->initializeFrom(*Args, Dependent, InstantiationDependent, + ContainsUnexpandedParameterPack); + ExprBits.ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack; } } @@ -632,6 +663,7 @@ CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T, SourceRange ParenRange) : Expr(SC, T, VK_RValue, OK_Ordinary, T->isDependentType(), T->isDependentType(), + T->isInstantiationDependentType(), T->containsUnexpandedParameterPack()), Constructor(D), Loc(Loc), ParenRange(ParenRange), Elidable(elidable), ZeroInitialization(ZeroInitialization), ConstructKind(ConstructKind), @@ -645,6 +677,8 @@ CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T, if (args[i]->isValueDependent()) ExprBits.ValueDependent = true; + if (args[i]->isInstantiationDependent()) + ExprBits.InstantiationDependent = true; if (args[i]->containsUnexpandedParameterPack()) ExprBits.ContainsUnexpandedParameterPack = true; @@ -660,6 +694,7 @@ ExprWithCleanups::ExprWithCleanups(ASTContext &C, : Expr(ExprWithCleanupsClass, subexpr->getType(), subexpr->getValueKind(), subexpr->getObjectKind(), subexpr->isTypeDependent(), subexpr->isValueDependent(), + subexpr->isInstantiationDependent(), subexpr->containsUnexpandedParameterPack()), SubExpr(subexpr), Temps(0), NumTemps(0) { if (numtemps) { @@ -690,8 +725,11 @@ CXXUnresolvedConstructExpr::CXXUnresolvedConstructExpr(TypeSourceInfo *Type, SourceLocation RParenLoc) : Expr(CXXUnresolvedConstructExprClass, Type->getType().getNonReferenceType(), - VK_LValue, OK_Ordinary, - Type->getType()->isDependentType(), true, + (Type->getType()->isLValueReferenceType() ? VK_LValue + :Type->getType()->isRValueReferenceType()? VK_XValue + :VK_RValue), + OK_Ordinary, + Type->getType()->isDependentType(), true, true, Type->getType()->containsUnexpandedParameterPack()), Type(Type), LParenLoc(LParenLoc), @@ -740,7 +778,7 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C, DeclarationNameInfo MemberNameInfo, const TemplateArgumentListInfo *TemplateArgs) : Expr(CXXDependentScopeMemberExprClass, C.DependentTy, - VK_LValue, OK_Ordinary, true, true, + VK_LValue, OK_Ordinary, true, true, true, ((Base && Base->containsUnexpandedParameterPack()) || (QualifierLoc && QualifierLoc.getNestedNameSpecifier() @@ -753,8 +791,10 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C, MemberNameInfo(MemberNameInfo) { if (TemplateArgs) { bool Dependent = true; + bool InstantiationDependent = true; bool ContainsUnexpandedParameterPack = false; getExplicitTemplateArgs().initializeFrom(*TemplateArgs, Dependent, + InstantiationDependent, ContainsUnexpandedParameterPack); if (ContainsUnexpandedParameterPack) ExprBits.ContainsUnexpandedParameterPack = true; @@ -769,7 +809,7 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C, NamedDecl *FirstQualifierFoundInScope, DeclarationNameInfo MemberNameInfo) : Expr(CXXDependentScopeMemberExprClass, C.DependentTy, - VK_LValue, OK_Ordinary, true, true, + VK_LValue, OK_Ordinary, true, true, true, ((Base && Base->containsUnexpandedParameterPack()) || (QualifierLoc && QualifierLoc.getNestedNameSpecifier()-> @@ -874,6 +914,8 @@ UnresolvedMemberExpr::UnresolvedMemberExpr(ASTContext &C, // Dependent ((Base && Base->isTypeDependent()) || BaseType->isDependentType()), + ((Base && Base->isInstantiationDependent()) || + BaseType->isInstantiationDependentType()), // Contains unexpanded parameter pack ((Base && Base->containsUnexpandedParameterPack()) || BaseType->containsUnexpandedParameterPack())), @@ -962,7 +1004,7 @@ SubstNonTypeTemplateParmPackExpr(QualType T, SourceLocation NameLoc, const TemplateArgument &ArgPack) : Expr(SubstNonTypeTemplateParmPackExprClass, T, VK_RValue, OK_Ordinary, - true, false, true), + true, true, true, true), Param(Param), Arguments(ArgPack.pack_begin()), NumArguments(ArgPack.pack_size()), NameLoc(NameLoc) { } diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp index d177cb5cbc97..e7888a6aa7b3 100644 --- a/lib/AST/ExprClassification.cpp +++ b/lib/AST/ExprClassification.cpp @@ -117,7 +117,6 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::UnresolvedLookupExprClass: case Expr::UnresolvedMemberExprClass: case Expr::CXXDependentScopeMemberExprClass: - case Expr::CXXUnresolvedConstructExprClass: case Expr::DependentScopeDeclRefExprClass: // ObjC instance variables are lvalues // FIXME: ObjC++0x might have different rules @@ -162,9 +161,13 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::SizeOfPackExprClass: case Expr::SubstNonTypeTemplateParmPackExprClass: case Expr::AsTypeExprClass: + case Expr::ObjCIndirectCopyRestoreExprClass: return Cl::CL_PRValue; // Next come the complicated cases. + case Expr::SubstNonTypeTemplateParmExprClass: + return ClassifyInternal(Ctx, + cast(E)->getReplacement()); // C++ [expr.sub]p1: The result is an lvalue of type "T". // However, subscripting vector types is more like member access. @@ -289,10 +292,15 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::CXXDynamicCastExprClass: case Expr::CXXReinterpretCastExprClass: case Expr::CXXConstCastExprClass: + case Expr::ObjCBridgedCastExprClass: // Only in C++ can casts be interesting at all. if (!Lang.CPlusPlus) return Cl::CL_PRValue; return ClassifyUnnamed(Ctx, cast(E)->getTypeAsWritten()); + case Expr::CXXUnresolvedConstructExprClass: + return ClassifyUnnamed(Ctx, + cast(E)->getTypeAsWritten()); + case Expr::BinaryConditionalOperatorClass: { if (!Lang.CPlusPlus) return Cl::CL_PRValue; const BinaryConditionalOperator *co = cast(E); @@ -339,6 +347,11 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::PackExpansionExprClass: return ClassifyInternal(Ctx, cast(E)->getPattern()); + + case Expr::MaterializeTemporaryExprClass: + return cast(E)->isBoundToLvalueReference() + ? Cl::CL_LValue + : Cl::CL_XValue; } llvm_unreachable("unhandled expression kind in classification"); diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 06c5645afb3f..786155af281d 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -224,11 +224,10 @@ static APSInt HandleFloatToIntCast(QualType DestType, QualType SrcType, bool DestSigned = DestType->isSignedIntegerOrEnumerationType(); // FIXME: Warning for overflow. - uint64_t Space[4]; + APSInt Result(DestWidth, !DestSigned); bool ignored; - (void)Value.convertToInteger(Space, DestWidth, DestSigned, - llvm::APFloat::rmTowardZero, &ignored); - return APSInt(llvm::APInt(DestWidth, 4, Space), !DestSigned); + (void)Value.convertToInteger(Result, llvm::APFloat::rmTowardZero, &ignored); + return Result; } static APFloat HandleFloatToFloatCast(QualType DestType, QualType SrcType, @@ -282,6 +281,17 @@ public: return true; return false; } + bool VisitObjCIvarRefExpr(const ObjCIvarRefExpr *E) { + if (Info.Ctx.getCanonicalType(E->getType()).isVolatileQualified()) + return true; + return false; + } + bool VisitBlockDeclRefExpr (const BlockDeclRefExpr *E) { + if (Info.Ctx.getCanonicalType(E->getType()).isVolatileQualified()) + return true; + return false; + } + // We don't want to evaluate BlockExprs multiple times, as they generate // a ton of code. bool VisitBlockExpr(const BlockExpr *E) { return true; } @@ -395,6 +405,8 @@ public: { return StmtVisitorTy::Visit(E->getChosenSubExpr(Info.Ctx)); } RetTy VisitGenericSelectionExpr(const GenericSelectionExpr *E) { return StmtVisitorTy::Visit(E->getResultExpr()); } + RetTy VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E) + { return StmtVisitorTy::Visit(E->getReplacement()); } RetTy VisitBinaryConditionalOperator(const BinaryConditionalOperator *E) { OpaqueValueEvaluation opaque(Info, E->getOpaqueValue(), E->getCommon()); @@ -525,15 +537,7 @@ bool LValueExprEvaluator::VisitMemberExpr(const MemberExpr *E) { if (FD->getType()->isReferenceType()) return false; - // FIXME: This is linear time. - unsigned i = 0; - for (RecordDecl::field_iterator Field = RD->field_begin(), - FieldEnd = RD->field_end(); - Field != FieldEnd; (void)++Field, ++i) { - if (*Field == FD) - break; - } - + unsigned i = FD->getFieldIndex(); Result.Offset += Info.Ctx.toCharUnitsFromBits(RL.getFieldOffset(i)); return true; } @@ -945,7 +949,7 @@ public: : ExprEvaluatorBaseTy(info), Result(result) {} bool Success(const llvm::APSInt &SI, const Expr *E) { - assert(E->getType()->isIntegralOrEnumerationType() && + assert(E->getType()->isIntegralOrEnumerationType() && "Invalid evaluation result."); assert(SI.isSigned() == E->getType()->isSignedIntegerOrEnumerationType() && "Invalid evaluation result."); @@ -1095,8 +1099,25 @@ static bool EvaluateInteger(const Expr* E, APSInt &Result, EvalInfo &Info) { bool IntExprEvaluator::CheckReferencedDecl(const Expr* E, const Decl* D) { // Enums are integer constant exprs. - if (const EnumConstantDecl *ECD = dyn_cast(D)) - return Success(ECD->getInitVal(), E); + if (const EnumConstantDecl *ECD = dyn_cast(D)) { + // Check for signedness/width mismatches between E type and ECD value. + bool SameSign = (ECD->getInitVal().isSigned() + == E->getType()->isSignedIntegerOrEnumerationType()); + bool SameWidth = (ECD->getInitVal().getBitWidth() + == Info.Ctx.getIntWidth(E->getType())); + if (SameSign && SameWidth) + return Success(ECD->getInitVal(), E); + else { + // Get rid of mismatch (otherwise Success assertions will fail) + // by computing a new value matching the type of E. + llvm::APSInt Val = ECD->getInitVal(); + if (!SameSign) + Val.setIsSigned(!ECD->getInitVal().isSigned()); + if (!SameWidth) + Val = Val.extOrTrunc(Info.Ctx.getIntWidth(E->getType())); + return Success(Val, E); + } + } // In C++, const, non-volatile integers initialized with ICEs are ICEs. // In C, they can also be folded, although they are not ICEs. @@ -1797,6 +1818,9 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) { case CK_GetObjCProperty: case CK_LValueBitCast: case CK_UserDefinedConversion: + case CK_ObjCProduceObject: + case CK_ObjCConsumeObject: + case CK_ObjCReclaimReturnedObject: return false; case CK_LValueToRValue: @@ -2301,6 +2325,9 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) { case CK_FloatingComplexToBoolean: case CK_IntegralComplexToReal: case CK_IntegralComplexToBoolean: + case CK_ObjCProduceObject: + case CK_ObjCConsumeObject: + case CK_ObjCReclaimReturnedObject: llvm_unreachable("invalid cast kind for complex value"); case CK_LValueToRValue: @@ -2771,6 +2798,8 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::PackExpansionExprClass: case Expr::SubstNonTypeTemplateParmPackExprClass: case Expr::AsTypeExprClass: + case Expr::ObjCIndirectCopyRestoreExprClass: + case Expr::MaterializeTemporaryExprClass: return ICEDiag(2, E->getLocStart()); case Expr::SizeOfPackExprClass: @@ -2778,6 +2807,10 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { // GCC considers the GNU __null value to be an integral constant expression. return NoDiag(); + case Expr::SubstNonTypeTemplateParmExprClass: + return + CheckICE(cast(E)->getReplacement(), Ctx); + case Expr::ParenExprClass: return CheckICE(cast(E)->getSubExpr(), Ctx); case Expr::GenericSelectionExprClass: @@ -2995,7 +3028,8 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::CXXFunctionalCastExprClass: case Expr::CXXStaticCastExprClass: case Expr::CXXReinterpretCastExprClass: - case Expr::CXXConstCastExprClass: { + case Expr::CXXConstCastExprClass: + case Expr::ObjCBridgedCastExprClass: { const Expr *SubExpr = cast(E)->getSubExpr(); if (SubExpr->getType()->isIntegralOrEnumerationType()) return CheckICE(SubExpr, Ctx); diff --git a/lib/AST/ExternalASTSource.cpp b/lib/AST/ExternalASTSource.cpp index f428318a21e3..b96d65a729ca 100644 --- a/lib/AST/ExternalASTSource.cpp +++ b/lib/AST/ExternalASTSource.cpp @@ -51,11 +51,11 @@ ExternalASTSource::FindExternalVisibleDeclsByName(const DeclContext *DC, void ExternalASTSource::MaterializeVisibleDecls(const DeclContext *DC) { } -bool +ExternalLoadResult ExternalASTSource::FindExternalLexicalDecls(const DeclContext *DC, bool (*isKindWeWant)(Decl::Kind), llvm::SmallVectorImpl &Result) { - return true; + return ELR_AlreadyLoaded; } void ExternalASTSource::getMemoryBufferSizes(MemoryBufferSizes &sizes) const { } diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index e81ec7e54b62..ec9863b298e6 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -21,6 +21,7 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/ABI.h" #include "clang/Basic/SourceManager.h" @@ -236,6 +237,9 @@ private: bool mangleSubstitution(TemplateName Template); bool mangleSubstitution(uintptr_t Ptr); + void mangleExistingSubstitution(QualType type); + void mangleExistingSubstitution(TemplateName name); + bool mangleStandardSubstitution(const NamedDecl *ND); void addSubstitution(const NamedDecl *ND) { @@ -255,9 +259,6 @@ private: DeclarationName name, unsigned KnownArity = UnknownArity); - static bool isUnresolvedType(const Type *type); - void mangleUnresolvedType(const Type *type); - void mangleName(const TemplateDecl *TD, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs); @@ -318,7 +319,7 @@ private: unsigned NumTemplateArgs); void mangleTemplateArgs(const TemplateParameterList &PL, const TemplateArgumentList &AL); - void mangleTemplateArg(const NamedDecl *P, const TemplateArgument &A); + void mangleTemplateArg(const NamedDecl *P, TemplateArgument A); void mangleUnresolvedTemplateArgs(const TemplateArgument *args, unsigned numArgs); @@ -451,13 +452,8 @@ void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) { FD = PrimaryTemplate->getTemplatedDecl(); } - // Do the canonicalization out here because parameter types can - // undergo additional canonicalization (e.g. array decay). - const FunctionType *FT - = cast(Context.getASTContext() - .getCanonicalType(FD->getType())); - - mangleBareFunctionType(FT, MangleReturnType); + mangleBareFunctionType(FD->getType()->getAs(), + MangleReturnType); } static const DeclContext *IgnoreLinkageSpecDecls(const DeclContext *DC) { @@ -597,19 +593,13 @@ void CXXNameMangler::mangleUnscopedTemplateName(TemplateName Template) { if (mangleSubstitution(Template)) return; - // FIXME: How to cope with operators here? DependentTemplateName *Dependent = Template.getAsDependentTemplateName(); assert(Dependent && "Not a dependent template name?"); - if (!Dependent->isIdentifier()) { - // FIXME: We can't possibly know the arity of the operator here! - Diagnostic &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error, - "cannot mangle dependent operator name"); - Diags.Report(DiagID); - return; - } + if (const IdentifierInfo *Id = Dependent->getIdentifier()) + mangleSourceName(Id); + else + mangleOperatorName(Dependent->getOperator(), UnknownArity); - mangleSourceName(Dependent->getIdentifier()); addSubstitution(Template); } @@ -702,31 +692,6 @@ void CXXNameMangler::manglePrefix(QualType type) { } } -/// Returns true if the given type, appearing within an -/// unresolved-name, should be mangled as an unresolved-type. -bool CXXNameMangler::isUnresolvedType(const Type *type) { - // ::= - // ::= - // ::= - // (this last is not official yet) - - if (isa(type)) return true; - if (isa(type)) return true; - // typeof? - if (const TemplateSpecializationType *tst = - dyn_cast(type)) { - TemplateDecl *temp = tst->getTemplateName().getAsTemplateDecl(); - if (temp && isa(temp)) - return true; - } - return false; -} - -void CXXNameMangler::mangleUnresolvedType(const Type *type) { - // This seems to be do everything we want. - mangleType(QualType(type, 0)); -} - /// Mangle everything prior to the base-unresolved-name in an unresolved-name. /// /// \param firstQualifierLookup - the entity found by unqualified lookup @@ -794,45 +759,141 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, } else { // Otherwise, all the cases want this. Out << "sr"; + } + + // Only certain other types are valid as prefixes; enumerate them. + switch (type->getTypeClass()) { + case Type::Builtin: + case Type::Complex: + case Type::Pointer: + case Type::BlockPointer: + case Type::LValueReference: + case Type::RValueReference: + case Type::MemberPointer: + case Type::ConstantArray: + case Type::IncompleteArray: + case Type::VariableArray: + case Type::DependentSizedArray: + case Type::DependentSizedExtVector: + case Type::Vector: + case Type::ExtVector: + case Type::FunctionProto: + case Type::FunctionNoProto: + case Type::Enum: + case Type::Paren: + case Type::Elaborated: + case Type::Attributed: + case Type::Auto: + case Type::PackExpansion: + case Type::ObjCObject: + case Type::ObjCInterface: + case Type::ObjCObjectPointer: + llvm_unreachable("type is illegal as a nested name specifier"); + + case Type::SubstTemplateTypeParmPack: + // FIXME: not clear how to mangle this! + // template class A { + // template void foo(decltype(T::foo(U())) x...); + // }; + Out << "_SUBSTPACK_"; + break; + + // ::= + // ::= + // ::= + // (this last is not official yet) + case Type::TypeOfExpr: + case Type::TypeOf: + case Type::Decltype: + case Type::TemplateTypeParm: + case Type::UnaryTransform: + case Type::SubstTemplateTypeParm: + unresolvedType: + assert(!qualifier->getPrefix()); + + // We only get here recursively if we're followed by identifiers. + if (recursive) Out << 'N'; + + // This seems to do everything we want. It's not really + // sanctioned for a substituted template parameter, though. + mangleType(QualType(type, 0)); + + // We never want to print 'E' directly after an unresolved-type, + // so we return directly. + return; + + case Type::Typedef: + mangleSourceName(cast(type)->getDecl()->getIdentifier()); + break; + + case Type::UnresolvedUsing: + mangleSourceName(cast(type)->getDecl() + ->getIdentifier()); + break; - if (isUnresolvedType(type)) { - // We only get here recursively if we're followed by identifiers. - if (recursive) Out << 'N'; - mangleUnresolvedType(type); + case Type::Record: + mangleSourceName(cast(type)->getDecl()->getIdentifier()); + break; - // We never want to print 'E' directly after an unresolved-type, - // so we return directly. - return; + case Type::TemplateSpecialization: { + const TemplateSpecializationType *tst + = cast(type); + TemplateName name = tst->getTemplateName(); + switch (name.getKind()) { + case TemplateName::Template: + case TemplateName::QualifiedTemplate: { + TemplateDecl *temp = name.getAsTemplateDecl(); + + // If the base is a template template parameter, this is an + // unresolved type. + assert(temp && "no template for template specialization type"); + if (isa(temp)) goto unresolvedType; + + mangleSourceName(temp->getIdentifier()); + break; } - } - assert(!isUnresolvedType(type)); + case TemplateName::OverloadedTemplate: + case TemplateName::DependentTemplate: + llvm_unreachable("invalid base for a template specialization type"); + + case TemplateName::SubstTemplateTemplateParm: { + SubstTemplateTemplateParmStorage *subst + = name.getAsSubstTemplateTemplateParm(); + mangleExistingSubstitution(subst->getReplacement()); + break; + } + + case TemplateName::SubstTemplateTemplateParmPack: { + // FIXME: not clear how to mangle this! + // template